--- /dev/null 2015-04-27 08:55:57.562705164 -0700 +++ new/test/java/awt/geom/Path2D/Path2DCopyConstructor.java 2015-05-15 12:51:07.546847506 -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); + } +}