1 /* 2 * Copyright (c) 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 import java.awt.Rectangle; 26 import java.awt.geom.AffineTransform; 27 import java.awt.geom.GeneralPath; 28 import java.awt.geom.IllegalPathStateException; 29 import java.awt.geom.Path2D; 30 import java.awt.geom.PathIterator; 31 import java.awt.geom.Point2D; 32 import java.awt.geom.Rectangle2D; 33 import java.util.Arrays; 34 35 /** 36 * @test 37 * @bug 8076419 38 * @summary Check Path2D copy constructor (trims arrays) 39 * and constructor with zero capacity 40 * @run main Path2DCopyConstructor 41 */ 42 public class Path2DCopyConstructor { 43 44 private final static float EPSILON = 5e-6f; 45 private final static float FLATNESS = 1e-2f; 46 47 private final static AffineTransform at 48 = AffineTransform.getScaleInstance(1.3, 2.4); 49 50 private final static Rectangle2D.Double rect2d 51 = new Rectangle2D.Double(3.2, 4.1, 5.0, 10.0); 52 53 private final static Point2D.Double pt2d 54 = new Point2D.Double(2.0, 2.5); 55 56 public static boolean verbose; 57 58 static void log(String msg) { 59 if (verbose) { 60 System.out.println(msg); 61 } 62 } 63 64 public static void main(String argv[]) { 65 verbose = (argv.length != 0); 66 67 testEmptyDoublePaths(); 68 testDoublePaths(); 69 70 testEmptyFloatPaths(); 71 testFloatPaths(); 72 73 testEmptyGeneralPath(); 74 testGeneralPath(); 75 } 76 77 static void testEmptyDoublePaths() { 78 log("\n - Test(Path2D.Double[0]) ---"); 79 test(() -> new Path2D.Double(Path2D.WIND_NON_ZERO, 0)); 80 } 81 82 static void testDoublePaths() { 83 log("\n - Test(Path2D.Double) ---"); 84 test(() -> new Path2D.Double()); 85 } 86 87 static void testEmptyFloatPaths() { 88 log("\n - Test(Path2D.Float[0]) ---"); 89 test(() -> new Path2D.Float(Path2D.WIND_NON_ZERO, 0)); 90 } 91 92 static void testFloatPaths() { 93 log("\n - Test(Path2D.Float) ---"); 94 test(() -> new Path2D.Float()); 95 } 96 97 static void testEmptyGeneralPath() { 98 log("\n - Test(GeneralPath[0]) ---"); 99 test(() -> new GeneralPath(Path2D.WIND_NON_ZERO, 0)); 100 } 101 102 static void testGeneralPath() { 103 log("\n - Test(GeneralPath) ---"); 104 test(() -> new GeneralPath()); 105 } 106 107 interface PathFactory { 108 Path2D makePath(); 109 } 110 111 static void test(PathFactory pf) { 112 log("\n --- test: path(empty) ---"); 113 test(pf.makePath(), true); 114 log("\n\n --- test: path(addMove) ---"); 115 test(addMove(pf.makePath()), false); 116 log("\n\n --- test: path(addMoveAndLines) ---"); 117 test(addMoveAndLines(pf.makePath()), false); 118 log("\n\n --- test: path(addMoveAndQuads) ---"); 119 test(addMoveAndQuads(pf.makePath()), false); 120 log("\n\n --- test: path(addMoveAndCubics) ---"); 121 test(addMoveAndCubics(pf.makePath()), false); 122 log("\n\n --- test: path(addMoveAndClose) ---"); 123 test(addMoveAndClose(pf.makePath()), false); 124 } 125 126 static Path2D addMove(Path2D p2d) { 127 p2d.moveTo(1.0, 0.5); 128 return p2d; 129 } 130 131 static Path2D addMoveAndLines(Path2D p2d) { 132 addMove(p2d); 133 addLines(p2d); 134 return p2d; 135 } 136 137 static Path2D addLines(Path2D p2d) { 138 for (int i = 0; i < 10; i++) { 139 p2d.lineTo(1.1 * i, 2.3 * i); 140 } 141 return p2d; 142 } 143 144 static Path2D addMoveAndCubics(Path2D p2d) { 145 addMove(p2d); 146 addCubics(p2d); 147 return p2d; 148 } 149 150 static Path2D addCubics(Path2D p2d) { 151 for (int i = 0; i < 10; i++) { 152 p2d.curveTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i, 1.5 * i, 1.6 * i); 153 } 154 return p2d; 155 } 156 157 static Path2D addMoveAndQuads(Path2D p2d) { 158 addMove(p2d); 159 addQuads(p2d); 160 return p2d; 161 } 162 163 static Path2D addQuads(Path2D p2d) { 164 for (int i = 0; i < 10; i++) { 165 p2d.quadTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i); 166 } 167 return p2d; 168 } 169 170 static Path2D addMoveAndClose(Path2D p2d) { 171 addMove(p2d); 172 addClose(p2d); 173 return p2d; 174 } 175 176 static Path2D addClose(Path2D p2d) { 177 p2d.closePath(); 178 return p2d; 179 } 180 181 static void test(Path2D p2d, boolean isEmpty) { 182 testEqual(new Path2D.Float(p2d), p2d); 183 testEqual(new Path2D.Double(p2d), p2d); 184 testEqual(new GeneralPath(p2d), p2d); 185 186 testIterator(new Path2D.Float(p2d), p2d); 187 testIterator(new Path2D.Double(p2d), p2d); 188 testIterator((Path2D) p2d.clone(), p2d); 189 190 testFlattening(new Path2D.Float(p2d), p2d); 191 testFlattening(new Path2D.Double(p2d), p2d); 192 testFlattening((Path2D) p2d.clone(), p2d); 193 194 testAddMove(new Path2D.Float(p2d)); 195 testAddMove(new Path2D.Double(p2d)); 196 testAddMove((Path2D) p2d.clone()); 197 198 // These should expect exception if empty 199 testAddLine(new Path2D.Float(p2d), isEmpty); 200 testAddLine(new Path2D.Double(p2d), isEmpty); 201 testAddLine((Path2D) p2d.clone(), isEmpty); 202 203 testAddQuad(new Path2D.Float(p2d), isEmpty); 204 testAddQuad(new Path2D.Double(p2d), isEmpty); 205 testAddQuad((Path2D) p2d.clone(), isEmpty); 206 207 testAddCubic(new Path2D.Float(p2d), isEmpty); 208 testAddCubic(new Path2D.Double(p2d), isEmpty); 209 testAddCubic((Path2D) p2d.clone(), isEmpty); 210 211 testAddClose(new Path2D.Float(p2d), isEmpty); 212 testAddClose(new Path2D.Double(p2d), isEmpty); 213 testAddClose((Path2D) p2d.clone(), isEmpty); 214 215 testGetBounds(new Path2D.Float(p2d), p2d); 216 testGetBounds(new Path2D.Double(p2d), p2d); 217 testGetBounds((Path2D) p2d.clone(), p2d); 218 219 testTransform(new Path2D.Float(p2d)); 220 testTransform(new Path2D.Double(p2d)); 221 testTransform((Path2D) p2d.clone()); 222 223 testIntersect(new Path2D.Float(p2d), p2d); 224 testIntersect(new Path2D.Double(p2d), p2d); 225 testIntersect((Path2D) p2d.clone(), p2d); 226 227 testContains(new Path2D.Float(p2d), p2d); 228 testContains(new Path2D.Double(p2d), p2d); 229 testContains((Path2D) p2d.clone(), p2d); 230 231 testGetCurrentPoint(new Path2D.Float(p2d), p2d); 232 testGetCurrentPoint(new Path2D.Double(p2d), p2d); 233 testGetCurrentPoint((Path2D) p2d.clone(), p2d); 234 } 235 236 static void testEqual(Path2D pathA, Path2D pathB) { 237 final PathIterator itA = pathA.getPathIterator(null); 238 final PathIterator itB = pathB.getPathIterator(null); 239 240 float[] coordsA = new float[6]; 241 float[] coordsB = new float[6]; 242 243 int n = 0; 244 for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { 245 int typeA = itA.currentSegment(coordsA); 246 int typeB = itB.currentSegment(coordsB); 247 248 if (typeA != typeB) { 249 throw new IllegalStateException("Path-segment[" + n + "] " 250 + " type are not equals [" + typeA + "|" + typeB + "] !"); 251 } 252 if (!equalsArray(coordsA, coordsB, getLength(typeA))) { 253 throw new IllegalStateException("Path-segment[" + n + "] coords" 254 + " are not equals [" + Arrays.toString(coordsA) + "|" 255 + Arrays.toString(coordsB) + "] !"); 256 } 257 } 258 if (!itA.isDone() || !itB.isDone()) { 259 throw new IllegalStateException("Paths do not have same lengths !"); 260 } 261 log("testEqual: " + n + " segments."); 262 } 263 264 static void testIterator(Path2D pathA, Path2D pathB) { 265 final PathIterator itA = pathA.getPathIterator(at); 266 final PathIterator itB = pathB.getPathIterator(at); 267 268 float[] coordsA = new float[6]; 269 float[] coordsB = new float[6]; 270 271 int n = 0; 272 for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { 273 int typeA = itA.currentSegment(coordsA); 274 int typeB = itB.currentSegment(coordsB); 275 276 if (typeA != typeB) { 277 throw new IllegalStateException("Path-segment[" + n + "] " 278 + "type are not equals [" + typeA + "|" + typeB + "] !"); 279 } 280 // Take care of floating-point precision: 281 if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) { 282 throw new IllegalStateException("Path-segment[" + n + "] coords" 283 + " are not equals [" + Arrays.toString(coordsA) + "|" 284 + Arrays.toString(coordsB) + "] !"); 285 } 286 } 287 if (!itA.isDone() || !itB.isDone()) { 288 throw new IllegalStateException("Paths do not have same lengths !"); 289 } 290 log("testIterator: " + n + " segments."); 291 } 292 293 static void testFlattening(Path2D pathA, Path2D pathB) { 294 final PathIterator itA = pathA.getPathIterator(at, FLATNESS); 295 final PathIterator itB = pathB.getPathIterator(at, FLATNESS); 296 297 float[] coordsA = new float[6]; 298 float[] coordsB = new float[6]; 299 300 int n = 0; 301 for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { 302 int typeA = itA.currentSegment(coordsA); 303 int typeB = itB.currentSegment(coordsB); 304 305 if (typeA != typeB) { 306 throw new IllegalStateException("Path-segment[" + n + "] " 307 + "type are not equals [" + typeA + "|" + typeB + "] !"); 308 } 309 // Take care of floating-point precision: 310 if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) { 311 throw new IllegalStateException("Path-segment[" + n + "] coords" 312 + " are not equals [" + Arrays.toString(coordsA) + "|" 313 + Arrays.toString(coordsB) + "] !"); 314 } 315 } 316 if (!itA.isDone() || !itB.isDone()) { 317 throw new IllegalStateException("Paths do not have same lengths !"); 318 } 319 log("testFlattening: " + n + " segments."); 320 } 321 322 static void testAddMove(Path2D pathA) { 323 addMove(pathA); 324 log("testAddMove: passed."); 325 } 326 327 static void testAddLine(Path2D pathA, boolean isEmpty) { 328 try { 329 addLines(pathA); 330 } 331 catch (IllegalPathStateException ipse) { 332 if (isEmpty) { 333 log("testAddLine: passed " 334 + "(expected IllegalPathStateException catched)."); 335 return; 336 } else { 337 throw ipse; 338 } 339 } 340 if (isEmpty) { 341 throw new IllegalStateException("IllegalPathStateException not thrown !"); 342 } 343 log("testAddLine: passed."); 344 } 345 346 static void testAddQuad(Path2D pathA, boolean isEmpty) { 347 try { 348 addQuads(pathA); 349 } 350 catch (IllegalPathStateException ipse) { 351 if (isEmpty) { 352 log("testAddQuad: passed " 353 + "(expected IllegalPathStateException catched)."); 354 return; 355 } else { 356 throw ipse; 357 } 358 } 359 if (isEmpty) { 360 throw new IllegalStateException("IllegalPathStateException not thrown !"); 361 } 362 log("testAddQuad: passed."); 363 } 364 365 static void testAddCubic(Path2D pathA, boolean isEmpty) { 366 try { 367 addCubics(pathA); 368 } 369 catch (IllegalPathStateException ipse) { 370 if (isEmpty) { 371 log("testAddCubic: passed " 372 + "(expected IllegalPathStateException catched)."); 373 return; 374 } else { 375 throw ipse; 376 } 377 } 378 if (isEmpty) { 379 throw new IllegalStateException("IllegalPathStateException not thrown !"); 380 } 381 log("testAddCubic: passed."); 382 } 383 384 static void testAddClose(Path2D pathA, boolean isEmpty) { 385 try { 386 addClose(pathA); 387 } 388 catch (IllegalPathStateException ipse) { 389 if (isEmpty) { 390 log("testAddClose: passed " 391 + "(expected IllegalPathStateException catched)."); 392 return; 393 } else { 394 throw ipse; 395 } 396 } 397 if (isEmpty) { 398 throw new IllegalStateException("IllegalPathStateException not thrown !"); 399 } 400 log("testAddClose: passed."); 401 } 402 403 static void testGetBounds(Path2D pathA, Path2D pathB) { 404 final Rectangle rA = pathA.getBounds(); 405 final Rectangle rB = pathB.getBounds(); 406 407 if (!rA.equals(rB)) { 408 throw new IllegalStateException("Bounds are not equals [" + rA 409 + "|" + rB + "] !"); 410 } 411 final Rectangle2D r2dA = pathA.getBounds2D(); 412 final Rectangle2D r2dB = pathB.getBounds2D(); 413 414 if (!equalsRectangle2D(r2dA, r2dB)) { 415 throw new IllegalStateException("Bounds2D are not equals [" 416 + r2dA + "|" + r2dB + "] !"); 417 } 418 log("testGetBounds: passed."); 419 } 420 421 static void testTransform(Path2D pathA) { 422 pathA.transform(at); 423 log("testTransform: passed."); 424 } 425 426 static void testIntersect(Path2D pathA, Path2D pathB) { 427 boolean resA = pathA.intersects(rect2d); 428 boolean resB = pathB.intersects(rect2d); 429 if (resA != resB) { 430 throw new IllegalStateException("Intersects(rect2d) are not equals [" 431 + resA + "|" + resB + "] !"); 432 } 433 resA = pathA.intersects(1.0, 2.0, 13.0, 17.0); 434 resB = pathB.intersects(1.0, 2.0, 13.0, 17.0); 435 if (resA != resB) { 436 throw new IllegalStateException("Intersects(doubles) are not equals [" 437 + resA + "|" + resB + "] !"); 438 } 439 log("testIntersect: passed."); 440 } 441 442 static void testContains(Path2D pathA, Path2D pathB) { 443 boolean resA = pathA.contains(pt2d); 444 boolean resB = pathB.contains(pt2d); 445 if (resA != resB) { 446 throw new IllegalStateException("Contains(pt) are not equals [" 447 + resA + "|" + resB + "] !"); 448 } 449 resA = pathA.contains(pt2d.getX(), pt2d.getY()); 450 resB = pathB.contains(pt2d.getX(), pt2d.getY()); 451 if (resA != resB) { 452 throw new IllegalStateException("Contains(x,y) are not equals [" 453 + resA + "|" + resB + "] !"); 454 } 455 resA = pathA.contains(rect2d); 456 resB = pathB.contains(rect2d); 457 if (resA != resB) { 458 throw new IllegalStateException("Contains(rect2d) are not equals [" 459 + resA + "|" + resB + "] !"); 460 } 461 resA = pathA.contains(1.0, 2.0, 13.0, 17.0); 462 resB = pathB.contains(1.0, 2.0, 13.0, 17.0); 463 if (resA != resB) { 464 throw new IllegalStateException("Contains(doubles) are not equals [" 465 + resA + "|" + resB + "] !"); 466 } 467 log("testContains: passed."); 468 } 469 470 static void testGetCurrentPoint(Path2D pathA, Path2D pathB) { 471 final Point2D ptA = pathA.getCurrentPoint(); 472 final Point2D ptB = pathA.getCurrentPoint(); 473 if (((ptA == null) && (ptB != null)) 474 || ((ptA != null) && !ptA.equals(ptB))) 475 { 476 throw new IllegalStateException("getCurrentPoint() are not equals [" 477 + ptA + "|" + ptB + "] !"); 478 } 479 log("testGetCurrentPoint: passed."); 480 } 481 482 static int getLength(int type) { 483 switch(type) { 484 case PathIterator.SEG_CUBICTO: 485 return 6; 486 case PathIterator.SEG_QUADTO: 487 return 4; 488 case PathIterator.SEG_LINETO: 489 case PathIterator.SEG_MOVETO: 490 return 2; 491 case PathIterator.SEG_CLOSE: 492 return 0; 493 default: 494 throw new IllegalStateException("Invalid type: " + type); 495 } 496 } 497 498 499 // Custom equals methods --- 500 501 public static boolean equalsArray(float[] a, float[] a2, final int len) { 502 for (int i = 0; i < len; i++) { 503 if (Float.floatToIntBits(a[i]) != Float.floatToIntBits(a2[i])) { 504 return false; 505 } 506 } 507 return true; 508 } 509 510 static boolean equalsArrayEps(float[] a, float[] a2, final int len) { 511 for (int i = 0; i < len; i++) { 512 if (!equalsEps(a[i], a2[i])) { 513 return false; 514 } 515 } 516 517 return true; 518 } 519 520 static boolean equalsRectangle2D(Rectangle2D a, Rectangle2D b) { 521 if (a == b) { 522 return true; 523 } 524 return equalsEps(a.getX(), b.getX()) 525 && equalsEps(a.getY(), b.getY()) 526 && equalsEps(a.getWidth(), b.getWidth()) 527 && equalsEps(a.getHeight(), b.getHeight()); 528 } 529 530 static boolean equalsEps(float a, float b) { 531 return (Math.abs(a - b) <= EPSILON); 532 } 533 534 static boolean equalsEps(double a, double b) { 535 return (Math.abs(a - b) <= EPSILON); 536 } 537 }