--- a/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java Mon Dec 11 10:08:51 2017 -0800
+++ b/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java Mon Dec 11 21:14:43 2017 +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) {
@@ -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));
@@ -596,14 +625,12 @@
}
private static void pathTo(final DRendererContext rdrCtx, final PathIterator pi,
- final DPathConsumer2D pc2d)
+ DPathConsumer2D pc2d)
{
// mark context as DIRTY:
rdrCtx.dirty = true;
- final double[] coords = rdrCtx.double6;
-
- pathToLoop(coords, pi, pc2d);
+ pathToLoop(rdrCtx.double6, pi, pc2d);
// mark context as CLEAN:
rdrCtx.dirty = false;
@@ -781,6 +808,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;
@@ -797,13 +837,29 @@
clip.getWidth(), clip.getHeight(),
pi.getWindingRule());
+ 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 +882,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 +918,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 +971,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");
}
@@ -1045,6 +1101,11 @@
logInfo("sun.java2d.renderer.useSimplifier = "
+ MarlinConst.USE_SIMPLIFIER);
+ logInfo("sun.java2d.renderer.clip = "
+ + MarlinProperties.isDoClip());
+ logInfo("sun.java2d.renderer.clip.runtime.enable = "
+ + MarlinProperties.isDoClipRuntimeFlag());
+
// debugging parameters
logInfo("sun.java2d.renderer.doStats = "
+ MarlinConst.DO_STATS);