|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.dc; |
|
|
|
import java.awt.Shape; |
|
import java.awt.BasicStroke; |
|
import java.awt.geom.Path2D; |
|
import java.awt.geom.PathIterator; |
|
import java.awt.geom.AffineTransform; |
|
|
|
import sun.awt.geom.PathConsumer2D; |
|
import sun.java2d.pipe.Region; |
|
import sun.java2d.pipe.AATileGenerator; |
|
import sun.java2d.pipe.RenderingEngine; |
|
|
|
import sun.dc.pr.Rasterizer; |
|
import sun.dc.pr.PathStroker; |
|
import sun.dc.pr.PathDasher; |
|
import sun.dc.pr.PRException; |
|
import sun.dc.path.PathConsumer; |
|
import sun.dc.path.PathException; |
|
import sun.dc.path.FastPathProducer; |
|
|
|
public class DuctusRenderingEngine extends RenderingEngine { |
|
static final float PenUnits = 0.01f; |
|
static final int MinPenUnits = 100; |
|
static final int MinPenUnitsAA = 20; |
|
static final float MinPenSizeAA = PenUnits * MinPenUnitsAA; |
|
|
|
static final float UPPER_BND = Float.MAX_VALUE / 2.0f; |
|
static final float LOWER_BND = -UPPER_BND; |
|
|
|
private static final int RasterizerCaps[] = { |
|
Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE |
|
}; |
|
|
|
private static final int RasterizerCorners[] = { |
|
Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL |
|
}; |
|
|
|
static float[] getTransformMatrix(AffineTransform transform) { |
|
float matrix[] = new float[4]; |
|
double dmatrix[] = new double[6]; |
|
transform.getMatrix(dmatrix); |
|
for (int i = 0; i < 4; i++) { |
|
matrix[i] = (float) dmatrix[i]; |
|
} |
|
return matrix; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Shape createStrokedShape(Shape src, |
|
float width, |
|
int caps, |
|
int join, |
|
float miterlimit, |
|
float dashes[], |
|
float dashphase) |
|
{ |
|
FillAdapter filler = new FillAdapter(); |
|
PathStroker stroker = new PathStroker(filler); |
|
PathDasher dasher = null; |
|
|
|
try { |
|
PathConsumer consumer; |
|
|
|
stroker.setPenDiameter(width); |
|
stroker.setPenT4(null); |
|
stroker.setCaps(RasterizerCaps[caps]); |
|
stroker.setCorners(RasterizerCorners[join], miterlimit); |
|
if (dashes != null) { |
|
dasher = new PathDasher(stroker); |
|
dasher.setDash(dashes, dashphase); |
|
dasher.setDashT4(null); |
|
consumer = dasher; |
|
} else { |
|
consumer = stroker; |
|
} |
|
|
|
feedConsumer(consumer, src.getPathIterator(null)); |
|
} finally { |
|
stroker.dispose(); |
|
if (dasher != null) { |
|
dasher.dispose(); |
|
} |
|
} |
|
|
|
return filler.getShape(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void strokeTo(Shape src, |
|
AffineTransform transform, |
|
BasicStroke bs, |
|
boolean thin, |
|
boolean normalize, |
|
boolean antialias, |
|
PathConsumer2D sr) |
|
{ |
|
PathStroker stroker = new PathStroker(sr); |
|
PathConsumer consumer = stroker; |
|
|
|
float matrix[] = null; |
|
if (!thin) { |
|
stroker.setPenDiameter(bs.getLineWidth()); |
|
if (transform != null) { |
|
matrix = getTransformMatrix(transform); |
|
} |
|
stroker.setPenT4(matrix); |
|
stroker.setPenFitting(PenUnits, MinPenUnits); |
|
} |
|
stroker.setCaps(RasterizerCaps[bs.getEndCap()]); |
|
stroker.setCorners(RasterizerCorners[bs.getLineJoin()], |
|
bs.getMiterLimit()); |
|
float[] dashes = bs.getDashArray(); |
|
if (dashes != null) { |
|
PathDasher dasher = new PathDasher(stroker); |
|
dasher.setDash(dashes, bs.getDashPhase()); |
|
if (transform != null && matrix == null) { |
|
matrix = getTransformMatrix(transform); |
|
} |
|
dasher.setDashT4(matrix); |
|
consumer = dasher; |
|
} |
|
|
|
try { |
|
PathIterator pi = src.getPathIterator(transform); |
|
|
|
feedConsumer(pi, consumer, normalize, 0.25f); |
|
} catch (PathException e) { |
|
throw new InternalError("Unable to Stroke shape ("+ |
|
e.getMessage()+")", e); |
|
} finally { |
|
while (consumer != null && consumer != sr) { |
|
PathConsumer next = consumer.getConsumer(); |
|
consumer.dispose(); |
|
consumer = next; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static void feedConsumer(PathIterator pi, PathConsumer consumer, |
|
boolean normalize, float norm) |
|
throws PathException |
|
{ |
|
consumer.beginPath(); |
|
boolean pathClosed = false; |
|
boolean skip = false; |
|
boolean subpathStarted = false; |
|
float mx = 0.0f; |
|
float my = 0.0f; |
|
float point[] = new float[6]; |
|
float rnd = (0.5f - norm); |
|
float ax = 0.0f; |
|
float ay = 0.0f; |
|
|
|
while (!pi.isDone()) { |
|
int type = pi.currentSegment(point); |
|
if (pathClosed == true) { |
|
pathClosed = false; |
|
if (type != PathIterator.SEG_MOVETO) { |
|
|
|
consumer.beginSubpath(mx, my); |
|
subpathStarted = true; |
|
} |
|
} |
|
if (normalize) { |
|
int index; |
|
switch (type) { |
|
case PathIterator.SEG_CUBICTO: |
|
index = 4; |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
index = 2; |
|
break; |
|
case PathIterator.SEG_MOVETO: |
|
case PathIterator.SEG_LINETO: |
|
index = 0; |
|
break; |
|
case PathIterator.SEG_CLOSE: |
|
default: |
|
index = -1; |
|
break; |
|
} |
|
if (index >= 0) { |
|
float ox = point[index]; |
|
float oy = point[index+1]; |
|
float newax = (float) Math.floor(ox + rnd) + norm; |
|
float neway = (float) Math.floor(oy + rnd) + norm; |
|
point[index] = newax; |
|
point[index+1] = neway; |
|
newax -= ox; |
|
neway -= oy; |
|
switch (type) { |
|
case PathIterator.SEG_CUBICTO: |
|
point[0] += ax; |
|
point[1] += ay; |
|
point[2] += newax; |
|
point[3] += neway; |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
point[0] += (newax + ax) / 2; |
|
point[1] += (neway + ay) / 2; |
|
break; |
|
case PathIterator.SEG_MOVETO: |
|
case PathIterator.SEG_LINETO: |
|
case PathIterator.SEG_CLOSE: |
|
break; |
|
} |
|
ax = newax; |
|
ay = neway; |
|
} |
|
} |
|
switch (type) { |
|
case PathIterator.SEG_MOVETO: |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
mx = point[0]; |
|
my = point[1]; |
|
consumer.beginSubpath(mx, my); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
skip = true; |
|
} |
|
break; |
|
case PathIterator.SEG_LINETO: |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
consumer.beginSubpath(point[0], point[1]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
consumer.appendLine(point[0], point[1]); |
|
} |
|
} |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
// Quadratic curves take two points |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[2] < UPPER_BND && point[2] > LOWER_BND && |
|
point[3] < UPPER_BND && point[3] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
consumer.beginSubpath(point[2], point[3]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
consumer.appendQuadratic(point[0], point[1], |
|
point[2], point[3]); |
|
} else { |
|
consumer.appendLine(point[2], point[3]); |
|
} |
|
} |
|
} |
|
break; |
|
case PathIterator.SEG_CUBICTO: |
|
// Cubic curves take three points |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[4] < UPPER_BND && point[4] > LOWER_BND && |
|
point[5] < UPPER_BND && point[5] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
consumer.beginSubpath(point[4], point[5]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND && |
|
point[2] < UPPER_BND && point[2] > LOWER_BND && |
|
point[3] < UPPER_BND && point[3] > LOWER_BND) |
|
{ |
|
consumer.appendCubic(point[0], point[1], |
|
point[2], point[3], |
|
point[4], point[5]); |
|
} else { |
|
consumer.appendLine(point[4], point[5]); |
|
} |
|
} |
|
} |
|
break; |
|
case PathIterator.SEG_CLOSE: |
|
if (subpathStarted) { |
|
consumer.closedSubpath(); |
|
subpathStarted = false; |
|
pathClosed = true; |
|
} |
|
break; |
|
} |
|
pi.next(); |
|
} |
|
|
|
consumer.endPath(); |
|
} |
|
|
|
private static Rasterizer theRasterizer; |
|
|
|
public synchronized static Rasterizer getRasterizer() { |
|
Rasterizer r = theRasterizer; |
|
if (r == null) { |
|
r = new Rasterizer(); |
|
} else { |
|
theRasterizer = null; |
|
} |
|
return r; |
|
} |
|
|
|
public synchronized static void dropRasterizer(Rasterizer r) { |
|
r.reset(); |
|
theRasterizer = r; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public float getMinimumAAPenSize() { |
|
return MinPenSizeAA; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public AATileGenerator getAATileGenerator(Shape s, |
|
AffineTransform at, |
|
Region clip, |
|
BasicStroke bs, |
|
boolean thin, |
|
boolean normalize, |
|
int bbox[]) |
|
{ |
|
Rasterizer r = getRasterizer(); |
|
PathIterator pi = s.getPathIterator(at); |
|
|
|
if (bs != null) { |
|
float matrix[] = null; |
|
r.setUsage(Rasterizer.STROKE); |
|
if (thin) { |
|
r.setPenDiameter(MinPenSizeAA); |
|
} else { |
|
r.setPenDiameter(bs.getLineWidth()); |
|
if (at != null) { |
|
matrix = getTransformMatrix(at); |
|
r.setPenT4(matrix); |
|
} |
|
r.setPenFitting(PenUnits, MinPenUnitsAA); |
|
} |
|
r.setCaps(RasterizerCaps[bs.getEndCap()]); |
|
r.setCorners(RasterizerCorners[bs.getLineJoin()], |
|
bs.getMiterLimit()); |
|
float[] dashes = bs.getDashArray(); |
|
if (dashes != null) { |
|
r.setDash(dashes, bs.getDashPhase()); |
|
if (at != null && matrix == null) { |
|
matrix = getTransformMatrix(at); |
|
} |
|
r.setDashT4(matrix); |
|
} |
|
} else { |
|
r.setUsage(pi.getWindingRule() == PathIterator.WIND_EVEN_ODD |
|
? Rasterizer.EOFILL |
|
: Rasterizer.NZFILL); |
|
} |
|
|
|
r.beginPath(); |
|
{ |
|
boolean pathClosed = false; |
|
boolean skip = false; |
|
boolean subpathStarted = false; |
|
float mx = 0.0f; |
|
float my = 0.0f; |
|
float point[] = new float[6]; |
|
float ax = 0.0f; |
|
float ay = 0.0f; |
|
|
|
while (!pi.isDone()) { |
|
int type = pi.currentSegment(point); |
|
if (pathClosed == true) { |
|
pathClosed = false; |
|
if (type != PathIterator.SEG_MOVETO) { |
|
|
|
r.beginSubpath(mx, my); |
|
subpathStarted = true; |
|
} |
|
} |
|
if (normalize) { |
|
int index; |
|
switch (type) { |
|
case PathIterator.SEG_CUBICTO: |
|
index = 4; |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
index = 2; |
|
break; |
|
case PathIterator.SEG_MOVETO: |
|
case PathIterator.SEG_LINETO: |
|
index = 0; |
|
break; |
|
case PathIterator.SEG_CLOSE: |
|
default: |
|
index = -1; |
|
break; |
|
} |
|
if (index >= 0) { |
|
float ox = point[index]; |
|
float oy = point[index+1]; |
|
float newax = (float) Math.floor(ox) + 0.5f; |
|
float neway = (float) Math.floor(oy) + 0.5f; |
|
point[index] = newax; |
|
point[index+1] = neway; |
|
newax -= ox; |
|
neway -= oy; |
|
switch (type) { |
|
case PathIterator.SEG_CUBICTO: |
|
point[0] += ax; |
|
point[1] += ay; |
|
point[2] += newax; |
|
point[3] += neway; |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
point[0] += (newax + ax) / 2; |
|
point[1] += (neway + ay) / 2; |
|
break; |
|
case PathIterator.SEG_MOVETO: |
|
case PathIterator.SEG_LINETO: |
|
case PathIterator.SEG_CLOSE: |
|
break; |
|
} |
|
ax = newax; |
|
ay = neway; |
|
} |
|
} |
|
switch (type) { |
|
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 (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
mx = point[0]; |
|
my = point[1]; |
|
r.beginSubpath(mx, my); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
skip = true; |
|
} |
|
break; |
|
|
|
case PathIterator.SEG_LINETO: |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
r.beginSubpath(point[0], point[1]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
r.appendLine(point[0], point[1]); |
|
} |
|
} |
|
break; |
|
|
|
case PathIterator.SEG_QUADTO: |
|
// Quadratic curves take two points |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (point[2] < UPPER_BND && point[2] > LOWER_BND && |
|
point[3] < UPPER_BND && point[3] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
r.beginSubpath(point[2], point[3]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND) |
|
{ |
|
r.appendQuadratic(point[0], point[1], |
|
point[2], point[3]); |
|
} else { |
|
r.appendLine(point[2], point[3]); |
|
} |
|
} |
|
} |
|
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 (point[4] < UPPER_BND && point[4] > LOWER_BND && |
|
point[5] < UPPER_BND && point[5] > LOWER_BND) |
|
{ |
|
if (skip) { |
|
r.beginSubpath(point[4], point[5]); |
|
subpathStarted = true; |
|
skip = false; |
|
} else { |
|
if (point[0] < UPPER_BND && point[0] > LOWER_BND && |
|
point[1] < UPPER_BND && point[1] > LOWER_BND && |
|
point[2] < UPPER_BND && point[2] > LOWER_BND && |
|
point[3] < UPPER_BND && point[3] > LOWER_BND) |
|
{ |
|
r.appendCubic(point[0], point[1], |
|
point[2], point[3], |
|
point[4], point[5]); |
|
} else { |
|
r.appendLine(point[4], point[5]); |
|
} |
|
} |
|
} |
|
break; |
|
case PathIterator.SEG_CLOSE: |
|
if (subpathStarted) { |
|
r.closedSubpath(); |
|
subpathStarted = false; |
|
pathClosed = true; |
|
} |
|
break; |
|
} |
|
pi.next(); |
|
} |
|
} |
|
|
|
try { |
|
r.endPath(); |
|
r.getAlphaBox(bbox); |
|
clip.clipBoxToBounds(bbox); |
|
if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) { |
|
dropRasterizer(r); |
|
return null; |
|
} |
|
r.setOutputArea(bbox[0], bbox[1], |
|
bbox[2] - bbox[0], |
|
bbox[3] - bbox[1]); |
|
} catch (PRException e) { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e); |
|
} |
|
|
|
return r; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public AATileGenerator getAATileGenerator(double x, double y, |
|
double dx1, double dy1, |
|
double dx2, double dy2, |
|
double lw1, double lw2, |
|
Region clip, |
|
int bbox[]) |
|
{ |
|
|
|
double ldx1, ldy1, ldx2, ldy2; |
|
boolean innerpgram = (lw1 > 0 && lw2 > 0); |
|
|
|
if (innerpgram) { |
|
ldx1 = dx1 * lw1; |
|
ldy1 = dy1 * lw1; |
|
ldx2 = dx2 * lw2; |
|
ldy2 = dy2 * lw2; |
|
x -= (ldx1 + ldx2) / 2.0; |
|
y -= (ldy1 + ldy2) / 2.0; |
|
dx1 += ldx1; |
|
dy1 += ldy1; |
|
dx2 += ldx2; |
|
dy2 += ldy2; |
|
if (lw1 > 1 && lw2 > 1) { |
|
|
|
innerpgram = false; |
|
} |
|
} else { |
|
ldx1 = ldy1 = ldx2 = ldy2 = 0; |
|
} |
|
|
|
Rasterizer r = getRasterizer(); |
|
|
|
r.setUsage(Rasterizer.EOFILL); |
|
|
|
r.beginPath(); |
|
r.beginSubpath((float) x, (float) y); |
|
r.appendLine((float) (x+dx1), (float) (y+dy1)); |
|
r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2)); |
|
r.appendLine((float) (x+dx2), (float) (y+dy2)); |
|
r.closedSubpath(); |
|
if (innerpgram) { |
|
x += ldx1 + ldx2; |
|
y += ldy1 + ldy2; |
|
dx1 -= 2.0 * ldx1; |
|
dy1 -= 2.0 * ldy1; |
|
dx2 -= 2.0 * ldx2; |
|
dy2 -= 2.0 * ldy2; |
|
r.beginSubpath((float) x, (float) y); |
|
r.appendLine((float) (x+dx1), (float) (y+dy1)); |
|
r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2)); |
|
r.appendLine((float) (x+dx2), (float) (y+dy2)); |
|
r.closedSubpath(); |
|
} |
|
|
|
try { |
|
r.endPath(); |
|
r.getAlphaBox(bbox); |
|
clip.clipBoxToBounds(bbox); |
|
if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) { |
|
dropRasterizer(r); |
|
return null; |
|
} |
|
r.setOutputArea(bbox[0], bbox[1], |
|
bbox[2] - bbox[0], |
|
bbox[3] - bbox[1]); |
|
} catch (PRException e) { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e); |
|
} |
|
|
|
return r; |
|
} |
|
|
|
private void feedConsumer(PathConsumer consumer, PathIterator pi) { |
|
try { |
|
consumer.beginPath(); |
|
boolean pathClosed = false; |
|
float mx = 0.0f; |
|
float my = 0.0f; |
|
float point[] = new float[6]; |
|
|
|
while (!pi.isDone()) { |
|
int type = pi.currentSegment(point); |
|
if (pathClosed == true) { |
|
pathClosed = false; |
|
if (type != PathIterator.SEG_MOVETO) { |
|
|
|
consumer.beginSubpath(mx, my); |
|
} |
|
} |
|
switch (type) { |
|
case PathIterator.SEG_MOVETO: |
|
mx = point[0]; |
|
my = point[1]; |
|
consumer.beginSubpath(point[0], point[1]); |
|
break; |
|
case PathIterator.SEG_LINETO: |
|
consumer.appendLine(point[0], point[1]); |
|
break; |
|
case PathIterator.SEG_QUADTO: |
|
consumer.appendQuadratic(point[0], point[1], |
|
point[2], point[3]); |
|
break; |
|
case PathIterator.SEG_CUBICTO: |
|
consumer.appendCubic(point[0], point[1], |
|
point[2], point[3], |
|
point[4], point[5]); |
|
break; |
|
case PathIterator.SEG_CLOSE: |
|
consumer.closedSubpath(); |
|
pathClosed = true; |
|
break; |
|
} |
|
pi.next(); |
|
} |
|
|
|
consumer.endPath(); |
|
} catch (PathException e) { |
|
throw new InternalError("Unable to Stroke shape ("+ |
|
e.getMessage()+")", e); |
|
} |
|
} |
|
|
|
private class FillAdapter implements PathConsumer { |
|
boolean closed; |
|
Path2D.Float path; |
|
|
|
public FillAdapter() { |
|
// Ductus only supplies float coordinates so |
|
|
|
path = new Path2D.Float(Path2D.WIND_NON_ZERO); |
|
} |
|
|
|
public Shape getShape() { |
|
return path; |
|
} |
|
|
|
public void dispose() { |
|
} |
|
|
|
public PathConsumer getConsumer() { |
|
return null; |
|
} |
|
|
|
public void beginPath() {} |
|
|
|
public void beginSubpath(float x0, float y0) { |
|
if (closed) { |
|
path.closePath(); |
|
closed = false; |
|
} |
|
path.moveTo(x0, y0); |
|
} |
|
|
|
public void appendLine(float x1, float y1) { |
|
path.lineTo(x1, y1); |
|
} |
|
|
|
public void appendQuadratic(float xm, float ym, float x1, float y1) { |
|
path.quadTo(xm, ym, x1, y1); |
|
} |
|
|
|
public void appendCubic(float xm, float ym, |
|
float xn, float yn, |
|
float x1, float y1) { |
|
path.curveTo(xm, ym, xn, yn, x1, y1); |
|
} |
|
|
|
public void closedSubpath() { |
|
closed = true; |
|
} |
|
|
|
public void endPath() { |
|
if (closed) { |
|
path.closePath(); |
|
closed = false; |
|
} |
|
} |
|
|
|
public void useProxy(FastPathProducer proxy) |
|
throws PathException |
|
{ |
|
proxy.sendTo(this); |
|
} |
|
|
|
public long getCPathConsumer() { |
|
return 0; |
|
} |
|
} |
|
} |