| /* |
| * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @key headful |
| * @bug 4678208 4771101 6328481 6588884 |
| * @summary verify the pixelization of degenerate polylines and polygons |
| * @run main PolyVertTest |
| * @run main/othervm -Dsun.java2d.d3d=True PolyVertTest -hwonly |
| * @run main/othervm -Dsun.java2d.opengl=True PolyVertTest -hwonly |
| */ |
| |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.awt.geom.*; |
| import java.awt.image.*; |
| |
| public class PolyVertTest { |
| static int TESTWIDTH; |
| static int TESTHEIGHT; |
| static final int REG_TEST_WIDTH = 10; |
| static final int REG_TEST_HEIGHT = 10; |
| static final int FULL_TEST_WIDTH = 50; |
| static final int FULL_TEST_HEIGHT = 200; |
| |
| static final int FRINGE = 2; |
| static final int GREEN = Color.green.getRGB(); |
| static final int RED = Color.red.getRGB(); |
| |
| static BufferedImage refImg; |
| static BufferedImage errorImg; |
| static Graphics errorG; |
| static Component testCanvas; |
| |
| static int totalbadpixels; |
| static int totalfuzzypixels; |
| static int numbadtests; |
| static int numfuzzytests; |
| static int numframes; |
| static int fuzzystarty; |
| |
| static boolean counting; |
| static boolean showerrors; |
| static boolean showresults; |
| static boolean fringe; |
| static boolean forceerror; |
| static boolean fulltest = true; |
| static boolean hwonly; |
| |
| static WindowListener windowCloser = new WindowAdapter() { |
| public void windowClosing(WindowEvent e) { |
| e.getWindow().hide(); |
| if (--numframes <= 0) { |
| System.exit(0); |
| } |
| } |
| }; |
| |
| public PolyVertTest() { |
| /* |
| setBackground(Color.white); |
| setForeground(Color.black); |
| */ |
| } |
| |
| static int polypts[][][] = { |
| { |
| // void polygon (no points) |
| {}, {}, |
| }, |
| { |
| // one point |
| { 0 }, { 0 }, |
| }, |
| { |
| // two points |
| { 0, 5 }, { 0, 0 }, |
| { 0, 0, 6, 1, |
| 10, 0, 6, 1, |
| 20, 0, 6, 1 }, |
| { 0, 0, 6, 1, |
| 10, 0, 1, 1, 15, 0, 1, 1, |
| 20, 0, 1, 1, 25, 0, 1, 1 }, |
| { 10, 0, 1, 1, |
| 20, 0, 1, 1 }, |
| }, |
| { |
| // open triangle |
| { 0, 5, 5 }, { 0, 0, 5 }, |
| |
| { 0, 0, 6, 1, 5, 1, 1, 5, |
| |
| 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, |
| 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, |
| |
| 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, |
| 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, |
| |
| { 0, 0, 6, 1, 5, 1, 1, 5, |
| |
| 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, |
| 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, |
| |
| 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, |
| 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, |
| |
| { 10, 0, 1, 1, |
| 20, 0, 1, 1 }, |
| }, |
| { |
| // closed triangle |
| { 0, 5, 5, 0 }, { 0, 0, 5, 0 }, |
| |
| { 0, 0, 6, 1, 5, 1, 1, 5, 1, 1, 1, 1, |
| 2, 2, 1, 1, 3, 3, 1, 1, 4, 4, 1, 1, |
| |
| 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, |
| 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, |
| |
| 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, |
| 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, |
| |
| { 1, 0, 5, 1, 5, 1, 1, 5, 1, 1, 1, 1, |
| 2, 2, 1, 1, 3, 3, 1, 1, 4, 4, 1, 1, |
| |
| 10, 0, 6, 1, 15, 1, 1, 5, 11, 1, 1, 1, |
| 12, 2, 1, 1, 13, 3, 1, 1, 14, 4, 1, 1, |
| |
| 20, 0, 6, 1, 25, 1, 1, 5, 21, 1, 1, 1, |
| 22, 2, 1, 1, 23, 3, 1, 1, 24, 4, 1, 1 }, |
| |
| { 0, 0, 1, 1, |
| 10, 0, 1, 1, |
| 20, 0, 1, 1 }, |
| }, |
| { |
| // empty line |
| { 0, 0 }, { 0, 0 }, |
| { 0, 0, 1, 1, |
| 10, 0, 1, 1, |
| 20, 0, 1, 1 }, |
| }, |
| { |
| // empty triangle |
| { 0, 0, 0 }, { 0, 0, 0 }, |
| { 0, 0, 1, 1, |
| 10, 0, 1, 1, |
| 20, 0, 1, 1 }, |
| }, |
| }; |
| |
| public static void render(Graphics2D g2d) { |
| g2d.setColor(Color.white); |
| g2d.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); |
| g2d.setColor(Color.black); |
| |
| if (forceerror) { |
| g2d.fillRect(2, 2, 2, 2); |
| g2d.fillRect(15, 5, 1, 1); |
| } |
| |
| if (!fulltest) { |
| g2d.draw(new Rectangle2D.Double(5, 5, 0, 0)); |
| return; |
| } |
| |
| g2d.drawLine(10, 10, 10, 10); |
| g2d.draw(new Line2D.Double(20, 10, 20, 10)); |
| |
| g2d.drawRect(10, 20, 0, 0); |
| g2d.draw(new Rectangle2D.Double(20, 20, 0, 0)); |
| |
| g2d.setXORMode(Color.white); |
| |
| g2d.drawLine(10, 30, 10, 30); |
| g2d.draw(new Line2D.Double(20, 30, 20, 30)); |
| |
| g2d.drawRect(10, 40, 0, 0); |
| g2d.draw(new Rectangle2D.Double(20, 40, 0, 0)); |
| |
| g2d.setPaintMode(); |
| |
| int y = 50; |
| for (int i = 0; i < polypts.length; i++) { |
| int data[][] = polypts[i]; |
| int xpoints[] = data[0]; |
| int ypoints[] = data[1]; |
| int npoints = xpoints.length; |
| g2d.translate(10, y); |
| g2d.drawPolyline(xpoints, ypoints, npoints); |
| g2d.translate(10, 0); |
| g2d.drawPolygon(xpoints, ypoints, npoints); |
| g2d.translate(10, 0); |
| g2d.draw(new Polygon(xpoints, ypoints, npoints)); |
| g2d.translate(-30, -y); |
| y += 10; |
| } |
| g2d.setXORMode(Color.white); |
| for (int i = 0; i < polypts.length; i++) { |
| int data[][] = polypts[i]; |
| int xpoints[] = data[0]; |
| int ypoints[] = data[1]; |
| int npoints = xpoints.length; |
| g2d.translate(10, y); |
| g2d.drawPolyline(xpoints, ypoints, npoints); |
| g2d.translate(10, 0); |
| g2d.drawPolygon(xpoints, ypoints, npoints); |
| g2d.translate(10, 0); |
| g2d.draw(new Polygon(xpoints, ypoints, npoints)); |
| g2d.translate(-30, -y); |
| y += 10; |
| } |
| g2d.setPaintMode(); |
| } |
| |
| public Dimension getPreferredSize() { |
| return new Dimension(500, 500); |
| } |
| |
| public static void usage(int exitcode) { |
| System.err.println("usage: java PolyVertTest [<option>]*"); |
| System.err.println(" -usage "+ |
| "print this usage summary"); |
| System.err.println(" -count "+ |
| "run all tests and accumulate error counts"); |
| System.err.println(" -forceerror "+ |
| "force at least one error in each test"); |
| System.err.println(" -fringe "+ |
| "draw a yellow fringe around problems"); |
| System.err.println(" -showerrors "+ |
| "display results window for tests with problems"); |
| System.err.println(" -showresults "+ |
| "display results window for all tests"); |
| System.err.println(" -quicktest "+ |
| "only run test cases reported in bug reports"); |
| System.err.println(" -fulltest "+ |
| "run full suite of test cases for a 'unit test'"); |
| System.err.println(" -hwonly "+ |
| "only run tests for screen and VolatileImage"); |
| System.exit(exitcode); |
| } |
| |
| public static void main(String argv[]) { |
| for (int i = 0; i < argv.length; i++) { |
| String arg = argv[i]; |
| if (arg.equalsIgnoreCase("-count")) { |
| counting = true; |
| } else if (arg.equalsIgnoreCase("-forceerror")) { |
| forceerror = true; |
| } else if (arg.equalsIgnoreCase("-fringe")) { |
| fringe = true; |
| } else if (arg.equalsIgnoreCase("-showerrors")) { |
| showerrors = true; |
| } else if (arg.equalsIgnoreCase("-showresults")) { |
| showresults = true; |
| } else if (arg.equalsIgnoreCase("-quicktest")) { |
| fulltest = false; |
| } else if (arg.equalsIgnoreCase("-fulltest")) { |
| fulltest = true; |
| } else if (arg.equalsIgnoreCase("-hwonly")) { |
| hwonly = true; |
| } else if (arg.equalsIgnoreCase("-usage")) { |
| usage(0); |
| } else { |
| System.err.println("unknown option: "+arg); |
| usage(1); |
| } |
| } |
| |
| if (fulltest) { |
| TESTWIDTH = FULL_TEST_WIDTH; |
| TESTHEIGHT = FULL_TEST_HEIGHT; |
| } else { |
| TESTWIDTH = REG_TEST_WIDTH; |
| TESTHEIGHT = REG_TEST_HEIGHT; |
| } |
| |
| // Prevents premature exit by the WindowAdapter if the user |
| // closes the last visible results window before we've |
| // finished our tests. |
| numframes++; |
| |
| makeReferenceImage(); |
| testScreen(); |
| testVolatileImage(); |
| if (!hwonly) { |
| testBufferedImage(); |
| testOffscreen(); |
| testCompatibleImages(); |
| } |
| if (totalfuzzypixels > 0) { |
| System.err.println(totalfuzzypixels+" fuzzy pixels found in "+ |
| numfuzzytests+" tests"); |
| } |
| if (totalbadpixels > 0) { |
| throw new RuntimeException(totalbadpixels+" bad pixels found in "+ |
| numbadtests+" tests"); |
| } |
| System.out.println("Test done - no bad pixels found"); |
| |
| --numframes; |
| |
| if (counting || ((showresults || showerrors) && numframes == 0)) { |
| System.exit(0); |
| } |
| } |
| |
| public static void makeReferenceImage() { |
| refImg = new BufferedImage(TESTWIDTH, TESTHEIGHT, |
| BufferedImage.TYPE_INT_RGB); |
| Graphics g = refImg.getGraphics(); |
| |
| g.setColor(Color.white); |
| g.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); |
| |
| g.setColor(Color.black); |
| |
| if (!fulltest) { |
| g.fillRect(5, 5, 1, 1); |
| g.dispose(); |
| return; |
| } |
| |
| for (int y = 10; y < 50; y += 10) { |
| g.fillRect(10, y, 1, 1); |
| g.fillRect(20, y, 1, 1); |
| } |
| int y = 50; |
| for (int i = 0; i < polypts.length; i++) { |
| int data[][] = polypts[i]; |
| g.translate(10, y); |
| if (data.length > 2) { |
| int rectvals[] = data[2]; |
| for (int j = 0; j < rectvals.length; j += 4) { |
| g.fillRect(rectvals[j+0], rectvals[j+1], |
| rectvals[j+2], rectvals[j+3]); |
| } |
| } |
| g.translate(-10, -y); |
| y += 10; |
| } |
| fuzzystarty = y; |
| for (int i = 0; i < polypts.length; i++) { |
| int data[][] = polypts[i]; |
| g.translate(10, y); |
| if (data.length > 2) { |
| int rectvals[] = data.length > 3 ? data[3] : data[2]; |
| for (int j = 0; j < rectvals.length; j += 4) { |
| g.fillRect(rectvals[j+0], rectvals[j+1], |
| rectvals[j+2], rectvals[j+3]); |
| } |
| } |
| g.translate(-10, -y); |
| y += 10; |
| } |
| g.dispose(); |
| } |
| |
| public static void initerrorbuf() { |
| if (errorImg == null) { |
| droperrorbuf(); |
| errorImg = new BufferedImage(TESTWIDTH, TESTHEIGHT, |
| BufferedImage.TYPE_INT_RGB); |
| } |
| if (errorG == null) { |
| errorG = errorImg.getGraphics(); |
| } |
| errorG.setColor(Color.green); |
| errorG.fillRect(0, 0, TESTWIDTH, TESTHEIGHT); |
| errorG.setColor(Color.red); |
| } |
| |
| public static void droperrorbuf() { |
| errorImg = null; |
| if (errorG != null) { |
| errorG.dispose(); |
| } |
| errorG = null; |
| } |
| |
| public static void test(Image img, String name) { |
| Graphics2D g2d = (Graphics2D) img.getGraphics(); |
| render(g2d); |
| g2d.dispose(); |
| verify(img, name); |
| } |
| |
| public static void test(BufferedImage bimg, String name) { |
| Graphics2D g2d = bimg.createGraphics(); |
| render(g2d); |
| g2d.dispose(); |
| verify(bimg, name); |
| } |
| |
| public static void verify(Image img, String name) { |
| BufferedImage bimg; |
| if (img instanceof BufferedImage) { |
| bimg = (BufferedImage) img; |
| } else { |
| bimg = new BufferedImage(TESTWIDTH, TESTHEIGHT, |
| BufferedImage.TYPE_INT_RGB); |
| Graphics g = bimg.getGraphics(); |
| g.drawImage(img, 0, 0, null); |
| g.dispose(); |
| } |
| verify(bimg, name); |
| } |
| |
| public static boolean isFuzzyPixel(int X, int Y) { |
| int ytrans = fuzzystarty; |
| if (!fulltest || Y < ytrans) { |
| return false; |
| } |
| for (int i = 0; i < polypts.length; i++) { |
| int data[][] = polypts[i]; |
| if (data.length > 4) { |
| int rectvals[] = data[4]; |
| for (int j = 0; j < rectvals.length; j += 4) { |
| int rectx = rectvals[j+0] + 10; |
| int recty = rectvals[j+1] + ytrans; |
| int rectw = rectvals[j+2]; |
| int recth = rectvals[j+3]; |
| if (X >= rectx && Y >= recty && |
| X < rectx + rectw && Y < recty + recth) |
| { |
| return true; |
| } |
| } |
| } |
| ytrans += 10; |
| } |
| return false; |
| } |
| |
| public static void verify(BufferedImage bimg, String name) { |
| int numbadpixels = 0; |
| int numfuzzypixels = 0; |
| for (int y = 0; y < TESTHEIGHT; y++) { |
| for (int x = 0; x < TESTWIDTH; x++) { |
| if (refImg.getRGB(x, y) != bimg.getRGB(x, y)) { |
| boolean isfuzzy = isFuzzyPixel(x, y); |
| if (showerrors || showresults) { |
| if (errorG == null) { |
| initerrorbuf(); |
| } |
| errorG.setColor(isfuzzy ? Color.blue : Color.red); |
| errorG.fillRect(x, y, 1, 1); |
| } else if (!counting && !isfuzzy) { |
| throw new RuntimeException("Error at "+x+", "+y+ |
| " while testing: "+name); |
| } |
| if (isfuzzy) { |
| numfuzzypixels++; |
| } else { |
| numbadpixels++; |
| } |
| } |
| } |
| } |
| if (numbadpixels > 0 || numfuzzypixels > 0) { |
| if (numbadpixels > 0) { |
| totalbadpixels += numbadpixels; |
| numbadtests++; |
| } |
| if (numfuzzypixels > 0) { |
| totalfuzzypixels += numfuzzypixels; |
| numfuzzytests++; |
| } |
| System.out.println(numbadpixels+" bad pixels and "+ |
| numfuzzypixels+" questionable pixels "+ |
| "found while testing "+name); |
| if (showerrors || showresults) { |
| displaydiffs(bimg, name); |
| } |
| } else if (showresults) { |
| if (errorG == null) { |
| initerrorbuf(); |
| } |
| displaydiffs(bimg, name); |
| } |
| } |
| |
| public static void displaydiffs(BufferedImage bimg, String name) { |
| if (fringe) { |
| errorG.setColor(Color.yellow); |
| for (int y = 0; y < TESTHEIGHT; y++) { |
| for (int x = 0; x < TESTWIDTH; x++) { |
| if (errorImg.getRGB(x, y) == RED) { |
| for (int iy = y-FRINGE; iy <= y+FRINGE; iy++) { |
| for (int ix = x-FRINGE; ix <= x+FRINGE; ix++) { |
| if (ix >= 0 && ix < TESTWIDTH && |
| iy >= 0 && iy < TESTHEIGHT && |
| errorImg.getRGB(ix, iy) == GREEN) |
| { |
| errorG.fillRect(ix, iy, 1, 1); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| Frame f = new Frame("Results for "+name); |
| f.setLayout(new BorderLayout()); |
| f.addWindowListener(windowCloser); |
| ++numframes; |
| Panel p = new Panel(); |
| p.add(new ImageCanvas(bimg)); |
| p.add(new ImageCanvas(errorImg)); |
| p.add(new ImageCanvas(refImg)); |
| f.add(p, "Center"); |
| droperrorbuf(); |
| f.pack(); |
| f.show(); |
| } |
| |
| public static void testBufferedImage() { |
| testBufferedImage(BufferedImage.TYPE_INT_RGB, "IntXrgb"); |
| testBufferedImage(BufferedImage.TYPE_INT_ARGB, "IntArgb"); |
| testBufferedImage(BufferedImage.TYPE_3BYTE_BGR, "ThreeByte"); |
| testBufferedImage(BufferedImage.TYPE_4BYTE_ABGR, "FourByte"); |
| testBufferedImage(BufferedImage.TYPE_USHORT_555_RGB, "UShort555"); |
| testBufferedImage(BufferedImage.TYPE_BYTE_GRAY, "ByteGray"); |
| testBufferedImage(BufferedImage.TYPE_BYTE_INDEXED, "Indexed"); |
| } |
| |
| public static void testBufferedImage(int type, String name) { |
| BufferedImage bimg = new BufferedImage(TESTWIDTH, TESTHEIGHT, type); |
| test(bimg, name); |
| } |
| |
| public static void testScreen() { |
| Frame f = new Frame("PolyVertTest"); |
| TestCanvas child = new TestCanvas(); |
| testCanvas = child; |
| f.add(child); |
| f.pack(); |
| f.show(); |
| BufferedImage bimg = child.getImage(); |
| f.hide(); |
| verify(bimg, "Screen"); |
| } |
| |
| public static void testOffscreen() { |
| Image img = testCanvas.createImage(TESTWIDTH, TESTHEIGHT); |
| test(img, "Offscreen"); |
| } |
| |
| public static void testCompatibleImages() { |
| GraphicsEnvironment genv = |
| GraphicsEnvironment.getLocalGraphicsEnvironment(); |
| GraphicsDevice gdevs[] = genv.getScreenDevices(); |
| for (int i = 0; i < gdevs.length; i++) { |
| testCompatibleImages(gdevs[i]); |
| } |
| } |
| |
| public static void testCompatibleImages(GraphicsDevice gdev) { |
| GraphicsConfiguration gconfigs[] = gdev.getConfigurations(); |
| for (int i = 0; i < gconfigs.length; i++) { |
| testCompatibleImages(gconfigs[i]); |
| } |
| } |
| |
| public static void testCompatibleImages(GraphicsConfiguration gconfig) { |
| test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT), |
| gconfig+".createCompat()"); |
| test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, |
| Transparency.OPAQUE), |
| gconfig+".createCompat(OPAQUE)"); |
| test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, |
| Transparency.BITMASK), |
| gconfig+".createCompat(BITMASK)"); |
| test(gconfig.createCompatibleImage(TESTWIDTH, TESTHEIGHT, |
| Transparency.TRANSLUCENT), |
| gconfig+".createCompat(TRANSLUCENT)"); |
| test(gconfig.createCompatibleVolatileImage(TESTWIDTH, TESTHEIGHT), |
| gconfig+".createCompatVolatile()"); |
| } |
| |
| public static void testVolatileImage() { |
| Image img = testCanvas.createVolatileImage(TESTWIDTH, TESTHEIGHT); |
| test(img, "Volatile"); |
| } |
| |
| public static class ImageCanvas extends Canvas { |
| BufferedImage bimg; |
| |
| public ImageCanvas(BufferedImage bimg) { |
| this.bimg = bimg; |
| } |
| |
| public Dimension getPreferredSize() { |
| return new Dimension(bimg.getWidth(), bimg.getHeight()); |
| } |
| |
| public void paint(Graphics g) { |
| g.drawImage(bimg, 0, 0, null); |
| } |
| } |
| |
| public static class TestCanvas extends Canvas { |
| BufferedImage bimg; |
| |
| public Dimension getPreferredSize() { |
| return new Dimension(TESTWIDTH, TESTHEIGHT); |
| } |
| |
| public void paint(Graphics g) { |
| if (bimg != null || |
| getWidth() < TESTWIDTH || |
| getHeight() < TESTHEIGHT) |
| { |
| return; |
| } |
| render((Graphics2D) g); |
| Toolkit.getDefaultToolkit().sync(); |
| Point p = getLocationOnScreen(); |
| Rectangle r = new Rectangle(p.x, p.y, TESTWIDTH, TESTHEIGHT); |
| try { |
| bimg = new Robot().createScreenCapture(r); |
| } catch (AWTException e) { |
| e.printStackTrace(); |
| } |
| synchronized (this) { |
| notifyAll(); |
| } |
| } |
| |
| public synchronized BufferedImage getImage() { |
| while (bimg == null) { |
| try { |
| wait(); |
| } catch (InterruptedException e) { |
| return null; |
| } |
| } |
| return bimg; |
| } |
| } |
| } |