DDasher
class takes a series of linear commands
- * (moveTo
, lineTo
, close
and
- * end
) and breaks them into smaller segments according to a
- * dash pattern array and a starting dash phase.
- *
- * Issues: in J2Se, a zero length dash segment as drawn as a very
- * short dash, whereas Pisces does not draw anything. The PostScript
- * semantics are unclear.
- *
- */
-final class DDasher implements DPathConsumer2D, MarlinConst {
-
- /* huge circle with radius ~ 2E9 only needs 12 subdivision levels */
- static final int REC_LIMIT = 16;
- static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial
- static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT);
-
- static final double EPS = 1e-6d;
-
- // More than 24 bits of mantissa means we can no longer accurately
- // measure the number of times cycled through the dash array so we
- // punt and override the phase to just be 0 past that point.
- static final double MAX_CYCLES = 16000000.0d;
-
- private DPathConsumer2D out;
- private double[] dash;
- private int dashLen;
- private double startPhase;
- private boolean startDashOn;
- private int startIdx;
-
- private boolean starting;
- private boolean needsMoveTo;
-
- private int idx;
- private boolean dashOn;
- private double phase;
-
- // The starting point of the path
- private double sx0, sy0;
- // the current point
- private double cx0, cy0;
-
- // temporary storage for the current curve
- private final double[] curCurvepts;
-
- // per-thread renderer context
- final DRendererContext rdrCtx;
-
- // flag to recycle dash array copy
- boolean recycleDashes;
-
- // We don't emit the first dash right away. If we did, caps would be
- // drawn on it, but we need joins to be drawn if there's a closePath()
- // So, we store the path elements that make up the first dash in the
- // buffer below.
- private double[] firstSegmentsBuffer; // dynamic array
- private int firstSegidx;
-
- // dashes ref (dirty)
- final ArrayCacheDouble.Reference dashes_ref;
- // firstSegmentsBuffer ref (dirty)
- final ArrayCacheDouble.Reference firstSegmentsBuffer_ref;
-
- // Bounds of the drawing region, at pixel precision.
- private double[] clipRect;
-
- // the outcode of the current point
- private int cOutCode = 0;
-
- private boolean subdivide = DO_CLIP_SUBDIVIDER;
-
- private final LengthIterator li = new LengthIterator();
-
- private final CurveClipSplitter curveSplitter;
-
- private double cycleLen;
- private boolean outside;
- private double totalSkipLen;
-
- /**
- * Constructs a
- * The specified {@code src} {@link Shape} is widened according
- * to the specified attribute parameters as per the
- * {@link BasicStroke} specification.
- *
- * @param src the source path to be widened
- * @param width the width of the widened path as per {@code BasicStroke}
- * @param caps the end cap decorations as per {@code BasicStroke}
- * @param join the segment join decorations as per {@code BasicStroke}
- * @param miterlimit the miter limit as per {@code BasicStroke}
- * @param dashes the dash length array as per {@code BasicStroke}
- * @param dashphase the initial dash phase as per {@code BasicStroke}
- * @return the widened path stored in a new {@code Shape} object
- * @since 1.7
- */
- @Override
- public Shape createStrokedShape(Shape src,
- float width,
- int caps,
- int join,
- float miterlimit,
- float[] dashes,
- float dashphase)
- {
- final RendererContext rdrCtx = getRendererContext();
- try {
- // initialize a large copyable Path2D to avoid a lot of array growing:
- final Path2D.Float p2d = rdrCtx.getPath2D();
-
- strokeTo(rdrCtx,
- src,
- null,
- width,
- NormMode.OFF,
- caps,
- join,
- miterlimit,
- dashes,
- dashphase,
- rdrCtx.transformerPC2D.wrapPath2D(p2d)
- );
-
- // Use Path2D copy constructor (trim)
- return new Path2D.Float(p2d);
-
- } finally {
- // recycle the RendererContext instance
- returnRendererContext(rdrCtx);
- }
- }
-
- /**
- * Sends the geometry for a widened path as specified by the parameters
- * to the specified consumer.
- *
- * The specified {@code src} {@link Shape} is widened according
- * to the parameters specified by the {@link BasicStroke} object.
- * Adjustments are made to the path as appropriate for the
- * {@link java.awt.RenderingHints#VALUE_STROKE_NORMALIZE} hint if the
- * {@code normalize} boolean parameter is true.
- * Adjustments are made to the path as appropriate for the
- * {@link java.awt.RenderingHints#VALUE_ANTIALIAS_ON} hint if the
- * {@code antialias} boolean parameter is true.
- *
- * The geometry of the widened path is forwarded to the indicated
- * {@link PathConsumer2D} object as it is calculated.
- *
- * @param src the source path to be widened
- * @param bs the {@code BasicSroke} object specifying the
- * decorations to be applied to the widened path
- * @param normalize indicates whether stroke normalization should
- * be applied
- * @param antialias indicates whether or not adjustments appropriate
- * to antialiased rendering should be applied
- * @param consumer the {@code PathConsumer2D} instance to forward
- * the widened geometry to
- * @since 1.7
- */
- @Override
- public void strokeTo(Shape src,
- AffineTransform at,
- BasicStroke bs,
- boolean thin,
- boolean normalize,
- boolean antialias,
- final PathConsumer2D consumer)
- {
- final NormMode norm = (normalize) ?
- ((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
- : NormMode.OFF;
-
- final RendererContext rdrCtx = getRendererContext();
- try {
- strokeTo(rdrCtx, src, at, bs, thin, norm, antialias, consumer);
- } finally {
- // recycle the RendererContext instance
- returnRendererContext(rdrCtx);
- }
- }
-
- void strokeTo(final RendererContext rdrCtx,
- Shape src,
- AffineTransform at,
- BasicStroke bs,
- boolean thin,
- NormMode normalize,
- boolean antialias,
- PathConsumer2D pc2d)
- {
- float lw;
- if (thin) {
- if (antialias) {
- lw = userSpaceLineWidth(at, MIN_PEN_SIZE);
- } else {
- lw = userSpaceLineWidth(at, 1.0f);
- }
- } else {
- lw = bs.getLineWidth();
- }
- strokeTo(rdrCtx,
- src,
- at,
- lw,
- normalize,
- bs.getEndCap(),
- bs.getLineJoin(),
- bs.getMiterLimit(),
- bs.getDashArray(),
- bs.getDashPhase(),
- pc2d);
- }
-
- private float userSpaceLineWidth(AffineTransform at, float lw) {
-
- float widthScale;
-
- if (at == null) {
- widthScale = 1.0f;
- } else if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM |
- AffineTransform.TYPE_GENERAL_SCALE)) != 0) {
- // Determinant may be negative (flip), use its absolute value:
- widthScale = (float)Math.sqrt(Math.abs(at.getDeterminant()));
- } else {
- // First calculate the "maximum scale" of this transform.
- double A = at.getScaleX(); // m00
- double C = at.getShearX(); // m01
- double B = at.getShearY(); // m10
- double D = at.getScaleY(); // m11
-
- /*
- * Given a 2 x 2 affine matrix [ A B ] such that
- * [ C D ]
- * v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to
- * find the maximum magnitude (norm) of the vector v'
- * with the constraint (x^2 + y^2 = 1).
- * The equation to maximize is
- * |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)
- * or |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).
- * Since sqrt is monotonic we can maximize |v'|^2
- * instead and plug in the substitution y = sqrt(1 - x^2).
- * Trigonometric equalities can then be used to get
- * rid of most of the sqrt terms.
- */
-
- double EA = A*A + B*B; // x^2 coefficient
- double EB = 2.0d * (A*C + B*D); // xy coefficient
- double EC = C*C + D*D; // y^2 coefficient
-
- /*
- * There is a lot of calculus omitted here.
- *
- * Conceptually, in the interests of understanding the
- * terms that the calculus produced we can consider
- * that EA and EC end up providing the lengths along
- * the major axes and the hypot term ends up being an
- * adjustment for the additional length along the off-axis
- * angle of rotated or sheared ellipses as well as an
- * adjustment for the fact that the equation below
- * averages the two major axis lengths. (Notice that
- * the hypot term contains a part which resolves to the
- * difference of these two axis lengths in the absence
- * of rotation.)
- *
- * In the calculus, the ratio of the EB and (EA-EC) terms
- * ends up being the tangent of 2*theta where theta is
- * the angle that the long axis of the ellipse makes
- * with the horizontal axis. Thus, this equation is
- * calculating the length of the hypotenuse of a triangle
- * along that axis.
- */
-
- double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
- // sqrt omitted, compare to squared limits below.
- double widthsquared = ((EA + EC + hypot) / 2.0d);
-
- widthScale = (float)Math.sqrt(widthsquared);
- }
-
- return (lw / widthScale);
- }
-
- void strokeTo(final RendererContext rdrCtx,
- Shape src,
- AffineTransform at,
- float width,
- NormMode norm,
- int caps,
- int join,
- float miterlimit,
- float[] dashes,
- float dashphase,
- PathConsumer2D 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
- // computations done in the path iterator, but the alternative is to
- // work with transformed paths and compute untransformed coordinates
- // as needed. This would be faster but I do not think the complexity
- // of working with both untransformed and transformed coordinates in
- // the same code is worth it.
- // However, if a path's width is constant after a transformation,
- // we can skip all this untransforming.
-
- // As pathTo() will check transformed coordinates for invalid values
- // (NaN / Infinity) to ignore such points, it is necessary to apply the
- // transformation before the path processing.
- AffineTransform strokerat = null;
-
- int dashLen = -1;
- boolean recycleDashes = false;
-
- if (at != null && !at.isIdentity()) {
- final double a = at.getScaleX();
- final double b = at.getShearX();
- final double c = at.getShearY();
- final double d = at.getScaleY();
- final double det = a * d - c * b;
-
- if (Math.abs(det) <= (2.0f * Float.MIN_VALUE)) {
- // this rendering engine takes one dimensional curves and turns
- // them into 2D shapes by giving them width.
- // However, if everything is to be passed through a singular
- // transformation, these 2D shapes will be squashed down to 1D
- // again so, nothing can be drawn.
-
- // Every path needs an initial moveTo and a pathDone. If these
- // are not there this causes a SIGSEGV in libawt.so (at the time
- // of writing of this comment (September 16, 2010)). Actually,
- // I am not sure if the moveTo is necessary to avoid the SIGSEGV
- // but the pathDone is definitely needed.
- pc2d.moveTo(0.0f, 0.0f);
- pc2d.pathDone();
- return;
- }
-
- // If the transform is a constant multiple of an orthogonal transformation
- // then every length is just multiplied by a constant, so we just
- // need to transform input paths to stroker and tell stroker
- // the scaled width. This condition is satisfied if
- // 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);
-
- if (dashes != null) {
- recycleDashes = true;
- dashLen = dashes.length;
- dashes = rdrCtx.dasher.copyDashArray(dashes);
- for (int i = 0; i < dashLen; i++) {
- dashes[i] *= scale;
- }
- dashphase *= scale;
- }
- width *= scale;
-
- // by now strokerat == null. Input paths to
- // stroker (and maybe dasher) will have the full transform at
- // applied to them and nothing will happen to the output paths.
- } else {
- strokerat = at;
-
- // by now strokerat == at. Input paths to
- // stroker (and maybe dasher) will have the full transform at
- // applied to them, then they will be normalized, and then
- // the inverse of *only the non translation part of at* will
- // be applied to the normalized paths. This won't cause problems
- // in stroker, because, suppose at = T*A, where T is just the
- // translation part of at, and A is the rest. T*A has already
- // been applied to Stroker/Dasher's input. Then Ainv will be
- // applied. Ainv*T*A is not equal to T, but it is a translation,
- // which means that none of stroker's assumptions about its
- // input will be violated. After all this, A will be applied
- // to stroker's output.
- }
- } else {
- // either at is null or it's the identity. In either case
- // we don't transform the path.
- at = null;
- }
-
- final TransformingPathConsumer2D 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);
- }
-
- // deltaTransformConsumer may adjust the clip rectangle:
- pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
-
- // stroker will adjust the clip rectangle (width / miter limit):
- pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit,
- (dashes == null));
-
- // Curve Monotizer:
- rdrCtx.monotonizer.init(width);
-
- if (dashes != null) {
- if (!recycleDashes) {
- dashLen = dashes.length;
- }
- if (DO_TRACE_PATH) {
- pc2d = transformerPC2D.traceDasher(pc2d);
- }
- pc2d = rdrCtx.dasher.init(pc2d, dashes, dashLen, dashphase,
- recycleDashes);
-
- if (DISABLE_2ND_STROKER_CLIPPING) {
- // disable stoker clipping
- rdrCtx.stroker.disableClipping();
- }
-
- } 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));
-
- pathTo(rdrCtx, pi, pc2d);
-
- /*
- * Pipeline seems to be:
- * shape.getPathIterator(at)
- * -> (NormalizingPathIterator)
- * -> (inverseDeltaTransformConsumer)
- * -> (Dasher)
- * -> Stroker
- * -> (deltaTransformConsumer)
- *
- * -> (CollinearSimplifier) to remove redundant segments
- *
- * -> pc2d = Renderer (bounding box)
- */
- }
-
- private static boolean nearZero(final double num) {
- return Math.abs(num) < 2.0d * Math.ulp(num);
- }
-
- abstract static class NormalizingPathIterator implements PathIterator {
-
- private PathIterator src;
-
- // the adjustment applied to the current position.
- private float curx_adjust, cury_adjust;
- // the adjustment applied to the last moveTo position.
- private float movx_adjust, movy_adjust;
-
- private final float[] tmp;
-
- NormalizingPathIterator(final float[] tmp) {
- this.tmp = tmp;
- }
-
- final NormalizingPathIterator init(final PathIterator src) {
- this.src = src;
- return this; // fluent API
- }
-
- /**
- * Disposes this path iterator:
- * clean up before reusing this instance
- */
- final void dispose() {
- // free source PathIterator:
- this.src = null;
- }
-
- @Override
- public final int currentSegment(final float[] coords) {
- int lastCoord;
- final int type = src.currentSegment(coords);
-
- switch(type) {
- case PathIterator.SEG_MOVETO:
- case PathIterator.SEG_LINETO:
- lastCoord = 0;
- break;
- case PathIterator.SEG_QUADTO:
- lastCoord = 2;
- break;
- case PathIterator.SEG_CUBICTO:
- lastCoord = 4;
- break;
- case PathIterator.SEG_CLOSE:
- // we don't want to deal with this case later. We just exit now
- curx_adjust = movx_adjust;
- cury_adjust = movy_adjust;
- return type;
- default:
- throw new InternalError("Unrecognized curve type");
- }
-
- // normalize endpoint
- float coord, x_adjust, y_adjust;
-
- coord = coords[lastCoord];
- x_adjust = normCoord(coord); // new coord
- coords[lastCoord] = x_adjust;
- x_adjust -= coord;
-
- coord = coords[lastCoord + 1];
- y_adjust = normCoord(coord); // new coord
- coords[lastCoord + 1] = y_adjust;
- y_adjust -= coord;
-
- // now that the end points are done, normalize the control points
- switch(type) {
- case PathIterator.SEG_MOVETO:
- movx_adjust = x_adjust;
- movy_adjust = y_adjust;
- break;
- case PathIterator.SEG_LINETO:
- break;
- case PathIterator.SEG_QUADTO:
- coords[0] += (curx_adjust + x_adjust) / 2.0f;
- coords[1] += (cury_adjust + y_adjust) / 2.0f;
- break;
- case PathIterator.SEG_CUBICTO:
- coords[0] += curx_adjust;
- coords[1] += cury_adjust;
- coords[2] += x_adjust;
- coords[3] += y_adjust;
- break;
- case PathIterator.SEG_CLOSE:
- // handled earlier
- default:
- }
- curx_adjust = x_adjust;
- cury_adjust = y_adjust;
- return type;
- }
-
- abstract float normCoord(final float coord);
-
- @Override
- public final int currentSegment(final double[] coords) {
- final float[] _tmp = tmp; // dirty
- int type = this.currentSegment(_tmp);
- for (int i = 0; i < 6; i++) {
- coords[i] = _tmp[i];
- }
- return type;
- }
-
- @Override
- public final int getWindingRule() {
- return src.getWindingRule();
- }
-
- @Override
- public final boolean isDone() {
- if (src.isDone()) {
- // Dispose this instance:
- dispose();
- return true;
- }
- return false;
- }
-
- @Override
- public final void next() {
- src.next();
- }
-
- static final class NearestPixelCenter
- extends NormalizingPathIterator
- {
- NearestPixelCenter(final float[] tmp) {
- super(tmp);
- }
-
- @Override
- float normCoord(final float coord) {
- // round to nearest pixel center
- return FloatMath.floor_f(coord) + 0.5f;
- }
- }
-
- static final class NearestPixelQuarter
- extends NormalizingPathIterator
- {
- NearestPixelQuarter(final float[] tmp) {
- super(tmp);
- }
-
- @Override
- float normCoord(final float coord) {
- // round to nearest (0.25, 0.25) pixel quarter
- return FloatMath.floor_f(coord + 0.25f) + 0.25f;
- }
- }
- }
-
- private static void pathTo(final RendererContext rdrCtx, final PathIterator pi,
- PathConsumer2D pc2d)
- {
- if (USE_PATH_SIMPLIFIER) {
- // Use path simplifier at the first step
- // to remove useless points
- pc2d = rdrCtx.pathSimplifier.init(pc2d);
- }
-
- // mark context as DIRTY:
- rdrCtx.dirty = true;
-
- pathToLoop(rdrCtx.float6, pi, pc2d);
-
- // mark context as CLEAN:
- rdrCtx.dirty = false;
- }
-
- private static void pathToLoop(final float[] coords, final PathIterator pi,
- final PathConsumer2D pc2d)
- {
- // ported from DuctusRenderingEngine.feedConsumer() but simplified:
- // - removed skip flag = !subpathStarted
- // - removed pathClosed (ie subpathStarted not set to false)
- boolean subpathStarted = false;
-
- for (; !pi.isDone(); pi.next()) {
- switch (pi.currentSegment(coords)) {
- case PathIterator.SEG_MOVETO:
- /* Checking SEG_MOVETO coordinates if they are out of the
- * [LOWER_BND, UPPER_BND] range. This check also handles NaN
- * and Infinity values. Skipping next path segment in case of
- * invalid data.
- */
- if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
- coords[1] < UPPER_BND && coords[1] > LOWER_BND)
- {
- pc2d.moveTo(coords[0], coords[1]);
- subpathStarted = true;
- }
- break;
- case PathIterator.SEG_LINETO:
- /* Checking SEG_LINETO coordinates if they are out of the
- * [LOWER_BND, UPPER_BND] range. This check also handles NaN
- * and Infinity values. Ignoring current path segment in case
- * of invalid data. If segment is skipped its endpoint
- * (if valid) is used to begin new subpath.
- */
- if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
- coords[1] < UPPER_BND && coords[1] > LOWER_BND)
- {
- if (subpathStarted) {
- pc2d.lineTo(coords[0], coords[1]);
- } else {
- pc2d.moveTo(coords[0], coords[1]);
- subpathStarted = true;
- }
- }
- break;
- case PathIterator.SEG_QUADTO:
- // Quadratic curves take two points
- /* Checking SEG_QUADTO coordinates if they are out of the
- * [LOWER_BND, UPPER_BND] range. This check also handles NaN
- * and Infinity values. Ignoring current path segment in case
- * of invalid endpoints's data. Equivalent to the SEG_LINETO
- * if endpoint coordinates are valid but there are invalid data
- * among other coordinates
- */
- if (coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
- coords[3] < UPPER_BND && coords[3] > LOWER_BND)
- {
- if (subpathStarted) {
- if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
- coords[1] < UPPER_BND && coords[1] > LOWER_BND)
- {
- pc2d.quadTo(coords[0], coords[1],
- coords[2], coords[3]);
- } else {
- pc2d.lineTo(coords[2], coords[3]);
- }
- } else {
- pc2d.moveTo(coords[2], coords[3]);
- subpathStarted = true;
- }
- }
- break;
- case PathIterator.SEG_CUBICTO:
- // Cubic curves take three points
- /* Checking SEG_CUBICTO coordinates if they are out of the
- * [LOWER_BND, UPPER_BND] range. This check also handles NaN
- * and Infinity values. Ignoring current path segment in case
- * of invalid endpoints's data. Equivalent to the SEG_LINETO
- * if endpoint coordinates are valid but there are invalid data
- * among other coordinates
- */
- if (coords[4] < UPPER_BND && coords[4] > LOWER_BND &&
- coords[5] < UPPER_BND && coords[5] > LOWER_BND)
- {
- if (subpathStarted) {
- if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
- coords[1] < UPPER_BND && coords[1] > LOWER_BND &&
- coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
- coords[3] < UPPER_BND && coords[3] > LOWER_BND)
- {
- pc2d.curveTo(coords[0], coords[1],
- coords[2], coords[3],
- coords[4], coords[5]);
- } else {
- pc2d.lineTo(coords[4], coords[5]);
- }
- } else {
- pc2d.moveTo(coords[4], coords[5]);
- subpathStarted = true;
- }
- }
- break;
- case PathIterator.SEG_CLOSE:
- if (subpathStarted) {
- pc2d.closePath();
- // do not set subpathStarted to false
- // in case of missing moveTo() after close()
- }
- break;
- default:
- }
- }
- pc2d.pathDone();
- }
-
- /**
- * Construct an antialiased tile generator for the given shape with
- * the given rendering attributes and store the bounds of the tile
- * iteration in the bbox parameter.
- * The {@code at} parameter specifies a transform that should affect
- * both the shape and the {@code BasicStroke} attributes.
- * The {@code clip} parameter specifies the current clip in effect
- * in device coordinates and can be used to prune the data for the
- * operation, but the renderer is not required to perform any
- * clipping.
- * If the {@code BasicStroke} parameter is null then the shape
- * should be filled as is, otherwise the attributes of the
- * {@code BasicStroke} should be used to specify a draw operation.
- * The {@code thin} parameter indicates whether or not the
- * transformed {@code BasicStroke} represents coordinates smaller
- * than the minimum resolution of the antialiasing rasterizer as
- * specified by the {@code getMinimumAAPenWidth()} method.
- *
- * Upon returning, this method will fill the {@code bbox} parameter
- * with 4 values indicating the bounds of the iteration of the
- * tile generator.
- * The iteration order of the tiles will be as specified by the
- * pseudo-code:
- * DDasher
.
- * @param rdrCtx per-thread renderer context
- */
- DDasher(final DRendererContext rdrCtx) {
- this.rdrCtx = rdrCtx;
-
- dashes_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
-
- firstSegmentsBuffer_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
- firstSegmentsBuffer = firstSegmentsBuffer_ref.initial;
-
- // we need curCurvepts to be able to contain 2 curves because when
- // dashing curves, we need to subdivide it
- curCurvepts = new double[8 * 2];
-
- this.curveSplitter = rdrCtx.curveClipSplitter;
- }
-
- /**
- * Initialize the DDasher
.
- *
- * @param out an output DPathConsumer2D
.
- * @param dash an array of double
s containing the dash pattern
- * @param dashLen length of the given dash array
- * @param phase a double
containing the dash phase
- * @param recycleDashes true to indicate to recycle the given dash array
- * @return this instance
- */
- DDasher init(final DPathConsumer2D out, final double[] dash, final int dashLen,
- double phase, final boolean recycleDashes)
- {
- if (this.out != out) {
- this.out = out;
- }
-
- // Normalize so 0 <= phase < dash[0]
- int sidx = 0;
- dashOn = true;
-
- // note: BasicStroke constructor checks dash elements and sum > 0
- double sum = 0.0d;
- for (int i = 0; i < dashLen; i++) {
- sum += dash[i];
- }
- this.cycleLen = sum;
-
- double cycles = phase / sum;
- if (phase < 0.0d) {
- if (-cycles >= MAX_CYCLES) {
- phase = 0.0d;
- } else {
- int fullcycles = FloatMath.floor_int(-cycles);
- if ((fullcycles & dashLen & 1) != 0) {
- dashOn = !dashOn;
- }
- phase += fullcycles * sum;
- while (phase < 0.0d) {
- if (--sidx < 0) {
- sidx = dashLen - 1;
- }
- phase += dash[sidx];
- dashOn = !dashOn;
- }
- }
- } else if (phase > 0.0d) {
- if (cycles >= MAX_CYCLES) {
- phase = 0.0d;
- } else {
- int fullcycles = FloatMath.floor_int(cycles);
- if ((fullcycles & dashLen & 1) != 0) {
- dashOn = !dashOn;
- }
- phase -= fullcycles * sum;
- double d;
- while (phase >= (d = dash[sidx])) {
- phase -= d;
- sidx = (sidx + 1) % dashLen;
- dashOn = !dashOn;
- }
- }
- }
-
- this.dash = dash;
- this.dashLen = dashLen;
- this.phase = phase;
- this.startPhase = phase;
- this.startDashOn = dashOn;
- this.startIdx = sidx;
- this.starting = true;
- this.needsMoveTo = false;
- this.firstSegidx = 0;
-
- this.recycleDashes = recycleDashes;
-
- if (rdrCtx.doClip) {
- this.clipRect = rdrCtx.clipRect;
- } else {
- this.clipRect = null;
- this.cOutCode = 0;
- }
- return this; // fluent API
- }
-
- /**
- * Disposes this dasher:
- * clean up before reusing this instance
- */
- void dispose() {
- if (DO_CLEAN_DIRTY) {
- // Force zero-fill dirty arrays:
- Arrays.fill(curCurvepts, 0.0d);
- }
- // Return arrays:
- if (recycleDashes) {
- if (dashes_ref.doCleanRef(dash)) {
- dash = dashes_ref.putArray(dash);
- }
- }
- if (firstSegmentsBuffer_ref.doCleanRef(firstSegmentsBuffer)) {
- firstSegmentsBuffer = firstSegmentsBuffer_ref.putArray(firstSegmentsBuffer);
- }
- }
-
- double[] copyDashArray(final float[] dashes) {
- final int len = dashes.length;
- final double[] newDashes;
- if (len <= MarlinConst.INITIAL_ARRAY) {
- newDashes = dashes_ref.initial;
- } else {
- if (DO_STATS) {
- rdrCtx.stats.stat_array_dasher_dasher.add(len);
- }
- newDashes = dashes_ref.getArray(len);
- }
- for (int i = 0; i < len; i++) { newDashes[i] = dashes[i]; }
- return newDashes;
- }
-
- @Override
- public void moveTo(final double x0, final double y0) {
- if (firstSegidx != 0) {
- out.moveTo(sx0, sy0);
- emitFirstSegments();
- }
- this.needsMoveTo = true;
- this.idx = startIdx;
- this.dashOn = this.startDashOn;
- this.phase = this.startPhase;
- this.cx0 = x0;
- this.cy0 = y0;
-
- // update starting point:
- this.sx0 = x0;
- this.sy0 = y0;
- this.starting = true;
-
- if (clipRect != null) {
- final int outcode = DHelpers.outcode(x0, y0, clipRect);
- this.cOutCode = outcode;
- this.outside = false;
- this.totalSkipLen = 0.0d;
- }
- }
-
- private void emitSeg(double[] buf, int off, int type) {
- switch (type) {
- case 4:
- out.lineTo(buf[off], buf[off + 1]);
- return;
- case 8:
- out.curveTo(buf[off ], buf[off + 1],
- buf[off + 2], buf[off + 3],
- buf[off + 4], buf[off + 5]);
- return;
- case 6:
- out.quadTo(buf[off ], buf[off + 1],
- buf[off + 2], buf[off + 3]);
- return;
- default:
- }
- }
-
- private void emitFirstSegments() {
- final double[] fSegBuf = firstSegmentsBuffer;
-
- for (int i = 0, len = firstSegidx; i < len; ) {
- int type = (int)fSegBuf[i];
- emitSeg(fSegBuf, i + 1, type);
- i += (type - 1);
- }
- firstSegidx = 0;
- }
-
- // precondition: pts must be in relative coordinates (relative to x0,y0)
- private void goTo(final double[] pts, final int off, final int type,
- final boolean on)
- {
- final int index = off + type;
- final double x = pts[index - 4];
- final double y = pts[index - 3];
-
- if (on) {
- if (starting) {
- goTo_starting(pts, off, type);
- } else {
- if (needsMoveTo) {
- needsMoveTo = false;
- out.moveTo(cx0, cy0);
- }
- emitSeg(pts, off, type);
- }
- } else {
- if (starting) {
- // low probability test (hotspot)
- starting = false;
- }
- needsMoveTo = true;
- }
- this.cx0 = x;
- this.cy0 = y;
- }
-
- private void goTo_starting(final double[] pts, final int off, final int type) {
- int len = type - 1; // - 2 + 1
- int segIdx = firstSegidx;
- double[] buf = firstSegmentsBuffer;
-
- if (segIdx + len > buf.length) {
- if (DO_STATS) {
- rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
- .add(segIdx + len);
- }
- firstSegmentsBuffer = buf
- = firstSegmentsBuffer_ref.widenArray(buf, segIdx,
- segIdx + len);
- }
- buf[segIdx++] = type;
- len--;
- // small arraycopy (2, 4 or 6) but with offset:
- System.arraycopy(pts, off, buf, segIdx, len);
- firstSegidx = segIdx + len;
- }
-
- @Override
- public void lineTo(final double x1, final double y1) {
- final int outcode0 = this.cOutCode;
-
- if (clipRect != null) {
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
-
- // Should clip
- final int orCode = (outcode0 | outcode1);
-
- if (orCode != 0) {
- final int sideCode = outcode0 & outcode1;
-
- // basic rejection criteria:
- if (sideCode == 0) {
- // overlap 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;
- skipLineTo(x1, y1);
- return;
- }
- }
-
- this.cOutCode = outcode1;
-
- if (this.outside) {
- this.outside = false;
- // Adjust current index, phase & dash:
- skipLen();
- }
- }
- _lineTo(x1, y1);
- }
-
- private void _lineTo(final double x1, final double y1) {
- final double dx = x1 - cx0;
- final double dy = y1 - cy0;
-
- double len = dx * dx + dy * dy;
- if (len == 0.0d) {
- return;
- }
- len = Math.sqrt(len);
-
- // The scaling factors needed to get the dx and dy of the
- // transformed dash segments.
- final double cx = dx / len;
- final double cy = dy / len;
-
- final double[] _curCurvepts = curCurvepts;
- final double[] _dash = dash;
- final int _dashLen = this.dashLen;
-
- int _idx = idx;
- boolean _dashOn = dashOn;
- double _phase = phase;
-
- double leftInThisDashSegment, rem;
-
- while (true) {
- leftInThisDashSegment = _dash[_idx] - _phase;
- rem = len - leftInThisDashSegment;
-
- if (rem <= EPS) {
- _curCurvepts[0] = x1;
- _curCurvepts[1] = y1;
-
- goTo(_curCurvepts, 0, 4, _dashOn);
-
- // Advance phase within current dash segment
- _phase += len;
-
- // compare values using epsilon:
- if (Math.abs(rem) <= EPS) {
- _phase = 0.0d;
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- }
- break;
- }
-
- _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
- _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
-
- goTo(_curCurvepts, 0, 4, _dashOn);
-
- len = rem;
- // Advance to next dash segment
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- _phase = 0.0d;
- }
- // Save local state:
- idx = _idx;
- dashOn = _dashOn;
- phase = _phase;
- }
-
- private void skipLineTo(final double x1, final double y1) {
- final double dx = x1 - cx0;
- final double dy = y1 - cy0;
-
- double len = dx * dx + dy * dy;
- if (len != 0.0d) {
- len = Math.sqrt(len);
- }
-
- // Accumulate skipped length:
- this.outside = true;
- this.totalSkipLen += len;
-
- // Fix initial move:
- this.needsMoveTo = true;
- this.starting = false;
-
- this.cx0 = x1;
- this.cy0 = y1;
- }
-
- public void skipLen() {
- double len = this.totalSkipLen;
- this.totalSkipLen = 0.0d;
-
- final double[] _dash = dash;
- final int _dashLen = this.dashLen;
-
- int _idx = idx;
- boolean _dashOn = dashOn;
- double _phase = phase;
-
- // -2 to ensure having 2 iterations of the post-loop
- // to compensate the remaining phase
- final long fullcycles = (long)Math.floor(len / cycleLen) - 2L;
-
- if (fullcycles > 0L) {
- len -= cycleLen * fullcycles;
-
- final long iterations = fullcycles * _dashLen;
- _idx = (int) (iterations + _idx) % _dashLen;
- _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
- }
-
- double leftInThisDashSegment, rem;
-
- while (true) {
- leftInThisDashSegment = _dash[_idx] - _phase;
- rem = len - leftInThisDashSegment;
-
- if (rem <= EPS) {
- // Advance phase within current dash segment
- _phase += len;
-
- // compare values using epsilon:
- if (Math.abs(rem) <= EPS) {
- _phase = 0.0d;
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- }
- break;
- }
-
- len = rem;
- // Advance to next dash segment
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- _phase = 0.0d;
- }
- // Save local state:
- idx = _idx;
- dashOn = _dashOn;
- phase = _phase;
- }
-
- // preconditions: curCurvepts must be an array of length at least 2 * type,
- // that contains the curve we want to dash in the first type elements
- private void somethingTo(final int type) {
- final double[] _curCurvepts = curCurvepts;
- if (DHelpers.isPointCurve(_curCurvepts, type)) {
- return;
- }
- final LengthIterator _li = li;
- final double[] _dash = dash;
- final int _dashLen = this.dashLen;
-
- _li.initializeIterationOnCurve(_curCurvepts, type);
-
- int _idx = idx;
- boolean _dashOn = dashOn;
- double _phase = phase;
-
- // initially the current curve is at curCurvepts[0...type]
- int curCurveoff = 0;
- double prevT = 0.0d;
- double t;
- double leftInThisDashSegment = _dash[_idx] - _phase;
-
- while ((t = _li.next(leftInThisDashSegment)) < 1.0d) {
- if (t != 0.0d) {
- DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
- _curCurvepts, curCurveoff,
- _curCurvepts, 0, type);
- prevT = t;
- goTo(_curCurvepts, 2, type, _dashOn);
- curCurveoff = type;
- }
- // Advance to next dash segment
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- _phase = 0.0d;
- leftInThisDashSegment = _dash[_idx];
- }
-
- goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
-
- _phase += _li.lastSegLen();
-
- // compare values using epsilon:
- if (_phase + EPS >= _dash[_idx]) {
- _phase = 0.0d;
- _idx = (_idx + 1) % _dashLen;
- _dashOn = !_dashOn;
- }
- // Save local state:
- idx = _idx;
- dashOn = _dashOn;
- phase = _phase;
-
- // reset LengthIterator:
- _li.reset();
- }
-
- private void skipSomethingTo(final int type) {
- final double[] _curCurvepts = curCurvepts;
- if (DHelpers.isPointCurve(_curCurvepts, type)) {
- return;
- }
- final LengthIterator _li = li;
-
- _li.initializeIterationOnCurve(_curCurvepts, type);
-
- // In contrary to somethingTo(),
- // just estimate properly the curve length:
- final double len = _li.totalLength();
-
- // Accumulate skipped length:
- this.outside = true;
- this.totalSkipLen += len;
-
- // Fix initial move:
- this.needsMoveTo = true;
- this.starting = false;
- }
-
- // Objects of this class are used to iterate through curves. They return
- // t values where the left side of the curve has a specified length.
- // It does this by subdividing the input curve until a certain error
- // condition has been met. A recursive subdivision procedure would
- // return as many as 1<src
array at indices srcoff
- * through (srcoff
+ 7) and stores the
- * resulting two subdivided curves into the two result arrays at the
- * corresponding indices.
- * Either or both of the left
and right
- * arrays may be null
or a reference to the same array
- * as the src
array.
- * Note that the last point in the first subdivided curve is the
- * same as the first point in the second subdivided curve. Thus,
- * it is possible to pass the same array for left
- * and right
and to use offsets, such as rightoff
- * equals (leftoff
+ 6), in order
- * to avoid allocating extra storage for this common point.
- * @param src the array holding the coordinates for the source curve
- * @param left the array for storing the coordinates for the first
- * half of the subdivided curve
- * @param right the array for storing the coordinates for the second
- * half of the subdivided curve
- * @since 1.7
- */
- static void subdivideCubic(final double[] src,
- final double[] left,
- final double[] right)
- {
- double x1 = src[0];
- double y1 = src[1];
- double cx1 = src[2];
- double cy1 = src[3];
- double cx2 = src[4];
- double cy2 = src[5];
- double x2 = src[6];
- double y2 = src[7];
-
- left[0] = x1;
- left[1] = y1;
-
- right[6] = x2;
- right[7] = y2;
-
- x1 = (x1 + cx1) / 2.0d;
- y1 = (y1 + cy1) / 2.0d;
- x2 = (x2 + cx2) / 2.0d;
- y2 = (y2 + cy2) / 2.0d;
-
- double cx = (cx1 + cx2) / 2.0d;
- double cy = (cy1 + cy2) / 2.0d;
-
- cx1 = (x1 + cx) / 2.0d;
- cy1 = (y1 + cy) / 2.0d;
- cx2 = (x2 + cx) / 2.0d;
- cy2 = (y2 + cy) / 2.0d;
- cx = (cx1 + cx2) / 2.0d;
- cy = (cy1 + cy2) / 2.0d;
-
- left[2] = x1;
- left[3] = y1;
- left[4] = cx1;
- left[5] = cy1;
- left[6] = cx;
- left[7] = cy;
-
- right[0] = cx;
- right[1] = cy;
- right[2] = cx2;
- right[3] = cy2;
- right[4] = x2;
- right[5] = y2;
- }
-
- static void subdivideCubicAt(final double t,
- final double[] src, final int offS,
- final double[] pts, final int offL, final int offR)
- {
- double x1 = src[offS ];
- double y1 = src[offS + 1];
- double cx1 = src[offS + 2];
- double cy1 = src[offS + 3];
- double cx2 = src[offS + 4];
- double cy2 = src[offS + 5];
- double x2 = src[offS + 6];
- double y2 = src[offS + 7];
-
- pts[offL ] = x1;
- pts[offL + 1] = y1;
-
- pts[offR + 6] = x2;
- pts[offR + 7] = y2;
-
- x1 = x1 + t * (cx1 - x1);
- y1 = y1 + t * (cy1 - y1);
- x2 = cx2 + t * (x2 - cx2);
- y2 = cy2 + t * (y2 - cy2);
-
- double cx = cx1 + t * (cx2 - cx1);
- double cy = cy1 + t * (cy2 - cy1);
-
- cx1 = x1 + t * (cx - x1);
- cy1 = y1 + t * (cy - y1);
- cx2 = cx + t * (x2 - cx);
- cy2 = cy + t * (y2 - cy);
- cx = cx1 + t * (cx2 - cx1);
- cy = cy1 + t * (cy2 - cy1);
-
- pts[offL + 2] = x1;
- pts[offL + 3] = y1;
- pts[offL + 4] = cx1;
- pts[offL + 5] = cy1;
- pts[offL + 6] = cx;
- pts[offL + 7] = cy;
-
- pts[offR ] = cx;
- pts[offR + 1] = cy;
- pts[offR + 2] = cx2;
- pts[offR + 3] = cy2;
- pts[offR + 4] = x2;
- pts[offR + 5] = y2;
- }
-
- static void subdivideQuad(final double[] src,
- final double[] left,
- final double[] right)
- {
- double x1 = src[0];
- double y1 = src[1];
- double cx = src[2];
- double cy = src[3];
- double x2 = src[4];
- double y2 = src[5];
-
- left[0] = x1;
- left[1] = y1;
-
- right[4] = x2;
- right[5] = y2;
-
- x1 = (x1 + cx) / 2.0d;
- y1 = (y1 + cy) / 2.0d;
- x2 = (x2 + cx) / 2.0d;
- y2 = (y2 + cy) / 2.0d;
- cx = (x1 + x2) / 2.0d;
- cy = (y1 + y2) / 2.0d;
-
- left[2] = x1;
- left[3] = y1;
- left[4] = cx;
- left[5] = cy;
-
- right[0] = cx;
- right[1] = cy;
- right[2] = x2;
- right[3] = y2;
- }
-
- static void subdivideQuadAt(final double t,
- final double[] src, final int offS,
- final double[] pts, final int offL, final int offR)
- {
- double x1 = src[offS ];
- double y1 = src[offS + 1];
- double cx = src[offS + 2];
- double cy = src[offS + 3];
- double x2 = src[offS + 4];
- double y2 = src[offS + 5];
-
- pts[offL ] = x1;
- pts[offL + 1] = y1;
-
- pts[offR + 4] = x2;
- pts[offR + 5] = y2;
-
- x1 = x1 + t * (cx - x1);
- y1 = y1 + t * (cy - y1);
- x2 = cx + t * (x2 - cx);
- y2 = cy + t * (y2 - cy);
- cx = x1 + t * (x2 - x1);
- cy = y1 + t * (y2 - y1);
-
- pts[offL + 2] = x1;
- pts[offL + 3] = y1;
- pts[offL + 4] = cx;
- pts[offL + 5] = cy;
-
- pts[offR ] = cx;
- pts[offR + 1] = cy;
- pts[offR + 2] = x2;
- pts[offR + 3] = y2;
- }
-
- static void subdivideLineAt(final double t,
- final double[] src, final int offS,
- final double[] pts, final int offL, final int offR)
- {
- double x1 = src[offS ];
- double y1 = src[offS + 1];
- double x2 = src[offS + 2];
- double y2 = src[offS + 3];
-
- pts[offL ] = x1;
- pts[offL + 1] = y1;
-
- pts[offR + 2] = x2;
- pts[offR + 3] = y2;
-
- x1 = x1 + t * (x2 - x1);
- y1 = y1 + t * (y2 - y1);
-
- pts[offL + 2] = x1;
- pts[offL + 3] = y1;
-
- pts[offR ] = x1;
- pts[offR + 1] = y1;
- }
-
- static void subdivideAt(final double t,
- final double[] src, final int offS,
- final double[] pts, final int offL, final int type)
- {
- // if instead of switch (perf + most probable cases first)
- if (type == 8) {
- subdivideCubicAt(t, src, offS, pts, offL, offL + type);
- } else if (type == 4) {
- subdivideLineAt(t, src, offS, pts, offL, offL + type);
- } else {
- subdivideQuadAt(t, src, offS, pts, offL, offL + type);
- }
- }
-
- // From sun.java2d.loops.GeneralRenderer:
-
- static int outcode(final double x, final double y,
- final double[] clipRect)
- {
- int code;
- if (y < clipRect[0]) {
- code = OUTCODE_TOP;
- } else if (y >= clipRect[1]) {
- code = OUTCODE_BOTTOM;
- } else {
- code = 0;
- }
- if (x < clipRect[2]) {
- code |= OUTCODE_LEFT;
- } else if (x >= clipRect[3]) {
- code |= OUTCODE_RIGHT;
- }
- return code;
- }
-
- // a stack of polynomial curves where each curve shares endpoints with
- // adjacent ones.
- static final class PolyStack {
- private static final byte TYPE_LINETO = (byte) 0;
- private static final byte TYPE_QUADTO = (byte) 1;
- private static final byte TYPE_CUBICTO = (byte) 2;
-
- // curves capacity = edges count (8192) = edges x 2 (coords)
- private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1;
-
- // types capacity = edges count (4096)
- private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT;
-
- double[] curves;
- int end;
- byte[] curveTypes;
- int numCurves;
-
- // curves ref (dirty)
- final ArrayCacheDouble.Reference curves_ref;
- // curveTypes ref (dirty)
- final ArrayCacheByte.Reference curveTypes_ref;
-
- // used marks (stats only)
- int curveTypesUseMark;
- int curvesUseMark;
-
- private final StatLong stat_polystack_types;
- private final StatLong stat_polystack_curves;
- private final Histogram hist_polystack_curves;
- private final StatLong stat_array_polystack_curves;
- private final StatLong stat_array_polystack_curveTypes;
-
- PolyStack(final DRendererContext rdrCtx) {
- this(rdrCtx, null, null, null, null, null);
- }
-
- PolyStack(final DRendererContext rdrCtx,
- final StatLong stat_polystack_types,
- final StatLong stat_polystack_curves,
- final Histogram hist_polystack_curves,
- final StatLong stat_array_polystack_curves,
- final StatLong stat_array_polystack_curveTypes)
- {
- curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K
- curves = curves_ref.initial;
-
- curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K
- curveTypes = curveTypes_ref.initial;
- numCurves = 0;
- end = 0;
-
- if (DO_STATS) {
- curveTypesUseMark = 0;
- curvesUseMark = 0;
- }
- this.stat_polystack_types = stat_polystack_types;
- this.stat_polystack_curves = stat_polystack_curves;
- this.hist_polystack_curves = hist_polystack_curves;
- this.stat_array_polystack_curves = stat_array_polystack_curves;
- this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes;
- }
-
- /**
- * Disposes this PolyStack:
- * clean up before reusing this instance
- */
- void dispose() {
- end = 0;
- numCurves = 0;
-
- if (DO_STATS) {
- stat_polystack_types.add(curveTypesUseMark);
- stat_polystack_curves.add(curvesUseMark);
- hist_polystack_curves.add(curvesUseMark);
-
- // reset marks
- curveTypesUseMark = 0;
- curvesUseMark = 0;
- }
-
- // Return arrays:
- // curves and curveTypes are kept dirty
- if (curves_ref.doCleanRef(curves)) {
- curves = curves_ref.putArray(curves);
- }
- if (curveTypes_ref.doCleanRef(curveTypes)) {
- curveTypes = curveTypes_ref.putArray(curveTypes);
- }
- }
-
- private void ensureSpace(final int n) {
- // use substraction to avoid integer overflow:
- if (curves.length - end < n) {
- if (DO_STATS) {
- stat_array_polystack_curves.add(end + n);
- }
- curves = curves_ref.widenArray(curves, end, end + n);
- }
- if (curveTypes.length <= numCurves) {
- if (DO_STATS) {
- stat_array_polystack_curveTypes.add(numCurves + 1);
- }
- curveTypes = curveTypes_ref.widenArray(curveTypes,
- numCurves,
- numCurves + 1);
- }
- }
-
- void pushCubic(double x0, double y0,
- double x1, double y1,
- double x2, double y2)
- {
- ensureSpace(6);
- curveTypes[numCurves++] = TYPE_CUBICTO;
- // we reverse the coordinate order to make popping easier
- final double[] _curves = curves;
- int e = end;
- _curves[e++] = x2; _curves[e++] = y2;
- _curves[e++] = x1; _curves[e++] = y1;
- _curves[e++] = x0; _curves[e++] = y0;
- end = e;
- }
-
- void pushQuad(double x0, double y0,
- double x1, double y1)
- {
- ensureSpace(4);
- curveTypes[numCurves++] = TYPE_QUADTO;
- final double[] _curves = curves;
- int e = end;
- _curves[e++] = x1; _curves[e++] = y1;
- _curves[e++] = x0; _curves[e++] = y0;
- end = e;
- }
-
- void pushLine(double x, double y) {
- ensureSpace(2);
- curveTypes[numCurves++] = TYPE_LINETO;
- curves[end++] = x; curves[end++] = y;
- }
-
- void pullAll(final DPathConsumer2D io) {
- final int nc = numCurves;
- if (nc == 0) {
- return;
- }
- if (DO_STATS) {
- // update used marks:
- if (numCurves > curveTypesUseMark) {
- curveTypesUseMark = numCurves;
- }
- if (end > curvesUseMark) {
- curvesUseMark = end;
- }
- }
- final byte[] _curveTypes = curveTypes;
- final double[] _curves = curves;
- int e = 0;
-
- for (int i = 0; i < nc; i++) {
- switch(_curveTypes[i]) {
- case TYPE_LINETO:
- io.lineTo(_curves[e], _curves[e+1]);
- e += 2;
- continue;
- case TYPE_CUBICTO:
- io.curveTo(_curves[e], _curves[e+1],
- _curves[e+2], _curves[e+3],
- _curves[e+4], _curves[e+5]);
- e += 6;
- continue;
- case TYPE_QUADTO:
- io.quadTo(_curves[e], _curves[e+1],
- _curves[e+2], _curves[e+3]);
- e += 4;
- continue;
- default:
- }
- }
- numCurves = 0;
- end = 0;
- }
-
- void popAll(final DPathConsumer2D io) {
- int nc = numCurves;
- if (nc == 0) {
- return;
- }
- if (DO_STATS) {
- // update used marks:
- if (numCurves > curveTypesUseMark) {
- curveTypesUseMark = numCurves;
- }
- if (end > curvesUseMark) {
- curvesUseMark = end;
- }
- }
- final byte[] _curveTypes = curveTypes;
- final double[] _curves = curves;
- int e = end;
-
- while (nc != 0) {
- switch(_curveTypes[--nc]) {
- case TYPE_LINETO:
- e -= 2;
- io.lineTo(_curves[e], _curves[e+1]);
- continue;
- case TYPE_CUBICTO:
- e -= 6;
- io.curveTo(_curves[e], _curves[e+1],
- _curves[e+2], _curves[e+3],
- _curves[e+4], _curves[e+5]);
- continue;
- case TYPE_QUADTO:
- e -= 4;
- io.quadTo(_curves[e], _curves[e+1],
- _curves[e+2], _curves[e+3]);
- continue;
- default:
- }
- }
- numCurves = 0;
- end = 0;
- }
-
- @Override
- public String toString() {
- String ret = "";
- int nc = numCurves;
- int last = end;
- int len;
- while (nc != 0) {
- switch(curveTypes[--nc]) {
- case TYPE_LINETO:
- len = 2;
- ret += "line: ";
- break;
- case TYPE_QUADTO:
- len = 4;
- ret += "quad: ";
- break;
- case TYPE_CUBICTO:
- len = 6;
- ret += "cubic: ";
- break;
- default:
- len = 0;
- }
- last -= len;
- ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len))
- + "\n";
- }
- return ret;
- }
- }
-
- // a stack of integer indices
- static final class IndexStack {
-
- // integer capacity = edges count / 4 ~ 1024
- private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2;
-
- private int end;
- private int[] indices;
-
- // indices ref (dirty)
- private final ArrayCacheInt.Reference indices_ref;
-
- // used marks (stats only)
- private int indicesUseMark;
-
- private final StatLong stat_idxstack_indices;
- private final Histogram hist_idxstack_indices;
- private final StatLong stat_array_idxstack_indices;
-
- IndexStack(final DRendererContext rdrCtx) {
- this(rdrCtx, null, null, null);
- }
-
- IndexStack(final DRendererContext rdrCtx,
- final StatLong stat_idxstack_indices,
- final Histogram hist_idxstack_indices,
- final StatLong stat_array_idxstack_indices)
- {
- indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K
- indices = indices_ref.initial;
- end = 0;
-
- if (DO_STATS) {
- indicesUseMark = 0;
- }
- this.stat_idxstack_indices = stat_idxstack_indices;
- this.hist_idxstack_indices = hist_idxstack_indices;
- this.stat_array_idxstack_indices = stat_array_idxstack_indices;
- }
-
- /**
- * Disposes this PolyStack:
- * clean up before reusing this instance
- */
- void dispose() {
- end = 0;
-
- if (DO_STATS) {
- stat_idxstack_indices.add(indicesUseMark);
- hist_idxstack_indices.add(indicesUseMark);
-
- // reset marks
- indicesUseMark = 0;
- }
-
- // Return arrays:
- // indices is kept dirty
- if (indices_ref.doCleanRef(indices)) {
- indices = indices_ref.putArray(indices);
- }
- }
-
- boolean isEmpty() {
- return (end == 0);
- }
-
- void reset() {
- end = 0;
- }
-
- void push(final int v) {
- // remove redundant values (reverse order):
- int[] _values = indices;
- final int nc = end;
- if (nc != 0) {
- if (_values[nc - 1] == v) {
- // remove both duplicated values:
- end--;
- return;
- }
- }
- if (_values.length <= nc) {
- if (DO_STATS) {
- stat_array_idxstack_indices.add(nc + 1);
- }
- indices = _values = indices_ref.widenArray(_values, nc, nc + 1);
- }
- _values[end++] = v;
-
- if (DO_STATS) {
- // update used marks:
- if (end > indicesUseMark) {
- indicesUseMark = end;
- }
- }
- }
-
- void pullAll(final double[] points, final DPathConsumer2D io,
- final boolean moveFirst)
- {
- final int nc = end;
- if (nc == 0) {
- return;
- }
- final int[] _values = indices;
-
- int i = 0;
-
- if (moveFirst) {
- int j = _values[i] << 1;
- io.moveTo(points[j], points[j + 1]);
- i++;
- }
-
- for (int j; i < nc; i++) {
- j = _values[i] << 1;
- io.lineTo(points[j], points[j + 1]);
- }
- end = 0;
- }
- }
-}
diff --git a/src/main/java/sun/java2d/marlin/DMarlinRenderingEngine.java b/src/main/java/sun/java2d/marlin/DMarlinRenderingEngine.java
index 51dd530..72ffecf 100644
--- a/src/main/java/sun/java2d/marlin/DMarlinRenderingEngine.java
+++ b/src/main/java/sun/java2d/marlin/DMarlinRenderingEngine.java
@@ -65,7 +65,7 @@ public final class DMarlinRenderingEngine extends RenderingEngine
private enum NormMode {
ON_WITH_AA {
@Override
- PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+ PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
final PathIterator src)
{
// NormalizingPathIterator NearestPixelCenter:
@@ -74,7 +74,7 @@ PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
},
ON_NO_AA{
@Override
- PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+ PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
final PathIterator src)
{
// NearestPixel NormalizingPathIterator:
@@ -83,7 +83,7 @@ PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
},
OFF{
@Override
- PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+ PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
final PathIterator src)
{
// return original path iterator if normalization is disabled:
@@ -91,7 +91,7 @@ PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
}
};
- abstract PathIterator getNormalizingPathIterator(DRendererContext rdrCtx,
+ abstract PathIterator getNormalizingPathIterator(RendererContext rdrCtx,
PathIterator src);
}
@@ -129,7 +129,7 @@ public Shape createStrokedShape(Shape src,
float[] dashes,
float dashphase)
{
- final DRendererContext rdrCtx = getRendererContext();
+ final RendererContext rdrCtx = getRendererContext();
try {
// initialize a large copyable Path2D to avoid a lot of array growing:
final Path2D.Double p2d = rdrCtx.getPath2D();
@@ -151,7 +151,7 @@ public Shape createStrokedShape(Shape src,
return new Path2D.Double(p2d);
} finally {
- // recycle the DRendererContext instance
+ // recycle the RendererContext instance
returnRendererContext(rdrCtx);
}
}
@@ -249,7 +249,7 @@ public void strokeTo(Shape src,
((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
: NormMode.OFF;
- final DRendererContext rdrCtx = getRendererContext();
+ final RendererContext rdrCtx = getRendererContext();
try {
if ((clip != null) &&
(DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime()))) {
@@ -284,12 +284,12 @@ public void strokeTo(Shape src,
strokeTo(rdrCtx, src, _at, bs, thin, norm, antialias,
rdrCtx.p2dAdapter.init(consumer));
} finally {
- // recycle the DRendererContext instance
+ // recycle the RendererContext instance
returnRendererContext(rdrCtx);
}
}
- void strokeTo(final DRendererContext rdrCtx,
+ void strokeTo(final RendererContext rdrCtx,
Shape src,
AffineTransform at,
BasicStroke bs,
@@ -390,7 +390,7 @@ private double userSpaceLineWidth(AffineTransform at, double lw) {
return (lw / widthScale);
}
- void strokeTo(final DRendererContext rdrCtx,
+ void strokeTo(final RendererContext rdrCtx,
Shape src,
AffineTransform at,
double width,
@@ -494,7 +494,7 @@ void strokeTo(final DRendererContext rdrCtx,
at = null;
}
- final DTransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
+ final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
if (DO_TRACE_PATH) {
// trace Stroker:
@@ -724,7 +724,7 @@ static final class NearestPixelQuarter
}
}
- private static void pathTo(final DRendererContext rdrCtx, final PathIterator pi,
+ private static void pathTo(final RendererContext rdrCtx, final PathIterator pi,
DPathConsumer2D pc2d)
{
if (USE_PATH_SIMPLIFIER) {
@@ -910,17 +910,17 @@ public AATileGenerator getAATileGenerator(Shape s,
int[] bbox)
{
MarlinTileGenerator ptg = null;
- DRenderer r = null;
+ Renderer r = null;
- final DRendererContext rdrCtx = getRendererContext();
+ final RendererContext rdrCtx = getRendererContext();
try {
if (DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime())) {
// Define the initial clip bounds:
final double[] clipRect = rdrCtx.clipRect;
// Adjust the clipping rectangle with the renderer offsets
- final double rdrOffX = DRenderer.RDR_OFFSET_X;
- final double rdrOffY = DRenderer.RDR_OFFSET_Y;
+ final double rdrOffX = Renderer.RDR_OFFSET_X;
+ final double rdrOffY = Renderer.RDR_OFFSET_Y;
// add a small rounding error:
final double margin = 1e-3d;
@@ -1033,9 +1033,9 @@ public AATileGenerator getAATileGenerator(double x, double y,
}
MarlinTileGenerator ptg = null;
- DRenderer r = null;
+ Renderer r = null;
- final DRendererContext rdrCtx = getRendererContext();
+ final RendererContext rdrCtx = getRendererContext();
try {
r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
@@ -1104,15 +1104,15 @@ public float getMinimumAAPenSize() {
}
}
- // --- DRendererContext handling ---
- // use ThreadLocal or ConcurrentLinkedQueue to get one DRendererContext
+ // --- RendererContext handling ---
+ // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext
private static final boolean USE_THREAD_LOCAL;
// reference type stored in either TL or CLQ
static final int REF_TYPE;
- // Per-thread DRendererContext
- private static final ReentrantContextProviderDStroker
.
- * @param rdrCtx per-thread renderer context
- */
- DStroker(final DRendererContext rdrCtx) {
- this.rdrCtx = rdrCtx;
-
- this.reverse = (rdrCtx.stats != null) ?
- new PolyStack(rdrCtx,
- rdrCtx.stats.stat_str_polystack_types,
- rdrCtx.stats.stat_str_polystack_curves,
- rdrCtx.stats.hist_str_polystack_curves,
- rdrCtx.stats.stat_array_str_polystack_curves,
- rdrCtx.stats.stat_array_str_polystack_types)
- : new PolyStack(rdrCtx);
-
- this.curve = rdrCtx.curve;
- this.curveSplitter = rdrCtx.curveClipSplitter;
- }
-
- /**
- * Inits the DStroker
.
- *
- * @param pc2d an output DPathConsumer2D
.
- * @param lineWidth the desired line width in pixels
- * @param capStyle the desired end cap style, one of
- * CAP_BUTT
, CAP_ROUND
or
- * CAP_SQUARE
.
- * @param joinStyle the desired line join style, one of
- * JOIN_MITER
, JOIN_ROUND
or
- * JOIN_BEVEL
.
- * @param miterLimit the desired miter limit
- * @param subdivideCurves true to indicate to subdivide curves, false if dasher does
- * @return this instance
- */
- DStroker init(final DPathConsumer2D pc2d,
- final double lineWidth,
- final int capStyle,
- final int joinStyle,
- final double miterLimit,
- final boolean subdivideCurves)
- {
- if (this.out != pc2d) {
- this.out = pc2d;
- }
-
- this.lineWidth2 = lineWidth / 2.0d;
- this.invHalfLineWidth2Sq = 1.0d / (2.0d * lineWidth2 * lineWidth2);
- this.monotonize = subdivideCurves;
-
- this.capStyle = capStyle;
- this.joinStyle = joinStyle;
-
- final double limit = miterLimit * lineWidth2;
- this.miterLimitSq = limit * limit;
-
- this.prev = CLOSE;
-
- rdrCtx.stroking = 1;
-
- if (rdrCtx.doClip) {
- // Adjust the clipping rectangle with the stroker margin (miter limit, width)
- double margin = lineWidth2;
-
- if (capStyle == CAP_SQUARE) {
- margin *= SQRT_2;
- }
- if ((joinStyle == JOIN_MITER) && (margin < limit)) {
- margin = limit;
- }
-
- // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
- // adjust clip rectangle (ymin, ymax, xmin, xmax):
- final double[] _clipRect = rdrCtx.clipRect;
- _clipRect[0] -= margin;
- _clipRect[1] += margin;
- _clipRect[2] -= margin;
- _clipRect[3] += margin;
- this.clipRect = _clipRect;
-
- if (MarlinConst.DO_LOG_CLIP) {
- MarlinUtils.logInfo("clipRect (stroker): "
- + Arrays.toString(rdrCtx.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;
- this.sOutCode = 0;
- }
- return this; // fluent API
- }
-
- void disableClipping() {
- this.clipRect = null;
- this.cOutCode = 0;
- this.sOutCode = 0;
- }
-
- /**
- * Disposes this stroker:
- * clean up before reusing this instance
- */
- void dispose() {
- reverse.dispose();
-
- opened = false;
- capStart = false;
-
- if (DO_CLEAN_DIRTY) {
- // Force zero-fill dirty arrays:
- Arrays.fill(offset0, 0.0d);
- Arrays.fill(offset1, 0.0d);
- Arrays.fill(offset2, 0.0d);
- Arrays.fill(miter, 0.0d);
- Arrays.fill(lp, 0.0d);
- Arrays.fill(rp, 0.0d);
- }
- }
-
- private static void computeOffset(final double lx, final double ly,
- final double w, final double[] m)
- {
- double len = lx*lx + ly*ly;
- if (len == 0.0d) {
- m[0] = 0.0d;
- m[1] = 0.0d;
- } else {
- len = Math.sqrt(len);
- m[0] = (ly * w) / len;
- m[1] = -(lx * w) / len;
- }
- }
-
- // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
- // clockwise (if dx1,dy1 needs to be rotated clockwise to close
- // the smallest angle between it and dx2,dy2).
- // This is equivalent to detecting whether a point q is on the right side
- // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
- // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
- // clockwise order.
- // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
- private static boolean isCW(final double dx1, final double dy1,
- final double dx2, final double dy2)
- {
- return dx1 * dy2 <= dy1 * dx2;
- }
-
- private void mayDrawRoundJoin(double cx, double cy,
- double omx, double omy,
- double mx, double my,
- boolean rev)
- {
- if ((omx == 0.0d && omy == 0.0d) || (mx == 0.0d && my == 0.0d)) {
- return;
- }
-
- final double domx = omx - mx;
- final double domy = omy - my;
- final double lenSq = domx*domx + domy*domy;
-
- if (lenSq < ROUND_JOIN_THRESHOLD) {
- return;
- }
-
- if (rev) {
- omx = -omx;
- omy = -omy;
- mx = -mx;
- my = -my;
- }
- drawRoundJoin(cx, cy, omx, omy, mx, my, rev);
- }
-
- private void drawRoundJoin(double cx, double cy,
- double omx, double omy,
- double mx, double my,
- boolean rev)
- {
- // The sign of the dot product of mx,my and omx,omy is equal to the
- // the sign of the cosine of ext
- // (ext is the angle between omx,omy and mx,my).
- final double cosext = omx * mx + omy * my;
- // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
- // need 1 curve to approximate the circle section that joins omx,omy
- // and mx,my.
- if (cosext >= 0.0d) {
- drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
- } else {
- // we need to split the arc into 2 arcs spanning the same angle.
- // The point we want will be one of the 2 intersections of the
- // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
- // circle. We could find this by scaling the vector
- // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
- // on the circle), but that can have numerical problems when the angle
- // between omx,omy and mx,my is close to 180 degrees. So we compute a
- // normal of (omx,omy)-(mx,my). This will be the direction of the
- // perpendicular bisector. To get one of the intersections, we just scale
- // this vector that its length is lineWidth2 (this works because the
- // perpendicular bisector goes through the origin). This scaling doesn't
- // have numerical problems because we know that lineWidth2 divided by
- // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
- // we know the angle of the arc is > 90 degrees).
- double nx = my - omy, ny = omx - mx;
- double nlen = Math.sqrt(nx*nx + ny*ny);
- double scale = lineWidth2/nlen;
- double mmx = nx * scale, mmy = ny * scale;
-
- // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
- // computed the wrong intersection so we get the other one.
- // The test above is equivalent to if (rev).
- if (rev) {
- mmx = -mmx;
- mmy = -mmy;
- }
- drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
- drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
- }
- }
-
- // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
- private void drawBezApproxForArc(final double cx, final double cy,
- final double omx, final double omy,
- final double mx, final double my,
- boolean rev)
- {
- final double cosext2 = (omx * mx + omy * my) * invHalfLineWidth2Sq;
-
- // check round off errors producing cos(ext) > 1 and a NaN below
- // cos(ext) == 1 implies colinear segments and an empty join anyway
- if (cosext2 >= 0.5d) {
- // just return to avoid generating a flat curve:
- return;
- }
-
- // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
- // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
- // define the bezier curve we're computing.
- // It is computed using the constraints that P1-P0 and P3-P2 are parallel
- // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
- double cv = ((4.0d / 3.0d) * Math.sqrt(0.5d - cosext2) /
- (1.0d + Math.sqrt(cosext2 + 0.5d)));
- // if clockwise, we need to negate cv.
- if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
- cv = -cv;
- }
- final double x1 = cx + omx;
- final double y1 = cy + omy;
- final double x2 = x1 - cv * omy;
- final double y2 = y1 + cv * omx;
-
- final double x4 = cx + mx;
- final double y4 = cy + my;
- final double x3 = x4 + cv * my;
- final double y3 = y4 - cv * mx;
-
- emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
- }
-
- private void drawRoundCap(double cx, double cy, double mx, double my) {
- final double Cmx = C * mx;
- final double Cmy = C * my;
- emitCurveTo(cx + mx - Cmy, cy + my + Cmx,
- cx - my + Cmx, cy + mx + Cmy,
- cx - my, cy + mx);
- emitCurveTo(cx - my - Cmx, cy + mx - Cmy,
- cx - mx - Cmy, cy - my + Cmx,
- cx - mx, cy - my);
- }
-
- // Return the intersection point of the lines (x0, y0) -> (x1, y1)
- // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
- private static void computeMiter(final double x0, final double y0,
- final double x1, final double y1,
- final double x0p, final double y0p,
- final double x1p, final double y1p,
- final double[] m)
- {
- double x10 = x1 - x0;
- double y10 = y1 - y0;
- double x10p = x1p - x0p;
- double y10p = y1p - y0p;
-
- // if this is 0, the lines are parallel. If they go in the
- // same direction, there is no intersection so m[off] and
- // m[off+1] will contain infinity, so no miter will be drawn.
- // If they go in the same direction that means that the start of the
- // current segment and the end of the previous segment have the same
- // tangent, in which case this method won't even be involved in
- // miter drawing because it won't be called by drawMiter (because
- // (mx == omx && my == omy) will be true, and drawMiter will return
- // immediately).
- double den = x10*y10p - x10p*y10;
- double t = x10p*(y0-y0p) - y10p*(x0-x0p);
- t /= den;
- m[0] = x0 + t*x10;
- m[1] = y0 + t*y10;
- }
-
- // Return the intersection point of the lines (x0, y0) -> (x1, y1)
- // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
- private static void safeComputeMiter(final double x0, final double y0,
- final double x1, final double y1,
- final double x0p, final double y0p,
- final double x1p, final double y1p,
- final double[] m)
- {
- double x10 = x1 - x0;
- double y10 = y1 - y0;
- double x10p = x1p - x0p;
- double y10p = y1p - y0p;
-
- // if this is 0, the lines are parallel. If they go in the
- // same direction, there is no intersection so m[off] and
- // m[off+1] will contain infinity, so no miter will be drawn.
- // If they go in the same direction that means that the start of the
- // current segment and the end of the previous segment have the same
- // tangent, in which case this method won't even be involved in
- // miter drawing because it won't be called by drawMiter (because
- // (mx == omx && my == omy) will be true, and drawMiter will return
- // immediately).
- double den = x10*y10p - x10p*y10;
- if (den == 0.0d) {
- m[2] = (x0 + x0p) / 2.0d;
- m[3] = (y0 + y0p) / 2.0d;
- } else {
- double t = x10p*(y0-y0p) - y10p*(x0-x0p);
- t /= den;
- m[2] = x0 + t*x10;
- m[3] = y0 + t*y10;
- }
- }
-
- private void drawMiter(final double pdx, final double pdy,
- final double x0, final double y0,
- final double dx, final double dy,
- double omx, double omy,
- double mx, double my,
- boolean rev)
- {
- if ((mx == omx && my == omy) ||
- (pdx == 0.0d && pdy == 0.0d) ||
- (dx == 0.0d && dy == 0.0d))
- {
- return;
- }
-
- if (rev) {
- omx = -omx;
- omy = -omy;
- mx = -mx;
- my = -my;
- }
-
- computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
- (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my, miter);
-
- final double miterX = miter[0];
- final double miterY = miter[1];
- double lenSq = (miterX-x0)*(miterX-x0) + (miterY-y0)*(miterY-y0);
-
- // If the lines are parallel, lenSq will be either NaN or +inf
- // (actually, I'm not sure if the latter is possible. The important
- // thing is that -inf is not possible, because lenSq is a square).
- // For both of those values, the comparison below will fail and
- // no miter will be drawn, which is correct.
- if (lenSq < miterLimitSq) {
- emitLineTo(miterX, miterY, rev);
- }
- }
-
- @Override
- public void moveTo(final double x0, final double y0) {
- _moveTo(x0, y0, cOutCode);
- // update starting point:
- this.sx0 = x0;
- this.sy0 = y0;
- this.sdx = 1.0d;
- this.sdy = 0.0d;
- this.opened = false;
- this.capStart = false;
-
- if (clipRect != null) {
- final int outcode = DHelpers.outcode(x0, y0, clipRect);
- this.cOutCode = outcode;
- this.sOutCode = outcode;
- }
- }
-
- private void _moveTo(final double x0, final double y0,
- final int outcode)
- {
- if (prev == MOVE_TO) {
- this.cx0 = x0;
- this.cy0 = y0;
- } else {
- if (prev == DRAWING_OP_TO) {
- finish(outcode);
- }
- this.prev = MOVE_TO;
- this.cx0 = x0;
- this.cy0 = y0;
- this.cdx = 1.0d;
- this.cdy = 0.0d;
- }
- }
-
- @Override
- public void lineTo(final double x1, final double y1) {
- final int outcode0 = this.cOutCode;
-
- if (clipRect != null) {
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
-
- // Should clip
- final int orCode = (outcode0 | outcode1);
- if (orCode != 0) {
- final int sideCode = outcode0 & outcode1;
-
- // basic rejection criteria:
- if (sideCode == 0) {
- // overlap 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;
- }
-
- double dx = x1 - cx0;
- double dy = y1 - cy0;
- if (dx == 0.0d && dy == 0.0d) {
- dx = 1.0d;
- }
- computeOffset(dx, dy, lineWidth2, offset0);
- final double mx = offset0[0];
- final double my = offset0[1];
-
- drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my, outcode0);
-
- emitLineTo(cx0 + mx, cy0 + my);
- emitLineTo( x1 + mx, y1 + my);
-
- emitLineToRev(cx0 - mx, cy0 - my);
- emitLineToRev( x1 - mx, y1 - my);
-
- this.prev = DRAWING_OP_TO;
- this.cx0 = x1;
- this.cy0 = y1;
- this.cdx = dx;
- this.cdy = dy;
- this.cmx = mx;
- this.cmy = my;
- }
-
- @Override
- public void closePath() {
- // distinguish empty path at all vs opened path ?
- if (prev != DRAWING_OP_TO && !opened) {
- if (prev == CLOSE) {
- return;
- }
- emitMoveTo(cx0, cy0 - lineWidth2);
-
- this.sdx = 1.0d;
- this.sdy = 0.0d;
- this.cdx = 1.0d;
- this.cdy = 0.0d;
-
- this.smx = 0.0d;
- this.smy = -lineWidth2;
- this.cmx = 0.0d;
- this.cmy = -lineWidth2;
-
- finish(cOutCode);
- return;
- }
-
- // basic acceptance criteria
- if ((sOutCode & cOutCode) == 0) {
- if (cx0 != sx0 || cy0 != sy0) {
- // may subdivide line:
- lineTo(sx0, sy0);
- }
-
- // ignore starting point outside:
- if (sOutCode == 0) {
- drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy, sOutCode);
-
- emitLineTo(sx0 + smx, sy0 + smy);
-
- if (opened) {
- emitLineTo(sx0 - smx, sy0 - smy);
- } else {
- emitMoveTo(sx0 - smx, sy0 - smy);
- }
- }
- }
- // Ignore caps like finish(false)
- emitReverse();
-
- this.prev = CLOSE;
- this.cx0 = sx0;
- this.cy0 = sy0;
- this.cOutCode = sOutCode;
-
- if (opened) {
- // do not emit close
- opened = false;
- } else {
- emitClose();
- }
- }
-
- private void emitReverse() {
- reverse.popAll(out);
- }
-
- @Override
- public void pathDone() {
- if (prev == DRAWING_OP_TO) {
- finish(cOutCode);
- }
-
- out.pathDone();
-
- // this shouldn't matter since this object won't be used
- // after the call to this method.
- this.prev = CLOSE;
-
- // Dispose this instance:
- dispose();
- }
-
- private void finish(final int outcode) {
- // Problem: impossible to guess if the path will be closed in advance
- // i.e. if caps must be drawn or not ?
- // Solution: use the ClosedPathDetector before Stroker to determine
- // if the path is a closed path or not
- if (rdrCtx.closedPath) {
- emitReverse();
- } else {
- if (outcode == 0) {
- // current point = end's cap:
- if (capStyle == CAP_ROUND) {
- drawRoundCap(cx0, cy0, cmx, cmy);
- } else if (capStyle == CAP_SQUARE) {
- emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
- emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
- }
- }
- emitReverse();
-
- if (!capStart) {
- capStart = true;
-
- if (sOutCode == 0) {
- // starting point = initial cap:
- if (capStyle == CAP_ROUND) {
- drawRoundCap(sx0, sy0, -smx, -smy);
- } else if (capStyle == CAP_SQUARE) {
- emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
- emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
- }
- }
- }
- }
- emitClose();
- }
-
- private void emitMoveTo(final double x0, final double y0) {
- out.moveTo(x0, y0);
- }
-
- private void emitLineTo(final double x1, final double y1) {
- out.lineTo(x1, y1);
- }
-
- private void emitLineToRev(final double x1, final double y1) {
- reverse.pushLine(x1, y1);
- }
-
- private void emitLineTo(final double x1, final double y1,
- final boolean rev)
- {
- if (rev) {
- emitLineToRev(x1, y1);
- } else {
- emitLineTo(x1, y1);
- }
- }
-
- private void emitQuadTo(final double x1, final double y1,
- final double x2, final double y2)
- {
- out.quadTo(x1, y1, x2, y2);
- }
-
- private void emitQuadToRev(final double x0, final double y0,
- final double x1, final double y1)
- {
- reverse.pushQuad(x0, y0, x1, y1);
- }
-
- private void emitCurveTo(final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3)
- {
- out.curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- private void emitCurveToRev(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2)
- {
- reverse.pushCubic(x0, y0, x1, y1, x2, y2);
- }
-
- private void emitCurveTo(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3, final boolean rev)
- {
- if (rev) {
- reverse.pushCubic(x0, y0, x1, y1, x2, y2);
- } else {
- out.curveTo(x1, y1, x2, y2, x3, y3);
- }
- }
-
- private void emitClose() {
- out.closePath();
- }
-
- private void drawJoin(double pdx, double pdy,
- double x0, double y0,
- double dx, double dy,
- double omx, double omy,
- double mx, double my,
- final int outcode)
- {
- if (prev != DRAWING_OP_TO) {
- emitMoveTo(x0 + mx, y0 + my);
- if (!opened) {
- this.sdx = dx;
- this.sdy = dy;
- this.smx = mx;
- this.smy = my;
- }
- } else if (rdrCtx.isFirstSegment) {
- // Precision on isCW is causing instabilities with Dasher !
- final boolean cw = isCW(pdx, pdy, dx, dy);
- if (outcode == 0) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
- } else if (joinStyle == JOIN_ROUND) {
- mayDrawRoundJoin(x0, y0, omx, omy, mx, my, cw);
- }
- }
- emitLineTo(x0, y0, !cw);
- }
- if (!rdrCtx.isFirstSegment) {
- // reset trigger to process further joins (normal operations)
- rdrCtx.isFirstSegment = true;
- }
-
- prev = DRAWING_OP_TO;
- }
-
- private int getLineOffsets(final double x1, final double y1,
- final double x2, final double y2,
- final double[] left, final double[] right)
- {
- computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
- final double mx = offset0[0];
- final double my = offset0[1];
- left[0] = x1 + mx;
- 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;
-
- return 4;
- }
-
- private int computeOffsetCubic(final double[] pts, final int off,
- final double[] leftOff,
- final double[] rightOff)
- {
- // if p1=p2 or p3=p4 it means that the derivative at the endpoint
- // vanishes, which creates problems with computeOffset. Usually
- // this happens when this stroker object is trying to widen
- // a curve with a cusp. What happens is that curveTo splits
- // 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 double x1 = pts[off ]; final double y1 = pts[off + 1];
- final double x2 = pts[off + 2]; final double y2 = pts[off + 3];
- final double x3 = pts[off + 4]; final double y3 = pts[off + 5];
- final double x4 = pts[off + 6]; final double y4 = pts[off + 7];
-
- double dx1 = x2 - x1; double dy1 = y2 - y1;
- double dx4 = x4 - x3; double dy4 = y4 - y3;
-
- // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
- // in which case ignore if p1 == p2
- final boolean p1eqp2 = DHelpers.withinD(dx1, dy1, 6.0d * Math.ulp(y2));
- final boolean p3eqp4 = DHelpers.withinD(dx4, dy4, 6.0d * Math.ulp(y4));
-
- if (p1eqp2 && p3eqp4) {
- return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
- } else if (p1eqp2) {
- dx1 = x3 - x1;
- dy1 = y3 - y1;
- } else if (p3eqp4) {
- dx4 = x4 - x2;
- dy4 = y4 - y2;
- }
-
- // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
- double dotsq = (dx1 * dx4 + dy1 * dy4);
- dotsq *= dotsq;
- final double l1sq = dx1 * dx1 + dy1 * dy1;
- final double l4sq = dx4 * dx4 + dy4 * dy4;
-
- if (DHelpers.within(dotsq, l1sq * l4sq, 4.0d * Math.ulp(dotsq))) {
- return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
- }
-
-// What we're trying to do in this function is to approximate an ideal
-// offset curve (call it I) of the input curve B using a bezier curve Bp.
-// The constraints I use to get the equations are:
-//
-// 1. The computed curve Bp should go through I(0) and I(1). These are
-// x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
-// 4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
-//
-// 2. Bp should have slope equal in absolute value to I at the endpoints. So,
-// (by the way, the operator || in the comments below means "aligned with".
-// It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
-// vectors I'(0) and Bp'(0) are aligned, which is the same as saying
-// that the tangent lines of I and Bp at 0 are parallel. Mathematically
-// this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
-// nonzero constant.)
-// I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
-// I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
-// We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
-// is true for any bezier curve; therefore, we get the equations
-// (1) p2p = c1 * (p2-p1) + p1p
-// (2) p3p = c2 * (p4-p3) + p4p
-// We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
-// of unknowns from 4 to 2 (i.e. just c1 and c2).
-// To eliminate these 2 unknowns we use the following constraint:
-//
-// 3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
-// that I(0.5) is *the only* reason for computing dxm,dym. This gives us
-// (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
-// (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
-// We can substitute (1) and (2) from above into (4) and we get:
-// (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
-// which is equivalent to
-// (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
-//
-// The right side of this is a 2D vector, and we know I(0.5), which gives us
-// Bp(0.5), which gives us the value of the right side.
-// The left side is just a matrix vector multiplication in disguise. It is
-//
-// [x2-x1, x4-x3][c1]
-// [y2-y1, y4-y3][c2]
-// which, is equal to
-// [dx1, dx4][c1]
-// [dy1, dy4][c2]
-// At this point we are left with a simple linear system and we solve it by
-// getting the inverse of the matrix above. Then we use [c1,c2] to compute
-// p2p and p3p.
-
- final double xm = (x1 + x4 + 3.0d * (x2 + x3)) / 8.0d;
- final double ym = (y1 + y4 + 3.0d * (y2 + y3)) / 8.0d;
- // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
- // c*B'(0.5) for some constant c.
- final double dxm = x3 + x4 - (x1 + x2);
- final double dym = y3 + y4 - (y1 + y2);
-
- // this computes the offsets at t=0, 0.5, 1, using the property that
- // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
- // the (dx/dt, dy/dt) vectors at the endpoints.
- computeOffset(dx1, dy1, lineWidth2, offset0);
- computeOffset(dxm, dym, lineWidth2, offset1);
- computeOffset(dx4, dy4, lineWidth2, offset2);
-
- // left side:
- double x1p = x1 + offset0[0]; // start
- double y1p = y1 + offset0[1]; // point
- double xi = xm + offset1[0]; // interpolation
- double yi = ym + offset1[1]; // point
- 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);
- double two_pi_m_p1_m_p4y = 2.0d * yi - (y1p + y4p);
-
- double c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
- double c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
-
- double x2p, y2p, x3p, y3p;
-
- if (c1 * c2 > 0.0) {
-// System.out.println("Buggy solver (left): c1 = " + c1 + " c2 = " + c2);
-
- // use lower quality approximation but good enough
- // to ensure cuve being in its convex hull
- x2p = x2 + offset1[0]; // 2nd
- y2p = y2 + offset1[1]; // point
- x3p = x3 + offset1[0]; // 3nd
- y3p = y3 + offset1[1]; // point
-
- safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x2p, y2p, x2p-dxm, y2p-dym, leftOff);
- x2p = leftOff[2]; y2p = leftOff[3];
-
- safeComputeMiter(x4p, y4p, x4p+dx4, y4p+dy4, x3p, y3p, x3p-dxm, y3p-dym, leftOff);
- x3p = leftOff[2]; y3p = leftOff[3];
- } else {
- x2p = x1p + c1 * dx1; y2p = y1p + c1 * dy1;
- x3p = x4p + c2 * dx4; y3p = y4p + c2 * dy4;
- }
-
- leftOff[0] = x1p; leftOff[1] = y1p;
- leftOff[2] = x2p; leftOff[3] = y2p;
- leftOff[4] = x3p; leftOff[5] = y3p;
- leftOff[6] = x4p; leftOff[7] = y4p;
-
- // Right side:
- x1p = x1 - offset0[0]; // start
- y1p = y1 - offset0[1]; // point
- xi = xm - offset1[0]; // interpolation
- yi = ym - offset1[1]; // point
- 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);
-
- c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
- c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
-
- if (c1 * c2 > 0.0) {
-// System.out.println("Buggy solver (right): c1 = " + c1 + " c2 = " + c2);
-
- // use lower quality approximation but good enough
- // to ensure cuve being in its convex hull
- x2p = x2 - offset1[0]; // 2nd
- y2p = y2 - offset1[1]; // point
- x3p = x3 - offset1[0]; // 3nd
- y3p = y3 - offset1[1]; // point
-
- safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x2p, y2p, x2p-dxm, y2p-dym, rightOff);
- x2p = rightOff[2]; y2p = rightOff[3];
-
- safeComputeMiter(x4p, y4p, x4p+dx4, y4p+dy4, x3p, y3p, x3p-dxm, y3p-dym, rightOff);
- x3p = rightOff[2]; y3p = rightOff[3];
- } else {
- x2p = x1p + c1 * dx1; y2p = y1p + c1 * dy1;
- x3p = x4p + c2 * dx4; y3p = y4p + c2 * dy4;
- }
-
- rightOff[0] = x1p; rightOff[1] = y1p;
- rightOff[2] = x2p; rightOff[3] = y2p;
- rightOff[4] = x3p; rightOff[5] = y3p;
- rightOff[6] = x4p; rightOff[7] = y4p;
-
- return 8;
- }
-
- // 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(final double[] pts, final int off,
- final double[] leftOff,
- final double[] rightOff)
- {
- return computeOffsetQuad(pts, off, leftOff, rightOff, true);
- }
-
- private int computeOffsetQuad(final double[] pts, final int off,
- final double[] leftOff,
- final double[] rightOff,
- final boolean checkCtrlPoints)
- {
- final double x1 = pts[off ]; final double y1 = pts[off + 1];
- final double x2 = pts[off + 2]; final double y2 = pts[off + 3];
- final double x3 = pts[off + 4]; final double y3 = pts[off + 5];
-
- final double dx12 = x2 - x1; final double dy12 = y2 - y1;
- final double dx23 = x3 - x2; final double dy23 = y3 - y2;
-
- if (checkCtrlPoints) {
- // if p1=p2 or p2=p3 it means that the derivative at the endpoint
- // vanishes, which creates problems with computeOffset. Usually
- // this happens when this stroker object is trying to widen
- // a curve with a cusp. What happens is that curveTo splits
- // 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.
-
- // if p1 == p2 or p2 == p3: draw line from p1->p3
- final boolean p1eqp2 = DHelpers.withinD(dx12, dy12, 6.0d * Math.ulp(y2));
- final boolean p2eqp3 = DHelpers.withinD(dx23, dy23, 6.0d * Math.ulp(y3));
-
- if (p1eqp2 || p2eqp3) {
- return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
- }
-
- // if p2-p1 and p3-p2 are parallel, that must mean this curve is a line
- double dotsq = (dx12 * dx23 + dy12 * dy23);
- dotsq *= dotsq;
- final double l1sq = dx12 * dx12 + dy12 * dy12;
- final double l3sq = dx23 * dx23 + dy23 * dy23;
-
- if (DHelpers.within(dotsq, l1sq * l3sq, 4.0d * Math.ulp(dotsq))) {
- return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
- }
- }
-
- // this computes the offsets at t=0, 0.5, 1, using the property that
- // for any bezier curve the vectors p2-p1 and p3-p2 are parallel to
- // the (dx/dt, dy/dt) vectors at the endpoints.
- computeOffset(dx12, dy12, lineWidth2, offset0);
- computeOffset(dx23, dy23, lineWidth2, offset1);
-
- double x1p = x1 + offset0[0]; // start
- double y1p = y1 + offset0[1]; // point
- double x3p = x3 + offset1[0]; // end
- double y3p = y3 + offset1[1]; // point
-
- safeComputeMiter(x1p, y1p, x1p+dx12, y1p+dy12, x3p, y3p, x3p-dx23, y3p-dy23, leftOff);
- leftOff[0] = x1p; leftOff[1] = y1p;
- leftOff[4] = x3p; leftOff[5] = y3p;
-
- x1p = x1 - offset0[0]; // start
- y1p = y1 - offset0[1]; // point
- x3p = x3 - offset1[0]; // end
- y3p = y3 - offset1[1]; // point
-
- safeComputeMiter(x1p, y1p, x1p+dx12, y1p+dy12, x3p, y3p, x3p-dx23, y3p-dy23, rightOff);
- rightOff[0] = x1p; rightOff[1] = y1p;
- rightOff[4] = x3p; rightOff[5] = y3p;
-
- return 6;
- }
-
- @Override
- public void curveTo(final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3)
- {
- final int outcode0 = this.cOutCode;
-
- if (clipRect != null) {
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
- final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
- final int outcode3 = DHelpers.outcode(x3, y3, clipRect);
-
- // 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) {
- // overlap 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;
- }
- }
-
- this.cOutCode = outcode3;
- }
- _curveTo(x1, y1, x2, y2, x3, y3, outcode0);
- }
-
- private void _curveTo(final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3,
- final int outcode0)
- {
- // need these so we can update the state at the end of this method
- double dxs = x1 - cx0;
- double dys = y1 - cy0;
- double dxf = x3 - x2;
- double dyf = y3 - y2;
-
- if ((dxs == 0.0d) && (dys == 0.0d)) {
- dxs = x2 - cx0;
- dys = y2 - cy0;
- if ((dxs == 0.0d) && (dys == 0.0d)) {
- dxs = x3 - cx0;
- dys = y3 - cy0;
- }
- }
- if ((dxf == 0.0d) && (dyf == 0.0d)) {
- dxf = x3 - x1;
- dyf = y3 - y1;
- if ((dxf == 0.0d) && (dyf == 0.0d)) {
- dxf = x3 - cx0;
- dyf = y3 - cy0;
- }
- }
- if ((dxs == 0.0d) && (dys == 0.0d)) {
- // this happens if the "curve" is just a point
- // fix outcode0 for lineTo() call:
- if (clipRect != null) {
- this.cOutCode = outcode0;
- }
- 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) {
- final double len = Math.sqrt(dxs * dxs + dys * dys);
- dxs /= len;
- dys /= len;
- }
- if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
- final double len = 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 = 0;
- final double[] mid;
- final double[] l = lp;
-
- if (monotonize) {
- // monotonize curve:
- final CurveBasicMonotonizer monotonizer
- = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
-
- 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 double[] r = rp;
-
- int kind = 0;
- for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
- kind = computeOffsetCubic(mid, off, l, r);
-
- emitLineTo(l[0], l[1]);
-
- switch(kind) {
- case 8:
- emitCurveTo(l[2], l[3], l[4], l[5], l[6], l[7]);
- emitCurveToRev(r[0], r[1], r[2], r[3], r[4], r[5]);
- break;
- case 4:
- emitLineTo(l[2], l[3]);
- emitLineToRev(r[0], r[1]);
- break;
- default:
- }
- emitLineToRev(r[kind - 2], r[kind - 1]);
- }
-
- this.prev = DRAWING_OP_TO;
- this.cx0 = x3;
- this.cy0 = y3;
- this.cdx = dxf;
- this.cdy = dyf;
- this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
- this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
- }
-
- @Override
- public void quadTo(final double x1, final double y1,
- final double x2, final double y2)
- {
- final int outcode0 = this.cOutCode;
-
- if (clipRect != null) {
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
- final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
-
- // Should clip
- final int orCode = (outcode0 | outcode1 | outcode2);
- if (orCode != 0) {
- final int sideCode = outcode0 & outcode1 & outcode2;
-
- // basic rejection criteria:
- if (sideCode == 0) {
- // overlap 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;
- }
- }
-
- this.cOutCode = outcode2;
- }
- _quadTo(x1, y1, x2, y2, outcode0);
- }
-
- private void _quadTo(final double x1, final double y1,
- final double x2, final double y2,
- final int outcode0)
- {
- // need these so we can update the state at the end of this method
- double dxs = x1 - cx0;
- double dys = y1 - cy0;
- double dxf = x2 - x1;
- double dyf = y2 - y1;
-
- if (((dxs == 0.0d) && (dys == 0.0d)) || ((dxf == 0.0d) && (dyf == 0.0d))) {
- dxs = dxf = x2 - cx0;
- dys = dyf = y2 - cy0;
- }
- if ((dxs == 0.0d) && (dys == 0.0d)) {
- // this happens if the "curve" is just a point
- // fix outcode0 for lineTo() call:
- if (clipRect != null) {
- this.cOutCode = outcode0;
- }
- 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) {
- final double len = Math.sqrt(dxs * dxs + dys * dys);
- dxs /= len;
- dys /= len;
- }
- if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
- final double len = 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 = 0;
- final double[] mid;
- final double[] l = lp;
-
- if (monotonize) {
- // monotonize quad:
- final CurveBasicMonotonizer monotonizer
- = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
-
- 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 double[] r = rp;
-
- int kind = 0;
- for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
- kind = computeOffsetQuad(mid, off, l, r);
-
- emitLineTo(l[0], l[1]);
-
- switch(kind) {
- case 6:
- emitQuadTo(l[2], l[3], l[4], l[5]);
- emitQuadToRev(r[0], r[1], r[2], r[3]);
- break;
- case 4:
- emitLineTo(l[2], l[3]);
- emitLineToRev(r[0], r[1]);
- break;
- default:
- }
- emitLineToRev(r[kind - 2], r[kind - 1]);
- }
-
- this.prev = DRAWING_OP_TO;
- this.cx0 = x2;
- this.cy0 = y2;
- this.cdx = dxf;
- this.cdy = dyf;
- this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
- this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
- }
-
- @Override public long getNativeConsumer() {
- throw new InternalError("Stroker doesn't use a native consumer");
- }
-}
diff --git a/src/main/java/sun/java2d/marlin/DTransformingPathConsumer2D.java b/src/main/java/sun/java2d/marlin/DTransformingPathConsumer2D.java
deleted file mode 100644
index d4d9b7e..0000000
--- a/src/main/java/sun/java2d/marlin/DTransformingPathConsumer2D.java
+++ /dev/null
@@ -1,1389 +0,0 @@
-/*
- * 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
- * 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.marlin;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.util.Arrays;
-import sun.java2d.marlin.DHelpers.IndexStack;
-import sun.java2d.marlin.DHelpers.PolyStack;
-
-final class DTransformingPathConsumer2D {
-
- // smaller uncertainty in double variant
- static final double CLIP_RECT_PADDING = 0.25d;
-
- private final DRendererContext rdrCtx;
-
- // recycled ClosedPathDetector instance from detectClosedPath()
- private final ClosedPathDetector cpDetector;
-
- // recycled PathClipFilter instance from pathClipper()
- private final PathClipFilter pathClipper;
-
- // recycled DPathConsumer2D instance from wrapPath2D()
- private final Path2DWrapper wp_Path2DWrapper = new Path2DWrapper();
-
- // recycled DPathConsumer2D instances from deltaTransformConsumer()
- private final DeltaScaleFilter dt_DeltaScaleFilter = new DeltaScaleFilter();
- private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
-
- // recycled DPathConsumer2D instances from inverseDeltaTransformConsumer()
- private final DeltaScaleFilter iv_DeltaScaleFilter = new DeltaScaleFilter();
- private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
-
- // recycled PathTracer instances from tracer...() methods
- private final PathTracer tracerInput = new PathTracer("[Input]");
- private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
- private final PathTracer tracerFiller = new PathTracer("Filler");
- private final PathTracer tracerStroker = new PathTracer("Stroker");
- private final PathTracer tracerDasher = new PathTracer("Dasher");
-
- DTransformingPathConsumer2D(final DRendererContext rdrCtx) {
- // used by RendererContext
- this.rdrCtx = rdrCtx;
- this.cpDetector = new ClosedPathDetector(rdrCtx);
- this.pathClipper = new PathClipFilter(rdrCtx);
- }
-
- DPathConsumer2D wrapPath2D(Path2D.Double p2d) {
- return wp_Path2DWrapper.init(p2d);
- }
-
- DPathConsumer2D traceInput(DPathConsumer2D out) {
- return tracerInput.init(out);
- }
-
- DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
- return tracerCPDetector.init(out);
- }
-
- DPathConsumer2D traceFiller(DPathConsumer2D out) {
- return tracerFiller.init(out);
- }
-
- DPathConsumer2D traceStroker(DPathConsumer2D out) {
- return tracerStroker.init(out);
- }
-
- DPathConsumer2D traceDasher(DPathConsumer2D out) {
- return tracerDasher.init(out);
- }
-
- DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
- return cpDetector.init(out);
- }
-
- DPathConsumer2D pathClipper(DPathConsumer2D out) {
- return pathClipper.init(out);
- }
-
- DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
- AffineTransform at)
- {
- if (at == null) {
- return out;
- }
- final double mxx = at.getScaleX();
- final double mxy = at.getShearX();
- final double myx = at.getShearY();
- final double myy = at.getScaleY();
-
- if (mxy == 0.0d && myx == 0.0d) {
- if (mxx == 1.0d && myy == 1.0d) {
- return out;
- } else {
- // Scale only
- if (rdrCtx.doClip) {
- // adjust clip rectangle (ymin, ymax, xmin, xmax):
- rdrCtx.clipInvScale = adjustClipScale(rdrCtx.clipRect,
- mxx, myy);
- }
- return dt_DeltaScaleFilter.init(out, mxx, myy);
- }
- } else {
- if (rdrCtx.doClip) {
- // adjust clip rectangle (ymin, ymax, xmin, xmax):
- rdrCtx.clipInvScale = adjustClipInverseDelta(rdrCtx.clipRect,
- mxx, mxy, myx, myy);
- }
- return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
- }
- }
-
- private static double adjustClipScale(final double[] clipRect,
- final double mxx, final double myy)
- {
- // Adjust the clipping rectangle (iv_DeltaScaleFilter):
- final double scaleY = 1.0d / myy;
- clipRect[0] *= scaleY;
- clipRect[1] *= scaleY;
-
- if (clipRect[1] < clipRect[0]) {
- double tmp = clipRect[0];
- clipRect[0] = clipRect[1];
- clipRect[1] = tmp;
- }
-
- final double scaleX = 1.0d / mxx;
- clipRect[2] *= scaleX;
- clipRect[3] *= scaleX;
-
- if (clipRect[3] < clipRect[2]) {
- double tmp = clipRect[2];
- clipRect[2] = clipRect[3];
- clipRect[3] = tmp;
- }
-
- if (MarlinConst.DO_LOG_CLIP) {
- MarlinUtils.logInfo("clipRect (ClipScale): "
- + Arrays.toString(clipRect));
- }
- return 0.5d * (Math.abs(scaleX) + Math.abs(scaleY));
- }
-
- private static double adjustClipInverseDelta(final double[] clipRect,
- final double mxx, final double mxy,
- final double myx, final double myy)
- {
- // Adjust the clipping rectangle (iv_DeltaTransformFilter):
- final double det = mxx * myy - mxy * myx;
- final double imxx = myy / det;
- final double imxy = -mxy / det;
- final double imyx = -myx / det;
- final double imyy = mxx / det;
-
- double xmin, xmax, ymin, ymax;
- double x, y;
- // xmin, ymin:
- x = clipRect[2] * imxx + clipRect[0] * imxy;
- y = clipRect[2] * imyx + clipRect[0] * imyy;
-
- xmin = xmax = x;
- ymin = ymax = y;
-
- // xmax, ymin:
- x = clipRect[3] * imxx + clipRect[0] * imxy;
- y = clipRect[3] * imyx + clipRect[0] * imyy;
-
- if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
- if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
-
- // xmin, ymax:
- x = clipRect[2] * imxx + clipRect[1] * imxy;
- y = clipRect[2] * imyx + clipRect[1] * imyy;
-
- if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
- if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
-
- // xmax, ymax:
- x = clipRect[3] * imxx + clipRect[1] * imxy;
- y = clipRect[3] * imyx + clipRect[1] * imyy;
-
- if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
- if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
-
- clipRect[0] = ymin;
- clipRect[1] = ymax;
- clipRect[2] = xmin;
- clipRect[3] = xmax;
-
- if (MarlinConst.DO_LOG_CLIP) {
- MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
- + Arrays.toString(clipRect));
- }
-
- final double scaleX = Math.sqrt(imxx * imxx + imxy * imxy);
- final double scaleY = Math.sqrt(imyx * imyx + imyy * imyy);
-
- return 0.5d * (scaleX + scaleY);
- }
-
- DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
- AffineTransform at)
- {
- if (at == null) {
- return out;
- }
- double mxx = at.getScaleX();
- double mxy = at.getShearX();
- double myx = at.getShearY();
- double myy = at.getScaleY();
-
- if (mxy == 0.0d && myx == 0.0d) {
- if (mxx == 1.0d && myy == 1.0d) {
- return out;
- } else {
- return iv_DeltaScaleFilter.init(out, 1.0d / mxx, 1.0d / myy);
- }
- } else {
- final double det = mxx * myy - mxy * myx;
- return iv_DeltaTransformFilter.init(out,
- myy / det,
- -mxy / det,
- -myx / det,
- mxx / det);
- }
- }
-
- static final class DeltaScaleFilter implements DPathConsumer2D {
- private DPathConsumer2D out;
- private double sx, sy;
-
- DeltaScaleFilter() {}
-
- DeltaScaleFilter init(DPathConsumer2D out,
- double mxx, double myy)
- {
- if (this.out != out) {
- this.out = out;
- }
- sx = mxx;
- sy = myy;
- return this; // fluent API
- }
-
- @Override
- public void moveTo(double x0, double y0) {
- out.moveTo(x0 * sx, y0 * sy);
- }
-
- @Override
- public void lineTo(double x1, double y1) {
- out.lineTo(x1 * sx, y1 * sy);
- }
-
- @Override
- public void quadTo(double x1, double y1,
- double x2, double y2)
- {
- out.quadTo(x1 * sx, y1 * sy,
- x2 * sx, y2 * sy);
- }
-
- @Override
- public void curveTo(double x1, double y1,
- double x2, double y2,
- double x3, double y3)
- {
- out.curveTo(x1 * sx, y1 * sy,
- x2 * sx, y2 * sy,
- x3 * sx, y3 * sy);
- }
-
- @Override
- public void closePath() {
- out.closePath();
- }
-
- @Override
- public void pathDone() {
- out.pathDone();
- }
-
- @Override
- public long getNativeConsumer() {
- return 0;
- }
- }
-
- static final class DeltaTransformFilter implements DPathConsumer2D {
- private DPathConsumer2D out;
- private double mxx, mxy, myx, myy;
-
- DeltaTransformFilter() {}
-
- DeltaTransformFilter init(DPathConsumer2D out,
- double mxx, double mxy,
- double myx, double myy)
- {
- if (this.out != out) {
- this.out = out;
- }
- this.mxx = mxx;
- this.mxy = mxy;
- this.myx = myx;
- this.myy = myy;
- return this; // fluent API
- }
-
- @Override
- public void moveTo(double x0, double y0) {
- out.moveTo(x0 * mxx + y0 * mxy,
- x0 * myx + y0 * myy);
- }
-
- @Override
- public void lineTo(double x1, double y1) {
- out.lineTo(x1 * mxx + y1 * mxy,
- x1 * myx + y1 * myy);
- }
-
- @Override
- public void quadTo(double x1, double y1,
- double x2, double y2)
- {
- out.quadTo(x1 * mxx + y1 * mxy,
- x1 * myx + y1 * myy,
- x2 * mxx + y2 * mxy,
- x2 * myx + y2 * myy);
- }
-
- @Override
- public void curveTo(double x1, double y1,
- double x2, double y2,
- double x3, double y3)
- {
- out.curveTo(x1 * mxx + y1 * mxy,
- x1 * myx + y1 * myy,
- x2 * mxx + y2 * mxy,
- x2 * myx + y2 * myy,
- x3 * mxx + y3 * mxy,
- x3 * myx + y3 * myy);
- }
-
- @Override
- public void closePath() {
- out.closePath();
- }
-
- @Override
- public void pathDone() {
- out.pathDone();
- }
-
- @Override
- public long getNativeConsumer() {
- return 0;
- }
- }
-
- static final class Path2DWrapper implements DPathConsumer2D {
- private Path2D.Double p2d;
-
- Path2DWrapper() {}
-
- Path2DWrapper init(Path2D.Double p2d) {
- if (this.p2d != p2d) {
- this.p2d = p2d;
- }
- return this;
- }
-
- @Override
- public void moveTo(double x0, double y0) {
- p2d.moveTo(x0, y0);
- }
-
- @Override
- public void lineTo(double x1, double y1) {
- p2d.lineTo(x1, y1);
- }
-
- @Override
- public void closePath() {
- p2d.closePath();
- }
-
- @Override
- public void pathDone() {}
-
- @Override
- public void curveTo(double x1, double y1,
- double x2, double y2,
- double x3, double y3)
- {
- p2d.curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- @Override
- public void quadTo(double x1, double y1, double x2, double y2) {
- p2d.quadTo(x1, y1, x2, y2);
- }
-
- @Override
- public long getNativeConsumer() {
- throw new InternalError("Not using a native peer");
- }
- }
-
- static final class ClosedPathDetector implements DPathConsumer2D {
-
- private final DRendererContext rdrCtx;
- private final PolyStack stack;
-
- private DPathConsumer2D out;
-
- ClosedPathDetector(final DRendererContext rdrCtx) {
- this.rdrCtx = rdrCtx;
- this.stack = (rdrCtx.stats != null) ?
- new PolyStack(rdrCtx,
- rdrCtx.stats.stat_cpd_polystack_types,
- rdrCtx.stats.stat_cpd_polystack_curves,
- rdrCtx.stats.hist_cpd_polystack_curves,
- rdrCtx.stats.stat_array_cpd_polystack_curves,
- rdrCtx.stats.stat_array_cpd_polystack_types)
- : new PolyStack(rdrCtx);
- }
-
- ClosedPathDetector init(DPathConsumer2D out) {
- if (this.out != out) {
- this.out = out;
- }
- return this; // fluent API
- }
-
- /**
- * Disposes this instance:
- * clean up before reusing this instance
- */
- void dispose() {
- stack.dispose();
- }
-
- @Override
- public void pathDone() {
- // previous path is not closed:
- finish(false);
- out.pathDone();
-
- // TODO: fix possible leak if exception happened
- // Dispose this instance:
- dispose();
- }
-
- @Override
- public void closePath() {
- // path is closed
- finish(true);
- out.closePath();
- }
-
- @Override
- public void moveTo(double x0, double y0) {
- // previous path is not closed:
- finish(false);
- out.moveTo(x0, y0);
- }
-
- private void finish(final boolean closed) {
- rdrCtx.closedPath = closed;
- stack.pullAll(out);
- }
-
- @Override
- public void lineTo(double x1, double y1) {
- stack.pushLine(x1, y1);
- }
-
- @Override
- public void curveTo(double x3, double y3,
- double x2, double y2,
- double x1, double y1)
- {
- stack.pushCubic(x1, y1, x2, y2, x3, y3);
- }
-
- @Override
- public void quadTo(double x2, double y2, double x1, double y1) {
- stack.pushQuad(x1, y1, x2, y2);
- }
-
- @Override
- public long getNativeConsumer() {
- throw new InternalError("Not using a native peer");
- }
- }
-
- static final class PathClipFilter implements DPathConsumer2D {
-
- private static final boolean TRACE = false;
-
- private static final int MOVE_TO = 0;
- private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
- private static final int CLOSE = 2;
-
- private DPathConsumer2D out;
-
- private int prev;
-
- // Bounds of the drawing region, at pixel precision.
- private final double[] clipRect;
-
- private final double[] corners = new double[8];
- private boolean init_corners = false;
-
- private final IndexStack stack;
-
- // the current outcode of the current sub path
- private int cOutCode = 0;
-
- // the outcode of the starting point
- private int sOutCode = 0;
-
- // the cumulated (and) outcode of the complete path
- private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
-
- private boolean outside = false;
-
- // The starting point of the path
- private double sx0, sy0;
-
- // The current point (TODO stupid repeated info)
- private double cx0, cy0;
-
- // The current point OUTSIDE
- private double cox0, coy0;
-
- private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
- private final CurveClipSplitter curveSplitter;
-
- PathClipFilter(final DRendererContext rdrCtx) {
- this.clipRect = rdrCtx.clipRect;
- this.curveSplitter = rdrCtx.curveClipSplitter;
-
- this.stack = (rdrCtx.stats != null) ?
- new IndexStack(rdrCtx,
- rdrCtx.stats.stat_pcf_idxstack_indices,
- rdrCtx.stats.hist_pcf_idxstack_indices,
- rdrCtx.stats.stat_array_pcf_idxstack_indices)
- : new IndexStack(rdrCtx);
- }
-
- PathClipFilter init(final DPathConsumer2D out) {
- if (this.out != out) {
- this.out = out;
- }
-
- if (MarlinConst.DO_CLIP_SUBDIVIDER) {
- // adjust padded clip rectangle:
- curveSplitter.init();
- }
-
- this.init_corners = true;
- this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
- this.prev = CLOSE;
-
- return this; // fluent API
- }
-
- /**
- * Disposes this instance:
- * clean up before reusing this instance
- */
- void dispose() {
- stack.dispose();
- }
-
- private void finishPath() {
- if (outside) {
- // criteria: inside or totally outside ?
- if (gOutCode == 0) {
- finish();
- } else {
- this.outside = false;
- stack.reset();
- }
- }
- }
-
- private void finish() {
- this.outside = false;
-
- if (!stack.isEmpty()) {
- if (init_corners) {
- init_corners = false;
-
- final double[] _corners = corners;
- final double[] _clipRect = clipRect;
- // Top Left (0):
- _corners[0] = _clipRect[2];
- _corners[1] = _clipRect[0];
- // Bottom Left (1):
- _corners[2] = _clipRect[2];
- _corners[3] = _clipRect[1];
- // Top right (2):
- _corners[4] = _clipRect[3];
- _corners[5] = _clipRect[0];
- // Bottom Right (3):
- _corners[6] = _clipRect[3];
- _corners[7] = _clipRect[1];
- }
- stack.pullAll(corners, out, (prev == MOVE_TO));
- prev = DRAWING_OP_TO;
- }
- // go to the last outside point:
- this.cx0 = cox0;
- this.cy0 = coy0;
- }
-
- @Override
- public void pathDone() {
- if (TRACE) {
- System.out.println("PathDone(" + sx0 + ", " + sy0 + ") prev: " + prev);
- }
- _closePath();
-
- out.pathDone();
-
- // this shouldn't matter since this object won't be used
- // after the call to this method.
- this.prev = CLOSE;
-
- // TODO: fix possible leak if exception happened
- // Dispose this instance:
- dispose();
- }
-
- @Override
- public void closePath() {
- if (TRACE) {
- System.out.println("ClosePath(" + sx0 + ", " + sy0 + ") prev: " + prev);
- }
- _closePath();
-
- out.closePath();
-
- // if outside, moveTo is needed
- if (sOutCode != 0) {
- this.prev = MOVE_TO;
- } else {
- this.prev = CLOSE;
- }
-
- // back to starting point:
- this.cOutCode = sOutCode;
- this.cx0 = sx0;
- this.cy0 = sy0;
- }
-
- private void _closePath() {
- // preserve outside flag for the lineTo call below
- final boolean prevOutside = outside;
- finishPath();
-
- if (prev == DRAWING_OP_TO) {
- // Should clip
- final int orCode = (cOutCode | sOutCode);
- if (orCode != 0) {
- if (cx0 != sx0 || cy0 != sy0) {
- // restore outside flag before lineTo:
- this.outside = prevOutside;
- // may subdivide line:
- lineTo(sx0, sy0);
- }
- }
- }
- finishPath();
- }
-
- @Override
- public void moveTo(final double x0, final double y0) {
- if (TRACE) {
- System.out.println("MoveTo(" + x0 + ", " + y0 + ") prev: " + prev);
- }
- _closePath();
-
- this.prev = MOVE_TO;
-
- // update starting point:
- final int outcode = DHelpers.outcode(x0, y0, clipRect);
- this.cOutCode = outcode;
- this.sOutCode = outcode;
- this.cx0 = x0;
- this.cy0 = y0;
-
- this.sx0 = x0;
- this.sy0 = y0;
- }
-
- @Override
- public void lineTo(final double xe, final double ye) {
- final int outcode0 = this.cOutCode;
- final int outcode1 = DHelpers.outcode(xe, ye, clipRect);
-
- if (TRACE) {
- if (subdivide) {
- System.out.println("----------------------");
- }
- if (outside) {
- System.out.println("LineTo co (" + cox0 + ", " + coy0 + ")");
- }
- System.out.println("LineTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("LineTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
- }
-
- // Should clip
- final int orCode = (outcode0 | outcode1);
- if (orCode != 0) {
- final int sideCode = (outcode0 & outcode1);
-
- // basic rejection criteria:
- if (sideCode == 0) {
- // overlap clip:
- if (subdivide) {
- // avoid reentrance
- subdivide = false;
- boolean ret;
- // subdivide curve => callback with subdivided parts:
- if (outside) {
- ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
- orCode, this);
- } else {
- ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
- orCode, this);
- }
- // reentrance is done:
- subdivide = true;
- if (ret) {
- return;
- }
- }
- // already subdivided so render it
- } else {
- this.cOutCode = outcode1;
- this.gOutCode &= sideCode;
- // keep last point coordinate before entering the clip again:
- this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
-
- if (TRACE) {
- System.out.println("skipped: (" + cox0 + ", " + coy0 + ")");
- }
-
- clip(sideCode, outcode0, outcode1);
- return;
- }
- }
-
- this.cOutCode = outcode1;
- this.gOutCode = 0;
-
- if (outside) {
- finish();
-
- // emit last point outside before entering again...
- if (outcode0 != 0) {
- if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
- }
- if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
- } else {
- out.lineTo(cox0, coy0);
- }
- prev = DRAWING_OP_TO;
- }
- }
- // clipping disabled:
- if (prev == MOVE_TO) {
- out.moveTo(cx0, cy0);
- }
- prev = DRAWING_OP_TO;
-
- out.lineTo(xe, ye);
- this.cx0 = xe;
- this.cy0 = ye;
-
- if (TRACE && subdivide) {
- System.out.println("----------------------");
- }
- }
-
- private void clip(final int sideCode,
- final int outcode0,
- final int outcode1)
- {
- // corner or cross-boundary on left or right side:
- if ((outcode0 != outcode1)
- && ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
- {
- // combine outcodes:
- final int mergeCode = (outcode0 | outcode1);
- final int tbCode = mergeCode & MarlinConst.OUTCODE_MASK_T_B;
- final int lrCode = mergeCode & MarlinConst.OUTCODE_MASK_L_R;
- final int off = (lrCode == MarlinConst.OUTCODE_LEFT) ? 0 : 2;
-
- // add corners to outside stack:
- switch (tbCode) {
- case MarlinConst.OUTCODE_TOP:
- stack.push(off); // top
- return;
- case MarlinConst.OUTCODE_BOTTOM:
- stack.push(off + 1); // bottom
- return;
- default:
- // both TOP / BOTTOM:
- if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
- // top to bottom
- stack.push(off); // top
- stack.push(off + 1); // bottom
- } else {
- // bottom to top
- stack.push(off + 1); // bottom
- stack.push(off); // top
- }
- }
- }
- }
-
- @Override
- public void curveTo(final double x1, final double y1,
- final double x2, final double y2,
- final double xe, final double ye)
- {
- final int outcode0 = this.cOutCode;
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
- final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
- final int outcode3 = DHelpers.outcode(xe, ye, clipRect);
-
- if (TRACE) {
- if (subdivide) {
- System.out.println("----------------------");
- }
- if (outside) {
- System.out.println("CurveTo co (" + cox0 + ", " + coy0 + ")");
- }
- System.out.println("CurveTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("CurveTo (" + xe + ", " + ye + ") outcode: " + outcode3 + " outside: " + outside);
- }
-
- // 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) {
- // overlap clip:
- if (subdivide) {
- // avoid reentrance
- subdivide = false;
- // subdivide curve => callback with subdivided parts:
- boolean ret;
- if (outside) {
- ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
- x2, y2, xe, ye,
- orCode, this);
- } else {
- ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
- x2, y2, xe, ye,
- orCode, this);
- }
- // reentrance is done:
- subdivide = true;
- if (ret) {
- return;
- }
- }
- // already subdivided so render it
- } else {
- this.cOutCode = outcode3;
- this.gOutCode &= sideCode;
- // keep last point coordinate before entering the clip again:
- this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
-
- if (TRACE) {
- System.out.println("skipped: (" + cox0 + ", " + coy0 + ")");
- }
-
- clip(sideCode, outcode0, outcode3);
- return;
- }
- }
-
- this.cOutCode = outcode3;
- this.gOutCode = 0;
-
- if (outside) {
- finish();
-
- // emit last point outside before entering again...
- if (outcode0 != 0) {
- if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
- }
- if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
- } else {
- out.lineTo(cox0, coy0);
- }
- prev = DRAWING_OP_TO;
- }
- }
- // clipping disabled:
- if (prev == MOVE_TO) {
- out.moveTo(cx0, cy0);
- }
- prev = DRAWING_OP_TO;
-
- out.curveTo(x1, y1, x2, y2, xe, ye);
- this.cx0 = xe;
- this.cy0 = ye;
-
- if (TRACE && subdivide) {
- System.out.println("----------------------");
- }
- }
-
- @Override
- public void quadTo(final double x1, final double y1,
- final double xe, final double ye)
- {
- final int outcode0 = this.cOutCode;
- final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
- final int outcode2 = DHelpers.outcode(xe, ye, clipRect);
-
- if (TRACE) {
- if (subdivide) {
- System.out.println("----------------------");
- }
- if (outside) {
- System.out.println("QuadTo co (" + cox0 + ", " + coy0 + ")");
- }
- System.out.println("QuadTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("QuadTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
- }
-
- // Should clip
- final int orCode = (outcode0 | outcode1 | outcode2);
- if (orCode != 0) {
- final int sideCode = outcode0 & outcode1 & outcode2;
-
- // basic rejection criteria:
- if (sideCode == 0) {
- // overlap clip:
- if (subdivide) {
- // avoid reentrance
- subdivide = false;
- // subdivide curve => callback with subdivided parts:
- boolean ret;
- if (outside) {
- ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
- xe, ye, orCode, this);
- } else {
- ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
- xe, ye, orCode, this);
- }
- // reentrance is done:
- subdivide = true;
- if (ret) {
- return;
- }
- }
- // already subdivided so render it
- } else {
- this.cOutCode = outcode2;
- this.gOutCode &= sideCode;
- // keep last point coordinate before entering the clip again:
- this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
-
- clip(sideCode, outcode0, outcode2);
- return;
- }
- }
-
- this.cOutCode = outcode2;
- this.gOutCode = 0;
-
- if (outside) {
- finish();
-
- // emit last point outside before entering again...
- if (outcode0 != 0) {
- if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
- }
- if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
- } else {
- out.lineTo(cox0, coy0);
- }
- prev = DRAWING_OP_TO;
- }
- }
- // clipping disabled:
- if (prev == MOVE_TO) {
- out.moveTo(cx0, cy0);
- }
- prev = DRAWING_OP_TO;
-
- out.quadTo(x1, y1, xe, ye);
- this.cx0 = xe;
- this.cy0 = ye;
-
- if (TRACE && subdivide) {
- System.out.println("----------------------");
- }
- }
-
- @Override
- public long getNativeConsumer() {
- throw new InternalError("Not using a native peer");
- }
- }
-
- static final class CurveClipSplitter {
-
- static final double LEN_TH = MarlinProperties.getSubdividerMinLength();
- static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0d);
-
- private static final boolean TRACE = false;
-
- private static final int MAX_N_CURVES = 3 * 4;
-
- private final DRendererContext rdrCtx;
-
- // scaled length threshold:
- private double minLength;
-
- // clip rectangle (ymin, ymax, xmin, xmax):
- final double[] clipRect;
-
- // clip rectangle (ymin, ymax, xmin, xmax) including padding:
- final double[] clipRectPad = new double[4];
- private boolean init_clipRectPad = false;
-
- // This is where the curve to be processed is put. We give it
- // enough room to store all curves.
- final double[] middle = new double[MAX_N_CURVES * 8 + 2];
- // t values at subdivision points
- private final double[] subdivTs = new double[MAX_N_CURVES];
-
- // dirty curve
- private final DCurve curve;
-
- CurveClipSplitter(final DRendererContext rdrCtx) {
- this.rdrCtx = rdrCtx;
- this.clipRect = rdrCtx.clipRect;
- this.curve = rdrCtx.curve;
- }
-
- void init() {
- this.init_clipRectPad = true;
-
- if (DO_CHECK_LENGTH) {
- this.minLength = (this.rdrCtx.clipInvScale == 0.0d) ? LEN_TH
- : (LEN_TH * this.rdrCtx.clipInvScale);
-
- if (MarlinConst.DO_LOG_CLIP) {
- MarlinUtils.logInfo("CurveClipSplitter.minLength = "
- + minLength);
- }
- }
- }
-
- private void initPaddedClip() {
- // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
- // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
- // add a rounding error (curve subdivision ~ 0.1px):
- final double[] _clipRect = clipRect;
- final double[] _clipRectPad = clipRectPad;
-
- _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
- _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
- _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
- _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
-
- if (TRACE) {
- MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
- + "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
- }
- }
-
- boolean splitLine(final double x0, final double y0,
- final double x1, final double y1,
- final int outCodeOR,
- final DPathConsumer2D out)
- {
- if (TRACE) {
- MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
- }
-
- if (DO_CHECK_LENGTH && DHelpers.fastLineLen(x0, y0, x1, y1) <= minLength) {
- return false;
- }
-
- final double[] mid = middle;
- mid[0] = x0; mid[1] = y0;
- mid[2] = x1; mid[3] = y1;
-
- return subdivideAtIntersections(4, outCodeOR, out);
- }
-
- boolean splitQuad(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2,
- final int outCodeOR,
- final DPathConsumer2D out)
- {
- if (TRACE) {
- MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
- }
-
- if (DO_CHECK_LENGTH && DHelpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= minLength) {
- return false;
- }
-
- final double[] mid = middle;
- mid[0] = x0; mid[1] = y0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
-
- return subdivideAtIntersections(6, outCodeOR, out);
- }
-
- boolean splitCurve(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3,
- final int outCodeOR,
- final DPathConsumer2D out)
- {
- if (TRACE) {
- MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
- }
-
- if (DO_CHECK_LENGTH && DHelpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= minLength) {
- return false;
- }
-
- final double[] mid = middle;
- mid[0] = x0; mid[1] = y0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
- mid[6] = x3; mid[7] = y3;
-
- return subdivideAtIntersections(8, outCodeOR, out);
- }
-
- private boolean subdivideAtIntersections(final int type, final int outCodeOR,
- final DPathConsumer2D out)
- {
- final double[] mid = middle;
- final double[] subTs = subdivTs;
-
- if (init_clipRectPad) {
- init_clipRectPad = false;
- initPaddedClip();
- }
-
- final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
- outCodeOR, clipRectPad);
-
- if (TRACE) {
- MarlinUtils.logInfo("nSplits: " + nSplits);
- MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
- }
- if (nSplits == 0) {
- // only curve support shortcut
- return false;
- }
- double prevT = 0.0d;
-
- for (int i = 0, off = 0; i < nSplits; i++, off += type) {
- final double t = subTs[i];
-
- DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
- mid, off, mid, off, type);
- prevT = t;
- }
-
- for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
- if (TRACE) {
- MarlinUtils.logInfo("Part Curve " + Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
- }
- emitCurrent(type, mid, off, out);
- }
- return true;
- }
-
- static void emitCurrent(final int type, final double[] pts,
- final int off, final DPathConsumer2D out)
- {
- // if instead of switch (perf + most probable cases first)
- if (type == 8) {
- out.curveTo(pts[off + 2], pts[off + 3],
- pts[off + 4], pts[off + 5],
- pts[off + 6], pts[off + 7]);
- } else if (type == 4) {
- out.lineTo(pts[off + 2], pts[off + 3]);
- } else {
- out.quadTo(pts[off + 2], pts[off + 3],
- pts[off + 4], pts[off + 5]);
- }
- }
- }
-
- static final class CurveBasicMonotonizer {
-
- private static final int MAX_N_CURVES = 11;
-
- // squared half line width (for stroker)
- private double lw2;
-
- // number of splitted curves
- int nbSplits;
-
- // This is where the curve to be processed is put. We give it
- // enough room to store all curves.
- final double[] middle = new double[MAX_N_CURVES * 6 + 2];
- // t values at subdivision points
- private final double[] subdivTs = new double[MAX_N_CURVES - 1];
-
- // dirty curve
- private final DCurve curve;
-
- CurveBasicMonotonizer(final DRendererContext rdrCtx) {
- this.curve = rdrCtx.curve;
- }
-
- void init(final double lineWidth) {
- this.lw2 = (lineWidth * lineWidth) / 4.0d;
- }
-
- CurveBasicMonotonizer curve(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2,
- final double x3, final double y3)
- {
- final double[] mid = middle;
- mid[0] = x0; mid[1] = y0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
- mid[6] = x3; mid[7] = y3;
-
- final double[] subTs = subdivTs;
- final int nSplits = DHelpers.findSubdivPoints(curve, mid, subTs, 8, lw2);
-
- double prevT = 0.0d;
- for (int i = 0, off = 0; i < nSplits; i++, off += 6) {
- final double t = subTs[i];
-
- DHelpers.subdivideCubicAt((t - prevT) / (1.0d - prevT),
- mid, off, mid, off, off + 6);
- prevT = t;
- }
-
- this.nbSplits = nSplits;
- return this;
- }
-
- CurveBasicMonotonizer quad(final double x0, final double y0,
- final double x1, final double y1,
- final double x2, final double y2)
- {
- final double[] mid = middle;
- mid[0] = x0; mid[1] = y0;
- mid[2] = x1; mid[3] = y1;
- mid[4] = x2; mid[5] = y2;
-
- final double[] subTs = subdivTs;
- final int nSplits = DHelpers.findSubdivPoints(curve, mid, subTs, 6, lw2);
-
- double prevt = 0.0d;
- for (int i = 0, off = 0; i < nSplits; i++, off += 4) {
- final double t = subTs[i];
- DHelpers.subdivideQuadAt((t - prevt) / (1.0d - prevt),
- mid, off, mid, off, off + 4);
- prevt = t;
- }
-
- this.nbSplits = nSplits;
- return this;
- }
- }
-
- static final class PathTracer implements DPathConsumer2D {
- private final String prefix;
- private DPathConsumer2D out;
-
- PathTracer(String name) {
- this.prefix = name + ": ";
- }
-
- PathTracer init(DPathConsumer2D out) {
- if (this.out != out) {
- this.out = out;
- }
- return this; // fluent API
- }
-
- @Override
- public void moveTo(double x0, double y0) {
- log("p.moveTo(" + x0 + ", " + y0 + ");");
- out.moveTo(x0, y0);
- }
-
- @Override
- public void lineTo(double x1, double y1) {
- log("p.lineTo(" + x1 + ", " + y1 + ");");
- out.lineTo(x1, y1);
- }
-
- @Override
- public void curveTo(double x1, double y1,
- double x2, double y2,
- double x3, double y3)
- {
- log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");");
- out.curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- @Override
- public void quadTo(double x1, double y1,
- double x2, double y2) {
- log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");");
- out.quadTo(x1, y1, x2, y2);
- }
-
- @Override
- public void closePath() {
- log("p.closePath();");
- out.closePath();
- }
-
- @Override
- public void pathDone() {
- log("p.pathDone();");
- out.pathDone();
- }
-
- private void log(final String message) {
- MarlinUtils.logInfo(prefix + message);
- }
-
- @Override
- public long getNativeConsumer() {
- throw new InternalError("Not using a native peer");
- }
- }
-}
diff --git a/src/main/java/sun/java2d/marlin/Dasher.java b/src/main/java/sun/java2d/marlin/Dasher.java
index cfcb208..aa75a29 100644
--- a/src/main/java/sun/java2d/marlin/Dasher.java
+++ b/src/main/java/sun/java2d/marlin/Dasher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -28,7 +28,6 @@
import java.util.Arrays;
import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer;
import sun.java2d.marlin.TransformingPathConsumer2D.CurveClipSplitter;
-import sun.awt.geom.PathConsumer2D;
/**
* The Dasher
class takes a series of linear commands
@@ -41,24 +40,24 @@
* semantics are unclear.
*
*/
-final class Dasher implements PathConsumer2D, MarlinConst {
+final class Dasher implements DPathConsumer2D, MarlinConst {
/* huge circle with radius ~ 2E9 only needs 12 subdivision levels */
static final int REC_LIMIT = 16;
- static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01
- static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT);
+ static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial
+ static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT);
- static final float EPS = 1e-6f;
+ static final double EPS = 1e-6d;
// More than 24 bits of mantissa means we can no longer accurately
// measure the number of times cycled through the dash array so we
// punt and override the phase to just be 0 past that point.
- static final float MAX_CYCLES = 16000000.0f;
+ static final double MAX_CYCLES = 16000000.0d;
- private PathConsumer2D out;
- private float[] dash;
+ private DPathConsumer2D out;
+ private double[] dash;
private int dashLen;
- private float startPhase;
+ private double startPhase;
private boolean startDashOn;
private int startIdx;
@@ -67,15 +66,15 @@ final class Dasher implements PathConsumer2D, MarlinConst {
private int idx;
private boolean dashOn;
- private float phase;
+ private double phase;
// The starting point of the path
- private float sx0, sy0;
+ private double sx0, sy0;
// the current point
- private float cx0, cy0;
+ private double cx0, cy0;
// temporary storage for the current curve
- private final float[] curCurvepts;
+ private final double[] curCurvepts;
// per-thread renderer context
final RendererContext rdrCtx;
@@ -87,16 +86,16 @@ final class Dasher implements PathConsumer2D, MarlinConst {
// drawn on it, but we need joins to be drawn if there's a closePath()
// So, we store the path elements that make up the first dash in the
// buffer below.
- private float[] firstSegmentsBuffer; // dynamic array
+ private double[] firstSegmentsBuffer; // dynamic array
private int firstSegidx;
// dashes ref (dirty)
- final ArrayCacheFloat.Reference dashes_ref;
+ final ArrayCacheDouble.Reference dashes_ref;
// firstSegmentsBuffer ref (dirty)
- final ArrayCacheFloat.Reference firstSegmentsBuffer_ref;
+ final ArrayCacheDouble.Reference firstSegmentsBuffer_ref;
// Bounds of the drawing region, at pixel precision.
- private float[] clipRect;
+ private double[] clipRect;
// the outcode of the current point
private int cOutCode = 0;
@@ -107,9 +106,9 @@ final class Dasher implements PathConsumer2D, MarlinConst {
private final CurveClipSplitter curveSplitter;
- private float cycleLen;
+ private double cycleLen;
private boolean outside;
- private float totalSkipLen;
+ private double totalSkipLen;
/**
* Constructs a Dasher
.
@@ -118,14 +117,14 @@ final class Dasher implements PathConsumer2D, MarlinConst {
Dasher(final RendererContext rdrCtx) {
this.rdrCtx = rdrCtx;
- dashes_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_ARRAY); // 1K
+ dashes_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
- firstSegmentsBuffer_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_ARRAY); // 1K
+ firstSegmentsBuffer_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
firstSegmentsBuffer = firstSegmentsBuffer_ref.initial;
// we need curCurvepts to be able to contain 2 curves because when
// dashing curves, we need to subdivide it
- curCurvepts = new float[8 * 2];
+ curCurvepts = new double[8 * 2];
this.curveSplitter = rdrCtx.curveClipSplitter;
}
@@ -133,15 +132,15 @@ final class Dasher implements PathConsumer2D, MarlinConst {
/**
* Initialize the Dasher
.
*
- * @param out an output PathConsumer2D
.
- * @param dash an array of float
s containing the dash pattern
+ * @param out an output DPathConsumer2D
.
+ * @param dash an array of double
s containing the dash pattern
* @param dashLen length of the given dash array
- * @param phase a float
containing the dash phase
+ * @param phase a double
containing the dash phase
* @param recycleDashes true to indicate to recycle the given dash array
* @return this instance
*/
- Dasher init(final PathConsumer2D out, final float[] dash, final int dashLen,
- float phase, final boolean recycleDashes)
+ Dasher init(final DPathConsumer2D out, final double[] dash, final int dashLen,
+ double phase, final boolean recycleDashes)
{
if (this.out != out) {
this.out = out;
@@ -152,23 +151,23 @@ Dasher init(final PathConsumer2D out, final float[] dash, final int dashLen,
dashOn = true;
// note: BasicStroke constructor checks dash elements and sum > 0
- float sum = 0.0f;
+ double sum = 0.0d;
for (int i = 0; i < dashLen; i++) {
sum += dash[i];
}
this.cycleLen = sum;
- float cycles = phase / sum;
- if (phase < 0.0f) {
+ double cycles = phase / sum;
+ if (phase < 0.0d) {
if (-cycles >= MAX_CYCLES) {
- phase = 0.0f;
+ phase = 0.0d;
} else {
int fullcycles = FloatMath.floor_int(-cycles);
if ((fullcycles & dashLen & 1) != 0) {
dashOn = !dashOn;
}
phase += fullcycles * sum;
- while (phase < 0.0f) {
+ while (phase < 0.0d) {
if (--sidx < 0) {
sidx = dashLen - 1;
}
@@ -176,16 +175,16 @@ Dasher init(final PathConsumer2D out, final float[] dash, final int dashLen,
dashOn = !dashOn;
}
}
- } else if (phase > 0.0f) {
+ } else if (phase > 0.0d) {
if (cycles >= MAX_CYCLES) {
- phase = 0.0f;
+ phase = 0.0d;
} else {
int fullcycles = FloatMath.floor_int(cycles);
if ((fullcycles & dashLen & 1) != 0) {
dashOn = !dashOn;
}
phase -= fullcycles * sum;
- float d;
+ double d;
while (phase >= (d = dash[sidx])) {
phase -= d;
sidx = (sidx + 1) % dashLen;
@@ -222,7 +221,7 @@ Dasher init(final PathConsumer2D out, final float[] dash, final int dashLen,
void dispose() {
if (DO_CLEAN_DIRTY) {
// Force zero-fill dirty arrays:
- Arrays.fill(curCurvepts, 0.0f);
+ Arrays.fill(curCurvepts, 0.0d);
}
// Return arrays:
if (recycleDashes) {
@@ -235,9 +234,9 @@ void dispose() {
}
}
- float[] copyDashArray(final float[] dashes) {
+ double[] copyDashArray(final float[] dashes) {
final int len = dashes.length;
- final float[] newDashes;
+ final double[] newDashes;
if (len <= MarlinConst.INITIAL_ARRAY) {
newDashes = dashes_ref.initial;
} else {
@@ -246,12 +245,12 @@ float[] copyDashArray(final float[] dashes) {
}
newDashes = dashes_ref.getArray(len);
}
- System.arraycopy(dashes, 0, newDashes, 0, len);
+ for (int i = 0; i < len; i++) { newDashes[i] = dashes[i]; }
return newDashes;
}
@Override
- public void moveTo(final float x0, final float y0) {
+ public void moveTo(final double x0, final double y0) {
if (firstSegidx != 0) {
out.moveTo(sx0, sy0);
emitFirstSegments();
@@ -272,11 +271,11 @@ public void moveTo(final float x0, final float y0) {
final int outcode = Helpers.outcode(x0, y0, clipRect);
this.cOutCode = outcode;
this.outside = false;
- this.totalSkipLen = 0.0f;
+ this.totalSkipLen = 0.0d;
}
}
- private void emitSeg(float[] buf, int off, int type) {
+ private void emitSeg(double[] buf, int off, int type) {
switch (type) {
case 4:
out.lineTo(buf[off], buf[off + 1]);
@@ -295,7 +294,7 @@ private void emitSeg(float[] buf, int off, int type) {
}
private void emitFirstSegments() {
- final float[] fSegBuf = firstSegmentsBuffer;
+ final double[] fSegBuf = firstSegmentsBuffer;
for (int i = 0, len = firstSegidx; i < len; ) {
int type = (int)fSegBuf[i];
@@ -306,12 +305,12 @@ private void emitFirstSegments() {
}
// precondition: pts must be in relative coordinates (relative to x0,y0)
- private void goTo(final float[] pts, final int off, final int type,
+ private void goTo(final double[] pts, final int off, final int type,
final boolean on)
{
final int index = off + type;
- final float x = pts[index - 4];
- final float y = pts[index - 3];
+ final double x = pts[index - 4];
+ final double y = pts[index - 3];
if (on) {
if (starting) {
@@ -334,10 +333,10 @@ private void goTo(final float[] pts, final int off, final int type,
this.cy0 = y;
}
- private void goTo_starting(final float[] pts, final int off, final int type) {
+ private void goTo_starting(final double[] pts, final int off, final int type) {
int len = type - 1; // - 2 + 1
int segIdx = firstSegidx;
- float[] buf = firstSegmentsBuffer;
+ double[] buf = firstSegmentsBuffer;
if (segIdx + len > buf.length) {
if (DO_STATS) {
@@ -356,7 +355,7 @@ private void goTo_starting(final float[] pts, final int off, final int type) {
}
@Override
- public void lineTo(final float x1, final float y1) {
+ public void lineTo(final double x1, final double y1) {
final int outcode0 = this.cOutCode;
if (clipRect != null) {
@@ -402,30 +401,30 @@ public void lineTo(final float x1, final float y1) {
_lineTo(x1, y1);
}
- private void _lineTo(final float x1, final float y1) {
- final float dx = x1 - cx0;
- final float dy = y1 - cy0;
+ private void _lineTo(final double x1, final double y1) {
+ final double dx = x1 - cx0;
+ final double dy = y1 - cy0;
- float len = dx * dx + dy * dy;
- if (len == 0.0f) {
+ double len = dx * dx + dy * dy;
+ if (len == 0.0d) {
return;
}
- len = (float) Math.sqrt(len);
+ len = Math.sqrt(len);
// The scaling factors needed to get the dx and dy of the
// transformed dash segments.
- final float cx = dx / len;
- final float cy = dy / len;
+ final double cx = dx / len;
+ final double cy = dy / len;
- final float[] _curCurvepts = curCurvepts;
- final float[] _dash = dash;
+ final double[] _curCurvepts = curCurvepts;
+ final double[] _dash = dash;
final int _dashLen = this.dashLen;
int _idx = idx;
boolean _dashOn = dashOn;
- float _phase = phase;
+ double _phase = phase;
- float leftInThisDashSegment, rem;
+ double leftInThisDashSegment, rem;
while (true) {
leftInThisDashSegment = _dash[_idx] - _phase;
@@ -442,7 +441,7 @@ private void _lineTo(final float x1, final float y1) {
// compare values using epsilon:
if (Math.abs(rem) <= EPS) {
- _phase = 0.0f;
+ _phase = 0.0d;
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
}
@@ -458,7 +457,7 @@ private void _lineTo(final float x1, final float y1) {
// Advance to next dash segment
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
- _phase = 0.0f;
+ _phase = 0.0d;
}
// Save local state:
idx = _idx;
@@ -466,13 +465,13 @@ private void _lineTo(final float x1, final float y1) {
phase = _phase;
}
- private void skipLineTo(final float x1, final float y1) {
- final float dx = x1 - cx0;
- final float dy = y1 - cy0;
+ private void skipLineTo(final double x1, final double y1) {
+ final double dx = x1 - cx0;
+ final double dy = y1 - cy0;
- float len = dx * dx + dy * dy;
- if (len != 0.0f) {
- len = (float)Math.sqrt(len);
+ double len = dx * dx + dy * dy;
+ if (len != 0.0d) {
+ len = Math.sqrt(len);
}
// Accumulate skipped length:
@@ -488,15 +487,15 @@ private void skipLineTo(final float x1, final float y1) {
}
public void skipLen() {
- float len = this.totalSkipLen;
- this.totalSkipLen = 0.0f;
+ double len = this.totalSkipLen;
+ this.totalSkipLen = 0.0d;
- final float[] _dash = dash;
+ final double[] _dash = dash;
final int _dashLen = this.dashLen;
int _idx = idx;
boolean _dashOn = dashOn;
- float _phase = phase;
+ double _phase = phase;
// -2 to ensure having 2 iterations of the post-loop
// to compensate the remaining phase
@@ -510,7 +509,7 @@ public void skipLen() {
_dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
}
- float leftInThisDashSegment, rem;
+ double leftInThisDashSegment, rem;
while (true) {
leftInThisDashSegment = _dash[_idx] - _phase;
@@ -522,7 +521,7 @@ public void skipLen() {
// compare values using epsilon:
if (Math.abs(rem) <= EPS) {
- _phase = 0.0f;
+ _phase = 0.0d;
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
}
@@ -533,7 +532,7 @@ public void skipLen() {
// Advance to next dash segment
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
- _phase = 0.0f;
+ _phase = 0.0d;
}
// Save local state:
idx = _idx;
@@ -544,29 +543,29 @@ public void skipLen() {
// preconditions: curCurvepts must be an array of length at least 2 * type,
// that contains the curve we want to dash in the first type elements
private void somethingTo(final int type) {
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
if (Helpers.isPointCurve(_curCurvepts, type)) {
return;
}
final LengthIterator _li = li;
- final float[] _dash = dash;
+ final double[] _dash = dash;
final int _dashLen = this.dashLen;
_li.initializeIterationOnCurve(_curCurvepts, type);
int _idx = idx;
boolean _dashOn = dashOn;
- float _phase = phase;
+ double _phase = phase;
// initially the current curve is at curCurvepts[0...type]
int curCurveoff = 0;
- float prevT = 0.0f;
- float t;
- float leftInThisDashSegment = _dash[_idx] - _phase;
+ double prevT = 0.0d;
+ double t;
+ double leftInThisDashSegment = _dash[_idx] - _phase;
- while ((t = _li.next(leftInThisDashSegment)) < 1.0f) {
- if (t != 0.0f) {
- Helpers.subdivideAt((t - prevT) / (1.0f - prevT),
+ while ((t = _li.next(leftInThisDashSegment)) < 1.0d) {
+ if (t != 0.0d) {
+ Helpers.subdivideAt((t - prevT) / (1.0d - prevT),
_curCurvepts, curCurveoff,
_curCurvepts, 0, type);
prevT = t;
@@ -576,7 +575,7 @@ private void somethingTo(final int type) {
// Advance to next dash segment
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
- _phase = 0.0f;
+ _phase = 0.0d;
leftInThisDashSegment = _dash[_idx];
}
@@ -586,7 +585,7 @@ private void somethingTo(final int type) {
// compare values using epsilon:
if (_phase + EPS >= _dash[_idx]) {
- _phase = 0.0f;
+ _phase = 0.0d;
_idx = (_idx + 1) % _dashLen;
_dashOn = !_dashOn;
}
@@ -600,7 +599,7 @@ private void somethingTo(final int type) {
}
private void skipSomethingTo(final int type) {
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
if (Helpers.isPointCurve(_curCurvepts, type)) {
return;
}
@@ -610,7 +609,7 @@ private void skipSomethingTo(final int type) {
// In contrary to somethingTo(),
// just estimate properly the curve length:
- final float len = _li.totalLength();
+ final double len = _li.totalLength();
// Accumulate skipped length:
this.outside = true;
@@ -639,18 +638,18 @@ static final class LengthIterator {
// (i.e. the original curve) is at recCurveStack[0] (but then it
// gets subdivided, the left half is put at 1, so most of the time
// only the right half of the original curve is at 0)
- private final float[][] recCurveStack; // dirty
+ private final double[][] recCurveStack; // dirty
// sidesRight[i] indicates whether the node at level i+1 in the path from
// the root to the current leaf is a left or right child of its parent.
private final boolean[] sidesRight; // dirty
private int curveType;
// lastT and nextT delimit the current leaf.
- private float nextT;
- private float lenAtNextT;
- private float lastT;
- private float lenAtLastT;
- private float lenAtLastSplit;
- private float lastSegLen;
+ private double nextT;
+ private double lenAtNextT;
+ private double lastT;
+ private double lenAtLastT;
+ private double lenAtLastSplit;
+ private double lastSegLen;
// the current level in the recursion tree. 0 is the root. limit
// is the deepest possible leaf.
private int recLevel;
@@ -659,18 +658,18 @@ static final class LengthIterator {
// the lengths of the lines of the control polygon. Only its first
// curveType/2 - 1 elements are valid. This is an optimization. See
// next() for more detail.
- private final float[] curLeafCtrlPolyLengths = new float[3];
+ private final double[] curLeafCtrlPolyLengths = new double[3];
LengthIterator() {
- this.recCurveStack = new float[REC_LIMIT + 1][8];
+ this.recCurveStack = new double[REC_LIMIT + 1][8];
this.sidesRight = new boolean[REC_LIMIT];
// if any methods are called without first initializing this object
// on a curve, we want it to fail ASAP.
- this.nextT = Float.MAX_VALUE;
- this.lenAtNextT = Float.MAX_VALUE;
- this.lenAtLastSplit = Float.MIN_VALUE;
+ this.nextT = Double.MAX_VALUE;
+ this.lenAtNextT = Double.MAX_VALUE;
+ this.lenAtLastSplit = Double.MIN_VALUE;
this.recLevel = Integer.MIN_VALUE;
- this.lastSegLen = Float.MAX_VALUE;
+ this.lastSegLen = Double.MAX_VALUE;
this.done = true;
}
@@ -683,29 +682,29 @@ void reset() {
if (DO_CLEAN_DIRTY) {
final int recLimit = recCurveStack.length - 1;
for (int i = recLimit; i >= 0; i--) {
- Arrays.fill(recCurveStack[i], 0.0f);
+ Arrays.fill(recCurveStack[i], 0.0d);
}
Arrays.fill(sidesRight, false);
- Arrays.fill(curLeafCtrlPolyLengths, 0.0f);
- Arrays.fill(nextRoots, 0.0f);
- Arrays.fill(flatLeafCoefCache, 0.0f);
- flatLeafCoefCache[2] = -1.0f;
+ Arrays.fill(curLeafCtrlPolyLengths, 0.0d);
+ Arrays.fill(nextRoots, 0.0d);
+ Arrays.fill(flatLeafCoefCache, 0.0d);
+ flatLeafCoefCache[2] = -1.0d;
}
}
- void initializeIterationOnCurve(final float[] pts, final int type) {
+ void initializeIterationOnCurve(final double[] pts, final int type) {
// optimize arraycopy (8 values faster than 6 = type):
System.arraycopy(pts, 0, recCurveStack[0], 0, 8);
this.curveType = type;
this.recLevel = 0;
- this.lastT = 0.0f;
- this.lenAtLastT = 0.0f;
- this.nextT = 0.0f;
- this.lenAtNextT = 0.0f;
+ this.lastT = 0.0d;
+ this.lenAtLastT = 0.0d;
+ this.nextT = 0.0d;
+ this.lenAtNextT = 0.0d;
// initializes nextT and lenAtNextT properly
goLeft();
- this.lenAtLastSplit = 0.0f;
+ this.lenAtLastSplit = 0.0d;
if (recLevel > 0) {
this.sidesRight[0] = false;
this.done = false;
@@ -714,16 +713,16 @@ void initializeIterationOnCurve(final float[] pts, final int type) {
this.sidesRight[0] = true;
this.done = true;
}
- this.lastSegLen = 0.0f;
+ this.lastSegLen = 0.0d;
}
// 0 == false, 1 == true, -1 == invalid cached value.
private int cachedHaveLowAcceleration = -1;
- private boolean haveLowAcceleration(final float err) {
+ private boolean haveLowAcceleration(final double err) {
if (cachedHaveLowAcceleration == -1) {
- final float len1 = curLeafCtrlPolyLengths[0];
- final float len2 = curLeafCtrlPolyLengths[1];
+ final double len1 = curLeafCtrlPolyLengths[0];
+ final double len2 = curLeafCtrlPolyLengths[1];
// the test below is equivalent to !within(len1/len2, 1, err).
// It is using a multiplication instead of a division, so it
// should be a bit faster.
@@ -732,11 +731,11 @@ private boolean haveLowAcceleration(final float err) {
return false;
}
if (curveType == 8) {
- final float len3 = curLeafCtrlPolyLengths[2];
+ final double len3 = curLeafCtrlPolyLengths[2];
// if len1 is close to 2 and 2 is close to 3, that probably
// means 1 is close to 3 so the second part of this test might
// not be needed, but it doesn't hurt to include it.
- final float errLen3 = err * len3;
+ final double errLen3 = err * len3;
if (!(Helpers.within(len2, len3, errLen3) &&
Helpers.within(len1, len3, errLen3))) {
cachedHaveLowAcceleration = 0;
@@ -752,73 +751,73 @@ private boolean haveLowAcceleration(final float err) {
// we want to avoid allocations/gc so we keep this array so we
// can put roots in it,
- private final float[] nextRoots = new float[4];
+ private final double[] nextRoots = new double[4];
// caches the coefficients of the current leaf in its flattened
// form (see inside next() for what that means). The cache is
// invalid when it's third element is negative, since in any
// valid flattened curve, this would be >= 0.
- private final float[] flatLeafCoefCache = new float[]{0.0f, 0.0f, -1.0f, 0.0f};
+ private final double[] flatLeafCoefCache = new double[]{0.0d, 0.0d, -1.0d, 0.0d};
// returns the t value where the remaining curve should be split in
// order for the left subdivided curve to have length len. If len
// is >= than the length of the uniterated curve, it returns 1.
- float next(final float len) {
- final float targetLength = lenAtLastSplit + len;
+ double next(final double len) {
+ final double targetLength = lenAtLastSplit + len;
while (lenAtNextT < targetLength) {
if (done) {
lastSegLen = lenAtNextT - lenAtLastSplit;
- return 1.0f;
+ return 1.0d;
}
goToNextLeaf();
}
lenAtLastSplit = targetLength;
- final float leaflen = lenAtNextT - lenAtLastT;
- float t = (targetLength - lenAtLastT) / leaflen;
+ final double leaflen = lenAtNextT - lenAtLastT;
+ double t = (targetLength - lenAtLastT) / leaflen;
// cubicRootsInAB is a fairly expensive call, so we just don't do it
// if the acceleration in this section of the curve is small enough.
- if (!haveLowAcceleration(0.05f)) {
+ if (!haveLowAcceleration(0.05d)) {
// We flatten the current leaf along the x axis, so that we're
// left with a, b, c which define a 1D Bezier curve. We then
// solve this to get the parameter of the original leaf that
// gives us the desired length.
- final float[] _flatLeafCoefCache = flatLeafCoefCache;
+ final double[] _flatLeafCoefCache = flatLeafCoefCache;
- if (_flatLeafCoefCache[2] < 0.0f) {
- float x = curLeafCtrlPolyLengths[0],
- y = x + curLeafCtrlPolyLengths[1];
+ if (_flatLeafCoefCache[2] < 0.0d) {
+ double x = curLeafCtrlPolyLengths[0],
+ y = x + curLeafCtrlPolyLengths[1];
if (curveType == 8) {
- float z = y + curLeafCtrlPolyLengths[2];
- _flatLeafCoefCache[0] = 3.0f * (x - y) + z;
- _flatLeafCoefCache[1] = 3.0f * (y - 2.0f * x);
- _flatLeafCoefCache[2] = 3.0f * x;
+ double z = y + curLeafCtrlPolyLengths[2];
+ _flatLeafCoefCache[0] = 3.0d * (x - y) + z;
+ _flatLeafCoefCache[1] = 3.0d * (y - 2.0d * x);
+ _flatLeafCoefCache[2] = 3.0d * x;
_flatLeafCoefCache[3] = -z;
} else if (curveType == 6) {
- _flatLeafCoefCache[0] = 0.0f;
- _flatLeafCoefCache[1] = y - 2.0f * x;
- _flatLeafCoefCache[2] = 2.0f * x;
+ _flatLeafCoefCache[0] = 0.0d;
+ _flatLeafCoefCache[1] = y - 2.0d * x;
+ _flatLeafCoefCache[2] = 2.0d * x;
_flatLeafCoefCache[3] = -y;
}
}
- float a = _flatLeafCoefCache[0];
- float b = _flatLeafCoefCache[1];
- float c = _flatLeafCoefCache[2];
- float d = t * _flatLeafCoefCache[3];
+ double a = _flatLeafCoefCache[0];
+ double b = _flatLeafCoefCache[1];
+ double c = _flatLeafCoefCache[2];
+ double d = t * _flatLeafCoefCache[3];
// we use cubicRootsInAB here, because we want only roots in 0, 1,
// and our quadratic root finder doesn't filter, so it's just a
// matter of convenience.
- final int n = Helpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0.0f, 1.0f);
- if (n == 1 && !Float.isNaN(nextRoots[0])) {
+ final int n = Helpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0.0d, 1.0d);
+ if (n == 1 && !Double.isNaN(nextRoots[0])) {
t = nextRoots[0];
}
}
// t is relative to the current leaf, so we must make it a valid parameter
// of the original curve.
t = t * (nextT - lastT) + lastT;
- if (t >= 1.0f) {
- t = 1.0f;
+ if (t >= 1.0d) {
+ t = 1.0d;
done = true;
}
// even if done = true, if we're here, that means targetLength
@@ -830,7 +829,7 @@ float next(final float len) {
return t;
}
- float totalLength() {
+ double totalLength() {
while (!done) {
goToNextLeaf();
}
@@ -840,7 +839,7 @@ float totalLength() {
return lenAtNextT;
}
- float lastSegLen() {
+ double lastSegLen() {
return lastSegLen;
}
@@ -872,19 +871,19 @@ private void goToNextLeaf() {
// go to the leftmost node from the current node. Return its length.
private void goLeft() {
- final float len = onLeaf();
- if (len >= 0.0f) {
+ final double len = onLeaf();
+ if (len >= 0.0d) {
lastT = nextT;
lenAtLastT = lenAtNextT;
nextT += (1 << (REC_LIMIT - recLevel)) * MIN_T_INC;
lenAtNextT += len;
// invalidate caches
- flatLeafCoefCache[2] = -1.0f;
+ flatLeafCoefCache[2] = -1.0d;
cachedHaveLowAcceleration = -1;
} else {
Helpers.subdivide(recCurveStack[recLevel],
- recCurveStack[recLevel + 1],
- recCurveStack[recLevel], curveType);
+ recCurveStack[recLevel + 1],
+ recCurveStack[recLevel], curveType);
sidesRight[recLevel] = false;
recLevel++;
@@ -894,34 +893,34 @@ private void goLeft() {
// this is a bit of a hack. It returns -1 if we're not on a leaf, and
// the length of the leaf if we are on a leaf.
- private float onLeaf() {
- final float[] curve = recCurveStack[recLevel];
+ private double onLeaf() {
+ final double[] curve = recCurveStack[recLevel];
final int _curveType = curveType;
- float polyLen = 0.0f;
+ double polyLen = 0.0d;
- float x0 = curve[0], y0 = curve[1];
+ double x0 = curve[0], y0 = curve[1];
for (int i = 2; i < _curveType; i += 2) {
- final float x1 = curve[i], y1 = curve[i + 1];
- final float len = Helpers.linelen(x0, y0, x1, y1);
+ final double x1 = curve[i], y1 = curve[i + 1];
+ final double len = Helpers.linelen(x0, y0, x1, y1);
polyLen += len;
curLeafCtrlPolyLengths[(i >> 1) - 1] = len;
x0 = x1;
y0 = y1;
}
- final float lineLen = Helpers.linelen(curve[0], curve[1], x0, y0);
+ final double lineLen = Helpers.linelen(curve[0], curve[1], x0, y0);
if ((polyLen - lineLen) < CURVE_LEN_ERR || recLevel == REC_LIMIT) {
- return (polyLen + lineLen) / 2.0f;
+ return (polyLen + lineLen) / 2.0d;
}
- return -1.0f;
+ return -1.0d;
}
}
@Override
- public void curveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ public void curveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
final int outcode0 = this.cOutCode;
@@ -969,18 +968,18 @@ public void curveTo(final float x1, final float y1,
_curveTo(x1, y1, x2, y2, x3, y3);
}
- private void _curveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ private void _curveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
// monotonize curve:
final CurveBasicMonotonizer monotonizer
= rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
final int nSplits = monotonizer.nbSplits;
- final float[] mid = monotonizer.middle;
+ final double[] mid = monotonizer.middle;
// Implicitely rdrCtx.isFirstSegment = true
@@ -997,11 +996,11 @@ private void _curveTo(final float x1, final float y1,
rdrCtx.isFirstSegment = true;
}
- private void skipCurveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ private void skipCurveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
_curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
_curCurvepts[2] = x1; _curCurvepts[3] = y1;
_curCurvepts[4] = x2; _curCurvepts[5] = y2;
@@ -1014,8 +1013,8 @@ private void skipCurveTo(final float x1, final float y1,
}
@Override
- public void quadTo(final float x1, final float y1,
- final float x2, final float y2)
+ public void quadTo(final double x1, final double y1,
+ final double x2, final double y2)
{
final int outcode0 = this.cOutCode;
@@ -1062,17 +1061,17 @@ public void quadTo(final float x1, final float y1,
_quadTo(x1, y1, x2, y2);
}
- private void _quadTo(final float x1, final float y1,
- final float x2, final float y2)
+ private void _quadTo(final double x1, final double y1,
+ final double x2, final double y2)
{
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
// monotonize quad:
final CurveBasicMonotonizer monotonizer
= rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
final int nSplits = monotonizer.nbSplits;
- final float[] mid = monotonizer.middle;
+ final double[] mid = monotonizer.middle;
// Implicitely rdrCtx.isFirstSegment = true
@@ -1089,10 +1088,10 @@ private void _quadTo(final float x1, final float y1,
rdrCtx.isFirstSegment = true;
}
- private void skipQuadTo(final float x1, final float y1,
- final float x2, final float y2)
+ private void skipQuadTo(final double x1, final double y1,
+ final double x2, final double y2)
{
- final float[] _curCurvepts = curCurvepts;
+ final double[] _curCurvepts = curCurvepts;
_curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
_curCurvepts[2] = x1; _curCurvepts[3] = y1;
_curCurvepts[4] = x2; _curCurvepts[5] = y2;
diff --git a/src/main/java/sun/java2d/marlin/Helpers.java b/src/main/java/sun/java2d/marlin/Helpers.java
index 63788ee..48b5ab0 100644
--- a/src/main/java/sun/java2d/marlin/Helpers.java
+++ b/src/main/java/sun/java2d/marlin/Helpers.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -26,32 +26,30 @@
package sun.java2d.marlin;
import java.util.Arrays;
-import net.jafama.FastMath;
import sun.java2d.marlin.stats.Histogram;
import sun.java2d.marlin.stats.StatLong;
-import sun.awt.geom.PathConsumer2D;
final class Helpers implements MarlinConst {
- private static final float EPS = 1e-9f;
+ private static final double EPS = 1e-9d;
private Helpers() {
throw new Error("This is a non instantiable class");
}
- static boolean within(final float x, final float y) {
+ static boolean within(final double x, final double y) {
return within(x, y, EPS);
}
- static boolean within(final float x, final float y, final float err) {
+ static boolean within(final double x, final double y, final double err) {
return withinD(y - x, err);
}
- static boolean withinD(final float d, final float err) {
+ static boolean withinD(final double d, final double err) {
return (d <= err && d >= -err);
}
- static boolean withinD(final float dx, final float dy, final float err)
+ static boolean withinD(final double dx, final double dy, final double err)
{
assert err > 0 : "";
// compare taxicab distance. ERR will always be small, so using
@@ -60,11 +58,11 @@ static boolean withinD(final float dx, final float dy, final float err)
withinD(dy, err)); // this is just as good.
}
- static boolean isPointCurve(final float[] curve, final int type) {
+ static boolean isPointCurve(final double[] curve, final int type) {
return isPointCurve(curve, type, EPS);
}
- static boolean isPointCurve(final float[] curve, final int type, final float err) {
+ static boolean isPointCurve(final double[] curve, final int type, final double err) {
for (int i = 2; i < type; i++) {
if (!within(curve[i], curve[i - 2], err)) {
return false;
@@ -73,57 +71,57 @@ static boolean isPointCurve(final float[] curve, final int type, final float err
return true;
}
- static float evalCubic(final float a, final float b,
- final float c, final float d,
- final float t)
+ static double evalCubic(final double a, final double b,
+ final double c, final double d,
+ final double t)
{
return t * (t * (t * a + b) + c) + d;
}
- static float evalQuad(final float a, final float b,
- final float c, final float t)
+ static double evalQuad(final double a, final double b,
+ final double c, final double t)
{
return t * (t * a + b) + c;
}
- static int quadraticRoots(final float a, final float b, final float c,
- final float[] zeroes, final int off)
+ static int quadraticRoots(final double a, final double b, final double c,
+ final double[] zeroes, final int off)
{
int ret = off;
- if (a != 0.0f) {
- float d = b * b - 4.0f * a * c;
- if (d > 0.0f) {
- d = (float)Math.sqrt(d);
+ if (a != 0.0d) {
+ double d = b * b - 4.0d * a * c;
+ if (d > 0.0d) {
+ d = Math.sqrt(d);
// For accuracy, calculate one root using:
// (-b +/- d) / 2a
// and the other using:
// 2c / (-b +/- d)
// Choose the sign of the +/- so that b+d gets larger in magnitude
- if (b < 0.0f) {
+ if (b < 0.0d) {
d = -d;
}
- final float q = (b + d) / -2.0f;
+ final double q = (b + d) / -2.0d;
// We already tested a for being 0 above
zeroes[ret++] = q / a;
- if (q != 0.0f) {
+ if (q != 0.0d) {
zeroes[ret++] = c / q;
}
- } else if (d == 0.0f) {
- zeroes[ret++] = -b / (2.0f * a);
+ } else if (d == 0.0d) {
+ zeroes[ret++] = -b / (2.0d * a);
}
- } else if (b != 0.0f) {
+ } else if (b != 0.0d) {
zeroes[ret++] = -c / b;
}
return ret - off;
}
// find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
- static int cubicRootsInAB(final float d0, float a0, float b0, float c0,
- final float[] pts, final int off,
- final float A, final float B)
+ static int cubicRootsInAB(final double d, double a, double b, double c,
+ final double[] pts, final int off,
+ final double A, final double B)
{
- if (d0 == 0.0f) {
- final int num = quadraticRoots(a0, b0, c0, pts, off);
+ if (d == 0.0d) {
+ final int num = quadraticRoots(a, b, c, pts, off);
return filterOutNotInAB(pts, off, num, A, B) - off;
}
// From Graphics Gems:
@@ -133,11 +131,9 @@ static int cubicRootsInAB(final float d0, float a0, float b0, float c0,
// our own customized version).
// normal form: x^3 + ax^2 + bx + c = 0
-
- // 2018.1: Need double precision if d is very small (flat curve) !
- final double a = ((double)a0) / d0;
- final double b = ((double)b0) / d0;
- final double c = ((double)c0) / d0;
+ a /= d;
+ b /= d;
+ c /= d;
// substitute x = y - A/3 to eliminate quadratic term:
// x^3 +Px + Q = 0
@@ -158,41 +154,41 @@ static int cubicRootsInAB(final float d0, float a0, float b0, float c0,
int num;
- if (DHelpers.within(D, 0.0d)) {
- if (DHelpers.within(q, 0.0d)) {
+ if (within(D, 0.0d)) {
+ if (within(q, 0.0d)) {
/* one triple solution */
- pts[off ] = (float) (- sub);
+ pts[off ] = (- sub);
num = 1;
} else {
/* one single and one double solution */
- final double u = FastMath.cbrt(-q);
- pts[off ] = (float) (2.0d * u - sub);
- pts[off + 1] = (float) (- u - sub);
+ final double u = Math.cbrt(-q);
+ pts[off ] = (2.0d * u - sub);
+ pts[off + 1] = (- u - sub);
num = 2;
}
} else if (D < 0.0d) {
// see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
- final double phi = (1.0d / 3.0d) * FastMath.acos(-q / Math.sqrt(-cb_p));
+ final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
final double t = 2.0d * Math.sqrt(-p);
- pts[off ] = (float) ( t * FastMath.cos(phi) - sub);
- pts[off + 1] = (float) (-t * FastMath.cos(phi + (Math.PI / 3.0d)) - sub);
- pts[off + 2] = (float) (-t * FastMath.cos(phi - (Math.PI / 3.0d)) - sub);
+ pts[off ] = ( t * Math.cos(phi) - sub);
+ pts[off + 1] = (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
+ pts[off + 2] = (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
num = 3;
} else {
final double sqrt_D = Math.sqrt(D);
- final double u = FastMath.cbrt(sqrt_D - q);
- final double v = - FastMath.cbrt(sqrt_D + q);
+ final double u = Math.cbrt(sqrt_D - q);
+ final double v = - Math.cbrt(sqrt_D + q);
- pts[off ] = (float) (u + v - sub);
+ pts[off ] = (u + v - sub);
num = 1;
}
return filterOutNotInAB(pts, off, num, A, B) - off;
}
// returns the index 1 past the last valid element remaining after filtering
- static int filterOutNotInAB(final float[] nums, final int off, final int len,
- final float a, final float b)
+ static int filterOutNotInAB(final double[] nums, final int off, final int len,
+ final double a, final double b)
{
int ret = off;
for (int i = off, end = off + len; i < end; i++) {
@@ -203,105 +199,104 @@ static int filterOutNotInAB(final float[] nums, final int off, final int len,
return ret;
}
- static float fastLineLen(final float x0, final float y0,
- final float x1, final float y1)
+ static double fastLineLen(final double x0, final double y0,
+ final double x1, final double y1)
{
- final float dx = x1 - x0;
- final float dy = y1 - y0;
+ final double dx = x1 - x0;
+ final double dy = y1 - y0;
// use manhattan norm:
return Math.abs(dx) + Math.abs(dy);
}
- static float linelen(final float x0, final float y0,
- final float x1, final float y1)
+ static double linelen(final double x0, final double y0,
+ final double x1, final double y1)
{
- final float dx = x1 - x0;
- final float dy = y1 - y0;
- return (float) Math.sqrt(dx * dx + dy * dy);
+ final double dx = x1 - x0;
+ final double dy = y1 - y0;
+ return Math.sqrt(dx * dx + dy * dy);
}
- static float fastQuadLen(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2)
+ static double fastQuadLen(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2)
{
- final float dx1 = x1 - x0;
- final float dx2 = x2 - x1;
- final float dy1 = y1 - y0;
- final float dy2 = y2 - y1;
+ final double dx1 = x1 - x0;
+ final double dx2 = x2 - x1;
+ final double dy1 = y1 - y0;
+ final double dy2 = y2 - y1;
// use manhattan norm:
return Math.abs(dx1) + Math.abs(dx2)
+ Math.abs(dy1) + Math.abs(dy2);
}
- static float quadlen(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2)
+ static double quadlen(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2)
{
return (linelen(x0, y0, x1, y1)
+ linelen(x1, y1, x2, y2)
- + linelen(x0, y0, x2, y2)) / 2.0f;
+ + linelen(x0, y0, x2, y2)) / 2.0d;
}
-
- static float fastCurvelen(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ static double fastCurvelen(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
- final float dx1 = x1 - x0;
- final float dx2 = x2 - x1;
- final float dx3 = x3 - x2;
- final float dy1 = y1 - y0;
- final float dy2 = y2 - y1;
- final float dy3 = y3 - y2;
+ final double dx1 = x1 - x0;
+ final double dx2 = x2 - x1;
+ final double dx3 = x3 - x2;
+ final double dy1 = y1 - y0;
+ final double dy2 = y2 - y1;
+ final double dy3 = y3 - y2;
// use manhattan norm:
return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
+ Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
}
- static float curvelen(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ static double curvelen(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
return (linelen(x0, y0, x1, y1)
+ linelen(x1, y1, x2, y2)
+ linelen(x2, y2, x3, y3)
- + linelen(x0, y0, x3, y3)) / 2.0f;
+ + linelen(x0, y0, x3, y3)) / 2.0d;
}
// 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.
- static int findSubdivPoints(final Curve c, final float[] pts,
- final float[] ts, final int type,
- final float w2)
+ static int findSubdivPoints(final Curve c, final double[] pts,
+ final double[] ts, final int type,
+ final double w2)
{
- final float x12 = pts[2] - pts[0];
- final float y12 = pts[3] - pts[1];
+ final double x12 = pts[2] - pts[0];
+ final double 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)) {
+ if ((y12 != 0.0d) && (x12 != 0.0d)) {
// 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];
+ final double hypot = Math.sqrt(x12 * x12 + y12 * y12);
+ final double cos = x12 / hypot;
+ final double sin = y12 / hypot;
+ final double x1 = cos * pts[0] + sin * pts[1];
+ final double y1 = cos * pts[1] - sin * pts[0];
+ final double x2 = cos * pts[2] + sin * pts[3];
+ final double y2 = cos * pts[3] - sin * pts[2];
+ final double x3 = cos * pts[4] + sin * pts[5];
+ final double 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];
+ final double x4 = cos * pts[6] + sin * pts[7];
+ final double y4 = cos * pts[7] - sin * pts[6];
c.set(x1, y1, x2, y2, x3, y3, x4, y4);
break;
case 6:
@@ -327,9 +322,9 @@ static int findSubdivPoints(final Curve c, final float[] pts,
// 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, w2, 0.0001f);
+ ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d);
- ret = filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
+ ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d);
isort(ts, ret);
return ret;
}
@@ -337,10 +332,10 @@ static int findSubdivPoints(final Curve c, final float[] pts,
// finds values of t where the curve in pts should be subdivided in order
// to get intersections with the given clip rectangle.
// Stores the points in ts, and returns how many of them there were.
- static int findClipPoints(final Curve curve, final float[] pts,
- final float[] ts, final int type,
+ static int findClipPoints(final Curve curve, final double[] pts,
+ final double[] ts, final int type,
final int outCodeOR,
- final float[] clipRect)
+ final double[] clipRect)
{
curve.set(pts, type);
@@ -363,8 +358,8 @@ static int findClipPoints(final Curve curve, final float[] pts,
return ret;
}
- static void subdivide(final float[] src,
- final float[] left, final float[] right,
+ static void subdivide(final double[] src,
+ final double[] left, final double[] right,
final int type)
{
switch(type) {
@@ -379,9 +374,9 @@ static void subdivide(final float[] src,
}
}
- static void isort(final float[] a, final int len) {
+ static void isort(final double[] a, final int len) {
for (int i = 1, j; i < len; i++) {
- final float ai = a[i];
+ final double ai = a[i];
j = i - 1;
for (; j >= 0 && a[j] > ai; j--) {
a[j + 1] = a[j];
@@ -415,18 +410,18 @@ static void isort(final float[] a, final int len) {
* half of the subdivided curve
* @since 1.7
*/
- static void subdivideCubic(final float[] src,
- final float[] left,
- final float[] right)
+ static void subdivideCubic(final double[] src,
+ final double[] left,
+ final double[] right)
{
- float x1 = src[0];
- float y1 = src[1];
- float cx1 = src[2];
- float cy1 = src[3];
- float cx2 = src[4];
- float cy2 = src[5];
- float x2 = src[6];
- float y2 = src[7];
+ double x1 = src[0];
+ double y1 = src[1];
+ double cx1 = src[2];
+ double cy1 = src[3];
+ double cx2 = src[4];
+ double cy2 = src[5];
+ double x2 = src[6];
+ double y2 = src[7];
left[0] = x1;
left[1] = y1;
@@ -434,20 +429,20 @@ static void subdivideCubic(final float[] src,
right[6] = x2;
right[7] = y2;
- x1 = (x1 + cx1) / 2.0f;
- y1 = (y1 + cy1) / 2.0f;
- x2 = (x2 + cx2) / 2.0f;
- y2 = (y2 + cy2) / 2.0f;
+ x1 = (x1 + cx1) / 2.0d;
+ y1 = (y1 + cy1) / 2.0d;
+ x2 = (x2 + cx2) / 2.0d;
+ y2 = (y2 + cy2) / 2.0d;
- float cx = (cx1 + cx2) / 2.0f;
- float cy = (cy1 + cy2) / 2.0f;
+ double cx = (cx1 + cx2) / 2.0d;
+ double cy = (cy1 + cy2) / 2.0d;
- cx1 = (x1 + cx) / 2.0f;
- cy1 = (y1 + cy) / 2.0f;
- cx2 = (x2 + cx) / 2.0f;
- cy2 = (y2 + cy) / 2.0f;
- cx = (cx1 + cx2) / 2.0f;
- cy = (cy1 + cy2) / 2.0f;
+ cx1 = (x1 + cx) / 2.0d;
+ cy1 = (y1 + cy) / 2.0d;
+ cx2 = (x2 + cx) / 2.0d;
+ cy2 = (y2 + cy) / 2.0d;
+ cx = (cx1 + cx2) / 2.0d;
+ cy = (cy1 + cy2) / 2.0d;
left[2] = x1;
left[3] = y1;
@@ -464,18 +459,18 @@ static void subdivideCubic(final float[] src,
right[5] = y2;
}
- static void subdivideCubicAt(final float t,
- final float[] src, final int offS,
- final float[] pts, final int offL, final int offR)
+ static void subdivideCubicAt(final double t,
+ final double[] src, final int offS,
+ final double[] pts, final int offL, final int offR)
{
- float x1 = src[offS ];
- float y1 = src[offS + 1];
- float cx1 = src[offS + 2];
- float cy1 = src[offS + 3];
- float cx2 = src[offS + 4];
- float cy2 = src[offS + 5];
- float x2 = src[offS + 6];
- float y2 = src[offS + 7];
+ double x1 = src[offS ];
+ double y1 = src[offS + 1];
+ double cx1 = src[offS + 2];
+ double cy1 = src[offS + 3];
+ double cx2 = src[offS + 4];
+ double cy2 = src[offS + 5];
+ double x2 = src[offS + 6];
+ double y2 = src[offS + 7];
pts[offL ] = x1;
pts[offL + 1] = y1;
@@ -488,8 +483,8 @@ static void subdivideCubicAt(final float t,
x2 = cx2 + t * (x2 - cx2);
y2 = cy2 + t * (y2 - cy2);
- float cx = cx1 + t * (cx2 - cx1);
- float cy = cy1 + t * (cy2 - cy1);
+ double cx = cx1 + t * (cx2 - cx1);
+ double cy = cy1 + t * (cy2 - cy1);
cx1 = x1 + t * (cx - x1);
cy1 = y1 + t * (cy - y1);
@@ -513,16 +508,16 @@ static void subdivideCubicAt(final float t,
pts[offR + 5] = y2;
}
- static void subdivideQuad(final float[] src,
- final float[] left,
- final float[] right)
+ static void subdivideQuad(final double[] src,
+ final double[] left,
+ final double[] right)
{
- float x1 = src[0];
- float y1 = src[1];
- float cx = src[2];
- float cy = src[3];
- float x2 = src[4];
- float y2 = src[5];
+ double x1 = src[0];
+ double y1 = src[1];
+ double cx = src[2];
+ double cy = src[3];
+ double x2 = src[4];
+ double y2 = src[5];
left[0] = x1;
left[1] = y1;
@@ -530,12 +525,12 @@ static void subdivideQuad(final float[] src,
right[4] = x2;
right[5] = y2;
- x1 = (x1 + cx) / 2.0f;
- y1 = (y1 + cy) / 2.0f;
- x2 = (x2 + cx) / 2.0f;
- y2 = (y2 + cy) / 2.0f;
- cx = (x1 + x2) / 2.0f;
- cy = (y1 + y2) / 2.0f;
+ x1 = (x1 + cx) / 2.0d;
+ y1 = (y1 + cy) / 2.0d;
+ x2 = (x2 + cx) / 2.0d;
+ y2 = (y2 + cy) / 2.0d;
+ cx = (x1 + x2) / 2.0d;
+ cy = (y1 + y2) / 2.0d;
left[2] = x1;
left[3] = y1;
@@ -548,16 +543,16 @@ static void subdivideQuad(final float[] src,
right[3] = y2;
}
- static void subdivideQuadAt(final float t,
- final float[] src, final int offS,
- final float[] pts, final int offL, final int offR)
+ static void subdivideQuadAt(final double t,
+ final double[] src, final int offS,
+ final double[] pts, final int offL, final int offR)
{
- float x1 = src[offS ];
- float y1 = src[offS + 1];
- float cx = src[offS + 2];
- float cy = src[offS + 3];
- float x2 = src[offS + 4];
- float y2 = src[offS + 5];
+ double x1 = src[offS ];
+ double y1 = src[offS + 1];
+ double cx = src[offS + 2];
+ double cy = src[offS + 3];
+ double x2 = src[offS + 4];
+ double y2 = src[offS + 5];
pts[offL ] = x1;
pts[offL + 1] = y1;
@@ -583,14 +578,14 @@ static void subdivideQuadAt(final float t,
pts[offR + 3] = y2;
}
- static void subdivideLineAt(final float t,
- final float[] src, final int offS,
- final float[] pts, final int offL, final int offR)
+ static void subdivideLineAt(final double t,
+ final double[] src, final int offS,
+ final double[] pts, final int offL, final int offR)
{
- float x1 = src[offS ];
- float y1 = src[offS + 1];
- float x2 = src[offS + 2];
- float y2 = src[offS + 3];
+ double x1 = src[offS ];
+ double y1 = src[offS + 1];
+ double x2 = src[offS + 2];
+ double y2 = src[offS + 3];
pts[offL ] = x1;
pts[offL + 1] = y1;
@@ -608,9 +603,9 @@ static void subdivideLineAt(final float t,
pts[offR + 1] = y1;
}
- static void subdivideAt(final float t,
- final float[] src, final int offS,
- final float[] pts, final int offL, final int type)
+ static void subdivideAt(final double t,
+ final double[] src, final int offS,
+ final double[] pts, final int offL, final int type)
{
// if instead of switch (perf + most probable cases first)
if (type == 8) {
@@ -624,8 +619,8 @@ static void subdivideAt(final float t,
// From sun.java2d.loops.GeneralRenderer:
- static int outcode(final float x, final float y,
- final float[] clipRect)
+ static int outcode(final double x, final double y,
+ final double[] clipRect)
{
int code;
if (y < clipRect[0]) {
@@ -656,13 +651,13 @@ static final class PolyStack {
// types capacity = edges count (4096)
private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT;
- float[] curves;
+ double[] curves;
int end;
byte[] curveTypes;
int numCurves;
// curves ref (dirty)
- final ArrayCacheFloat.Reference curves_ref;
+ final ArrayCacheDouble.Reference curves_ref;
// curveTypes ref (dirty)
final ArrayCacheByte.Reference curveTypes_ref;
@@ -687,7 +682,7 @@ static final class PolyStack {
final StatLong stat_array_polystack_curves,
final StatLong stat_array_polystack_curveTypes)
{
- curves_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_CURVES_COUNT); // 32K
+ curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K
curves = curves_ref.initial;
curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K
@@ -752,14 +747,14 @@ private void ensureSpace(final int n) {
}
}
- void pushCubic(float x0, float y0,
- float x1, float y1,
- float x2, float y2)
+ void pushCubic(double x0, double y0,
+ double x1, double y1,
+ double x2, double y2)
{
ensureSpace(6);
curveTypes[numCurves++] = TYPE_CUBICTO;
// we reverse the coordinate order to make popping easier
- final float[] _curves = curves;
+ final double[] _curves = curves;
int e = end;
_curves[e++] = x2; _curves[e++] = y2;
_curves[e++] = x1; _curves[e++] = y1;
@@ -767,25 +762,25 @@ void pushCubic(float x0, float y0,
end = e;
}
- void pushQuad(float x0, float y0,
- float x1, float y1)
+ void pushQuad(double x0, double y0,
+ double x1, double y1)
{
ensureSpace(4);
curveTypes[numCurves++] = TYPE_QUADTO;
- final float[] _curves = curves;
+ final double[] _curves = curves;
int e = end;
_curves[e++] = x1; _curves[e++] = y1;
_curves[e++] = x0; _curves[e++] = y0;
end = e;
}
- void pushLine(float x, float y) {
+ void pushLine(double x, double y) {
ensureSpace(2);
curveTypes[numCurves++] = TYPE_LINETO;
curves[end++] = x; curves[end++] = y;
}
- void pullAll(final PathConsumer2D io) {
+ void pullAll(final DPathConsumer2D io) {
final int nc = numCurves;
if (nc == 0) {
return;
@@ -800,7 +795,7 @@ void pullAll(final PathConsumer2D io) {
}
}
final byte[] _curveTypes = curveTypes;
- final float[] _curves = curves;
+ final double[] _curves = curves;
int e = 0;
for (int i = 0; i < nc; i++) {
@@ -827,7 +822,7 @@ void pullAll(final PathConsumer2D io) {
end = 0;
}
- void popAll(final PathConsumer2D io) {
+ void popAll(final DPathConsumer2D io) {
int nc = numCurves;
if (nc == 0) {
return;
@@ -842,7 +837,7 @@ void popAll(final PathConsumer2D io) {
}
}
final byte[] _curveTypes = curveTypes;
- final float[] _curves = curves;
+ final double[] _curves = curves;
int e = end;
while (nc != 0) {
@@ -997,7 +992,7 @@ void push(final int v) {
}
}
- void pullAll(final float[] points, final PathConsumer2D io,
+ void pullAll(final double[] points, final DPathConsumer2D io,
final boolean moveFirst)
{
final int nc = end;
diff --git a/src/main/java/sun/java2d/marlin/IRendererContext.java b/src/main/java/sun/java2d/marlin/IRendererContext.java
deleted file mode 100644
index 7dd58dd..0000000
--- a/src/main/java/sun/java2d/marlin/IRendererContext.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2017, 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.marlin;
-
-interface IRendererContext extends MarlinConst {
-
- public RendererStats stats();
-
- public OffHeapArray newOffHeapArray(final long initialSize);
-
- public ArrayCacheIntClean.Reference newCleanIntArrayRef(final int initialSize);
-
-}
diff --git a/src/main/java/sun/java2d/marlin/MarlinCache.java b/src/main/java/sun/java2d/marlin/MarlinCache.java
index 5b9ae76..e9ffbd0 100644
--- a/src/main/java/sun/java2d/marlin/MarlinCache.java
+++ b/src/main/java/sun/java2d/marlin/MarlinCache.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -107,7 +107,7 @@ public final class MarlinCache implements MarlinConst {
boolean useRLE = false;
- MarlinCache(final IRendererContext rdrCtx) {
+ MarlinCache(final RendererContext rdrCtx) {
this.rdrStats = rdrCtx.stats();
rowAAChunk = rdrCtx.newOffHeapArray(INITIAL_CHUNK_ARRAY); // 64K
diff --git a/src/main/java/sun/java2d/marlin/MarlinProperties.java b/src/main/java/sun/java2d/marlin/MarlinProperties.java
index 4ffee64..65b3dfd 100644
--- a/src/main/java/sun/java2d/marlin/MarlinProperties.java
+++ b/src/main/java/sun/java2d/marlin/MarlinProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -317,6 +317,7 @@ public static boolean isLogUnsafeMalloc() {
}
// quality settings
+
public static float getCurveLengthError() {
return getFloat("sun.java2d.renderer.curve_len_err", 0.01f, 1e-6f, 1.0f);
}
@@ -343,7 +344,7 @@ static String getString(final String key, final String def) {
}
static boolean getBoolean(final String key, final String def) {
- return Boolean.valueOf(AccessController.doPrivileged(
+ return Boolean.parseBoolean(AccessController.doPrivileged(
new GetPropertyAction(key, def)));
}
diff --git a/src/main/java/sun/java2d/marlin/MarlinRenderer.java b/src/main/java/sun/java2d/marlin/MarlinRenderer.java
deleted file mode 100644
index 8b4e751..0000000
--- a/src/main/java/sun/java2d/marlin/MarlinRenderer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2017, 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.marlin;
-
-public interface MarlinRenderer extends MarlinConst {
-
-}
diff --git a/src/main/java/sun/java2d/marlin/MarlinRenderingEngine.java b/src/main/java/sun/java2d/marlin/MarlinRenderingEngine.java
deleted file mode 100644
index cea94e2..0000000
--- a/src/main/java/sun/java2d/marlin/MarlinRenderingEngine.java
+++ /dev/null
@@ -1,1227 +0,0 @@
-/*
- * 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
- * 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.marlin;
-
-import java.awt.BasicStroke;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
-import java.security.AccessController;
-import java.util.Arrays;
-import static sun.java2d.marlin.MarlinUtils.logInfo;
-import sun.awt.geom.PathConsumer2D;
-import sun.java2d.ReentrantContextProvider;
-import sun.java2d.ReentrantContextProviderCLQ;
-import sun.java2d.ReentrantContextProviderTL;
-import sun.java2d.pipe.AATileGenerator;
-import sun.java2d.pipe.Region;
-import sun.java2d.pipe.RenderingEngine;
-import sun.security.action.GetPropertyAction;
-
-/**
- * Marlin RendererEngine implementation (derived from Pisces)
- */
-public final class MarlinRenderingEngine extends RenderingEngine
- implements MarlinConst
-{
- // slightly slower ~2% if enabled stroker clipping (lines) but skipping cap / join handling is few percents faster in specific cases
- static final boolean DISABLE_2ND_STROKER_CLIPPING = true;
-
- static final boolean DO_TRACE_PATH = false;
-
- static final boolean DO_CLIP = MarlinProperties.isDoClip();
- static final boolean DO_CLIP_FILL = true;
- static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag();
-
- private static final float MIN_PEN_SIZE = 1.0f / MIN_SUBPIXELS;
-
- static final float UPPER_BND = Float.MAX_VALUE / 2.0f;
- static final float LOWER_BND = -UPPER_BND;
-
- private enum NormMode {
- ON_WITH_AA {
- @Override
- PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
- final PathIterator src)
- {
- // NormalizingPathIterator NearestPixelCenter:
- return rdrCtx.nPCPathIterator.init(src);
- }
- },
- ON_NO_AA{
- @Override
- PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
- final PathIterator src)
- {
- // NearestPixel NormalizingPathIterator:
- return rdrCtx.nPQPathIterator.init(src);
- }
- },
- OFF{
- @Override
- PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
- final PathIterator src)
- {
- // return original path iterator if normalization is disabled:
- return src;
- }
- };
-
- abstract PathIterator getNormalizingPathIterator(RendererContext rdrCtx,
- PathIterator src);
- }
-
- /**
- * Public constructor
- */
- public MarlinRenderingEngine() {
- super();
- logSettings(MarlinRenderingEngine.class.getName());
- }
-
- /**
- * Create a widened path as specified by the parameters.
- *
- * for (y = bbox[1]; y < bbox[3]; y += tileheight) {
- * for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
- * }
- * }
- *
- * If there is no output to be rendered, this method may return
- * null.
- *
- * @param s the shape to be rendered (fill or draw)
- * @param at the transform to be applied to the shape and the
- * stroke attributes
- * @param clip the current clip in effect in device coordinates
- * @param bs if non-null, a {@code BasicStroke} whose attributes
- * should be applied to this operation
- * @param thin true if the transformed stroke attributes are smaller
- * than the minimum dropout pen width
- * @param normalize true if the {@code VALUE_STROKE_NORMALIZE}
- * {@code RenderingHint} is in effect
- * @param bbox returns the bounds of the iteration
- * @return the {@code AATileGenerator} instance to be consulted
- * for tile coverages, or null if there is no output to render
- * @since 1.7
- */
- @Override
- public AATileGenerator getAATileGenerator(Shape s,
- AffineTransform at,
- Region clip,
- BasicStroke bs,
- boolean thin,
- boolean normalize,
- int[] bbox)
- {
- MarlinTileGenerator ptg = null;
- Renderer r = null;
-
- final RendererContext rdrCtx = getRendererContext();
- try {
- if (DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime())) {
- // Define the initial clip bounds:
- final float[] clipRect = rdrCtx.clipRect;
-
- // Adjust the clipping rectangle with the renderer offsets
- final float rdrOffX = Renderer.RDR_OFFSET_X;
- final float rdrOffY = Renderer.RDR_OFFSET_Y;
-
- // add a small rounding error:
- final float margin = 1e-3f;
-
- clipRect[0] = clip.getLoY()
- - margin + rdrOffY;
- clipRect[1] = clip.getLoY() + clip.getHeight()
- + margin + rdrOffY;
- clipRect[2] = clip.getLoX()
- - margin + rdrOffX;
- clipRect[3] = clip.getLoX() + clip.getWidth()
- + margin + rdrOffX;
-
- if (MarlinConst.DO_LOG_CLIP) {
- MarlinUtils.logInfo("clipRect (clip): "
- + Arrays.toString(rdrCtx.clipRect));
- }
-
- // Enable clipping:
- rdrCtx.doClip = true;
- }
-
- // Test if at is identity:
- final AffineTransform _at = (at != null && !at.isIdentity()) ? at
- : null;
-
- final NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
-
- if (bs == null) {
- // fill shape:
- final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx,
- s.getPathIterator(_at));
-
- // note: Winding rule may be EvenOdd ONLY for fill operations !
- r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
- clip.getWidth(), clip.getHeight(),
- pi.getWindingRule());
-
- PathConsumer2D 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);
- }
- pathTo(rdrCtx, pi, pc2d);
-
- } else {
- // draw shape with given stroke:
- r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
- clip.getWidth(), clip.getHeight(),
- WIND_NON_ZERO);
-
- strokeTo(rdrCtx, s, _at, bs, thin, norm, true, r);
- }
- if (r.endRendering()) {
- ptg = rdrCtx.ptg.init();
- ptg.getBbox(bbox);
- // note: do not returnRendererContext(rdrCtx)
- // as it will be called later by MarlinTileGenerator.dispose()
- r = null;
- }
- } finally {
- if (r != null) {
- // dispose renderer and recycle the RendererContext instance:
- r.dispose();
- }
- }
-
- // Return null to cancel AA tile generation (nothing to render)
- return ptg;
- }
-
- @Override
- 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;
- boolean innerpgram = (lw1 > 0.0d && lw2 > 0.0d);
-
- if (innerpgram) {
- ldx1 = dx1 * lw1;
- ldy1 = dy1 * lw1;
- ldx2 = dx2 * lw2;
- ldy2 = dy2 * lw2;
- x -= (ldx1 + ldx2) / 2.0d;
- y -= (ldy1 + ldy2) / 2.0d;
- dx1 += ldx1;
- dy1 += ldy1;
- dx2 += ldx2;
- dy2 += ldy2;
- if (lw1 > 1.0d && lw2 > 1.0d) {
- // Inner parallelogram was entirely consumed by stroke...
- innerpgram = false;
- }
- } else {
- ldx1 = ldy1 = ldx2 = ldy2 = 0.0d;
- }
-
- MarlinTileGenerator ptg = null;
- Renderer r = null;
-
- final RendererContext rdrCtx = getRendererContext();
- try {
- r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
- clip.getWidth(), clip.getHeight(),
- WIND_EVEN_ODD);
-
- r.moveTo((float) x, (float) y);
- r.lineTo((float) (x+dx1), (float) (y+dy1));
- r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
- r.lineTo((float) (x+dx2), (float) (y+dy2));
- r.closePath();
-
- if (innerpgram) {
- x += ldx1 + ldx2;
- y += ldy1 + ldy2;
- dx1 -= 2.0d * ldx1;
- dy1 -= 2.0d * ldy1;
- dx2 -= 2.0d * ldx2;
- dy2 -= 2.0d * ldy2;
- r.moveTo((float) x, (float) y);
- r.lineTo((float) (x+dx1), (float) (y+dy1));
- r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
- r.lineTo((float) (x+dx2), (float) (y+dy2));
- r.closePath();
- }
- r.pathDone();
-
- if (r.endRendering()) {
- ptg = rdrCtx.ptg.init();
- ptg.getBbox(bbox);
- // note: do not returnRendererContext(rdrCtx)
- // as it will be called later by MarlinTileGenerator.dispose()
- r = null;
- }
- } finally {
- if (r != null) {
- // dispose renderer and recycle the RendererContext instance:
- r.dispose();
- }
- }
-
- // Return null to cancel AA tile generation (nothing to render)
- return ptg;
- }
-
- /**
- * Returns the minimum pen width that the antialiasing rasterizer
- * can represent without dropouts occuring.
- * @since 1.7
- */
- @Override
- public float getMinimumAAPenSize() {
- return MIN_PEN_SIZE;
- }
-
- static {
- 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");
- }
- }
-
- // --- RendererContext handling ---
- // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext
- private static final boolean USE_THREAD_LOCAL;
-
- // reference type stored in either TL or CLQ
- static final int REF_TYPE;
-
- // Per-thread RendererContext
- private static final ReentrantContextProviderStroker
.
*
- * @param pc2d an output PathConsumer2D
.
+ * @param pc2d an output DPathConsumer2D
.
* @param lineWidth the desired line width in pixels
* @param capStyle the desired end cap style, one of
* CAP_BUTT
, CAP_ROUND
or
@@ -145,25 +143,25 @@ final class Stroker implements PathConsumer2D, MarlinConst {
* @param subdivideCurves true to indicate to subdivide curves, false if dasher does
* @return this instance
*/
- Stroker init(final PathConsumer2D pc2d,
- final float lineWidth,
- final int capStyle,
- final int joinStyle,
- final float miterLimit,
- final boolean subdivideCurves)
+ Stroker init(final DPathConsumer2D pc2d,
+ final double lineWidth,
+ final int capStyle,
+ final int joinStyle,
+ final double miterLimit,
+ final boolean subdivideCurves)
{
if (this.out != pc2d) {
this.out = pc2d;
}
- this.lineWidth2 = lineWidth / 2.0f;
- this.invHalfLineWidth2Sq = 1.0f / (2.0f * lineWidth2 * lineWidth2);
+ this.lineWidth2 = lineWidth / 2.0d;
+ this.invHalfLineWidth2Sq = 1.0d / (2.0d * lineWidth2 * lineWidth2);
this.monotonize = subdivideCurves;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
- final float limit = miterLimit * lineWidth2;
+ final double limit = miterLimit * lineWidth2;
this.miterLimitSq = limit * limit;
this.prev = CLOSE;
@@ -172,7 +170,7 @@ Stroker init(final PathConsumer2D pc2d,
if (rdrCtx.doClip) {
// Adjust the clipping rectangle with the stroker margin (miter limit, width)
- float margin = lineWidth2;
+ double margin = lineWidth2;
if (capStyle == CAP_SQUARE) {
margin *= SQRT_2;
@@ -183,7 +181,7 @@ Stroker init(final PathConsumer2D pc2d,
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
- final float[] _clipRect = rdrCtx.clipRect;
+ final double[] _clipRect = rdrCtx.clipRect;
_clipRect[0] -= margin;
_clipRect[1] += margin;
_clipRect[2] -= margin;
@@ -229,24 +227,24 @@ void dispose() {
if (DO_CLEAN_DIRTY) {
// Force zero-fill dirty arrays:
- Arrays.fill(offset0, 0.0f);
- Arrays.fill(offset1, 0.0f);
- Arrays.fill(offset2, 0.0f);
- Arrays.fill(miter, 0.0f);
- Arrays.fill(lp, 0.0f);
- Arrays.fill(rp, 0.0f);
+ Arrays.fill(offset0, 0.0d);
+ Arrays.fill(offset1, 0.0d);
+ Arrays.fill(offset2, 0.0d);
+ Arrays.fill(miter, 0.0d);
+ Arrays.fill(lp, 0.0d);
+ Arrays.fill(rp, 0.0d);
}
}
- private static void computeOffset(final float lx, final float ly,
- final float w, final float[] m)
+ private static void computeOffset(final double lx, final double ly,
+ final double w, final double[] m)
{
- float len = lx*lx + ly*ly;
- if (len == 0.0f) {
- m[0] = 0.0f;
- m[1] = 0.0f;
+ double len = lx*lx + ly*ly;
+ if (len == 0.0d) {
+ m[0] = 0.0d;
+ m[1] = 0.0d;
} else {
- len = (float) Math.sqrt(len);
+ len = Math.sqrt(len);
m[0] = (ly * w) / len;
m[1] = -(lx * w) / len;
}
@@ -260,24 +258,24 @@ private static void computeOffset(final float lx, final float ly,
// q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
// clockwise order.
// NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
- private static boolean isCW(final float dx1, final float dy1,
- final float dx2, final float dy2)
+ private static boolean isCW(final double dx1, final double dy1,
+ final double dx2, final double dy2)
{
return dx1 * dy2 <= dy1 * dx2;
}
- private void mayDrawRoundJoin(float cx, float cy,
- float omx, float omy,
- float mx, float my,
+ private void mayDrawRoundJoin(double cx, double cy,
+ double omx, double omy,
+ double mx, double my,
boolean rev)
{
- if ((omx == 0.0f && omy == 0.0f) || (mx == 0.0f && my == 0.0f)) {
+ if ((omx == 0.0d && omy == 0.0d) || (mx == 0.0d && my == 0.0d)) {
return;
}
- final float domx = omx - mx;
- final float domy = omy - my;
- final float lenSq = domx*domx + domy*domy;
+ final double domx = omx - mx;
+ final double domy = omy - my;
+ final double lenSq = domx*domx + domy*domy;
if (lenSq < ROUND_JOIN_THRESHOLD) {
return;
@@ -292,19 +290,19 @@ private void mayDrawRoundJoin(float cx, float cy,
drawRoundJoin(cx, cy, omx, omy, mx, my, rev);
}
- private void drawRoundJoin(float cx, float cy,
- float omx, float omy,
- float mx, float my,
+ private void drawRoundJoin(double cx, double cy,
+ double omx, double omy,
+ double mx, double my,
boolean rev)
{
// The sign of the dot product of mx,my and omx,omy is equal to the
// the sign of the cosine of ext
// (ext is the angle between omx,omy and mx,my).
- final float cosext = omx * mx + omy * my;
+ final double cosext = omx * mx + omy * my;
// If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
// need 1 curve to approximate the circle section that joins omx,omy
// and mx,my.
- if (cosext >= 0.0f) {
+ if (cosext >= 0.0d) {
drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
} else {
// we need to split the arc into 2 arcs spanning the same angle.
@@ -321,10 +319,10 @@ private void drawRoundJoin(float cx, float cy,
// have numerical problems because we know that lineWidth2 divided by
// this normal's length is at least 0.5 and at most sqrt(2)/2 (because
// we know the angle of the arc is > 90 degrees).
- float nx = my - omy, ny = omx - mx;
- float nlen = (float) Math.sqrt(nx*nx + ny*ny);
- float scale = lineWidth2/nlen;
- float mmx = nx * scale, mmy = ny * scale;
+ double nx = my - omy, ny = omx - mx;
+ double nlen = Math.sqrt(nx*nx + ny*ny);
+ double scale = lineWidth2/nlen;
+ double mmx = nx * scale, mmy = ny * scale;
// if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
// computed the wrong intersection so we get the other one.
@@ -339,16 +337,16 @@ private void drawRoundJoin(float cx, float cy,
}
// the input arc defined by omx,omy and mx,my must span <= 90 degrees.
- private void drawBezApproxForArc(final float cx, final float cy,
- final float omx, final float omy,
- final float mx, final float my,
+ private void drawBezApproxForArc(final double cx, final double cy,
+ final double omx, final double omy,
+ final double mx, final double my,
boolean rev)
{
- final float cosext2 = (omx * mx + omy * my) * invHalfLineWidth2Sq;
+ final double cosext2 = (omx * mx + omy * my) * invHalfLineWidth2Sq;
// check round off errors producing cos(ext) > 1 and a NaN below
// cos(ext) == 1 implies colinear segments and an empty join anyway
- if (cosext2 >= 0.5f) {
+ if (cosext2 >= 0.5d) {
// just return to avoid generating a flat curve:
return;
}
@@ -358,28 +356,28 @@ private void drawBezApproxForArc(final float cx, final float cy,
// define the bezier curve we're computing.
// It is computed using the constraints that P1-P0 and P3-P2 are parallel
// to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
- float cv = (float) ((4.0d / 3.0d) * Math.sqrt(0.5d - cosext2) /
+ double cv = ((4.0d / 3.0d) * Math.sqrt(0.5d - cosext2) /
(1.0d + Math.sqrt(cosext2 + 0.5d)));
// if clockwise, we need to negate cv.
if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
cv = -cv;
}
- final float x1 = cx + omx;
- final float y1 = cy + omy;
- final float x2 = x1 - cv * omy;
- final float y2 = y1 + cv * omx;
+ final double x1 = cx + omx;
+ final double y1 = cy + omy;
+ final double x2 = x1 - cv * omy;
+ final double y2 = y1 + cv * omx;
- final float x4 = cx + mx;
- final float y4 = cy + my;
- final float x3 = x4 + cv * my;
- final float y3 = y4 - cv * mx;
+ final double x4 = cx + mx;
+ final double y4 = cy + my;
+ final double x3 = x4 + cv * my;
+ final double y3 = y4 - cv * mx;
emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
}
- private void drawRoundCap(float cx, float cy, float mx, float my) {
- final float Cmx = C * mx;
- final float Cmy = C * my;
+ private void drawRoundCap(double cx, double cy, double mx, double my) {
+ final double Cmx = C * mx;
+ final double Cmy = C * my;
emitCurveTo(cx + mx - Cmy, cy + my + Cmx,
cx - my + Cmx, cy + mx + Cmy,
cx - my, cy + mx);
@@ -390,16 +388,16 @@ private void drawRoundCap(float cx, float cy, float mx, float my) {
// Return the intersection point of the lines (x0, y0) -> (x1, y1)
// and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
- private static void computeMiter(final float x0, final float y0,
- final float x1, final float y1,
- final float x0p, final float y0p,
- final float x1p, final float y1p,
- final float[] m)
+ private static void computeMiter(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x0p, final double y0p,
+ final double x1p, final double y1p,
+ final double[] m)
{
- float x10 = x1 - x0;
- float y10 = y1 - y0;
- float x10p = x1p - x0p;
- float y10p = y1p - y0p;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x10p = x1p - x0p;
+ double y10p = y1p - y0p;
// if this is 0, the lines are parallel. If they go in the
// same direction, there is no intersection so m[off] and
@@ -410,8 +408,8 @@ private static void computeMiter(final float x0, final float y0,
// miter drawing because it won't be called by drawMiter (because
// (mx == omx && my == omy) will be true, and drawMiter will return
// immediately).
- float den = x10*y10p - x10p*y10;
- float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ double den = x10*y10p - x10p*y10;
+ double t = x10p*(y0-y0p) - y10p*(x0-x0p);
t /= den;
m[0] = x0 + t*x10;
m[1] = y0 + t*y10;
@@ -419,16 +417,16 @@ private static void computeMiter(final float x0, final float y0,
// Return the intersection point of the lines (x0, y0) -> (x1, y1)
// and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
- private static void safeComputeMiter(final float x0, final float y0,
- final float x1, final float y1,
- final float x0p, final float y0p,
- final float x1p, final float y1p,
- final float[] m)
+ private static void safeComputeMiter(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x0p, final double y0p,
+ final double x1p, final double y1p,
+ final double[] m)
{
- float x10 = x1 - x0;
- float y10 = y1 - y0;
- float x10p = x1p - x0p;
- float y10p = y1p - y0p;
+ double x10 = x1 - x0;
+ double y10 = y1 - y0;
+ double x10p = x1p - x0p;
+ double y10p = y1p - y0p;
// if this is 0, the lines are parallel. If they go in the
// same direction, there is no intersection so m[off] and
@@ -439,28 +437,28 @@ private static void safeComputeMiter(final float x0, final float y0,
// miter drawing because it won't be called by drawMiter (because
// (mx == omx && my == omy) will be true, and drawMiter will return
// immediately).
- float den = x10*y10p - x10p*y10;
- if (den == 0.0f) {
- m[2] = (x0 + x0p) / 2.0f;
- m[3] = (y0 + y0p) / 2.0f;
+ double den = x10*y10p - x10p*y10;
+ if (den == 0.0d) {
+ m[2] = (x0 + x0p) / 2.0d;
+ m[3] = (y0 + y0p) / 2.0d;
} else {
- float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ double t = x10p*(y0-y0p) - y10p*(x0-x0p);
t /= den;
m[2] = x0 + t*x10;
m[3] = 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,
+ private void drawMiter(final double pdx, final double pdy,
+ final double x0, final double y0,
+ final double dx, final double dy,
+ double omx, double omy,
+ double mx, double my,
boolean rev)
{
if ((mx == omx && my == omy) ||
- (pdx == 0.0f && pdy == 0.0f) ||
- (dx == 0.0f && dy == 0.0f))
+ (pdx == 0.0d && pdy == 0.0d) ||
+ (dx == 0.0d && dy == 0.0d))
{
return;
}
@@ -475,9 +473,9 @@ private void drawMiter(final float pdx, final float pdy,
computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
(dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my, miter);
- final float miterX = miter[0];
- final float miterY = miter[1];
- float lenSq = (miterX-x0)*(miterX-x0) + (miterY-y0)*(miterY-y0);
+ final double miterX = miter[0];
+ final double miterY = miter[1];
+ double lenSq = (miterX-x0)*(miterX-x0) + (miterY-y0)*(miterY-y0);
// If the lines are parallel, lenSq will be either NaN or +inf
// (actually, I'm not sure if the latter is possible. The important
@@ -490,13 +488,13 @@ private void drawMiter(final float pdx, final float pdy,
}
@Override
- public void moveTo(final float x0, final float y0) {
+ public void moveTo(final double x0, final double y0) {
_moveTo(x0, y0, cOutCode);
// update starting point:
this.sx0 = x0;
this.sy0 = y0;
- this.sdx = 1.0f;
- this.sdy = 0.0f;
+ this.sdx = 1.0d;
+ this.sdy = 0.0d;
this.opened = false;
this.capStart = false;
@@ -507,7 +505,7 @@ public void moveTo(final float x0, final float y0) {
}
}
- private void _moveTo(final float x0, final float y0,
+ private void _moveTo(final double x0, final double y0,
final int outcode)
{
if (prev == MOVE_TO) {
@@ -520,13 +518,13 @@ private void _moveTo(final float x0, final float y0,
this.prev = MOVE_TO;
this.cx0 = x0;
this.cy0 = y0;
- this.cdx = 1.0f;
- this.cdy = 0.0f;
+ this.cdx = 1.0d;
+ this.cdy = 0.0d;
}
}
@Override
- public void lineTo(final float x1, final float y1) {
+ public void lineTo(final double x1, final double y1) {
final int outcode0 = this.cOutCode;
if (clipRect != null) {
@@ -564,14 +562,14 @@ public void lineTo(final float x1, final float y1) {
this.cOutCode = outcode1;
}
- float dx = x1 - cx0;
- float dy = y1 - cy0;
- if (dx == 0.0f && dy == 0.0f) {
- dx = 1.0f;
+ double dx = x1 - cx0;
+ double dy = y1 - cy0;
+ if (dx == 0.0d && dy == 0.0d) {
+ dx = 1.0d;
}
computeOffset(dx, dy, lineWidth2, offset0);
- final float mx = offset0[0];
- final float my = offset0[1];
+ final double mx = offset0[0];
+ final double my = offset0[1];
drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my, outcode0);
@@ -599,14 +597,14 @@ public void closePath() {
}
emitMoveTo(cx0, cy0 - lineWidth2);
- this.sdx = 1.0f;
- this.sdy = 0.0f;
- this.cdx = 1.0f;
- this.cdy = 0.0f;
+ this.sdx = 1.0d;
+ this.sdy = 0.0d;
+ this.cdx = 1.0d;
+ this.cdy = 0.0d;
- this.smx = 0.0f;
+ this.smx = 0.0d;
this.smy = -lineWidth2;
- this.cmx = 0.0f;
+ this.cmx = 0.0d;
this.cmy = -lineWidth2;
finish(cOutCode);
@@ -615,7 +613,7 @@ public void closePath() {
// basic acceptance criteria
if ((sOutCode & cOutCode) == 0) {
- if (cx0 != sx0 || cy0 != sy0) {
+ if ((cx0 != sx0) || (cy0 != sy0)) {
// may subdivide line:
lineTo(sx0, sy0);
}
@@ -705,19 +703,19 @@ private void finish(final int outcode) {
emitClose();
}
- private void emitMoveTo(final float x0, final float y0) {
+ private void emitMoveTo(final double x0, final double y0) {
out.moveTo(x0, y0);
}
- private void emitLineTo(final float x1, final float y1) {
+ private void emitLineTo(final double x1, final double y1) {
out.lineTo(x1, y1);
}
- private void emitLineToRev(final float x1, final float y1) {
+ private void emitLineToRev(final double x1, final double y1) {
reverse.pushLine(x1, y1);
}
- private void emitLineTo(final float x1, final float y1,
+ private void emitLineTo(final double x1, final double y1,
final boolean rev)
{
if (rev) {
@@ -727,36 +725,36 @@ private void emitLineTo(final float x1, final float y1,
}
}
- private void emitQuadTo(final float x1, final float y1,
- final float x2, final float y2)
+ private void emitQuadTo(final double x1, final double y1,
+ final double x2, final double y2)
{
out.quadTo(x1, y1, x2, y2);
}
- private void emitQuadToRev(final float x0, final float y0,
- final float x1, final float y1)
+ private void emitQuadToRev(final double x0, final double y0,
+ final double x1, final double y1)
{
reverse.pushQuad(x0, y0, x1, y1);
}
- private void emitCurveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ private void emitCurveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
out.curveTo(x1, y1, x2, y2, x3, y3);
}
- private void emitCurveToRev(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2)
+ private void emitCurveToRev(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2)
{
reverse.pushCubic(x0, y0, x1, y1, x2, y2);
}
- private void emitCurveTo(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3, final boolean rev)
+ private void emitCurveTo(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3, final boolean rev)
{
if (rev) {
reverse.pushCubic(x0, y0, x1, y1, x2, y2);
@@ -769,11 +767,11 @@ private void emitClose() {
out.closePath();
}
- private void drawJoin(float pdx, float pdy,
- float x0, float y0,
- float dx, float dy,
- float omx, float omy,
- float mx, float my,
+ private void drawJoin(double pdx, double pdy,
+ double x0, double y0,
+ double dx, double dy,
+ double omx, double omy,
+ double mx, double my,
final int outcode)
{
if (prev != DRAWING_OP_TO) {
@@ -800,17 +798,16 @@ private void drawJoin(float pdx, float pdy,
// reset trigger to process further joins (normal operations)
rdrCtx.isFirstSegment = true;
}
-
prev = DRAWING_OP_TO;
}
- private int getLineOffsets(final float x1, final float y1,
- final float x2, final float y2,
- final float[] left, final float[] right)
+ private int getLineOffsets(final double x1, final double y1,
+ final double x2, final double y2,
+ final double[] left, final double[] right)
{
computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
- final float mx = offset0[0];
- final float my = offset0[1];
+ final double mx = offset0[0];
+ final double my = offset0[1];
left[0] = x1 + mx;
left[1] = y1 + my;
left[2] = x2 + mx;
@@ -824,9 +821,9 @@ private int getLineOffsets(final float x1, final float y1,
return 4;
}
- private int computeOffsetCubic(final float[] pts, final int off,
- final float[] leftOff,
- final float[] rightOff)
+ private int computeOffsetCubic(final double[] pts, final int off,
+ final double[] leftOff,
+ final double[] rightOff)
{
// if p1=p2 or p3=p4 it means that the derivative at the endpoint
// vanishes, which creates problems with computeOffset. Usually
@@ -835,18 +832,18 @@ private int computeOffsetCubic(final float[] pts, final int off,
// 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 ]; final float y1 = pts[off + 1];
- final float x2 = pts[off + 2]; final float y2 = pts[off + 3];
- final float x3 = pts[off + 4]; final float y3 = pts[off + 5];
- final float x4 = pts[off + 6]; final float y4 = pts[off + 7];
+ final double x1 = pts[off ]; final double y1 = pts[off + 1];
+ final double x2 = pts[off + 2]; final double y2 = pts[off + 3];
+ final double x3 = pts[off + 4]; final double y3 = pts[off + 5];
+ final double x4 = pts[off + 6]; final double y4 = pts[off + 7];
- float dx1 = x2 - x1; float dy1 = y2 - y1;
- float dx4 = x4 - x3; float dy4 = y4 - y3;
+ double dx1 = x2 - x1; double dy1 = y2 - y1;
+ double dx4 = x4 - x3; double dy4 = y4 - y3;
// 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.0f * Math.ulp(y2));
- final boolean p3eqp4 = Helpers.withinD(dx4, dy4, 6.0f * Math.ulp(y4));
+ final boolean p1eqp2 = Helpers.withinD(dx1, dy1, 6.0d * Math.ulp(y2));
+ final boolean p3eqp4 = Helpers.withinD(dx4, dy4, 6.0d * Math.ulp(y4));
if (p1eqp2 && p3eqp4) {
return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
@@ -859,12 +856,12 @@ private int computeOffsetCubic(final float[] pts, final int off,
}
// if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
- float dotsq = (dx1 * dx4 + dy1 * dy4);
+ double dotsq = (dx1 * dx4 + dy1 * dy4);
dotsq *= dotsq;
- final float l1sq = dx1 * dx1 + dy1 * dy1;
- final float l4sq = dx4 * dx4 + dy4 * dy4;
+ final double l1sq = dx1 * dx1 + dy1 * dy1;
+ final double l4sq = dx4 * dx4 + dy4 * dy4;
- if (Helpers.within(dotsq, l1sq * l4sq, 4.0f * Math.ulp(dotsq))) {
+ if (Helpers.within(dotsq, l1sq * l4sq, 4.0d * Math.ulp(dotsq))) {
return getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
}
@@ -915,12 +912,12 @@ private int computeOffsetCubic(final float[] pts, final int off,
// getting the inverse of the matrix above. Then we use [c1,c2] to compute
// p2p and p3p.
- final float xm = (x1 + x4 + 3.0f * (x2 + x3)) / 8.0f;
- final float ym = (y1 + y4 + 3.0f * (y2 + y3)) / 8.0f;
+ final double xm = (x1 + x4 + 3.0d * (x2 + x3)) / 8.0d;
+ final double ym = (y1 + y4 + 3.0d * (y2 + y3)) / 8.0d;
// (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
// c*B'(0.5) for some constant c.
- final float dxm = x3 + x4 - (x1 + x2);
- final float dym = y3 + y4 - (y1 + y2);
+ final double dxm = x3 + x4 - (x1 + x2);
+ final double dym = y3 + y4 - (y1 + y2);
// this computes the offsets at t=0, 0.5, 1, using the property that
// for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
@@ -930,12 +927,12 @@ private int computeOffsetCubic(final float[] pts, final int off,
computeOffset(dx4, dy4, lineWidth2, offset2);
// left side:
- float x1p = x1 + offset0[0]; // start
- float y1p = y1 + offset0[1]; // point
- float xi = xm + offset1[0]; // interpolation
- float yi = ym + offset1[1]; // point
- float x4p = x4 + offset2[0]; // end
- float y4p = y4 + offset2[1]; // point
+ double x1p = x1 + offset0[0]; // start
+ double y1p = y1 + offset0[1]; // point
+ double xi = xm + offset1[0]; // interpolation
+ double yi = ym + offset1[1]; // point
+ double x4p = x4 + offset2[0]; // end
+ double y4p = y4 + offset2[1]; // point
if (false) {
final MarlinDebugThreadLocal dbgCtx = MarlinDebugThreadLocal.get();
@@ -943,15 +940,15 @@ private int computeOffsetCubic(final float[] pts, final int off,
dbgCtx.addPoint(xi, yi);
}
- final float invdet43 = 4.0f / (3.0f * (dx1 * dy4 - dy1 * dx4));
+ final double invdet43 = 4.0d / (3.0d * (dx1 * dy4 - dy1 * dx4));
- float two_pi_m_p1_m_p4x = 2.0f * xi - (x1p + x4p);
- float two_pi_m_p1_m_p4y = 2.0f * yi - (y1p + y4p);
+ double two_pi_m_p1_m_p4x = 2.0d * xi - (x1p + x4p);
+ double two_pi_m_p1_m_p4y = 2.0d * yi - (y1p + y4p);
- float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
- float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+ double c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ double c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
- float x2p, y2p, x3p, y3p;
+ double x2p, y2p, x3p, y3p;
if (c1 * c2 > 0.0) {
// System.out.println("Buggy solver (left): c1 = " + c1 + " c2 = " + c2);
@@ -992,8 +989,8 @@ private int computeOffsetCubic(final float[] pts, final int off,
dbgCtx.addPoint(xi, yi);
}
- two_pi_m_p1_m_p4x = 2.0f * xi - (x1p + x4p);
- two_pi_m_p1_m_p4y = 2.0f * yi - (y1p + y4p);
+ two_pi_m_p1_m_p4x = 2.0d * xi - (x1p + x4p);
+ two_pi_m_p1_m_p4y = 2.0d * yi - (y1p + y4p);
c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
@@ -1029,24 +1026,24 @@ private int computeOffsetCubic(final float[] pts, final int off,
// 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(final float[] pts, final int off,
- final float[] leftOff,
- final float[] rightOff)
+ private int computeOffsetQuad(final double[] pts, final int off,
+ final double[] leftOff,
+ final double[] rightOff)
{
return computeOffsetQuad(pts, off, leftOff, rightOff, true);
}
- private int computeOffsetQuad(final float[] pts, final int off,
- final float[] leftOff,
- final float[] rightOff,
+ private int computeOffsetQuad(final double[] pts, final int off,
+ final double[] leftOff,
+ final double[] rightOff,
final boolean checkCtrlPoints)
{
- final float x1 = pts[off ]; final float y1 = pts[off + 1];
- final float x2 = pts[off + 2]; final float y2 = pts[off + 3];
- final float x3 = pts[off + 4]; final float y3 = pts[off + 5];
+ final double x1 = pts[off ]; final double y1 = pts[off + 1];
+ final double x2 = pts[off + 2]; final double y2 = pts[off + 3];
+ final double x3 = pts[off + 4]; final double y3 = pts[off + 5];
- final float dx12 = x2 - x1; final float dy12 = y2 - y1;
- final float dx23 = x3 - x2; final float dy23 = y3 - y2;
+ final double dx12 = x2 - x1; final double dy12 = y2 - y1;
+ final double dx23 = x3 - x2; final double dy23 = y3 - y2;
if (checkCtrlPoints) {
// if p1=p2 or p2=p3 it means that the derivative at the endpoint
@@ -1058,20 +1055,20 @@ private int computeOffsetQuad(final float[] pts, final int off,
// equal if they're very close to each other.
// if p1 == p2 or p2 == p3: draw line from p1->p3
- final boolean p1eqp2 = Helpers.withinD(dx12, dy12, 6.0f * Math.ulp(y2));
- final boolean p2eqp3 = Helpers.withinD(dx23, dy23, 6.0f * Math.ulp(y3));
+ final boolean p1eqp2 = Helpers.withinD(dx12, dy12, 6.0d * Math.ulp(y2));
+ final boolean p2eqp3 = Helpers.withinD(dx23, dy23, 6.0d * Math.ulp(y3));
if (p1eqp2 || p2eqp3) {
return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
}
// if p2-p1 and p3-p2 are parallel, that must mean this curve is a line
- float dotsq = (dx12 * dx23 + dy12 * dy23);
+ double dotsq = (dx12 * dx23 + dy12 * dy23);
dotsq *= dotsq;
- final float l1sq = dx12 * dx12 + dy12 * dy12;
- final float l3sq = dx23 * dx23 + dy23 * dy23;
+ final double l1sq = dx12 * dx12 + dy12 * dy12;
+ final double l3sq = dx23 * dx23 + dy23 * dy23;
- if (Helpers.within(dotsq, l1sq * l3sq, 4.0f * Math.ulp(dotsq))) {
+ if (Helpers.within(dotsq, l1sq * l3sq, 4.0d * Math.ulp(dotsq))) {
return getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
}
}
@@ -1082,10 +1079,10 @@ private int computeOffsetQuad(final float[] pts, final int off,
computeOffset(dx12, dy12, lineWidth2, offset0);
computeOffset(dx23, dy23, lineWidth2, offset1);
- float x1p = x1 + offset0[0]; // start
- float y1p = y1 + offset0[1]; // point
- float x3p = x3 + offset1[0]; // end
- float y3p = y3 + offset1[1]; // point
+ double x1p = x1 + offset0[0]; // start
+ double y1p = y1 + offset0[1]; // point
+ double x3p = x3 + offset1[0]; // end
+ double y3p = y3 + offset1[1]; // point
safeComputeMiter(x1p, y1p, x1p+dx12, y1p+dy12, x3p, y3p, x3p-dx23, y3p-dy23, leftOff);
leftOff[0] = x1p; leftOff[1] = y1p;
@@ -1104,9 +1101,9 @@ private int computeOffsetQuad(final float[] pts, final int off,
}
@Override
- public void curveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ public void curveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
final int outcode0 = this.cOutCode;
@@ -1150,34 +1147,34 @@ public void curveTo(final float x1, final float y1,
_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,
+ private void _curveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3,
final int outcode0)
{
// need these so we can update the state at the end of this method
- float dxs = x1 - cx0;
- float dys = y1 - cy0;
- float dxf = x3 - x2;
- float dyf = y3 - y2;
+ double dxs = x1 - cx0;
+ double dys = y1 - cy0;
+ double dxf = x3 - x2;
+ double dyf = y3 - y2;
- if ((dxs == 0.0f) && (dys == 0.0f)) {
+ if ((dxs == 0.0d) && (dys == 0.0d)) {
dxs = x2 - cx0;
dys = y2 - cy0;
- if ((dxs == 0.0f) && (dys == 0.0f)) {
+ if ((dxs == 0.0d) && (dys == 0.0d)) {
dxs = x3 - cx0;
dys = y3 - cy0;
}
}
- if ((dxf == 0.0f) && (dyf == 0.0f)) {
+ if ((dxf == 0.0d) && (dyf == 0.0d)) {
dxf = x3 - x1;
dyf = y3 - y1;
- if ((dxf == 0.0f) && (dyf == 0.0f)) {
+ if ((dxf == 0.0d) && (dyf == 0.0d)) {
dxf = x3 - cx0;
dyf = y3 - cy0;
}
}
- if ((dxs == 0.0f) && (dys == 0.0f)) {
+ if ((dxs == 0.0d) && (dys == 0.0d)) {
// this happens if the "curve" is just a point
// fix outcode0 for lineTo() call:
if (clipRect != null) {
@@ -1189,13 +1186,13 @@ private void _curveTo(final float x1, final float y1,
// if these vectors are too small, normalize them, to avoid future
// precision problems.
- if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
- final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
+ if (Math.abs(dxs) < 0.1d && Math.abs(dys) < 0.1d) {
+ final double len = Math.sqrt(dxs * dxs + dys * dys);
dxs /= len;
dys /= len;
}
- if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
- final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
+ if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
+ final double len = Math.sqrt(dxf * dxf + dyf * dyf);
dxf /= len;
dyf /= len;
}
@@ -1204,8 +1201,8 @@ private void _curveTo(final float x1, final float y1,
drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
int nSplits = 0;
- final float[] mid;
- final float[] l = lp;
+ final double[] mid;
+ final double[] l = lp;
if (monotonize) {
// monotonize curve:
@@ -1222,7 +1219,7 @@ private void _curveTo(final float x1, final float y1,
mid[4] = x2; mid[5] = y2;
mid[6] = x3; mid[7] = y3;
}
- final float[] r = rp;
+ final double[] r = rp;
int kind = 0;
for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
@@ -1249,13 +1246,13 @@ private void _curveTo(final float x1, final float y1,
this.cy0 = y3;
this.cdx = dxf;
this.cdy = dyf;
- this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;
- this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0f;
+ this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
+ this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
}
@Override
- public void quadTo(final float x1, final float y1,
- final float x2, final float y2)
+ public void quadTo(final double x1, final double y1,
+ final double x2, final double y2)
{
final int outcode0 = this.cOutCode;
@@ -1297,21 +1294,21 @@ public void quadTo(final float x1, final float y1,
_quadTo(x1, y1, x2, y2, outcode0);
}
- private void _quadTo(final float x1, final float y1,
- final float x2, final float y2,
- final int outcode0)
+ private void _quadTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final int outcode0)
{
// need these so we can update the state at the end of this method
- float dxs = x1 - cx0;
- float dys = y1 - cy0;
- float dxf = x2 - x1;
- float dyf = y2 - y1;
+ double dxs = x1 - cx0;
+ double dys = y1 - cy0;
+ double dxf = x2 - x1;
+ double dyf = y2 - y1;
- if (((dxs == 0.0f) && (dys == 0.0f)) || ((dxf == 0.0f) && (dyf == 0.0f))) {
+ if (((dxs == 0.0d) && (dys == 0.0d)) || ((dxf == 0.0d) && (dyf == 0.0d))) {
dxs = dxf = x2 - cx0;
dys = dyf = y2 - cy0;
}
- if ((dxs == 0.0f) && (dys == 0.0f)) {
+ if ((dxs == 0.0d) && (dys == 0.0d)) {
// this happens if the "curve" is just a point
// fix outcode0 for lineTo() call:
if (clipRect != null) {
@@ -1322,13 +1319,13 @@ private void _quadTo(final float x1, final float y1,
}
// if these vectors are too small, normalize them, to avoid future
// precision problems.
- if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
- final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
+ if (Math.abs(dxs) < 0.1d && Math.abs(dys) < 0.1d) {
+ final double len = Math.sqrt(dxs * dxs + dys * dys);
dxs /= len;
dys /= len;
}
- if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
- final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
+ if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
+ final double len = Math.sqrt(dxf * dxf + dyf * dyf);
dxf /= len;
dyf /= len;
}
@@ -1336,8 +1333,8 @@ private void _quadTo(final float x1, final float y1,
drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
int nSplits = 0;
- final float[] mid;
- final float[] l = lp;
+ final double[] mid;
+ final double[] l = lp;
if (monotonize) {
// monotonize quad:
@@ -1353,7 +1350,7 @@ private void _quadTo(final float x1, final float y1,
mid[2] = x1; mid[3] = y1;
mid[4] = x2; mid[5] = y2;
}
- final float[] r = rp;
+ final double[] r = rp;
int kind = 0;
for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
@@ -1380,8 +1377,8 @@ private void _quadTo(final float x1, final float y1,
this.cy0 = y2;
this.cdx = dxf;
this.cdy = dyf;
- this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;
- this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0f;
+ this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
+ this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
}
@Override public long getNativeConsumer() {
diff --git a/src/main/java/sun/java2d/marlin/TransformingPathConsumer2D.java b/src/main/java/sun/java2d/marlin/TransformingPathConsumer2D.java
index 1262d01..d540472 100644
--- a/src/main/java/sun/java2d/marlin/TransformingPathConsumer2D.java
+++ b/src/main/java/sun/java2d/marlin/TransformingPathConsumer2D.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -25,7 +25,6 @@
package sun.java2d.marlin;
-import sun.awt.geom.PathConsumer2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.Arrays;
@@ -34,8 +33,8 @@
final class TransformingPathConsumer2D {
- // higher uncertainty in float variant for huge shapes > 10^7
- static final float CLIP_RECT_PADDING = 1.0f;
+ // smaller uncertainty in double variant
+ static final double CLIP_RECT_PADDING = 0.25d;
private final RendererContext rdrCtx;
@@ -45,14 +44,14 @@ final class TransformingPathConsumer2D {
// recycled PathClipFilter instance from pathClipper()
private final PathClipFilter pathClipper;
- // recycled PathConsumer2D instance from wrapPath2D()
+ // recycled DPathConsumer2D instance from wrapPath2D()
private final Path2DWrapper wp_Path2DWrapper = new Path2DWrapper();
- // recycled PathConsumer2D instances from deltaTransformConsumer()
+ // recycled DPathConsumer2D instances from deltaTransformConsumer()
private final DeltaScaleFilter dt_DeltaScaleFilter = new DeltaScaleFilter();
private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
- // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
+ // recycled DPathConsumer2D instances from inverseDeltaTransformConsumer()
private final DeltaScaleFilter iv_DeltaScaleFilter = new DeltaScaleFilter();
private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
@@ -70,51 +69,51 @@ final class TransformingPathConsumer2D {
this.pathClipper = new PathClipFilter(rdrCtx);
}
- PathConsumer2D wrapPath2D(Path2D.Float p2d) {
+ DPathConsumer2D wrapPath2D(Path2D.Double p2d) {
return wp_Path2DWrapper.init(p2d);
}
- PathConsumer2D traceInput(PathConsumer2D out) {
+ DPathConsumer2D traceInput(DPathConsumer2D out) {
return tracerInput.init(out);
}
- PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
+ DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
return tracerCPDetector.init(out);
}
- PathConsumer2D traceFiller(PathConsumer2D out) {
+ DPathConsumer2D traceFiller(DPathConsumer2D out) {
return tracerFiller.init(out);
}
- PathConsumer2D traceStroker(PathConsumer2D out) {
+ DPathConsumer2D traceStroker(DPathConsumer2D out) {
return tracerStroker.init(out);
}
- PathConsumer2D traceDasher(PathConsumer2D out) {
+ DPathConsumer2D traceDasher(DPathConsumer2D out) {
return tracerDasher.init(out);
}
- PathConsumer2D detectClosedPath(PathConsumer2D out) {
+ DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
return cpDetector.init(out);
}
- PathConsumer2D pathClipper(PathConsumer2D out) {
+ DPathConsumer2D pathClipper(DPathConsumer2D out) {
return pathClipper.init(out);
}
- PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
+ DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
AffineTransform at)
{
if (at == null) {
return out;
}
- final float mxx = (float) at.getScaleX();
- final float mxy = (float) at.getShearX();
- final float myx = (float) at.getShearY();
- final float myy = (float) at.getScaleY();
+ final double mxx = at.getScaleX();
+ final double mxy = at.getShearX();
+ final double myx = at.getShearY();
+ final double myy = at.getScaleY();
- if (mxy == 0.0f && myx == 0.0f) {
- if (mxx == 1.0f && myy == 1.0f) {
+ if (mxy == 0.0d && myx == 0.0d) {
+ if (mxx == 1.0d && myy == 1.0d) {
return out;
} else {
// Scale only
@@ -135,26 +134,26 @@ PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
}
}
- private static float adjustClipScale(final float[] clipRect,
- final float mxx, final float myy)
+ private static double adjustClipScale(final double[] clipRect,
+ final double mxx, final double myy)
{
// Adjust the clipping rectangle (iv_DeltaScaleFilter):
- final float scaleY = 1.0f / myy;
+ final double scaleY = 1.0d / myy;
clipRect[0] *= scaleY;
clipRect[1] *= scaleY;
if (clipRect[1] < clipRect[0]) {
- float tmp = clipRect[0];
+ double tmp = clipRect[0];
clipRect[0] = clipRect[1];
clipRect[1] = tmp;
}
- final float scaleX = 1.0f / mxx;
+ final double scaleX = 1.0d / mxx;
clipRect[2] *= scaleX;
clipRect[3] *= scaleX;
if (clipRect[3] < clipRect[2]) {
- float tmp = clipRect[2];
+ double tmp = clipRect[2];
clipRect[2] = clipRect[3];
clipRect[3] = tmp;
}
@@ -163,22 +162,22 @@ private static float adjustClipScale(final float[] clipRect,
MarlinUtils.logInfo("clipRect (ClipScale): "
+ Arrays.toString(clipRect));
}
- return 0.5f * (Math.abs(scaleX) + Math.abs(scaleY));
+ return 0.5d * (Math.abs(scaleX) + Math.abs(scaleY));
}
- private static float adjustClipInverseDelta(final float[] clipRect,
- final float mxx, final float mxy,
- final float myx, final float myy)
+ private static double adjustClipInverseDelta(final double[] clipRect,
+ final double mxx, final double mxy,
+ final double myx, final double myy)
{
// Adjust the clipping rectangle (iv_DeltaTransformFilter):
- final float det = mxx * myy - mxy * myx;
- final float imxx = myy / det;
- final float imxy = -mxy / det;
- final float imyx = -myx / det;
- final float imyy = mxx / det;
-
- float xmin, xmax, ymin, ymax;
- float x, y;
+ final double det = mxx * myy - mxy * myx;
+ final double imxx = myy / det;
+ final double imxy = -mxy / det;
+ final double imyx = -myx / det;
+ final double imyy = mxx / det;
+
+ double xmin, xmax, ymin, ymax;
+ double x, y;
// xmin, ymin:
x = clipRect[2] * imxx + clipRect[0] * imxy;
y = clipRect[2] * imyx + clipRect[0] * imyy;
@@ -217,31 +216,31 @@ private static float adjustClipInverseDelta(final float[] clipRect,
+ Arrays.toString(clipRect));
}
- final float scaleX = (float) Math.sqrt(imxx * imxx + imxy * imxy);
- final float scaleY = (float) Math.sqrt(imyx * imyx + imyy * imyy);
+ final double scaleX = Math.sqrt(imxx * imxx + imxy * imxy);
+ final double scaleY = Math.sqrt(imyx * imyx + imyy * imyy);
- return 0.5f * (scaleX + scaleY);
+ return 0.5d * (scaleX + scaleY);
}
- PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
+ DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
AffineTransform at)
{
if (at == null) {
return out;
}
- float mxx = (float) at.getScaleX();
- float mxy = (float) at.getShearX();
- float myx = (float) at.getShearY();
- float myy = (float) at.getScaleY();
+ double mxx = at.getScaleX();
+ double mxy = at.getShearX();
+ double myx = at.getShearY();
+ double myy = at.getScaleY();
- if (mxy == 0.0f && myx == 0.0f) {
- if (mxx == 1.0f && myy == 1.0f) {
+ if (mxy == 0.0d && myx == 0.0d) {
+ if (mxx == 1.0d && myy == 1.0d) {
return out;
} else {
- return iv_DeltaScaleFilter.init(out, 1.0f / mxx, 1.0f / myy);
+ return iv_DeltaScaleFilter.init(out, 1.0d / mxx, 1.0d / myy);
}
} else {
- final float det = mxx * myy - mxy * myx;
+ final double det = mxx * myy - mxy * myx;
return iv_DeltaTransformFilter.init(out,
myy / det,
-mxy / det,
@@ -250,14 +249,14 @@ PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
}
}
- static final class DeltaScaleFilter implements PathConsumer2D {
- private PathConsumer2D out;
- private float sx, sy;
+ static final class DeltaScaleFilter implements DPathConsumer2D {
+ private DPathConsumer2D out;
+ private double sx, sy;
DeltaScaleFilter() {}
- DeltaScaleFilter init(PathConsumer2D out,
- float mxx, float myy)
+ DeltaScaleFilter init(DPathConsumer2D out,
+ double mxx, double myy)
{
if (this.out != out) {
this.out = out;
@@ -268,27 +267,27 @@ DeltaScaleFilter init(PathConsumer2D out,
}
@Override
- public void moveTo(float x0, float y0) {
+ public void moveTo(double x0, double y0) {
out.moveTo(x0 * sx, y0 * sy);
}
@Override
- public void lineTo(float x1, float y1) {
+ public void lineTo(double x1, double y1) {
out.lineTo(x1 * sx, y1 * sy);
}
@Override
- public void quadTo(float x1, float y1,
- float x2, float y2)
+ public void quadTo(double x1, double y1,
+ double x2, double y2)
{
out.quadTo(x1 * sx, y1 * sy,
x2 * sx, y2 * sy);
}
@Override
- public void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3)
+ public void curveTo(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3)
{
out.curveTo(x1 * sx, y1 * sy,
x2 * sx, y2 * sy,
@@ -311,15 +310,15 @@ public long getNativeConsumer() {
}
}
- static final class DeltaTransformFilter implements PathConsumer2D {
- private PathConsumer2D out;
- private float mxx, mxy, myx, myy;
+ static final class DeltaTransformFilter implements DPathConsumer2D {
+ private DPathConsumer2D out;
+ private double mxx, mxy, myx, myy;
DeltaTransformFilter() {}
- DeltaTransformFilter init(PathConsumer2D out,
- float mxx, float mxy,
- float myx, float myy)
+ DeltaTransformFilter init(DPathConsumer2D out,
+ double mxx, double mxy,
+ double myx, double myy)
{
if (this.out != out) {
this.out = out;
@@ -332,20 +331,20 @@ DeltaTransformFilter init(PathConsumer2D out,
}
@Override
- public void moveTo(float x0, float y0) {
+ public void moveTo(double x0, double y0) {
out.moveTo(x0 * mxx + y0 * mxy,
x0 * myx + y0 * myy);
}
@Override
- public void lineTo(float x1, float y1) {
+ public void lineTo(double x1, double y1) {
out.lineTo(x1 * mxx + y1 * mxy,
x1 * myx + y1 * myy);
}
@Override
- public void quadTo(float x1, float y1,
- float x2, float y2)
+ public void quadTo(double x1, double y1,
+ double x2, double y2)
{
out.quadTo(x1 * mxx + y1 * mxy,
x1 * myx + y1 * myy,
@@ -354,9 +353,9 @@ public void quadTo(float x1, float y1,
}
@Override
- public void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3)
+ public void curveTo(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3)
{
out.curveTo(x1 * mxx + y1 * mxy,
x1 * myx + y1 * myy,
@@ -382,12 +381,12 @@ public long getNativeConsumer() {
}
}
- static final class Path2DWrapper implements PathConsumer2D {
- private Path2D.Float p2d;
+ static final class Path2DWrapper implements DPathConsumer2D {
+ private Path2D.Double p2d;
Path2DWrapper() {}
- Path2DWrapper init(Path2D.Float p2d) {
+ Path2DWrapper init(Path2D.Double p2d) {
if (this.p2d != p2d) {
this.p2d = p2d;
}
@@ -395,12 +394,12 @@ Path2DWrapper init(Path2D.Float p2d) {
}
@Override
- public void moveTo(float x0, float y0) {
+ public void moveTo(double x0, double y0) {
p2d.moveTo(x0, y0);
}
@Override
- public void lineTo(float x1, float y1) {
+ public void lineTo(double x1, double y1) {
p2d.lineTo(x1, y1);
}
@@ -413,15 +412,15 @@ public void closePath() {
public void pathDone() {}
@Override
- public void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3)
+ public void curveTo(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3)
{
p2d.curveTo(x1, y1, x2, y2, x3, y3);
}
@Override
- public void quadTo(float x1, float y1, float x2, float y2) {
+ public void quadTo(double x1, double y1, double x2, double y2) {
p2d.quadTo(x1, y1, x2, y2);
}
@@ -431,12 +430,12 @@ public long getNativeConsumer() {
}
}
- static final class ClosedPathDetector implements PathConsumer2D {
+ static final class ClosedPathDetector implements DPathConsumer2D {
private final RendererContext rdrCtx;
private final PolyStack stack;
- private PathConsumer2D out;
+ private DPathConsumer2D out;
ClosedPathDetector(final RendererContext rdrCtx) {
this.rdrCtx = rdrCtx;
@@ -450,7 +449,7 @@ static final class ClosedPathDetector implements PathConsumer2D {
: new PolyStack(rdrCtx);
}
- ClosedPathDetector init(PathConsumer2D out) {
+ ClosedPathDetector init(DPathConsumer2D out) {
if (this.out != out) {
this.out = out;
}
@@ -484,7 +483,7 @@ public void closePath() {
}
@Override
- public void moveTo(float x0, float y0) {
+ public void moveTo(double x0, double y0) {
// previous path is not closed:
finish(false);
out.moveTo(x0, y0);
@@ -496,20 +495,20 @@ private void finish(final boolean closed) {
}
@Override
- public void lineTo(float x1, float y1) {
+ public void lineTo(double x1, double y1) {
stack.pushLine(x1, y1);
}
@Override
- public void curveTo(float x3, float y3,
- float x2, float y2,
- float x1, float y1)
+ public void curveTo(double x3, double y3,
+ double x2, double y2,
+ double x1, double y1)
{
stack.pushCubic(x1, y1, x2, y2, x3, y3);
}
@Override
- public void quadTo(float x2, float y2, float x1, float y1) {
+ public void quadTo(double x2, double y2, double x1, double y1) {
stack.pushQuad(x1, y1, x2, y2);
}
@@ -519,7 +518,7 @@ public long getNativeConsumer() {
}
}
- static final class PathClipFilter implements PathConsumer2D {
+ static final class PathClipFilter implements DPathConsumer2D {
private static final boolean TRACE = false;
@@ -527,14 +526,14 @@ static final class PathClipFilter implements PathConsumer2D {
private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
private static final int CLOSE = 2;
- private PathConsumer2D out;
+ private DPathConsumer2D out;
private int prev;
// Bounds of the drawing region, at pixel precision.
- private final float[] clipRect;
+ private final double[] clipRect;
- private final float[] corners = new float[8];
+ private final double[] corners = new double[8];
private boolean init_corners = false;
private final IndexStack stack;
@@ -551,13 +550,10 @@ static final class PathClipFilter implements PathConsumer2D {
private boolean outside = false;
// The starting point of the path
- private float sx0, sy0;
+ private double sx0, sy0;
- // The current point (TODO stupid repeated info)
- private float cx0, cy0;
-
- // The current point OUTSIDE
- private float cox0, coy0;
+ // The current point
+ private double cx0, cy0;
private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
private final CurveClipSplitter curveSplitter;
@@ -574,7 +570,7 @@ static final class PathClipFilter implements PathConsumer2D {
: new IndexStack(rdrCtx);
}
- PathClipFilter init(final PathConsumer2D out) {
+ PathClipFilter init(final DPathConsumer2D out) {
if (this.out != out) {
this.out = out;
}
@@ -600,14 +596,12 @@ void dispose() {
}
private void finishPath() {
- if (outside) {
- // criteria: inside or totally outside ?
- if (gOutCode == 0) {
- finish();
- } else {
- this.outside = false;
- stack.reset();
- }
+ // criteria: inside or totally outside ?
+ if (gOutCode == 0) {
+ finish();
+ } else {
+ this.outside = false;
+ stack.reset();
}
}
@@ -618,8 +612,8 @@ private void finish() {
if (init_corners) {
init_corners = false;
- final float[] _corners = corners;
- final float[] _clipRect = clipRect;
+ final double[] _corners = corners;
+ final double[] _clipRect = clipRect;
// Top Left (0):
_corners[0] = _clipRect[2];
_corners[1] = _clipRect[0];
@@ -636,18 +630,16 @@ private void finish() {
stack.pullAll(corners, out, (prev == MOVE_TO));
prev = DRAWING_OP_TO;
}
- // go to the last outside point:
- this.cx0 = cox0;
- this.cy0 = coy0;
}
@Override
public void pathDone() {
if (TRACE) {
- System.out.println("PathDone(" + sx0 + ", " + sy0 + ") prev: " + prev);
+ MarlinUtils.logInfo("PathDone(" + sx0 + ", " + sy0 + ") prev: " + prev);
}
_closePath();
+ // note: renderer's pathDone() must handle missing moveTo() if outside
out.pathDone();
// this shouldn't matter since this object won't be used
@@ -662,11 +654,13 @@ public void pathDone() {
@Override
public void closePath() {
if (TRACE) {
- System.out.println("ClosePath(" + sx0 + ", " + sy0 + ") prev: " + prev);
+ MarlinUtils.logInfo("ClosePath(" + sx0 + ", " + sy0 + ") prev: " + prev);
}
_closePath();
- out.closePath();
+ if (prev == DRAWING_OP_TO) {
+ out.closePath();
+ }
// if outside, moveTo is needed
if (sOutCode != 0) {
@@ -684,27 +678,32 @@ public void closePath() {
private void _closePath() {
// preserve outside flag for the lineTo call below
final boolean prevOutside = outside;
- finishPath();
+ if (prevOutside) {
+ finishPath();
+ }
if (prev == DRAWING_OP_TO) {
// Should clip
final int orCode = (cOutCode | sOutCode);
if (orCode != 0) {
- if (cx0 != sx0 || cy0 != sy0) {
+ if ((cx0 != sx0) || (cy0 != sy0)) {
// restore outside flag before lineTo:
this.outside = prevOutside;
// may subdivide line:
lineTo(sx0, sy0);
+ // finish if outside caused by lineTo:
+ if (outside) {
+ finishPath();
+ }
}
}
}
- finishPath();
}
@Override
- public void moveTo(final float x0, final float y0) {
+ public void moveTo(final double x0, final double y0) {
if (TRACE) {
- System.out.println("MoveTo(" + x0 + ", " + y0 + ") prev: " + prev);
+ MarlinUtils.logInfo("MoveTo(" + x0 + ", " + y0 + ") prev: " + prev);
}
_closePath();
@@ -716,25 +715,21 @@ public void moveTo(final float x0, final float y0) {
this.sOutCode = outcode;
this.cx0 = x0;
this.cy0 = y0;
-
this.sx0 = x0;
this.sy0 = y0;
}
@Override
- public void lineTo(final float xe, final float ye) {
+ public void lineTo(final double xe, final double ye) {
final int outcode0 = this.cOutCode;
final int outcode1 = Helpers.outcode(xe, ye, clipRect);
if (TRACE) {
if (subdivide) {
- System.out.println("----------------------");
+ MarlinUtils.logInfo("----------------------");
}
- if (outside) {
- System.out.println("LineTo co (" + cox0 + ", " + coy0 + ")");
- }
- System.out.println("LineTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("LineTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
+ MarlinUtils.logInfo("LineTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
+ MarlinUtils.logInfo("LineTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
}
// Should clip
@@ -750,13 +745,8 @@ public void lineTo(final float xe, final float ye) {
subdivide = false;
boolean ret;
// subdivide curve => callback with subdivided parts:
- if (outside) {
- ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
- orCode, this);
- } else {
- ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
- orCode, this);
- }
+ ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
+ orCode, this);
// reentrance is done:
subdivide = true;
if (ret) {
@@ -769,11 +759,11 @@ public void lineTo(final float xe, final float ye) {
this.gOutCode &= sideCode;
// keep last point coordinate before entering the clip again:
this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
+ this.cx0 = xe;
+ this.cy0 = ye;
if (TRACE) {
- System.out.println("skipped: (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("skipped: (" + cx0 + ", " + cy0 + ")");
}
clip(sideCode, outcode0, outcode1);
@@ -790,12 +780,12 @@ public void lineTo(final float xe, final float ye) {
// emit last point outside before entering again...
if (outcode0 != 0) {
if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("add last point outside: (" + cx0 + ", " + cy0 + ")");
}
if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
+ out.moveTo(cx0, cy0);
} else {
- out.lineTo(cox0, coy0);
+ out.lineTo(cx0, cy0);
}
prev = DRAWING_OP_TO;
}
@@ -811,7 +801,7 @@ public void lineTo(final float xe, final float ye) {
this.cy0 = ye;
if (TRACE && subdivide) {
- System.out.println("----------------------");
+ MarlinUtils.logInfo("----------------------");
}
}
@@ -853,9 +843,9 @@ private void clip(final int sideCode,
}
@Override
- public void curveTo(final float x1, final float y1,
- final float x2, final float y2,
- final float xe, final float ye)
+ public void curveTo(final double x1, final double y1,
+ final double x2, final double y2,
+ final double xe, final double ye)
{
final int outcode0 = this.cOutCode;
final int outcode1 = Helpers.outcode(x1, y1, clipRect);
@@ -864,13 +854,10 @@ public void curveTo(final float x1, final float y1,
if (TRACE) {
if (subdivide) {
- System.out.println("----------------------");
+ MarlinUtils.logInfo("----------------------");
}
- if (outside) {
- System.out.println("CurveTo co (" + cox0 + ", " + coy0 + ")");
- }
- System.out.println("CurveTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("CurveTo (" + xe + ", " + ye + ") outcode: " + outcode3 + " outside: " + outside);
+ MarlinUtils.logInfo("CurveTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
+ MarlinUtils.logInfo("CurveTo (" + xe + ", " + ye + ") outcode: " + outcode3 + " outside: " + outside);
}
// Should clip
@@ -886,15 +873,9 @@ public void curveTo(final float x1, final float y1,
subdivide = false;
// subdivide curve => callback with subdivided parts:
boolean ret;
- if (outside) {
- ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
- x2, y2, xe, ye,
- orCode, this);
- } else {
- ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
- x2, y2, xe, ye,
- orCode, this);
- }
+ ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+ x2, y2, xe, ye,
+ orCode, this);
// reentrance is done:
subdivide = true;
if (ret) {
@@ -907,11 +888,11 @@ public void curveTo(final float x1, final float y1,
this.gOutCode &= sideCode;
// keep last point coordinate before entering the clip again:
this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
+ this.cx0 = xe;
+ this.cy0 = ye;
if (TRACE) {
- System.out.println("skipped: (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("skipped: (" + cx0 + ", " + cy0 + ")");
}
clip(sideCode, outcode0, outcode3);
@@ -928,12 +909,12 @@ public void curveTo(final float x1, final float y1,
// emit last point outside before entering again...
if (outcode0 != 0) {
if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("add last point outside: (" + cx0 + ", " + cy0 + ")");
}
if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
+ out.moveTo(cx0, cy0);
} else {
- out.lineTo(cox0, coy0);
+ out.lineTo(cx0, cy0);
}
prev = DRAWING_OP_TO;
}
@@ -949,13 +930,13 @@ public void curveTo(final float x1, final float y1,
this.cy0 = ye;
if (TRACE && subdivide) {
- System.out.println("----------------------");
+ MarlinUtils.logInfo("----------------------");
}
}
@Override
- public void quadTo(final float x1, final float y1,
- final float xe, final float ye)
+ public void quadTo(final double x1, final double y1,
+ final double xe, final double ye)
{
final int outcode0 = this.cOutCode;
final int outcode1 = Helpers.outcode(x1, y1, clipRect);
@@ -963,13 +944,10 @@ public void quadTo(final float x1, final float y1,
if (TRACE) {
if (subdivide) {
- System.out.println("----------------------");
- }
- if (outside) {
- System.out.println("QuadTo co (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("----------------------");
}
- System.out.println("QuadTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
- System.out.println("QuadTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
+ MarlinUtils.logInfo("QuadTo c (" + cx0 + ", " + cy0 + ") outcode: " + outcode0);
+ MarlinUtils.logInfo("QuadTo (" + xe + ", " + ye + ") outcode: " + outcode1 + " outside: " + outside);
}
// Should clip
@@ -985,13 +963,8 @@ public void quadTo(final float x1, final float y1,
subdivide = false;
// subdivide curve => callback with subdivided parts:
boolean ret;
- if (outside) {
- ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
- xe, ye, orCode, this);
- } else {
- ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
- xe, ye, orCode, this);
- }
+ ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+ xe, ye, orCode, this);
// reentrance is done:
subdivide = true;
if (ret) {
@@ -1004,8 +977,8 @@ public void quadTo(final float x1, final float y1,
this.gOutCode &= sideCode;
// keep last point coordinate before entering the clip again:
this.outside = true;
- this.cox0 = xe;
- this.coy0 = ye;
+ this.cx0 = xe;
+ this.cy0 = ye;
clip(sideCode, outcode0, outcode2);
return;
@@ -1021,12 +994,12 @@ public void quadTo(final float x1, final float y1,
// emit last point outside before entering again...
if (outcode0 != 0) {
if (TRACE) {
- System.out.println("add last point outside: (" + cox0 + ", " + coy0 + ")");
+ MarlinUtils.logInfo("add last point outside: (" + cx0 + ", " + cy0 + ")");
}
if (prev == MOVE_TO) {
- out.moveTo(cox0, coy0);
+ out.moveTo(cx0, cy0);
} else {
- out.lineTo(cox0, coy0);
+ out.lineTo(cx0, cy0);
}
prev = DRAWING_OP_TO;
}
@@ -1042,7 +1015,7 @@ public void quadTo(final float x1, final float y1,
this.cy0 = ye;
if (TRACE && subdivide) {
- System.out.println("----------------------");
+ MarlinUtils.logInfo("----------------------");
}
}
@@ -1052,11 +1025,10 @@ public long getNativeConsumer() {
}
}
- /* note: CurveClipSplitter uses double-precision for higher accuracy */
static final class CurveClipSplitter {
- static final float LEN_TH = MarlinProperties.getSubdividerMinLength();
- static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0f);
+ static final double LEN_TH = MarlinProperties.getSubdividerMinLength();
+ static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0d);
private static final boolean TRACE = false;
@@ -1065,10 +1037,10 @@ static final class CurveClipSplitter {
private final RendererContext rdrCtx;
// scaled length threshold:
- private float minLength;
+ private double minLength;
// clip rectangle (ymin, ymax, xmin, xmax):
- final float[] clipRect;
+ final double[] clipRect;
// clip rectangle (ymin, ymax, xmin, xmax) including padding:
final double[] clipRectPad = new double[4];
@@ -1081,19 +1053,19 @@ static final class CurveClipSplitter {
private final double[] subdivTs = new double[MAX_N_CURVES];
// dirty curve
- private final DCurve curve;
+ private final Curve curve;
CurveClipSplitter(final RendererContext rdrCtx) {
this.rdrCtx = rdrCtx;
this.clipRect = rdrCtx.clipRect;
- this.curve = /* rdrCtx.curve */ new DCurve(); // double-precision curve
+ this.curve = rdrCtx.curve;
}
void init() {
this.init_clipRectPad = true;
if (DO_CHECK_LENGTH) {
- this.minLength = (this.rdrCtx.clipInvScale == 0.0f) ? LEN_TH
+ this.minLength = (this.rdrCtx.clipInvScale == 0.0d) ? LEN_TH
: (LEN_TH * this.rdrCtx.clipInvScale);
if (MarlinConst.DO_LOG_CLIP) {
@@ -1107,7 +1079,7 @@ private void initPaddedClip() {
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust padded clip rectangle (ymin, ymax, xmin, xmax):
// add a rounding error (curve subdivision ~ 0.1px):
- final float[] _clipRect = clipRect;
+ final double[] _clipRect = clipRect;
final double[] _clipRectPad = clipRectPad;
_clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
@@ -1121,10 +1093,10 @@ private void initPaddedClip() {
}
}
- boolean splitLine(final float x0, final float y0,
- final float x1, final float y1,
+ boolean splitLine(final double x0, final double y0,
+ final double x1, final double y1,
final int outCodeOR,
- final PathConsumer2D out)
+ final DPathConsumer2D out)
{
if (TRACE) {
MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
@@ -1141,11 +1113,11 @@ boolean splitLine(final float x0, final float y0,
return subdivideAtIntersections(4, outCodeOR, out);
}
- boolean splitQuad(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
+ boolean splitQuad(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
final int outCodeOR,
- final PathConsumer2D out)
+ final DPathConsumer2D out)
{
if (TRACE) {
MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
@@ -1163,12 +1135,12 @@ boolean splitQuad(final float x0, final float y0,
return subdivideAtIntersections(6, outCodeOR, out);
}
- boolean splitCurve(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3,
+ boolean splitCurve(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3,
final int outCodeOR,
- final PathConsumer2D out)
+ final DPathConsumer2D out)
{
if (TRACE) {
MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
@@ -1188,7 +1160,7 @@ boolean splitCurve(final float x0, final float y0,
}
private boolean subdivideAtIntersections(final int type, final int outCodeOR,
- final PathConsumer2D out)
+ final DPathConsumer2D out)
{
final double[] mid = middle;
final double[] subTs = subdivTs;
@@ -1198,7 +1170,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
initPaddedClip();
}
- final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
+ final int nSplits = Helpers.findClipPoints(curve, mid, subTs, type,
outCodeOR, clipRectPad);
if (TRACE) {
@@ -1214,7 +1186,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
for (int i = 0, off = 0; i < nSplits; i++, off += type) {
final double t = subTs[i];
- DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
+ Helpers.subdivideAt((t - prevT) / (1.0d - prevT),
mid, off, mid, off, type);
prevT = t;
}
@@ -1229,18 +1201,18 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
}
static void emitCurrent(final int type, final double[] pts,
- final int off, final PathConsumer2D out)
+ final int off, final DPathConsumer2D out)
{
// if instead of switch (perf + most probable cases first)
if (type == 8) {
- out.curveTo((float)pts[off + 2], (float)pts[off + 3],
- (float)pts[off + 4], (float)pts[off + 5],
- (float)pts[off + 6], (float)pts[off + 7]);
+ out.curveTo(pts[off + 2], pts[off + 3],
+ pts[off + 4], pts[off + 5],
+ pts[off + 6], pts[off + 7]);
} else if (type == 4) {
- out.lineTo((float)pts[off + 2], (float)pts[off + 3]);
+ out.lineTo(pts[off + 2], pts[off + 3]);
} else {
- out.quadTo((float)pts[off + 2], (float)pts[off + 3],
- (float)pts[off + 4], (float)pts[off + 5]);
+ out.quadTo(pts[off + 2], pts[off + 3],
+ pts[off + 4], pts[off + 5]);
}
}
}
@@ -1250,16 +1222,16 @@ static final class CurveBasicMonotonizer {
private static final int MAX_N_CURVES = 11;
// squared half line width (for stroker)
- private float lw2;
+ private double lw2;
// number of splitted curves
int nbSplits;
// This is where the curve to be processed is put. We give it
// enough room to store all curves.
- final float[] middle = new float[MAX_N_CURVES * 6 + 2];
+ final double[] middle = new double[MAX_N_CURVES * 6 + 2];
// t values at subdivision points
- private final float[] subdivTs = new float[MAX_N_CURVES - 1];
+ private final double[] subdivTs = new double[MAX_N_CURVES - 1];
// dirty curve
private final Curve curve;
@@ -1268,29 +1240,29 @@ static final class CurveBasicMonotonizer {
this.curve = rdrCtx.curve;
}
- void init(final float lineWidth) {
- this.lw2 = (lineWidth * lineWidth) / 4.0f;
+ void init(final double lineWidth) {
+ this.lw2 = (lineWidth * lineWidth) / 4.0d;
}
- CurveBasicMonotonizer curve(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2,
- final float x3, final float y3)
+ CurveBasicMonotonizer curve(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2,
+ final double x3, final double y3)
{
- final float[] mid = middle;
+ final double[] mid = middle;
mid[0] = x0; mid[1] = y0;
mid[2] = x1; mid[3] = y1;
mid[4] = x2; mid[5] = y2;
mid[6] = x3; mid[7] = y3;
- final float[] subTs = subdivTs;
+ final double[] subTs = subdivTs;
final int nSplits = Helpers.findSubdivPoints(curve, mid, subTs, 8, lw2);
- float prevT = 0.0f;
+ double prevT = 0.0d;
for (int i = 0, off = 0; i < nSplits; i++, off += 6) {
- final float t = subTs[i];
+ final double t = subTs[i];
- Helpers.subdivideCubicAt((t - prevT) / (1.0f - prevT),
+ Helpers.subdivideCubicAt((t - prevT) / (1.0d - prevT),
mid, off, mid, off, off + 6);
prevT = t;
}
@@ -1299,22 +1271,22 @@ CurveBasicMonotonizer curve(final float x0, final float y0,
return this;
}
- CurveBasicMonotonizer quad(final float x0, final float y0,
- final float x1, final float y1,
- final float x2, final float y2)
+ CurveBasicMonotonizer quad(final double x0, final double y0,
+ final double x1, final double y1,
+ final double x2, final double y2)
{
- final float[] mid = middle;
+ final double[] mid = middle;
mid[0] = x0; mid[1] = y0;
mid[2] = x1; mid[3] = y1;
mid[4] = x2; mid[5] = y2;
- final float[] subTs = subdivTs;
+ final double[] subTs = subdivTs;
final int nSplits = Helpers.findSubdivPoints(curve, mid, subTs, 6, lw2);
- float prevt = 0.0f;
+ double prevt = 0.0d;
for (int i = 0, off = 0; i < nSplits; i++, off += 4) {
- final float t = subTs[i];
- Helpers.subdivideQuadAt((t - prevt) / (1.0f - prevt),
+ final double t = subTs[i];
+ Helpers.subdivideQuadAt((t - prevt) / (1.0d - prevt),
mid, off, mid, off, off + 4);
prevt = t;
}
@@ -1324,15 +1296,15 @@ CurveBasicMonotonizer quad(final float x0, final float y0,
}
}
- static final class PathTracer implements PathConsumer2D {
+ static final class PathTracer implements DPathConsumer2D {
private final String prefix;
- private PathConsumer2D out;
+ private DPathConsumer2D out;
PathTracer(String name) {
this.prefix = name + ": ";
}
- PathTracer init(PathConsumer2D out) {
+ PathTracer init(DPathConsumer2D out) {
if (this.out != out) {
this.out = out;
}
@@ -1340,29 +1312,29 @@ PathTracer init(PathConsumer2D out) {
}
@Override
- public void moveTo(float x0, float y0) {
+ public void moveTo(double x0, double y0) {
log("p.moveTo(" + x0 + ", " + y0 + ");");
out.moveTo(x0, y0);
}
@Override
- public void lineTo(float x1, float y1) {
+ public void lineTo(double x1, double y1) {
log("p.lineTo(" + x1 + ", " + y1 + ");");
out.lineTo(x1, y1);
}
@Override
- public void curveTo(float x1, float y1,
- float x2, float y2,
- float x3, float y3)
+ public void curveTo(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3)
{
log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + x3 + ", " + y3 + ");");
out.curveTo(x1, y1, x2, y2, x3, y3);
}
@Override
- public void quadTo(float x1, float y1,
- float x2, float y2) {
+ public void quadTo(double x1, double y1,
+ double x2, double y2) {
log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ");");
out.quadTo(x1, y1, x2, y2);
}
diff --git a/src/main/java/test/ClipShapeTest.java b/src/main/java/test/ClipShapeTest.java
index 23bdcb2..e931ea4 100644
--- a/src/main/java/test/ClipShapeTest.java
+++ b/src/main/java/test/ClipShapeTest.java
@@ -1,7 +1,7 @@
package test;
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -63,10 +63,6 @@
* for paths made of either 9 lines, 4 quads, 2 cubics (random)
* Note: Use the argument -slow to run more intensive tests (too much time)
*
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly -doDash
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic -doDash
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly -doDash
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic
@@ -135,7 +131,6 @@ static enum ShapeMode {
static final File OUTPUT_DIR = new File(".");
static final AtomicBoolean isMarlin = new AtomicBoolean();
- static final AtomicBoolean isMarlinFloat = new AtomicBoolean();
static final AtomicBoolean isClipRuntime = new AtomicBoolean();
static {
@@ -152,8 +147,7 @@ public void publish(LogRecord record) {
if (msg != null) {
// last space to avoid matching other settings:
if (msg.startsWith("sun.java2d.renderer ")) {
- isMarlin.set(msg.contains("MarlinRenderingEngine"));
- isMarlinFloat.set(!msg.contains("DMarlinRenderingEngine"));
+ isMarlin.set(msg.contains("DMarlinRenderingEngine"));
}
if (msg.startsWith("sun.java2d.renderer.clip.runtime.enable")) {
isClipRuntime.set(msg.contains("true"));
@@ -357,10 +351,7 @@ public static void main(String[] args) {
NbPixels [All Test setups][n: 30] sum: 232 avg: 7.733 [1 | 27]
*/
THRESHOLD_DELTA = 2;
- THRESHOLD_NBPIX = (USE_DASHES) ?
- // float variant have higher uncertainty
- ((isMarlinFloat.get()) ? 30 : 6) // low for double
- : (isMarlinFloat.get()) ? 10 : 0;
+ THRESHOLD_NBPIX = (USE_DASHES) ? 6 : 0;
}
// Visual inspection (low threshold):
diff --git a/src/main/java/test/EndlessLoop.java b/src/main/java/test/EndlessLoop.java
index 2812921..acd1e94 100644
--- a/src/main/java/test/EndlessLoop.java
+++ b/src/main/java/test/EndlessLoop.java
@@ -18,12 +18,6 @@
drawLine(1.0E8) [AA=true]: 1.86741 ms.
drawLine(1.0E8) [AA=true]: 4.550681 ms.
drawLine(1.0E8) [AA=true]: 1.9914479999999999 ms.
- * - AA org.marlin.pisces.MarlinRenderingEngine:
-drawLine(1.0E8) [AA=true]: 50.357248999999996 ms.
-drawLine(1.0E8) [AA=true]: 1.935198 ms.
-
-drawLine(7.0E15) [AA=true]: 48.779185999999996 ms.
-drawLine(7.0E15) [AA=true]: 1.946686 ms.
*/
public class EndlessLoop extends JFrame {
diff --git a/src/main/resources/META-INF/services/sun.java2d.pipe.RenderingEngine b/src/main/resources/META-INF/services/sun.java2d.pipe.RenderingEngine
index e760a02..2530788 100644
--- a/src/main/resources/META-INF/services/sun.java2d.pipe.RenderingEngine
+++ b/src/main/resources/META-INF/services/sun.java2d.pipe.RenderingEngine
@@ -1,3 +1,2 @@
# Marlin Rendering Engine module
-sun.java2d.marlin.MarlinRenderingEngine
sun.java2d.marlin.DMarlinRenderingEngine
diff --git a/src/main/resources/org/marlin/pisces/Version.properties b/src/main/resources/sun/java2d/marlin/Version.properties
similarity index 100%
rename from src/main/resources/org/marlin/pisces/Version.properties
rename to src/main/resources/sun/java2d/marlin/Version.properties
diff --git a/src/test/java/ClipShapeTest.java b/src/test/java/ClipShapeTest.java
index 057bdde..c678590 100644
--- a/src/test/java/ClipShapeTest.java
+++ b/src/test/java/ClipShapeTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -61,10 +61,6 @@
* for paths made of either 9 lines, 4 quads, 2 cubics (random)
* Note: Use the argument -slow to run more intensive tests (too much time)
*
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -poly -doDash
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic
- * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine ClipShapeTest -cubic -doDash
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly -doDash
* @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic
@@ -133,7 +129,6 @@ static enum ShapeMode {
static final File OUTPUT_DIR = new File(".");
static final AtomicBoolean isMarlin = new AtomicBoolean();
- static final AtomicBoolean isMarlinFloat = new AtomicBoolean();
static final AtomicBoolean isClipRuntime = new AtomicBoolean();
static {
@@ -150,8 +145,7 @@ public void publish(LogRecord record) {
if (msg != null) {
// last space to avoid matching other settings:
if (msg.startsWith("sun.java2d.renderer ")) {
- isMarlin.set(msg.contains("MarlinRenderingEngine"));
- isMarlinFloat.set(!msg.contains("DMarlinRenderingEngine"));
+ isMarlin.set(msg.contains("DMarlinRenderingEngine"));
}
if (msg.startsWith("sun.java2d.renderer.clip.runtime.enable")) {
isClipRuntime.set(msg.contains("true"));
@@ -355,10 +349,7 @@ public static void main(String[] args) {
NbPixels [All Test setups][n: 30] sum: 232 avg: 7.733 [1 | 27]
*/
THRESHOLD_DELTA = 2;
- THRESHOLD_NBPIX = (USE_DASHES) ?
- // float variant have higher uncertainty
- ((isMarlinFloat.get()) ? 30 : 6) // low for double
- : (isMarlinFloat.get()) ? 10 : 0;
+ THRESHOLD_NBPIX = (USE_DASHES) ? 6 : 0;
}
// Visual inspection (low threshold):