0N/A/*
3909N/A * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.dc;
0N/A
0N/Aimport java.awt.Shape;
0N/Aimport java.awt.BasicStroke;
0N/Aimport java.awt.geom.Path2D;
0N/Aimport java.awt.geom.PathIterator;
0N/Aimport java.awt.geom.AffineTransform;
0N/A
0N/Aimport sun.awt.geom.PathConsumer2D;
0N/Aimport sun.java2d.pipe.Region;
0N/Aimport sun.java2d.pipe.AATileGenerator;
0N/Aimport sun.java2d.pipe.RenderingEngine;
0N/A
0N/Aimport sun.dc.pr.Rasterizer;
0N/Aimport sun.dc.pr.PathStroker;
0N/Aimport sun.dc.pr.PathDasher;
0N/Aimport sun.dc.pr.PRException;
0N/Aimport sun.dc.path.PathConsumer;
0N/Aimport sun.dc.path.PathException;
0N/Aimport sun.dc.path.FastPathProducer;
0N/A
0N/Apublic class DuctusRenderingEngine extends RenderingEngine {
0N/A static final float PenUnits = 0.01f;
0N/A static final int MinPenUnits = 100;
0N/A static final int MinPenUnitsAA = 20;
0N/A static final float MinPenSizeAA = PenUnits * MinPenUnitsAA;
0N/A
0N/A static final float UPPER_BND = Float.MAX_VALUE / 2.0f;
0N/A static final float LOWER_BND = -UPPER_BND;
0N/A
0N/A private static final int RasterizerCaps[] = {
0N/A Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE
0N/A };
0N/A
0N/A private static final int RasterizerCorners[] = {
0N/A Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL
0N/A };
0N/A
0N/A static float[] getTransformMatrix(AffineTransform transform) {
0N/A float matrix[] = new float[4];
0N/A double dmatrix[] = new double[6];
0N/A transform.getMatrix(dmatrix);
0N/A for (int i = 0; i < 4; i++) {
0N/A matrix[i] = (float) dmatrix[i];
0N/A }
0N/A return matrix;
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A @Override
0N/A public Shape createStrokedShape(Shape src,
0N/A float width,
0N/A int caps,
0N/A int join,
0N/A float miterlimit,
0N/A float dashes[],
0N/A float dashphase)
0N/A {
0N/A FillAdapter filler = new FillAdapter();
0N/A PathStroker stroker = new PathStroker(filler);
0N/A PathDasher dasher = null;
0N/A
0N/A try {
0N/A PathConsumer consumer;
0N/A
0N/A stroker.setPenDiameter(width);
0N/A stroker.setPenT4(null);
0N/A stroker.setCaps(RasterizerCaps[caps]);
0N/A stroker.setCorners(RasterizerCorners[join], miterlimit);
0N/A if (dashes != null) {
0N/A dasher = new PathDasher(stroker);
0N/A dasher.setDash(dashes, dashphase);
0N/A dasher.setDashT4(null);
0N/A consumer = dasher;
0N/A } else {
0N/A consumer = stroker;
0N/A }
0N/A
0N/A feedConsumer(consumer, src.getPathIterator(null));
0N/A } finally {
0N/A stroker.dispose();
0N/A if (dasher != null) {
0N/A dasher.dispose();
0N/A }
0N/A }
0N/A
0N/A return filler.getShape();
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A @Override
0N/A public void strokeTo(Shape src,
0N/A AffineTransform transform,
0N/A BasicStroke bs,
0N/A boolean thin,
0N/A boolean normalize,
0N/A boolean antialias,
0N/A PathConsumer2D sr)
0N/A {
0N/A PathStroker stroker = new PathStroker(sr);
0N/A PathConsumer consumer = stroker;
0N/A
0N/A float matrix[] = null;
0N/A if (!thin) {
0N/A stroker.setPenDiameter(bs.getLineWidth());
0N/A if (transform != null) {
0N/A matrix = getTransformMatrix(transform);
0N/A }
0N/A stroker.setPenT4(matrix);
0N/A stroker.setPenFitting(PenUnits, MinPenUnits);
0N/A }
0N/A stroker.setCaps(RasterizerCaps[bs.getEndCap()]);
0N/A stroker.setCorners(RasterizerCorners[bs.getLineJoin()],
0N/A bs.getMiterLimit());
0N/A float[] dashes = bs.getDashArray();
0N/A if (dashes != null) {
0N/A PathDasher dasher = new PathDasher(stroker);
0N/A dasher.setDash(dashes, bs.getDashPhase());
0N/A if (transform != null && matrix == null) {
0N/A matrix = getTransformMatrix(transform);
0N/A }
0N/A dasher.setDashT4(matrix);
0N/A consumer = dasher;
0N/A }
0N/A
0N/A try {
0N/A PathIterator pi = src.getPathIterator(transform);
0N/A
0N/A feedConsumer(pi, consumer, normalize, 0.25f);
0N/A } catch (PathException e) {
0N/A throw new InternalError("Unable to Stroke shape ("+
0N/A e.getMessage()+")");
0N/A } finally {
0N/A while (consumer != null && consumer != sr) {
0N/A PathConsumer next = consumer.getConsumer();
0N/A consumer.dispose();
0N/A consumer = next;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Feed a path from a PathIterator to a Ductus PathConsumer.
0N/A */
0N/A public static void feedConsumer(PathIterator pi, PathConsumer consumer,
0N/A boolean normalize, float norm)
0N/A throws PathException
0N/A {
0N/A consumer.beginPath();
0N/A boolean pathClosed = false;
0N/A boolean skip = false;
0N/A boolean subpathStarted = false;
0N/A float mx = 0.0f;
0N/A float my = 0.0f;
0N/A float point[] = new float[6];
0N/A float rnd = (0.5f - norm);
0N/A float ax = 0.0f;
0N/A float ay = 0.0f;
0N/A
0N/A while (!pi.isDone()) {
0N/A int type = pi.currentSegment(point);
0N/A if (pathClosed == true) {
0N/A pathClosed = false;
0N/A if (type != PathIterator.SEG_MOVETO) {
0N/A // Force current point back to last moveto point
0N/A consumer.beginSubpath(mx, my);
0N/A subpathStarted = true;
0N/A }
0N/A }
0N/A if (normalize) {
0N/A int index;
0N/A switch (type) {
0N/A case PathIterator.SEG_CUBICTO:
0N/A index = 4;
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A index = 2;
0N/A break;
0N/A case PathIterator.SEG_MOVETO:
0N/A case PathIterator.SEG_LINETO:
0N/A index = 0;
0N/A break;
0N/A case PathIterator.SEG_CLOSE:
0N/A default:
0N/A index = -1;
0N/A break;
0N/A }
0N/A if (index >= 0) {
0N/A float ox = point[index];
0N/A float oy = point[index+1];
0N/A float newax = (float) Math.floor(ox + rnd) + norm;
0N/A float neway = (float) Math.floor(oy + rnd) + norm;
0N/A point[index] = newax;
0N/A point[index+1] = neway;
0N/A newax -= ox;
0N/A neway -= oy;
0N/A switch (type) {
0N/A case PathIterator.SEG_CUBICTO:
0N/A point[0] += ax;
0N/A point[1] += ay;
0N/A point[2] += newax;
0N/A point[3] += neway;
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A point[0] += (newax + ax) / 2;
0N/A point[1] += (neway + ay) / 2;
0N/A break;
0N/A case PathIterator.SEG_MOVETO:
0N/A case PathIterator.SEG_LINETO:
0N/A case PathIterator.SEG_CLOSE:
0N/A break;
0N/A }
0N/A ax = newax;
0N/A ay = neway;
0N/A }
0N/A }
0N/A switch (type) {
0N/A case PathIterator.SEG_MOVETO:
0N/A
0N/A /* Checking SEG_MOVETO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles NaN
0N/A * and Infinity values. Skipping next path segment in case of
0N/A * invalid data.
0N/A */
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A mx = point[0];
0N/A my = point[1];
0N/A consumer.beginSubpath(mx, my);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A skip = true;
0N/A }
0N/A break;
0N/A case PathIterator.SEG_LINETO:
0N/A /* Checking SEG_LINETO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles NaN
0N/A * and Infinity values. Ignoring current path segment in case
0N/A * of invalid data. If segment is skipped its endpoint
0N/A * (if valid) is used to begin new subpath.
0N/A */
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A consumer.beginSubpath(point[0], point[1]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A consumer.appendLine(point[0], point[1]);
0N/A }
0N/A }
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A // Quadratic curves take two points
0N/A
0N/A /* Checking SEG_QUADTO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles NaN
0N/A * and Infinity values. Ignoring current path segment in case
0N/A * of invalid endpoints's data. Equivalent to the SEG_LINETO
0N/A * if endpoint coordinates are valid but there are invalid data
0N/A * amoung other coordinates
0N/A */
0N/A if (point[2] < UPPER_BND && point[2] > LOWER_BND &&
0N/A point[3] < UPPER_BND && point[3] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A consumer.beginSubpath(point[2], point[3]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A consumer.appendQuadratic(point[0], point[1],
0N/A point[2], point[3]);
0N/A } else {
0N/A consumer.appendLine(point[2], point[3]);
0N/A }
0N/A }
0N/A }
0N/A break;
0N/A case PathIterator.SEG_CUBICTO:
0N/A // Cubic curves take three points
0N/A
0N/A /* Checking SEG_CUBICTO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles NaN
0N/A * and Infinity values. Ignoring current path segment in case
0N/A * of invalid endpoints's data. Equivalent to the SEG_LINETO
0N/A * if endpoint coordinates are valid but there are invalid data
0N/A * amoung other coordinates
0N/A */
0N/A if (point[4] < UPPER_BND && point[4] > LOWER_BND &&
0N/A point[5] < UPPER_BND && point[5] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A consumer.beginSubpath(point[4], point[5]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND &&
0N/A point[2] < UPPER_BND && point[2] > LOWER_BND &&
0N/A point[3] < UPPER_BND && point[3] > LOWER_BND)
0N/A {
0N/A consumer.appendCubic(point[0], point[1],
0N/A point[2], point[3],
0N/A point[4], point[5]);
0N/A } else {
0N/A consumer.appendLine(point[4], point[5]);
0N/A }
0N/A }
0N/A }
0N/A break;
0N/A case PathIterator.SEG_CLOSE:
0N/A if (subpathStarted) {
0N/A consumer.closedSubpath();
0N/A subpathStarted = false;
0N/A pathClosed = true;
0N/A }
0N/A break;
0N/A }
0N/A pi.next();
0N/A }
0N/A
0N/A consumer.endPath();
0N/A }
0N/A
0N/A private static Rasterizer theRasterizer;
0N/A
0N/A public synchronized static Rasterizer getRasterizer() {
0N/A Rasterizer r = theRasterizer;
0N/A if (r == null) {
0N/A r = new Rasterizer();
0N/A } else {
0N/A theRasterizer = null;
0N/A }
0N/A return r;
0N/A }
0N/A
0N/A public synchronized static void dropRasterizer(Rasterizer r) {
0N/A r.reset();
0N/A theRasterizer = r;
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A @Override
0N/A public float getMinimumAAPenSize() {
0N/A return MinPenSizeAA;
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A */
0N/A @Override
0N/A public AATileGenerator getAATileGenerator(Shape s,
0N/A AffineTransform at,
0N/A Region clip,
0N/A BasicStroke bs,
0N/A boolean thin,
0N/A boolean normalize,
0N/A int bbox[])
0N/A {
0N/A Rasterizer r = getRasterizer();
0N/A PathIterator pi = s.getPathIterator(at);
0N/A
0N/A if (bs != null) {
0N/A float matrix[] = null;
0N/A r.setUsage(Rasterizer.STROKE);
0N/A if (thin) {
0N/A r.setPenDiameter(MinPenSizeAA);
0N/A } else {
0N/A r.setPenDiameter(bs.getLineWidth());
0N/A if (at != null) {
0N/A matrix = getTransformMatrix(at);
0N/A r.setPenT4(matrix);
0N/A }
0N/A r.setPenFitting(PenUnits, MinPenUnitsAA);
0N/A }
0N/A r.setCaps(RasterizerCaps[bs.getEndCap()]);
0N/A r.setCorners(RasterizerCorners[bs.getLineJoin()],
0N/A bs.getMiterLimit());
0N/A float[] dashes = bs.getDashArray();
0N/A if (dashes != null) {
0N/A r.setDash(dashes, bs.getDashPhase());
0N/A if (at != null && matrix == null) {
0N/A matrix = getTransformMatrix(at);
0N/A }
0N/A r.setDashT4(matrix);
0N/A }
0N/A } else {
0N/A r.setUsage(pi.getWindingRule() == PathIterator.WIND_EVEN_ODD
0N/A ? Rasterizer.EOFILL
0N/A : Rasterizer.NZFILL);
0N/A }
0N/A
0N/A r.beginPath();
0N/A {
0N/A boolean pathClosed = false;
0N/A boolean skip = false;
0N/A boolean subpathStarted = false;
0N/A float mx = 0.0f;
0N/A float my = 0.0f;
0N/A float point[] = new float[6];
0N/A float ax = 0.0f;
0N/A float ay = 0.0f;
0N/A
0N/A while (!pi.isDone()) {
0N/A int type = pi.currentSegment(point);
0N/A if (pathClosed == true) {
0N/A pathClosed = false;
0N/A if (type != PathIterator.SEG_MOVETO) {
0N/A // Force current point back to last moveto point
0N/A r.beginSubpath(mx, my);
0N/A subpathStarted = true;
0N/A }
0N/A }
0N/A if (normalize) {
0N/A int index;
0N/A switch (type) {
0N/A case PathIterator.SEG_CUBICTO:
0N/A index = 4;
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A index = 2;
0N/A break;
0N/A case PathIterator.SEG_MOVETO:
0N/A case PathIterator.SEG_LINETO:
0N/A index = 0;
0N/A break;
0N/A case PathIterator.SEG_CLOSE:
0N/A default:
0N/A index = -1;
0N/A break;
0N/A }
0N/A if (index >= 0) {
0N/A float ox = point[index];
0N/A float oy = point[index+1];
0N/A float newax = (float) Math.floor(ox) + 0.5f;
0N/A float neway = (float) Math.floor(oy) + 0.5f;
0N/A point[index] = newax;
0N/A point[index+1] = neway;
0N/A newax -= ox;
0N/A neway -= oy;
0N/A switch (type) {
0N/A case PathIterator.SEG_CUBICTO:
0N/A point[0] += ax;
0N/A point[1] += ay;
0N/A point[2] += newax;
0N/A point[3] += neway;
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A point[0] += (newax + ax) / 2;
0N/A point[1] += (neway + ay) / 2;
0N/A break;
0N/A case PathIterator.SEG_MOVETO:
0N/A case PathIterator.SEG_LINETO:
0N/A case PathIterator.SEG_CLOSE:
0N/A break;
0N/A }
0N/A ax = newax;
0N/A ay = neway;
0N/A }
0N/A }
0N/A switch (type) {
0N/A case PathIterator.SEG_MOVETO:
0N/A
0N/A /* Checking SEG_MOVETO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles NaN
0N/A * and Infinity values. Skipping next path segment in case
0N/A * of invalid data.
0N/A */
0N/A
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A mx = point[0];
0N/A my = point[1];
0N/A r.beginSubpath(mx, my);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A skip = true;
0N/A }
0N/A break;
0N/A
0N/A case PathIterator.SEG_LINETO:
0N/A /* Checking SEG_LINETO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles
0N/A * NaN and Infinity values. Ignoring current path segment
0N/A * in case of invalid data. If segment is skipped its
0N/A * endpoint (if valid) is used to begin new subpath.
0N/A */
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A r.beginSubpath(point[0], point[1]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A r.appendLine(point[0], point[1]);
0N/A }
0N/A }
0N/A break;
0N/A
0N/A case PathIterator.SEG_QUADTO:
0N/A // Quadratic curves take two points
0N/A
0N/A /* Checking SEG_QUADTO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles
0N/A * NaN and Infinity values. Ignoring current path segment
0N/A * in case of invalid endpoints's data. Equivalent to the
0N/A * SEG_LINETO if endpoint coordinates are valid but there
0N/A * are invalid data amoung other coordinates
0N/A */
0N/A if (point[2] < UPPER_BND && point[2] > LOWER_BND &&
0N/A point[3] < UPPER_BND && point[3] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A r.beginSubpath(point[2], point[3]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND)
0N/A {
0N/A r.appendQuadratic(point[0], point[1],
0N/A point[2], point[3]);
0N/A } else {
0N/A r.appendLine(point[2], point[3]);
0N/A }
0N/A }
0N/A }
0N/A break;
0N/A case PathIterator.SEG_CUBICTO:
0N/A // Cubic curves take three points
0N/A
0N/A /* Checking SEG_CUBICTO coordinates if they are out of the
0N/A * [LOWER_BND, UPPER_BND] range. This check also handles
0N/A * NaN and Infinity values. Ignoring current path segment
0N/A * in case of invalid endpoints's data. Equivalent to the
0N/A * SEG_LINETO if endpoint coordinates are valid but there
0N/A * are invalid data amoung other coordinates
0N/A */
0N/A
0N/A if (point[4] < UPPER_BND && point[4] > LOWER_BND &&
0N/A point[5] < UPPER_BND && point[5] > LOWER_BND)
0N/A {
0N/A if (skip) {
0N/A r.beginSubpath(point[4], point[5]);
0N/A subpathStarted = true;
0N/A skip = false;
0N/A } else {
0N/A if (point[0] < UPPER_BND && point[0] > LOWER_BND &&
0N/A point[1] < UPPER_BND && point[1] > LOWER_BND &&
0N/A point[2] < UPPER_BND && point[2] > LOWER_BND &&
0N/A point[3] < UPPER_BND && point[3] > LOWER_BND)
0N/A {
0N/A r.appendCubic(point[0], point[1],
0N/A point[2], point[3],
0N/A point[4], point[5]);
0N/A } else {
0N/A r.appendLine(point[4], point[5]);
0N/A }
0N/A }
0N/A }
0N/A break;
0N/A case PathIterator.SEG_CLOSE:
0N/A if (subpathStarted) {
0N/A r.closedSubpath();
0N/A subpathStarted = false;
0N/A pathClosed = true;
0N/A }
0N/A break;
0N/A }
0N/A pi.next();
0N/A }
0N/A }
0N/A
0N/A try {
0N/A r.endPath();
0N/A r.getAlphaBox(bbox);
0N/A clip.clipBoxToBounds(bbox);
0N/A if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) {
0N/A dropRasterizer(r);
0N/A return null;
0N/A }
0N/A r.setOutputArea(bbox[0], bbox[1],
0N/A bbox[2] - bbox[0],
0N/A bbox[3] - bbox[1]);
0N/A } catch (PRException e) {
0N/A /*
0N/A * This exeption is thrown from the native part of the Ductus
0N/A * (only in case of a debug build) to indicate that some
0N/A * segments of the path have very large coordinates.
0N/A * See 4485298 for more info.
0N/A */
0N/A System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e);
0N/A }
0N/A
0N/A return r;
0N/A }
0N/A
3265N/A /**
3265N/A * {@inheritDoc}
3265N/A */
3265N/A @Override
3265N/A public AATileGenerator getAATileGenerator(double x, double y,
3265N/A double dx1, double dy1,
3265N/A double dx2, double dy2,
3265N/A double lw1, double lw2,
3265N/A Region clip,
3265N/A int bbox[])
3265N/A {
3265N/A // REMIND: Deal with large coordinates!
3265N/A double ldx1, ldy1, ldx2, ldy2;
3265N/A boolean innerpgram = (lw1 > 0 && lw2 > 0);
3265N/A
3265N/A if (innerpgram) {
3265N/A ldx1 = dx1 * lw1;
3265N/A ldy1 = dy1 * lw1;
3265N/A ldx2 = dx2 * lw2;
3265N/A ldy2 = dy2 * lw2;
3265N/A x -= (ldx1 + ldx2) / 2.0;
3265N/A y -= (ldy1 + ldy2) / 2.0;
3265N/A dx1 += ldx1;
3265N/A dy1 += ldy1;
3265N/A dx2 += ldx2;
3265N/A dy2 += ldy2;
3265N/A if (lw1 > 1 && lw2 > 1) {
3265N/A // Inner parallelogram was entirely consumed by stroke...
3265N/A innerpgram = false;
3265N/A }
3265N/A } else {
3265N/A ldx1 = ldy1 = ldx2 = ldy2 = 0;
3265N/A }
3265N/A
3265N/A Rasterizer r = getRasterizer();
3265N/A
3265N/A r.setUsage(Rasterizer.EOFILL);
3265N/A
3265N/A r.beginPath();
3265N/A r.beginSubpath((float) x, (float) y);
3265N/A r.appendLine((float) (x+dx1), (float) (y+dy1));
3265N/A r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2));
3265N/A r.appendLine((float) (x+dx2), (float) (y+dy2));
3265N/A r.closedSubpath();
3265N/A if (innerpgram) {
3265N/A x += ldx1 + ldx2;
3265N/A y += ldy1 + ldy2;
3265N/A dx1 -= 2.0 * ldx1;
3265N/A dy1 -= 2.0 * ldy1;
3265N/A dx2 -= 2.0 * ldx2;
3265N/A dy2 -= 2.0 * ldy2;
3265N/A r.beginSubpath((float) x, (float) y);
3265N/A r.appendLine((float) (x+dx1), (float) (y+dy1));
3265N/A r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2));
3265N/A r.appendLine((float) (x+dx2), (float) (y+dy2));
3265N/A r.closedSubpath();
3265N/A }
3265N/A
3265N/A try {
3265N/A r.endPath();
3265N/A r.getAlphaBox(bbox);
3265N/A clip.clipBoxToBounds(bbox);
3265N/A if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) {
3265N/A dropRasterizer(r);
3265N/A return null;
3265N/A }
3265N/A r.setOutputArea(bbox[0], bbox[1],
3265N/A bbox[2] - bbox[0],
3265N/A bbox[3] - bbox[1]);
3265N/A } catch (PRException e) {
3265N/A /*
3265N/A * This exeption is thrown from the native part of the Ductus
3265N/A * (only in case of a debug build) to indicate that some
3265N/A * segments of the path have very large coordinates.
3265N/A * See 4485298 for more info.
3265N/A */
3265N/A System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e);
3265N/A }
3265N/A
3265N/A return r;
3265N/A }
3265N/A
0N/A private void feedConsumer(PathConsumer consumer, PathIterator pi) {
0N/A try {
0N/A consumer.beginPath();
0N/A boolean pathClosed = false;
0N/A float mx = 0.0f;
0N/A float my = 0.0f;
0N/A float point[] = new float[6];
0N/A
0N/A while (!pi.isDone()) {
0N/A int type = pi.currentSegment(point);
0N/A if (pathClosed == true) {
0N/A pathClosed = false;
0N/A if (type != PathIterator.SEG_MOVETO) {
0N/A // Force current point back to last moveto point
0N/A consumer.beginSubpath(mx, my);
0N/A }
0N/A }
0N/A switch (type) {
0N/A case PathIterator.SEG_MOVETO:
0N/A mx = point[0];
0N/A my = point[1];
0N/A consumer.beginSubpath(point[0], point[1]);
0N/A break;
0N/A case PathIterator.SEG_LINETO:
0N/A consumer.appendLine(point[0], point[1]);
0N/A break;
0N/A case PathIterator.SEG_QUADTO:
0N/A consumer.appendQuadratic(point[0], point[1],
0N/A point[2], point[3]);
0N/A break;
0N/A case PathIterator.SEG_CUBICTO:
0N/A consumer.appendCubic(point[0], point[1],
0N/A point[2], point[3],
0N/A point[4], point[5]);
0N/A break;
0N/A case PathIterator.SEG_CLOSE:
0N/A consumer.closedSubpath();
0N/A pathClosed = true;
0N/A break;
0N/A }
0N/A pi.next();
0N/A }
0N/A
0N/A consumer.endPath();
0N/A } catch (PathException e) {
0N/A throw new InternalError("Unable to Stroke shape ("+
0N/A e.getMessage()+")");
0N/A }
0N/A }
0N/A
0N/A private class FillAdapter implements PathConsumer {
0N/A boolean closed;
0N/A Path2D.Float path;
0N/A
0N/A public FillAdapter() {
0N/A // Ductus only supplies float coordinates so
0N/A // Path2D.Double is not necessary here.
0N/A path = new Path2D.Float(Path2D.WIND_NON_ZERO);
0N/A }
0N/A
0N/A public Shape getShape() {
0N/A return path;
0N/A }
0N/A
0N/A public void dispose() {
0N/A }
0N/A
0N/A public PathConsumer getConsumer() {
0N/A return null;
0N/A }
0N/A
0N/A public void beginPath() {}
0N/A
0N/A public void beginSubpath(float x0, float y0) {
0N/A if (closed) {
0N/A path.closePath();
0N/A closed = false;
0N/A }
0N/A path.moveTo(x0, y0);
0N/A }
0N/A
0N/A public void appendLine(float x1, float y1) {
0N/A path.lineTo(x1, y1);
0N/A }
0N/A
0N/A public void appendQuadratic(float xm, float ym, float x1, float y1) {
0N/A path.quadTo(xm, ym, x1, y1);
0N/A }
0N/A
0N/A public void appendCubic(float xm, float ym,
0N/A float xn, float yn,
0N/A float x1, float y1) {
0N/A path.curveTo(xm, ym, xn, yn, x1, y1);
0N/A }
0N/A
0N/A public void closedSubpath() {
0N/A closed = true;
0N/A }
0N/A
0N/A public void endPath() {
0N/A if (closed) {
0N/A path.closePath();
0N/A closed = false;
0N/A }
0N/A }
0N/A
0N/A public void useProxy(FastPathProducer proxy)
0N/A throws PathException
0N/A {
0N/A proxy.sendTo(this);
0N/A }
0N/A
0N/A public long getCPathConsumer() {
0N/A return 0;
0N/A }
0N/A }
0N/A}