< prev index next >
src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
Print this page
*** 49,58 ****
--- 49,61 ----
{
private static enum NormMode {ON_WITH_AA, ON_NO_AA, OFF}
private static final float MIN_PEN_SIZE = 1f / NORM_SUBPIXELS;
+ static final float UPPER_BND = Float.MAX_VALUE / 2.0f;
+ static final float LOWER_BND = -UPPER_BND;
+
/**
* Public constructor
*/
public MarlinRenderingEngine() {
super();
*** 277,305 ****
float miterlimit,
float dashes[],
float dashphase,
PathConsumer2D pc2d)
{
! // We use strokerat and outat 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.
! // If normalization is off we save some transformations by not
! // transforming the input to pisces. Instead, we apply the
! // transformation after the path processing has been done.
! // We can't do this if normalization is on, because it isn't a good
! // idea to normalize before the transformation is applied.
AffineTransform strokerat = null;
- AffineTransform outat = null;
- PathIterator pi;
int dashLen = -1;
boolean recycleDashes = false;
if (at != null && !at.isIdentity()) {
final double a = at.getScaleX();
--- 280,304 ----
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();
*** 331,340 ****
--- 330,340 ----
// 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;
final float[] newDashes;
if (dashLen <= INITIAL_ARRAY) {
*** 347,412 ****
newDashes = rdrCtx.getDirtyFloatArray(dashLen);
}
System.arraycopy(dashes, 0, newDashes, 0, dashLen);
dashes = newDashes;
for (int i = 0; i < dashLen; i++) {
! dashes[i] = scale * dashes[i];
}
! dashphase = scale * dashphase;
}
! width = scale * width;
! pi = getNormalizingPathIterator(rdrCtx, normalize,
! src.getPathIterator(at));
! // by now strokerat == null && outat == 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 {
! if (normalize != NormMode.OFF) {
! strokerat = at;
! pi = getNormalizingPathIterator(rdrCtx, normalize,
! src.getPathIterator(at));
!
! // by now strokerat == at && outat == null. 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 {
! outat = at;
! pi = src.getPathIterator(null);
! // outat == at && strokerat == null. This is because if no
! // normalization is done, we can just apply all our
! // transformations to stroker's output.
! }
}
} else {
// either at is null or it's the identity. In either case
// we don't transform the path.
! pi = getNormalizingPathIterator(rdrCtx, normalize,
! src.getPathIterator(null));
}
if (useSimplifier) {
// Use simplifier after stroker before Renderer
// to remove collinear segments (notably due to cap square)
pc2d = rdrCtx.simplifier.init(pc2d);
}
- // by now, at least one of outat and strokerat will be null. Unless at is not
- // a constant multiple of an orthogonal transformation, they will both be
- // null. In other cases, outat == at if normalization is off, and if
- // normalization is on, strokerat == at.
final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
- pc2d = transformerPC2D.transformConsumer(pc2d, outat);
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit);
if (dashes != null) {
--- 347,394 ----
newDashes = rdrCtx.getDirtyFloatArray(dashLen);
}
System.arraycopy(dashes, 0, newDashes, 0, dashLen);
dashes = newDashes;
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;
}
if (useSimplifier) {
// Use simplifier after stroker before Renderer
// to remove collinear segments (notably due to cap square)
pc2d = rdrCtx.simplifier.init(pc2d);
}
final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit);
if (dashes != null) {
*** 415,436 ****
}
pc2d = rdrCtx.dasher.init(pc2d, dashes, dashLen, dashphase,
recycleDashes);
}
pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat);
pathTo(rdrCtx, pi, pc2d);
/*
* Pipeline seems to be:
! * shape.getPathIterator
! * -> NormalizingPathIterator
! * -> inverseDeltaTransformConsumer
! * -> Dasher
* -> Stroker
! * -> deltaTransformConsumer OR transformConsumer
*
! * -> CollinearSimplifier to remove redundant segments
*
* -> pc2d = Renderer (bounding box)
*/
}
--- 397,422 ----
}
pc2d = rdrCtx.dasher.init(pc2d, dashes, dashLen, dashphase,
recycleDashes);
}
pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat);
+
+ final PathIterator pi = getNormalizingPathIterator(rdrCtx, normalize,
+ 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)
*/
}
*** 640,670 ****
}
private static void pathToLoop(final float[] coords, final PathIterator pi,
final PathConsumer2D pc2d)
{
for (; !pi.isDone(); pi.next()) {
switch (pi.currentSegment(coords)) {
! case PathIterator.SEG_MOVETO:
pc2d.moveTo(coords[0], coords[1]);
! continue;
! case PathIterator.SEG_LINETO:
! pc2d.lineTo(coords[0], coords[1]);
! continue;
! case PathIterator.SEG_QUADTO:
! pc2d.quadTo(coords[0], coords[1],
! coords[2], coords[3]);
! continue;
! case PathIterator.SEG_CUBICTO:
! pc2d.curveTo(coords[0], coords[1],
! coords[2], coords[3],
! coords[4], coords[5]);
! continue;
! case PathIterator.SEG_CLOSE:
pc2d.closePath();
! continue;
! default:
}
}
pc2d.pathDone();
}
--- 626,738 ----
}
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();
}
< prev index next >