/* * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.java2d.pipe; import java.awt.Rectangle;import java.awt.Shape;import java.awt.geom.AffineTransform;import java.awt.geom.RectangularShape; /** * This class encapsulates a definition of a two dimensional region which * consists of a number of Y ranges each containing multiple X bands. * <p> * A rectangular Region is allowed to have a null band list in which * case the rectangular shape is defined by the bounding box parameters * (lox, loy, hix, hiy). * <p> * The band list, if present, consists of a list of rows in ascending Y * order, ending at endIndex which is the index beyond the end of the * last row. Each row consists of at least 3 + 2n entries (n >= 1) * where the first 3 entries specify the Y range as start, end, and * the number of X ranges in that Y range. These 3 entries are * followed by pairs of X coordinates in ascending order: * <pre> * bands[rowstart+0] = Y0; // starting Y coordinate * bands[rowstart+1] = Y1; // ending Y coordinate - endY > startY * bands[rowstart+2] = N; // number of X bands - N >= 1 * * bands[rowstart+3] = X10; // starting X coordinate of first band * bands[rowstart+4] = X11; // ending X coordinate of first band * bands[rowstart+5] = X20; // starting X coordinate of second band * bands[rowstart+6] = X21; // ending X coordinate of second band * ... * bands[rowstart+3+N*2-2] = XN0; // starting X coord of last band * bands[rowstart+3+N*2-1] = XN1; // ending X coord of last band * * bands[rowstart+3+N*2] = ... // start of next Y row * </pre> */public class Region { static final int INIT_SIZE = 50; static final int GROW_SIZE = 50; /** * Immutable Region. */ private static final class ImmutableRegion extends Region { protected ImmutableRegion(int lox, int loy, int hix, int hiy) { super(lox, loy, hix, hiy); } // Override all the methods that mutate the object public void appendSpans(sun.java2d.pipe.SpanIterator si) {} public void setOutputArea(java.awt.Rectangle r) {} public void setOutputAreaXYWH(int x, int y, int w, int h) {} public void setOutputArea(int[] box) {} public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) {} } public static final Region EMPTY_REGION = new ImmutableRegion(0, 0, 0, 0); public static final Region WHOLE_REGION = new ImmutableRegion( Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); int lox; int loy; int hix; int hiy; int endIndex; int[] bands; private static native void initIDs(); static { initIDs(); } /** * Adds the dimension <code>dim</code> to the coordinate * <code>start</code> with appropriate clipping. If * <code>dim</code> is non-positive then the method returns * the start coordinate. If the sum overflows an integer * data type then the method returns <code>Integer.MAX_VALUE</code>. */ public static int dimAdd(int start, int dim) { if (dim <= 0) return start; if ((dim += start) < start) return Integer.MAX_VALUE; return dim; } /** * Adds the delta {@code dv} to the value {@code v} with * appropriate clipping to the bounds of Integer resolution. * If the answer would be greater than {@code Integer.MAX_VALUE} * then {@code Integer.MAX_VALUE} is returned. * If the answer would be less than {@code Integer.MIN_VALUE} * then {@code Integer.MIN_VALUE} is returned. * Otherwise the sum is returned. */ public static int clipAdd(int v, int dv) { int newv = v + dv; if ((newv > v) != (dv > 0)) { newv = (dv < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; } return newv; } protected Region(int lox, int loy, int hix, int hiy) { this.lox = lox; this.loy = loy; this.hix = hix; this.hiy = hiy; } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object. * * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Shape s, AffineTransform at) { return getInstance(WHOLE_REGION, false, s, at); } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object further restricted by the specified * device bounds. * <p> * Note that only the bounds of the specified Region are used to * restrict the resulting Region. * If devBounds is non-rectangular and clipping to the specific * bands of devBounds is needed, then an intersection of the * resulting Region with devBounds must be performed in a * subsequent step. * * @param devBounds a non-null Region specifying some bounds to * clip the geometry to * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Region devBounds, Shape s, AffineTransform at) { return getInstance(devBounds, false, s, at); } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object further restricted by the specified * device bounds. * If the normalize parameter is true then coordinate normalization * is performed as per the 2D Graphics non-antialiasing implementation * of the VALUE_STROKE_NORMALIZE hint. * <p> * Note that only the bounds of the specified Region are used to * restrict the resulting Region. * If devBounds is non-rectangular and clipping to the specific * bands of devBounds is needed, then an intersection of the * resulting Region with devBounds must be performed in a * subsequent step. * * @param devBounds a non-null Region specifying some bounds to * clip the geometry to * @param normalize a boolean indicating whether or not to apply * normalization * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Region devBounds, boolean normalize, Shape s, AffineTransform at) { // Optimize for empty shapes to avoid involving the SpanIterator if (s instanceof RectangularShape && ((RectangularShape)s).isEmpty()) { return EMPTY_REGION; } int box[] = new int[4]; ShapeSpanIterator sr = new ShapeSpanIterator(normalize); try { sr.setOutputArea(devBounds); sr.appendPath(s.getPathIterator(at)); sr.getPathBox(box); Region r = Region.getInstance(box); r.appendSpans(sr); return r; } finally { sr.dispose(); } } /** * Returns a Region object with a rectangle of interest specified * by the indicated Rectangle object. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstance(Rectangle r) { return Region.getInstanceXYWH(r.x, r.y, r.width, r.height); } /** * Returns a Region object with a rectangle of interest specified * by the indicated rectangular area in x, y, width, height format. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstanceXYWH(int x, int y, int w, int h) { return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Returns a Region object with a rectangle of interest specified * by the indicated span array. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstance(int box[]) { return new Region(box[0], box[1], box[2], box[3]); } /** * Returns a Region object with a rectangle of interest specified * by the indicated rectangular area in lox, loy, hix, hiy format. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) { return new Region(lox, loy, hix, hiy); } /** * Sets the rectangle of interest for storing and returning * region bands. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputArea(Rectangle r) { setOutputAreaXYWH(r.x, r.y, r.width, r.height); } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified in x, y, width, height * format and appropriate clipping is performed as per the method * <code>dimAdd</code>. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputAreaXYWH(int x, int y, int w, int h) { setOutputAreaXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified as a span array. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputArea(int box[]) { this.lox = box[0]; this.loy = box[1]; this.hix = box[2]; this.hiy = box[3]; } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified in lox, loy, * hix, hiy format. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) { this.lox = lox; this.loy = loy; this.hix = hix; this.hiy = hiy; } /** * Appends the list of spans returned from the indicated * SpanIterator. Each span must be at a higher starting * Y coordinate than the previous data or it must have a * Y range equal to the highest Y band in the region and a * higher X coordinate than any of the spans in that band. */ public void appendSpans(SpanIterator si) { int[] box = new int[6]; while (si.nextSpan(box)) { appendSpan(box); } endRow(box); calcBBox(); } /** * Returns a Region object that represents the same list of * rectangles as the current Region object, translated by * the specified dx, dy translation factors. */ public Region getTranslatedRegion(int dx, int dy) { if ((dx | dy) == 0) { return this; } int tlox = lox + dx; int tloy = loy + dy; int thix = hix + dx; int thiy = hiy + dy; if ((tlox > lox) != (dx > 0) || (tloy > loy) != (dy > 0) || (thix > hix) != (dx > 0) || (thiy > hiy) != (dy > 0)) { return getSafeTranslatedRegion(dx, dy); } Region ret = new Region(tlox, tloy, thix, thiy); int bands[] = this.bands; if (bands != null) { int end = endIndex; ret.endIndex = end; int newbands[] = new int[end]; ret.bands = newbands; int i = 0; int ncol; while (i < end) { newbands[i] = bands[i] + dy; i++; newbands[i] = bands[i] + dy; i++; newbands[i] = ncol = bands[i]; i++; while (--ncol >= 0) { newbands[i] = bands[i] + dx; i++; newbands[i] = bands[i] + dx; i++; } } } return ret; } private Region getSafeTranslatedRegion(int dx, int dy) { int tlox = clipAdd(lox, dx); int tloy = clipAdd(loy, dy); int thix = clipAdd(hix, dx); int thiy = clipAdd(hiy, dy); Region ret = new Region(tlox, tloy, thix, thiy); int bands[] = this.bands; if (bands != null) { int end = endIndex; int newbands[] = new int[end]; int i = 0; // index for source bands int j = 0; // index for translated newbands int ncol; while (i < end) { int y1, y2; newbands[j++] = y1 = clipAdd(bands[i++], dy); newbands[j++] = y2 = clipAdd(bands[i++], dy); newbands[j++] = ncol = bands[i++]; int savej = j; if (y1 < y2) { while (--ncol >= 0) { int x1 = clipAdd(bands[i++], dx); int x2 = clipAdd(bands[i++], dx); if (x1 < x2) { newbands[j++] = x1; newbands[j++] = x2; } } } else { i += ncol * 2; } // Did we get any non-empty bands in this row? if (j > savej) { newbands[savej-1] = (j - savej) / 2; } else { j = savej - 3; } } if (j <= 5) { if (j < 5) { // No rows or bands were generated... ret.lox = ret.loy = ret.hix = ret.hiy = 0; } else { // Only generated one single rect in the end... ret.loy = newbands[0]; ret.hiy = newbands[1]; ret.lox = newbands[3]; ret.hix = newbands[4]; } // ret.endIndex and ret.bands were never initialized... // ret.endIndex = 0; // ret.newbands = null; } else { // Generated multiple bands and/or multiple rows... ret.endIndex = j; ret.bands = newbands; } } return ret; } /** * Returns a Region object that represents the intersection of * this object with the specified Rectangle. The return value * may be this same object if no clipping occurs. */ public Region getIntersection(Rectangle r) { return getIntersectionXYWH(r.x, r.y, r.width, r.height); } /** * Returns a Region object that represents the intersection of * this object with the specified rectangular area. The return * value may be this same object if no clipping occurs. */ public Region getIntersectionXYWH(int x, int y, int w, int h) { return getIntersectionXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Returns a Region object that represents the intersection of * this object with the specified rectangular area. The return * value may be this same object if no clipping occurs. */ public Region getIntersectionXYXY(int lox, int loy, int hix, int hiy) { if (isInsideXYXY(lox, loy, hix, hiy)) { return this; } Region ret = new Region((lox < this.lox) ? this.lox : lox, (loy < this.loy) ? this.loy : loy, (hix > this.hix) ? this.hix : hix, (hiy > this.hiy) ? this.hiy : hiy); if (bands != null) { ret.appendSpans(this.getSpanIterator()); } return ret; } /** * Returns a Region object that represents the intersection of this * object with the specified Region object. * <p> * If {@code A} and {@code B} are both Region Objects and * <code>C = A.getIntersection(B);</code> then a point will * be contained in {@code C} iff it is contained in both * {@code A} and {@code B}. * <p> * The return value may be this same object or the argumentLines 1–500 of 1255. Load more
/* * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.java2d.pipe; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.RectangularShape; /** * This class encapsulates a definition of a two dimensional region which * consists of a number of Y ranges each containing multiple X bands. * <p> * A rectangular Region is allowed to have a null band list in which * case the rectangular shape is defined by the bounding box parameters * (lox, loy, hix, hiy). * <p> * The band list, if present, consists of a list of rows in ascending Y * order, ending at endIndex which is the index beyond the end of the * last row. Each row consists of at least 3 + 2n entries (n >= 1) * where the first 3 entries specify the Y range as start, end, and * the number of X ranges in that Y range. These 3 entries are * followed by pairs of X coordinates in ascending order: * <pre> * bands[rowstart+0] = Y0; // starting Y coordinate * bands[rowstart+1] = Y1; // ending Y coordinate - endY > startY * bands[rowstart+2] = N; // number of X bands - N >= 1 * * bands[rowstart+3] = X10; // starting X coordinate of first band * bands[rowstart+4] = X11; // ending X coordinate of first band * bands[rowstart+5] = X20; // starting X coordinate of second band * bands[rowstart+6] = X21; // ending X coordinate of second band * ... * bands[rowstart+3+N*2-2] = XN0; // starting X coord of last band * bands[rowstart+3+N*2-1] = XN1; // ending X coord of last band * * bands[rowstart+3+N*2] = ... // start of next Y row * </pre> */ public class Region { static final int INIT_SIZE = 50; static final int GROW_SIZE = 50; /** * Immutable Region. */ private static final class ImmutableRegion extends Region { protected ImmutableRegion(int lox, int loy, int hix, int hiy) { super(lox, loy, hix, hiy); } // Override all the methods that mutate the object public void appendSpans(sun.java2d.pipe.SpanIterator si) {} public void setOutputArea(java.awt.Rectangle r) {} public void setOutputAreaXYWH(int x, int y, int w, int h) {} public void setOutputArea(int[] box) {} public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) {} } public static final Region EMPTY_REGION = new ImmutableRegion(0, 0, 0, 0); public static final Region WHOLE_REGION = new ImmutableRegion( Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); int lox; int loy; int hix; int hiy; int endIndex; int[] bands; private static native void initIDs(); static { initIDs(); } /** * Adds the dimension <code>dim</code> to the coordinate * <code>start</code> with appropriate clipping. If * <code>dim</code> is non-positive then the method returns * the start coordinate. If the sum overflows an integer * data type then the method returns <code>Integer.MAX_VALUE</code>. */ public static int dimAdd(int start, int dim) { if (dim <= 0) return start; if ((dim += start) < start) return Integer.MAX_VALUE; return dim; } /** * Adds the delta {@code dv} to the value {@code v} with * appropriate clipping to the bounds of Integer resolution. * If the answer would be greater than {@code Integer.MAX_VALUE} * then {@code Integer.MAX_VALUE} is returned. * If the answer would be less than {@code Integer.MIN_VALUE} * then {@code Integer.MIN_VALUE} is returned. * Otherwise the sum is returned. */ public static int clipAdd(int v, int dv) { int newv = v + dv; if ((newv > v) != (dv > 0)) { newv = (dv < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; } return newv; } protected Region(int lox, int loy, int hix, int hiy) { this.lox = lox; this.loy = loy; this.hix = hix; this.hiy = hiy; } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object. * * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Shape s, AffineTransform at) { return getInstance(WHOLE_REGION, false, s, at); } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object further restricted by the specified * device bounds. * <p> * Note that only the bounds of the specified Region are used to * restrict the resulting Region. * If devBounds is non-rectangular and clipping to the specific * bands of devBounds is needed, then an intersection of the * resulting Region with devBounds must be performed in a * subsequent step. * * @param devBounds a non-null Region specifying some bounds to * clip the geometry to * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Region devBounds, Shape s, AffineTransform at) { return getInstance(devBounds, false, s, at); } /** * Returns a Region object covering the pixels which would be * touched by a fill or clip operation on a Graphics implementation * on the specified Shape object under the optionally specified * AffineTransform object further restricted by the specified * device bounds. * If the normalize parameter is true then coordinate normalization * is performed as per the 2D Graphics non-antialiasing implementation * of the VALUE_STROKE_NORMALIZE hint. * <p> * Note that only the bounds of the specified Region are used to * restrict the resulting Region. * If devBounds is non-rectangular and clipping to the specific * bands of devBounds is needed, then an intersection of the * resulting Region with devBounds must be performed in a * subsequent step. * * @param devBounds a non-null Region specifying some bounds to * clip the geometry to * @param normalize a boolean indicating whether or not to apply * normalization * @param s a non-null Shape object specifying the geometry enclosing * the pixels of interest * @param at an optional <code>AffineTransform</code> to be applied to the * coordinates as they are returned in the iteration, or * <code>null</code> if untransformed coordinates are desired */ public static Region getInstance(Region devBounds, boolean normalize, Shape s, AffineTransform at) { // Optimize for empty shapes to avoid involving the SpanIterator if (s instanceof RectangularShape && ((RectangularShape)s).isEmpty()) { return EMPTY_REGION; } int box[] = new int[4]; ShapeSpanIterator sr = new ShapeSpanIterator(normalize); try { sr.setOutputArea(devBounds); sr.appendPath(s.getPathIterator(at)); sr.getPathBox(box); Region r = Region.getInstance(box); r.appendSpans(sr); return r; } finally { sr.dispose(); } } /** * Returns a Region object with a rectangle of interest specified * by the indicated Rectangle object. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstance(Rectangle r) { return Region.getInstanceXYWH(r.x, r.y, r.width, r.height); } /** * Returns a Region object with a rectangle of interest specified * by the indicated rectangular area in x, y, width, height format. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstanceXYWH(int x, int y, int w, int h) { return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Returns a Region object with a rectangle of interest specified * by the indicated span array. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstance(int box[]) { return new Region(box[0], box[1], box[2], box[3]); } /** * Returns a Region object with a rectangle of interest specified * by the indicated rectangular area in lox, loy, hix, hiy format. * <p> * This method can also be used to create a simple rectangular * region. */ public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) { return new Region(lox, loy, hix, hiy); } /** * Sets the rectangle of interest for storing and returning * region bands. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputArea(Rectangle r) { setOutputAreaXYWH(r.x, r.y, r.width, r.height); } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified in x, y, width, height * format and appropriate clipping is performed as per the method * <code>dimAdd</code>. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputAreaXYWH(int x, int y, int w, int h) { setOutputAreaXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified as a span array. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputArea(int box[]) { this.lox = box[0]; this.loy = box[1]; this.hix = box[2]; this.hiy = box[3]; } /** * Sets the rectangle of interest for storing and returning * region bands. The rectangle is specified in lox, loy, * hix, hiy format. * <p> * This method can also be used to initialize a simple rectangular * region. */ public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) { this.lox = lox; this.loy = loy; this.hix = hix; this.hiy = hiy; } /** * Appends the list of spans returned from the indicated * SpanIterator. Each span must be at a higher starting * Y coordinate than the previous data or it must have a * Y range equal to the highest Y band in the region and a * higher X coordinate than any of the spans in that band. */ public void appendSpans(SpanIterator si) { int[] box = new int[6]; while (si.nextSpan(box)) { appendSpan(box); } endRow(box); calcBBox(); } /** * Returns a Region object that represents the same list of * rectangles as the current Region object, translated by * the specified dx, dy translation factors. */ public Region getTranslatedRegion(int dx, int dy) { if ((dx | dy) == 0) { return this; } int tlox = lox + dx; int tloy = loy + dy; int thix = hix + dx; int thiy = hiy + dy; if ((tlox > lox) != (dx > 0) || (tloy > loy) != (dy > 0) || (thix > hix) != (dx > 0) || (thiy > hiy) != (dy > 0)) { return getSafeTranslatedRegion(dx, dy); } Region ret = new Region(tlox, tloy, thix, thiy); int bands[] = this.bands; if (bands != null) { int end = endIndex; ret.endIndex = end; int newbands[] = new int[end]; ret.bands = newbands; int i = 0; int ncol; while (i < end) { newbands[i] = bands[i] + dy; i++; newbands[i] = bands[i] + dy; i++; newbands[i] = ncol = bands[i]; i++; while (--ncol >= 0) { newbands[i] = bands[i] + dx; i++; newbands[i] = bands[i] + dx; i++; } } } return ret; } private Region getSafeTranslatedRegion(int dx, int dy) { int tlox = clipAdd(lox, dx); int tloy = clipAdd(loy, dy); int thix = clipAdd(hix, dx); int thiy = clipAdd(hiy, dy); Region ret = new Region(tlox, tloy, thix, thiy); int bands[] = this.bands; if (bands != null) { int end = endIndex; int newbands[] = new int[end]; int i = 0; // index for source bands int j = 0; // index for translated newbands int ncol; while (i < end) { int y1, y2; newbands[j++] = y1 = clipAdd(bands[i++], dy); newbands[j++] = y2 = clipAdd(bands[i++], dy); newbands[j++] = ncol = bands[i++]; int savej = j; if (y1 < y2) { while (--ncol >= 0) { int x1 = clipAdd(bands[i++], dx); int x2 = clipAdd(bands[i++], dx); if (x1 < x2) { newbands[j++] = x1; newbands[j++] = x2; } } } else { i += ncol * 2; } // Did we get any non-empty bands in this row? if (j > savej) { newbands[savej-1] = (j - savej) / 2; } else { j = savej - 3; } } if (j <= 5) { if (j < 5) { // No rows or bands were generated... ret.lox = ret.loy = ret.hix = ret.hiy = 0; } else { // Only generated one single rect in the end... ret.loy = newbands[0]; ret.hiy = newbands[1]; ret.lox = newbands[3]; ret.hix = newbands[4]; } // ret.endIndex and ret.bands were never initialized... // ret.endIndex = 0; // ret.newbands = null; } else { // Generated multiple bands and/or multiple rows... ret.endIndex = j; ret.bands = newbands; } } return ret; } /** * Returns a Region object that represents the intersection of * this object with the specified Rectangle. The return value * may be this same object if no clipping occurs. */ public Region getIntersection(Rectangle r) { return getIntersectionXYWH(r.x, r.y, r.width, r.height); } /** * Returns a Region object that represents the intersection of * this object with the specified rectangular area. The return * value may be this same object if no clipping occurs. */ public Region getIntersectionXYWH(int x, int y, int w, int h) { return getIntersectionXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } /** * Returns a Region object that represents the intersection of * this object with the specified rectangular area. The return * value may be this same object if no clipping occurs. */ public Region getIntersectionXYXY(int lox, int loy, int hix, int hiy) { if (isInsideXYXY(lox, loy, hix, hiy)) { return this; } Region ret = new Region((lox < this.lox) ? this.lox : lox, (loy < this.loy) ? this.loy : loy, (hix > this.hix) ? this.hix : hix, (hiy > this.hiy) ? this.hiy : hiy); if (bands != null) { ret.appendSpans(this.getSpanIterator()); } return ret; } /** * Returns a Region object that represents the intersection of this * object with the specified Region object. * <p> * If {@code A} and {@code B} are both Region Objects and * <code>C = A.getIntersection(B);</code> then a point will * be contained in {@code C} iff it is contained in both * {@code A} and {@code B}. * <p> * The return value may be this same object or the argument