/* * This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com> * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) */ /* * @(#)DuctusRenderer.java 1.16 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package sun.java2d.pipe; import java.awt.geom.AffineTransform; import java.awt.BasicStroke; import java.awt.Shape; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import sun.dc.path.PathConsumer; import sun.dc.path.PathException; import sun.dc.pr.Rasterizer; import sun.dc.pr.PathStroker; import sun.dc.pr.PathDasher; import sun.dc.pr.PRException; /** * This is the superclass of any class that needs to use the Ductus * Rasterizer. * This class provides utility routines to create, cache, initialize * and release Rasterizer objects. */ public class DuctusRenderer { public static final float PenUnits = 0.01f; public static final int MinPenUnits = 100; public static final int MinPenUnitsAA = 20; public static final float MinPenSizeAA = PenUnits * MinPenUnitsAA; static final float UPPER_BND = 1.701412E+038F; static final float LOWER_BND = -UPPER_BND; static final int RasterizerCaps[] = { Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE }; static final int RasterizerCorners[] = { Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL }; 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; } private static byte[] theTile; public synchronized static byte[] getAlphaTile() { byte[] t = theTile; if (t == null) { int dim = Rasterizer.TILE_SIZE; t = new byte[dim * dim]; } else { theTile = null; } return t; } public synchronized static void dropAlphaTile(byte[] t) { theTile = t; } /* * writeAlpha is not threadsafe (it uses a global table without * locking), so we must use this static synchronized accessor * method to serialize accesses to it. */ public synchronized static void getAlpha(Rasterizer r, byte[] alpha, int xstride, int ystride, int offset) throws PRException { try { r.writeAlpha(alpha, xstride, ystride, offset); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } /* * Returns a new PathConsumer that will take a path trajectory and * feed the stroked outline for that trajectory to the supplied * PathConsumer. */ public static PathConsumer createStroker(PathConsumer consumer, BasicStroke bs, boolean thin, AffineTransform transform) { PathStroker stroker = new PathStroker(consumer); consumer = stroker; float matrix[] = null; if (!thin) { stroker.setPenDiameter(bs.getLineWidth()); if (transform != null) { matrix = new float[4]; double dmatrix[] = new double[6]; transform.getMatrix(dmatrix); for (int i = 0; i < 4; i++) { matrix[i] = (float) dmatrix[i]; } } 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()); dasher.setDashT4(matrix); consumer = dasher; } return consumer; } /* * Feed a path from a PathIterator to a Ductus PathConsumer. */ public static void feedConsumer(PathIterator pi, PathConsumer consumer, boolean normalize, float norm) throws PathException { consumer.beginPath(); boolean pathClosed = false; boolean subpathBegin = false; boolean subpathOpened = 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) { // Force current point back to last moveto point consumer.beginSubpath(mx, my); subpathOpened = 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) { default: break; 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); subpathOpened = true; subpathBegin = false; } else { subpathBegin = true; } break; case PathIterator.SEG_LINETO: if (point[0] >= UPPER_BND || point[0] <= LOWER_BND || point[1] >= UPPER_BND || point[1] <= LOWER_BND) { break; } if (subpathBegin) { consumer.beginSubpath(point[0], point[1]); subpathOpened = true; subpathBegin = 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) { break; } if (subpathBegin) { consumer.beginSubpath(point[2], point[3]); subpathOpened = true; subpathBegin = false; break; } 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) { break; } if (subpathBegin) { consumer.beginSubpath(point[4], point[5]); subpathOpened = true; subpathBegin = false; break; } 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 (subpathOpened) { consumer.closedSubpath(); subpathOpened = false; pathClosed = true; } break; } pi.next(); } consumer.endPath(); } /* * Returns a new Rasterizer that is ready to rasterize the given Shape. */ public static Rasterizer createShapeRasterizer(PathIterator pi, AffineTransform transform, BasicStroke stroke, boolean thin, boolean normalize, float norm) { Rasterizer r = getRasterizer(); if (stroke != null) { float matrix[] = null; r.setUsage(Rasterizer.STROKE); if (thin) { r.setPenDiameter(MinPenSizeAA); } else { r.setPenDiameter(stroke.getLineWidth()); if (transform != null) { matrix = new float[4]; double dmatrix[] = new double[6]; transform.getMatrix(dmatrix); for (int i = 0; i < 4; i++) { matrix[i] = (float) dmatrix[i]; } r.setPenT4(matrix); } r.setPenFitting(PenUnits, MinPenUnitsAA); } r.setCaps(RasterizerCaps[stroke.getEndCap()]); r.setCorners(RasterizerCorners[stroke.getLineJoin()], stroke.getMiterLimit()); float[] dashes = stroke.getDashArray(); if (dashes != null) { r.setDash(dashes, stroke.getDashPhase()); r.setDashT4(matrix); } } else { r.setUsage(pi.getWindingRule() == PathIterator.WIND_EVEN_ODD ? Rasterizer.EOFILL : Rasterizer.NZFILL); } r.beginPath(); { boolean pathClosed = false; boolean subpathBegin = false; boolean subpathOpened = 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) { // Force current point back to last moveto point r.beginSubpath(mx, my); subpathOpened = 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) { default: break; 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]; r.beginSubpath(mx, my); subpathOpened = true; subpathBegin = false; } else { subpathBegin = true; } break; case PathIterator.SEG_LINETO: if (point[0] >= UPPER_BND || point[0] <= LOWER_BND || point[1] >= UPPER_BND || point[1] <= LOWER_BND) { break; } if (subpathBegin) { r.beginSubpath(point[0], point[1]); subpathOpened = true; subpathBegin = 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) { break; } if (subpathBegin) { r.beginSubpath(point[2], point[3]); subpathOpened = true; subpathBegin = false; break; } 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 if (point[4] >= UPPER_BND || point[4] <= LOWER_BND || point[5] >= UPPER_BND || point[5] <= LOWER_BND) { break; } if (subpathBegin) { r.beginSubpath(point[4], point[5]); subpathOpened = true; subpathBegin = false; break; } 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 (subpathOpened) { r.closedSubpath(); subpathOpened = false; pathClosed = true; } break; } pi.next(); } } try { r.endPath(); } catch (PRException e) { e.printStackTrace(); } return r; } }