1 /*
   2  * Copyright (c) 2006, 2015, 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
  23  * questions.
  24  */
  25 
  26 package java.awt.geom;
  27 
  28 import java.awt.Shape;
  29 import java.awt.Rectangle;
  30 import sun.awt.geom.Curve;
  31 import java.io.Serializable;
  32 import java.io.StreamCorruptedException;
  33 import java.util.Arrays;
  34 
  35 /**
  36  * The {@code Path2D} class provides a simple, yet flexible
  37  * shape which represents an arbitrary geometric path.
  38  * It can fully represent any path which can be iterated by the
  39  * {@link PathIterator} interface including all of its segment
  40  * types and winding rules and it implements all of the
  41  * basic hit testing methods of the {@link Shape} interface.
  42  * <p>
  43  * Use {@link Path2D.Float} when dealing with data that can be represented
  44  * and used with floating point precision.  Use {@link Path2D.Double}
  45  * for data that requires the accuracy or range of double precision.
  46  * <p>
  47  * {@code Path2D} provides exactly those facilities required for
  48  * basic construction and management of a geometric path and
  49  * implementation of the above interfaces with little added
  50  * interpretation.
  51  * If it is useful to manipulate the interiors of closed
  52  * geometric shapes beyond simple hit testing then the
  53  * {@link Area} class provides additional capabilities
  54  * specifically targeted at closed figures.
  55  * While both classes nominally implement the {@code Shape}
  56  * interface, they differ in purpose and together they provide
  57  * two useful views of a geometric shape where {@code Path2D}
  58  * deals primarily with a trajectory formed by path segments
  59  * and {@code Area} deals more with interpretation and manipulation
  60  * of enclosed regions of 2D geometric space.
  61  * <p>
  62  * The {@link PathIterator} interface has more detailed descriptions
  63  * of the types of segments that make up a path and the winding rules
  64  * that control how to determine which regions are inside or outside
  65  * the path.
  66  *
  67  * @author Jim Graham
  68  * @since 1.6
  69  */
  70 public abstract class Path2D implements Shape, Cloneable {
  71     /**
  72      * An even-odd winding rule for determining the interior of
  73      * a path.
  74      *
  75      * @see PathIterator#WIND_EVEN_ODD
  76      * @since 1.6
  77      */
  78     public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
  79 
  80     /**
  81      * A non-zero winding rule for determining the interior of a
  82      * path.
  83      *
  84      * @see PathIterator#WIND_NON_ZERO
  85      * @since 1.6
  86      */
  87     public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
  88 
  89     // For code simplicity, copy these constants to our namespace
  90     // and cast them to byte constants for easy storage.
  91     private static final byte SEG_MOVETO  = (byte) PathIterator.SEG_MOVETO;
  92     private static final byte SEG_LINETO  = (byte) PathIterator.SEG_LINETO;
  93     private static final byte SEG_QUADTO  = (byte) PathIterator.SEG_QUADTO;
  94     private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
  95     private static final byte SEG_CLOSE   = (byte) PathIterator.SEG_CLOSE;
  96 
  97     transient byte[] pointTypes;
  98     transient int numTypes;
  99     transient int numCoords;
 100     transient int windingRule;
 101 
 102     static final int INIT_SIZE = 20;
 103     static final int EXPAND_MAX = 500;
 104     static final int EXPAND_MAX_COORDS = EXPAND_MAX * 2;
 105     static final int EXPAND_MIN = 10; // ensure > 6 (cubics)
 106 
 107     /**
 108      * Constructs a new empty {@code Path2D} object.
 109      * It is assumed that the package sibling subclass that is
 110      * defaulting to this constructor will fill in all values.
 111      *
 112      * @since 1.6
 113      */
 114     /* private protected */
 115     Path2D() {
 116     }
 117 
 118     /**
 119      * Constructs a new {@code Path2D} object from the given
 120      * specified initial values.
 121      * This method is only intended for internal use and should
 122      * not be made public if the other constructors for this class
 123      * are ever exposed.
 124      *
 125      * @param rule the winding rule
 126      * @param initialTypes the size to make the initial array to
 127      *                     store the path segment types
 128      * @since 1.6
 129      */
 130     /* private protected */
 131     Path2D(int rule, int initialTypes) {
 132         setWindingRule(rule);
 133         this.pointTypes = new byte[initialTypes];
 134     }
 135 
 136     abstract float[] cloneCoordsFloat(AffineTransform at);
 137     abstract double[] cloneCoordsDouble(AffineTransform at);
 138     abstract void append(float x, float y);
 139     abstract void append(double x, double y);
 140     abstract Point2D getPoint(int coordindex);
 141     abstract void needRoom(boolean needMove, int newCoords);
 142     abstract int pointCrossings(double px, double py);
 143     abstract int rectCrossings(double rxmin, double rymin,
 144                                double rxmax, double rymax);
 145 
 146     static byte[] expandPointTypes(byte[] oldPointTypes, int needed) {
 147         final int oldSize = oldPointTypes.length;
 148         final int newSizeMin = oldSize + needed;
 149         if (newSizeMin < oldSize) {
 150             // hard overflow failure - we can't even accommodate
 151             // new items without overflowing
 152             throw new ArrayIndexOutOfBoundsException(
 153                           "pointTypes exceeds maximum capacity !");
 154         }
 155         // growth algorithm computation
 156         int grow = oldSize;
 157         if (grow > EXPAND_MAX) {
 158             grow = Math.max(EXPAND_MAX, oldSize >> 3); // 1/8th min
 159         } else if (grow < EXPAND_MIN) {
 160             grow = EXPAND_MIN;
 161         }
 162         assert grow > 0;
 163 
 164         int newSize = oldSize + grow;
 165         if (newSize < newSizeMin) {
 166             // overflow in growth algorithm computation
 167             newSize = Integer.MAX_VALUE;
 168         }
 169         while (true) {
 170             try {
 171                 // try allocating the larger array
 172                 return Arrays.copyOf(oldPointTypes, newSize);
 173             } catch (OutOfMemoryError oome) {
 174                 if (newSize == newSizeMin) {
 175                     throw oome;
 176                 }
 177             }
 178             newSize = newSizeMin + (newSize - newSizeMin) / 2;
 179         }
 180     }
 181 
 182     /**
 183      * The {@code Float} class defines a geometric path with
 184      * coordinates stored in single precision floating point.
 185      *
 186      * @since 1.6
 187      */
 188     public static class Float extends Path2D implements Serializable {
 189         transient float floatCoords[];
 190 
 191         /**
 192          * Constructs a new empty single precision {@code Path2D} object
 193          * with a default winding rule of {@link #WIND_NON_ZERO}.
 194          *
 195          * @since 1.6
 196          */
 197         public Float() {
 198             this(WIND_NON_ZERO, INIT_SIZE);
 199         }
 200 
 201         /**
 202          * Constructs a new empty single precision {@code Path2D} object
 203          * with the specified winding rule to control operations that
 204          * require the interior of the path to be defined.
 205          *
 206          * @param rule the winding rule
 207          * @see #WIND_EVEN_ODD
 208          * @see #WIND_NON_ZERO
 209          * @since 1.6
 210          */
 211         public Float(int rule) {
 212             this(rule, INIT_SIZE);
 213         }
 214 
 215         /**
 216          * Constructs a new empty single precision {@code Path2D} object
 217          * with the specified winding rule and the specified initial
 218          * capacity to store path segments.
 219          * This number is an initial guess as to how many path segments
 220          * will be added to the path, but the storage is expanded as
 221          * needed to store whatever path segments are added.
 222          *
 223          * @param rule the winding rule
 224          * @param initialCapacity the estimate for the number of path segments
 225          *                        in the path
 226          * @see #WIND_EVEN_ODD
 227          * @see #WIND_NON_ZERO
 228          * @since 1.6
 229          */
 230         public Float(int rule, int initialCapacity) {
 231             super(rule, initialCapacity);
 232             floatCoords = new float[initialCapacity * 2];
 233         }
 234 
 235         /**
 236          * Constructs a new single precision {@code Path2D} object
 237          * from an arbitrary {@link Shape} object.
 238          * All of the initial geometry and the winding rule for this path are
 239          * taken from the specified {@code Shape} object.
 240          *
 241          * @param s the specified {@code Shape} object
 242          * @since 1.6
 243          */
 244         public Float(Shape s) {
 245             this(s, null);
 246         }
 247 
 248         /**
 249          * Constructs a new single precision {@code Path2D} object
 250          * from an arbitrary {@link Shape} object, transformed by an
 251          * {@link AffineTransform} object.
 252          * All of the initial geometry and the winding rule for this path are
 253          * taken from the specified {@code Shape} object and transformed
 254          * by the specified {@code AffineTransform} object.
 255          *
 256          * @param s the specified {@code Shape} object
 257          * @param at the specified {@code AffineTransform} object
 258          * @since 1.6
 259          */
 260         public Float(Shape s, AffineTransform at) {
 261             if (s instanceof Path2D) {
 262                 Path2D p2d = (Path2D) s;
 263                 setWindingRule(p2d.windingRule);
 264                 this.numTypes = p2d.numTypes;
 265                 // trim arrays:
 266                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
 267                 this.numCoords = p2d.numCoords;
 268                 this.floatCoords = p2d.cloneCoordsFloat(at);
 269             } else {
 270                 PathIterator pi = s.getPathIterator(at);
 271                 setWindingRule(pi.getWindingRule());
 272                 this.pointTypes = new byte[INIT_SIZE];
 273                 this.floatCoords = new float[INIT_SIZE * 2];
 274                 append(pi, false);
 275             }
 276         }
 277         
 278         @Override
 279         public final Path2D trimToSize() {
 280             // trim arrays:
 281             if (numTypes < pointTypes.length) {
 282                 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
 283             }
 284             if (numCoords < floatCoords.length) {
 285                 this.floatCoords = Arrays.copyOf(floatCoords, numCoords);
 286             }
 287             return this;
 288         }
 289 
 290         @Override
 291         float[] cloneCoordsFloat(AffineTransform at) {
 292             // trim arrays:
 293             float ret[];
 294             if (at == null) {
 295                 ret = Arrays.copyOf(floatCoords, numCoords);
 296             } else {
 297                 ret = new float[numCoords];
 298                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
 299             }
 300             return ret;
 301         }
 302 
 303         @Override
 304         double[] cloneCoordsDouble(AffineTransform at) {
 305             // trim arrays:
 306             double ret[] = new double[numCoords];
 307             if (at == null) {
 308                 for (int i = 0; i < numCoords; i++) {
 309                     ret[i] = floatCoords[i];
 310                 }
 311             } else {
 312                 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
 313             }
 314             return ret;
 315         }
 316 
 317         void append(float x, float y) {
 318             floatCoords[numCoords++] = x;
 319             floatCoords[numCoords++] = y;
 320         }
 321 
 322         void append(double x, double y) {
 323             floatCoords[numCoords++] = (float) x;
 324             floatCoords[numCoords++] = (float) y;
 325         }
 326 
 327         Point2D getPoint(int coordindex) {
 328             return new Point2D.Float(floatCoords[coordindex],
 329                                      floatCoords[coordindex+1]);
 330         }
 331 
 332         @Override
 333         void needRoom(boolean needMove, int newCoords) {
 334             if ((numTypes == 0) && needMove) {
 335                 throw new IllegalPathStateException("missing initial moveto "+
 336                                                     "in path definition");
 337             }
 338             if (numTypes >= pointTypes.length) {
 339                 pointTypes = expandPointTypes(pointTypes, 1);
 340             }
 341             if (numCoords > (floatCoords.length - newCoords)) {
 342                 floatCoords = expandCoords(floatCoords, newCoords);
 343             }
 344         }
 345 
 346         static float[] expandCoords(float[] oldCoords, int needed) {
 347             final int oldSize = oldCoords.length;
 348             final int newSizeMin = oldSize + needed;
 349             if (newSizeMin < oldSize) {
 350                 // hard overflow failure - we can't even accommodate
 351                 // new items without overflowing
 352                 throw new ArrayIndexOutOfBoundsException(
 353                               "coords exceeds maximum capacity !");
 354             }
 355             // growth algorithm computation
 356             int grow = oldSize;
 357             if (grow > EXPAND_MAX_COORDS) {
 358                 grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
 359             } else if (grow < EXPAND_MIN) {
 360                 grow = EXPAND_MIN;
 361             }
 362             assert grow > needed;
 363 
 364             int newSize = oldSize + grow;
 365             if (newSize < newSizeMin) {
 366                 // overflow in growth algorithm computation
 367                 newSize = Integer.MAX_VALUE;
 368             }
 369             while (true) {
 370                 try {
 371                     // try allocating the larger array
 372                     return Arrays.copyOf(oldCoords, newSize);
 373                 } catch (OutOfMemoryError oome) {
 374                     if (newSize == newSizeMin) {
 375                         throw oome;
 376                     }
 377                 }
 378                 newSize = newSizeMin + (newSize - newSizeMin) / 2;
 379             }
 380         }
 381 
 382         /**
 383          * {@inheritDoc}
 384          * @since 1.6
 385          */
 386         public final synchronized void moveTo(double x, double y) {
 387             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
 388                 floatCoords[numCoords-2] = (float) x;
 389                 floatCoords[numCoords-1] = (float) y;
 390             } else {
 391                 needRoom(false, 2);
 392                 pointTypes[numTypes++] = SEG_MOVETO;
 393                 floatCoords[numCoords++] = (float) x;
 394                 floatCoords[numCoords++] = (float) y;
 395             }
 396         }
 397 
 398         /**
 399          * Adds a point to the path by moving to the specified
 400          * coordinates specified in float precision.
 401          * <p>
 402          * This method provides a single precision variant of
 403          * the double precision {@code moveTo()} method on the
 404          * base {@code Path2D} class.
 405          *
 406          * @param x the specified X coordinate
 407          * @param y the specified Y coordinate
 408          * @see Path2D#moveTo
 409          * @since 1.6
 410          */
 411         public final synchronized void moveTo(float x, float y) {
 412             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
 413                 floatCoords[numCoords-2] = x;
 414                 floatCoords[numCoords-1] = y;
 415             } else {
 416                 needRoom(false, 2);
 417                 pointTypes[numTypes++] = SEG_MOVETO;
 418                 floatCoords[numCoords++] = x;
 419                 floatCoords[numCoords++] = y;
 420             }
 421         }
 422 
 423         /**
 424          * {@inheritDoc}
 425          * @since 1.6
 426          */
 427         public final synchronized void lineTo(double x, double y) {
 428             needRoom(true, 2);
 429             pointTypes[numTypes++] = SEG_LINETO;
 430             floatCoords[numCoords++] = (float) x;
 431             floatCoords[numCoords++] = (float) y;
 432         }
 433 
 434         /**
 435          * Adds a point to the path by drawing a straight line from the
 436          * current coordinates to the new specified coordinates
 437          * specified in float precision.
 438          * <p>
 439          * This method provides a single precision variant of
 440          * the double precision {@code lineTo()} method on the
 441          * base {@code Path2D} class.
 442          *
 443          * @param x the specified X coordinate
 444          * @param y the specified Y coordinate
 445          * @see Path2D#lineTo
 446          * @since 1.6
 447          */
 448         public final synchronized void lineTo(float x, float y) {
 449             needRoom(true, 2);
 450             pointTypes[numTypes++] = SEG_LINETO;
 451             floatCoords[numCoords++] = x;
 452             floatCoords[numCoords++] = y;
 453         }
 454 
 455         /**
 456          * {@inheritDoc}
 457          * @since 1.6
 458          */
 459         public final synchronized void quadTo(double x1, double y1,
 460                                               double x2, double y2)
 461         {
 462             needRoom(true, 4);
 463             pointTypes[numTypes++] = SEG_QUADTO;
 464             floatCoords[numCoords++] = (float) x1;
 465             floatCoords[numCoords++] = (float) y1;
 466             floatCoords[numCoords++] = (float) x2;
 467             floatCoords[numCoords++] = (float) y2;
 468         }
 469 
 470         /**
 471          * Adds a curved segment, defined by two new points, to the path by
 472          * drawing a Quadratic curve that intersects both the current
 473          * coordinates and the specified coordinates {@code (x2,y2)},
 474          * using the specified point {@code (x1,y1)} as a quadratic
 475          * parametric control point.
 476          * All coordinates are specified in float precision.
 477          * <p>
 478          * This method provides a single precision variant of
 479          * the double precision {@code quadTo()} method on the
 480          * base {@code Path2D} class.
 481          *
 482          * @param x1 the X coordinate of the quadratic control point
 483          * @param y1 the Y coordinate of the quadratic control point
 484          * @param x2 the X coordinate of the final end point
 485          * @param y2 the Y coordinate of the final end point
 486          * @see Path2D#quadTo
 487          * @since 1.6
 488          */
 489         public final synchronized void quadTo(float x1, float y1,
 490                                               float x2, float y2)
 491         {
 492             needRoom(true, 4);
 493             pointTypes[numTypes++] = SEG_QUADTO;
 494             floatCoords[numCoords++] = x1;
 495             floatCoords[numCoords++] = y1;
 496             floatCoords[numCoords++] = x2;
 497             floatCoords[numCoords++] = y2;
 498         }
 499 
 500         /**
 501          * {@inheritDoc}
 502          * @since 1.6
 503          */
 504         public final synchronized void curveTo(double x1, double y1,
 505                                                double x2, double y2,
 506                                                double x3, double y3)
 507         {
 508             needRoom(true, 6);
 509             pointTypes[numTypes++] = SEG_CUBICTO;
 510             floatCoords[numCoords++] = (float) x1;
 511             floatCoords[numCoords++] = (float) y1;
 512             floatCoords[numCoords++] = (float) x2;
 513             floatCoords[numCoords++] = (float) y2;
 514             floatCoords[numCoords++] = (float) x3;
 515             floatCoords[numCoords++] = (float) y3;
 516         }
 517 
 518         /**
 519          * Adds a curved segment, defined by three new points, to the path by
 520          * drawing a B&eacute;zier curve that intersects both the current
 521          * coordinates and the specified coordinates {@code (x3,y3)},
 522          * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
 523          * B&eacute;zier control points.
 524          * All coordinates are specified in float precision.
 525          * <p>
 526          * This method provides a single precision variant of
 527          * the double precision {@code curveTo()} method on the
 528          * base {@code Path2D} class.
 529          *
 530          * @param x1 the X coordinate of the first B&eacute;zier control point
 531          * @param y1 the Y coordinate of the first B&eacute;zier control point
 532          * @param x2 the X coordinate of the second B&eacute;zier control point
 533          * @param y2 the Y coordinate of the second B&eacute;zier control point
 534          * @param x3 the X coordinate of the final end point
 535          * @param y3 the Y coordinate of the final end point
 536          * @see Path2D#curveTo
 537          * @since 1.6
 538          */
 539         public final synchronized void curveTo(float x1, float y1,
 540                                                float x2, float y2,
 541                                                float x3, float y3)
 542         {
 543             needRoom(true, 6);
 544             pointTypes[numTypes++] = SEG_CUBICTO;
 545             floatCoords[numCoords++] = x1;
 546             floatCoords[numCoords++] = y1;
 547             floatCoords[numCoords++] = x2;
 548             floatCoords[numCoords++] = y2;
 549             floatCoords[numCoords++] = x3;
 550             floatCoords[numCoords++] = y3;
 551         }
 552 
 553         int pointCrossings(double px, double py) {
 554             if (numTypes == 0) {
 555                 return 0;
 556             }
 557             double movx, movy, curx, cury, endx, endy;
 558             float coords[] = floatCoords;
 559             curx = movx = coords[0];
 560             cury = movy = coords[1];
 561             int crossings = 0;
 562             int ci = 2;
 563             for (int i = 1; i < numTypes; i++) {
 564                 switch (pointTypes[i]) {
 565                 case PathIterator.SEG_MOVETO:
 566                     if (cury != movy) {
 567                         crossings +=
 568                             Curve.pointCrossingsForLine(px, py,
 569                                                         curx, cury,
 570                                                         movx, movy);
 571                     }
 572                     movx = curx = coords[ci++];
 573                     movy = cury = coords[ci++];
 574                     break;
 575                 case PathIterator.SEG_LINETO:
 576                     crossings +=
 577                         Curve.pointCrossingsForLine(px, py,
 578                                                     curx, cury,
 579                                                     endx = coords[ci++],
 580                                                     endy = coords[ci++]);
 581                     curx = endx;
 582                     cury = endy;
 583                     break;
 584                 case PathIterator.SEG_QUADTO:
 585                     crossings +=
 586                         Curve.pointCrossingsForQuad(px, py,
 587                                                     curx, cury,
 588                                                     coords[ci++],
 589                                                     coords[ci++],
 590                                                     endx = coords[ci++],
 591                                                     endy = coords[ci++],
 592                                                     0);
 593                     curx = endx;
 594                     cury = endy;
 595                     break;
 596             case PathIterator.SEG_CUBICTO:
 597                     crossings +=
 598                         Curve.pointCrossingsForCubic(px, py,
 599                                                      curx, cury,
 600                                                      coords[ci++],
 601                                                      coords[ci++],
 602                                                      coords[ci++],
 603                                                      coords[ci++],
 604                                                      endx = coords[ci++],
 605                                                      endy = coords[ci++],
 606                                                      0);
 607                     curx = endx;
 608                     cury = endy;
 609                     break;
 610                 case PathIterator.SEG_CLOSE:
 611                     if (cury != movy) {
 612                         crossings +=
 613                             Curve.pointCrossingsForLine(px, py,
 614                                                         curx, cury,
 615                                                         movx, movy);
 616                     }
 617                     curx = movx;
 618                     cury = movy;
 619                     break;
 620                 }
 621             }
 622             if (cury != movy) {
 623                 crossings +=
 624                     Curve.pointCrossingsForLine(px, py,
 625                                                 curx, cury,
 626                                                 movx, movy);
 627             }
 628             return crossings;
 629         }
 630 
 631         int rectCrossings(double rxmin, double rymin,
 632                           double rxmax, double rymax)
 633         {
 634             if (numTypes == 0) {
 635                 return 0;
 636             }
 637             float coords[] = floatCoords;
 638             double curx, cury, movx, movy, endx, endy;
 639             curx = movx = coords[0];
 640             cury = movy = coords[1];
 641             int crossings = 0;
 642             int ci = 2;
 643             for (int i = 1;
 644                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
 645                  i++)
 646             {
 647                 switch (pointTypes[i]) {
 648                 case PathIterator.SEG_MOVETO:
 649                     if (curx != movx || cury != movy) {
 650                         crossings =
 651                             Curve.rectCrossingsForLine(crossings,
 652                                                        rxmin, rymin,
 653                                                        rxmax, rymax,
 654                                                        curx, cury,
 655                                                        movx, movy);
 656                     }
 657                     // Count should always be a multiple of 2 here.
 658                     // assert((crossings & 1) != 0);
 659                     movx = curx = coords[ci++];
 660                     movy = cury = coords[ci++];
 661                     break;
 662                 case PathIterator.SEG_LINETO:
 663                     crossings =
 664                         Curve.rectCrossingsForLine(crossings,
 665                                                    rxmin, rymin,
 666                                                    rxmax, rymax,
 667                                                    curx, cury,
 668                                                    endx = coords[ci++],
 669                                                    endy = coords[ci++]);
 670                     curx = endx;
 671                     cury = endy;
 672                     break;
 673                 case PathIterator.SEG_QUADTO:
 674                     crossings =
 675                         Curve.rectCrossingsForQuad(crossings,
 676                                                    rxmin, rymin,
 677                                                    rxmax, rymax,
 678                                                    curx, cury,
 679                                                    coords[ci++],
 680                                                    coords[ci++],
 681                                                    endx = coords[ci++],
 682                                                    endy = coords[ci++],
 683                                                    0);
 684                     curx = endx;
 685                     cury = endy;
 686                     break;
 687                 case PathIterator.SEG_CUBICTO:
 688                     crossings =
 689                         Curve.rectCrossingsForCubic(crossings,
 690                                                     rxmin, rymin,
 691                                                     rxmax, rymax,
 692                                                     curx, cury,
 693                                                     coords[ci++],
 694                                                     coords[ci++],
 695                                                     coords[ci++],
 696                                                     coords[ci++],
 697                                                     endx = coords[ci++],
 698                                                     endy = coords[ci++],
 699                                                     0);
 700                     curx = endx;
 701                     cury = endy;
 702                     break;
 703                 case PathIterator.SEG_CLOSE:
 704                     if (curx != movx || cury != movy) {
 705                         crossings =
 706                             Curve.rectCrossingsForLine(crossings,
 707                                                        rxmin, rymin,
 708                                                        rxmax, rymax,
 709                                                        curx, cury,
 710                                                        movx, movy);
 711                     }
 712                     curx = movx;
 713                     cury = movy;
 714                     // Count should always be a multiple of 2 here.
 715                     // assert((crossings & 1) != 0);
 716                     break;
 717                 }
 718             }
 719             if (crossings != Curve.RECT_INTERSECTS &&
 720                 (curx != movx || cury != movy))
 721             {
 722                 crossings =
 723                     Curve.rectCrossingsForLine(crossings,
 724                                                rxmin, rymin,
 725                                                rxmax, rymax,
 726                                                curx, cury,
 727                                                movx, movy);
 728             }
 729             // Count should always be a multiple of 2 here.
 730             // assert((crossings & 1) != 0);
 731             return crossings;
 732         }
 733 
 734         /**
 735          * {@inheritDoc}
 736          * @since 1.6
 737          */
 738         public final void append(PathIterator pi, boolean connect) {
 739             float coords[] = new float[6];
 740             while (!pi.isDone()) {
 741                 switch (pi.currentSegment(coords)) {
 742                 case SEG_MOVETO:
 743                     if (!connect || numTypes < 1 || numCoords < 1) {
 744                         moveTo(coords[0], coords[1]);
 745                         break;
 746                     }
 747                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
 748                         floatCoords[numCoords-2] == coords[0] &&
 749                         floatCoords[numCoords-1] == coords[1])
 750                     {
 751                         // Collapse out initial moveto/lineto
 752                         break;
 753                     }
 754                     lineTo(coords[0], coords[1]);
 755                     break;
 756                 case SEG_LINETO:
 757                     lineTo(coords[0], coords[1]);
 758                     break;
 759                 case SEG_QUADTO:
 760                     quadTo(coords[0], coords[1],
 761                            coords[2], coords[3]);
 762                     break;
 763                 case SEG_CUBICTO:
 764                     curveTo(coords[0], coords[1],
 765                             coords[2], coords[3],
 766                             coords[4], coords[5]);
 767                     break;
 768                 case SEG_CLOSE:
 769                     closePath();
 770                     break;
 771                 }
 772                 pi.next();
 773                 connect = false;
 774             }
 775         }
 776 
 777         /**
 778          * {@inheritDoc}
 779          * @since 1.6
 780          */
 781         public final void transform(AffineTransform at) {
 782             at.transform(floatCoords, 0, floatCoords, 0, numCoords / 2);
 783         }
 784 
 785         /**
 786          * {@inheritDoc}
 787          * @since 1.6
 788          */
 789         public final synchronized Rectangle2D getBounds2D() {
 790             float x1, y1, x2, y2;
 791             int i = numCoords;
 792             if (i > 0) {
 793                 y1 = y2 = floatCoords[--i];
 794                 x1 = x2 = floatCoords[--i];
 795                 while (i > 0) {
 796                     float y = floatCoords[--i];
 797                     float x = floatCoords[--i];
 798                     if (x < x1) x1 = x;
 799                     if (y < y1) y1 = y;
 800                     if (x > x2) x2 = x;
 801                     if (y > y2) y2 = y;
 802                 }
 803             } else {
 804                 x1 = y1 = x2 = y2 = 0.0f;
 805             }
 806             return new Rectangle2D.Float(x1, y1, x2 - x1, y2 - y1);
 807         }
 808 
 809         /**
 810          * {@inheritDoc}
 811          * <p>
 812          * The iterator for this class is not multi-threaded safe,
 813          * which means that the {@code Path2D} class does not
 814          * guarantee that modifications to the geometry of this
 815          * {@code Path2D} object do not affect any iterations of
 816          * that geometry that are already in process.
 817          *
 818          * @since 1.6
 819          */
 820         public final PathIterator getPathIterator(AffineTransform at) {
 821             if (at == null) {
 822                 return new CopyIterator(this);
 823             } else {
 824                 return new TxIterator(this, at);
 825             }
 826         }
 827 
 828         /**
 829          * Creates a new object of the same class as this object.
 830          *
 831          * @return     a clone of this instance.
 832          * @exception  OutOfMemoryError    if there is not enough memory.
 833          * @see        java.lang.Cloneable
 834          * @since      1.6
 835          */
 836         public final Object clone() {
 837             // Note: It would be nice to have this return Path2D
 838             // but one of our subclasses (GeneralPath) needs to
 839             // offer "public Object clone()" for backwards
 840             // compatibility so we cannot restrict it further.
 841             // REMIND: Can we do both somehow?
 842             if (this instanceof GeneralPath) {
 843                 return new GeneralPath(this);
 844             } else {
 845                 return new Path2D.Float(this);
 846             }
 847         }
 848 
 849         /*
 850          * JDK 1.6 serialVersionUID
 851          */
 852         private static final long serialVersionUID = 6990832515060788886L;
 853 
 854         /**
 855          * Writes the default serializable fields to the
 856          * {@code ObjectOutputStream} followed by an explicit
 857          * serialization of the path segments stored in this
 858          * path.
 859          *
 860          * @serialData
 861          * <a name="Path2DSerialData"><!-- --></a>
 862          * <ol>
 863          * <li>The default serializable fields.
 864          * There are no default serializable fields as of 1.6.
 865          * <li>followed by
 866          * a byte indicating the storage type of the original object
 867          * as a hint (SERIAL_STORAGE_FLT_ARRAY)
 868          * <li>followed by
 869          * an integer indicating the number of path segments to follow (NP)
 870          * or -1 to indicate an unknown number of path segments follows
 871          * <li>followed by
 872          * an integer indicating the total number of coordinates to follow (NC)
 873          * or -1 to indicate an unknown number of coordinates follows
 874          * (NC should always be even since coordinates always appear in pairs
 875          *  representing an x,y pair)
 876          * <li>followed by
 877          * a byte indicating the winding rule
 878          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
 879          *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
 880          * <li>followed by
 881          * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
 882          * a single byte indicating a path segment type
 883          * followed by one or more pairs of float or double
 884          * values representing the coordinates of the path segment
 885          * <li>followed by
 886          * a byte indicating the end of the path (SERIAL_PATH_END).
 887          * </ol>
 888          * <p>
 889          * The following byte value constants are used in the serialized form
 890          * of {@code Path2D} objects:
 891          * <table>
 892          * <tr>
 893          * <th>Constant Name</th>
 894          * <th>Byte Value</th>
 895          * <th>Followed by</th>
 896          * <th>Description</th>
 897          * </tr>
 898          * <tr>
 899          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
 900          * <td>0x30</td>
 901          * <td></td>
 902          * <td>A hint that the original {@code Path2D} object stored
 903          * the coordinates in a Java array of floats.</td>
 904          * </tr>
 905          * <tr>
 906          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
 907          * <td>0x31</td>
 908          * <td></td>
 909          * <td>A hint that the original {@code Path2D} object stored
 910          * the coordinates in a Java array of doubles.</td>
 911          * </tr>
 912          * <tr>
 913          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
 914          * <td>0x40</td>
 915          * <td>2 floats</td>
 916          * <td>A {@link #moveTo moveTo} path segment follows.</td>
 917          * </tr>
 918          * <tr>
 919          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
 920          * <td>0x41</td>
 921          * <td>2 floats</td>
 922          * <td>A {@link #lineTo lineTo} path segment follows.</td>
 923          * </tr>
 924          * <tr>
 925          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
 926          * <td>0x42</td>
 927          * <td>4 floats</td>
 928          * <td>A {@link #quadTo quadTo} path segment follows.</td>
 929          * </tr>
 930          * <tr>
 931          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
 932          * <td>0x43</td>
 933          * <td>6 floats</td>
 934          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 935          * </tr>
 936          * <tr>
 937          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
 938          * <td>0x50</td>
 939          * <td>2 doubles</td>
 940          * <td>A {@link #moveTo moveTo} path segment follows.</td>
 941          * </tr>
 942          * <tr>
 943          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
 944          * <td>0x51</td>
 945          * <td>2 doubles</td>
 946          * <td>A {@link #lineTo lineTo} path segment follows.</td>
 947          * </tr>
 948          * <tr>
 949          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
 950          * <td>0x52</td>
 951          * <td>4 doubles</td>
 952          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 953          * </tr>
 954          * <tr>
 955          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
 956          * <td>0x53</td>
 957          * <td>6 doubles</td>
 958          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 959          * </tr>
 960          * <tr>
 961          * <td>{@code SERIAL_SEG_CLOSE}</td>
 962          * <td>0x60</td>
 963          * <td></td>
 964          * <td>A {@link #closePath closePath} path segment.</td>
 965          * </tr>
 966          * <tr>
 967          * <td>{@code SERIAL_PATH_END}</td>
 968          * <td>0x61</td>
 969          * <td></td>
 970          * <td>There are no more path segments following.</td>
 971          * </table>
 972          *
 973          * @since 1.6
 974          */
 975         private void writeObject(java.io.ObjectOutputStream s)
 976             throws java.io.IOException
 977         {
 978             super.writeObject(s, false);
 979         }
 980 
 981         /**
 982          * Reads the default serializable fields from the
 983          * {@code ObjectInputStream} followed by an explicit
 984          * serialization of the path segments stored in this
 985          * path.
 986          * <p>
 987          * There are no default serializable fields as of 1.6.
 988          * <p>
 989          * The serial data for this object is described in the
 990          * writeObject method.
 991          *
 992          * @since 1.6
 993          */
 994         private void readObject(java.io.ObjectInputStream s)
 995             throws java.lang.ClassNotFoundException, java.io.IOException
 996         {
 997             super.readObject(s, false);
 998         }
 999 
1000         static class CopyIterator extends Path2D.Iterator {
1001             float floatCoords[];
1002 
1003             CopyIterator(Path2D.Float p2df) {
1004                 super(p2df);
1005                 this.floatCoords = p2df.floatCoords;
1006             }
1007 
1008             public int currentSegment(float[] coords) {
1009                 int type = path.pointTypes[typeIdx];
1010                 int numCoords = curvecoords[type];
1011                 if (numCoords > 0) {
1012                     System.arraycopy(floatCoords, pointIdx,
1013                                      coords, 0, numCoords);
1014                 }
1015                 return type;
1016             }
1017 
1018             public int currentSegment(double[] coords) {
1019                 int type = path.pointTypes[typeIdx];
1020                 int numCoords = curvecoords[type];
1021                 if (numCoords > 0) {
1022                     for (int i = 0; i < numCoords; i++) {
1023                         coords[i] = floatCoords[pointIdx + i];
1024                     }
1025                 }
1026                 return type;
1027             }
1028         }
1029 
1030         static class TxIterator extends Path2D.Iterator {
1031             float floatCoords[];
1032             AffineTransform affine;
1033 
1034             TxIterator(Path2D.Float p2df, AffineTransform at) {
1035                 super(p2df);
1036                 this.floatCoords = p2df.floatCoords;
1037                 this.affine = at;
1038             }
1039 
1040             public int currentSegment(float[] coords) {
1041                 int type = path.pointTypes[typeIdx];
1042                 int numCoords = curvecoords[type];
1043                 if (numCoords > 0) {
1044                     affine.transform(floatCoords, pointIdx,
1045                                      coords, 0, numCoords / 2);
1046                 }
1047                 return type;
1048             }
1049 
1050             public int currentSegment(double[] coords) {
1051                 int type = path.pointTypes[typeIdx];
1052                 int numCoords = curvecoords[type];
1053                 if (numCoords > 0) {
1054                     affine.transform(floatCoords, pointIdx,
1055                                      coords, 0, numCoords / 2);
1056                 }
1057                 return type;
1058             }
1059         }
1060 
1061     }
1062 
1063     /**
1064      * The {@code Double} class defines a geometric path with
1065      * coordinates stored in double precision floating point.
1066      *
1067      * @since 1.6
1068      */
1069     public static class Double extends Path2D implements Serializable {
1070         transient double doubleCoords[];
1071 
1072         /**
1073          * Constructs a new empty double precision {@code Path2D} object
1074          * with a default winding rule of {@link #WIND_NON_ZERO}.
1075          *
1076          * @since 1.6
1077          */
1078         public Double() {
1079             this(WIND_NON_ZERO, INIT_SIZE);
1080         }
1081 
1082         /**
1083          * Constructs a new empty double precision {@code Path2D} object
1084          * with the specified winding rule to control operations that
1085          * require the interior of the path to be defined.
1086          *
1087          * @param rule the winding rule
1088          * @see #WIND_EVEN_ODD
1089          * @see #WIND_NON_ZERO
1090          * @since 1.6
1091          */
1092         public Double(int rule) {
1093             this(rule, INIT_SIZE);
1094         }
1095 
1096         /**
1097          * Constructs a new empty double precision {@code Path2D} object
1098          * with the specified winding rule and the specified initial
1099          * capacity to store path segments.
1100          * This number is an initial guess as to how many path segments
1101          * are in the path, but the storage is expanded as needed to store
1102          * whatever path segments are added to this path.
1103          *
1104          * @param rule the winding rule
1105          * @param initialCapacity the estimate for the number of path segments
1106          *                        in the path
1107          * @see #WIND_EVEN_ODD
1108          * @see #WIND_NON_ZERO
1109          * @since 1.6
1110          */
1111         public Double(int rule, int initialCapacity) {
1112             super(rule, initialCapacity);
1113             doubleCoords = new double[initialCapacity * 2];
1114         }
1115 
1116         /**
1117          * Constructs a new double precision {@code Path2D} object
1118          * from an arbitrary {@link Shape} object.
1119          * All of the initial geometry and the winding rule for this path are
1120          * taken from the specified {@code Shape} object.
1121          *
1122          * @param s the specified {@code Shape} object
1123          * @since 1.6
1124          */
1125         public Double(Shape s) {
1126             this(s, null);
1127         }
1128 
1129         /**
1130          * Constructs a new double precision {@code Path2D} object
1131          * from an arbitrary {@link Shape} object, transformed by an
1132          * {@link AffineTransform} object.
1133          * All of the initial geometry and the winding rule for this path are
1134          * taken from the specified {@code Shape} object and transformed
1135          * by the specified {@code AffineTransform} object.
1136          *
1137          * @param s the specified {@code Shape} object
1138          * @param at the specified {@code AffineTransform} object
1139          * @since 1.6
1140          */
1141         public Double(Shape s, AffineTransform at) {
1142             if (s instanceof Path2D) {
1143                 Path2D p2d = (Path2D) s;
1144                 setWindingRule(p2d.windingRule);
1145                 this.numTypes = p2d.numTypes;
1146                 // trim arrays:
1147                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
1148                 this.numCoords = p2d.numCoords;
1149                 this.doubleCoords = p2d.cloneCoordsDouble(at);
1150             } else {
1151                 PathIterator pi = s.getPathIterator(at);
1152                 setWindingRule(pi.getWindingRule());
1153                 this.pointTypes = new byte[INIT_SIZE];
1154                 this.doubleCoords = new double[INIT_SIZE * 2];
1155                 append(pi, false);
1156             }
1157         }
1158         
1159         @Override
1160         public final Path2D trimToSize() {
1161             // trim arrays:
1162             if (numTypes < pointTypes.length) {
1163                 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
1164             }
1165             if (numCoords < doubleCoords.length) {
1166                 this.doubleCoords = Arrays.copyOf(doubleCoords, numCoords);
1167             }
1168             return this;
1169         }
1170 
1171         @Override
1172         float[] cloneCoordsFloat(AffineTransform at) {
1173             // trim arrays:
1174             float ret[] = new float[numCoords];
1175             if (at == null) {
1176                 for (int i = 0; i < numCoords; i++) {
1177                     ret[i] = (float) doubleCoords[i];
1178                 }
1179             } else {
1180                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1181             }
1182             return ret;
1183         }
1184 
1185         @Override
1186         double[] cloneCoordsDouble(AffineTransform at) {
1187             // trim arrays:
1188             double ret[];
1189             if (at == null) {
1190                 ret = Arrays.copyOf(doubleCoords, numCoords);
1191             } else {
1192                 ret = new double[numCoords];
1193                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1194             }
1195             return ret;
1196         }
1197 
1198         void append(float x, float y) {
1199             doubleCoords[numCoords++] = x;
1200             doubleCoords[numCoords++] = y;
1201         }
1202 
1203         void append(double x, double y) {
1204             doubleCoords[numCoords++] = x;
1205             doubleCoords[numCoords++] = y;
1206         }
1207 
1208         Point2D getPoint(int coordindex) {
1209             return new Point2D.Double(doubleCoords[coordindex],
1210                                       doubleCoords[coordindex+1]);
1211         }
1212 
1213         @Override
1214         void needRoom(boolean needMove, int newCoords) {
1215             if ((numTypes == 0) && needMove) {
1216                 throw new IllegalPathStateException("missing initial moveto "+
1217                                                     "in path definition");
1218             }
1219             if (numTypes >= pointTypes.length) {
1220                 pointTypes = expandPointTypes(pointTypes, 1);
1221             }
1222             if (numCoords > (doubleCoords.length - newCoords)) {
1223                 doubleCoords = expandCoords(doubleCoords, newCoords);
1224             }
1225         }
1226 
1227         static double[] expandCoords(double[] oldCoords, int needed) {
1228             final int oldSize = oldCoords.length;
1229             final int newSizeMin = oldSize + needed;
1230             if (newSizeMin < oldSize) {
1231                 // hard overflow failure - we can't even accommodate
1232                 // new items without overflowing
1233                 throw new ArrayIndexOutOfBoundsException(
1234                               "coords exceeds maximum capacity !");
1235             }
1236             // growth algorithm computation
1237             int grow = oldSize;
1238             if (grow > EXPAND_MAX_COORDS) {
1239                 grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
1240             } else if (grow < EXPAND_MIN) {
1241                 grow = EXPAND_MIN;
1242             }
1243             assert grow > needed;
1244 
1245             int newSize = oldSize + grow;
1246             if (newSize < newSizeMin) {
1247                 // overflow in growth algorithm computation
1248                 newSize = Integer.MAX_VALUE;
1249             }
1250             while (true) {
1251                 try {
1252                     // try allocating the larger array
1253                     return Arrays.copyOf(oldCoords, newSize);
1254                 } catch (OutOfMemoryError oome) {
1255                     if (newSize == newSizeMin) {
1256                         throw oome;
1257                     }
1258                 }
1259                 newSize = newSizeMin + (newSize - newSizeMin) / 2;
1260             }
1261         }
1262 
1263         /**
1264          * {@inheritDoc}
1265          * @since 1.6
1266          */
1267         public final synchronized void moveTo(double x, double y) {
1268             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1269                 doubleCoords[numCoords-2] = x;
1270                 doubleCoords[numCoords-1] = y;
1271             } else {
1272                 needRoom(false, 2);
1273                 pointTypes[numTypes++] = SEG_MOVETO;
1274                 doubleCoords[numCoords++] = x;
1275                 doubleCoords[numCoords++] = y;
1276             }
1277         }
1278 
1279         /**
1280          * {@inheritDoc}
1281          * @since 1.6
1282          */
1283         public final synchronized void lineTo(double x, double y) {
1284             needRoom(true, 2);
1285             pointTypes[numTypes++] = SEG_LINETO;
1286             doubleCoords[numCoords++] = x;
1287             doubleCoords[numCoords++] = y;
1288         }
1289 
1290         /**
1291          * {@inheritDoc}
1292          * @since 1.6
1293          */
1294         public final synchronized void quadTo(double x1, double y1,
1295                                               double x2, double y2)
1296         {
1297             needRoom(true, 4);
1298             pointTypes[numTypes++] = SEG_QUADTO;
1299             doubleCoords[numCoords++] = x1;
1300             doubleCoords[numCoords++] = y1;
1301             doubleCoords[numCoords++] = x2;
1302             doubleCoords[numCoords++] = y2;
1303         }
1304 
1305         /**
1306          * {@inheritDoc}
1307          * @since 1.6
1308          */
1309         public final synchronized void curveTo(double x1, double y1,
1310                                                double x2, double y2,
1311                                                double x3, double y3)
1312         {
1313             needRoom(true, 6);
1314             pointTypes[numTypes++] = SEG_CUBICTO;
1315             doubleCoords[numCoords++] = x1;
1316             doubleCoords[numCoords++] = y1;
1317             doubleCoords[numCoords++] = x2;
1318             doubleCoords[numCoords++] = y2;
1319             doubleCoords[numCoords++] = x3;
1320             doubleCoords[numCoords++] = y3;
1321         }
1322 
1323         int pointCrossings(double px, double py) {
1324             if (numTypes == 0) {
1325                 return 0;
1326             }
1327             double movx, movy, curx, cury, endx, endy;
1328             double coords[] = doubleCoords;
1329             curx = movx = coords[0];
1330             cury = movy = coords[1];
1331             int crossings = 0;
1332             int ci = 2;
1333             for (int i = 1; i < numTypes; i++) {
1334                 switch (pointTypes[i]) {
1335                 case PathIterator.SEG_MOVETO:
1336                     if (cury != movy) {
1337                         crossings +=
1338                             Curve.pointCrossingsForLine(px, py,
1339                                                         curx, cury,
1340                                                         movx, movy);
1341                     }
1342                     movx = curx = coords[ci++];
1343                     movy = cury = coords[ci++];
1344                     break;
1345                 case PathIterator.SEG_LINETO:
1346                     crossings +=
1347                         Curve.pointCrossingsForLine(px, py,
1348                                                     curx, cury,
1349                                                     endx = coords[ci++],
1350                                                     endy = coords[ci++]);
1351                     curx = endx;
1352                     cury = endy;
1353                     break;
1354                 case PathIterator.SEG_QUADTO:
1355                     crossings +=
1356                         Curve.pointCrossingsForQuad(px, py,
1357                                                     curx, cury,
1358                                                     coords[ci++],
1359                                                     coords[ci++],
1360                                                     endx = coords[ci++],
1361                                                     endy = coords[ci++],
1362                                                     0);
1363                     curx = endx;
1364                     cury = endy;
1365                     break;
1366             case PathIterator.SEG_CUBICTO:
1367                     crossings +=
1368                         Curve.pointCrossingsForCubic(px, py,
1369                                                      curx, cury,
1370                                                      coords[ci++],
1371                                                      coords[ci++],
1372                                                      coords[ci++],
1373                                                      coords[ci++],
1374                                                      endx = coords[ci++],
1375                                                      endy = coords[ci++],
1376                                                      0);
1377                     curx = endx;
1378                     cury = endy;
1379                     break;
1380                 case PathIterator.SEG_CLOSE:
1381                     if (cury != movy) {
1382                         crossings +=
1383                             Curve.pointCrossingsForLine(px, py,
1384                                                         curx, cury,
1385                                                         movx, movy);
1386                     }
1387                     curx = movx;
1388                     cury = movy;
1389                     break;
1390                 }
1391             }
1392             if (cury != movy) {
1393                 crossings +=
1394                     Curve.pointCrossingsForLine(px, py,
1395                                                 curx, cury,
1396                                                 movx, movy);
1397             }
1398             return crossings;
1399         }
1400 
1401         int rectCrossings(double rxmin, double rymin,
1402                           double rxmax, double rymax)
1403         {
1404             if (numTypes == 0) {
1405                 return 0;
1406             }
1407             double coords[] = doubleCoords;
1408             double curx, cury, movx, movy, endx, endy;
1409             curx = movx = coords[0];
1410             cury = movy = coords[1];
1411             int crossings = 0;
1412             int ci = 2;
1413             for (int i = 1;
1414                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
1415                  i++)
1416             {
1417                 switch (pointTypes[i]) {
1418                 case PathIterator.SEG_MOVETO:
1419                     if (curx != movx || cury != movy) {
1420                         crossings =
1421                             Curve.rectCrossingsForLine(crossings,
1422                                                        rxmin, rymin,
1423                                                        rxmax, rymax,
1424                                                        curx, cury,
1425                                                        movx, movy);
1426                     }
1427                     // Count should always be a multiple of 2 here.
1428                     // assert((crossings & 1) != 0);
1429                     movx = curx = coords[ci++];
1430                     movy = cury = coords[ci++];
1431                     break;
1432                 case PathIterator.SEG_LINETO:
1433                     endx = coords[ci++];
1434                     endy = coords[ci++];
1435                     crossings =
1436                         Curve.rectCrossingsForLine(crossings,
1437                                                    rxmin, rymin,
1438                                                    rxmax, rymax,
1439                                                    curx, cury,
1440                                                    endx, endy);
1441                     curx = endx;
1442                     cury = endy;
1443                     break;
1444                 case PathIterator.SEG_QUADTO:
1445                     crossings =
1446                         Curve.rectCrossingsForQuad(crossings,
1447                                                    rxmin, rymin,
1448                                                    rxmax, rymax,
1449                                                    curx, cury,
1450                                                    coords[ci++],
1451                                                    coords[ci++],
1452                                                    endx = coords[ci++],
1453                                                    endy = coords[ci++],
1454                                                    0);
1455                     curx = endx;
1456                     cury = endy;
1457                     break;
1458                 case PathIterator.SEG_CUBICTO:
1459                     crossings =
1460                         Curve.rectCrossingsForCubic(crossings,
1461                                                     rxmin, rymin,
1462                                                     rxmax, rymax,
1463                                                     curx, cury,
1464                                                     coords[ci++],
1465                                                     coords[ci++],
1466                                                     coords[ci++],
1467                                                     coords[ci++],
1468                                                     endx = coords[ci++],
1469                                                     endy = coords[ci++],
1470                                                     0);
1471                     curx = endx;
1472                     cury = endy;
1473                     break;
1474                 case PathIterator.SEG_CLOSE:
1475                     if (curx != movx || cury != movy) {
1476                         crossings =
1477                             Curve.rectCrossingsForLine(crossings,
1478                                                        rxmin, rymin,
1479                                                        rxmax, rymax,
1480                                                        curx, cury,
1481                                                        movx, movy);
1482                     }
1483                     curx = movx;
1484                     cury = movy;
1485                     // Count should always be a multiple of 2 here.
1486                     // assert((crossings & 1) != 0);
1487                     break;
1488                 }
1489             }
1490             if (crossings != Curve.RECT_INTERSECTS &&
1491                 (curx != movx || cury != movy))
1492             {
1493                 crossings =
1494                     Curve.rectCrossingsForLine(crossings,
1495                                                rxmin, rymin,
1496                                                rxmax, rymax,
1497                                                curx, cury,
1498                                                movx, movy);
1499             }
1500             // Count should always be a multiple of 2 here.
1501             // assert((crossings & 1) != 0);
1502             return crossings;
1503         }
1504 
1505         /**
1506          * {@inheritDoc}
1507          * @since 1.6
1508          */
1509         public final void append(PathIterator pi, boolean connect) {
1510             double coords[] = new double[6];
1511             while (!pi.isDone()) {
1512                 switch (pi.currentSegment(coords)) {
1513                 case SEG_MOVETO:
1514                     if (!connect || numTypes < 1 || numCoords < 1) {
1515                         moveTo(coords[0], coords[1]);
1516                         break;
1517                     }
1518                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1519                         doubleCoords[numCoords-2] == coords[0] &&
1520                         doubleCoords[numCoords-1] == coords[1])
1521                     {
1522                         // Collapse out initial moveto/lineto
1523                         break;
1524                     }
1525                     lineTo(coords[0], coords[1]);
1526                     break;
1527                 case SEG_LINETO:
1528                     lineTo(coords[0], coords[1]);
1529                     break;
1530                 case SEG_QUADTO:
1531                     quadTo(coords[0], coords[1],
1532                            coords[2], coords[3]);
1533                     break;
1534                 case SEG_CUBICTO:
1535                     curveTo(coords[0], coords[1],
1536                             coords[2], coords[3],
1537                             coords[4], coords[5]);
1538                     break;
1539                 case SEG_CLOSE:
1540                     closePath();
1541                     break;
1542                 }
1543                 pi.next();
1544                 connect = false;
1545             }
1546         }
1547 
1548         /**
1549          * {@inheritDoc}
1550          * @since 1.6
1551          */
1552         public final void transform(AffineTransform at) {
1553             at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1554         }
1555 
1556         /**
1557          * {@inheritDoc}
1558          * @since 1.6
1559          */
1560         public final synchronized Rectangle2D getBounds2D() {
1561             double x1, y1, x2, y2;
1562             int i = numCoords;
1563             if (i > 0) {
1564                 y1 = y2 = doubleCoords[--i];
1565                 x1 = x2 = doubleCoords[--i];
1566                 while (i > 0) {
1567                     double y = doubleCoords[--i];
1568                     double x = doubleCoords[--i];
1569                     if (x < x1) x1 = x;
1570                     if (y < y1) y1 = y;
1571                     if (x > x2) x2 = x;
1572                     if (y > y2) y2 = y;
1573                 }
1574             } else {
1575                 x1 = y1 = x2 = y2 = 0.0;
1576             }
1577             return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
1578         }
1579 
1580         /**
1581          * {@inheritDoc}
1582          * <p>
1583          * The iterator for this class is not multi-threaded safe,
1584          * which means that the {@code Path2D} class does not
1585          * guarantee that modifications to the geometry of this
1586          * {@code Path2D} object do not affect any iterations of
1587          * that geometry that are already in process.
1588          *
1589          * @param at an {@code AffineTransform}
1590          * @return a new {@code PathIterator} that iterates along the boundary
1591          *         of this {@code Shape} and provides access to the geometry
1592          *         of this {@code Shape}'s outline
1593          * @since 1.6
1594          */
1595         public final PathIterator getPathIterator(AffineTransform at) {
1596             if (at == null) {
1597                 return new CopyIterator(this);
1598             } else {
1599                 return new TxIterator(this, at);
1600             }
1601         }
1602 
1603         /**
1604          * Creates a new object of the same class as this object.
1605          *
1606          * @return     a clone of this instance.
1607          * @exception  OutOfMemoryError    if there is not enough memory.
1608          * @see        java.lang.Cloneable
1609          * @since      1.6
1610          */
1611         public final Object clone() {
1612             // Note: It would be nice to have this return Path2D
1613             // but one of our subclasses (GeneralPath) needs to
1614             // offer "public Object clone()" for backwards
1615             // compatibility so we cannot restrict it further.
1616             // REMIND: Can we do both somehow?
1617             return new Path2D.Double(this);
1618         }
1619 
1620         /*
1621          * JDK 1.6 serialVersionUID
1622          */
1623         private static final long serialVersionUID = 1826762518450014216L;
1624 
1625         /**
1626          * Writes the default serializable fields to the
1627          * {@code ObjectOutputStream} followed by an explicit
1628          * serialization of the path segments stored in this
1629          * path.
1630          *
1631          * @serialData
1632          * <a name="Path2DSerialData"><!-- --></a>
1633          * <ol>
1634          * <li>The default serializable fields.
1635          * There are no default serializable fields as of 1.6.
1636          * <li>followed by
1637          * a byte indicating the storage type of the original object
1638          * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1639          * <li>followed by
1640          * an integer indicating the number of path segments to follow (NP)
1641          * or -1 to indicate an unknown number of path segments follows
1642          * <li>followed by
1643          * an integer indicating the total number of coordinates to follow (NC)
1644          * or -1 to indicate an unknown number of coordinates follows
1645          * (NC should always be even since coordinates always appear in pairs
1646          *  representing an x,y pair)
1647          * <li>followed by
1648          * a byte indicating the winding rule
1649          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1650          *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
1651          * <li>followed by
1652          * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
1653          * a single byte indicating a path segment type
1654          * followed by one or more pairs of float or double
1655          * values representing the coordinates of the path segment
1656          * <li>followed by
1657          * a byte indicating the end of the path (SERIAL_PATH_END).
1658          * </ol>
1659          * <p>
1660          * The following byte value constants are used in the serialized form
1661          * of {@code Path2D} objects:
1662          * <table>
1663          * <tr>
1664          * <th>Constant Name</th>
1665          * <th>Byte Value</th>
1666          * <th>Followed by</th>
1667          * <th>Description</th>
1668          * </tr>
1669          * <tr>
1670          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1671          * <td>0x30</td>
1672          * <td></td>
1673          * <td>A hint that the original {@code Path2D} object stored
1674          * the coordinates in a Java array of floats.</td>
1675          * </tr>
1676          * <tr>
1677          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1678          * <td>0x31</td>
1679          * <td></td>
1680          * <td>A hint that the original {@code Path2D} object stored
1681          * the coordinates in a Java array of doubles.</td>
1682          * </tr>
1683          * <tr>
1684          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1685          * <td>0x40</td>
1686          * <td>2 floats</td>
1687          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1688          * </tr>
1689          * <tr>
1690          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1691          * <td>0x41</td>
1692          * <td>2 floats</td>
1693          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1694          * </tr>
1695          * <tr>
1696          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1697          * <td>0x42</td>
1698          * <td>4 floats</td>
1699          * <td>A {@link #quadTo quadTo} path segment follows.</td>
1700          * </tr>
1701          * <tr>
1702          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1703          * <td>0x43</td>
1704          * <td>6 floats</td>
1705          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1706          * </tr>
1707          * <tr>
1708          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1709          * <td>0x50</td>
1710          * <td>2 doubles</td>
1711          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1712          * </tr>
1713          * <tr>
1714          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1715          * <td>0x51</td>
1716          * <td>2 doubles</td>
1717          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1718          * </tr>
1719          * <tr>
1720          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1721          * <td>0x52</td>
1722          * <td>4 doubles</td>
1723          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1724          * </tr>
1725          * <tr>
1726          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1727          * <td>0x53</td>
1728          * <td>6 doubles</td>
1729          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1730          * </tr>
1731          * <tr>
1732          * <td>{@code SERIAL_SEG_CLOSE}</td>
1733          * <td>0x60</td>
1734          * <td></td>
1735          * <td>A {@link #closePath closePath} path segment.</td>
1736          * </tr>
1737          * <tr>
1738          * <td>{@code SERIAL_PATH_END}</td>
1739          * <td>0x61</td>
1740          * <td></td>
1741          * <td>There are no more path segments following.</td>
1742          * </table>
1743          *
1744          * @since 1.6
1745          */
1746         private void writeObject(java.io.ObjectOutputStream s)
1747             throws java.io.IOException
1748         {
1749             super.writeObject(s, true);
1750         }
1751 
1752         /**
1753          * Reads the default serializable fields from the
1754          * {@code ObjectInputStream} followed by an explicit
1755          * serialization of the path segments stored in this
1756          * path.
1757          * <p>
1758          * There are no default serializable fields as of 1.6.
1759          * <p>
1760          * The serial data for this object is described in the
1761          * writeObject method.
1762          *
1763          * @since 1.6
1764          */
1765         private void readObject(java.io.ObjectInputStream s)
1766             throws java.lang.ClassNotFoundException, java.io.IOException
1767         {
1768             super.readObject(s, true);
1769         }
1770 
1771         static class CopyIterator extends Path2D.Iterator {
1772             double doubleCoords[];
1773 
1774             CopyIterator(Path2D.Double p2dd) {
1775                 super(p2dd);
1776                 this.doubleCoords = p2dd.doubleCoords;
1777             }
1778 
1779             public int currentSegment(float[] coords) {
1780                 int type = path.pointTypes[typeIdx];
1781                 int numCoords = curvecoords[type];
1782                 if (numCoords > 0) {
1783                     for (int i = 0; i < numCoords; i++) {
1784                         coords[i] = (float) doubleCoords[pointIdx + i];
1785                     }
1786                 }
1787                 return type;
1788             }
1789 
1790             public int currentSegment(double[] coords) {
1791                 int type = path.pointTypes[typeIdx];
1792                 int numCoords = curvecoords[type];
1793                 if (numCoords > 0) {
1794                     System.arraycopy(doubleCoords, pointIdx,
1795                                      coords, 0, numCoords);
1796                 }
1797                 return type;
1798             }
1799         }
1800 
1801         static class TxIterator extends Path2D.Iterator {
1802             double doubleCoords[];
1803             AffineTransform affine;
1804 
1805             TxIterator(Path2D.Double p2dd, AffineTransform at) {
1806                 super(p2dd);
1807                 this.doubleCoords = p2dd.doubleCoords;
1808                 this.affine = at;
1809             }
1810 
1811             public int currentSegment(float[] coords) {
1812                 int type = path.pointTypes[typeIdx];
1813                 int numCoords = curvecoords[type];
1814                 if (numCoords > 0) {
1815                     affine.transform(doubleCoords, pointIdx,
1816                                      coords, 0, numCoords / 2);
1817                 }
1818                 return type;
1819             }
1820 
1821             public int currentSegment(double[] coords) {
1822                 int type = path.pointTypes[typeIdx];
1823                 int numCoords = curvecoords[type];
1824                 if (numCoords > 0) {
1825                     affine.transform(doubleCoords, pointIdx,
1826                                      coords, 0, numCoords / 2);
1827                 }
1828                 return type;
1829             }
1830         }
1831     }
1832 
1833     /**
1834      * Adds a point to the path by moving to the specified
1835      * coordinates specified in double precision.
1836      *
1837      * @param x the specified X coordinate
1838      * @param y the specified Y coordinate
1839      * @since 1.6
1840      */
1841     public abstract void moveTo(double x, double y);
1842 
1843     /**
1844      * Adds a point to the path by drawing a straight line from the
1845      * current coordinates to the new specified coordinates
1846      * specified in double precision.
1847      *
1848      * @param x the specified X coordinate
1849      * @param y the specified Y coordinate
1850      * @since 1.6
1851      */
1852     public abstract void lineTo(double x, double y);
1853 
1854     /**
1855      * Adds a curved segment, defined by two new points, to the path by
1856      * drawing a Quadratic curve that intersects both the current
1857      * coordinates and the specified coordinates {@code (x2,y2)},
1858      * using the specified point {@code (x1,y1)} as a quadratic
1859      * parametric control point.
1860      * All coordinates are specified in double precision.
1861      *
1862      * @param x1 the X coordinate of the quadratic control point
1863      * @param y1 the Y coordinate of the quadratic control point
1864      * @param x2 the X coordinate of the final end point
1865      * @param y2 the Y coordinate of the final end point
1866      * @since 1.6
1867      */
1868     public abstract void quadTo(double x1, double y1,
1869                                 double x2, double y2);
1870 
1871     /**
1872      * Adds a curved segment, defined by three new points, to the path by
1873      * drawing a B&eacute;zier curve that intersects both the current
1874      * coordinates and the specified coordinates {@code (x3,y3)},
1875      * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1876      * B&eacute;zier control points.
1877      * All coordinates are specified in double precision.
1878      *
1879      * @param x1 the X coordinate of the first B&eacute;zier control point
1880      * @param y1 the Y coordinate of the first B&eacute;zier control point
1881      * @param x2 the X coordinate of the second B&eacute;zier control point
1882      * @param y2 the Y coordinate of the second B&eacute;zier control point
1883      * @param x3 the X coordinate of the final end point
1884      * @param y3 the Y coordinate of the final end point
1885      * @since 1.6
1886      */
1887     public abstract void curveTo(double x1, double y1,
1888                                  double x2, double y2,
1889                                  double x3, double y3);
1890 
1891     /**
1892      * Closes the current subpath by drawing a straight line back to
1893      * the coordinates of the last {@code moveTo}.  If the path is already
1894      * closed then this method has no effect.
1895      *
1896      * @since 1.6
1897      */
1898     public final synchronized void closePath() {
1899         if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1900             needRoom(true, 0);
1901             pointTypes[numTypes++] = SEG_CLOSE;
1902         }
1903     }
1904 
1905     /**
1906      * Appends the geometry of the specified {@code Shape} object to the
1907      * path, possibly connecting the new geometry to the existing path
1908      * segments with a line segment.
1909      * If the {@code connect} parameter is {@code true} and the
1910      * path is not empty then any initial {@code moveTo} in the
1911      * geometry of the appended {@code Shape}
1912      * is turned into a {@code lineTo} segment.
1913      * If the destination coordinates of such a connecting {@code lineTo}
1914      * segment match the ending coordinates of a currently open
1915      * subpath then the segment is omitted as superfluous.
1916      * The winding rule of the specified {@code Shape} is ignored
1917      * and the appended geometry is governed by the winding
1918      * rule specified for this path.
1919      *
1920      * @param s the {@code Shape} whose geometry is appended
1921      *          to this path
1922      * @param connect a boolean to control whether or not to turn an initial
1923      *                {@code moveTo} segment into a {@code lineTo} segment
1924      *                to connect the new geometry to the existing path
1925      * @since 1.6
1926      */
1927     public final void append(Shape s, boolean connect) {
1928         append(s.getPathIterator(null), connect);
1929     }
1930 
1931     /**
1932      * Appends the geometry of the specified
1933      * {@link PathIterator} object
1934      * to the path, possibly connecting the new geometry to the existing
1935      * path segments with a line segment.
1936      * If the {@code connect} parameter is {@code true} and the
1937      * path is not empty then any initial {@code moveTo} in the
1938      * geometry of the appended {@code Shape} is turned into a
1939      * {@code lineTo} segment.
1940      * If the destination coordinates of such a connecting {@code lineTo}
1941      * segment match the ending coordinates of a currently open
1942      * subpath then the segment is omitted as superfluous.
1943      * The winding rule of the specified {@code Shape} is ignored
1944      * and the appended geometry is governed by the winding
1945      * rule specified for this path.
1946      *
1947      * @param pi the {@code PathIterator} whose geometry is appended to
1948      *           this path
1949      * @param connect a boolean to control whether or not to turn an initial
1950      *                {@code moveTo} segment into a {@code lineTo} segment
1951      *                to connect the new geometry to the existing path
1952      * @since 1.6
1953      */
1954     public abstract void append(PathIterator pi, boolean connect);
1955 
1956     /**
1957      * Returns the fill style winding rule.
1958      *
1959      * @return an integer representing the current winding rule.
1960      * @see #WIND_EVEN_ODD
1961      * @see #WIND_NON_ZERO
1962      * @see #setWindingRule
1963      * @since 1.6
1964      */
1965     public final synchronized int getWindingRule() {
1966         return windingRule;
1967     }
1968 
1969     /**
1970      * Sets the winding rule for this path to the specified value.
1971      *
1972      * @param rule an integer representing the specified
1973      *             winding rule
1974      * @exception IllegalArgumentException if
1975      *          {@code rule} is not either
1976      *          {@link #WIND_EVEN_ODD} or
1977      *          {@link #WIND_NON_ZERO}
1978      * @see #getWindingRule
1979      * @since 1.6
1980      */
1981     public final void setWindingRule(int rule) {
1982         if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1983             throw new IllegalArgumentException("winding rule must be "+
1984                                                "WIND_EVEN_ODD or "+
1985                                                "WIND_NON_ZERO");
1986         }
1987         windingRule = rule;
1988     }
1989 
1990     /**
1991      * Returns the coordinates most recently added to the end of the path
1992      * as a {@link Point2D} object.
1993      *
1994      * @return a {@code Point2D} object containing the ending coordinates of
1995      *         the path or {@code null} if there are no points in the path.
1996      * @since 1.6
1997      */
1998     public final synchronized Point2D getCurrentPoint() {
1999         int index = numCoords;
2000         if (numTypes < 1 || index < 1) {
2001             return null;
2002         }
2003         if (pointTypes[numTypes - 1] == SEG_CLOSE) {
2004         loop:
2005             for (int i = numTypes - 2; i > 0; i--) {
2006                 switch (pointTypes[i]) {
2007                 case SEG_MOVETO:
2008                     break loop;
2009                 case SEG_LINETO:
2010                     index -= 2;
2011                     break;
2012                 case SEG_QUADTO:
2013                     index -= 4;
2014                     break;
2015                 case SEG_CUBICTO:
2016                     index -= 6;
2017                     break;
2018                 case SEG_CLOSE:
2019                     break;
2020                 }
2021             }
2022         }
2023         return getPoint(index - 2);
2024     }
2025 
2026     /**
2027      * Resets the path to empty.  The append position is set back to the
2028      * beginning of the path and all coordinates and point types are
2029      * forgotten.
2030      *
2031      * @since 1.6
2032      */
2033     public final synchronized void reset() {
2034         numTypes = numCoords = 0;
2035     }
2036 
2037     /**
2038      * Transforms the geometry of this path using the specified
2039      * {@link AffineTransform}.
2040      * The geometry is transformed in place, which permanently changes the
2041      * boundary defined by this object.
2042      *
2043      * @param at the {@code AffineTransform} used to transform the area
2044      * @since 1.6
2045      */
2046     public abstract void transform(AffineTransform at);
2047 
2048     /**
2049      * Returns a new {@code Shape} representing a transformed version
2050      * of this {@code Path2D}.
2051      * Note that the exact type and coordinate precision of the return
2052      * value is not specified for this method.
2053      * The method will return a Shape that contains no less precision
2054      * for the transformed geometry than this {@code Path2D} currently
2055      * maintains, but it may contain no more precision either.
2056      * If the tradeoff of precision vs. storage size in the result is
2057      * important then the convenience constructors in the
2058      * {@link Path2D.Float#Float(Shape, AffineTransform) Path2D.Float}
2059      * and
2060      * {@link Path2D.Double#Double(Shape, AffineTransform) Path2D.Double}
2061      * subclasses should be used to make the choice explicit.
2062      *
2063      * @param at the {@code AffineTransform} used to transform a
2064      *           new {@code Shape}.
2065      * @return a new {@code Shape}, transformed with the specified
2066      *         {@code AffineTransform}.
2067      * @since 1.6
2068      */
2069     public final synchronized Shape createTransformedShape(AffineTransform at) {
2070         Path2D p2d = (Path2D) clone();
2071         if (at != null) {
2072             p2d.transform(at);
2073         }
2074         return p2d;
2075     }
2076 
2077     /**
2078      * {@inheritDoc}
2079      * @since 1.6
2080      */
2081     public final Rectangle getBounds() {
2082         return getBounds2D().getBounds();
2083     }
2084 
2085     /**
2086      * Tests if the specified coordinates are inside the closed
2087      * boundary of the specified {@link PathIterator}.
2088      * <p>
2089      * This method provides a basic facility for implementors of
2090      * the {@link Shape} interface to implement support for the
2091      * {@link Shape#contains(double, double)} method.
2092      *
2093      * @param pi the specified {@code PathIterator}
2094      * @param x the specified X coordinate
2095      * @param y the specified Y coordinate
2096      * @return {@code true} if the specified coordinates are inside the
2097      *         specified {@code PathIterator}; {@code false} otherwise
2098      * @since 1.6
2099      */
2100     public static boolean contains(PathIterator pi, double x, double y) {
2101         if (x * 0.0 + y * 0.0 == 0.0) {
2102             /* N * 0.0 is 0.0 only if N is finite.
2103              * Here we know that both x and y are finite.
2104              */
2105             int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
2106             int cross = Curve.pointCrossingsForPath(pi, x, y);
2107             return ((cross & mask) != 0);
2108         } else {
2109             /* Either x or y was infinite or NaN.
2110              * A NaN always produces a negative response to any test
2111              * and Infinity values cannot be "inside" any path so
2112              * they should return false as well.
2113              */
2114             return false;
2115         }
2116     }
2117 
2118     /**
2119      * Tests if the specified {@link Point2D} is inside the closed
2120      * boundary of the specified {@link PathIterator}.
2121      * <p>
2122      * This method provides a basic facility for implementors of
2123      * the {@link Shape} interface to implement support for the
2124      * {@link Shape#contains(Point2D)} method.
2125      *
2126      * @param pi the specified {@code PathIterator}
2127      * @param p the specified {@code Point2D}
2128      * @return {@code true} if the specified coordinates are inside the
2129      *         specified {@code PathIterator}; {@code false} otherwise
2130      * @since 1.6
2131      */
2132     public static boolean contains(PathIterator pi, Point2D p) {
2133         return contains(pi, p.getX(), p.getY());
2134     }
2135 
2136     /**
2137      * {@inheritDoc}
2138      * @since 1.6
2139      */
2140     public final boolean contains(double x, double y) {
2141         if (x * 0.0 + y * 0.0 == 0.0) {
2142             /* N * 0.0 is 0.0 only if N is finite.
2143              * Here we know that both x and y are finite.
2144              */
2145             if (numTypes < 2) {
2146                 return false;
2147             }
2148             int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2149             return ((pointCrossings(x, y) & mask) != 0);
2150         } else {
2151             /* Either x or y was infinite or NaN.
2152              * A NaN always produces a negative response to any test
2153              * and Infinity values cannot be "inside" any path so
2154              * they should return false as well.
2155              */
2156             return false;
2157         }
2158     }
2159 
2160     /**
2161      * {@inheritDoc}
2162      * @since 1.6
2163      */
2164     public final boolean contains(Point2D p) {
2165         return contains(p.getX(), p.getY());
2166     }
2167 
2168     /**
2169      * Tests if the specified rectangular area is entirely inside the
2170      * closed boundary of the specified {@link PathIterator}.
2171      * <p>
2172      * This method provides a basic facility for implementors of
2173      * the {@link Shape} interface to implement support for the
2174      * {@link Shape#contains(double, double, double, double)} method.
2175      * <p>
2176      * This method object may conservatively return false in
2177      * cases where the specified rectangular area intersects a
2178      * segment of the path, but that segment does not represent a
2179      * boundary between the interior and exterior of the path.
2180      * Such segments could lie entirely within the interior of the
2181      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2182      * winding rule or if the segments are retraced in the reverse
2183      * direction such that the two sets of segments cancel each
2184      * other out without any exterior area falling between them.
2185      * To determine whether segments represent true boundaries of
2186      * the interior of the path would require extensive calculations
2187      * involving all of the segments of the path and the winding
2188      * rule and are thus beyond the scope of this implementation.
2189      *
2190      * @param pi the specified {@code PathIterator}
2191      * @param x the specified X coordinate
2192      * @param y the specified Y coordinate
2193      * @param w the width of the specified rectangular area
2194      * @param h the height of the specified rectangular area
2195      * @return {@code true} if the specified {@code PathIterator} contains
2196      *         the specified rectangular area; {@code false} otherwise.
2197      * @since 1.6
2198      */
2199     public static boolean contains(PathIterator pi,
2200                                    double x, double y, double w, double h)
2201     {
2202         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2203             /* [xy]+[wh] is NaN if any of those values are NaN,
2204              * or if adding the two together would produce NaN
2205              * by virtue of adding opposing Infinte values.
2206              * Since we need to add them below, their sum must
2207              * not be NaN.
2208              * We return false because NaN always produces a
2209              * negative response to tests
2210              */
2211             return false;
2212         }
2213         if (w <= 0 || h <= 0) {
2214             return false;
2215         }
2216         int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2217         int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2218         return (crossings != Curve.RECT_INTERSECTS &&
2219                 (crossings & mask) != 0);
2220     }
2221 
2222     /**
2223      * Tests if the specified {@link Rectangle2D} is entirely inside the
2224      * closed boundary of the specified {@link PathIterator}.
2225      * <p>
2226      * This method provides a basic facility for implementors of
2227      * the {@link Shape} interface to implement support for the
2228      * {@link Shape#contains(Rectangle2D)} method.
2229      * <p>
2230      * This method object may conservatively return false in
2231      * cases where the specified rectangular area intersects a
2232      * segment of the path, but that segment does not represent a
2233      * boundary between the interior and exterior of the path.
2234      * Such segments could lie entirely within the interior of the
2235      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2236      * winding rule or if the segments are retraced in the reverse
2237      * direction such that the two sets of segments cancel each
2238      * other out without any exterior area falling between them.
2239      * To determine whether segments represent true boundaries of
2240      * the interior of the path would require extensive calculations
2241      * involving all of the segments of the path and the winding
2242      * rule and are thus beyond the scope of this implementation.
2243      *
2244      * @param pi the specified {@code PathIterator}
2245      * @param r a specified {@code Rectangle2D}
2246      * @return {@code true} if the specified {@code PathIterator} contains
2247      *         the specified {@code Rectangle2D}; {@code false} otherwise.
2248      * @since 1.6
2249      */
2250     public static boolean contains(PathIterator pi, Rectangle2D r) {
2251         return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2252     }
2253 
2254     /**
2255      * {@inheritDoc}
2256      * <p>
2257      * This method object may conservatively return false in
2258      * cases where the specified rectangular area intersects a
2259      * segment of the path, but that segment does not represent a
2260      * boundary between the interior and exterior of the path.
2261      * Such segments could lie entirely within the interior of the
2262      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2263      * winding rule or if the segments are retraced in the reverse
2264      * direction such that the two sets of segments cancel each
2265      * other out without any exterior area falling between them.
2266      * To determine whether segments represent true boundaries of
2267      * the interior of the path would require extensive calculations
2268      * involving all of the segments of the path and the winding
2269      * rule and are thus beyond the scope of this implementation.
2270      *
2271      * @since 1.6
2272      */
2273     public final boolean contains(double x, double y, double w, double h) {
2274         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2275             /* [xy]+[wh] is NaN if any of those values are NaN,
2276              * or if adding the two together would produce NaN
2277              * by virtue of adding opposing Infinte values.
2278              * Since we need to add them below, their sum must
2279              * not be NaN.
2280              * We return false because NaN always produces a
2281              * negative response to tests
2282              */
2283             return false;
2284         }
2285         if (w <= 0 || h <= 0) {
2286             return false;
2287         }
2288         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2289         int crossings = rectCrossings(x, y, x+w, y+h);
2290         return (crossings != Curve.RECT_INTERSECTS &&
2291                 (crossings & mask) != 0);
2292     }
2293 
2294     /**
2295      * {@inheritDoc}
2296      * <p>
2297      * This method object may conservatively return false in
2298      * cases where the specified rectangular area intersects a
2299      * segment of the path, but that segment does not represent a
2300      * boundary between the interior and exterior of the path.
2301      * Such segments could lie entirely within the interior of the
2302      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2303      * winding rule or if the segments are retraced in the reverse
2304      * direction such that the two sets of segments cancel each
2305      * other out without any exterior area falling between them.
2306      * To determine whether segments represent true boundaries of
2307      * the interior of the path would require extensive calculations
2308      * involving all of the segments of the path and the winding
2309      * rule and are thus beyond the scope of this implementation.
2310      *
2311      * @since 1.6
2312      */
2313     public final boolean contains(Rectangle2D r) {
2314         return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2315     }
2316 
2317     /**
2318      * Tests if the interior of the specified {@link PathIterator}
2319      * intersects the interior of a specified set of rectangular
2320      * coordinates.
2321      * <p>
2322      * This method provides a basic facility for implementors of
2323      * the {@link Shape} interface to implement support for the
2324      * {@link Shape#intersects(double, double, double, double)} method.
2325      * <p>
2326      * This method object may conservatively return true in
2327      * cases where the specified rectangular area intersects a
2328      * segment of the path, but that segment does not represent a
2329      * boundary between the interior and exterior of the path.
2330      * Such a case may occur if some set of segments of the
2331      * path are retraced in the reverse direction such that the
2332      * two sets of segments cancel each other out without any
2333      * interior area between them.
2334      * To determine whether segments represent true boundaries of
2335      * the interior of the path would require extensive calculations
2336      * involving all of the segments of the path and the winding
2337      * rule and are thus beyond the scope of this implementation.
2338      *
2339      * @param pi the specified {@code PathIterator}
2340      * @param x the specified X coordinate
2341      * @param y the specified Y coordinate
2342      * @param w the width of the specified rectangular coordinates
2343      * @param h the height of the specified rectangular coordinates
2344      * @return {@code true} if the specified {@code PathIterator} and
2345      *         the interior of the specified set of rectangular
2346      *         coordinates intersect each other; {@code false} otherwise.
2347      * @since 1.6
2348      */
2349     public static boolean intersects(PathIterator pi,
2350                                      double x, double y, double w, double h)
2351     {
2352         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2353             /* [xy]+[wh] is NaN if any of those values are NaN,
2354              * or if adding the two together would produce NaN
2355              * by virtue of adding opposing Infinte values.
2356              * Since we need to add them below, their sum must
2357              * not be NaN.
2358              * We return false because NaN always produces a
2359              * negative response to tests
2360              */
2361             return false;
2362         }
2363         if (w <= 0 || h <= 0) {
2364             return false;
2365         }
2366         int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2367         int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2368         return (crossings == Curve.RECT_INTERSECTS ||
2369                 (crossings & mask) != 0);
2370     }
2371 
2372     /**
2373      * Tests if the interior of the specified {@link PathIterator}
2374      * intersects the interior of a specified {@link Rectangle2D}.
2375      * <p>
2376      * This method provides a basic facility for implementors of
2377      * the {@link Shape} interface to implement support for the
2378      * {@link Shape#intersects(Rectangle2D)} method.
2379      * <p>
2380      * This method object may conservatively return true in
2381      * cases where the specified rectangular area intersects a
2382      * segment of the path, but that segment does not represent a
2383      * boundary between the interior and exterior of the path.
2384      * Such a case may occur if some set of segments of the
2385      * path are retraced in the reverse direction such that the
2386      * two sets of segments cancel each other out without any
2387      * interior area between them.
2388      * To determine whether segments represent true boundaries of
2389      * the interior of the path would require extensive calculations
2390      * involving all of the segments of the path and the winding
2391      * rule and are thus beyond the scope of this implementation.
2392      *
2393      * @param pi the specified {@code PathIterator}
2394      * @param r the specified {@code Rectangle2D}
2395      * @return {@code true} if the specified {@code PathIterator} and
2396      *         the interior of the specified {@code Rectangle2D}
2397      *         intersect each other; {@code false} otherwise.
2398      * @since 1.6
2399      */
2400     public static boolean intersects(PathIterator pi, Rectangle2D r) {
2401         return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2402     }
2403 
2404     /**
2405      * {@inheritDoc}
2406      * <p>
2407      * This method object may conservatively return true in
2408      * cases where the specified rectangular area intersects a
2409      * segment of the path, but that segment does not represent a
2410      * boundary between the interior and exterior of the path.
2411      * Such a case may occur if some set of segments of the
2412      * path are retraced in the reverse direction such that the
2413      * two sets of segments cancel each other out without any
2414      * interior area between them.
2415      * To determine whether segments represent true boundaries of
2416      * the interior of the path would require extensive calculations
2417      * involving all of the segments of the path and the winding
2418      * rule and are thus beyond the scope of this implementation.
2419      *
2420      * @since 1.6
2421      */
2422     public final boolean intersects(double x, double y, double w, double h) {
2423         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2424             /* [xy]+[wh] is NaN if any of those values are NaN,
2425              * or if adding the two together would produce NaN
2426              * by virtue of adding opposing Infinte values.
2427              * Since we need to add them below, their sum must
2428              * not be NaN.
2429              * We return false because NaN always produces a
2430              * negative response to tests
2431              */
2432             return false;
2433         }
2434         if (w <= 0 || h <= 0) {
2435             return false;
2436         }
2437         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2438         int crossings = rectCrossings(x, y, x+w, y+h);
2439         return (crossings == Curve.RECT_INTERSECTS ||
2440                 (crossings & mask) != 0);
2441     }
2442 
2443     /**
2444      * {@inheritDoc}
2445      * <p>
2446      * This method object may conservatively return true in
2447      * cases where the specified rectangular area intersects a
2448      * segment of the path, but that segment does not represent a
2449      * boundary between the interior and exterior of the path.
2450      * Such a case may occur if some set of segments of the
2451      * path are retraced in the reverse direction such that the
2452      * two sets of segments cancel each other out without any
2453      * interior area between them.
2454      * To determine whether segments represent true boundaries of
2455      * the interior of the path would require extensive calculations
2456      * involving all of the segments of the path and the winding
2457      * rule and are thus beyond the scope of this implementation.
2458      *
2459      * @since 1.6
2460      */
2461     public final boolean intersects(Rectangle2D r) {
2462         return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2463     }
2464 
2465     /**
2466      * {@inheritDoc}
2467      * <p>
2468      * The iterator for this class is not multi-threaded safe,
2469      * which means that this {@code Path2D} class does not
2470      * guarantee that modifications to the geometry of this
2471      * {@code Path2D} object do not affect any iterations of
2472      * that geometry that are already in process.
2473      *
2474      * @since 1.6
2475      */
2476     public final PathIterator getPathIterator(AffineTransform at,
2477                                               double flatness)
2478     {
2479         return new FlatteningPathIterator(getPathIterator(at), flatness);
2480     }
2481 
2482     /**
2483      * Creates a new object of the same class as this object.
2484      *
2485      * @return     a clone of this instance.
2486      * @exception  OutOfMemoryError            if there is not enough memory.
2487      * @see        java.lang.Cloneable
2488      * @since      1.6
2489      */
2490     public abstract Object clone();
2491         // Note: It would be nice to have this return Path2D
2492         // but one of our subclasses (GeneralPath) needs to
2493         // offer "public Object clone()" for backwards
2494         // compatibility so we cannot restrict it further.
2495         // REMIND: Can we do both somehow?
2496 
2497     /**
2498      * Trims the capacity of this Path2D instance to its current
2499      * size. If the capacity of this path is larger than its current
2500      * size, then the capacity is changed to equal the size by replacing
2501      * its internal data array. An application can use this operation to
2502      * minimize the storage of a path.
2503      * @return this Path2D instance
2504      * @Since 10
2505      */
2506     public abstract Path2D trimToSize();
2507 
2508     /*
2509      * Support fields and methods for serializing the subclasses.
2510      */
2511     private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2512     private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2513 
2514     private static final byte SERIAL_SEG_FLT_MOVETO    = 0x40;
2515     private static final byte SERIAL_SEG_FLT_LINETO    = 0x41;
2516     private static final byte SERIAL_SEG_FLT_QUADTO    = 0x42;
2517     private static final byte SERIAL_SEG_FLT_CUBICTO   = 0x43;
2518 
2519     private static final byte SERIAL_SEG_DBL_MOVETO    = 0x50;
2520     private static final byte SERIAL_SEG_DBL_LINETO    = 0x51;
2521     private static final byte SERIAL_SEG_DBL_QUADTO    = 0x52;
2522     private static final byte SERIAL_SEG_DBL_CUBICTO   = 0x53;
2523 
2524     private static final byte SERIAL_SEG_CLOSE         = 0x60;
2525     private static final byte SERIAL_PATH_END          = 0x61;
2526 
2527     final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2528         throws java.io.IOException
2529     {
2530         s.defaultWriteObject();
2531 
2532         float fCoords[];
2533         double dCoords[];
2534 
2535         if (isdbl) {
2536             dCoords = ((Path2D.Double) this).doubleCoords;
2537             fCoords = null;
2538         } else {
2539             fCoords = ((Path2D.Float) this).floatCoords;
2540             dCoords = null;
2541         }
2542 
2543         int numTypes = this.numTypes;
2544 
2545         s.writeByte(isdbl
2546                     ? SERIAL_STORAGE_DBL_ARRAY
2547                     : SERIAL_STORAGE_FLT_ARRAY);
2548         s.writeInt(numTypes);
2549         s.writeInt(numCoords);
2550         s.writeByte((byte) windingRule);
2551 
2552         int cindex = 0;
2553         for (int i = 0; i < numTypes; i++) {
2554             int npoints;
2555             byte serialtype;
2556             switch (pointTypes[i]) {
2557             case SEG_MOVETO:
2558                 npoints = 1;
2559                 serialtype = (isdbl
2560                               ? SERIAL_SEG_DBL_MOVETO
2561                               : SERIAL_SEG_FLT_MOVETO);
2562                 break;
2563             case SEG_LINETO:
2564                 npoints = 1;
2565                 serialtype = (isdbl
2566                               ? SERIAL_SEG_DBL_LINETO
2567                               : SERIAL_SEG_FLT_LINETO);
2568                 break;
2569             case SEG_QUADTO:
2570                 npoints = 2;
2571                 serialtype = (isdbl
2572                               ? SERIAL_SEG_DBL_QUADTO
2573                               : SERIAL_SEG_FLT_QUADTO);
2574                 break;
2575             case SEG_CUBICTO:
2576                 npoints = 3;
2577                 serialtype = (isdbl
2578                               ? SERIAL_SEG_DBL_CUBICTO
2579                               : SERIAL_SEG_FLT_CUBICTO);
2580                 break;
2581             case SEG_CLOSE:
2582                 npoints = 0;
2583                 serialtype = SERIAL_SEG_CLOSE;
2584                 break;
2585 
2586             default:
2587                 // Should never happen
2588                 throw new InternalError("unrecognized path type");
2589             }
2590             s.writeByte(serialtype);
2591             while (--npoints >= 0) {
2592                 if (isdbl) {
2593                     s.writeDouble(dCoords[cindex++]);
2594                     s.writeDouble(dCoords[cindex++]);
2595                 } else {
2596                     s.writeFloat(fCoords[cindex++]);
2597                     s.writeFloat(fCoords[cindex++]);
2598                 }
2599             }
2600         }
2601         s.writeByte(SERIAL_PATH_END);
2602     }
2603 
2604     final void readObject(java.io.ObjectInputStream s, boolean storedbl)
2605         throws java.lang.ClassNotFoundException, java.io.IOException
2606     {
2607         s.defaultReadObject();
2608 
2609         // The subclass calls this method with the storage type that
2610         // they want us to use (storedbl) so we ignore the storage
2611         // method hint from the stream.
2612         s.readByte();
2613         int nT = s.readInt();
2614         int nC = s.readInt();
2615         try {
2616             setWindingRule(s.readByte());
2617         } catch (IllegalArgumentException iae) {
2618             throw new java.io.InvalidObjectException(iae.getMessage());
2619         }
2620 
2621         pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT];
2622         if (nC < 0) {
2623             nC = INIT_SIZE * 2;
2624         }
2625         if (storedbl) {
2626             ((Path2D.Double) this).doubleCoords = new double[nC];
2627         } else {
2628             ((Path2D.Float) this).floatCoords = new float[nC];
2629         }
2630 
2631     PATHDONE:
2632         for (int i = 0; nT < 0 || i < nT; i++) {
2633             boolean isdbl;
2634             int npoints;
2635             byte segtype;
2636 
2637             byte serialtype = s.readByte();
2638             switch (serialtype) {
2639             case SERIAL_SEG_FLT_MOVETO:
2640                 isdbl = false;
2641                 npoints = 1;
2642                 segtype = SEG_MOVETO;
2643                 break;
2644             case SERIAL_SEG_FLT_LINETO:
2645                 isdbl = false;
2646                 npoints = 1;
2647                 segtype = SEG_LINETO;
2648                 break;
2649             case SERIAL_SEG_FLT_QUADTO:
2650                 isdbl = false;
2651                 npoints = 2;
2652                 segtype = SEG_QUADTO;
2653                 break;
2654             case SERIAL_SEG_FLT_CUBICTO:
2655                 isdbl = false;
2656                 npoints = 3;
2657                 segtype = SEG_CUBICTO;
2658                 break;
2659 
2660             case SERIAL_SEG_DBL_MOVETO:
2661                 isdbl = true;
2662                 npoints = 1;
2663                 segtype = SEG_MOVETO;
2664                 break;
2665             case SERIAL_SEG_DBL_LINETO:
2666                 isdbl = true;
2667                 npoints = 1;
2668                 segtype = SEG_LINETO;
2669                 break;
2670             case SERIAL_SEG_DBL_QUADTO:
2671                 isdbl = true;
2672                 npoints = 2;
2673                 segtype = SEG_QUADTO;
2674                 break;
2675             case SERIAL_SEG_DBL_CUBICTO:
2676                 isdbl = true;
2677                 npoints = 3;
2678                 segtype = SEG_CUBICTO;
2679                 break;
2680 
2681             case SERIAL_SEG_CLOSE:
2682                 isdbl = false;
2683                 npoints = 0;
2684                 segtype = SEG_CLOSE;
2685                 break;
2686 
2687             case SERIAL_PATH_END:
2688                 if (nT < 0) {
2689                     break PATHDONE;
2690                 }
2691                 throw new StreamCorruptedException("unexpected PATH_END");
2692 
2693             default:
2694                 throw new StreamCorruptedException("unrecognized path type");
2695             }
2696             needRoom(segtype != SEG_MOVETO, npoints * 2);
2697             if (isdbl) {
2698                 while (--npoints >= 0) {
2699                     append(s.readDouble(), s.readDouble());
2700                 }
2701             } else {
2702                 while (--npoints >= 0) {
2703                     append(s.readFloat(), s.readFloat());
2704                 }
2705             }
2706             pointTypes[numTypes++] = segtype;
2707         }
2708         if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2709             throw new StreamCorruptedException("missing PATH_END");
2710         }
2711     }
2712 
2713     abstract static class Iterator implements PathIterator {
2714         int typeIdx;
2715         int pointIdx;
2716         Path2D path;
2717 
2718         static final int curvecoords[] = {2, 2, 4, 6, 0};
2719 
2720         Iterator(Path2D path) {
2721             this.path = path;
2722         }
2723 
2724         public int getWindingRule() {
2725             return path.getWindingRule();
2726         }
2727 
2728         public boolean isDone() {
2729             return (typeIdx >= path.numTypes);
2730         }
2731 
2732         public void next() {
2733             int type = path.pointTypes[typeIdx++];
2734             pointIdx += curvecoords[type];
2735         }
2736     }
2737 }