/*
* @(#)YXBandList.java 1.13 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package sun.porting.utils;
/**
* Implementation of Y-X bounded rectangles. The band lists are
* circular and doubly-linked, with a dummy element separating the
* head from the tail; this makes insertion and deletion extremely cheap.
*
* @version 1.9, 08/19/02
* @author Richard Berlin
*/
class YXBandList {
YXBand bandList;
// static {
// Coverage.cover(17, "(removed)");
// }
// static {
// mark these covered, (a) so that they don't show as gaps, and
// (b) so we get an error message if they ever get called.
// // Coverage.cover(44, "(error case)");
// // Coverage.cover(47, "(error case)");
// // Coverage.cover(132, "(error case)");
// // Coverage.cover(135, "(error case)");
// }
public YXBandList() {
// // Coverage.cover(43, "YXBandList default constructor");
bandList = null;
}
public YXBandList(int x, int y, int w, int h) {
// // Coverage.cover(44, "YXBandList(x,y,w,h)");
if ((w > 0) && (h > 0)) {
init(x, y, w, h);
}
}
public void init(int x, int y, int w, int h) {
if ((w < 0) || (h < 0)) {
throw new IllegalArgumentException("Width or height is < 0");
}
// // Coverage.cover(45, "init(x,y,w,h)");
bandList = new YXBand(0, -1, null); // dummy element
if ((w > 0) && (h > 0)) {
bandList.next = new YXBand(x, y, w, h, bandList, bandList);
bandList.prev = bandList.next;
} else {
bandList.next = bandList.prev = bandList;
}
}
/*
* Circular, doubly-linked lists are central to the implementation.
*
* The idiom for creating a new list is to start by building the
* following structure, in which a dummy element and the real
* first element have their prev and next pointers all pointing at
* each other. In this example we're making an initial X band
* which goes from 10 to 18. Dummy elements are usually set with
* their start as 0 and their span as negative.
*
* --------
* |x = 0 |
* head --->|w = -1 |
* |next = -+---+
* +---+- = prev| |
* | | | |
* | -------- |
* | ^ ^ |
* | | | |
* | +---+ +----+ |
* | | | |
* | | -------- | |
* | | |x = 10 | | |
* | | |w = 8 | | |
* | | |next = -+-+ |
* | +-+- = prev| |
* +-->| |<--+
* --------
*
* Once this structure is set up, appending to the list is a general
* and very simple insertion before the dummy head element and after
* the last real element. The code for appending a new element which
* extends from 21 to 24 is
*
* head.prev.next = head.prev = new XSpan(21, 3, head.prev, head);
*
* In the first stage of execution (calling the constructor)
* a new element is created and its links correctly set:
*
* --------
* |x = 0 |
* head --->|w = -1 |<--------------------+
* |next = -+---+ |
* +---+- = prev| | |
* | | | | |
* | -------- | |
* | ^ ^ | |
* | | | | |
* | +---+ +----+ | |
* | | | | |
* | | -------- | | -------- |
* | | |x = 10 | | | |x = 21 | |
* | | |w = 8 | | | |w = 3 | |
* | | |next = -+-+ | |next = -+--+
* | +-+- = prev| | +-+- = prev|
* +-->| |<--+ | | |
* -------- | --------
* ^ |
* +-------------+
*
* and in the second phase (the assigments) the pointers are adjusted:
*
* --------
* |x = 0 |
* head --->|w = -1 |<--------------------+
* +---+- = next| |
* | |prev = -+----------------+ |
* | | | | |
* | -------- | |
* | ^ | |
* | | | |
* | +---+ | |
* | | V |
* | | -------- -------- |
* | | |x = 10 | |x = 21 | |
* | | |w = 8 | |w = 3 | |
* | | |next = -+-------->|next = -+--+
* | +-+- = prev|<--------+- = prev|
* +-->| | | |
* -------- --------
*
* Analogous code will work for inserting between any two
* elements of the list. For example, to prepend a band
* running from 3 to 5 we insert after the head and before the
* first real element:
*
* head.next.prev = head.next = new XSpan(3, 2, head, head.next);
*/
/*
* Simple copy of the elements of a doubly-linked list.
*/
protected void copyBands(YXBandList src) {
// // Coverage.cover(46, "copyBands(YXBandList)");
if (src.bandList == null) {
// // Coverage.cover(47, "source bandlist is null");
bandList = null;
return;
} else {
// // Coverage.cover(48, "create dummy head");
bandList = new YXBand(0, -1, null);
}
YXBand q = bandList; // dummy element
// // Coverage.cover(49, "Copy first element");
// copy first real element
YXBand p = src.bandList.next;
q.next = new YXBand(p.y, p.h, XSpan.copy(p.children), q, q);
q.prev = q.next;
// copy remainder of list
for (p = p.next; p != src.bandList; p = p.next) {
// // Coverage.cover(50, "Copy remainder");
q.prev = q.prev.next =
new YXBand(p.y, p.h, XSpan.copy(p.children), q.prev, q);
}
}
public boolean isRectangle() {
if (bandList.next == bandList.prev) {
XSpan kids = bandList.next.children;
return (kids.next == kids.prev);
}
return false;
}
/*
* Subtract a rectangle from a region. This is done in 3 stages:
* 1) If the first y band in the range overlaps the edge
* of the rectangle, and some of its x spans extend outside
* the rectangle, split the first band; if y overlaps but
* x does not, just shorten the band.
* 2) clear out the x range of any band wholly within the y range.
* if all spans are within the rectangle for a given band, delete
* the entire band.
* 3) If the last y band overlaps the edge, perform an operation
* analogous to step 1.
*/
protected void subtract(int x, int y, int w, int h) {
if ((w < 0) || (h < 0)) {
throw new IllegalArgumentException("Width or height is < 0");
}
// // Coverage.cover(51, "subtract(x,y,w,h)");
int x2 = x + w;
int y2 = y + h;
YXBand yb = YXBand.findBand(y, y2, bandList);
if (yb == null) {
// // Coverage.cover(52, "no pertinent bands found");
return;
}
// yb now points to the first relevant band
if (yb.y < y) {
// // Coverage.cover(53, "yb < y");
int yEnd = yb.y + yb.h;
// first band crosses the rectangle--we may have to split bands
XSpan oldKids = yb.children;
XSpan newKids = XSpan.copyOutside(x, x2, yb.children);
if (newKids == null) {
// // Coverage.cover(54, "newKids == null (shorten band)");
// the newly split-off band would have no children, so
// we can just shorten this band
yb.h = y - yb.y;
if (yEnd <= y2) {
yb = yb.next;
}
} else {
// // Coverage.cover(55, "newKids != null (split band)");
// do the split.
// --create a new band from y..(yb.y + yb.h)
int newEnd = yEnd;
if (yEnd > y2) {
// // Coverage.cover(56, "decrease newEnd");
newEnd = y2;
}
yb.next = yb.next.prev =
new YXBand(y, newEnd - y, newKids, yb, yb.next);
yb.h = y - yb.y;
yb = yb.next;
}
if (yEnd > y2) {
// // Coverage.cover(57, "yEnd > y2");
yb.next = yb.next.prev =
new YXBand(y2, yEnd - y2, XSpan.copy(oldKids),
yb, yb.next);
return;
}
}
while (yb != bandList) {
if (yb.y >= y2) {
// // Coverage.cover(58, "yb.y > y2 (exit)");
return;
}
int yEnd = yb.y + yb.h;
XSpan prev = yb.children.prev;
if ((yb.children.next.x >= x) && ((prev.x + prev.w) <= x2)) {
if (yEnd > y2) {
// // Coverage.cover(59, "yEnd > y2 (shorten last band)");
// we can just shorten the last band to y2..(yb.y + yb.h)
yb.y = y2;
yb.h = yEnd - y2;
return;
} else {
// // Coverage.cover(60, "delete last band");
// delete this band
yb.next.prev = yb.prev;
yb.prev.next = yb.next;
yb = yb.next;
}
} else {
if (yEnd > y2) {
// // Coverage.cover(61, "yEnd > y2 (split bands)");
// last band must be split
XSpan newKids = XSpan.copyOutside(x, x2, yb.children);
if (newKids != null) {
yb.prev = yb.prev.next =
new YXBand(yb.y, y2 - yb.y, newKids, yb.prev, yb);
}
yb.y = y2;
yb.h = yEnd - y2;
return;
} else {
// // Coverage.cover(62, "call deleteInside()");
XSpan.deleteInside(x, x2, yb.children);
yb = yb.next;
}
}
}
}
/*
* Destructively intersect a rectangle from a region.
* This is done in several steps:
* 1) Delete y bands that end above the rectangle.
* 2) If the first y band in the range overlaps the edge
* of the rectangle, shorten it.
* 3) For each band, remove spans outside the rectangle. If this
* is all spans, delete the band.
* 4) If the last y band overlaps the edge, shorten it.
* 5) Delete bands that begin below the rectangle.
*/
protected void intersect(int x, int y, int w, int h) {
if ((w < 0) || (h < 0)) {
throw new IllegalArgumentException("Width or height is < 0");
}
// // Coverage.cover(63, "intersect(x,y,w,h)");
int x2 = x + w;
int y2 = y + h;
YXBand yb = YXBand.findBand(y, y2, bandList);
if (yb == null) {
// // Coverage.cover(64, "no pertinent bands (null out list and return)");
bandList.next = bandList;
bandList.prev = bandList;
return;
}
// yb now points to the first relevant band
// delete anything in front of it
yb.prev = bandList;
bandList.next = yb;
// shorten the first band if necessary
int yEnd = yb.y + yb.h;
if (y2 < yEnd) {
// // Coverage.cover(65, "decrease yEnd");
yEnd = y2;
}
if (y > yb.y) {
// // Coverage.cover(66, "increase yb.y");
yb.y = y;
}
yb.h = yEnd - yb.y;
// trim the x spans of each relevant band
while ((yb != bandList) && (yb.y < y2)) {
XSpan prv = yb.children.prev;
if ((yb.children.next.x < x) || ((prv.x + prv.w) > x2)) {
// // Coverage.cover(67, "call deleteOutside()");
XSpan.deleteOutside(x, x2, yb.children);
if (yb.children.next == yb.children) {
// // Coverage.cover(68, "delete empty band");
// delete empty band
yb.prev.next = yb.next;
yb.next.prev = yb.prev;
}
}
yb = yb.next;
}
// yb points past the last relevant band; back it up one.
// then shorten the last band if necessary.
yb = yb.prev;
yEnd = y2 - yb.y;
if (yEnd < yb.h) {
// // Coverage.cover(69, "decrease yb.h");
yb.h = yEnd;
}
// Delete anything beyond the last relevant band.
yb.next = bandList;
bandList.prev = yb;
}
/*
* Destructively union a rectangle into a region. This is a relatively
* simple operation requiring creation of new bands wherever a band does
* not exist in the range y..y+h. Where bands do exist, an XSpan must be
* merged in to cover the range x..x+w. Only two possible split bands are
* required: if the first overlapping band starts before y, and if the
* last overlapping band extends beyond y+h;
*/
protected void union(int x, int y, int w, int h) {
if ((w < 0) || (h < 0)) {
throw new IllegalArgumentException("Width or height is < 0");
}
int yEnd = y + h;
// find first overlapping band
YXBand yb;
for (yb = bandList.next; yb != bandList; yb = yb.next) {
if ((yb.y + yb.h) > y) {
break;
}
}
if ((yb != bandList) && (y > yb.y)) {
// split bands, and operate (below) on the second one
// Coverage.cover(11, "split bands");
yb.next = yb.next.prev =
new YXBand(y, yb.y + yb.h - y,
XSpan.copy(yb.children), yb, yb.next);
yb.h = y - yb.y;
yb = yb.next;
}
while ((yb != bandList) && (yb.y < yEnd)) {
if (yb.y > y) {
// Coverage.cover(12, "insert band");
// insert a band from x,y to x+h,yb.y
yb.prev = yb.prev.next =
new YXBand(x, y, w, yb.y - y, yb.prev, yb);
}
y = yb.y + yb.h;
if (y > yEnd) {
// Coverage.cover(13, "split again");
// split bands, and operate (below) on the first one
yb.next = yb.next.prev =
new YXBand(yEnd, y - yEnd,
XSpan.copy(yb.children), yb, yb.next);
yb.h = yEnd - yb.y;
}
// now insert XSpan to cover x,yb.y to x+h,yb.y+yb.h
XSpan.cover(yb.children, x, w);
yb = yb.next;
};
if (y < yEnd) {
// Coverage.cover(14, "handle last band");
// yb is the first band that comes after yEnd
// insert a band (in front) from x,y to x+h,yEnd
yb.prev = yb.prev.next =
new YXBand(x, y, w, yEnd - y, yb.prev, yb);
}
}
/*
* Operations on a pair of regions are done by case analysis. There
* are eleven cases:
*
* 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
* A: -- -- --- ---- ----- -- --- ---- --- --- ---
* B: -- -- --- -- --- ---- --- --- --- ---- -----
*
* The first two cases (no overlap) are typically handled specially--
* bands are either skipped or deleted.
*
* Cases 3-5 are reduced to cases 6-8 by shortening or splitting bands.
* Case 8 is further reducible to case 7 and case 9 reducible to case
* 10 by shortening or splitting.
*
* For subtraction and intersection, the only difference in handling
* cases 6, 7, 10, 11 is whether band b has to be re-examined.
*/
/*
* destructively subtract two band structures
*/
protected void subtract(YXBand l) {
// // Coverage.cover(70, "subtract(YXBand)");
YXBand a = bandList.next;
YXBand b = l.next;
while ((a != bandList) && (b != l)) {
int aEnd = a.y + a.h;
if (aEnd <= b.y) {
// // Coverage.cover(71, "no overlap (skip a)");
// no overlap -- skip
a = a.next;
continue;
}
int bEnd = b.y + b.h;
if (bEnd <= a.y) {
// // Coverage.cover(72, "no overlap (skip b)");
// no overlap -- skip
b = b.next;
continue;
}
if ((a.y == b.y) && (aEnd == bEnd)) {
// // Coverage.cover(73, "y bands are equal - subtract kids");
// special case this because it's so common
XSpan.subtract(a.children, b.children);
if (a.children.next == a.children) {
// // Coverage.cover(74, "delete empty band");
// band is empty--delete it
a.prev.next = a.next;
a.next.prev = a.prev;
}
a = a.next;
b = b.next;
continue;
}
XSpan newKids;
if (a.y < b.y) {
// // Coverage.cover(75, "a.y < b.y (trim and split bands)");
// keep the non-overlap area preceding the overlap
newKids = XSpan.copy(a.children);
a.next = a.next.prev =
new YXBand(b.y, aEnd - b.y, newKids, a, a.next);
a.h = b.y - a.y;
a = a.next;
}
if (aEnd > bEnd) {
// // Coverage.cover(76, "aEnd > bEnd (trim and split bands)");
// keep the non-overlap area following the overlap
newKids = XSpan.copy(a.children);
a.next = a.next.prev =
new YXBand(bEnd, aEnd - bEnd, newKids, a, a.next);
a.h = bEnd - a.y;
}
XSpan.subtract(a.children, b.children);
if (a.children.next == a.children) {
// // Coverage.cover(77, "delete empty band");
// band is empty--delete it
a.prev.next = a.next;
a.next.prev = a.prev;
}
a = a.next;
}
}
/*
* destructively intersect two band structures
*/
protected void intersect(YXBand l, int x1, int x2) {
// // Coverage.cover(78, "intersect(YXBand, x1, x2)");
YXBand a = bandList.next;
YXBand b = l.next;
while ((a != bandList) && (b != l)) {
int aEnd = a.y + a.h;
if (aEnd <= b.y) {
// // Coverage.cover(79, "no overlap (delete a)");
// no overlap -- delete
a.prev.next = a.next;
a.next.prev = a.prev;
a = a.next;
continue;
}
int bEnd = b.y + b.h;
if (bEnd <= a.y) {
// // Coverage.cover(80, "no overlap (skip b)");
// no overlap -- skip
b = b.next;
continue;
}
if (a.y <= b.y) {
// // Coverage.cover(81, "a.y <= b.y (trim band)");
// we're not interested in the non-overlap.
// begin by shortening the band.
a.y = b.y;
a.h = aEnd - a.y;
}
if (aEnd > bEnd) {
// // Coverage.cover(82, "aEnd > bEnd");
if ((b.next != l) && (b.next.y < aEnd)) {
// may need to split
XSpan newKids = XSpan.copyInside(x1, x2, a.children);
if (newKids == null) {
// // Coverage.cover(83, "newKids == null (delete band)");
// we've discovered that this band can't contribute
// to overlap at all. Delete it and don't bother
// with the split.
a.prev.next = a.next;
a.next.prev = a.prev;
a = a.next;
b = b.next;
continue;
} else {
// // Coverage.cover(84, "split band");
a.next = a.next.prev =
new YXBand(b.next.y, aEnd - b.next.y, newKids,
a, a.next);
}
}
// now shorten the band
a.h = bEnd - a.y;
}
// intersect the x spans
XSpan.intersect(a.children, b.children);
if (a.children.next == a.children) {
// // Coverage.cover(85, "delete empty band");
// band is empty--delete it
a.prev.next = a.next;
a.next.prev = a.prev;
}
a = a.next;
}
// delete any remaining a elements which don't overlap.
a.prev.next = bandList;
bandList.prev = a.prev;
}
/*
* destructively union two band structures
*/
protected void union(YXBand l) {
YXBand a = bandList.next;
YXBand b = l.next;
while ((a != bandList) && (b != l)) {
int aEnd = a.y + a.h;
if (aEnd <= b.y) {
// Coverage.cover(15, "no overlap -- skip");
// no overlap -- skip
a = a.next;
continue;
}
int bEnd = b.y + b.h;
if (bEnd <= a.y) {
// Coverage.cover(16, "no overlap -- insert part of b");
// no overlap -- simple insertion of (part of) b
int start = (a.prev == bandList) ? b.y : (a.prev.y + a.prev.h);
if (b.y > start) {
start = b.y;
}
a.prev = a.prev.next =
new YXBand(start, bEnd - start, XSpan.copy(b.children),
a.prev, a);
b = b.next;
continue;
}
if (b.y < a.y) {
// Coverage.cover(40, "add non-overlap which precedes overlap");
int start = (a.prev == bandList) ? b.y : (a.prev.y + a.prev.h);
if (b.y > start) {
start = b.y;
}
if (a.y > start) {
a.prev = a.prev.next =
new YXBand(start, a.y - start, XSpan.copy(b.children),
a.prev, a);
}
}
if ((a.y < b.y) && (aEnd > b.y)) {
// Coverage.cover(18, "keep non-overlap which precedes overlap");
// keep the non-overlap area preceding the overlap
a.next = a.next.prev =
new YXBand(b.y, aEnd - b.y,
XSpan.copy(a.children), a, a.next);
a.h = b.y - a.y;
a = a.next;
}
if (aEnd > bEnd) {
// Coverage.cover(19, "keep non-overlap which follows overlap");
// keep the non-overlap area following the overlap
a.next = a.next.prev =
new YXBand(bEnd, aEnd - bEnd,
XSpan.copy(a.children), a, a.next);
a.h = bEnd - a.y;
}
XSpan.merge(a.children, b.children);
a = a.next;
if (aEnd >= bEnd) {
// Coverage.cover(20, "aEnd >= bEnd");
b = b.next;
}
}
if (b != l) {
int start = (a.prev == bandList) ? b.y : (a.prev.y + a.prev.h);
if (b.y > start) {
start = b.y;
}
a.prev = a.prev.next =
new YXBand(start, b.y + b.h - start, XSpan.copy(b.children),
a.prev, a);
b = b.next;
while (b != l) {
a.prev = a.prev.next =
new YXBand(b.y, b.h, XSpan.copy(b.children), a.prev, a);
b = b.next;
}
}
}
/* Scan the band list. If two adjacent y bands have identical
* lists of children, coalesce the bands.
*/
public void deFragment() {
// // Coverage.cover(86, "deFragment");
for (YXBand yb = bandList.next; yb != bandList.prev; yb = yb.next) {
while ((yb.h == 0) && (yb != bandList)) {
yb.prev.next = yb.next;
yb.next.prev = yb.prev;
yb = yb.next;
}
if ((yb.y + yb.h) != yb.next.y) {
// // Coverage.cover(87, "non-adjacent");
continue; // not adjacent
}
XSpan aHead = yb.children;
XSpan bHead = yb.next.children;
XSpan a = aHead.next;
XSpan b = bHead.next;
while ((a != aHead) && (b != bHead)) {
if ((a.x == b.x) && (a.w == b.w)) {
// // Coverage.cover(88, "spans are equal");
a = a.next;
b = b.next;
} else {
// // Coverage.cover(89, "spans not equal");
break;
}
}
if ((a == aHead) && (b == bHead)) {
// // Coverage.cover(90, "coalesce");
// children match--coalesce
yb.h += yb.next.h;
yb.next = yb.next.next;
yb.next.prev = yb;
yb = yb.prev;
}
}
}
/*
* See if the rectangle x,y,w,h is all within the band structure.
*/
protected boolean contains(int x, int y, int w, int h) {
if ((w < 0) || (h < 0)) {
throw new IllegalArgumentException("Width or height is < 0");
}
// // Coverage.cover(91, "contains(x,y,w,h)");
YXBand yb;
XSpan xs;
int x2 = x + w;
int y2 = y + h;
int xEnd, yEnd;
yb = YXBand.findBand(y, y2, bandList);
if (yb == null) {
// // Coverage.cover(92, "no relevant bands");
return false;
}
// before we loop, check first band
if (yb.y > y) {
// // Coverage.cover(93, "end uncovered");
return false; // end uncovered
}
// now scan all bands between y and y2, checking for
// discontiguity and making sure x range is covered
for (yEnd = yb.y; (yb != bandList) && (yEnd < y2); yb = yb.next) {
if (yb.y > yEnd) {
// // Coverage.cover(94, "y discontiguous");
return false; // discontigous
}
// before we loop, check last band
XSpan xHead = yb.children;
if ((xHead.prev.x + xHead.prev.w) < x2) {
// // Coverage.cover(95, "end uncovered");
return false; // end uncovered
}
// search for first overlapping band
for (xs = xHead.next; xs != xHead; xs = xs.next) {
if (xs.x > x) {
// // Coverage.cover(96, "end uncovered");
return false; // end uncovered
} else if (xs.x + xs.w > x) {
// // Coverage.cover(97, "found band");
break;
}
}
// now scan all bands between x and x2 for discontiguity
// NOTE: we really should be able to dispense with this loop,
// because we coalesce XSpans at every step. Either there is
// a single XSpan which contains all of x..xEnd, or we can
// return false. But for now I'll let it stand because it's
// only a minor ineffeciency in practice.
for (xEnd = xs.x; (xs != xHead) && (xEnd < x2); xs = xs.next) {
if (xs.x > xEnd) {
// // Coverage.cover(98, "discontiguous");
return false; // discontiguous
}
xEnd = xs.x + xs.w;
}
// // Coverage.cover(99, "update yEnd");
yEnd = yb.y + yb.h;
}
return true;
}
public boolean equals(YXBandList head) {
YXBand aBand = bandList.next;
YXBand bBand = head.bandList.next;
while ((aBand != bandList) || (bBand != head.bandList)) {
if ((aBand.y != bBand.y) || (aBand.h != bBand.h)) {
return false;
}
XSpan aHead = aBand.children;
XSpan bHead = bBand.children;
XSpan a = aHead.next;
XSpan b = bHead.next;
while ((a != aHead) || (b != bHead)) {
if ((a.x != b.x) || (a.w != b.w)) {
return false;
}
a = a.next;
b = b.next;
}
aBand = aBand.next;
bBand = bBand.next;
}
return true;
}
/*
* find the smallest rectangle which contains the whole band structure.
*/
public java.awt.Rectangle getBounds() {
// // Coverage.cover(100, "getBounds");
if ((bandList == null) || (bandList.next == bandList)) {
// // Coverage.cover(101, "null bandList");
bandList = null;
return new Rectangle();
}
XSpan firstX = bandList.next.children;
int x1 = firstX.next.x;
int x2 = firstX.prev.x + firstX.prev.w;
int tmp;
for (YXBand l = bandList.next.next; l != bandList; l = l.next) {
tmp = l.children.next.x;
if (x1 > tmp) {
// // Coverage.cover(102, "increase x1");
x1 = tmp;
}
XSpan lastX = l.children.prev;
tmp = lastX.x + lastX.w;
if (x2 < tmp) {
// // Coverage.cover(103, "decrease x2");
x2 = tmp;
}
// // Coverage.cover(104, "(spans examined)");
}
YXBand prev = bandList.prev;
return new Rectangle(x1, bandList.next.y,
x2 - x1, prev.y + prev.h - bandList.next.y);
}
/*
* translate all bands by dx, dy
*/
protected void translate(int dx, int dy) {
// // Coverage.cover(105, "translate(dx,dy)");
for (YXBand yb = bandList.next; yb != bandList; yb = yb.next) {
yb.y += dy;
// // Coverage.cover(106, "bands processed");
XSpan xHead = yb.children;
for (XSpan xs = xHead.next; xs != xHead; xs = xs.next) {
// // Coverage.cover(107, "spans processed");
xs.x += dx;
}
}
}
// no test coverage for toString
public String toString() {
return YXBand.makeString(bandList);
}
}