< prev index next >

src/java.desktop/share/classes/sun/java2d/pipe/Region.java

Print this page


   1 /*
   2  * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 250      * @param devBounds a non-null Region specifying some bounds to
 251      *          clip the geometry to
 252      * @param normalize a boolean indicating whether or not to apply
 253      *          normalization
 254      * @param s a non-null Shape object specifying the geometry enclosing
 255      *          the pixels of interest
 256      * @param at an optional {@code AffineTransform} to be applied to the
 257      *          coordinates as they are returned in the iteration, or
 258      *          {@code null} if untransformed coordinates are desired
 259      */
 260     public static Region getInstance(Region devBounds, boolean normalize,
 261                                      Shape s, AffineTransform at)
 262     {
 263         // Optimize for empty shapes to avoid involving the SpanIterator
 264         if (s instanceof RectangularShape &&
 265                 ((RectangularShape)s).isEmpty())
 266         {
 267             return EMPTY_REGION;
 268         }
 269 
 270         int box[] = new int[4];
 271         ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
 272         try {
 273             sr.setOutputArea(devBounds);
 274             sr.appendPath(s.getPathIterator(at));
 275             sr.getPathBox(box);
 276             return Region.getInstance(box, sr);
 277         } finally {
 278             sr.dispose();
 279         }
 280     }
 281 
 282     /**
 283      * Returns a Region object with a rectangle of interest specified by the
 284      * indicated rectangular area in lox, loy, hix, hiy and edges array, which
 285      * is located relative to the rectangular area. Edges array - 0,1 are y
 286      * range, 2N,2N+1 are x ranges, 1 per y range.
 287      *
 288      * @see TransformHelper
 289      */
 290     static Region getInstance(final int lox, final int loy, final int hix,


 329     }
 330 
 331     /**
 332      * Returns a Region object with a rectangle of interest specified
 333      * by the indicated rectangular area in x, y, width, height format.
 334      * <p>
 335      * This method can also be used to create a simple rectangular
 336      * region.
 337      */
 338     public static Region getInstanceXYWH(int x, int y, int w, int h) {
 339         return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
 340     }
 341 
 342     /**
 343      * Returns a Region object with a rectangle of interest specified
 344      * by the indicated span array.
 345      * <p>
 346      * This method can also be used to create a simple rectangular
 347      * region.
 348      */
 349     public static Region getInstance(int box[]) {
 350         return new Region(box[0], box[1], box[2], box[3]);
 351     }
 352 
 353     /**
 354      * Returns a Region object with a rectangle of interest specified
 355      * by the indicated rectangular area in lox, loy, hix, hiy format.
 356      * <p>
 357      * This method can also be used to create a simple rectangular
 358      * region.
 359      */
 360     public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
 361         return new Region(lox, loy, hix, hiy);
 362     }
 363 
 364     /**
 365      * Returns a Region object with a rectangle of interest specified by the
 366      * indicated rectangular area in lox, loy, hix, hiy format.
 367      * <p/>
 368      * Appends the list of spans returned from the indicated SpanIterator. Each
 369      * span must be at a higher starting Y coordinate than the previous data or
 370      * it must have a Y range equal to the highest Y band in the region and a
 371      * higher X coordinate than any of the spans in that band.
 372      */
 373     public static Region getInstance(int box[], SpanIterator si) {
 374         Region ret = new Region(box[0], box[1], box[2], box[3]);
 375         ret.appendSpans(si);
 376         return ret;
 377     }
 378 
 379     /**
 380      * Appends the list of spans returned from the indicated
 381      * SpanIterator.  Each span must be at a higher starting
 382      * Y coordinate than the previous data or it must have a
 383      * Y range equal to the highest Y band in the region and a
 384      * higher X coordinate than any of the spans in that band.
 385      */
 386     private void appendSpans(SpanIterator si) {
 387         int[] box = new int[6];
 388 
 389         while (si.nextSpan(box)) {
 390             appendSpan(box);
 391         }
 392 
 393         endRow(box);
 394         calcBBox();
 395     }
 396 
 397     /**
 398      * Returns a Region object that represents the same list of rectangles as
 399      * the current Region object, scaled by the specified sx, sy factors.
 400      */
 401     public Region getScaledRegion(final double sx, final double sy) {
 402         if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
 403             return EMPTY_REGION;
 404         }
 405         if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
 406             return this;
 407         }
 408 
 409         int tlox = clipScale(lox, sx);
 410         int tloy = clipScale(loy, sy);
 411         int thix = clipScale(hix, sx);
 412         int thiy = clipScale(hiy, sy);
 413         Region ret = new Region(tlox, tloy, thix, thiy);
 414         int bands[] = this.bands;
 415         if (bands != null) {
 416             int end = endIndex;
 417             int newbands[] = new int[end];
 418             int i = 0; // index for source bands
 419             int j = 0; // index for translated newbands
 420             int ncol;
 421             while (i < end) {
 422                 int y1, y2;
 423                 newbands[j++] = y1   = clipScale(bands[i++], sy);
 424                 newbands[j++] = y2   = clipScale(bands[i++], sy);
 425                 newbands[j++] = ncol = bands[i++];
 426                 int savej = j;
 427                 if (y1 < y2) {
 428                     while (--ncol >= 0) {
 429                         int x1 = clipScale(bands[i++], sx);
 430                         int x2 = clipScale(bands[i++], sx);
 431                         if (x1 < x2) {
 432                             newbands[j++] = x1;
 433                             newbands[j++] = x2;
 434                         }
 435                     }
 436                 } else {
 437                     i += ncol * 2;


 471      * Returns a Region object that represents the same list of
 472      * rectangles as the current Region object, translated by
 473      * the specified dx, dy translation factors.
 474      */
 475     public Region getTranslatedRegion(int dx, int dy) {
 476         if ((dx | dy) == 0) {
 477             return this;
 478         }
 479         int tlox = lox + dx;
 480         int tloy = loy + dy;
 481         int thix = hix + dx;
 482         int thiy = hiy + dy;
 483         if ((tlox > lox) != (dx > 0) ||
 484             (tloy > loy) != (dy > 0) ||
 485             (thix > hix) != (dx > 0) ||
 486             (thiy > hiy) != (dy > 0))
 487         {
 488             return getSafeTranslatedRegion(dx, dy);
 489         }
 490         Region ret = new Region(tlox, tloy, thix, thiy);
 491         int bands[] = this.bands;
 492         if (bands != null) {
 493             int end = endIndex;
 494             ret.endIndex = end;
 495             int newbands[] = new int[end];
 496             ret.bands = newbands;
 497             int i = 0;
 498             int ncol;
 499             while (i < end) {
 500                 newbands[i] = bands[i] + dy; i++;
 501                 newbands[i] = bands[i] + dy; i++;
 502                 newbands[i] = ncol = bands[i]; i++;
 503                 while (--ncol >= 0) {
 504                     newbands[i] = bands[i] + dx; i++;
 505                     newbands[i] = bands[i] + dx; i++;
 506                 }
 507             }
 508         }
 509         return ret;
 510     }
 511 
 512     private Region getSafeTranslatedRegion(int dx, int dy) {
 513         int tlox = clipAdd(lox, dx);
 514         int tloy = clipAdd(loy, dy);
 515         int thix = clipAdd(hix, dx);
 516         int thiy = clipAdd(hiy, dy);
 517         Region ret = new Region(tlox, tloy, thix, thiy);
 518         int bands[] = this.bands;
 519         if (bands != null) {
 520             int end = endIndex;
 521             int newbands[] = new int[end];
 522             int i = 0; // index for source bands
 523             int j = 0; // index for translated newbands
 524             int ncol;
 525             while (i < end) {
 526                 int y1, y2;
 527                 newbands[j++] = y1   = clipAdd(bands[i++], dy);
 528                 newbands[j++] = y2   = clipAdd(bands[i++], dy);
 529                 newbands[j++] = ncol = bands[i++];
 530                 int savej = j;
 531                 if (y1 < y2) {
 532                     while (--ncol >= 0) {
 533                         int x1 = clipAdd(bands[i++], dx);
 534                         int x2 = clipAdd(bands[i++], dx);
 535                         if (x1 < x2) {
 536                             newbands[j++] = x1;
 537                             newbands[j++] = x2;
 538                         }
 539                     }
 540                 } else {
 541                     i += ncol * 2;


 729     public Region getExclusiveOr(Region r) {
 730         if (r.isEmpty()) {
 731             return this;
 732         }
 733         if (this.isEmpty()) {
 734             return r;
 735         }
 736         Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
 737                                 (r.loy > this.loy) ? this.loy : r.loy,
 738                                 (r.hix < this.hix) ? this.hix : r.hix,
 739                                 (r.hiy < this.hiy) ? this.hiy : r.hiy);
 740         ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
 741         return ret;
 742     }
 743 
 744     private static final int INCLUDE_A      = 1;
 745     private static final int INCLUDE_B      = 2;
 746     private static final int INCLUDE_COMMON = 4;
 747 
 748     private void filterSpans(Region ra, Region rb, int flags) {
 749         int abands[] = ra.bands;
 750         int bbands[] = rb.bands;
 751         if (abands == null) {
 752             abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
 753         }
 754         if (bbands == null) {
 755             bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
 756         }
 757         int box[] = new int[6];
 758         int acolstart = 0;
 759         int ay1 = abands[acolstart++];
 760         int ay2 = abands[acolstart++];
 761         int acolend = abands[acolstart++];
 762         acolend = acolstart + 2 * acolend;
 763         int bcolstart = 0;
 764         int by1 = bbands[bcolstart++];
 765         int by2 = bbands[bcolstart++];
 766         int bcolend = bbands[bcolstart++];
 767         bcolend = bcolstart + 2 * bcolend;
 768         int y = loy;
 769         while (y < hiy) {
 770             if (y >= ay2) {
 771                 if (acolend < ra.endIndex) {
 772                     acolstart = acolend;
 773                     ay1 = abands[acolstart++];
 774                     ay2 = abands[acolstart++];
 775                     acolend = abands[acolstart++];
 776                     acolend = acolstart + 2 * acolend;
 777                 } else {


 948         if (this.encompasses(r)) {
 949             return r;
 950         }
 951         if (r.encompasses(this)) {
 952             return this;
 953         }
 954         return new Region((r.lox < this.lox) ? this.lox : r.lox,
 955                           (r.loy < this.loy) ? this.loy : r.loy,
 956                           (r.hix > this.hix) ? this.hix : r.hix,
 957                           (r.hiy > this.hiy) ? this.hiy : r.hiy);
 958     }
 959 
 960     /**
 961      * Appends a single span defined by the 4 parameters
 962      * spanlox, spanloy, spanhix, spanhiy.
 963      * This span must be at a higher starting Y coordinate than
 964      * the previous data or it must have a Y range equal to the
 965      * highest Y band in the region and a higher X coordinate
 966      * than any of the spans in that band.
 967      */
 968     private void appendSpan(int box[]) {
 969         int spanlox, spanloy, spanhix, spanhiy;
 970         if ((spanlox = box[0]) < lox) spanlox = lox;
 971         if ((spanloy = box[1]) < loy) spanloy = loy;
 972         if ((spanhix = box[2]) > hix) spanhix = hix;
 973         if ((spanhiy = box[3]) > hiy) spanhiy = hiy;
 974         if (spanhix <= spanlox || spanhiy <= spanloy) {
 975             return;
 976         }
 977 
 978         int curYrow = box[4];
 979         if (endIndex == 0 || spanloy >= bands[curYrow + 1]) {
 980             if (bands == null) {
 981                 bands = new int[INIT_SIZE];
 982             } else {
 983                 needSpace(5);
 984                 endRow(box);
 985                 curYrow = box[4];
 986             }
 987             bands[endIndex++] = spanloy;
 988             bands[endIndex++] = spanhiy;


 994                 bands[endIndex - 1] = spanhix;
 995                 return;
 996             }
 997             needSpace(2);
 998         } else {
 999             throw new InternalError("bad span");
1000         }
1001         bands[endIndex++] = spanlox;
1002         bands[endIndex++] = spanhix;
1003         bands[curYrow + 2]++;
1004     }
1005 
1006     private void needSpace(int num) {
1007         if (endIndex + num >= bands.length) {
1008             int[] newbands = new int[bands.length + GROW_SIZE];
1009             System.arraycopy(bands, 0, newbands, 0, endIndex);
1010             bands = newbands;
1011         }
1012     }
1013 
1014     private void endRow(int box[]) {
1015         int cur = box[4];
1016         int prev = box[5];
1017         if (cur > prev) {
1018             int[] bands = this.bands;
1019             if (bands[prev + 1] == bands[cur] &&
1020                 bands[prev + 2] == bands[cur + 2])
1021             {
1022                 int num = bands[cur + 2] * 2;
1023                 cur += 3;
1024                 prev += 3;
1025                 while (num > 0) {
1026                     if (bands[cur++] != bands[prev++]) {
1027                         break;
1028                     }
1029                     num--;
1030                 }
1031                 if (num == 0) {
1032                     // prev == box[4]
1033                     bands[box[5] + 1] = bands[prev + 1];
1034                     endIndex = prev;


1256     public boolean encompassesXYWH(int x, int y, int w, int h) {
1257         return encompassesXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
1258     }
1259 
1260     /**
1261      * Quickly checks if this Region surrounds the specified
1262      * rectangular area specified in lox, loy, hix, hiy format.
1263      * <p>
1264      * This method will return false if this Region object is
1265      * not a simple rectangle.
1266      */
1267     public boolean encompassesXYXY(int lox, int loy, int hix, int hiy) {
1268         return (this.bands == null &&
1269                 this.lox <= lox && this.loy <= loy &&
1270                 this.hix >= hix && this.hiy >= hiy);
1271     }
1272 
1273     /**
1274      * Gets the bbox of the available spans, clipped to the OutputArea.
1275      */
1276     public void getBounds(int pathbox[]) {
1277         pathbox[0] = lox;
1278         pathbox[1] = loy;
1279         pathbox[2] = hix;
1280         pathbox[3] = hiy;
1281     }
1282 
1283     /**
1284      * Clips the indicated bbox array to the bounds of this Region.
1285      */
1286     public void clipBoxToBounds(int bbox[]) {
1287         if (bbox[0] < lox) bbox[0] = lox;
1288         if (bbox[1] < loy) bbox[1] = loy;
1289         if (bbox[2] > hix) bbox[2] = hix;
1290         if (bbox[3] > hiy) bbox[3] = hiy;
1291     }
1292 
1293     /**
1294      * Gets an iterator object to iterate over the spans in this region.
1295      */
1296     public RegionIterator getIterator() {
1297         return new RegionIterator(this);
1298     }
1299 
1300     /**
1301      * Gets a span iterator object that iterates over the spans in this region
1302      */
1303     public SpanIterator getSpanIterator() {
1304         return new RegionSpanIterator(this);
1305     }
1306 
1307     /**
1308      * Gets a span iterator object that iterates over the spans in this region
1309      * but clipped to the bounds given in the argument (xlo, ylo, xhi, yhi).
1310      */
1311     public SpanIterator getSpanIterator(int bbox[]) {
1312         SpanIterator result = getSpanIterator();
1313         result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1314         return result;
1315     }
1316 
1317     /**
1318      * Returns a SpanIterator that is the argument iterator filtered by
1319      * this region.
1320      */
1321     public SpanIterator filter(SpanIterator si) {
1322         if (bands == null) {
1323             si.intersectClipBox(lox, loy, hix, hiy);
1324         } else {
1325             si = new RegionClipSpanIterator(this, si);
1326         }
1327         return si;
1328     }
1329 
1330     @Override
1331     public String toString() {


1378         }
1379         Region r = (Region) o;
1380         if (this.isEmpty()) {
1381             return r.isEmpty();
1382         } else if (r.isEmpty()) {
1383             return false;
1384         }
1385         if (r.lox != this.lox || r.loy != this.loy ||
1386             r.hix != this.hix || r.hiy != this.hiy)
1387         {
1388             return false;
1389         }
1390         if (this.bands == null) {
1391             return (r.bands == null);
1392         } else if (r.bands == null) {
1393             return false;
1394         }
1395         if (this.endIndex != r.endIndex) {
1396             return false;
1397         }
1398         int abands[] = this.bands;
1399         int bbands[] = r.bands;
1400         for (int i = 0; i < endIndex; i++) {
1401             if (abands[i] != bbands[i]) {
1402                 return false;
1403             }
1404         }
1405         return true;
1406     }
1407 }
   1 /*
   2  * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 250      * @param devBounds a non-null Region specifying some bounds to
 251      *          clip the geometry to
 252      * @param normalize a boolean indicating whether or not to apply
 253      *          normalization
 254      * @param s a non-null Shape object specifying the geometry enclosing
 255      *          the pixels of interest
 256      * @param at an optional {@code AffineTransform} to be applied to the
 257      *          coordinates as they are returned in the iteration, or
 258      *          {@code null} if untransformed coordinates are desired
 259      */
 260     public static Region getInstance(Region devBounds, boolean normalize,
 261                                      Shape s, AffineTransform at)
 262     {
 263         // Optimize for empty shapes to avoid involving the SpanIterator
 264         if (s instanceof RectangularShape &&
 265                 ((RectangularShape)s).isEmpty())
 266         {
 267             return EMPTY_REGION;
 268         }
 269 
 270         int[] box = new int[4];
 271         ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
 272         try {
 273             sr.setOutputArea(devBounds);
 274             sr.appendPath(s.getPathIterator(at));
 275             sr.getPathBox(box);
 276             return Region.getInstance(box, sr);
 277         } finally {
 278             sr.dispose();
 279         }
 280     }
 281 
 282     /**
 283      * Returns a Region object with a rectangle of interest specified by the
 284      * indicated rectangular area in lox, loy, hix, hiy and edges array, which
 285      * is located relative to the rectangular area. Edges array - 0,1 are y
 286      * range, 2N,2N+1 are x ranges, 1 per y range.
 287      *
 288      * @see TransformHelper
 289      */
 290     static Region getInstance(final int lox, final int loy, final int hix,


 329     }
 330 
 331     /**
 332      * Returns a Region object with a rectangle of interest specified
 333      * by the indicated rectangular area in x, y, width, height format.
 334      * <p>
 335      * This method can also be used to create a simple rectangular
 336      * region.
 337      */
 338     public static Region getInstanceXYWH(int x, int y, int w, int h) {
 339         return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
 340     }
 341 
 342     /**
 343      * Returns a Region object with a rectangle of interest specified
 344      * by the indicated span array.
 345      * <p>
 346      * This method can also be used to create a simple rectangular
 347      * region.
 348      */
 349     public static Region getInstance(int[] box) {
 350         return new Region(box[0], box[1], box[2], box[3]);
 351     }
 352 
 353     /**
 354      * Returns a Region object with a rectangle of interest specified
 355      * by the indicated rectangular area in lox, loy, hix, hiy format.
 356      * <p>
 357      * This method can also be used to create a simple rectangular
 358      * region.
 359      */
 360     public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
 361         return new Region(lox, loy, hix, hiy);
 362     }
 363 
 364     /**
 365      * Returns a Region object with a rectangle of interest specified by the
 366      * indicated rectangular area in lox, loy, hix, hiy format.
 367      * <p/>
 368      * Appends the list of spans returned from the indicated SpanIterator. Each
 369      * span must be at a higher starting Y coordinate than the previous data or
 370      * it must have a Y range equal to the highest Y band in the region and a
 371      * higher X coordinate than any of the spans in that band.
 372      */
 373     public static Region getInstance(int[] box, SpanIterator si) {
 374         Region ret = new Region(box[0], box[1], box[2], box[3]);
 375         ret.appendSpans(si);
 376         return ret;
 377     }
 378 
 379     /**
 380      * Appends the list of spans returned from the indicated
 381      * SpanIterator.  Each span must be at a higher starting
 382      * Y coordinate than the previous data or it must have a
 383      * Y range equal to the highest Y band in the region and a
 384      * higher X coordinate than any of the spans in that band.
 385      */
 386     private void appendSpans(SpanIterator si) {
 387         int[] box = new int[6];
 388 
 389         while (si.nextSpan(box)) {
 390             appendSpan(box);
 391         }
 392 
 393         endRow(box);
 394         calcBBox();
 395     }
 396 
 397     /**
 398      * Returns a Region object that represents the same list of rectangles as
 399      * the current Region object, scaled by the specified sx, sy factors.
 400      */
 401     public Region getScaledRegion(final double sx, final double sy) {
 402         if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
 403             return EMPTY_REGION;
 404         }
 405         if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
 406             return this;
 407         }
 408 
 409         int tlox = clipScale(lox, sx);
 410         int tloy = clipScale(loy, sy);
 411         int thix = clipScale(hix, sx);
 412         int thiy = clipScale(hiy, sy);
 413         Region ret = new Region(tlox, tloy, thix, thiy);
 414         int[] bands = this.bands;
 415         if (bands != null) {
 416             int end = endIndex;
 417             int[] newbands = new int[end];
 418             int i = 0; // index for source bands
 419             int j = 0; // index for translated newbands
 420             int ncol;
 421             while (i < end) {
 422                 int y1, y2;
 423                 newbands[j++] = y1   = clipScale(bands[i++], sy);
 424                 newbands[j++] = y2   = clipScale(bands[i++], sy);
 425                 newbands[j++] = ncol = bands[i++];
 426                 int savej = j;
 427                 if (y1 < y2) {
 428                     while (--ncol >= 0) {
 429                         int x1 = clipScale(bands[i++], sx);
 430                         int x2 = clipScale(bands[i++], sx);
 431                         if (x1 < x2) {
 432                             newbands[j++] = x1;
 433                             newbands[j++] = x2;
 434                         }
 435                     }
 436                 } else {
 437                     i += ncol * 2;


 471      * Returns a Region object that represents the same list of
 472      * rectangles as the current Region object, translated by
 473      * the specified dx, dy translation factors.
 474      */
 475     public Region getTranslatedRegion(int dx, int dy) {
 476         if ((dx | dy) == 0) {
 477             return this;
 478         }
 479         int tlox = lox + dx;
 480         int tloy = loy + dy;
 481         int thix = hix + dx;
 482         int thiy = hiy + dy;
 483         if ((tlox > lox) != (dx > 0) ||
 484             (tloy > loy) != (dy > 0) ||
 485             (thix > hix) != (dx > 0) ||
 486             (thiy > hiy) != (dy > 0))
 487         {
 488             return getSafeTranslatedRegion(dx, dy);
 489         }
 490         Region ret = new Region(tlox, tloy, thix, thiy);
 491         int[] bands = this.bands;
 492         if (bands != null) {
 493             int end = endIndex;
 494             ret.endIndex = end;
 495             int[] newbands = new int[end];
 496             ret.bands = newbands;
 497             int i = 0;
 498             int ncol;
 499             while (i < end) {
 500                 newbands[i] = bands[i] + dy; i++;
 501                 newbands[i] = bands[i] + dy; i++;
 502                 newbands[i] = ncol = bands[i]; i++;
 503                 while (--ncol >= 0) {
 504                     newbands[i] = bands[i] + dx; i++;
 505                     newbands[i] = bands[i] + dx; i++;
 506                 }
 507             }
 508         }
 509         return ret;
 510     }
 511 
 512     private Region getSafeTranslatedRegion(int dx, int dy) {
 513         int tlox = clipAdd(lox, dx);
 514         int tloy = clipAdd(loy, dy);
 515         int thix = clipAdd(hix, dx);
 516         int thiy = clipAdd(hiy, dy);
 517         Region ret = new Region(tlox, tloy, thix, thiy);
 518         int[] bands = this.bands;
 519         if (bands != null) {
 520             int end = endIndex;
 521             int[] newbands = new int[end];
 522             int i = 0; // index for source bands
 523             int j = 0; // index for translated newbands
 524             int ncol;
 525             while (i < end) {
 526                 int y1, y2;
 527                 newbands[j++] = y1   = clipAdd(bands[i++], dy);
 528                 newbands[j++] = y2   = clipAdd(bands[i++], dy);
 529                 newbands[j++] = ncol = bands[i++];
 530                 int savej = j;
 531                 if (y1 < y2) {
 532                     while (--ncol >= 0) {
 533                         int x1 = clipAdd(bands[i++], dx);
 534                         int x2 = clipAdd(bands[i++], dx);
 535                         if (x1 < x2) {
 536                             newbands[j++] = x1;
 537                             newbands[j++] = x2;
 538                         }
 539                     }
 540                 } else {
 541                     i += ncol * 2;


 729     public Region getExclusiveOr(Region r) {
 730         if (r.isEmpty()) {
 731             return this;
 732         }
 733         if (this.isEmpty()) {
 734             return r;
 735         }
 736         Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
 737                                 (r.loy > this.loy) ? this.loy : r.loy,
 738                                 (r.hix < this.hix) ? this.hix : r.hix,
 739                                 (r.hiy < this.hiy) ? this.hiy : r.hiy);
 740         ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
 741         return ret;
 742     }
 743 
 744     private static final int INCLUDE_A      = 1;
 745     private static final int INCLUDE_B      = 2;
 746     private static final int INCLUDE_COMMON = 4;
 747 
 748     private void filterSpans(Region ra, Region rb, int flags) {
 749         int[] abands = ra.bands;
 750         int[] bbands = rb.bands;
 751         if (abands == null) {
 752             abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
 753         }
 754         if (bbands == null) {
 755             bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
 756         }
 757         int[] box = new int[6];
 758         int acolstart = 0;
 759         int ay1 = abands[acolstart++];
 760         int ay2 = abands[acolstart++];
 761         int acolend = abands[acolstart++];
 762         acolend = acolstart + 2 * acolend;
 763         int bcolstart = 0;
 764         int by1 = bbands[bcolstart++];
 765         int by2 = bbands[bcolstart++];
 766         int bcolend = bbands[bcolstart++];
 767         bcolend = bcolstart + 2 * bcolend;
 768         int y = loy;
 769         while (y < hiy) {
 770             if (y >= ay2) {
 771                 if (acolend < ra.endIndex) {
 772                     acolstart = acolend;
 773                     ay1 = abands[acolstart++];
 774                     ay2 = abands[acolstart++];
 775                     acolend = abands[acolstart++];
 776                     acolend = acolstart + 2 * acolend;
 777                 } else {


 948         if (this.encompasses(r)) {
 949             return r;
 950         }
 951         if (r.encompasses(this)) {
 952             return this;
 953         }
 954         return new Region((r.lox < this.lox) ? this.lox : r.lox,
 955                           (r.loy < this.loy) ? this.loy : r.loy,
 956                           (r.hix > this.hix) ? this.hix : r.hix,
 957                           (r.hiy > this.hiy) ? this.hiy : r.hiy);
 958     }
 959 
 960     /**
 961      * Appends a single span defined by the 4 parameters
 962      * spanlox, spanloy, spanhix, spanhiy.
 963      * This span must be at a higher starting Y coordinate than
 964      * the previous data or it must have a Y range equal to the
 965      * highest Y band in the region and a higher X coordinate
 966      * than any of the spans in that band.
 967      */
 968     private void appendSpan(int[] box) {
 969         int spanlox, spanloy, spanhix, spanhiy;
 970         if ((spanlox = box[0]) < lox) spanlox = lox;
 971         if ((spanloy = box[1]) < loy) spanloy = loy;
 972         if ((spanhix = box[2]) > hix) spanhix = hix;
 973         if ((spanhiy = box[3]) > hiy) spanhiy = hiy;
 974         if (spanhix <= spanlox || spanhiy <= spanloy) {
 975             return;
 976         }
 977 
 978         int curYrow = box[4];
 979         if (endIndex == 0 || spanloy >= bands[curYrow + 1]) {
 980             if (bands == null) {
 981                 bands = new int[INIT_SIZE];
 982             } else {
 983                 needSpace(5);
 984                 endRow(box);
 985                 curYrow = box[4];
 986             }
 987             bands[endIndex++] = spanloy;
 988             bands[endIndex++] = spanhiy;


 994                 bands[endIndex - 1] = spanhix;
 995                 return;
 996             }
 997             needSpace(2);
 998         } else {
 999             throw new InternalError("bad span");
1000         }
1001         bands[endIndex++] = spanlox;
1002         bands[endIndex++] = spanhix;
1003         bands[curYrow + 2]++;
1004     }
1005 
1006     private void needSpace(int num) {
1007         if (endIndex + num >= bands.length) {
1008             int[] newbands = new int[bands.length + GROW_SIZE];
1009             System.arraycopy(bands, 0, newbands, 0, endIndex);
1010             bands = newbands;
1011         }
1012     }
1013 
1014     private void endRow(int[] box) {
1015         int cur = box[4];
1016         int prev = box[5];
1017         if (cur > prev) {
1018             int[] bands = this.bands;
1019             if (bands[prev + 1] == bands[cur] &&
1020                 bands[prev + 2] == bands[cur + 2])
1021             {
1022                 int num = bands[cur + 2] * 2;
1023                 cur += 3;
1024                 prev += 3;
1025                 while (num > 0) {
1026                     if (bands[cur++] != bands[prev++]) {
1027                         break;
1028                     }
1029                     num--;
1030                 }
1031                 if (num == 0) {
1032                     // prev == box[4]
1033                     bands[box[5] + 1] = bands[prev + 1];
1034                     endIndex = prev;


1256     public boolean encompassesXYWH(int x, int y, int w, int h) {
1257         return encompassesXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
1258     }
1259 
1260     /**
1261      * Quickly checks if this Region surrounds the specified
1262      * rectangular area specified in lox, loy, hix, hiy format.
1263      * <p>
1264      * This method will return false if this Region object is
1265      * not a simple rectangle.
1266      */
1267     public boolean encompassesXYXY(int lox, int loy, int hix, int hiy) {
1268         return (this.bands == null &&
1269                 this.lox <= lox && this.loy <= loy &&
1270                 this.hix >= hix && this.hiy >= hiy);
1271     }
1272 
1273     /**
1274      * Gets the bbox of the available spans, clipped to the OutputArea.
1275      */
1276     public void getBounds(int[] pathbox) {
1277         pathbox[0] = lox;
1278         pathbox[1] = loy;
1279         pathbox[2] = hix;
1280         pathbox[3] = hiy;
1281     }
1282 
1283     /**
1284      * Clips the indicated bbox array to the bounds of this Region.
1285      */
1286     public void clipBoxToBounds(int[] bbox) {
1287         if (bbox[0] < lox) bbox[0] = lox;
1288         if (bbox[1] < loy) bbox[1] = loy;
1289         if (bbox[2] > hix) bbox[2] = hix;
1290         if (bbox[3] > hiy) bbox[3] = hiy;
1291     }
1292 
1293     /**
1294      * Gets an iterator object to iterate over the spans in this region.
1295      */
1296     public RegionIterator getIterator() {
1297         return new RegionIterator(this);
1298     }
1299 
1300     /**
1301      * Gets a span iterator object that iterates over the spans in this region
1302      */
1303     public SpanIterator getSpanIterator() {
1304         return new RegionSpanIterator(this);
1305     }
1306 
1307     /**
1308      * Gets a span iterator object that iterates over the spans in this region
1309      * but clipped to the bounds given in the argument (xlo, ylo, xhi, yhi).
1310      */
1311     public SpanIterator getSpanIterator(int[] bbox) {
1312         SpanIterator result = getSpanIterator();
1313         result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1314         return result;
1315     }
1316 
1317     /**
1318      * Returns a SpanIterator that is the argument iterator filtered by
1319      * this region.
1320      */
1321     public SpanIterator filter(SpanIterator si) {
1322         if (bands == null) {
1323             si.intersectClipBox(lox, loy, hix, hiy);
1324         } else {
1325             si = new RegionClipSpanIterator(this, si);
1326         }
1327         return si;
1328     }
1329 
1330     @Override
1331     public String toString() {


1378         }
1379         Region r = (Region) o;
1380         if (this.isEmpty()) {
1381             return r.isEmpty();
1382         } else if (r.isEmpty()) {
1383             return false;
1384         }
1385         if (r.lox != this.lox || r.loy != this.loy ||
1386             r.hix != this.hix || r.hiy != this.hiy)
1387         {
1388             return false;
1389         }
1390         if (this.bands == null) {
1391             return (r.bands == null);
1392         } else if (r.bands == null) {
1393             return false;
1394         }
1395         if (this.endIndex != r.endIndex) {
1396             return false;
1397         }
1398         int[] abands = this.bands;
1399         int[] bbands = r.bands;
1400         for (int i = 0; i < endIndex; i++) {
1401             if (abands[i] != bbands[i]) {
1402                 return false;
1403             }
1404         }
1405         return true;
1406     }
1407 }
< prev index next >