--- old/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java 2017-11-14 22:42:38.750357476 +0100 +++ new/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java 2017-11-14 22:42:38.618354603 +0100 @@ -84,6 +84,13 @@ static final double UPPER_BND = Float.MAX_VALUE / 2.0d; static final double LOWER_BND = -UPPER_BND; + static final boolean DO_CLIP = MarlinProperties.isDoClip(); + static final boolean DO_CLIP_FILL = true; + + static final boolean DO_TRACE_PATH = false; + + static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag(); + /** * Public constructor */ @@ -133,7 +140,7 @@ miterlimit, dashes, dashphase, - rdrCtx.transformerPC2D.wrapPath2d(p2d) + rdrCtx.transformerPC2D.wrapPath2D(p2d) ); // Use Path2D copy constructor (trim) @@ -195,14 +202,14 @@ } } - final void strokeTo(final DRendererContext rdrCtx, - Shape src, - AffineTransform at, - BasicStroke bs, - boolean thin, - NormMode normalize, - boolean antialias, - DPathConsumer2D pc2d) + void strokeTo(final DRendererContext rdrCtx, + Shape src, + AffineTransform at, + BasicStroke bs, + boolean thin, + NormMode normalize, + boolean antialias, + DPathConsumer2D pc2d) { double lw; if (thin) { @@ -227,7 +234,7 @@ pc2d); } - private final double userSpaceLineWidth(AffineTransform at, double lw) { + private double userSpaceLineWidth(AffineTransform at, double lw) { double widthScale; @@ -295,17 +302,17 @@ return (lw / widthScale); } - final void strokeTo(final DRendererContext rdrCtx, - Shape src, - AffineTransform at, - double width, - NormMode norm, - int caps, - int join, - float miterlimit, - float[] dashes, - float dashphase, - DPathConsumer2D pc2d) + void strokeTo(final DRendererContext rdrCtx, + Shape src, + AffineTransform at, + double width, + NormMode norm, + int caps, + int join, + float miterlimit, + float[] dashes, + float dashphase, + DPathConsumer2D pc2d) { // We use strokerat so that in Stroker and Dasher we can work only // with the pre-transformation coordinates. This will repeat a lot of @@ -324,6 +331,7 @@ int dashLen = -1; boolean recycleDashes = false; + double scale = 1.0d; double[] dashesD = null; // Ensure converting dashes to double precision: @@ -364,7 +372,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 double scale = Math.sqrt(a*a + c*c); + scale = Math.sqrt(a*a + c*c); if (dashesD != null) { for (int i = 0; i < dashLen; i++) { @@ -399,23 +407,44 @@ at = null; } + final DTransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D; + + if (DO_TRACE_PATH) { + // trace Stroker: + pc2d = transformerPC2D.traceStroker(pc2d); + } + if (USE_SIMPLIFIER) { // Use simplifier after stroker before Renderer // to remove collinear segments (notably due to cap square) pc2d = rdrCtx.simplifier.init(pc2d); } - final DTransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D; + // deltaTransformConsumer may adjust the clip rectangle: pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat); - pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit); + // stroker will adjust the clip rectangle (width / miter limit): + pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale); if (dashesD != null) { pc2d = rdrCtx.dasher.init(pc2d, dashesD, dashLen, dashphase, recycleDashes); + } else if (rdrCtx.doClip && (caps != Stroker.CAP_BUTT)) { + if (DO_TRACE_PATH) { + pc2d = transformerPC2D.traceClosedPathDetector(pc2d); + } + + // If no dash and clip is enabled: + // detect closedPaths (polygons) for caps + pc2d = transformerPC2D.detectClosedPath(pc2d); } pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat); + if (DO_TRACE_PATH) { + // trace Input: + pc2d = transformerPC2D.traceInput(pc2d); + } + final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx, src.getPathIterator(at)); @@ -781,6 +810,19 @@ final DRendererContext rdrCtx = getRendererContext(); try { + if (DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime())) { + // Define the initial clip bounds: + final double[] clipRect = rdrCtx.clipRect; + + clipRect[0] = clip.getLoY(); + clipRect[1] = clip.getLoY() + clip.getHeight(); + clipRect[2] = clip.getLoX(); + clipRect[3] = clip.getLoX() + clip.getWidth(); + + // Enable clipping: + rdrCtx.doClip = true; + } + // Test if at is identity: final AffineTransform _at = (at != null && !at.isIdentity()) ? at : null; @@ -792,18 +834,36 @@ final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx, s.getPathIterator(_at)); + final int windingRule = pi.getWindingRule(); + // note: Winding rule may be EvenOdd ONLY for fill operations ! r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(), clip.getWidth(), clip.getHeight(), - pi.getWindingRule()); + windingRule); + + DPathConsumer2D pc2d = r; + + if (DO_CLIP_FILL && rdrCtx.doClip) { + if (DO_TRACE_PATH) { + // trace Filler: + pc2d = rdrCtx.transformerPC2D.traceFiller(pc2d); + } + pc2d = rdrCtx.transformerPC2D.pathClipper(pc2d); + } + + if (DO_TRACE_PATH) { + // trace Input: + pc2d = rdrCtx.transformerPC2D.traceInput(pc2d); + } // TODO: subdivide quad/cubic curves into monotonic curves ? - pathTo(rdrCtx, pi, r); + pathTo(rdrCtx, pi, pc2d); + } else { // draw shape with given stroke: r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(), clip.getWidth(), clip.getHeight(), - PathIterator.WIND_NON_ZERO); + WIND_NON_ZERO); strokeTo(rdrCtx, s, _at, bs, thin, norm, true, r); } @@ -826,12 +886,12 @@ } @Override - public final AATileGenerator getAATileGenerator(double x, double y, - double dx1, double dy1, - double dx2, double dy2, - double lw1, double lw2, - Region clip, - int[] bbox) + public AATileGenerator getAATileGenerator(double x, double y, + double dx1, double dy1, + double dx2, double dy2, + double lw1, double lw2, + Region clip, + int[] bbox) { // REMIND: Deal with large coordinates! double ldx1, ldy1, ldx2, ldy2; @@ -862,8 +922,8 @@ final DRendererContext rdrCtx = getRendererContext(); try { r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(), - clip.getWidth(), clip.getHeight(), - DRenderer.WIND_EVEN_ODD); + clip.getWidth(), clip.getHeight(), + WIND_EVEN_ODD); r.moveTo( x, y); r.lineTo( (x+dx1), (y+dy1)); @@ -915,14 +975,14 @@ } static { - if (PathIterator.WIND_NON_ZERO != DRenderer.WIND_NON_ZERO || - PathIterator.WIND_EVEN_ODD != DRenderer.WIND_EVEN_ODD || - BasicStroke.JOIN_MITER != DStroker.JOIN_MITER || - BasicStroke.JOIN_ROUND != DStroker.JOIN_ROUND || - BasicStroke.JOIN_BEVEL != DStroker.JOIN_BEVEL || - BasicStroke.CAP_BUTT != DStroker.CAP_BUTT || - BasicStroke.CAP_ROUND != DStroker.CAP_ROUND || - BasicStroke.CAP_SQUARE != DStroker.CAP_SQUARE) + if (PathIterator.WIND_NON_ZERO != WIND_NON_ZERO || + PathIterator.WIND_EVEN_ODD != WIND_EVEN_ODD || + BasicStroke.JOIN_MITER != JOIN_MITER || + BasicStroke.JOIN_ROUND != JOIN_ROUND || + BasicStroke.JOIN_BEVEL != JOIN_BEVEL || + BasicStroke.CAP_BUTT != CAP_BUTT || + BasicStroke.CAP_ROUND != CAP_ROUND || + BasicStroke.CAP_SQUARE != CAP_SQUARE) { throw new InternalError("mismatched renderer constants"); } @@ -1044,6 +1104,8 @@ // optimisation parameters logInfo("sun.java2d.renderer.useSimplifier = " + MarlinConst.USE_SIMPLIFIER); + logInfo("sun.java2d.renderer.clip = " + + MarlinProperties.isDoClip()); // debugging parameters logInfo("sun.java2d.renderer.doStats = "