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 }