--- old/modules/javafx.graphics/src/main/java/com/sun/prism/impl/shape/MarlinPrismUtils.java 2017-08-25 21:49:17.015693317 +0200 +++ new/modules/javafx.graphics/src/main/java/com/sun/prism/impl/shape/MarlinPrismUtils.java 2017-08-25 21:49:16.863690298 +0200 @@ -33,8 +33,10 @@ import com.sun.javafx.geom.Shape; import com.sun.javafx.geom.transform.BaseTransform; import com.sun.marlin.MarlinConst; +import com.sun.marlin.MarlinProperties; import com.sun.marlin.MarlinRenderer; import com.sun.marlin.RendererContext; +import com.sun.marlin.Stroker; import com.sun.marlin.TransformingPathConsumer2D; import com.sun.prism.BasicStroke; @@ -45,6 +47,9 @@ static final float UPPER_BND = Float.MAX_VALUE / 2.0f; static final float LOWER_BND = -UPPER_BND; + static final boolean DO_CLIP = MarlinProperties.isDoClip(); + static final boolean DO_TRACE = false; + /** * Private constructor to prevent instantiation. */ @@ -79,7 +84,7 @@ int dashLen = -1; boolean recycleDashes = false; - + float scale = 1.0f; float width = 0.0f, dashphase = 0.0f; float[] dashes = null; @@ -101,7 +106,7 @@ // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we // leave a bit of room for error. if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) { - final float scale = (float) Math.sqrt(a*a + c*c); + scale = (float) Math.sqrt(a*a + c*c); if (dashes != null) { recycleDashes = true; @@ -136,7 +141,33 @@ } } - PathConsumer2D pc = renderer.init(clip.x, clip.y, clip.width, clip.height, oprule); + final MarlinRenderer rdr = renderer.init(clip.x, clip.y, clip.width, clip.height, oprule); + PathConsumer2D pc = rdr; + + float rdrOffX = 0.0f, rdrOffY = 0.0f; + + if (DO_CLIP && stroke != null) { + // Define the initial clip bounds: + final float[] clipRect = rdrCtx.clipRect; + clipRect[0] = clip.y; + clipRect[1] = clip.y + clip.height; + clipRect[2] = clip.x; + clipRect[3] = clip.x + clip.width; + + // Get offsets: + rdrOffX = rdr.getOffsetX(); + rdrOffY = rdr.getOffsetY(); + + // Enable clipping: + rdrCtx.doClip = true; + } + + final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D; + + if (DO_TRACE) { + // trace Stroker: + pc = transformerPC2D.traceStroker(pc); + } if (MarlinConst.USE_SIMPLIFIER) { // Use simplifier after stroker before Renderer @@ -144,23 +175,36 @@ pc = rdrCtx.simplifier.init(pc); } - final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D; - pc = transformerPC2D.deltaTransformConsumer(pc, strokerTx); + // deltaTransformConsumer may adjust the clip rectangle: + pc = transformerPC2D.deltaTransformConsumer(pc, strokerTx, rdrOffX, rdrOffY); if (stroke != null) { + // stroker will adjust the clip rectangle (width / miter limit): pc = rdrCtx.stroker.init(pc, width, stroke.getEndCap(), - stroke.getLineJoin(), stroke.getMiterLimit()); + stroke.getLineJoin(), stroke.getMiterLimit(), + scale, rdrOffX, rdrOffY); if (dashes != null) { if (!recycleDashes) { dashLen = dashes.length; } pc = rdrCtx.dasher.init(pc, dashes, dashLen, dashphase, recycleDashes); + } else if (rdrCtx.doClip && (stroke.getEndCap() != Stroker.CAP_BUTT)) { + if (DO_TRACE) { + pc = transformerPC2D.traceClosedPathDetector(pc); + } + + // If no dash and clip is enabled: + // detect closedPaths (polygons) for caps + pc = transformerPC2D.detectClosedPath(pc); } } - pc = transformerPC2D.inverseDeltaTransformConsumer(pc, strokerTx); + if (DO_TRACE) { + // trace Input: + pc = transformerPC2D.traceInput(pc); + } /* * Pipeline seems to be: * shape.getPathIterator(tx) @@ -358,8 +402,8 @@ // - removed pathClosed (ie subpathStarted not set to false) boolean subpathStarted = false; - final float pCoords[] = p2d.getFloatCoordsNoClone(); - final byte pTypes[] = p2d.getCommandsNoClone(); + final float[] pCoords = p2d.getFloatCoordsNoClone(); + final byte[] pTypes = p2d.getCommandsNoClone(); final int nsegs = p2d.getNumCommands(); for (int i = 0, coff = 0; i < nsegs; i++) {