1 /* 2 * Copyright (c) 2002, 2016, 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 * @test 26 * @key headful 27 * @bug 4678208 4771101 6328481 6588884 28 * @summary verify the pixelization of degenerate polylines and polygons 29 * @run main PolyVertTest 30 * @run main/othervm -Dsun.java2d.d3d=True PolyVertTest -hwonly 31 * @run main/othervm -Dsun.java2d.opengl=True PolyVertTest -hwonly 32 */ 33 34 import java.awt.*; 35 import java.awt.event.*; 36 import java.awt.geom.*; 37 import java.awt.image.*; 38 39 public class PolyVertTest { 40 static int TESTWIDTH; 41 static int TESTHEIGHT; 42 static final int REG_TEST_WIDTH = 10; 43 static final int REG_TEST_HEIGHT = 10; 44 static final int FULL_TEST_WIDTH = 50; 45 static final int FULL_TEST_HEIGHT = 200; 46 47 static final int FRINGE = 2; 48 static final int GREEN = Color.green.getRGB(); 49 static final int RED = Color.red.getRGB(); 50 51 static BufferedImage refImg; 52 static BufferedImage errorImg; 53 static Graphics errorG; 54 static Component testCanvas; 55 56 static int totalbadpixels; 57 static int totalfuzzypixels; 58 static int numbadtests; 59 static int numfuzzytests; 60 static int numframes; 61 static int fuzzystarty; 62 63 static boolean counting; 64 static boolean showerrors; 65 static boolean showresults; 66 static boolean fringe; 67 static boolean forceerror; 68 static boolean fulltest = true; 69 static boolean hwonly; 70 71 static WindowListener windowCloser = new WindowAdapter() { 72 public void windowClosing(WindowEvent e) { 73 e.getWindow().hide(); 74 if (--numframes <= 0) { 75 System.exit(0); 76 } 77 } 78 }; 79 80 public PolyVertTest() { 81 /* 82 setBackground(Color.white); 83 setForeground(Color.black); 84 */ 85 } 86 87 static int polypts[][][] = { 88 { 89 // void polygon (no points) 90 {}, {}, 91 }, 92 { 93 // one point 94 { 0 }, { 0 }, 95 }, 96 { 97 // two points 98 { 0, 5 }, { 0, 0 }, 99 { 0, 0, 6, 1, 100 10, 0, 6, 1, 101 20, 0, 6, 1 }, 102 { 0, 0, 6, 1, 103 10, 0, 1, 1, 15, 0, 1, 1, 104 20, 0, 1, 1, 25, 0, 1, 1 }, 105 { 10, 0, 1, 1, 106 20, 0, 1, 1 }, 107 }, 108 { 109 // open triangle 110 { 0, 5, 5 }, { 0, 0, 5 }, 111 112 { 0, 0, 6, 1, 5, 1, 1, 5, 113 114 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, 115 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, 116 117 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, 118 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, 119 120 { 0, 0, 6, 1, 5, 1, 1, 5, 121 122 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, 123 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, 124 125 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, 126 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, 127 128 { 10, 0, 1, 1, 129 20, 0, 1, 1 }, 130 }, 131 { 132 // closed triangle 133 { 0, 5, 5, 0 }, { 0, 0, 5, 0 }, 134 135 { 0, 0, 6, 1, 5, 1, 1, 5, 1, 1, 1, 1, 136 2, 2, 1, 1, 3, 3, 1, 1, 4, 4, 1, 1, 137 138 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, 139 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, 140 141 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, 142 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, 143 144 { 1, 0, 5, 1, 5, 1, 1, 5, 1, 1, 1, 1, 145 2, 2, 1, 1, 3, 3, 1, 1, 4, 4, 1, 1, 146 147 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, 148 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, 149 150 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, 151 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, 152 153 { 0, 0, 1, 1, 154 10, 0, 1, 1, 155 20, 0, 1, 1 }, 156 }, 157 { 158 // empty line 159 { 0, 0 }, { 0, 0 }, 160 { 0, 0, 1, 1, 161 10, 0, 1, 1, 162 20, 0, 1, 1 }, 163 }, 164 { 165 // empty triangle 166 { 0, 0, 0 }, { 0, 0, 0 }, 167 { 0, 0, 1, 1, 168 10, 0, 1, 1, 169 20, 0, 1, 1 }, 170 }, 171 }; 172 173 public static void render(Graphics2D g2d) { 174 g2d.setColor(Color.white); 175 g2d.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); 176 g2d.setColor(Color.black); 177 178 if (forceerror) { 179 g2d.fillRect(2, 2, 2, 2); 180 g2d.fillRect(15, 5, 1, 1); 181 } 182 183 if (!fulltest) { 184 g2d.draw(new Rectangle2D.Double(5, 5, 0, 0)); 185 return; 186 } 187 188 g2d.drawLine(10, 10, 10, 10); 189 g2d.draw(new Line2D.Double(20, 10, 20, 10)); 190 191 g2d.drawRect(10, 20, 0, 0); 192 g2d.draw(new Rectangle2D.Double(20, 20, 0, 0)); 193 194 g2d.setXORMode(Color.white); 195 196 g2d.drawLine(10, 30, 10, 30); 197 g2d.draw(new Line2D.Double(20, 30, 20, 30)); 198 199 g2d.drawRect(10, 40, 0, 0); 200 g2d.draw(new Rectangle2D.Double(20, 40, 0, 0)); 201 202 g2d.setPaintMode(); 203 204 int y = 50; 205 for (int i = 0; i < polypts.length; i++) { 206 int data[][] = polypts[i]; 207 int xpoints[] = data[0]; 208 int ypoints[] = data[1]; 209 int npoints = xpoints.length; 210 g2d.translate(10, y); 211 g2d.drawPolyline(xpoints, ypoints, npoints); 212 g2d.translate(10, 0); 213 g2d.drawPolygon(xpoints, ypoints, npoints); 214 g2d.translate(10, 0); 215 g2d.draw(new Polygon(xpoints, ypoints, npoints)); 216 g2d.translate(-30, -y); 217 y += 10; 218 } 219 g2d.setXORMode(Color.white); 220 for (int i = 0; i < polypts.length; i++) { 221 int data[][] = polypts[i]; 222 int xpoints[] = data[0]; 223 int ypoints[] = data[1]; 224 int npoints = xpoints.length; 225 g2d.translate(10, y); 226 g2d.drawPolyline(xpoints, ypoints, npoints); 227 g2d.translate(10, 0); 228 g2d.drawPolygon(xpoints, ypoints, npoints); 229 g2d.translate(10, 0); 230 g2d.draw(new Polygon(xpoints, ypoints, npoints)); 231 g2d.translate(-30, -y); 232 y += 10; 233 } 234 g2d.setPaintMode(); 235 } 236 237 public Dimension getPreferredSize() { 238 return new Dimension(500, 500); 239 } 240 241 public static void usage(int exitcode) { 242 System.err.println("usage: java PolyVertTest [<option>]*"); 243 System.err.println(" -usage "+ 244 "print this usage summary"); 245 System.err.println(" -count "+ 246 "run all tests and accumulate error counts"); 247 System.err.println(" -forceerror "+ 248 "force at least one error in each test"); 249 System.err.println(" -fringe "+ 250 "draw a yellow fringe around problems"); 251 System.err.println(" -showerrors "+ 252 "display results window for tests with problems"); 253 System.err.println(" -showresults "+ 254 "display results window for all tests"); 255 System.err.println(" -quicktest "+ 256 "only run test cases reported in bug reports"); 257 System.err.println(" -fulltest "+ 258 "run full suite of test cases for a 'unit test'"); 259 System.err.println(" -hwonly "+ 260 "only run tests for screen and VolatileImage"); 261 System.exit(exitcode); 262 } 263 264 public static void main(String argv[]) { 265 for (int i = 0; i < argv.length; i++) { 266 String arg = argv[i]; 267 if (arg.equalsIgnoreCase("-count")) { 268 counting = true; 269 } else if (arg.equalsIgnoreCase("-forceerror")) { 270 forceerror = true; 271 } else if (arg.equalsIgnoreCase("-fringe")) { 272 fringe = true; 273 } else if (arg.equalsIgnoreCase("-showerrors")) { 274 showerrors = true; 275 } else if (arg.equalsIgnoreCase("-showresults")) { 276 showresults = true; 277 } else if (arg.equalsIgnoreCase("-quicktest")) { 278 fulltest = false; 279 } else if (arg.equalsIgnoreCase("-fulltest")) { 280 fulltest = true; 281 } else if (arg.equalsIgnoreCase("-hwonly")) { 282 hwonly = true; 283 } else if (arg.equalsIgnoreCase("-usage")) { 284 usage(0); 285 } else { 286 System.err.println("unknown option: "+arg); 287 usage(1); 288 } 289 } 290 291 if (fulltest) { 292 TESTWIDTH = FULL_TEST_WIDTH; 293 TESTHEIGHT = FULL_TEST_HEIGHT; 294 } else { 295 TESTWIDTH = REG_TEST_WIDTH; 296 TESTHEIGHT = REG_TEST_HEIGHT; 297 } 298 299 // Prevents premature exit by the WindowAdapter if the user 300 // closes the last visible results window before we've 301 // finished our tests. 302 numframes++; 303 304 makeReferenceImage(); 305 testScreen(); 306 testVolatileImage(); 307 if (!hwonly) { 308 testBufferedImage(); 309 testOffscreen(); 310 testCompatibleImages(); 311 } 312 if (totalfuzzypixels > 0) { 313 System.err.println(totalfuzzypixels+" fuzzy pixels found in "+ 314 numfuzzytests+" tests"); 315 } 316 if (totalbadpixels > 0) { 317 throw new RuntimeException(totalbadpixels+" bad pixels found in "+ 318 numbadtests+" tests"); 319 } 320 System.out.println("Test done - no bad pixels found"); 321 322 --numframes; 323 324 if (counting || ((showresults || showerrors) && numframes == 0)) { 325 System.exit(0); 326 } 327 } 328 329 public static void makeReferenceImage() { 330 refImg = new BufferedImage(TESTWIDTH, TESTHEIGHT, 331 BufferedImage.TYPE_INT_RGB); 332 Graphics g = refImg.getGraphics(); 333 334 g.setColor(Color.white); 335 g.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); 336 337 g.setColor(Color.black); 338 339 if (!fulltest) { 340 g.fillRect(5, 5, 1, 1); 341 g.dispose(); 342 return; 343 } 344 345 for (int y = 10; y < 50; y += 10) { 346 g.fillRect(10, y, 1, 1); 347 g.fillRect(20, y, 1, 1); 348 } 349 int y = 50; 350 for (int i = 0; i < polypts.length; i++) { 351 int data[][] = polypts[i]; 352 g.translate(10, y); 353 if (data.length > 2) { 354 int rectvals[] = data[2]; 355 for (int j = 0; j < rectvals.length; j += 4) { 356 g.fillRect(rectvals[j+0], rectvals[j+1], 357 rectvals[j+2], rectvals[j+3]); 358 } 359 } 360 g.translate(-10, -y); 361 y += 10; 362 } 363 fuzzystarty = y; 364 for (int i = 0; i < polypts.length; i++) { 365 int data[][] = polypts[i]; 366 g.translate(10, y); 367 if (data.length > 2) { 368 int rectvals[] = data.length > 3 ? data[3] : data[2]; 369 for (int j = 0; j < rectvals.length; j += 4) { 370 g.fillRect(rectvals[j+0], rectvals[j+1], 371 rectvals[j+2], rectvals[j+3]); 372 } 373 } 374 g.translate(-10, -y); 375 y += 10; 376 } 377 g.dispose(); 378 } 379 380 public static void initerrorbuf() { 381 if (errorImg == null) { 382 droperrorbuf(); 383 errorImg = new BufferedImage(TESTWIDTH, TESTHEIGHT, 384 BufferedImage.TYPE_INT_RGB); 385 } 386 if (errorG == null) { 387 errorG = errorImg.getGraphics(); 388 } 389 errorG.setColor(Color.green); 390 errorG.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); 391 errorG.setColor(Color.red); 392 } 393 394 public static void droperrorbuf() { 395 errorImg = null; 396 if (errorG != null) { 397 errorG.dispose(); 398 } 399 errorG = null; 400 } 401 402 public static void test(Image img, String name) { 403 Graphics2D g2d = (Graphics2D) img.getGraphics(); 404 render(g2d); 405 g2d.dispose(); 406 verify(img, name); 407 } 408 409 public static void test(BufferedImage bimg, String name) { 410 Graphics2D g2d = bimg.createGraphics(); 411 render(g2d); 412 g2d.dispose(); 413 verify(bimg, name); 414 } 415 416 public static void verify(Image img, String name) { 417 BufferedImage bimg; 418 if (img instanceof BufferedImage) { 419 bimg = (BufferedImage) img; 420 } else { 421 bimg = new BufferedImage(TESTWIDTH, TESTHEIGHT, 422 BufferedImage.TYPE_INT_RGB); 423 Graphics g = bimg.getGraphics(); 424 g.drawImage(img, 0, 0, null); 425 g.dispose(); 426 } 427 verify(bimg, name); 428 } 429 430 public static boolean isFuzzyPixel(int X, int Y) { 431 int ytrans = fuzzystarty; 432 if (!fulltest || Y < ytrans) { 433 return false; 434 } 435 for (int i = 0; i < polypts.length; i++) { 436 int data[][] = polypts[i]; 437 if (data.length > 4) { 438 int rectvals[] = data[4]; 439 for (int j = 0; j < rectvals.length; j += 4) { 440 int rectx = rectvals[j+0] + 10; 441 int recty = rectvals[j+1] + ytrans; 442 int rectw = rectvals[j+2]; 443 int recth = rectvals[j+3]; 444 if (X >= rectx && Y >= recty && 445 X < rectx + rectw && Y < recty + recth) 446 { 447 return true; 448 } 449 } 450 } 451 ytrans += 10; 452 } 453 return false; 454 } 455 456 public static void verify(BufferedImage bimg, String name) { 457 int numbadpixels = 0; 458 int numfuzzypixels = 0; 459 for (int y = 0; y < TESTHEIGHT; y++) { 460 for (int x = 0; x < TESTWIDTH; x++) { 461 if (refImg.getRGB(x, y) != bimg.getRGB(x, y)) { 462 boolean isfuzzy = isFuzzyPixel(x, y); 463 if (showerrors || showresults) { 464 if (errorG == null) { 465 initerrorbuf(); 466 } 467 errorG.setColor(isfuzzy ? Color.blue : Color.red); 468 errorG.fillRect(x, y, 1, 1); 469 } else if (!counting && !isfuzzy) { 470 throw new RuntimeException("Error at "+x+", "+y+ 471 " while testing: "+name); 472 } 473 if (isfuzzy) { 474 numfuzzypixels++; 475 } else { 476 numbadpixels++; 477 } 478 } 479 } 480 } 481 if (numbadpixels > 0 || numfuzzypixels > 0) { 482 if (numbadpixels > 0) { 483 totalbadpixels += numbadpixels; 484 numbadtests++; 485 } 486 if (numfuzzypixels > 0) { 487 totalfuzzypixels += numfuzzypixels; 488 numfuzzytests++; 489 } 490 System.out.println(numbadpixels+" bad pixels and "+ 491 numfuzzypixels+" questionable pixels "+ 492 "found while testing "+name); 493 if (showerrors || showresults) { 494 displaydiffs(bimg, name); 495 } 496 } else if (showresults) { 497 if (errorG == null) { 498 initerrorbuf(); 499 } 500 displaydiffs(bimg, name); 501 } 502 } 503 504 public static void displaydiffs(BufferedImage bimg, String name) { 505 if (fringe) { 506 errorG.setColor(Color.yellow); 507 for (int y = 0; y < TESTHEIGHT; y++) { 508 for (int x = 0; x < TESTWIDTH; x++) { 509 if (errorImg.getRGB(x, y) == RED) { 510 for (int iy = y-FRINGE; iy <= y+FRINGE; iy++) { 511 for (int ix = x-FRINGE; ix <= x+FRINGE; ix++) { 512 if (ix >= 0 && ix < TESTWIDTH && 513 iy >= 0 && iy < TESTHEIGHT && 514 errorImg.getRGB(ix, iy) == GREEN) 515 { 516 errorG.fillRect(ix, iy, 1, 1); 517 } 518 } 519 } 520 } 521 } 522 } 523 } 524 Frame f = new Frame("Results for "+name); 525 f.setLayout(new BorderLayout()); 526 f.addWindowListener(windowCloser); 527 ++numframes; 528 Panel p = new Panel(); 529 p.add(new ImageCanvas(bimg)); 530 p.add(new ImageCanvas(errorImg)); 531 p.add(new ImageCanvas(refImg)); 532 f.add(p, "Center"); 533 droperrorbuf(); 534 f.pack(); 535 f.show(); 536 } 537 538 public static void testBufferedImage() { 539 testBufferedImage(BufferedImage.TYPE_INT_RGB, "IntXrgb"); 540 testBufferedImage(BufferedImage.TYPE_INT_ARGB, "IntArgb"); 541 testBufferedImage(BufferedImage.TYPE_3BYTE_BGR, "ThreeByte"); 542 testBufferedImage(BufferedImage.TYPE_4BYTE_ABGR, "FourByte"); 543 testBufferedImage(BufferedImage.TYPE_USHORT_555_RGB, "UShort555"); 544 testBufferedImage(BufferedImage.TYPE_BYTE_GRAY, "ByteGray"); 545 testBufferedImage(BufferedImage.TYPE_BYTE_INDEXED, "Indexed"); 546 } 547 548 public static void testBufferedImage(int type, String name) { 549 BufferedImage bimg = new BufferedImage(TESTWIDTH, TESTHEIGHT, type); 550 test(bimg, name); 551 } 552 553 public static void testScreen() { 554 Frame f = new Frame("PolyVertTest"); 555 TestCanvas child = new TestCanvas(); 556 testCanvas = child; 557 f.add(child); 558 f.pack(); 559 f.show(); 560 BufferedImage bimg = child.getImage(); 561 f.hide(); 562 verify(bimg, "Screen"); 563 } 564 565 public static void testOffscreen() { 566 Image img = testCanvas.createImage(TESTWIDTH, TESTHEIGHT); 567 test(img, "Offscreen"); 568 } 569 570 public static void testCompatibleImages() { 571 GraphicsEnvironment genv = 572 GraphicsEnvironment.getLocalGraphicsEnvironment(); 573 GraphicsDevice gdevs[] = genv.getScreenDevices(); 574 for (int i = 0; i < gdevs.length; i++) { 575 testCompatibleImages(gdevs[i]); 576 } 577 } 578 579 public static void testCompatibleImages(GraphicsDevice gdev) { 580 GraphicsConfiguration gconfigs[] = gdev.getConfigurations(); 581 for (int i = 0; i < gconfigs.length; i++) { 582 testCompatibleImages(gconfigs[i]); 583 } 584 } 585 586 public static void testCompatibleImages(GraphicsConfiguration gconfig) { 587 test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT), 588 gconfig+".createCompat()"); 589 test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, 590 Transparency.OPAQUE), 591 gconfig+".createCompat(OPAQUE)"); 592 test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, 593 Transparency.BITMASK), 594 gconfig+".createCompat(BITMASK)"); 595 test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, 596 Transparency.TRANSLUCENT), 597 gconfig+".createCompat(TRANSLUCENT)"); 598 test(gconfig.createCompatibleVolatileImage(TESTWIDTH, TESTHEIGHT), 599 gconfig+".createCompatVolatile()"); 600 } 601 602 public static void testVolatileImage() { 603 Image img = testCanvas.createVolatileImage(TESTWIDTH, TESTHEIGHT); 604 test(img, "Volatile"); 605 } 606 607 public static class ImageCanvas extends Canvas { 608 BufferedImage bimg; 609 610 public ImageCanvas(BufferedImage bimg) { 611 this.bimg = bimg; 612 } 613 614 public Dimension getPreferredSize() { 615 return new Dimension(bimg.getWidth(), bimg.getHeight()); 616 } 617 618 public void paint(Graphics g) { 619 g.drawImage(bimg, 0, 0, null); 620 } 621 } 622 623 public static class TestCanvas extends Canvas { 624 BufferedImage bimg; 625 626 public Dimension getPreferredSize() { 627 return new Dimension(TESTWIDTH, TESTHEIGHT); 628 } 629 630 public void paint(Graphics g) { 631 if (bimg != null || 632 getWidth() < TESTWIDTH || 633 getHeight() < TESTHEIGHT) 634 { 635 return; 636 } 637 render((Graphics2D) g); 638 Toolkit.getDefaultToolkit().sync(); 639 Point p = getLocationOnScreen(); 640 Rectangle r = new Rectangle(p.x, p.y, TESTWIDTH, TESTHEIGHT); 641 try { 642 bimg = new Robot().createScreenCapture(r); 643 } catch (AWTException e) { 644 e.printStackTrace(); 645 } 646 synchronized (this) { 647 notifyAll(); 648 } 649 } 650 651 public synchronized BufferedImage getImage() { 652 while (bimg == null) { 653 try { 654 wait(); 655 } catch (InterruptedException e) { 656 return null; 657 } 658 } 659 return bimg; 660 } 661 } 662 }