--- a/jdk/src/java.desktop/share/classes/java/awt/geom/Path2D.java Tue Mar 31 16:23:01 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/geom/Path2D.java Wed Apr 01 11:23:47 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -224,8 +224,8 @@
Path2D p2d = (Path2D) s;
setWindingRule(p2d.windingRule);
this.numTypes = p2d.numTypes;
- this.pointTypes = Arrays.copyOf(p2d.pointTypes,
- p2d.pointTypes.length);
+ // trim arrays:
+ this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
this.numCoords = p2d.numCoords;
this.floatCoords = p2d.cloneCoordsFloat(at);
} else {
@@ -237,19 +237,23 @@
}
}
+ @Override
float[] cloneCoordsFloat(AffineTransform at) {
+ // trim arrays:
float ret[];
if (at == null) {
- ret = Arrays.copyOf(this.floatCoords, this.floatCoords.length);
+ ret = Arrays.copyOf(floatCoords, numCoords);
} else {
- ret = new float[floatCoords.length];
+ ret = new float[numCoords];
at.transform(floatCoords, 0, ret, 0, numCoords / 2);
}
return ret;
}
+ @Override
double[] cloneCoordsDouble(AffineTransform at) {
- double ret[] = new double[floatCoords.length];
+ // trim arrays:
+ double ret[] = new double[numCoords];
if (at == null) {
for (int i = 0; i < numCoords; i++) {
ret[i] = floatCoords[i];
@@ -475,6 +479,9 @@
}
int pointCrossings(double px, double py) {
+ if (numTypes == 0) {
+ return 0;
+ }
double movx, movy, curx, cury, endx, endy;
float coords[] = floatCoords;
curx = movx = coords[0];
@@ -552,6 +559,9 @@
int rectCrossings(double rxmin, double rymin,
double rxmax, double rymax)
{
+ if (numTypes == 0) {
+ return 0;
+ }
float coords[] = floatCoords;
double curx, cury, movx, movy, endx, endy;
curx = movx = coords[0];
@@ -1061,8 +1071,8 @@
Path2D p2d = (Path2D) s;
setWindingRule(p2d.windingRule);
this.numTypes = p2d.numTypes;
- this.pointTypes = Arrays.copyOf(p2d.pointTypes,
- p2d.pointTypes.length);
+ // trim arrays:
+ this.pointTypes = Arrays.copyOf(p2d.pointTypes, p2d.numTypes);
this.numCoords = p2d.numCoords;
this.doubleCoords = p2d.cloneCoordsDouble(at);
} else {
@@ -1074,8 +1084,10 @@
}
}
+ @Override
float[] cloneCoordsFloat(AffineTransform at) {
- float ret[] = new float[doubleCoords.length];
+ // trim arrays:
+ float ret[] = new float[numCoords];
if (at == null) {
for (int i = 0; i < numCoords; i++) {
ret[i] = (float) doubleCoords[i];
@@ -1086,13 +1098,14 @@
return ret;
}
+ @Override
double[] cloneCoordsDouble(AffineTransform at) {
+ // trim arrays:
double ret[];
if (at == null) {
- ret = Arrays.copyOf(this.doubleCoords,
- this.doubleCoords.length);
+ ret = Arrays.copyOf(doubleCoords, numCoords);
} else {
- ret = new double[doubleCoords.length];
+ ret = new double[numCoords];
at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
}
return ret;
@@ -1202,6 +1215,9 @@
}
int pointCrossings(double px, double py) {
+ if (numTypes == 0) {
+ return 0;
+ }
double movx, movy, curx, cury, endx, endy;
double coords[] = doubleCoords;
curx = movx = coords[0];
@@ -1279,6 +1295,9 @@
int rectCrossings(double rxmin, double rymin,
double rxmax, double rymax)
{
+ if (numTypes == 0) {
+ return 0;
+ }
double coords[] = doubleCoords;
double curx, cury, movx, movy, endx, endy;
curx = movx = coords[0];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java Wed Apr 01 11:23:47 2015 -0700
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.IllegalPathStateException;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+/**
+ * @test
+ * @bug 8076419
+ * @summary Check Path2D copy constructor (trims arrays)
+ * and constructor with zero capacity
+ * @run main Path2DTrimCopy
+ */
+public class Path2DCopyConstructor {
+
+ private final static float EPSILON = 5e-6f;
+ private final static float FLATNESS = 1e-2f;
+
+ private final static AffineTransform at
+ = AffineTransform.getScaleInstance(1.3, 2.4);
+
+ private final static Rectangle2D.Double rect2d
+ = new Rectangle2D.Double(3.2, 4.1, 5.0, 10.0);
+
+ private final static Point2D.Double pt2d
+ = new Point2D.Double(2.0, 2.5);
+
+ public static boolean verbose;
+
+ static void log(String msg) {
+ if (verbose) {
+ System.out.println(msg);
+ }
+ }
+
+ public static void main(String argv[]) {
+ verbose = (argv.length != 0);
+
+ testEmptyDoublePaths();
+ testDoublePaths();
+
+ testEmptyFloatPaths();
+ testFloatPaths();
+
+ testEmptyGeneralPath();
+ testGeneralPath();
+ }
+
+ static void testEmptyDoublePaths() {
+ log("\n - Test(Path2D.Double[0]) ---");
+ test(() -> new Path2D.Double(Path2D.WIND_NON_ZERO, 0));
+ }
+
+ static void testDoublePaths() {
+ log("\n - Test(Path2D.Double) ---");
+ test(() -> new Path2D.Double());
+ }
+
+ static void testEmptyFloatPaths() {
+ log("\n - Test(Path2D.Float[0]) ---");
+ test(() -> new Path2D.Float(Path2D.WIND_NON_ZERO, 0));
+ }
+
+ static void testFloatPaths() {
+ log("\n - Test(Path2D.Float) ---");
+ test(() -> new Path2D.Float());
+ }
+
+ static void testEmptyGeneralPath() {
+ log("\n - Test(GeneralPath[0]) ---");
+ test(() -> new GeneralPath(Path2D.WIND_NON_ZERO, 0));
+ }
+
+ static void testGeneralPath() {
+ log("\n - Test(GeneralPath) ---");
+ test(() -> new GeneralPath());
+ }
+
+ interface PathFactory {
+ Path2D makePath();
+ }
+
+ static void test(PathFactory pf) {
+ log("\n --- test: path(empty) ---");
+ test(pf.makePath(), true);
+ log("\n\n --- test: path(addMove) ---");
+ test(addMove(pf.makePath()), false);
+ log("\n\n --- test: path(addMoveAndLines) ---");
+ test(addMoveAndLines(pf.makePath()), false);
+ log("\n\n --- test: path(addMoveAndQuads) ---");
+ test(addMoveAndQuads(pf.makePath()), false);
+ log("\n\n --- test: path(addMoveAndCubics) ---");
+ test(addMoveAndCubics(pf.makePath()), false);
+ log("\n\n --- test: path(addMoveAndClose) ---");
+ test(addMoveAndClose(pf.makePath()), false);
+ }
+
+ static Path2D addMove(Path2D p2d) {
+ p2d.moveTo(1.0, 0.5);
+ return p2d;
+ }
+
+ static Path2D addMoveAndLines(Path2D p2d) {
+ addMove(p2d);
+ addLines(p2d);
+ return p2d;
+ }
+
+ static Path2D addLines(Path2D p2d) {
+ for (int i = 0; i < 10; i++) {
+ p2d.lineTo(1.1 * i, 2.3 * i);
+ }
+ return p2d;
+ }
+
+ static Path2D addMoveAndCubics(Path2D p2d) {
+ addMove(p2d);
+ addCubics(p2d);
+ return p2d;
+ }
+
+ static Path2D addCubics(Path2D p2d) {
+ for (int i = 0; i < 10; i++) {
+ p2d.curveTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i, 1.5 * i, 1.6 * i);
+ }
+ return p2d;
+ }
+
+ static Path2D addMoveAndQuads(Path2D p2d) {
+ addMove(p2d);
+ addQuads(p2d);
+ return p2d;
+ }
+
+ static Path2D addQuads(Path2D p2d) {
+ for (int i = 0; i < 10; i++) {
+ p2d.quadTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i);
+ }
+ return p2d;
+ }
+
+ static Path2D addMoveAndClose(Path2D p2d) {
+ addMove(p2d);
+ addClose(p2d);
+ return p2d;
+ }
+
+ static Path2D addClose(Path2D p2d) {
+ p2d.closePath();
+ return p2d;
+ }
+
+ static void test(Path2D p2d, boolean isEmpty) {
+ testEqual(new Path2D.Float(p2d), p2d);
+ testEqual(new Path2D.Double(p2d), p2d);
+ testEqual(new GeneralPath(p2d), p2d);
+
+ testIterator(new Path2D.Float(p2d), p2d);
+ testIterator(new Path2D.Double(p2d), p2d);
+ testIterator((Path2D) p2d.clone(), p2d);
+
+ testFlattening(new Path2D.Float(p2d), p2d);
+ testFlattening(new Path2D.Double(p2d), p2d);
+ testFlattening((Path2D) p2d.clone(), p2d);
+
+ testAddMove(new Path2D.Float(p2d));
+ testAddMove(new Path2D.Double(p2d));
+ testAddMove((Path2D) p2d.clone());
+
+ // These should expect exception if empty
+ testAddLine(new Path2D.Float(p2d), isEmpty);
+ testAddLine(new Path2D.Double(p2d), isEmpty);
+ testAddLine((Path2D) p2d.clone(), isEmpty);
+
+ testAddQuad(new Path2D.Float(p2d), isEmpty);
+ testAddQuad(new Path2D.Double(p2d), isEmpty);
+ testAddQuad((Path2D) p2d.clone(), isEmpty);
+
+ testAddCubic(new Path2D.Float(p2d), isEmpty);
+ testAddCubic(new Path2D.Double(p2d), isEmpty);
+ testAddCubic((Path2D) p2d.clone(), isEmpty);
+
+ testAddClose(new Path2D.Float(p2d), isEmpty);
+ testAddClose(new Path2D.Double(p2d), isEmpty);
+ testAddClose((Path2D) p2d.clone(), isEmpty);
+
+ testGetBounds(new Path2D.Float(p2d), p2d);
+ testGetBounds(new Path2D.Double(p2d), p2d);
+ testGetBounds((Path2D) p2d.clone(), p2d);
+
+ testTransform(new Path2D.Float(p2d));
+ testTransform(new Path2D.Double(p2d));
+ testTransform((Path2D) p2d.clone());
+
+ testIntersect(new Path2D.Float(p2d), p2d);
+ testIntersect(new Path2D.Double(p2d), p2d);
+ testIntersect((Path2D) p2d.clone(), p2d);
+
+ testContains(new Path2D.Float(p2d), p2d);
+ testContains(new Path2D.Double(p2d), p2d);
+ testContains((Path2D) p2d.clone(), p2d);
+
+ testGetCurrentPoint(new Path2D.Float(p2d), p2d);
+ testGetCurrentPoint(new Path2D.Double(p2d), p2d);
+ testGetCurrentPoint((Path2D) p2d.clone(), p2d);
+ }
+
+ static void testEqual(Path2D pathA, Path2D pathB) {
+ final PathIterator itA = pathA.getPathIterator(null);
+ final PathIterator itB = pathB.getPathIterator(null);
+
+ float[] coordsA = new float[6];
+ float[] coordsB = new float[6];
+
+ int n = 0;
+ for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
+ int typeA = itA.currentSegment(coordsA);
+ int typeB = itB.currentSegment(coordsB);
+
+ if (typeA != typeB) {
+ throw new IllegalStateException("Path-segment[" + n + "] "
+ + " type are not equals [" + typeA + "|" + typeB + "] !");
+ }
+ if (!equalsArray(coordsA, coordsB, getLength(typeA))) {
+ throw new IllegalStateException("Path-segment[" + n + "] coords"
+ + " are not equals [" + Arrays.toString(coordsA) + "|"
+ + Arrays.toString(coordsB) + "] !");
+ }
+ }
+ if (!itA.isDone() || !itB.isDone()) {
+ throw new IllegalStateException("Paths do not have same lengths !");
+ }
+ log("testEqual: " + n + " segments.");
+ }
+
+ static void testIterator(Path2D pathA, Path2D pathB) {
+ final PathIterator itA = pathA.getPathIterator(at);
+ final PathIterator itB = pathB.getPathIterator(at);
+
+ float[] coordsA = new float[6];
+ float[] coordsB = new float[6];
+
+ int n = 0;
+ for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
+ int typeA = itA.currentSegment(coordsA);
+ int typeB = itB.currentSegment(coordsB);
+
+ if (typeA != typeB) {
+ throw new IllegalStateException("Path-segment[" + n + "] "
+ + "type are not equals [" + typeA + "|" + typeB + "] !");
+ }
+ // Take care of floating-point precision:
+ if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) {
+ throw new IllegalStateException("Path-segment[" + n + "] coords"
+ + " are not equals [" + Arrays.toString(coordsA) + "|"
+ + Arrays.toString(coordsB) + "] !");
+ }
+ }
+ if (!itA.isDone() || !itB.isDone()) {
+ throw new IllegalStateException("Paths do not have same lengths !");
+ }
+ log("testIterator: " + n + " segments.");
+ }
+
+ static void testFlattening(Path2D pathA, Path2D pathB) {
+ final PathIterator itA = pathA.getPathIterator(at, FLATNESS);
+ final PathIterator itB = pathB.getPathIterator(at, FLATNESS);
+
+ float[] coordsA = new float[6];
+ float[] coordsB = new float[6];
+
+ int n = 0;
+ for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
+ int typeA = itA.currentSegment(coordsA);
+ int typeB = itB.currentSegment(coordsB);
+
+ if (typeA != typeB) {
+ throw new IllegalStateException("Path-segment[" + n + "] "
+ + "type are not equals [" + typeA + "|" + typeB + "] !");
+ }
+ // Take care of floating-point precision:
+ if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) {
+ throw new IllegalStateException("Path-segment[" + n + "] coords"
+ + " are not equals [" + Arrays.toString(coordsA) + "|"
+ + Arrays.toString(coordsB) + "] !");
+ }
+ }
+ if (!itA.isDone() || !itB.isDone()) {
+ throw new IllegalStateException("Paths do not have same lengths !");
+ }
+ log("testFlattening: " + n + " segments.");
+ }
+
+ static void testAddMove(Path2D pathA) {
+ addMove(pathA);
+ log("testAddMove: passed.");
+ }
+
+ static void testAddLine(Path2D pathA, boolean isEmpty) {
+ try {
+ addLines(pathA);
+ }
+ catch (IllegalPathStateException ipse) {
+ if (isEmpty) {
+ log("testAddLine: passed "
+ + "(expected IllegalPathStateException catched).");
+ return;
+ } else {
+ throw ipse;
+ }
+ }
+ if (isEmpty) {
+ throw new IllegalStateException("IllegalPathStateException not thrown !");
+ }
+ log("testAddLine: passed.");
+ }
+
+ static void testAddQuad(Path2D pathA, boolean isEmpty) {
+ try {
+ addQuads(pathA);
+ }
+ catch (IllegalPathStateException ipse) {
+ if (isEmpty) {
+ log("testAddQuad: passed "
+ + "(expected IllegalPathStateException catched).");
+ return;
+ } else {
+ throw ipse;
+ }
+ }
+ if (isEmpty) {
+ throw new IllegalStateException("IllegalPathStateException not thrown !");
+ }
+ log("testAddQuad: passed.");
+ }
+
+ static void testAddCubic(Path2D pathA, boolean isEmpty) {
+ try {
+ addCubics(pathA);
+ }
+ catch (IllegalPathStateException ipse) {
+ if (isEmpty) {
+ log("testAddCubic: passed "
+ + "(expected IllegalPathStateException catched).");
+ return;
+ } else {
+ throw ipse;
+ }
+ }
+ if (isEmpty) {
+ throw new IllegalStateException("IllegalPathStateException not thrown !");
+ }
+ log("testAddCubic: passed.");
+ }
+
+ static void testAddClose(Path2D pathA, boolean isEmpty) {
+ try {
+ addClose(pathA);
+ }
+ catch (IllegalPathStateException ipse) {
+ if (isEmpty) {
+ log("testAddClose: passed "
+ + "(expected IllegalPathStateException catched).");
+ return;
+ } else {
+ throw ipse;
+ }
+ }
+ if (isEmpty) {
+ throw new IllegalStateException("IllegalPathStateException not thrown !");
+ }
+ log("testAddClose: passed.");
+ }
+
+ static void testGetBounds(Path2D pathA, Path2D pathB) {
+ final Rectangle rA = pathA.getBounds();
+ final Rectangle rB = pathB.getBounds();
+
+ if (!rA.equals(rB)) {
+ throw new IllegalStateException("Bounds are not equals [" + rA
+ + "|" + rB + "] !");
+ }
+ final Rectangle2D r2dA = pathA.getBounds2D();
+ final Rectangle2D r2dB = pathB.getBounds2D();
+
+ if (!equalsRectangle2D(r2dA, r2dB)) {
+ throw new IllegalStateException("Bounds2D are not equals ["
+ + r2dA + "|" + r2dB + "] !");
+ }
+ log("testGetBounds: passed.");
+ }
+
+ static void testTransform(Path2D pathA) {
+ pathA.transform(at);
+ log("testTransform: passed.");
+ }
+
+ static void testIntersect(Path2D pathA, Path2D pathB) {
+ boolean resA = pathA.intersects(rect2d);
+ boolean resB = pathB.intersects(rect2d);
+ if (resA != resB) {
+ throw new IllegalStateException("Intersects(rect2d) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ resA = pathA.intersects(1.0, 2.0, 13.0, 17.0);
+ resB = pathB.intersects(1.0, 2.0, 13.0, 17.0);
+ if (resA != resB) {
+ throw new IllegalStateException("Intersects(doubles) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ log("testIntersect: passed.");
+ }
+
+ static void testContains(Path2D pathA, Path2D pathB) {
+ boolean resA = pathA.contains(pt2d);
+ boolean resB = pathB.contains(pt2d);
+ if (resA != resB) {
+ throw new IllegalStateException("Contains(pt) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ resA = pathA.contains(pt2d.getX(), pt2d.getY());
+ resB = pathB.contains(pt2d.getX(), pt2d.getY());
+ if (resA != resB) {
+ throw new IllegalStateException("Contains(x,y) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ resA = pathA.contains(rect2d);
+ resB = pathB.contains(rect2d);
+ if (resA != resB) {
+ throw new IllegalStateException("Contains(rect2d) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ resA = pathA.contains(1.0, 2.0, 13.0, 17.0);
+ resB = pathB.contains(1.0, 2.0, 13.0, 17.0);
+ if (resA != resB) {
+ throw new IllegalStateException("Contains(doubles) are not equals ["
+ + resA + "|" + resB + "] !");
+ }
+ log("testContains: passed.");
+ }
+
+ static void testGetCurrentPoint(Path2D pathA, Path2D pathB) {
+ final Point2D ptA = pathA.getCurrentPoint();
+ final Point2D ptB = pathA.getCurrentPoint();
+ if (((ptA == null) && (ptB != null))
+ || ((ptA != null) && !ptA.equals(ptB)))
+ {
+ throw new IllegalStateException("getCurrentPoint() are not equals ["
+ + ptA + "|" + ptB + "] !");
+ }
+ log("testGetCurrentPoint: passed.");
+ }
+
+ static int getLength(int type) {
+ switch(type) {
+ case PathIterator.SEG_CUBICTO:
+ return 6;
+ case PathIterator.SEG_QUADTO:
+ return 4;
+ case PathIterator.SEG_LINETO:
+ case PathIterator.SEG_MOVETO:
+ return 2;
+ case PathIterator.SEG_CLOSE:
+ return 0;
+ default:
+ throw new IllegalStateException("Invalid type: " + type);
+ }
+ }
+
+
+ // Custom equals methods ---
+
+ public static boolean equalsArray(float[] a, float[] a2, final int len) {
+ for (int i = 0; i < len; i++) {
+ if (Float.floatToIntBits(a[i]) != Float.floatToIntBits(a2[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static boolean equalsArrayEps(float[] a, float[] a2, final int len) {
+ for (int i = 0; i < len; i++) {
+ if (!equalsEps(a[i], a2[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static boolean equalsRectangle2D(Rectangle2D a, Rectangle2D b) {
+ if (a == b) {
+ return true;
+ }
+ return equalsEps(a.getX(), b.getX())
+ && equalsEps(a.getY(), b.getY())
+ && equalsEps(a.getWidth(), b.getWidth())
+ && equalsEps(a.getHeight(), b.getHeight());
+ }
+
+ static boolean equalsEps(float a, float b) {
+ return (Math.abs(a - b) <= EPSILON);
+ }
+
+ static boolean equalsEps(double a, double b) {
+ return (Math.abs(a - b) <= EPSILON);
+ }
+}