1 /*
   2  * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.geom;
  27 
  28 import java.awt.Shape;
  29 import java.awt.Rectangle;
  30 import sun.awt.geom.Curve;
  31 import java.io.Serializable;
  32 import java.io.StreamCorruptedException;
  33 import java.util.Arrays;
  34 
  35 /**
  36  * The {@code Path2D} class provides a simple, yet flexible
  37  * shape which represents an arbitrary geometric path.
  38  * It can fully represent any path which can be iterated by the
  39  * {@link PathIterator} interface including all of its segment
  40  * types and winding rules and it implements all of the
  41  * basic hit testing methods of the {@link Shape} interface.
  42  * <p>
  43  * Use {@link Path2D.Float} when dealing with data that can be represented
  44  * and used with floating point precision.  Use {@link Path2D.Double}
  45  * for data that requires the accuracy or range of double precision.
  46  * <p>
  47  * {@code Path2D} provides exactly those facilities required for
  48  * basic construction and management of a geometric path and
  49  * implementation of the above interfaces with little added
  50  * interpretation.
  51  * If it is useful to manipulate the interiors of closed
  52  * geometric shapes beyond simple hit testing then the
  53  * {@link Area} class provides additional capabilities
  54  * specifically targeted at closed figures.
  55  * While both classes nominally implement the {@code Shape}
  56  * interface, they differ in purpose and together they provide
  57  * two useful views of a geometric shape where {@code Path2D}
  58  * deals primarily with a trajectory formed by path segments
  59  * and {@code Area} deals more with interpretation and manipulation
  60  * of enclosed regions of 2D geometric space.
  61  * <p>
  62  * The {@link PathIterator} interface has more detailed descriptions
  63  * of the types of segments that make up a path and the winding rules
  64  * that control how to determine which regions are inside or outside
  65  * the path.
  66  *
  67  * @author Jim Graham
  68  * @since 1.6
  69  */
  70 public abstract class Path2D implements Shape, Cloneable {
  71     /**
  72      * An even-odd winding rule for determining the interior of
  73      * a path.
  74      *
  75      * @see PathIterator#WIND_EVEN_ODD
  76      * @since 1.6
  77      */
  78     public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
  79 
  80     /**
  81      * A non-zero winding rule for determining the interior of a
  82      * path.
  83      *
  84      * @see PathIterator#WIND_NON_ZERO
  85      * @since 1.6
  86      */
  87     public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
  88 
  89     // For code simplicity, copy these constants to our namespace
  90     // and cast them to byte constants for easy storage.
  91     private static final byte SEG_MOVETO  = (byte) PathIterator.SEG_MOVETO;
  92     private static final byte SEG_LINETO  = (byte) PathIterator.SEG_LINETO;
  93     private static final byte SEG_QUADTO  = (byte) PathIterator.SEG_QUADTO;
  94     private static final byte SEG_CUBICTO = (byte) PathIterator.SEG_CUBICTO;
  95     private static final byte SEG_CLOSE   = (byte) PathIterator.SEG_CLOSE;
  96 
  97     transient byte[] pointTypes;
  98     transient int numTypes;
  99     transient int numCoords;
 100     transient int windingRule;
 101 
 102     static final int INIT_SIZE = 20;
 103     static final int EXPAND_MAX = 500;
 104     static final int EXPAND_MAX_COORDS = EXPAND_MAX * 2;
 105     static final int EXPAND_MIN = 10; // ensure > 6 (cubics)
 106 
 107     /**
 108      * Constructs a new empty {@code Path2D} object.
 109      * It is assumed that the package sibling subclass that is
 110      * defaulting to this constructor will fill in all values.
 111      *
 112      * @since 1.6
 113      */
 114     /* private protected */
 115     Path2D() {
 116     }
 117 
 118     /**
 119      * Constructs a new {@code Path2D} object from the given
 120      * specified initial values.
 121      * This method is only intended for internal use and should
 122      * not be made public if the other constructors for this class
 123      * are ever exposed.
 124      *
 125      * @param rule the winding rule
 126      * @param initialTypes the size to make the initial array to
 127      *                     store the path segment types
 128      * @since 1.6
 129      */
 130     /* private protected */
 131     Path2D(int rule, int initialTypes) {
 132         setWindingRule(rule);
 133         this.pointTypes = new byte[initialTypes];
 134     }
 135 
 136     abstract float[] cloneCoordsFloat(AffineTransform at);
 137     abstract double[] cloneCoordsDouble(AffineTransform at);
 138     abstract void append(float x, float y);
 139     abstract void append(double x, double y);
 140     abstract Point2D getPoint(int coordindex);
 141     abstract void needRoom(boolean needMove, int newCoords);
 142     abstract int pointCrossings(double px, double py);
 143     abstract int rectCrossings(double rxmin, double rymin,
 144                                double rxmax, double rymax);
 145 
 146     static byte[] expandPointTypes(byte[] oldPointTypes, int needed) {
 147         final int oldSize = oldPointTypes.length;
 148         final int newSizeMin = oldSize + needed;
 149         if (newSizeMin < oldSize) {
 150             // hard overflow failure - we can't even accommodate
 151             // new items without overflowing
 152             throw new ArrayIndexOutOfBoundsException(
 153                           "pointTypes exceeds maximum capacity !");
 154         }
 155         // growth algorithm computation
 156         int grow = oldSize;
 157         if (grow > EXPAND_MAX) {
 158             grow = Math.max(EXPAND_MAX, oldSize >> 3); // 1/8th min
 159         } else if (grow < EXPAND_MIN) {
 160             grow = EXPAND_MIN;
 161         }
 162         assert grow > 0;
 163 
 164         int newSize = oldSize + grow;
 165         if (newSize < newSizeMin) {
 166             // overflow in growth algorithm computation
 167             newSize = Integer.MAX_VALUE;
 168         }
 169         while (true) {
 170             try {
 171                 // try allocating the larger array
 172                 return Arrays.copyOf(oldPointTypes, newSize);
 173             } catch (OutOfMemoryError oome) {
 174                 if (newSize == newSizeMin) {
 175                     throw oome;
 176                 }
 177             }
 178             newSize = newSizeMin + (newSize - newSizeMin) / 2;
 179         }
 180     }
 181 
 182     /**
 183      * The {@code Float} class defines a geometric path with
 184      * coordinates stored in single precision floating point.
 185      *
 186      * @since 1.6
 187      */
 188     public static class Float extends Path2D implements Serializable {
 189         transient float floatCoords[];
 190 
 191         /**
 192          * Constructs a new empty single precision {@code Path2D} object
 193          * with a default winding rule of {@link #WIND_NON_ZERO}.
 194          *
 195          * @since 1.6
 196          */
 197         public Float() {
 198             this(WIND_NON_ZERO, INIT_SIZE);
 199         }
 200 
 201         /**
 202          * Constructs a new empty single precision {@code Path2D} object
 203          * with the specified winding rule to control operations that
 204          * require the interior of the path to be defined.
 205          *
 206          * @param rule the winding rule
 207          * @see #WIND_EVEN_ODD
 208          * @see #WIND_NON_ZERO
 209          * @since 1.6
 210          */
 211         public Float(int rule) {
 212             this(rule, INIT_SIZE);
 213         }
 214 
 215         /**
 216          * Constructs a new empty single precision {@code Path2D} object
 217          * with the specified winding rule and the specified initial
 218          * capacity to store path segments.
 219          * This number is an initial guess as to how many path segments
 220          * will be added to the path, but the storage is expanded as
 221          * needed to store whatever path segments are added.
 222          *
 223          * @param rule the winding rule
 224          * @param initialCapacity the estimate for the number of path segments
 225          *                        in the path
 226          * @see #WIND_EVEN_ODD
 227          * @see #WIND_NON_ZERO
 228          * @since 1.6
 229          */
 230         public Float(int rule, int initialCapacity) {
 231             super(rule, initialCapacity);
 232             floatCoords = new float[initialCapacity * 2];
 233         }
 234 
 235         /**
 236          * Constructs a new single precision {@code Path2D} object
 237          * from an arbitrary {@link Shape} object.
 238          * All of the initial geometry and the winding rule for this path are
 239          * taken from the specified {@code Shape} object.
 240          *
 241          * @param s the specified {@code Shape} object
 242          * @since 1.6
 243          */
 244         public Float(Shape s) {
 245             this(s, null);
 246         }
 247 
 248         /**
 249          * Constructs a new single precision {@code Path2D} object
 250          * from an arbitrary {@link Shape} object, transformed by an
 251          * {@link AffineTransform} object.
 252          * All of the initial geometry and the winding rule for this path are
 253          * taken from the specified {@code Shape} object and transformed
 254          * by the specified {@code AffineTransform} object.
 255          *
 256          * @param s the specified {@code Shape} object
 257          * @param at the specified {@code AffineTransform} object
 258          * @since 1.6
 259          */
 260         public Float(Shape s, AffineTransform at) {
 261             if (s instanceof Path2D) {
 262                 Path2D p2d = (Path2D) s;
 263                 setWindingRule(p2d.windingRule);
 264                 this.numTypes = p2d.numTypes;
 265                 // trim arrays:
 266                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
 267                 this.numCoords = p2d.numCoords;
 268                 this.floatCoords = p2d.cloneCoordsFloat(at);
 269             } else {
 270                 PathIterator pi = s.getPathIterator(at);
 271                 setWindingRule(pi.getWindingRule());
 272                 this.pointTypes = new byte[INIT_SIZE];
 273                 this.floatCoords = new float[INIT_SIZE * 2];
 274                 append(pi, false);
 275             }
 276         }
 277 
 278         @Override
 279         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 name="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          * <table>
 880          * <tr>
 881          * <th>Constant Name</th>
 882          * <th>Byte Value</th>
 883          * <th>Followed by</th>
 884          * <th>Description</th>
 885          * </tr>
 886          * <tr>
 887          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
 888          * <td>0x30</td>
 889          * <td></td>
 890          * <td>A hint that the original {@code Path2D} object stored
 891          * the coordinates in a Java array of floats.</td>
 892          * </tr>
 893          * <tr>
 894          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
 895          * <td>0x31</td>
 896          * <td></td>
 897          * <td>A hint that the original {@code Path2D} object stored
 898          * the coordinates in a Java array of doubles.</td>
 899          * </tr>
 900          * <tr>
 901          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
 902          * <td>0x40</td>
 903          * <td>2 floats</td>
 904          * <td>A {@link #moveTo moveTo} path segment follows.</td>
 905          * </tr>
 906          * <tr>
 907          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
 908          * <td>0x41</td>
 909          * <td>2 floats</td>
 910          * <td>A {@link #lineTo lineTo} path segment follows.</td>
 911          * </tr>
 912          * <tr>
 913          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
 914          * <td>0x42</td>
 915          * <td>4 floats</td>
 916          * <td>A {@link #quadTo quadTo} path segment follows.</td>
 917          * </tr>
 918          * <tr>
 919          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
 920          * <td>0x43</td>
 921          * <td>6 floats</td>
 922          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 923          * </tr>
 924          * <tr>
 925          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
 926          * <td>0x50</td>
 927          * <td>2 doubles</td>
 928          * <td>A {@link #moveTo moveTo} path segment follows.</td>
 929          * </tr>
 930          * <tr>
 931          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
 932          * <td>0x51</td>
 933          * <td>2 doubles</td>
 934          * <td>A {@link #lineTo lineTo} path segment follows.</td>
 935          * </tr>
 936          * <tr>
 937          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
 938          * <td>0x52</td>
 939          * <td>4 doubles</td>
 940          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 941          * </tr>
 942          * <tr>
 943          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
 944          * <td>0x53</td>
 945          * <td>6 doubles</td>
 946          * <td>A {@link #curveTo curveTo} path segment follows.</td>
 947          * </tr>
 948          * <tr>
 949          * <td>{@code SERIAL_SEG_CLOSE}</td>
 950          * <td>0x60</td>
 951          * <td></td>
 952          * <td>A {@link #closePath closePath} path segment.</td>
 953          * </tr>
 954          * <tr>
 955          * <td>{@code SERIAL_PATH_END}</td>
 956          * <td>0x61</td>
 957          * <td></td>
 958          * <td>There are no more path segments following.</td>
 959          * </table>
 960          *
 961          * @since 1.6
 962          */
 963         private void writeObject(java.io.ObjectOutputStream s)
 964             throws java.io.IOException
 965         {
 966             super.writeObject(s, false);
 967         }
 968 
 969         /**
 970          * Reads the default serializable fields from the
 971          * {@code ObjectInputStream} followed by an explicit
 972          * serialization of the path segments stored in this
 973          * path.
 974          * <p>
 975          * There are no default serializable fields as of 1.6.
 976          * <p>
 977          * The serial data for this object is described in the
 978          * writeObject method.
 979          *
 980          * @since 1.6
 981          */
 982         private void readObject(java.io.ObjectInputStream s)
 983             throws java.lang.ClassNotFoundException, java.io.IOException
 984         {
 985             super.readObject(s, false);
 986         }
 987 
 988         static class CopyIterator extends Path2D.Iterator {
 989             float floatCoords[];
 990 
 991             CopyIterator(Path2D.Float p2df) {
 992                 super(p2df);
 993                 this.floatCoords = p2df.floatCoords;
 994             }
 995 
 996             public int currentSegment(float[] coords) {
 997                 int type = path.pointTypes[typeIdx];
 998                 int numCoords = curvecoords[type];
 999                 if (numCoords > 0) {
1000                     System.arraycopy(floatCoords, pointIdx,
1001                                      coords, 0, numCoords);
1002                 }
1003                 return type;
1004             }
1005 
1006             public int currentSegment(double[] coords) {
1007                 int type = path.pointTypes[typeIdx];
1008                 int numCoords = curvecoords[type];
1009                 if (numCoords > 0) {
1010                     for (int i = 0; i < numCoords; i++) {
1011                         coords[i] = floatCoords[pointIdx + i];
1012                     }
1013                 }
1014                 return type;
1015             }
1016         }
1017 
1018         static class TxIterator extends Path2D.Iterator {
1019             float floatCoords[];
1020             AffineTransform affine;
1021 
1022             TxIterator(Path2D.Float p2df, AffineTransform at) {
1023                 super(p2df);
1024                 this.floatCoords = p2df.floatCoords;
1025                 this.affine = at;
1026             }
1027 
1028             public int currentSegment(float[] coords) {
1029                 int type = path.pointTypes[typeIdx];
1030                 int numCoords = curvecoords[type];
1031                 if (numCoords > 0) {
1032                     affine.transform(floatCoords, pointIdx,
1033                                      coords, 0, numCoords / 2);
1034                 }
1035                 return type;
1036             }
1037 
1038             public int currentSegment(double[] coords) {
1039                 int type = path.pointTypes[typeIdx];
1040                 int numCoords = curvecoords[type];
1041                 if (numCoords > 0) {
1042                     affine.transform(floatCoords, pointIdx,
1043                                      coords, 0, numCoords / 2);
1044                 }
1045                 return type;
1046             }
1047         }
1048 
1049     }
1050 
1051     /**
1052      * The {@code Double} class defines a geometric path with
1053      * coordinates stored in double precision floating point.
1054      *
1055      * @since 1.6
1056      */
1057     public static class Double extends Path2D implements Serializable {
1058         transient double doubleCoords[];
1059 
1060         /**
1061          * Constructs a new empty double precision {@code Path2D} object
1062          * with a default winding rule of {@link #WIND_NON_ZERO}.
1063          *
1064          * @since 1.6
1065          */
1066         public Double() {
1067             this(WIND_NON_ZERO, INIT_SIZE);
1068         }
1069 
1070         /**
1071          * Constructs a new empty double precision {@code Path2D} object
1072          * with the specified winding rule to control operations that
1073          * require the interior of the path to be defined.
1074          *
1075          * @param rule the winding rule
1076          * @see #WIND_EVEN_ODD
1077          * @see #WIND_NON_ZERO
1078          * @since 1.6
1079          */
1080         public Double(int rule) {
1081             this(rule, INIT_SIZE);
1082         }
1083 
1084         /**
1085          * Constructs a new empty double precision {@code Path2D} object
1086          * with the specified winding rule and the specified initial
1087          * capacity to store path segments.
1088          * This number is an initial guess as to how many path segments
1089          * are in the path, but the storage is expanded as needed to store
1090          * whatever path segments are added to this path.
1091          *
1092          * @param rule the winding rule
1093          * @param initialCapacity the estimate for the number of path segments
1094          *                        in the path
1095          * @see #WIND_EVEN_ODD
1096          * @see #WIND_NON_ZERO
1097          * @since 1.6
1098          */
1099         public Double(int rule, int initialCapacity) {
1100             super(rule, initialCapacity);
1101             doubleCoords = new double[initialCapacity * 2];
1102         }
1103 
1104         /**
1105          * Constructs a new double precision {@code Path2D} object
1106          * from an arbitrary {@link Shape} object.
1107          * All of the initial geometry and the winding rule for this path are
1108          * taken from the specified {@code Shape} object.
1109          *
1110          * @param s the specified {@code Shape} object
1111          * @since 1.6
1112          */
1113         public Double(Shape s) {
1114             this(s, null);
1115         }
1116 
1117         /**
1118          * Constructs a new double precision {@code Path2D} object
1119          * from an arbitrary {@link Shape} object, transformed by an
1120          * {@link AffineTransform} object.
1121          * All of the initial geometry and the winding rule for this path are
1122          * taken from the specified {@code Shape} object and transformed
1123          * by the specified {@code AffineTransform} object.
1124          *
1125          * @param s the specified {@code Shape} object
1126          * @param at the specified {@code AffineTransform} object
1127          * @since 1.6
1128          */
1129         public Double(Shape s, AffineTransform at) {
1130             if (s instanceof Path2D) {
1131                 Path2D p2d = (Path2D) s;
1132                 setWindingRule(p2d.windingRule);
1133                 this.numTypes = p2d.numTypes;
1134                 // trim arrays:
1135                 this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
1136                 this.numCoords = p2d.numCoords;
1137                 this.doubleCoords = p2d.cloneCoordsDouble(at);
1138             } else {
1139                 PathIterator pi = s.getPathIterator(at);
1140                 setWindingRule(pi.getWindingRule());
1141                 this.pointTypes = new byte[INIT_SIZE];
1142                 this.doubleCoords = new double[INIT_SIZE * 2];
1143                 append(pi, false);
1144             }
1145         }
1146 
1147         @Override
1148         float[] cloneCoordsFloat(AffineTransform at) {
1149             // trim arrays:
1150             float ret[] = new float[numCoords];
1151             if (at == null) {
1152                 for (int i = 0; i < numCoords; i++) {
1153                     ret[i] = (float) doubleCoords[i];
1154                 }
1155             } else {
1156                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1157             }
1158             return ret;
1159         }
1160 
1161         @Override
1162         double[] cloneCoordsDouble(AffineTransform at) {
1163             // trim arrays:
1164             double ret[];
1165             if (at == null) {
1166                 ret = Arrays.copyOf(doubleCoords, numCoords);
1167             } else {
1168                 ret = new double[numCoords];
1169                 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1170             }
1171             return ret;
1172         }
1173 
1174         void append(float x, float y) {
1175             doubleCoords[numCoords++] = x;
1176             doubleCoords[numCoords++] = y;
1177         }
1178 
1179         void append(double x, double y) {
1180             doubleCoords[numCoords++] = x;
1181             doubleCoords[numCoords++] = y;
1182         }
1183 
1184         Point2D getPoint(int coordindex) {
1185             return new Point2D.Double(doubleCoords[coordindex],
1186                                       doubleCoords[coordindex+1]);
1187         }
1188 
1189         @Override
1190         void needRoom(boolean needMove, int newCoords) {
1191             if ((numTypes == 0) && needMove) {
1192                 throw new IllegalPathStateException("missing initial moveto "+
1193                                                     "in path definition");
1194             }
1195             if (numTypes >= pointTypes.length) {
1196                 pointTypes = expandPointTypes(pointTypes, 1);
1197             }
1198             if (numCoords > (doubleCoords.length - newCoords)) {
1199                 doubleCoords = expandCoords(doubleCoords, newCoords);
1200             }
1201         }
1202 
1203         static double[] expandCoords(double[] oldCoords, int needed) {
1204             final int oldSize = oldCoords.length;
1205             final int newSizeMin = oldSize + needed;
1206             if (newSizeMin < oldSize) {
1207                 // hard overflow failure - we can't even accommodate
1208                 // new items without overflowing
1209                 throw new ArrayIndexOutOfBoundsException(
1210                               "coords exceeds maximum capacity !");
1211             }
1212             // growth algorithm computation
1213             int grow = oldSize;
1214             if (grow > EXPAND_MAX_COORDS) {
1215                 grow = Math.max(EXPAND_MAX_COORDS, oldSize >> 3); // 1/8th min
1216             } else if (grow < EXPAND_MIN) {
1217                 grow = EXPAND_MIN;
1218             }
1219             assert grow > needed;
1220 
1221             int newSize = oldSize + grow;
1222             if (newSize < newSizeMin) {
1223                 // overflow in growth algorithm computation
1224                 newSize = Integer.MAX_VALUE;
1225             }
1226             while (true) {
1227                 try {
1228                     // try allocating the larger array
1229                     return Arrays.copyOf(oldCoords, newSize);
1230                 } catch (OutOfMemoryError oome) {
1231                     if (newSize == newSizeMin) {
1232                         throw oome;
1233                     }
1234                 }
1235                 newSize = newSizeMin + (newSize - newSizeMin) / 2;
1236             }
1237         }
1238 
1239         /**
1240          * {@inheritDoc}
1241          * @since 1.6
1242          */
1243         public final synchronized void moveTo(double x, double y) {
1244             if (numTypes > 0 && pointTypes[numTypes - 1] == SEG_MOVETO) {
1245                 doubleCoords[numCoords-2] = x;
1246                 doubleCoords[numCoords-1] = y;
1247             } else {
1248                 needRoom(false, 2);
1249                 pointTypes[numTypes++] = SEG_MOVETO;
1250                 doubleCoords[numCoords++] = x;
1251                 doubleCoords[numCoords++] = y;
1252             }
1253         }
1254 
1255         /**
1256          * {@inheritDoc}
1257          * @since 1.6
1258          */
1259         public final synchronized void lineTo(double x, double y) {
1260             needRoom(true, 2);
1261             pointTypes[numTypes++] = SEG_LINETO;
1262             doubleCoords[numCoords++] = x;
1263             doubleCoords[numCoords++] = y;
1264         }
1265 
1266         /**
1267          * {@inheritDoc}
1268          * @since 1.6
1269          */
1270         public final synchronized void quadTo(double x1, double y1,
1271                                               double x2, double y2)
1272         {
1273             needRoom(true, 4);
1274             pointTypes[numTypes++] = SEG_QUADTO;
1275             doubleCoords[numCoords++] = x1;
1276             doubleCoords[numCoords++] = y1;
1277             doubleCoords[numCoords++] = x2;
1278             doubleCoords[numCoords++] = y2;
1279         }
1280 
1281         /**
1282          * {@inheritDoc}
1283          * @since 1.6
1284          */
1285         public final synchronized void curveTo(double x1, double y1,
1286                                                double x2, double y2,
1287                                                double x3, double y3)
1288         {
1289             needRoom(true, 6);
1290             pointTypes[numTypes++] = SEG_CUBICTO;
1291             doubleCoords[numCoords++] = x1;
1292             doubleCoords[numCoords++] = y1;
1293             doubleCoords[numCoords++] = x2;
1294             doubleCoords[numCoords++] = y2;
1295             doubleCoords[numCoords++] = x3;
1296             doubleCoords[numCoords++] = y3;
1297         }
1298 
1299         int pointCrossings(double px, double py) {
1300             if (numTypes == 0) {
1301                 return 0;
1302             }
1303             double movx, movy, curx, cury, endx, endy;
1304             double coords[] = doubleCoords;
1305             curx = movx = coords[0];
1306             cury = movy = coords[1];
1307             int crossings = 0;
1308             int ci = 2;
1309             for (int i = 1; i < numTypes; i++) {
1310                 switch (pointTypes[i]) {
1311                 case PathIterator.SEG_MOVETO:
1312                     if (cury != movy) {
1313                         crossings +=
1314                             Curve.pointCrossingsForLine(px, py,
1315                                                         curx, cury,
1316                                                         movx, movy);
1317                     }
1318                     movx = curx = coords[ci++];
1319                     movy = cury = coords[ci++];
1320                     break;
1321                 case PathIterator.SEG_LINETO:
1322                     crossings +=
1323                         Curve.pointCrossingsForLine(px, py,
1324                                                     curx, cury,
1325                                                     endx = coords[ci++],
1326                                                     endy = coords[ci++]);
1327                     curx = endx;
1328                     cury = endy;
1329                     break;
1330                 case PathIterator.SEG_QUADTO:
1331                     crossings +=
1332                         Curve.pointCrossingsForQuad(px, py,
1333                                                     curx, cury,
1334                                                     coords[ci++],
1335                                                     coords[ci++],
1336                                                     endx = coords[ci++],
1337                                                     endy = coords[ci++],
1338                                                     0);
1339                     curx = endx;
1340                     cury = endy;
1341                     break;
1342             case PathIterator.SEG_CUBICTO:
1343                     crossings +=
1344                         Curve.pointCrossingsForCubic(px, py,
1345                                                      curx, cury,
1346                                                      coords[ci++],
1347                                                      coords[ci++],
1348                                                      coords[ci++],
1349                                                      coords[ci++],
1350                                                      endx = coords[ci++],
1351                                                      endy = coords[ci++],
1352                                                      0);
1353                     curx = endx;
1354                     cury = endy;
1355                     break;
1356                 case PathIterator.SEG_CLOSE:
1357                     if (cury != movy) {
1358                         crossings +=
1359                             Curve.pointCrossingsForLine(px, py,
1360                                                         curx, cury,
1361                                                         movx, movy);
1362                     }
1363                     curx = movx;
1364                     cury = movy;
1365                     break;
1366                 }
1367             }
1368             if (cury != movy) {
1369                 crossings +=
1370                     Curve.pointCrossingsForLine(px, py,
1371                                                 curx, cury,
1372                                                 movx, movy);
1373             }
1374             return crossings;
1375         }
1376 
1377         int rectCrossings(double rxmin, double rymin,
1378                           double rxmax, double rymax)
1379         {
1380             if (numTypes == 0) {
1381                 return 0;
1382             }
1383             double coords[] = doubleCoords;
1384             double curx, cury, movx, movy, endx, endy;
1385             curx = movx = coords[0];
1386             cury = movy = coords[1];
1387             int crossings = 0;
1388             int ci = 2;
1389             for (int i = 1;
1390                  crossings != Curve.RECT_INTERSECTS && i < numTypes;
1391                  i++)
1392             {
1393                 switch (pointTypes[i]) {
1394                 case PathIterator.SEG_MOVETO:
1395                     if (curx != movx || cury != movy) {
1396                         crossings =
1397                             Curve.rectCrossingsForLine(crossings,
1398                                                        rxmin, rymin,
1399                                                        rxmax, rymax,
1400                                                        curx, cury,
1401                                                        movx, movy);
1402                     }
1403                     // Count should always be a multiple of 2 here.
1404                     // assert((crossings & 1) != 0);
1405                     movx = curx = coords[ci++];
1406                     movy = cury = coords[ci++];
1407                     break;
1408                 case PathIterator.SEG_LINETO:
1409                     endx = coords[ci++];
1410                     endy = coords[ci++];
1411                     crossings =
1412                         Curve.rectCrossingsForLine(crossings,
1413                                                    rxmin, rymin,
1414                                                    rxmax, rymax,
1415                                                    curx, cury,
1416                                                    endx, endy);
1417                     curx = endx;
1418                     cury = endy;
1419                     break;
1420                 case PathIterator.SEG_QUADTO:
1421                     crossings =
1422                         Curve.rectCrossingsForQuad(crossings,
1423                                                    rxmin, rymin,
1424                                                    rxmax, rymax,
1425                                                    curx, cury,
1426                                                    coords[ci++],
1427                                                    coords[ci++],
1428                                                    endx = coords[ci++],
1429                                                    endy = coords[ci++],
1430                                                    0);
1431                     curx = endx;
1432                     cury = endy;
1433                     break;
1434                 case PathIterator.SEG_CUBICTO:
1435                     crossings =
1436                         Curve.rectCrossingsForCubic(crossings,
1437                                                     rxmin, rymin,
1438                                                     rxmax, rymax,
1439                                                     curx, cury,
1440                                                     coords[ci++],
1441                                                     coords[ci++],
1442                                                     coords[ci++],
1443                                                     coords[ci++],
1444                                                     endx = coords[ci++],
1445                                                     endy = coords[ci++],
1446                                                     0);
1447                     curx = endx;
1448                     cury = endy;
1449                     break;
1450                 case PathIterator.SEG_CLOSE:
1451                     if (curx != movx || cury != movy) {
1452                         crossings =
1453                             Curve.rectCrossingsForLine(crossings,
1454                                                        rxmin, rymin,
1455                                                        rxmax, rymax,
1456                                                        curx, cury,
1457                                                        movx, movy);
1458                     }
1459                     curx = movx;
1460                     cury = movy;
1461                     // Count should always be a multiple of 2 here.
1462                     // assert((crossings & 1) != 0);
1463                     break;
1464                 }
1465             }
1466             if (crossings != Curve.RECT_INTERSECTS &&
1467                 (curx != movx || cury != movy))
1468             {
1469                 crossings =
1470                     Curve.rectCrossingsForLine(crossings,
1471                                                rxmin, rymin,
1472                                                rxmax, rymax,
1473                                                curx, cury,
1474                                                movx, movy);
1475             }
1476             // Count should always be a multiple of 2 here.
1477             // assert((crossings & 1) != 0);
1478             return crossings;
1479         }
1480 
1481         /**
1482          * {@inheritDoc}
1483          * @since 1.6
1484          */
1485         public final void append(PathIterator pi, boolean connect) {
1486             double coords[] = new double[6];
1487             while (!pi.isDone()) {
1488                 switch (pi.currentSegment(coords)) {
1489                 case SEG_MOVETO:
1490                     if (!connect || numTypes < 1 || numCoords < 1) {
1491                         moveTo(coords[0], coords[1]);
1492                         break;
1493                     }
1494                     if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1495                         doubleCoords[numCoords-2] == coords[0] &&
1496                         doubleCoords[numCoords-1] == coords[1])
1497                     {
1498                         // Collapse out initial moveto/lineto
1499                         break;
1500                     }
1501                     lineTo(coords[0], coords[1]);
1502                     break;
1503                 case SEG_LINETO:
1504                     lineTo(coords[0], coords[1]);
1505                     break;
1506                 case SEG_QUADTO:
1507                     quadTo(coords[0], coords[1],
1508                            coords[2], coords[3]);
1509                     break;
1510                 case SEG_CUBICTO:
1511                     curveTo(coords[0], coords[1],
1512                             coords[2], coords[3],
1513                             coords[4], coords[5]);
1514                     break;
1515                 case SEG_CLOSE:
1516                     closePath();
1517                     break;
1518                 }
1519                 pi.next();
1520                 connect = false;
1521             }
1522         }
1523 
1524         /**
1525          * {@inheritDoc}
1526          * @since 1.6
1527          */
1528         public final void transform(AffineTransform at) {
1529             at.transform(doubleCoords, 0, doubleCoords, 0, numCoords / 2);
1530         }
1531 
1532         /**
1533          * {@inheritDoc}
1534          * @since 1.6
1535          */
1536         public final synchronized Rectangle2D getBounds2D() {
1537             double x1, y1, x2, y2;
1538             int i = numCoords;
1539             if (i > 0) {
1540                 y1 = y2 = doubleCoords[--i];
1541                 x1 = x2 = doubleCoords[--i];
1542                 while (i > 0) {
1543                     double y = doubleCoords[--i];
1544                     double x = doubleCoords[--i];
1545                     if (x < x1) x1 = x;
1546                     if (y < y1) y1 = y;
1547                     if (x > x2) x2 = x;
1548                     if (y > y2) y2 = y;
1549                 }
1550             } else {
1551                 x1 = y1 = x2 = y2 = 0.0;
1552             }
1553             return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
1554         }
1555 
1556         /**
1557          * {@inheritDoc}
1558          * <p>
1559          * The iterator for this class is not multi-threaded safe,
1560          * which means that the {@code Path2D} class does not
1561          * guarantee that modifications to the geometry of this
1562          * {@code Path2D} object do not affect any iterations of
1563          * that geometry that are already in process.
1564          *
1565          * @param at an {@code AffineTransform}
1566          * @return a new {@code PathIterator} that iterates along the boundary
1567          *         of this {@code Shape} and provides access to the geometry
1568          *         of this {@code Shape}'s outline
1569          * @since 1.6
1570          */
1571         public final PathIterator getPathIterator(AffineTransform at) {
1572             if (at == null) {
1573                 return new CopyIterator(this);
1574             } else {
1575                 return new TxIterator(this, at);
1576             }
1577         }
1578 
1579         /**
1580          * Creates a new object of the same class as this object.
1581          *
1582          * @return     a clone of this instance.
1583          * @exception  OutOfMemoryError    if there is not enough memory.
1584          * @see        java.lang.Cloneable
1585          * @since      1.6
1586          */
1587         public final Object clone() {
1588             // Note: It would be nice to have this return Path2D
1589             // but one of our subclasses (GeneralPath) needs to
1590             // offer "public Object clone()" for backwards
1591             // compatibility so we cannot restrict it further.
1592             // REMIND: Can we do both somehow?
1593             return new Path2D.Double(this);
1594         }
1595 
1596         /*
1597          * JDK 1.6 serialVersionUID
1598          */
1599         private static final long serialVersionUID = 1826762518450014216L;
1600 
1601         /**
1602          * Writes the default serializable fields to the
1603          * {@code ObjectOutputStream} followed by an explicit
1604          * serialization of the path segments stored in this
1605          * path.
1606          *
1607          * @serialData
1608          * <a name="Path2DSerialData"><!-- --></a>
1609          * <ol>
1610          * <li>The default serializable fields.
1611          * There are no default serializable fields as of 1.6.
1612          * <li>followed by
1613          * a byte indicating the storage type of the original object
1614          * as a hint (SERIAL_STORAGE_DBL_ARRAY)
1615          * <li>followed by
1616          * an integer indicating the number of path segments to follow (NP)
1617          * or -1 to indicate an unknown number of path segments follows
1618          * <li>followed by
1619          * an integer indicating the total number of coordinates to follow (NC)
1620          * or -1 to indicate an unknown number of coordinates follows
1621          * (NC should always be even since coordinates always appear in pairs
1622          *  representing an x,y pair)
1623          * <li>followed by
1624          * a byte indicating the winding rule
1625          * ({@link #WIND_EVEN_ODD WIND_EVEN_ODD} or
1626          *  {@link #WIND_NON_ZERO WIND_NON_ZERO})
1627          * <li>followed by
1628          * {@code NP} (or unlimited if {@code NP < 0}) sets of values consisting of
1629          * a single byte indicating a path segment type
1630          * followed by one or more pairs of float or double
1631          * values representing the coordinates of the path segment
1632          * <li>followed by
1633          * a byte indicating the end of the path (SERIAL_PATH_END).
1634          * </ol>
1635          * <p>
1636          * The following byte value constants are used in the serialized form
1637          * of {@code Path2D} objects:
1638          * <table>
1639          * <tr>
1640          * <th>Constant Name</th>
1641          * <th>Byte Value</th>
1642          * <th>Followed by</th>
1643          * <th>Description</th>
1644          * </tr>
1645          * <tr>
1646          * <td>{@code SERIAL_STORAGE_FLT_ARRAY}</td>
1647          * <td>0x30</td>
1648          * <td></td>
1649          * <td>A hint that the original {@code Path2D} object stored
1650          * the coordinates in a Java array of floats.</td>
1651          * </tr>
1652          * <tr>
1653          * <td>{@code SERIAL_STORAGE_DBL_ARRAY}</td>
1654          * <td>0x31</td>
1655          * <td></td>
1656          * <td>A hint that the original {@code Path2D} object stored
1657          * the coordinates in a Java array of doubles.</td>
1658          * </tr>
1659          * <tr>
1660          * <td>{@code SERIAL_SEG_FLT_MOVETO}</td>
1661          * <td>0x40</td>
1662          * <td>2 floats</td>
1663          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1664          * </tr>
1665          * <tr>
1666          * <td>{@code SERIAL_SEG_FLT_LINETO}</td>
1667          * <td>0x41</td>
1668          * <td>2 floats</td>
1669          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1670          * </tr>
1671          * <tr>
1672          * <td>{@code SERIAL_SEG_FLT_QUADTO}</td>
1673          * <td>0x42</td>
1674          * <td>4 floats</td>
1675          * <td>A {@link #quadTo quadTo} path segment follows.</td>
1676          * </tr>
1677          * <tr>
1678          * <td>{@code SERIAL_SEG_FLT_CUBICTO}</td>
1679          * <td>0x43</td>
1680          * <td>6 floats</td>
1681          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1682          * </tr>
1683          * <tr>
1684          * <td>{@code SERIAL_SEG_DBL_MOVETO}</td>
1685          * <td>0x50</td>
1686          * <td>2 doubles</td>
1687          * <td>A {@link #moveTo moveTo} path segment follows.</td>
1688          * </tr>
1689          * <tr>
1690          * <td>{@code SERIAL_SEG_DBL_LINETO}</td>
1691          * <td>0x51</td>
1692          * <td>2 doubles</td>
1693          * <td>A {@link #lineTo lineTo} path segment follows.</td>
1694          * </tr>
1695          * <tr>
1696          * <td>{@code SERIAL_SEG_DBL_QUADTO}</td>
1697          * <td>0x52</td>
1698          * <td>4 doubles</td>
1699          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1700          * </tr>
1701          * <tr>
1702          * <td>{@code SERIAL_SEG_DBL_CUBICTO}</td>
1703          * <td>0x53</td>
1704          * <td>6 doubles</td>
1705          * <td>A {@link #curveTo curveTo} path segment follows.</td>
1706          * </tr>
1707          * <tr>
1708          * <td>{@code SERIAL_SEG_CLOSE}</td>
1709          * <td>0x60</td>
1710          * <td></td>
1711          * <td>A {@link #closePath closePath} path segment.</td>
1712          * </tr>
1713          * <tr>
1714          * <td>{@code SERIAL_PATH_END}</td>
1715          * <td>0x61</td>
1716          * <td></td>
1717          * <td>There are no more path segments following.</td>
1718          * </table>
1719          *
1720          * @since 1.6
1721          */
1722         private void writeObject(java.io.ObjectOutputStream s)
1723             throws java.io.IOException
1724         {
1725             super.writeObject(s, true);
1726         }
1727 
1728         /**
1729          * Reads the default serializable fields from the
1730          * {@code ObjectInputStream} followed by an explicit
1731          * serialization of the path segments stored in this
1732          * path.
1733          * <p>
1734          * There are no default serializable fields as of 1.6.
1735          * <p>
1736          * The serial data for this object is described in the
1737          * writeObject method.
1738          *
1739          * @since 1.6
1740          */
1741         private void readObject(java.io.ObjectInputStream s)
1742             throws java.lang.ClassNotFoundException, java.io.IOException
1743         {
1744             super.readObject(s, true);
1745         }
1746 
1747         static class CopyIterator extends Path2D.Iterator {
1748             double doubleCoords[];
1749 
1750             CopyIterator(Path2D.Double p2dd) {
1751                 super(p2dd);
1752                 this.doubleCoords = p2dd.doubleCoords;
1753             }
1754 
1755             public int currentSegment(float[] coords) {
1756                 int type = path.pointTypes[typeIdx];
1757                 int numCoords = curvecoords[type];
1758                 if (numCoords > 0) {
1759                     for (int i = 0; i < numCoords; i++) {
1760                         coords[i] = (float) doubleCoords[pointIdx + i];
1761                     }
1762                 }
1763                 return type;
1764             }
1765 
1766             public int currentSegment(double[] coords) {
1767                 int type = path.pointTypes[typeIdx];
1768                 int numCoords = curvecoords[type];
1769                 if (numCoords > 0) {
1770                     System.arraycopy(doubleCoords, pointIdx,
1771                                      coords, 0, numCoords);
1772                 }
1773                 return type;
1774             }
1775         }
1776 
1777         static class TxIterator extends Path2D.Iterator {
1778             double doubleCoords[];
1779             AffineTransform affine;
1780 
1781             TxIterator(Path2D.Double p2dd, AffineTransform at) {
1782                 super(p2dd);
1783                 this.doubleCoords = p2dd.doubleCoords;
1784                 this.affine = at;
1785             }
1786 
1787             public int currentSegment(float[] coords) {
1788                 int type = path.pointTypes[typeIdx];
1789                 int numCoords = curvecoords[type];
1790                 if (numCoords > 0) {
1791                     affine.transform(doubleCoords, pointIdx,
1792                                      coords, 0, numCoords / 2);
1793                 }
1794                 return type;
1795             }
1796 
1797             public int currentSegment(double[] coords) {
1798                 int type = path.pointTypes[typeIdx];
1799                 int numCoords = curvecoords[type];
1800                 if (numCoords > 0) {
1801                     affine.transform(doubleCoords, pointIdx,
1802                                      coords, 0, numCoords / 2);
1803                 }
1804                 return type;
1805             }
1806         }
1807     }
1808 
1809     /**
1810      * Adds a point to the path by moving to the specified
1811      * coordinates specified in double precision.
1812      *
1813      * @param x the specified X coordinate
1814      * @param y the specified Y coordinate
1815      * @since 1.6
1816      */
1817     public abstract void moveTo(double x, double y);
1818 
1819     /**
1820      * Adds a point to the path by drawing a straight line from the
1821      * current coordinates to the new specified coordinates
1822      * 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 lineTo(double x, double y);
1829 
1830     /**
1831      * Adds a curved segment, defined by two new points, to the path by
1832      * drawing a Quadratic curve that intersects both the current
1833      * coordinates and the specified coordinates {@code (x2,y2)},
1834      * using the specified point {@code (x1,y1)} as a quadratic
1835      * parametric control point.
1836      * All coordinates are specified in double precision.
1837      *
1838      * @param x1 the X coordinate of the quadratic control point
1839      * @param y1 the Y coordinate of the quadratic control point
1840      * @param x2 the X coordinate of the final end point
1841      * @param y2 the Y coordinate of the final end point
1842      * @since 1.6
1843      */
1844     public abstract void quadTo(double x1, double y1,
1845                                 double x2, double y2);
1846 
1847     /**
1848      * Adds a curved segment, defined by three new points, to the path by
1849      * drawing a B&eacute;zier curve that intersects both the current
1850      * coordinates and the specified coordinates {@code (x3,y3)},
1851      * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
1852      * B&eacute;zier control points.
1853      * All coordinates are specified in double precision.
1854      *
1855      * @param x1 the X coordinate of the first B&eacute;zier control point
1856      * @param y1 the Y coordinate of the first B&eacute;zier control point
1857      * @param x2 the X coordinate of the second B&eacute;zier control point
1858      * @param y2 the Y coordinate of the second B&eacute;zier control point
1859      * @param x3 the X coordinate of the final end point
1860      * @param y3 the Y coordinate of the final end point
1861      * @since 1.6
1862      */
1863     public abstract void curveTo(double x1, double y1,
1864                                  double x2, double y2,
1865                                  double x3, double y3);
1866 
1867     /**
1868      * Closes the current subpath by drawing a straight line back to
1869      * the coordinates of the last {@code moveTo}.  If the path is already
1870      * closed then this method has no effect.
1871      *
1872      * @since 1.6
1873      */
1874     public final synchronized void closePath() {
1875         if (numTypes == 0 || pointTypes[numTypes - 1] != SEG_CLOSE) {
1876             needRoom(true, 0);
1877             pointTypes[numTypes++] = SEG_CLOSE;
1878         }
1879     }
1880 
1881     /**
1882      * Appends the geometry of the specified {@code Shape} object to the
1883      * path, possibly connecting the new geometry to the existing path
1884      * segments with a line segment.
1885      * If the {@code connect} parameter is {@code true} and the
1886      * path is not empty then any initial {@code moveTo} in the
1887      * geometry of the appended {@code Shape}
1888      * is turned into a {@code lineTo} segment.
1889      * If the destination coordinates of such a connecting {@code lineTo}
1890      * segment match the ending coordinates of a currently open
1891      * subpath then the segment is omitted as superfluous.
1892      * The winding rule of the specified {@code Shape} is ignored
1893      * and the appended geometry is governed by the winding
1894      * rule specified for this path.
1895      *
1896      * @param s the {@code Shape} whose geometry is appended
1897      *          to this path
1898      * @param connect a boolean to control whether or not to turn an initial
1899      *                {@code moveTo} segment into a {@code lineTo} segment
1900      *                to connect the new geometry to the existing path
1901      * @since 1.6
1902      */
1903     public final void append(Shape s, boolean connect) {
1904         append(s.getPathIterator(null), connect);
1905     }
1906 
1907     /**
1908      * Appends the geometry of the specified
1909      * {@link PathIterator} object
1910      * to the path, possibly connecting the new geometry to the existing
1911      * path segments with a line segment.
1912      * If the {@code connect} parameter is {@code true} and the
1913      * path is not empty then any initial {@code moveTo} in the
1914      * geometry of the appended {@code Shape} is turned into a
1915      * {@code lineTo} segment.
1916      * If the destination coordinates of such a connecting {@code lineTo}
1917      * segment match the ending coordinates of a currently open
1918      * subpath then the segment is omitted as superfluous.
1919      * The winding rule of the specified {@code Shape} is ignored
1920      * and the appended geometry is governed by the winding
1921      * rule specified for this path.
1922      *
1923      * @param pi the {@code PathIterator} whose geometry is appended to
1924      *           this path
1925      * @param connect a boolean to control whether or not to turn an initial
1926      *                {@code moveTo} segment into a {@code lineTo} segment
1927      *                to connect the new geometry to the existing path
1928      * @since 1.6
1929      */
1930     public abstract void append(PathIterator pi, boolean connect);
1931 
1932     /**
1933      * Returns the fill style winding rule.
1934      *
1935      * @return an integer representing the current winding rule.
1936      * @see #WIND_EVEN_ODD
1937      * @see #WIND_NON_ZERO
1938      * @see #setWindingRule
1939      * @since 1.6
1940      */
1941     public final synchronized int getWindingRule() {
1942         return windingRule;
1943     }
1944 
1945     /**
1946      * Sets the winding rule for this path to the specified value.
1947      *
1948      * @param rule an integer representing the specified
1949      *             winding rule
1950      * @exception IllegalArgumentException if
1951      *          {@code rule} is not either
1952      *          {@link #WIND_EVEN_ODD} or
1953      *          {@link #WIND_NON_ZERO}
1954      * @see #getWindingRule
1955      * @since 1.6
1956      */
1957     public final void setWindingRule(int rule) {
1958         if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
1959             throw new IllegalArgumentException("winding rule must be "+
1960                                                "WIND_EVEN_ODD or "+
1961                                                "WIND_NON_ZERO");
1962         }
1963         windingRule = rule;
1964     }
1965 
1966     /**
1967      * Returns the coordinates most recently added to the end of the path
1968      * as a {@link Point2D} object.
1969      *
1970      * @return a {@code Point2D} object containing the ending coordinates of
1971      *         the path or {@code null} if there are no points in the path.
1972      * @since 1.6
1973      */
1974     public final synchronized Point2D getCurrentPoint() {
1975         int index = numCoords;
1976         if (numTypes < 1 || index < 1) {
1977             return null;
1978         }
1979         if (pointTypes[numTypes - 1] == SEG_CLOSE) {
1980         loop:
1981             for (int i = numTypes - 2; i > 0; i--) {
1982                 switch (pointTypes[i]) {
1983                 case SEG_MOVETO:
1984                     break loop;
1985                 case SEG_LINETO:
1986                     index -= 2;
1987                     break;
1988                 case SEG_QUADTO:
1989                     index -= 4;
1990                     break;
1991                 case SEG_CUBICTO:
1992                     index -= 6;
1993                     break;
1994                 case SEG_CLOSE:
1995                     break;
1996                 }
1997             }
1998         }
1999         return getPoint(index - 2);
2000     }
2001 
2002     /**
2003      * Resets the path to empty.  The append position is set back to the
2004      * beginning of the path and all coordinates and point types are
2005      * forgotten.
2006      *
2007      * @since 1.6
2008      */
2009     public final synchronized void reset() {
2010         numTypes = numCoords = 0;
2011     }
2012 
2013     /**
2014      * Transforms the geometry of this path using the specified
2015      * {@link AffineTransform}.
2016      * The geometry is transformed in place, which permanently changes the
2017      * boundary defined by this object.
2018      *
2019      * @param at the {@code AffineTransform} used to transform the area
2020      * @since 1.6
2021      */
2022     public abstract void transform(AffineTransform at);
2023 
2024     /**
2025      * Returns a new {@code Shape} representing a transformed version
2026      * of this {@code Path2D}.
2027      * Note that the exact type and coordinate precision of the return
2028      * value is not specified for this method.
2029      * The method will return a Shape that contains no less precision
2030      * for the transformed geometry than this {@code Path2D} currently
2031      * maintains, but it may contain no more precision either.
2032      * If the tradeoff of precision vs. storage size in the result is
2033      * important then the convenience constructors in the
2034      * {@link Path2D.Float#Float(Shape, AffineTransform) Path2D.Float}
2035      * and
2036      * {@link Path2D.Double#Double(Shape, AffineTransform) Path2D.Double}
2037      * subclasses should be used to make the choice explicit.
2038      *
2039      * @param at the {@code AffineTransform} used to transform a
2040      *           new {@code Shape}.
2041      * @return a new {@code Shape}, transformed with the specified
2042      *         {@code AffineTransform}.
2043      * @since 1.6
2044      */
2045     public final synchronized Shape createTransformedShape(AffineTransform at) {
2046         Path2D p2d = (Path2D) clone();
2047         if (at != null) {
2048             p2d.transform(at);
2049         }
2050         return p2d;
2051     }
2052 
2053     /**
2054      * {@inheritDoc}
2055      * @since 1.6
2056      */
2057     public final Rectangle getBounds() {
2058         return getBounds2D().getBounds();
2059     }
2060 
2061     /**
2062      * Tests if the specified coordinates are inside the closed
2063      * boundary of the specified {@link PathIterator}.
2064      * <p>
2065      * This method provides a basic facility for implementors of
2066      * the {@link Shape} interface to implement support for the
2067      * {@link Shape#contains(double, double)} method.
2068      *
2069      * @param pi the specified {@code PathIterator}
2070      * @param x the specified X coordinate
2071      * @param y the specified Y coordinate
2072      * @return {@code true} if the specified coordinates are inside the
2073      *         specified {@code PathIterator}; {@code false} otherwise
2074      * @since 1.6
2075      */
2076     public static boolean contains(PathIterator pi, double x, double y) {
2077         if (x * 0.0 + y * 0.0 == 0.0) {
2078             /* N * 0.0 is 0.0 only if N is finite.
2079              * Here we know that both x and y are finite.
2080              */
2081             int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 1);
2082             int cross = Curve.pointCrossingsForPath(pi, x, y);
2083             return ((cross & mask) != 0);
2084         } else {
2085             /* Either x or y was infinite or NaN.
2086              * A NaN always produces a negative response to any test
2087              * and Infinity values cannot be "inside" any path so
2088              * they should return false as well.
2089              */
2090             return false;
2091         }
2092     }
2093 
2094     /**
2095      * Tests if the specified {@link Point2D} is inside the closed
2096      * boundary of the specified {@link PathIterator}.
2097      * <p>
2098      * This method provides a basic facility for implementors of
2099      * the {@link Shape} interface to implement support for the
2100      * {@link Shape#contains(Point2D)} method.
2101      *
2102      * @param pi the specified {@code PathIterator}
2103      * @param p the specified {@code Point2D}
2104      * @return {@code true} if the specified coordinates are inside the
2105      *         specified {@code PathIterator}; {@code false} otherwise
2106      * @since 1.6
2107      */
2108     public static boolean contains(PathIterator pi, Point2D p) {
2109         return contains(pi, p.getX(), p.getY());
2110     }
2111 
2112     /**
2113      * {@inheritDoc}
2114      * @since 1.6
2115      */
2116     public final boolean contains(double x, double y) {
2117         if (x * 0.0 + y * 0.0 == 0.0) {
2118             /* N * 0.0 is 0.0 only if N is finite.
2119              * Here we know that both x and y are finite.
2120              */
2121             if (numTypes < 2) {
2122                 return false;
2123             }
2124             int mask = (windingRule == WIND_NON_ZERO ? -1 : 1);
2125             return ((pointCrossings(x, y) & mask) != 0);
2126         } else {
2127             /* Either x or y was infinite or NaN.
2128              * A NaN always produces a negative response to any test
2129              * and Infinity values cannot be "inside" any path so
2130              * they should return false as well.
2131              */
2132             return false;
2133         }
2134     }
2135 
2136     /**
2137      * {@inheritDoc}
2138      * @since 1.6
2139      */
2140     public final boolean contains(Point2D p) {
2141         return contains(p.getX(), p.getY());
2142     }
2143 
2144     /**
2145      * Tests if the specified rectangular area is entirely inside the
2146      * closed boundary of the specified {@link PathIterator}.
2147      * <p>
2148      * This method provides a basic facility for implementors of
2149      * the {@link Shape} interface to implement support for the
2150      * {@link Shape#contains(double, double, double, double)} method.
2151      * <p>
2152      * This method object may conservatively return false in
2153      * cases where the specified rectangular area intersects a
2154      * segment of the path, but that segment does not represent a
2155      * boundary between the interior and exterior of the path.
2156      * Such segments could lie entirely within the interior of the
2157      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2158      * winding rule or if the segments are retraced in the reverse
2159      * direction such that the two sets of segments cancel each
2160      * other out without any exterior area falling between them.
2161      * To determine whether segments represent true boundaries of
2162      * the interior of the path would require extensive calculations
2163      * involving all of the segments of the path and the winding
2164      * rule and are thus beyond the scope of this implementation.
2165      *
2166      * @param pi the specified {@code PathIterator}
2167      * @param x the specified X coordinate
2168      * @param y the specified Y coordinate
2169      * @param w the width of the specified rectangular area
2170      * @param h the height of the specified rectangular area
2171      * @return {@code true} if the specified {@code PathIterator} contains
2172      *         the specified rectangular area; {@code false} otherwise.
2173      * @since 1.6
2174      */
2175     public static boolean contains(PathIterator pi,
2176                                    double x, double y, double w, double h)
2177     {
2178         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2179             /* [xy]+[wh] is NaN if any of those values are NaN,
2180              * or if adding the two together would produce NaN
2181              * by virtue of adding opposing Infinte values.
2182              * Since we need to add them below, their sum must
2183              * not be NaN.
2184              * We return false because NaN always produces a
2185              * negative response to tests
2186              */
2187             return false;
2188         }
2189         if (w <= 0 || h <= 0) {
2190             return false;
2191         }
2192         int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2193         int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2194         return (crossings != Curve.RECT_INTERSECTS &&
2195                 (crossings & mask) != 0);
2196     }
2197 
2198     /**
2199      * Tests if the specified {@link Rectangle2D} is entirely inside the
2200      * closed boundary of the specified {@link PathIterator}.
2201      * <p>
2202      * This method provides a basic facility for implementors of
2203      * the {@link Shape} interface to implement support for the
2204      * {@link Shape#contains(Rectangle2D)} method.
2205      * <p>
2206      * This method object may conservatively return false in
2207      * cases where the specified rectangular area intersects a
2208      * segment of the path, but that segment does not represent a
2209      * boundary between the interior and exterior of the path.
2210      * Such segments could lie entirely within the interior of the
2211      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2212      * winding rule or if the segments are retraced in the reverse
2213      * direction such that the two sets of segments cancel each
2214      * other out without any exterior area falling between them.
2215      * To determine whether segments represent true boundaries of
2216      * the interior of the path would require extensive calculations
2217      * involving all of the segments of the path and the winding
2218      * rule and are thus beyond the scope of this implementation.
2219      *
2220      * @param pi the specified {@code PathIterator}
2221      * @param r a specified {@code Rectangle2D}
2222      * @return {@code true} if the specified {@code PathIterator} contains
2223      *         the specified {@code Rectangle2D}; {@code false} otherwise.
2224      * @since 1.6
2225      */
2226     public static boolean contains(PathIterator pi, Rectangle2D r) {
2227         return contains(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2228     }
2229 
2230     /**
2231      * {@inheritDoc}
2232      * <p>
2233      * This method object may conservatively return false in
2234      * cases where the specified rectangular area intersects a
2235      * segment of the path, but that segment does not represent a
2236      * boundary between the interior and exterior of the path.
2237      * Such segments could lie entirely within the interior of the
2238      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2239      * winding rule or if the segments are retraced in the reverse
2240      * direction such that the two sets of segments cancel each
2241      * other out without any exterior area falling between them.
2242      * To determine whether segments represent true boundaries of
2243      * the interior of the path would require extensive calculations
2244      * involving all of the segments of the path and the winding
2245      * rule and are thus beyond the scope of this implementation.
2246      *
2247      * @since 1.6
2248      */
2249     public final boolean contains(double x, double y, double w, double h) {
2250         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2251             /* [xy]+[wh] is NaN if any of those values are NaN,
2252              * or if adding the two together would produce NaN
2253              * by virtue of adding opposing Infinte values.
2254              * Since we need to add them below, their sum must
2255              * not be NaN.
2256              * We return false because NaN always produces a
2257              * negative response to tests
2258              */
2259             return false;
2260         }
2261         if (w <= 0 || h <= 0) {
2262             return false;
2263         }
2264         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2265         int crossings = rectCrossings(x, y, x+w, y+h);
2266         return (crossings != Curve.RECT_INTERSECTS &&
2267                 (crossings & mask) != 0);
2268     }
2269 
2270     /**
2271      * {@inheritDoc}
2272      * <p>
2273      * This method object may conservatively return false in
2274      * cases where the specified rectangular area intersects a
2275      * segment of the path, but that segment does not represent a
2276      * boundary between the interior and exterior of the path.
2277      * Such segments could lie entirely within the interior of the
2278      * path if they are part of a path with a {@link #WIND_NON_ZERO}
2279      * winding rule or if the segments are retraced in the reverse
2280      * direction such that the two sets of segments cancel each
2281      * other out without any exterior area falling between them.
2282      * To determine whether segments represent true boundaries of
2283      * the interior of the path would require extensive calculations
2284      * involving all of the segments of the path and the winding
2285      * rule and are thus beyond the scope of this implementation.
2286      *
2287      * @since 1.6
2288      */
2289     public final boolean contains(Rectangle2D r) {
2290         return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2291     }
2292 
2293     /**
2294      * Tests if the interior of the specified {@link PathIterator}
2295      * intersects the interior of a specified set of rectangular
2296      * coordinates.
2297      * <p>
2298      * This method provides a basic facility for implementors of
2299      * the {@link Shape} interface to implement support for the
2300      * {@link Shape#intersects(double, double, double, double)} method.
2301      * <p>
2302      * This method object may conservatively return true in
2303      * cases where the specified rectangular area intersects a
2304      * segment of the path, but that segment does not represent a
2305      * boundary between the interior and exterior of the path.
2306      * Such a case may occur if some set of segments of the
2307      * path are retraced in the reverse direction such that the
2308      * two sets of segments cancel each other out without any
2309      * interior area between them.
2310      * To determine whether segments represent true boundaries of
2311      * the interior of the path would require extensive calculations
2312      * involving all of the segments of the path and the winding
2313      * rule and are thus beyond the scope of this implementation.
2314      *
2315      * @param pi the specified {@code PathIterator}
2316      * @param x the specified X coordinate
2317      * @param y the specified Y coordinate
2318      * @param w the width of the specified rectangular coordinates
2319      * @param h the height of the specified rectangular coordinates
2320      * @return {@code true} if the specified {@code PathIterator} and
2321      *         the interior of the specified set of rectangular
2322      *         coordinates intersect each other; {@code false} otherwise.
2323      * @since 1.6
2324      */
2325     public static boolean intersects(PathIterator pi,
2326                                      double x, double y, double w, double h)
2327     {
2328         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2329             /* [xy]+[wh] is NaN if any of those values are NaN,
2330              * or if adding the two together would produce NaN
2331              * by virtue of adding opposing Infinte values.
2332              * Since we need to add them below, their sum must
2333              * not be NaN.
2334              * We return false because NaN always produces a
2335              * negative response to tests
2336              */
2337             return false;
2338         }
2339         if (w <= 0 || h <= 0) {
2340             return false;
2341         }
2342         int mask = (pi.getWindingRule() == WIND_NON_ZERO ? -1 : 2);
2343         int crossings = Curve.rectCrossingsForPath(pi, x, y, x+w, y+h);
2344         return (crossings == Curve.RECT_INTERSECTS ||
2345                 (crossings & mask) != 0);
2346     }
2347 
2348     /**
2349      * Tests if the interior of the specified {@link PathIterator}
2350      * intersects the interior of a specified {@link Rectangle2D}.
2351      * <p>
2352      * This method provides a basic facility for implementors of
2353      * the {@link Shape} interface to implement support for the
2354      * {@link Shape#intersects(Rectangle2D)} method.
2355      * <p>
2356      * This method object may conservatively return true in
2357      * cases where the specified rectangular area intersects a
2358      * segment of the path, but that segment does not represent a
2359      * boundary between the interior and exterior of the path.
2360      * Such a case may occur if some set of segments of the
2361      * path are retraced in the reverse direction such that the
2362      * two sets of segments cancel each other out without any
2363      * interior area between them.
2364      * To determine whether segments represent true boundaries of
2365      * the interior of the path would require extensive calculations
2366      * involving all of the segments of the path and the winding
2367      * rule and are thus beyond the scope of this implementation.
2368      *
2369      * @param pi the specified {@code PathIterator}
2370      * @param r the specified {@code Rectangle2D}
2371      * @return {@code true} if the specified {@code PathIterator} and
2372      *         the interior of the specified {@code Rectangle2D}
2373      *         intersect each other; {@code false} otherwise.
2374      * @since 1.6
2375      */
2376     public static boolean intersects(PathIterator pi, Rectangle2D r) {
2377         return intersects(pi, r.getX(), r.getY(), r.getWidth(), r.getHeight());
2378     }
2379 
2380     /**
2381      * {@inheritDoc}
2382      * <p>
2383      * This method object may conservatively return true in
2384      * cases where the specified rectangular area intersects a
2385      * segment of the path, but that segment does not represent a
2386      * boundary between the interior and exterior of the path.
2387      * Such a case may occur if some set of segments of the
2388      * path are retraced in the reverse direction such that the
2389      * two sets of segments cancel each other out without any
2390      * interior area between them.
2391      * To determine whether segments represent true boundaries of
2392      * the interior of the path would require extensive calculations
2393      * involving all of the segments of the path and the winding
2394      * rule and are thus beyond the scope of this implementation.
2395      *
2396      * @since 1.6
2397      */
2398     public final boolean intersects(double x, double y, double w, double h) {
2399         if (java.lang.Double.isNaN(x+w) || java.lang.Double.isNaN(y+h)) {
2400             /* [xy]+[wh] is NaN if any of those values are NaN,
2401              * or if adding the two together would produce NaN
2402              * by virtue of adding opposing Infinte values.
2403              * Since we need to add them below, their sum must
2404              * not be NaN.
2405              * We return false because NaN always produces a
2406              * negative response to tests
2407              */
2408             return false;
2409         }
2410         if (w <= 0 || h <= 0) {
2411             return false;
2412         }
2413         int mask = (windingRule == WIND_NON_ZERO ? -1 : 2);
2414         int crossings = rectCrossings(x, y, x+w, y+h);
2415         return (crossings == Curve.RECT_INTERSECTS ||
2416                 (crossings & mask) != 0);
2417     }
2418 
2419     /**
2420      * {@inheritDoc}
2421      * <p>
2422      * This method object may conservatively return true in
2423      * cases where the specified rectangular area intersects a
2424      * segment of the path, but that segment does not represent a
2425      * boundary between the interior and exterior of the path.
2426      * Such a case may occur if some set of segments of the
2427      * path are retraced in the reverse direction such that the
2428      * two sets of segments cancel each other out without any
2429      * interior area between them.
2430      * To determine whether segments represent true boundaries of
2431      * the interior of the path would require extensive calculations
2432      * involving all of the segments of the path and the winding
2433      * rule and are thus beyond the scope of this implementation.
2434      *
2435      * @since 1.6
2436      */
2437     public final boolean intersects(Rectangle2D r) {
2438         return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
2439     }
2440 
2441     /**
2442      * {@inheritDoc}
2443      * <p>
2444      * The iterator for this class is not multi-threaded safe,
2445      * which means that this {@code Path2D} class does not
2446      * guarantee that modifications to the geometry of this
2447      * {@code Path2D} object do not affect any iterations of
2448      * that geometry that are already in process.
2449      *
2450      * @since 1.6
2451      */
2452     public final PathIterator getPathIterator(AffineTransform at,
2453                                               double flatness)
2454     {
2455         return new FlatteningPathIterator(getPathIterator(at), flatness);
2456     }
2457 
2458     /**
2459      * Creates a new object of the same class as this object.
2460      *
2461      * @return     a clone of this instance.
2462      * @exception  OutOfMemoryError            if there is not enough memory.
2463      * @see        java.lang.Cloneable
2464      * @since      1.6
2465      */
2466     public abstract Object clone();
2467         // Note: It would be nice to have this return Path2D
2468         // but one of our subclasses (GeneralPath) needs to
2469         // offer "public Object clone()" for backwards
2470         // compatibility so we cannot restrict it further.
2471         // REMIND: Can we do both somehow?
2472 
2473     /*
2474      * Support fields and methods for serializing the subclasses.
2475      */
2476     private static final byte SERIAL_STORAGE_FLT_ARRAY = 0x30;
2477     private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2478 
2479     private static final byte SERIAL_SEG_FLT_MOVETO    = 0x40;
2480     private static final byte SERIAL_SEG_FLT_LINETO    = 0x41;
2481     private static final byte SERIAL_SEG_FLT_QUADTO    = 0x42;
2482     private static final byte SERIAL_SEG_FLT_CUBICTO   = 0x43;
2483 
2484     private static final byte SERIAL_SEG_DBL_MOVETO    = 0x50;
2485     private static final byte SERIAL_SEG_DBL_LINETO    = 0x51;
2486     private static final byte SERIAL_SEG_DBL_QUADTO    = 0x52;
2487     private static final byte SERIAL_SEG_DBL_CUBICTO   = 0x53;
2488 
2489     private static final byte SERIAL_SEG_CLOSE         = 0x60;
2490     private static final byte SERIAL_PATH_END          = 0x61;
2491 
2492     final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2493         throws java.io.IOException
2494     {
2495         s.defaultWriteObject();
2496 
2497         float fCoords[];
2498         double dCoords[];
2499 
2500         if (isdbl) {
2501             dCoords = ((Path2D.Double) this).doubleCoords;
2502             fCoords = null;
2503         } else {
2504             fCoords = ((Path2D.Float) this).floatCoords;
2505             dCoords = null;
2506         }
2507 
2508         int numTypes = this.numTypes;
2509 
2510         s.writeByte(isdbl
2511                     ? SERIAL_STORAGE_DBL_ARRAY
2512                     : SERIAL_STORAGE_FLT_ARRAY);
2513         s.writeInt(numTypes);
2514         s.writeInt(numCoords);
2515         s.writeByte((byte) windingRule);
2516 
2517         int cindex = 0;
2518         for (int i = 0; i < numTypes; i++) {
2519             int npoints;
2520             byte serialtype;
2521             switch (pointTypes[i]) {
2522             case SEG_MOVETO:
2523                 npoints = 1;
2524                 serialtype = (isdbl
2525                               ? SERIAL_SEG_DBL_MOVETO
2526                               : SERIAL_SEG_FLT_MOVETO);
2527                 break;
2528             case SEG_LINETO:
2529                 npoints = 1;
2530                 serialtype = (isdbl
2531                               ? SERIAL_SEG_DBL_LINETO
2532                               : SERIAL_SEG_FLT_LINETO);
2533                 break;
2534             case SEG_QUADTO:
2535                 npoints = 2;
2536                 serialtype = (isdbl
2537                               ? SERIAL_SEG_DBL_QUADTO
2538                               : SERIAL_SEG_FLT_QUADTO);
2539                 break;
2540             case SEG_CUBICTO:
2541                 npoints = 3;
2542                 serialtype = (isdbl
2543                               ? SERIAL_SEG_DBL_CUBICTO
2544                               : SERIAL_SEG_FLT_CUBICTO);
2545                 break;
2546             case SEG_CLOSE:
2547                 npoints = 0;
2548                 serialtype = SERIAL_SEG_CLOSE;
2549                 break;
2550 
2551             default:
2552                 // Should never happen
2553                 throw new InternalError("unrecognized path type");
2554             }
2555             s.writeByte(serialtype);
2556             while (--npoints >= 0) {
2557                 if (isdbl) {
2558                     s.writeDouble(dCoords[cindex++]);
2559                     s.writeDouble(dCoords[cindex++]);
2560                 } else {
2561                     s.writeFloat(fCoords[cindex++]);
2562                     s.writeFloat(fCoords[cindex++]);
2563                 }
2564             }
2565         }
2566         s.writeByte(SERIAL_PATH_END);
2567     }
2568 
2569     final void readObject(java.io.ObjectInputStream s, boolean storedbl)
2570         throws java.lang.ClassNotFoundException, java.io.IOException
2571     {
2572         s.defaultReadObject();
2573 
2574         // The subclass calls this method with the storage type that
2575         // they want us to use (storedbl) so we ignore the storage
2576         // method hint from the stream.
2577         s.readByte();
2578         int nT = s.readInt();
2579         int nC = s.readInt();
2580         try {
2581             setWindingRule(s.readByte());
2582         } catch (IllegalArgumentException iae) {
2583             throw new java.io.InvalidObjectException(iae.getMessage());
2584         }
2585 
2586         pointTypes = new byte[(nT < 0) ? INIT_SIZE : nT];
2587         if (nC < 0) {
2588             nC = INIT_SIZE * 2;
2589         }
2590         if (storedbl) {
2591             ((Path2D.Double) this).doubleCoords = new double[nC];
2592         } else {
2593             ((Path2D.Float) this).floatCoords = new float[nC];
2594         }
2595 
2596     PATHDONE:
2597         for (int i = 0; nT < 0 || i < nT; i++) {
2598             boolean isdbl;
2599             int npoints;
2600             byte segtype;
2601 
2602             byte serialtype = s.readByte();
2603             switch (serialtype) {
2604             case SERIAL_SEG_FLT_MOVETO:
2605                 isdbl = false;
2606                 npoints = 1;
2607                 segtype = SEG_MOVETO;
2608                 break;
2609             case SERIAL_SEG_FLT_LINETO:
2610                 isdbl = false;
2611                 npoints = 1;
2612                 segtype = SEG_LINETO;
2613                 break;
2614             case SERIAL_SEG_FLT_QUADTO:
2615                 isdbl = false;
2616                 npoints = 2;
2617                 segtype = SEG_QUADTO;
2618                 break;
2619             case SERIAL_SEG_FLT_CUBICTO:
2620                 isdbl = false;
2621                 npoints = 3;
2622                 segtype = SEG_CUBICTO;
2623                 break;
2624 
2625             case SERIAL_SEG_DBL_MOVETO:
2626                 isdbl = true;
2627                 npoints = 1;
2628                 segtype = SEG_MOVETO;
2629                 break;
2630             case SERIAL_SEG_DBL_LINETO:
2631                 isdbl = true;
2632                 npoints = 1;
2633                 segtype = SEG_LINETO;
2634                 break;
2635             case SERIAL_SEG_DBL_QUADTO:
2636                 isdbl = true;
2637                 npoints = 2;
2638                 segtype = SEG_QUADTO;
2639                 break;
2640             case SERIAL_SEG_DBL_CUBICTO:
2641                 isdbl = true;
2642                 npoints = 3;
2643                 segtype = SEG_CUBICTO;
2644                 break;
2645 
2646             case SERIAL_SEG_CLOSE:
2647                 isdbl = false;
2648                 npoints = 0;
2649                 segtype = SEG_CLOSE;
2650                 break;
2651 
2652             case SERIAL_PATH_END:
2653                 if (nT < 0) {
2654                     break PATHDONE;
2655                 }
2656                 throw new StreamCorruptedException("unexpected PATH_END");
2657 
2658             default:
2659                 throw new StreamCorruptedException("unrecognized path type");
2660             }
2661             needRoom(segtype != SEG_MOVETO, npoints * 2);
2662             if (isdbl) {
2663                 while (--npoints >= 0) {
2664                     append(s.readDouble(), s.readDouble());
2665                 }
2666             } else {
2667                 while (--npoints >= 0) {
2668                     append(s.readFloat(), s.readFloat());
2669                 }
2670             }
2671             pointTypes[numTypes++] = segtype;
2672         }
2673         if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2674             throw new StreamCorruptedException("missing PATH_END");
2675         }
2676     }
2677 
2678     abstract static class Iterator implements PathIterator {
2679         int typeIdx;
2680         int pointIdx;
2681         Path2D path;
2682 
2683         static final int curvecoords[] = {2, 2, 4, 6, 0};
2684 
2685         Iterator(Path2D path) {
2686             this.path = path;
2687         }
2688 
2689         public int getWindingRule() {
2690             return path.getWindingRule();
2691         }
2692 
2693         public boolean isDone() {
2694             return (typeIdx >= path.numTypes);
2695         }
2696 
2697         public void next() {
2698             int type = path.pointTypes[typeIdx++];
2699             pointIdx += curvecoords[type];
2700         }
2701     }
2702 }