From 5b1cbb57c39082cc444807daec401dd033754af7 Mon Sep 17 00:00:00 2001 From: bourgesl Date: Mon, 15 Jan 2024 17:53:35 +0100 Subject: [PATCH] Merge with latest OpenJDK 22 + JetBrains Runtime 23 --- .../java2d/marlin/BBoxAATileGenerator.java | 4 +- src/main/java/sun/java2d/marlin/Stroker.java | 56 ---- src/main/java/sun/java2d/marlin/Version.java | 2 +- .../sun/java2d/opengl/OGLRenderQueue.java | 250 ------------------ src/main/java/sun/java2d/pipe/LoopPipe.java | 1 + .../java/sun/java2d/pipe/RenderQueue.java | 7 +- src/test/java/ClipShapeTest.java | 1 + src/test/java/ScaleTest.java | 6 +- src/test/java/StrokeShapeTest.java | 6 + .../java/TestCreateStrokedShapeJoins.java | 208 +++++++-------- src/test/java/ThinLineTest.java | 6 + 11 files changed, 130 insertions(+), 417 deletions(-) delete mode 100644 src/main/java/sun/java2d/opengl/OGLRenderQueue.java diff --git a/src/main/java/sun/java2d/marlin/BBoxAATileGenerator.java b/src/main/java/sun/java2d/marlin/BBoxAATileGenerator.java index e029d61..d298677 100644 --- a/src/main/java/sun/java2d/marlin/BBoxAATileGenerator.java +++ b/src/main/java/sun/java2d/marlin/BBoxAATileGenerator.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, JetBrains s.r.o.. 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 diff --git a/src/main/java/sun/java2d/marlin/Stroker.java b/src/main/java/sun/java2d/marlin/Stroker.java index aec4c41..59f93ed 100644 --- a/src/main/java/sun/java2d/marlin/Stroker.java +++ b/src/main/java/sun/java2d/marlin/Stroker.java @@ -25,7 +25,6 @@ package sun.java2d.marlin; -import sun.java2d.marlin.debug.MarlinDebugThreadLocal; import java.util.Arrays; import sun.java2d.marlin.Helpers.PolyStack; import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer; @@ -866,8 +865,6 @@ private int getLineOffsets(final double x1, final double y1, return 4; } - private final static boolean DEBUG_CUBIC_INFO = false; - private int computeOffsetCubic(final double[] pts, final int off, final double[] leftOff, final double[] rightOff) @@ -884,29 +881,9 @@ private int computeOffsetCubic(final double[] pts, final int off, final double x3 = pts[off + 4]; final double y3 = pts[off + 5]; final double x4 = pts[off + 6]; final double y4 = pts[off + 7]; - if (DEBUG_CUBIC_INFO) { - if ((437.4173312717014 == pts[off]) - && (45.489651150173614 == pts[off + 1])) - { - System.out.println("Bad case ?"); - } - MarlinUtils.logInfo("Stroker.computeOffsetCubic(" - + pts[off] + ", " + pts[off + 1] + ", " - + pts[off + 2] + ", " + pts[off + 3] + ", " - + pts[off + 4] + ", " + pts[off + 5] + ", " - + pts[off + 6] + ", " + pts[off + 7] + ");"); - } double dx1 = x2 - x1; double dy1 = y2 - y1; double dx4 = x4 - x3; double dy4 = y4 - y3; - if (DEBUG_CUBIC_INFO) { - System.out.println("dx1: "+dx1); - System.out.println("dy1: "+dy1); - System.out.println("th: "+(6.0d * Math.ulp(y2))); - System.out.println("dx4: "+dx4); - System.out.println("dy4: "+dy4); - System.out.println("th: "+(6.0d * Math.ulp(y4))); - } // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4, // in which case ignore if p1 == p2 final boolean p1eqp2 = Helpers.withinD(dx1, dy1, 6.0d * Math.ulp(y2)); @@ -928,19 +905,6 @@ private int computeOffsetCubic(final double[] pts, final int off, final double l1sq = dx1 * dx1 + dy1 * dy1; final double l4sq = dx4 * dx4 + dy4 * dy4; - if (DEBUG_CUBIC_INFO) { - System.out.println("dotsq: "+dotsq); - System.out.println("l1sq: "+l1sq); - System.out.println("l4sq: "+l4sq); - - System.out.println("l1sq * l4sq: "+(l1sq * l4sq)); - System.out.println("th: "+(4.0d * Math.ulp(dotsq))); - - final double th = Math.max(1e-15, 4.0d * Math.ulp(dotsq)); - System.out.println("th fixed: "+th); - } - -// if (Helpers.within(dotsq, l1sq * l4sq, th)) { if (Helpers.within(dotsq, l1sq * l4sq, 4.0d * Math.ulp(dotsq))) { return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff); } @@ -1014,12 +978,6 @@ private int computeOffsetCubic(final double[] pts, final int off, double x4p = x4 + offset2[0]; // end double y4p = y4 + offset2[1]; // point -if (false) { - final MarlinDebugThreadLocal dbgCtx = MarlinDebugThreadLocal.get(); - // never release (reset): - dbgCtx.addPoint(xi, yi); -} - final double invdet43 = 4.0d / (3.0d * (dx1 * dy4 - dy1 * dx4)); double two_pi_m_p1_m_p4x = 2.0d * xi - (x1p + x4p); @@ -1063,12 +1021,6 @@ private int computeOffsetCubic(final double[] pts, final int off, x4p = x4 - offset2[0]; // end y4p = y4 - offset2[1]; // point -if (false) { - final MarlinDebugThreadLocal dbgCtx = MarlinDebugThreadLocal.get(); - // never release (reset): - dbgCtx.addPoint(xi, yi); -} - two_pi_m_p1_m_p4x = 2.0d * xi - (x1p + x4p); two_pi_m_p1_m_p4y = 2.0d * yi - (y1p + y4p); @@ -1292,13 +1244,6 @@ private void _curveTo(final double x1, final double y1, int kind = 0; for (int i = 0, off = 0; i <= nSplits; i++, off += 6) { - if (DEBUG_CUBIC_INFO) { - MarlinUtils.logInfo("Stroker._curveTo(): p.curveTo(" - + mid[off] + ", " + mid[off + 1] + ", " - + mid[off + 2] + ", " + mid[off + 3] + ", " - + mid[off + 4] + ", " + mid[off + 5] + ", " - + mid[off + 6] + ", " + mid[off + 7] + ");"); - } kind = computeOffsetCubic(mid, off, l, r); emitLineTo(l[0], l[1]); @@ -1392,7 +1337,6 @@ private void _quadTo(final double x1, final double y1, lineTo(cx0, cy0); return; } - // if these vectors are too small, normalize them, to avoid future // precision problems. if (Math.abs(dxs) < 0.1d && Math.abs(dys) < 0.1d) { diff --git a/src/main/java/sun/java2d/marlin/Version.java b/src/main/java/sun/java2d/marlin/Version.java index 0e51e93..ef06df2 100644 --- a/src/main/java/sun/java2d/marlin/Version.java +++ b/src/main/java/sun/java2d/marlin/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 diff --git a/src/main/java/sun/java2d/opengl/OGLRenderQueue.java b/src/main/java/sun/java2d/opengl/OGLRenderQueue.java deleted file mode 100644 index d7353ad..0000000 --- a/src/main/java/sun/java2d/opengl/OGLRenderQueue.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2005, 2021, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package sun.java2d.opengl; - -import sun.java2d.pipe.RenderBuffer; -import sun.java2d.pipe.RenderQueue; - -import static sun.java2d.pipe.BufferedOpCodes.*; -import java.security.AccessController; -import java.security.PrivilegedAction; -import sun.java2d.marlin.MarlinUtils; - -/** - * OGL-specific implementation of RenderQueue. This class provides a - * single (daemon) thread that is responsible for periodically flushing - * the queue, thus ensuring that only one thread communicates with the native - * OpenGL libraries for the entire process. - */ -public class OGLRenderQueue extends RenderQueue { - - private static OGLRenderQueue theInstance; - private final QueueFlusher flusher; - - @SuppressWarnings("removal") - private OGLRenderQueue() { - /* - * The thread must be a member of a thread group - * which will not get GCed before VM exit. - */ - flusher = AccessController.doPrivileged((PrivilegedAction) QueueFlusher::new); - } - - /** - * Returns the single OGLRenderQueue instance. If it has not yet been - * initialized, this method will first construct the single instance - * before returning it. - */ - public static synchronized OGLRenderQueue getInstance() { - if (theInstance == null) { - theInstance = new OGLRenderQueue(); - } - return theInstance; - } - - /** - * Flushes the single OGLRenderQueue instance synchronously. If an - * OGLRenderQueue has not yet been instantiated, this method is a no-op. - * This method is useful in the case of Toolkit.sync(), in which we want - * to flush the OGL pipeline, but only if the OGL pipeline is currently - * enabled. Since this class has few external dependencies, callers need - * not be concerned that calling this method will trigger initialization - * of the OGL pipeline and related classes. - */ - public static void sync() { - if (theInstance != null) { - theInstance.lock(); - try { - theInstance.ensureCapacity(4); - theInstance.getBuffer().putInt(SYNC); - theInstance.flushNow(); - } finally { - theInstance.unlock(); - } - } - } - - /** - * Disposes the native memory associated with the given native - * graphics config info pointer on the single queue flushing thread. - */ - public static void disposeGraphicsConfig(long pConfigInfo) { - OGLRenderQueue rq = getInstance(); - rq.lock(); - try { - // make sure we make the context associated with the given - // GraphicsConfig current before disposing the native resources - OGLContext.setScratchSurface(pConfigInfo); - - RenderBuffer buf = rq.getBuffer(); - rq.ensureCapacityAndAlignment(12, 4); - buf.putInt(DISPOSE_CONFIG); - buf.putLong(pConfigInfo); - - // this call is expected to complete synchronously, so flush now - rq.flushNow(); - } finally { - rq.unlock(); - } - } - - /** - * Returns true if the current thread is the OGL QueueFlusher thread. - */ - public static boolean isQueueFlusherThread() { - return (Thread.currentThread() == getInstance().flusher.thread); - } - - public void flushNow() { - // assert lock.isHeldByCurrentThread(); - try { - flusher.flushNow(); - } catch (Exception e) { - System.err.println("exception in flushNow:"); - e.printStackTrace(); - } - } - - public void flushAndInvokeNow(Runnable r) { - // assert lock.isHeldByCurrentThread(); - try { - flusher.flushAndInvokeNow(r); - } catch (Exception e) { - System.err.println("exception in flushAndInvokeNow:"); - e.printStackTrace(); - } - } - - private native void flushBuffer(long buf, int limit); - - private void flushBuffer() { - // assert lock.isHeldByCurrentThread(); - int limit = buf.position(); - if (limit > 0) { - // process the queue - flushBuffer(buf.getAddress(), limit); - } - // reset the buffer position - buf.clear(); - // clear the set of references, since we no longer need them - refSet.clear(); - } - - private class QueueFlusher implements Runnable { - private boolean needsFlush; - private Runnable task; - private Error error; - private final Thread thread; - - public QueueFlusher() { - String name = "Java2D Queue Flusher"; - thread = new Thread(MarlinUtils.getRootThreadGroup(), this, name); - thread.setDaemon(true); - thread.setPriority(Thread.MAX_PRIORITY); - thread.start(); - } - - public synchronized void flushNow() { - // wake up the flusher - needsFlush = true; - notify(); - - // wait for flush to complete - while (needsFlush) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // re-throw any error that may have occurred during the flush - if (error != null) { - throw error; - } - } - - public synchronized void flushAndInvokeNow(Runnable task) { - this.task = task; - flushNow(); - } - - public synchronized void run() { - boolean timedOut = false; - while (true) { - while (!needsFlush) { - try { - timedOut = false; - /* - * Wait until we're woken up with a flushNow() call, - * or the timeout period elapses (so that we can - * flush the queue periodically). - */ - wait(100); - /* - * We will automatically flush the queue if the - * following conditions apply: - * - the wait() timed out - * - we can lock the queue (without blocking) - * - there is something in the queue to flush - * Otherwise, just continue (we'll flush eventually). - */ - if (!needsFlush && (timedOut = tryLock())) { - if (buf.position() > 0) { - needsFlush = true; - } else { - unlock(); - } - } - } catch (InterruptedException e) { - } - } - try { - // reset the throwable state - error = null; - // flush the buffer now - flushBuffer(); - // if there's a task, invoke that now as well - if (task != null) { - task.run(); - } - } catch (Error e) { - error = e; - } catch (Exception x) { - System.err.println("exception in QueueFlusher:"); - x.printStackTrace(); - } finally { - if (timedOut) { - unlock(); - } - task = null; - // allow the waiting thread to continue - needsFlush = false; - notify(); - } - } - } - } -} diff --git a/src/main/java/sun/java2d/pipe/LoopPipe.java b/src/main/java/sun/java2d/pipe/LoopPipe.java index de81069..78f5b57 100644 --- a/src/main/java/sun/java2d/pipe/LoopPipe.java +++ b/src/main/java/sun/java2d/pipe/LoopPipe.java @@ -270,6 +270,7 @@ public static ShapeSpanIterator getStrokeSpans(SunGraphics2D sg2d, boolean normalize = (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE); + // Needed for OpenJDK 11 compatibility: if (RenderEngine instanceof sun.java2d.marlin.DMarlinRenderingEngine) { ((sun.java2d.marlin.DMarlinRenderingEngine)RenderEngine).strokeTo(s, sg2d.transform, clip, bs, diff --git a/src/main/java/sun/java2d/pipe/RenderQueue.java b/src/main/java/sun/java2d/pipe/RenderQueue.java index 31c4b4d..a2ee65f 100644 --- a/src/main/java/sun/java2d/pipe/RenderQueue.java +++ b/src/main/java/sun/java2d/pipe/RenderQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -79,7 +79,8 @@ public abstract class RenderQueue { static { // 1M instead of 32K (D3D / OGL) for high-end GPU - BUFFER_SIZE = align(getInteger("sun.java2d.render.bufferSize", 1024 * 1024, 32 * 1024, 16 * 1024 * 1024), 1024); + BUFFER_SIZE = align(getInteger("sun.java2d.render.bufferSize", 1024 * 1024, + 32 * 1024, 16 * 1024 * 1024), 1024); System.out.println("RenderQueue: sun.java2d.render.bufferSize = " + BUFFER_SIZE); } @@ -94,7 +95,7 @@ public abstract class RenderQueue { protected final Set refSet; protected RenderQueue() { - refSet = new HashSet<>(64); // large enough (LBO) ? + refSet = new HashSet<>(64); buf = RenderBuffer.allocate(BUFFER_SIZE); } diff --git a/src/test/java/ClipShapeTest.java b/src/test/java/ClipShapeTest.java index c678590..3396b82 100644 --- a/src/test/java/ClipShapeTest.java +++ b/src/test/java/ClipShapeTest.java @@ -348,6 +348,7 @@ public static void main(String[] args) { Differences [Diff Pixels [All Test setups]]: NbPixels [All Test setups][n: 30] sum: 232 avg: 7.733 [1 | 27] */ + // float variant have higher uncertainty THRESHOLD_DELTA = 2; THRESHOLD_NBPIX = (USE_DASHES) ? 6 : 0; } diff --git a/src/test/java/ScaleTest.java b/src/test/java/ScaleTest.java index bfd5642..c9778a6 100644 --- a/src/test/java/ScaleTest.java +++ b/src/test/java/ScaleTest.java @@ -21,13 +21,17 @@ * questions. */ +/* @test + * @summary Circle is rendered in C shape + * @bug 6829659 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; - public class ScaleTest { public static void main(String[] args) throws Exception { BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); diff --git a/src/test/java/StrokeShapeTest.java b/src/test/java/StrokeShapeTest.java index 41413bf..bc23f29 100644 --- a/src/test/java/StrokeShapeTest.java +++ b/src/test/java/StrokeShapeTest.java @@ -20,6 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* @test + * @summary StrokeShapeTest: createStrokedShape() behaves differently + * @bug 6829678 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; diff --git a/src/test/java/TestCreateStrokedShapeJoins.java b/src/test/java/TestCreateStrokedShapeJoins.java index 2bb0152..77672b4 100644 --- a/src/test/java/TestCreateStrokedShapeJoins.java +++ b/src/test/java/TestCreateStrokedShapeJoins.java @@ -1,104 +1,104 @@ -/* - * Copyright (c) 2023, 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. - */ - -import java.io.*; -import java.awt.*; -import java.awt.image.*; -import java.awt.geom.*; -import java.util.Arrays; -import javax.imageio.*; - -/** - * @test - * @bug 8316741 - * @summary Verifies that Marlin renderer's Stroker generates properly joins - * in createStrokedShape() - * @run main TestCreateStrokedShapeJoins - */ -public class TestCreateStrokedShapeJoins { - - static final boolean SAVE_IMAGE = false; - - private final static int W = 200; - - private final static int[] REF_COUNTS = new int[]{4561, 4790, 5499}; - - public static void main(String[] args) throws Exception { - final int[] test = new int[]{ - test(BasicStroke.JOIN_BEVEL), - test(BasicStroke.JOIN_ROUND), - test(BasicStroke.JOIN_MITER) - }; - - System.out.println("test: " + Arrays.toString(test)); - System.out.println("ref: " + Arrays.toString(REF_COUNTS)); - - // check results: - for (int i = 0; i < REF_COUNTS.length; i++) { - if (test[i] != REF_COUNTS[i]) { - throw new RuntimeException("Invalid test[" + i + "]: " + test[i] + " != " + REF_COUNTS[i]); - } - } - } - - private static int test(int join) throws Exception { - final BufferedImage image = new BufferedImage(W, W, BufferedImage.TYPE_INT_ARGB); - final Graphics2D g = image.createGraphics(); - try { - g.setPaint(Color.BLACK); - g.fillRect(0, 0, W, W); - g.setPaint(Color.WHITE); - g.setTransform(new AffineTransform(W, 0, 0, W, 0, 0)); - - final BasicStroke stroke = new BasicStroke(0.15f, 0, join, 10); - - final Path2D p = new Path2D.Float(); - p.moveTo(0.95f, 0.6f); - p.lineTo(0.5f, 0.5f); - p.lineTo(0.95f, 0.4f); - - final Shape outline = stroke.createStrokedShape(p); - g.fill(outline); - } finally { - g.dispose(); - } - if (SAVE_IMAGE) { - final File file = new File("TestCreateStrokedShapeJoins-" + join + ".png"); - System.out.println("Writing " + file.getAbsolutePath()); - ImageIO.write(image, "png", file); - } - int count = 0; - - for (int y = 0; y < W; y++) { - for (int x = 0; x < W; x++) { - final int rgb = image.getRGB(x, y); - final int b = rgb & 0xFF; - - if (b != 0) { - count++; - } - } - } - return count; - } -} +/* + * Copyright (c) 2023, 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. + */ + +import java.io.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.geom.*; +import java.util.Arrays; +import javax.imageio.*; + +/** + * @test + * @bug 8316741 + * @summary Verifies that Marlin renderer's Stroker generates properly joins + * in createStrokedShape() + * @run main TestCreateStrokedShapeJoins + */ +public class TestCreateStrokedShapeJoins { + + static final boolean SAVE_IMAGE = false; + + private final static int W = 200; + + private final static int[] REF_COUNTS = new int[] {4561, 4790, 5499}; + + public static void main(String[] args) throws Exception { + final int[] test = new int[] { + test(BasicStroke.JOIN_BEVEL), + test(BasicStroke.JOIN_ROUND), + test(BasicStroke.JOIN_MITER) + }; + + System.out.println("test: " + Arrays.toString(test)); + System.out.println("ref: " + Arrays.toString(REF_COUNTS)); + + // check results: + for (int i = 0; i < REF_COUNTS.length; i++) { + if (test[i] != REF_COUNTS[i]) { + throw new RuntimeException("Invalid test[" + i + "]: " + test[i] + " != " + REF_COUNTS[i]); + } + } + } + + private static int test(int join) throws Exception { + final BufferedImage image = new BufferedImage(W, W, BufferedImage.TYPE_INT_ARGB); + final Graphics2D g = image.createGraphics(); + try { + g.setPaint(Color.BLACK); + g.fillRect(0, 0, W, W); + g.setPaint(Color.WHITE); + g.setTransform(new AffineTransform(W, 0, 0, W, 0, 0)); + + final BasicStroke stroke = new BasicStroke(0.15f, 0, join, 10); + + final Path2D p = new Path2D.Float(); + p.moveTo(0.95f, 0.6f); + p.lineTo(0.5f, 0.5f); + p.lineTo(0.95f, 0.4f); + + final Shape outline = stroke.createStrokedShape(p); + g.fill(outline); + } finally { + g.dispose(); + } + if (SAVE_IMAGE) { + final File file = new File("TestCreateStrokedShapeJoins-" + join + ".png"); + System.out.println("Writing " + file.getAbsolutePath()); + ImageIO.write(image, "png", file); + } + int count = 0; + + for (int y = 0; y < W; y++) { + for (int x = 0; x < W; x++) { + final int rgb = image.getRGB(x, y); + final int b = rgb & 0xFF; + + if (b != 0) { + count++; + } + } + } + return count; + } +} diff --git a/src/test/java/ThinLineTest.java b/src/test/java/ThinLineTest.java index a1a033c..7450f4e 100644 --- a/src/test/java/ThinLineTest.java +++ b/src/test/java/ThinLineTest.java @@ -20,6 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* @test + * @summary ThinLineTest: A line < 1 pixel disappears. + * @bug 6829673 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage;