--- old/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java 2018-02-15 13:11:17.624520637 +0100
+++ new/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java 2018-02-15 13:11:17.472516476 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, 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
@@ -29,6 +29,8 @@
import sun.awt.geom.PathConsumer2D;
import sun.java2d.marlin.Helpers.PolyStack;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveClipSplitter;
// TODO: some of the arithmetic here is too verbose and prone to hard to
// debug typos. We should consider making a small Point/Vector class that
@@ -39,10 +41,9 @@
private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
private static final int CLOSE = 2;
- // pisces used to use fixed point arithmetic with 16 decimal digits. I
- // didn't want to change the values of the constant below when I converted
- // it to floating point, so that's why the divisions by 2^16 are there.
- private static final float ROUND_JOIN_THRESHOLD = 1000.0f/65536.0f;
+ // round join threshold = 1 subpixel
+ private static final float ERR_JOIN = (1.0f / MIN_SUBPIXELS);
+ private static final float ROUND_JOIN_THRESHOLD = ERR_JOIN * ERR_JOIN;
// kappa = (4/3) * (SQRT(2) - 1)
private static final float C = (float)(4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d);
@@ -50,8 +51,6 @@
// SQRT(2)
private static final float SQRT_2 = (float)Math.sqrt(2.0d);
- private static final int MAX_N_CURVES = 11;
-
private PathConsumer2D out;
private int capStyle;
@@ -82,12 +81,8 @@
private final PolyStack reverse;
- // This is where the curve to be processed is put. We give it
- // enough room to store all curves.
- private final float[] middle = new float[MAX_N_CURVES * 6 + 2];
private final float[] lp = new float[8];
private final float[] rp = new float[8];
- private final float[] subdivTs = new float[MAX_N_CURVES - 1];
// per-thread renderer context
final RendererContext rdrCtx;
@@ -108,6 +103,11 @@
private boolean opened = false;
// flag indicating if the starting point's cap is done
private boolean capStart = false;
+ // flag indicating to monotonize curves
+ private boolean monotonize;
+
+ private boolean subdivide = DO_CLIP_SUBDIVIDER;
+ private final CurveClipSplitter curveSplitter;
/**
* Constructs a Stroker
.
@@ -126,6 +126,7 @@
: new PolyStack(rdrCtx);
this.curve = rdrCtx.curve;
+ this.curveSplitter = rdrCtx.curveClipSplitter;
}
/**
@@ -141,6 +142,7 @@
* JOIN_BEVEL
.
* @param miterLimit the desired miter limit
* @param scale scaling factor applied to clip boundaries
+ * @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
Stroker init(final PathConsumer2D pc2d,
@@ -148,12 +150,15 @@
final int capStyle,
final int joinStyle,
final float miterLimit,
- final float scale)
+ final float scale,
+ final boolean subdivideCurves)
{
this.out = pc2d;
this.lineWidth2 = lineWidth / 2.0f;
this.invHalfLineWidth2Sq = 1.0f / (2.0f * lineWidth2 * lineWidth2);
+ this.monotonize = subdivideCurves;
+
this.capStyle = capStyle;
this.joinStyle = joinStyle;
@@ -191,6 +196,15 @@
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;
this.clipRect = _clipRect;
+
+ // initialize curve splitter here for stroker & dasher:
+ if (DO_CLIP_SUBDIVIDER) {
+ subdivide = subdivideCurves;
+ // adjust padded clip rectangle:
+ curveSplitter.init();
+ } else {
+ subdivide = false;
+ }
} else {
this.clipRect = null;
this.cOutCode = 0;
@@ -199,6 +213,12 @@
return this; // fluent API
}
+ void disableClipping() {
+ this.clipRect = null;
+ this.cOutCode = 0;
+ this.sOutCode = 0;
+ }
+
/**
* Disposes this stroker:
* clean up before reusing this instance
@@ -215,10 +235,8 @@
Arrays.fill(offset1, 0.0f);
Arrays.fill(offset2, 0.0f);
Arrays.fill(miter, 0.0f);
- Arrays.fill(middle, 0.0f);
Arrays.fill(lp, 0.0f);
Arrays.fill(rp, 0.0f);
- Arrays.fill(subdivTs, 0.0f);
}
}
@@ -250,19 +268,20 @@
return dx1 * dy2 <= dy1 * dx2;
}
- private void drawRoundJoin(float x, float y,
- float omx, float omy, float mx, float my,
- boolean rev,
- float threshold)
+ private void mayDrawRoundJoin(float cx, float cy,
+ float omx, float omy,
+ float mx, float my,
+ boolean rev)
{
if ((omx == 0.0f && omy == 0.0f) || (mx == 0.0f && my == 0.0f)) {
return;
}
- float domx = omx - mx;
- float domy = omy - my;
- float len = domx*domx + domy*domy;
- if (len < threshold) {
+ final float domx = omx - mx;
+ final float domy = omy - my;
+ final float lenSq = domx*domx + domy*domy;
+
+ if (lenSq < ROUND_JOIN_THRESHOLD) {
return;
}
@@ -272,7 +291,7 @@
mx = -mx;
my = -my;
}
- drawRoundJoin(x, y, omx, omy, mx, my, rev);
+ drawRoundJoin(cx, cy, omx, omy, mx, my, rev);
}
private void drawRoundJoin(float cx, float cy,
@@ -383,7 +402,7 @@
final float x1, final float y1,
final float x0p, final float y0p,
final float x1p, final float y1p,
- final float[] m, int off)
+ final float[] m)
{
float x10 = x1 - x0;
float y10 = y1 - y0;
@@ -402,8 +421,8 @@
float den = x10*y10p - x10p*y10;
float t = x10p*(y0-y0p) - y10p*(x0-x0p);
t /= den;
- m[off++] = x0 + t*x10;
- m[off] = y0 + t*y10;
+ m[0] = x0 + t*x10;
+ m[1] = y0 + t*y10;
}
// Return the intersection point of the lines (x0, y0) -> (x1, y1)
@@ -412,7 +431,7 @@
final float x1, final float y1,
final float x0p, final float y0p,
final float x1p, final float y1p,
- final float[] m, int off)
+ final float[] m)
{
float x10 = x1 - x0;
float y10 = y1 - y0;
@@ -430,20 +449,21 @@
// immediately).
float den = x10*y10p - x10p*y10;
if (den == 0.0f) {
- m[off++] = (x0 + x0p) / 2.0f;
- m[off] = (y0 + y0p) / 2.0f;
- return;
+ m[2] = (x0 + x0p) / 2.0f;
+ m[3] = (y0 + y0p) / 2.0f;
+ } else {
+ float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ t /= den;
+ m[2] = x0 + t*x10;
+ m[3] = y0 + t*y10;
}
- float t = x10p*(y0-y0p) - y10p*(x0-x0p);
- t /= den;
- m[off++] = x0 + t*x10;
- m[off] = y0 + t*y10;
}
private void drawMiter(final float pdx, final float pdy,
final float x0, final float y0,
final float dx, final float dy,
- float omx, float omy, float mx, float my,
+ float omx, float omy,
+ float mx, float my,
boolean rev)
{
if ((mx == omx && my == omy) ||
@@ -461,8 +481,7 @@
}
computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
- (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
- miter, 0);
+ (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my, miter);
final float miterX = miter[0];
final float miterY = miter[1];
@@ -480,7 +499,7 @@
@Override
public void moveTo(final float x0, final float y0) {
- moveTo(x0, y0, cOutCode);
+ _moveTo(x0, y0, cOutCode);
// update starting point:
this.sx0 = x0;
this.sy0 = y0;
@@ -496,7 +515,7 @@
}
}
- private void moveTo(final float x0, final float y0,
+ private void _moveTo(final float x0, final float y0,
final int outcode)
{
if (prev == MOVE_TO) {
@@ -523,16 +542,40 @@
final boolean force)
{
final int outcode0 = this.cOutCode;
+
if (!force && clipRect != null) {
final int outcode1 = Helpers.outcode(x1, y1, clipRect);
- this.cOutCode = outcode1;
- // basic rejection criteria
- if ((outcode0 & outcode1) != 0) {
- moveTo(x1, y1, outcode0);
- opened = true;
- return;
+ // Should clip
+ final int orCode = (outcode0 | outcode1);
+ if (orCode != 0) {
+ final int sideCode = outcode0 & outcode1;
+
+ // basic rejection criteria:
+ if (sideCode == 0) {
+ // ovelap clip:
+ if (subdivide) {
+ // avoid reentrance
+ subdivide = false;
+ // subdivide curve => callback with subdivided parts:
+ boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1,
+ orCode, this);
+ // reentrance is done:
+ subdivide = true;
+ if (ret) {
+ return;
+ }
+ }
+ // already subdivided so render it
+ } else {
+ this.cOutCode = outcode1;
+ _moveTo(x1, y1, outcode0);
+ opened = true;
+ return;
+ }
}
+
+ this.cOutCode = outcode1;
}
float dx = x1 - cx0;
@@ -754,10 +797,7 @@
if (joinStyle == JOIN_MITER) {
drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
} else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, cw,
- ROUND_JOIN_THRESHOLD);
+ mayDrawRoundJoin(x0, y0, omx, omy, mx, my, cw);
}
}
emitLineTo(x0, y0, !cw);
@@ -767,18 +807,19 @@
private static boolean within(final float x1, final float y1,
final float x2, final float y2,
- final float ERR)
+ final float err)
{
- assert ERR > 0 : "";
+ assert err > 0 : "";
// compare taxicab distance. ERR will always be small, so using
// true distance won't give much benefit
- return (Helpers.within(x1, x2, ERR) && // we want to avoid calling Math.abs
- Helpers.within(y1, y2, ERR)); // this is just as good.
+ return (Helpers.within(x1, x2, err) && // we want to avoid calling Math.abs
+ Helpers.within(y1, y2, err)); // this is just as good.
}
- private void getLineOffsets(float x1, float y1,
- float x2, float y2,
- float[] left, float[] right) {
+ private void getLineOffsets(final float x1, final float y1,
+ final float x2, final float y2,
+ final float[] left, final float[] right)
+ {
computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
final float mx = offset0[0];
final float my = offset0[1];
@@ -786,14 +827,16 @@
left[1] = y1 + my;
left[2] = x2 + mx;
left[3] = y2 + my;
+
right[0] = x1 - mx;
right[1] = y1 - my;
right[2] = x2 - mx;
right[3] = y2 - my;
}
- private int computeOffsetCubic(float[] pts, final int off,
- float[] leftOff, float[] rightOff)
+ private int computeOffsetCubic(final float[] pts, final int off,
+ final float[] leftOff,
+ final float[] rightOff)
{
// if p1=p2 or p3=p4 it means that the derivative at the endpoint
// vanishes, which creates problems with computeOffset. Usually
@@ -802,7 +845,7 @@
// the input curve at the cusp, and passes it to this function.
// because of inaccuracies in the splitting, we consider points
// equal if they're very close to each other.
- final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x1 = pts[off ], y1 = pts[off + 1];
final float x2 = pts[off + 2], y2 = pts[off + 3];
final float x3 = pts[off + 4], y3 = pts[off + 5];
final float x4 = pts[off + 6], y4 = pts[off + 7];
@@ -816,6 +859,7 @@
// in which case ignore if p1 == p2
final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0f * Math.ulp(y2));
final boolean p3eqp4 = within(x3, y3, x4, y4, 6.0f * Math.ulp(y4));
+
if (p1eqp2 && p3eqp4) {
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
return 4;
@@ -831,6 +875,7 @@
float dotsq = (dx1 * dx4 + dy1 * dy4);
dotsq *= dotsq;
float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+
if (Helpers.within(dotsq, l1sq * l4sq, 4.0f * Math.ulp(dotsq))) {
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
return 4;
@@ -944,10 +989,11 @@
// compute offset curves using bezier spline through t=0.5 (i.e.
// ComputedCurve(0.5) == IdealParallelCurve(0.5))
// return the kind of curve in the right and left arrays.
- private int computeOffsetQuad(float[] pts, final int off,
- float[] leftOff, float[] rightOff)
+ private int computeOffsetQuad(final float[] pts, final int off,
+ final float[] leftOff,
+ final float[] rightOff)
{
- final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x1 = pts[off ], y1 = pts[off + 1];
final float x2 = pts[off + 2], y2 = pts[off + 3];
final float x3 = pts[off + 4], y3 = pts[off + 5];
@@ -968,6 +1014,7 @@
// in which case ignore.
final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0f * Math.ulp(y2));
final boolean p2eqp3 = within(x2, y2, x3, y3, 6.0f * Math.ulp(y3));
+
if (p1eqp2 || p2eqp3) {
getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
return 4;
@@ -977,6 +1024,7 @@
float dotsq = (dx1 * dx3 + dy1 * dy3);
dotsq *= dotsq;
float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+
if (Helpers.within(dotsq, l1sq * l3sq, 4.0f * Math.ulp(dotsq))) {
getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
return 4;
@@ -992,151 +1040,111 @@
float y1p = y1 + offset0[1]; // point
float x3p = x3 + offset1[0]; // end
float y3p = y3 + offset1[1]; // point
- safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
+ safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff);
leftOff[0] = x1p; leftOff[1] = y1p;
leftOff[4] = x3p; leftOff[5] = y3p;
x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
x3p = x3 - offset1[0]; y3p = y3 - offset1[1];
- safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
+ safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff);
rightOff[0] = x1p; rightOff[1] = y1p;
rightOff[4] = x3p; rightOff[5] = y3p;
return 6;
}
- // finds values of t where the curve in pts should be subdivided in order
- // to get good offset curves a distance of w away from the middle curve.
- // Stores the points in ts, and returns how many of them there were.
- private static int findSubdivPoints(final Curve c, float[] pts, float[] ts,
- final int type, final float w)
- {
- final float x12 = pts[2] - pts[0];
- final float y12 = pts[3] - pts[1];
- // if the curve is already parallel to either axis we gain nothing
- // from rotating it.
- if (y12 != 0.0f && x12 != 0.0f) {
- // we rotate it so that the first vector in the control polygon is
- // parallel to the x-axis. This will ensure that rotated quarter
- // circles won't be subdivided.
- final float hypot = (float) Math.sqrt(x12 * x12 + y12 * y12);
- final float cos = x12 / hypot;
- final float sin = y12 / hypot;
- final float x1 = cos * pts[0] + sin * pts[1];
- final float y1 = cos * pts[1] - sin * pts[0];
- final float x2 = cos * pts[2] + sin * pts[3];
- final float y2 = cos * pts[3] - sin * pts[2];
- final float x3 = cos * pts[4] + sin * pts[5];
- final float y3 = cos * pts[5] - sin * pts[4];
-
- switch(type) {
- case 8:
- final float x4 = cos * pts[6] + sin * pts[7];
- final float y4 = cos * pts[7] - sin * pts[6];
- c.set(x1, y1, x2, y2, x3, y3, x4, y4);
- break;
- case 6:
- c.set(x1, y1, x2, y2, x3, y3);
- break;
- default:
- }
- } else {
- c.set(pts, type);
- }
-
- int ret = 0;
- // we subdivide at values of t such that the remaining rotated
- // curves are monotonic in x and y.
- ret += c.dxRoots(ts, ret);
- ret += c.dyRoots(ts, ret);
- // subdivide at inflection points.
- if (type == 8) {
- // quadratic curves can't have inflection points
- ret += c.infPoints(ts, ret);
- }
-
- // now we must subdivide at points where one of the offset curves will have
- // a cusp. This happens at ts where the radius of curvature is equal to w.
- ret += c.rootsOfROCMinusW(ts, ret, w, 0.0001f);
-
- ret = Helpers.filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
- Helpers.isort(ts, 0, ret);
- return ret;
- }
-
@Override
public void curveTo(final float x1, final float y1,
final float x2, final float y2,
final float x3, final float y3)
{
final int outcode0 = this.cOutCode;
+
if (clipRect != null) {
+ final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+ final int outcode2 = Helpers.outcode(x2, y2, clipRect);
final int outcode3 = Helpers.outcode(x3, y3, clipRect);
- this.cOutCode = outcode3;
- if ((outcode0 & outcode3) != 0) {
- final int outcode1 = Helpers.outcode(x1, y1, clipRect);
- final int outcode2 = Helpers.outcode(x2, y2, clipRect);
-
- // basic rejection criteria
- if ((outcode0 & outcode1 & outcode2 & outcode3) != 0) {
- moveTo(x3, y3, outcode0);
+ // Should clip
+ final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+ if (orCode != 0) {
+ final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+ // basic rejection criteria:
+ if (sideCode == 0) {
+ // ovelap clip:
+ if (subdivide) {
+ // avoid reentrance
+ subdivide = false;
+ // subdivide curve => callback with subdivided parts:
+ boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+ x2, y2, x3, y3,
+ orCode, this);
+ // reentrance is done:
+ subdivide = true;
+ if (ret) {
+ return;
+ }
+ }
+ // already subdivided so render it
+ } else {
+ this.cOutCode = outcode3;
+ _moveTo(x3, y3, outcode0);
opened = true;
return;
}
}
- }
- final float[] mid = middle;
-
- mid[0] = cx0; mid[1] = cy0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
- mid[6] = x3; mid[7] = y3;
+ this.cOutCode = outcode3;
+ }
+ _curveTo(x1, y1, x2, y2, x3, y3, outcode0);
+ }
+ private void _curveTo(final float x1, final float y1,
+ final float x2, final float y2,
+ final float x3, final float y3,
+ final int outcode0)
+ {
// need these so we can update the state at the end of this method
- final float xf = x3, yf = y3;
- float dxs = mid[2] - mid[0];
- float dys = mid[3] - mid[1];
- float dxf = mid[6] - mid[4];
- float dyf = mid[7] - mid[5];
-
- boolean p1eqp2 = (dxs == 0.0f && dys == 0.0f);
- boolean p3eqp4 = (dxf == 0.0f && dyf == 0.0f);
- if (p1eqp2) {
- dxs = mid[4] - mid[0];
- dys = mid[5] - mid[1];
- if (dxs == 0.0f && dys == 0.0f) {
- dxs = mid[6] - mid[0];
- dys = mid[7] - mid[1];
- }
- }
- if (p3eqp4) {
- dxf = mid[6] - mid[2];
- dyf = mid[7] - mid[3];
- if (dxf == 0.0f && dyf == 0.0f) {
- dxf = mid[6] - mid[0];
- dyf = mid[7] - mid[1];
+ float dxs = x1 - cx0;
+ float dys = y1 - cy0;
+ float dxf = x3 - x2;
+ float dyf = y3 - y2;
+
+ if ((dxs == 0.0f) && (dys == 0.0f)) {
+ dxs = x2 - cx0;
+ dys = y2 - cy0;
+ if ((dxs == 0.0f) && (dys == 0.0f)) {
+ dxs = x3 - cx0;
+ dys = y3 - cy0;
+ }
+ }
+ if ((dxf == 0.0f) && (dyf == 0.0f)) {
+ dxf = x3 - x1;
+ dyf = y3 - y1;
+ if ((dxf == 0.0f) && (dyf == 0.0f)) {
+ dxf = x3 - cx0;
+ dyf = y3 - cy0;
}
}
- if (dxs == 0.0f && dys == 0.0f) {
+ if ((dxs == 0.0f) && (dys == 0.0f)) {
// this happens if the "curve" is just a point
// fix outcode0 for lineTo() call:
if (clipRect != null) {
this.cOutCode = outcode0;
}
- lineTo(mid[0], mid[1]);
+ lineTo(cx0, cy0);
return;
}
// if these vectors are too small, normalize them, to avoid future
// precision problems.
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
- float len = (float) Math.sqrt(dxs*dxs + dys*dys);
+ final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
dxs /= len;
dys /= len;
}
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
- float len = (float) Math.sqrt(dxf*dxf + dyf*dyf);
+ final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
dxf /= len;
dyf /= len;
}
@@ -1144,17 +1152,25 @@
computeOffset(dxs, dys, lineWidth2, offset0);
drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
- final int nSplits = findSubdivPoints(curve, mid, subdivTs, 8, lineWidth2);
+ int nSplits = 0;
+ final float[] mid;
+ final float[] l = lp;
- float prevT = 0.0f;
- for (int i = 0, off = 0; i < nSplits; i++, off += 6) {
- final float t = subdivTs[i];
- Helpers.subdivideCubicAt((t - prevT) / (1.0f - prevT),
- mid, off, mid, off, mid, off + 6);
- prevT = t;
- }
+ if (monotonize) {
+ // monotonize curve:
+ final CurveBasicMonotonizer monotonizer
+ = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
- final float[] l = lp;
+ nSplits = monotonizer.nbSplits;
+ mid = monotonizer.middle;
+ } else {
+ // use left instead:
+ mid = l;
+ mid[0] = cx0; mid[1] = cy0;
+ mid[2] = x1; mid[3] = y1;
+ mid[4] = x2; mid[5] = y2;
+ mid[6] = x3; mid[7] = y3;
+ }
final float[] r = rp;
int kind = 0;
@@ -1178,8 +1194,8 @@
}
this.prev = DRAWING_OP_TO;
- this.cx0 = xf;
- this.cy0 = yf;
+ this.cx0 = x3;
+ this.cy0 = y3;
this.cdx = dxf;
this.cdy = dyf;
this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;
@@ -1191,74 +1207,101 @@
final float x2, final float y2)
{
final int outcode0 = this.cOutCode;
+
if (clipRect != null) {
+ final int outcode1 = Helpers.outcode(x1, y1, clipRect);
final int outcode2 = Helpers.outcode(x2, y2, clipRect);
- this.cOutCode = outcode2;
-
- if ((outcode0 & outcode2) != 0) {
- final int outcode1 = Helpers.outcode(x1, y1, clipRect);
- // basic rejection criteria
- if ((outcode0 & outcode1 & outcode2) != 0) {
- moveTo(x2, y2, outcode0);
+ // Should clip
+ final int orCode = (outcode0 | outcode1 | outcode2);
+ if (orCode != 0) {
+ final int sideCode = outcode0 & outcode1 & outcode2;
+
+ // basic rejection criteria:
+ if (sideCode == 0) {
+ // ovelap clip:
+ if (subdivide) {
+ // avoid reentrance
+ subdivide = false;
+ // subdivide curve => call lineTo() with subdivided curves:
+ boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+ x2, y2, orCode, this);
+ // reentrance is done:
+ subdivide = true;
+ if (ret) {
+ return;
+ }
+ }
+ // already subdivided so render it
+ } else {
+ this.cOutCode = outcode2;
+ _moveTo(x2, y2, outcode0);
opened = true;
return;
}
}
- }
- final float[] mid = middle;
-
- mid[0] = cx0; mid[1] = cy0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
+ this.cOutCode = outcode2;
+ }
+ _quadTo(x1, y1, x2, y2, outcode0);
+ }
+ private void _quadTo(final float x1, final float y1,
+ final float x2, final float y2,
+ final int outcode0)
+ {
// need these so we can update the state at the end of this method
- final float xf = x2, yf = y2;
- float dxs = mid[2] - mid[0];
- float dys = mid[3] - mid[1];
- float dxf = mid[4] - mid[2];
- float dyf = mid[5] - mid[3];
- if ((dxs == 0.0f && dys == 0.0f) || (dxf == 0.0f && dyf == 0.0f)) {
- dxs = dxf = mid[4] - mid[0];
- dys = dyf = mid[5] - mid[1];
+ float dxs = x1 - cx0;
+ float dys = y1 - cy0;
+ float dxf = x2 - x1;
+ float dyf = y2 - y1;
+
+ if (((dxs == 0.0f) && (dys == 0.0f)) || ((dxf == 0.0f) && (dyf == 0.0f))) {
+ dxs = dxf = x2 - cx0;
+ dys = dyf = y2 - cy0;
}
- if (dxs == 0.0f && dys == 0.0f) {
+ if ((dxs == 0.0f) && (dys == 0.0f)) {
// this happens if the "curve" is just a point
// fix outcode0 for lineTo() call:
if (clipRect != null) {
this.cOutCode = outcode0;
}
- lineTo(mid[0], mid[1]);
+ lineTo(cx0, cy0);
return;
}
// if these vectors are too small, normalize them, to avoid future
// precision problems.
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
- float len = (float) Math.sqrt(dxs*dxs + dys*dys);
+ final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
dxs /= len;
dys /= len;
}
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
- float len = (float) Math.sqrt(dxf*dxf + dyf*dyf);
+ final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
dxf /= len;
dyf /= len;
}
-
computeOffset(dxs, dys, lineWidth2, offset0);
drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
- int nSplits = findSubdivPoints(curve, mid, subdivTs, 6, lineWidth2);
+ int nSplits = 0;
+ final float[] mid;
+ final float[] l = lp;
- float prevt = 0.0f;
- for (int i = 0, off = 0; i < nSplits; i++, off += 4) {
- final float t = subdivTs[i];
- Helpers.subdivideQuadAt((t - prevt) / (1.0f - prevt),
- mid, off, mid, off, mid, off + 4);
- prevt = t;
- }
+ if (monotonize) {
+ // monotonize quad:
+ final CurveBasicMonotonizer monotonizer
+ = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
- final float[] l = lp;
+ nSplits = monotonizer.nbSplits;
+ mid = monotonizer.middle;
+ } else {
+ // use left instead:
+ mid = l;
+ mid[0] = cx0; mid[1] = cy0;
+ mid[2] = x1; mid[3] = y1;
+ mid[4] = x2; mid[5] = y2;
+ }
final float[] r = rp;
int kind = 0;
@@ -1282,8 +1325,8 @@
}
this.prev = DRAWING_OP_TO;
- this.cx0 = xf;
- this.cy0 = yf;
+ this.cx0 = x2;
+ this.cy0 = y2;
this.cdx = dxf;
this.cdy = dyf;
this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;