/* * Copyright (c) 2002, 2008, 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 * @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; } } }