aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java')
-rw-r--r--src/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java417
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);
+ }
+}