< prev index next >

test/jdk/sun/java2d/marlin/ClipShapeTest.java

Print this page

        

@@ -52,17 +52,28 @@
 /**
  * @test
  * @bug 8191814
  * @summary Verifies that Marlin rendering generates the same
  * images with and without clipping optimization with all possible
- * stroke (cap/join) and fill modes (EO rules)
+ * stroke (cap/join) and/or dashes or fill modes (EO rules)
+ * for paths made of either 9 lines, 4 quads, 2 cubics (random)
  * Note: Use the argument -slow to run more intensive tests (too much time)
- * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest
- * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest
- */
+ *
+ * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly
+ * @run main/othervm/timeout=240 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly -doDash
+ * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic
+ * @run main/othervm/timeout=240 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic -doDash
+ * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly
+ * @run main/othervm/timeout=240 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly -doDash
+ * @run main/othervm/timeout=120 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic
+ * @run main/othervm/timeout=240 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic -doDash
+*/
 public final class ClipShapeTest {
 
+    static boolean TX_SCALE = false;
+    static boolean TX_SHEAR = false;
+
     static final boolean TEST_STROKER = true;
     static final boolean TEST_FILLER = true;
 
     // complementary tests in slow mode:
     static boolean USE_DASHES = false;

@@ -71,22 +82,27 @@
     static int NUM_TESTS = 5000;
     static final int TESTW = 100;
     static final int TESTH = 100;
 
     // shape settings:
-    static final ShapeMode SHAPE_MODE = ShapeMode.NINE_LINE_POLYS;
+    static ShapeMode SHAPE_MODE = ShapeMode.NINE_LINE_POLYS;
+
+    static int THRESHOLD_DELTA;
+    static long THRESHOLD_NBPIX;
+
     static final boolean SHAPE_REPEAT = true;
 
     // dump path on console:
     static final boolean DUMP_SHAPE = true;
 
-    static final boolean SHOW_DETAILS = true;
+    static final boolean SHOW_DETAILS = false; // disabled
     static final boolean SHOW_OUTLINE = true;
     static final boolean SHOW_POINTS = true;
     static final boolean SHOW_INFO = false;
 
     static final int MAX_SHOW_FRAMES = 10;
+    static final int MAX_SAVE_FRAMES = 100;
 
     // use fixed seed to reproduce always same polygons between tests
     static final boolean FIXED_SEED = false;
     static final double RAND_SCALE = 3.0;
     static final double RANDW = TESTW * RAND_SCALE;

@@ -107,28 +123,17 @@
     // Fixed seed to avoid any difference between runs:
     static final Random RANDOM = new Random(SEED);
 
     static final File OUTPUT_DIR = new File(".");
 
-    /**
-     * Test
-     * @param args
-     */
-    public static void main(String[] args) {
-        boolean runSlowTests = (args.length != 0 && "-slow".equals(args[0]));
-
-        if (runSlowTests) {
-            NUM_TESTS = 20000; // or 100000 (very slow)
-            USE_DASHES = true;
-            USE_VAR_STROKE = true;
-        }
+    static final AtomicBoolean isMarlin = new AtomicBoolean();
+    static final AtomicBoolean isClipRuntime = new AtomicBoolean();
 
+    static {
         Locale.setDefault(Locale.US);
 
-        // Get Marlin runtime state from its log:
-        final AtomicBoolean isMarlin = new AtomicBoolean();
-        final AtomicBoolean isClipRuntime = new AtomicBoolean();
+        // FIRST: Get Marlin runtime state from its log:
 
         // initialize j.u.l Looger:
         final Logger log = Logger.getLogger("sun.java2d.marlin");
         log.addHandler(new Handler() {
             @Override

@@ -169,26 +174,122 @@
 
         // disable static clipping setting:
         System.setProperty("sun.java2d.renderer.clip", "false");
         System.setProperty("sun.java2d.renderer.clip.runtime.enable", "true");
 
+        // enable subdivider:
+        System.setProperty("sun.java2d.renderer.clip.subdivider", "true");
+
+        // disable min length check: always subdivide curves at clip edges
+        System.setProperty("sun.java2d.renderer.clip.subdivider.minLength", "-1");
+
+        // If any curve, increase curve accuracy:
+        // curve length max error:
+        System.setProperty("sun.java2d.renderer.curve_len_err", "1e-4");
+
+        // quad max error:
+        System.setProperty("sun.java2d.renderer.quad_dec_d2", "5e-4");
+
+        // cubic min/max error:
+        System.setProperty("sun.java2d.renderer.cubic_dec_d2", "1e-3");
+        System.setProperty("sun.java2d.renderer.cubic_inc_d1", "1e-4"); // or disabled ~ 1e-6
+    }
+
+    /**
+     * Test
+     * @param args
+     */
+    public static void main(String[] args) {
+        boolean runSlowTests = false;
+
+        for (String arg : args) {
+            if ("-slow".equals(arg)) {
+                System.out.println("slow: enabled.");
+                runSlowTests = true;
+            } else if ("-doScale".equals(arg)) {
+                System.out.println("doScale: enabled.");
+                TX_SCALE = true;
+            } else if ("-doShear".equals(arg)) {
+                System.out.println("doShear: enabled.");
+                TX_SHEAR = true;
+            } else if ("-doDash".equals(arg)) {
+                System.out.println("doDash: enabled.");
+                USE_DASHES = true;
+            } else if ("-doVarStroke".equals(arg)) {
+                System.out.println("doVarStroke: enabled.");
+                USE_VAR_STROKE = true;
+            }
+            // shape mode:
+            else if (arg.equalsIgnoreCase("-poly")) {
+                SHAPE_MODE = ShapeMode.NINE_LINE_POLYS;
+            } else if (arg.equalsIgnoreCase("-bigpoly")) {
+                SHAPE_MODE = ShapeMode.FIFTY_LINE_POLYS;
+            } else if (arg.equalsIgnoreCase("-quad")) {
+                SHAPE_MODE = ShapeMode.FOUR_QUADS;
+            } else if (arg.equalsIgnoreCase("-cubic")) {
+                SHAPE_MODE = ShapeMode.TWO_CUBICS;
+            } else if (arg.equalsIgnoreCase("-mixed")) {
+                SHAPE_MODE = ShapeMode.MIXED;
+            }
+        }
+
+        System.out.println("Shape mode: " + SHAPE_MODE);
+
+        // adjust image comparison thresholds:
+        switch(SHAPE_MODE) {
+            case TWO_CUBICS:
+                // Define uncertainty for curves:
+                THRESHOLD_DELTA = 32; //  / 256
+                THRESHOLD_NBPIX = 128; //  / 10000
+                break;
+            case FOUR_QUADS:
+            case MIXED:
+                // Define uncertainty for quads:
+                // curve subdivision causes curves to be smaller
+                // then curve offsets are different (more accurate)
+                THRESHOLD_DELTA = 64;  // 64 / 256
+                THRESHOLD_NBPIX = 256; // 256 / 10000
+                break;
+            default:
+                // Define uncertainty for lines:
+                // float variant have higher uncertainty
+                THRESHOLD_DELTA = 8;
+                THRESHOLD_NBPIX = 8;
+        }
+
+        System.out.println("THRESHOLD_DELTA: "+THRESHOLD_DELTA);
+        System.out.println("THRESHOLD_NBPIX: "+THRESHOLD_NBPIX);
+
+        if (runSlowTests) {
+            NUM_TESTS = 10000; // or 100000 (very slow)
+            USE_DASHES = true;
+            USE_VAR_STROKE = true;
+        }
+
         System.out.println("ClipShapeTests: image = " + TESTW + " x " + TESTH);
 
         int failures = 0;
         final long start = System.nanoTime();
         try {
             // TODO: test affine transforms ?
 
             if (TEST_STROKER) {
-                final float[][] dashArrays = (USE_DASHES)
-                        ? new float[][]{null, new float[]{1f, 2f}}
+                final float[][] dashArrays = (USE_DASHES) ?
+// small
+//                        new float[][]{new float[]{1f, 2f}}
+// normal
+                        new float[][]{new float[]{13f, 7f}}
+// large (prime)
+//                        new float[][]{new float[]{41f, 7f}}
+// none
                         : new float[][]{null};
 
-                System.out.println("dashes: " + Arrays.toString(dashArrays));
+                System.out.println("dashes: " + Arrays.deepToString(dashArrays));
 
                 final float[] strokeWidths = (USE_VAR_STROKE)
-                        ? new float[5] : new float[]{8f};
+                                                ? new float[5] :
+                                                  new float[]{10f};
 
                 int nsw = 0;
                 if (USE_VAR_STROKE) {
                     for (float width = 0.1f; width < 110f; width *= 5f) {
                         strokeWidths[nsw++] = width;

@@ -288,26 +389,24 @@
                     nd++;
 
                     final double ratio = (100.0 * testCtx.histPix.count) / testCtx.histAll.count;
                     System.out.println("Diff ratio: " + testName + " = " + trimTo3Digits(ratio) + " %");
 
-                    if (false) {
-                        saveImage(diffImage, OUTPUT_DIR, testName + "-diff.png");
-                    }
-
-                    if (DUMP_SHAPE) {
-                        dumpShape(p2d);
-                    }
                     if (nd < MAX_SHOW_FRAMES) {
                         if (SHOW_DETAILS) {
                             paintShapeDetails(g2dOff, p2d);
                             paintShapeDetails(g2dOn, p2d);
                         }
 
-                        saveImage(imgOff, OUTPUT_DIR, testName + "-off.png");
-                        saveImage(imgOn, OUTPUT_DIR, testName + "-on.png");
-                        saveImage(diffImage, OUTPUT_DIR, testName + "-diff.png");
+                        if (nd < MAX_SAVE_FRAMES) {
+                            if (DUMP_SHAPE) {
+                                dumpShape(p2d);
+                            }
+                            saveImage(imgOff, OUTPUT_DIR, testName + "-off.png");
+                            saveImage(imgOn, OUTPUT_DIR, testName + "-on.png");
+                            saveImage(diffImage, OUTPUT_DIR, testName + "-diff.png");
+                        }
                     }
                 }
             }
         } finally {
             g2dOff.dispose();

@@ -349,10 +448,19 @@
         if (ts.isStroke()) {
             g2d.setStroke(createStroke(ts));
         }
         g2d.setColor(Color.GRAY);
 
+        // Test scale
+        if (TX_SCALE) {
+            g2d.scale(1.2, 1.2);
+        }
+        // Test shear
+        if (TX_SHEAR) {
+            g2d.shear(0.1, 0.2);
+        }
+
         return g2d;
     }
 
     private static void reset(final Graphics2D g2d) {
         // Disable antialiasing:

@@ -468,10 +576,12 @@
                     if (SHOW_POINTS) {
                         g2d.setColor(COLOR_MOVETO);
                     }
                     break;
                 case PathIterator.SEG_LINETO:
+                case PathIterator.SEG_QUADTO:
+                case PathIterator.SEG_CUBICTO:
                     if (SHOW_POINTS) {
                         g2d.setColor((nLine % 2 == 0) ? COLOR_LINETO_ODD : COLOR_LINETO_EVEN);
                     }
                     nLine++;
                     break;

@@ -513,10 +623,16 @@
                     System.out.println("p2d.moveTo(" + coords[0] + ", " + coords[1] + ");");
                     break;
                 case PathIterator.SEG_LINETO:
                     System.out.println("p2d.lineTo(" + coords[0] + ", " + coords[1] + ");");
                     break;
+                case PathIterator.SEG_QUADTO:
+                    System.out.println("p2d.quadTo(" + coords[0] + ", " + coords[1] + ", " + coords[2] + ", " + coords[3] + ");");
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    System.out.println("p2d.curveTo(" + coords[0] + ", " + coords[1] + ", " + coords[2] + ", " + coords[3] + ", " + coords[4] + ", " + coords[5] + ");");
+                    break;
                 case PathIterator.SEG_CLOSE:
                     System.out.println("p2d.closePath();");
                     break;
                 default:
                     System.out.println("// Unsupported segment type= " + type);

@@ -578,14 +694,58 @@
             return this.strokeWidth > 0f;
         }
 
         @Override
         public String toString() {
+            if (isStroke()) {
+                return "TestSetup{id=" + id + ", shapeMode=" + shapeMode + ", closed=" + closed
+                        + ", strokeWidth=" + strokeWidth + ", strokeCap=" + getCap(strokeCap) + ", strokeJoin=" + getJoin(strokeJoin)
+                        + ((dashes != null) ? ", dashes: " + Arrays.toString(dashes) : "")
+                        + '}';
+            }
             return "TestSetup{id=" + id + ", shapeMode=" + shapeMode + ", closed=" + closed
-                    + ", strokeWidth=" + strokeWidth + ", strokeCap=" + strokeCap + ", strokeJoin=" + strokeJoin
-                    + ((dashes != null) ? ", dashes: " + Arrays.toString(dashes) : "")
-                    + ", windingRule=" + windingRule + '}';
+                    + ", fill"
+                    + ", windingRule=" + getWindingRule(windingRule) + '}';
+        }
+
+        private static String getCap(final int cap) {
+            switch (cap) {
+                case BasicStroke.CAP_BUTT:
+                    return "CAP_BUTT";
+                case BasicStroke.CAP_ROUND:
+                    return "CAP_ROUND";
+                case BasicStroke.CAP_SQUARE:
+                    return "CAP_SQUARE";
+                default:
+                    return "";
+            }
+
+        }
+
+        private static String getJoin(final int join) {
+            switch (join) {
+                case BasicStroke.JOIN_MITER:
+                    return "JOIN_MITER";
+                case BasicStroke.JOIN_ROUND:
+                    return "JOIN_ROUND";
+                case BasicStroke.JOIN_BEVEL:
+                    return "JOIN_BEVEL";
+                default:
+                    return "";
+            }
+
+        }
+
+        private static String getWindingRule(final int rule) {
+            switch (rule) {
+                case PathIterator.WIND_EVEN_ODD:
+                    return "WIND_EVEN_ODD";
+                case PathIterator.WIND_NON_ZERO:
+                    return "WIND_NON_ZERO";
+                default:
+                    return "";
+            }
         }
     }
 
     // --- utilities ---
     private static final int DCM_ALPHA_MASK = 0xff000000;

@@ -616,20 +776,27 @@
             dg = (r(ref) + g(ref) + b(ref)) - (r(tst) + g(tst) + b(tst));
 
             // max difference on grayscale values:
             v = (int) Math.ceil(Math.abs(dg / 3.0));
 
-            aDifPix[i] = toInt(v, v, v);
+// TODO: count warnings
+            if (v <= THRESHOLD_DELTA) {
+                aDifPix[i] = 0;
+            } else {
+                aDifPix[i] = toInt(v, v, v);
 
-            localCtx.add(v);
+                localCtx.add(v);
+            }
             globalCtx.add(v);
         }
 
-        if (!localCtx.isDiff()) {
+        if (!localCtx.isDiff() || (localCtx.histPix.count <= THRESHOLD_NBPIX)) {
             return null;
         }
 
+        localCtx.dump();
+
         return diffImage;
     }
 
     static void saveImage(final BufferedImage image, final File resDirectory, final String imageFileName) throws IOException {
         final Iterator<ImageWriter> itWriters = ImageIO.getImageWritersByFormatName("PNG");
< prev index next >