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