diff options
Diffstat (limited to 'src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java')
-rw-r--r-- | src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java b/src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java new file mode 100644 index 000000000..dcbebb2fb --- /dev/null +++ b/src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java @@ -0,0 +1,417 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.java2d.pipe; + +import java.awt.Shape; +import java.awt.BasicStroke; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.AffineTransform; +import sun.java2d.SunGraphics2D; +import sun.awt.SunHints; + +/** + * This class converts calls to the basic pixel rendering methods + * into calls to the methods on a ParallelogramPipe. + * Most calls are transformed into calls to the fill(Shape) method + * by the parent PixelToShapeConverter class, but some calls are + * transformed into calls to fill/drawParallelogram(). + */ +public class PixelToParallelogramConverter extends PixelToShapeConverter + implements ShapeDrawPipe +{ + ParallelogramPipe outrenderer; + double minPenSize; + double normPosition; + double normRoundingBias; + boolean adjustfill; + + /** + * @param shapepipe pipeline to forward shape calls to + * @param pgrampipe pipeline to forward parallelogram calls to + * (and drawLine calls if possible) + * @param minPenSize minimum pen size for dropout control + * @param normPosition sub-pixel location to normalize endpoints + * for STROKE_NORMALIZE cases + * @param adjustFill boolean to control whethere normalization + * constants are also applied to fill operations + * (normally true for non-AA, false for AA) + */ + public PixelToParallelogramConverter(ShapeDrawPipe shapepipe, + ParallelogramPipe pgrampipe, + double minPenSize, + double normPosition, + boolean adjustfill) + { + super(shapepipe); + outrenderer = pgrampipe; + this.minPenSize = minPenSize; + this.normPosition = normPosition; + this.normRoundingBias = 0.5 - normPosition; + this.adjustfill = adjustfill; + } + + public void drawLine(SunGraphics2D sg2d, + int x1, int y1, int x2, int y2) + { + if (!drawGeneralLine(sg2d, x1, y1, x2, y2)) { + super.drawLine(sg2d, x1, y1, x2, y2); + } + } + + public void drawRect(SunGraphics2D sg2d, + int x, int y, int w, int h) + { + if (w >= 0 && h >= 0) { + if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { + BasicStroke bs = ((BasicStroke) sg2d.stroke); + if (w > 0 && h > 0) { + if (bs.getLineJoin() == BasicStroke.JOIN_MITER && + bs.getDashArray() == null) + { + double lw = bs.getLineWidth(); + drawRectangle(sg2d, x, y, w, h, lw); + return; + } + } else { + // Note: This calls the integer version which + // will verify that the local drawLine optimizations + // work and call super.drawLine(), if not. + drawLine(sg2d, x, y, x+w, y+h); + return; + } + } + super.drawRect(sg2d, x, y, w, h); + } + } + + public void fillRect(SunGraphics2D sg2d, + int x, int y, int w, int h) + { + if (w > 0 && h > 0) { + fillRectangle(sg2d, x, y, w, h); + } + } + + public void draw(SunGraphics2D sg2d, Shape s) { + if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { + BasicStroke bs = ((BasicStroke) sg2d.stroke); + if (s instanceof Rectangle2D) { + if (bs.getLineJoin() == BasicStroke.JOIN_MITER && + bs.getDashArray() == null) + { + Rectangle2D r2d = (Rectangle2D) s; + double w = r2d.getWidth(); + double h = r2d.getHeight(); + double x = r2d.getX(); + double y = r2d.getY(); + if (w >= 0 && h >= 0) { + double lw = bs.getLineWidth(); + drawRectangle(sg2d, x, y, w, h, lw); + } + return; + } + } else if (s instanceof Line2D) { + Line2D l2d = (Line2D) s; + if (drawGeneralLine(sg2d, + l2d.getX1(), l2d.getY1(), + l2d.getX2(), l2d.getY2())) + { + return; + } + } + } + + outpipe.draw(sg2d, s); + } + + public void fill(SunGraphics2D sg2d, Shape s) { + if (s instanceof Rectangle2D) { + Rectangle2D r2d = (Rectangle2D) s; + double w = r2d.getWidth(); + double h = r2d.getHeight(); + if (w > 0 && h > 0) { + double x = r2d.getX(); + double y = r2d.getY(); + fillRectangle(sg2d, x, y, w, h); + } + return; + } + + outpipe.fill(sg2d, s); + } + + static double len(double x, double y) { + return ((x == 0) ? Math.abs(y) + : ((y == 0) ? Math.abs(x) + : Math.sqrt(x * x + y * y))); + } + + double normalize(double v) { + return Math.floor(v + normRoundingBias) + normPosition; + } + + public boolean drawGeneralLine(SunGraphics2D sg2d, + double x1, double y1, + double x2, double y2) + { + if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM || + sg2d.strokeState == SunGraphics2D.STROKE_THINDASHED) + { + return false; + } + BasicStroke bs = (BasicStroke) sg2d.stroke; + int cap = bs.getEndCap(); + if (cap == BasicStroke.CAP_ROUND || bs.getDashArray() != null) { + // TODO: we could construct the GeneralPath directly + // for CAP_ROUND and save a lot of processing in that case... + // And again, we would need to deal with dropout control... + return false; + } + double lw = bs.getLineWidth(); + // Save the original dx, dy in case we need it to transform + // the linewidth as a perpendicular vector below + double dx = x2 - x1; + double dy = y2 - y1; + switch (sg2d.transformState) { + case SunGraphics2D.TRANSFORM_GENERIC: + case SunGraphics2D.TRANSFORM_TRANSLATESCALE: + { + double coords[] = {x1, y1, x2, y2}; + sg2d.transform.transform(coords, 0, coords, 0, 2); + x1 = coords[0]; + y1 = coords[1]; + x2 = coords[2]; + y2 = coords[3]; + } + break; + case SunGraphics2D.TRANSFORM_ANY_TRANSLATE: + case SunGraphics2D.TRANSFORM_INT_TRANSLATE: + { + double tx = sg2d.transform.getTranslateX(); + double ty = sg2d.transform.getTranslateY(); + x1 += tx; + y1 += ty; + x2 += tx; + y2 += ty; + } + break; + case SunGraphics2D.TRANSFORM_ISIDENT: + break; + default: + throw new InternalError("unknown TRANSFORM state..."); + } + if (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) { + if (sg2d.strokeState == SunGraphics2D.STROKE_THIN && + outrenderer instanceof PixelDrawPipe) + { + // PixelDrawPipes will add sg2d.transXY so we need to factor + // that out... + int ix1 = (int) Math.floor(x1 - sg2d.transX); + int iy1 = (int) Math.floor(y1 - sg2d.transY); + int ix2 = (int) Math.floor(x2 - sg2d.transX); + int iy2 = (int) Math.floor(y2 - sg2d.transY); + ((PixelDrawPipe)outrenderer).drawLine(sg2d, ix1, iy1, ix2, iy2); + return true; + } + x1 = normalize(x1); + y1 = normalize(y1); + x2 = normalize(x2); + y2 = normalize(y2); + } + if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { + // Transform the linewidth... + // calculate the scaling factor for a unit vector + // perpendicular to the original user space line. + double len = len(dx, dy); + if (len == 0) { + dx = len = 1; + // dy = 0; already + } + // delta transform the transposed (90 degree rotated) unit vector + double unitvector[] = {dy/len, -dx/len}; + sg2d.transform.deltaTransform(unitvector, 0, unitvector, 0, 1); + lw *= len(unitvector[0], unitvector[1]); + } + lw = Math.max(lw, minPenSize); + dx = x2 - x1; + dy = y2 - y1; + double len = len(dx, dy); + double udx, udy; + if (len == 0) { + if (cap == BasicStroke.CAP_BUTT) { + return true; + } + udx = lw; + udy = 0; + } else { + udx = lw * dx / len; + udy = lw * dy / len; + } + double px = x1 + udy / 2.0; + double py = y1 - udx / 2.0; + if (cap == BasicStroke.CAP_SQUARE) { + px -= udx / 2.0; + py -= udy / 2.0; + dx += udx; + dy += udy; + } + outrenderer.fillParallelogram(sg2d, px, py, -udy, udx, dx, dy); + return true; + } + + public void fillRectangle(SunGraphics2D sg2d, + double rx, double ry, + double rw, double rh) + { + double px, py; + double dx1, dy1, dx2, dy2; + AffineTransform txform = sg2d.transform; + dx1 = txform.getScaleX(); + dy1 = txform.getShearY(); + dx2 = txform.getShearX(); + dy2 = txform.getScaleY(); + px = rx * dx1 + ry * dx2 + txform.getTranslateX(); + py = rx * dy1 + ry * dy2 + txform.getTranslateY(); + dx1 *= rw; + dy1 *= rw; + dx2 *= rh; + dy2 *= rh; + if (adjustfill && + sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && + sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) + { + double newx = normalize(px); + double newy = normalize(py); + dx1 = normalize(px + dx1) - newx; + dy1 = normalize(py + dy1) - newy; + dx2 = normalize(px + dx2) - newx; + dy2 = normalize(py + dy2) - newy; + px = newx; + py = newy; + } + outrenderer.fillParallelogram(sg2d, px, py, dx1, dy1, dx2, dy2); + } + + public void drawRectangle(SunGraphics2D sg2d, + double rx, double ry, + double rw, double rh, + double lw) + { + double px, py; + double dx1, dy1, dx2, dy2; + double lw1, lw2; + AffineTransform txform = sg2d.transform; + dx1 = txform.getScaleX(); + dy1 = txform.getShearY(); + dx2 = txform.getShearX(); + dy2 = txform.getScaleY(); + px = rx * dx1 + ry * dx2 + txform.getTranslateX(); + py = rx * dy1 + ry * dy2 + txform.getTranslateY(); + // lw along dx1,dy1 scale by transformed length of dx2,dy2 vectors + // and vice versa + lw1 = len(dx1, dy1) * lw; + lw2 = len(dx2, dy2) * lw; + dx1 *= rw; + dy1 *= rw; + dx2 *= rh; + dy2 *= rh; + if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && + sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) + { + double newx = normalize(px); + double newy = normalize(py); + dx1 = normalize(px + dx1) - newx; + dy1 = normalize(py + dy1) - newy; + dx2 = normalize(px + dx2) - newx; + dy2 = normalize(py + dy2) - newy; + px = newx; + py = newy; + } + lw1 = Math.max(lw1, minPenSize); + lw2 = Math.max(lw2, minPenSize); + double len1 = len(dx1, dy1); + double len2 = len(dx2, dy2); + if (lw1 >= len1 || lw2 >= len2) { + // The line widths are large enough to consume the + // entire hole in the middle of the parallelogram + // so we can just fill the outer parallelogram. + fillOuterParallelogram(sg2d, + px, py, dx1, dy1, dx2, dy2, + len1, len2, lw1, lw2); + } else { + outrenderer.drawParallelogram(sg2d, + px, py, dx1, dy1, dx2, dy2, + lw1 / len1, lw2 / len2); + } + } + + /** + * This utility function handles the case where a drawRectangle + * operation discovered that the interior hole in the rectangle + * or parallelogram has been completely filled in by the stroke + * width. It calculates the outer parallelogram of the stroke + * and issues a single fillParallelogram request to fill it. + */ + public void fillOuterParallelogram(SunGraphics2D sg2d, + double px, double py, + double dx1, double dy1, + double dx2, double dy2, + double len1, double len2, + double lw1, double lw2) + { + double udx1 = dx1 / len1; + double udy1 = dy1 / len1; + double udx2 = dx2 / len2; + double udy2 = dy2 / len2; + if (len1 == 0) { + // len1 is 0, replace udxy1 with perpendicular of udxy2 + if (len2 == 0) { + // both are 0, use a unit Y vector for udxy2 + udx2 = 0; + udy2 = 1; + } + udx1 = udy2; + udy1 = -udx2; + } else if (len2 == 0) { + // len2 is 0, replace udxy2 with perpendicular of udxy1 + udx2 = udy1; + udy2 = -udx1; + } + udx1 *= lw1; + udy1 *= lw1; + udx2 *= lw2; + udy2 *= lw2; + px -= (udx1 + udx2) / 2; + py -= (udy1 + udy2) / 2; + dx1 += udx1; + dy1 += udy1; + dx2 += udx2; + dy2 += udy2; + + outrenderer.fillParallelogram(sg2d, px, py, dx1, dy1, dx2, dy2); + } +} |