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