PolyVertTest.java revision 14851:980da45565c8
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
34import java.awt.*;
35import java.awt.event.*;
36import java.awt.geom.*;
37import java.awt.image.*;
38
39public 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}
663