From f8ee3c2cfbfbdc8aa3d47c274fd2f2f77c57aa34 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Fri, 29 Sep 2006 12:36:31 +0000 Subject: 2006-09-29 Roman Kennke * gnu/java/awt/java2d/AbstractGraphics2D.java: Updated API docs. (isOptimized): Initialize with true. (paintRaster): Removed unneeded field. (shapeCache): New static field. Caches certain shapes for reuse. (computeIntersection): Removed unneeded casts. (drawArc): Use shape cache. (drawImage): Removed unneeded statement. (drawLine): Use shape cache. Pass untranslated coordinates to rawDrawLine(). (drawOval): Use shape cache. (drawPolygon): Use shape cache. (drawRect): Overridden to provide accelerated rectangle drawing if possible and to use the shape cache. (drawRoundRect): Use shape cache. (fillArc): Use shape cache. (fillOval): Use shape cache. (fillPolygon): Use shape cache. (fillRect): Pass untranslated coordinates to rawFillRect(). Use shape cache. (fillRoundRect): Use shape cache. (fillScanlineAA): Removed unneeded statement. (fillScanline): Updated API docs. (fillShapeAntialias): Removed unnecessary cast. (fillShapeImpl): Update API docs. Removed unnecessary cast. (fillShape): Updated API docs. (getShapeCache): New helper method. * gnu/java/awt/java2d/ShapeCache.java: New class. Caches certain shapes for reuse in AbstractGraphics2D. --- gnu/java/awt/java2d/AbstractGraphics2D.java | 178 +++++++++++++++++++++------- gnu/java/awt/java2d/ShapeCache.java | 85 +++++++++++++ 2 files changed, 218 insertions(+), 45 deletions(-) create mode 100644 gnu/java/awt/java2d/ShapeCache.java (limited to 'gnu/java/awt/java2d') diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java index 9d017240d..db4bdb4ff 100644 --- a/gnu/java/awt/java2d/AbstractGraphics2D.java +++ b/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -100,6 +100,20 @@ import java.util.Map; * {@link #updateRaster(Raster, int, int, int, int)} method, which always gets * called after a chunk of data got painted into the raster. *

+ *

Alternativly the backend can provide a method for filling Shapes by + * overriding the protected method fillShape(). This can be accomplished + * by a polygon filling function of the backend. Keep in mind though that + * Shapes can be quite complex (i.e. non-convex and containing holes, etc) + * which is not supported by all polygon fillers. Also it must be noted + * that fillShape() is expected to handle painting and compositing as well as + * clipping and transformation. If your backend can't support this natively, + * then you can fallback to the implementation in this class. You'll need + * to provide a writable Raster then, see above.

+ *

Another alternative is to implement fillScanline() which only requires + * the backend to be able to draw horizontal lines in device space, + * which is usually very cheap. + * The implementation should still handle painting and compositing, + * but no more clipping and transformation is required by the backend.

*

The backend is free to provide implementations for the various raw* * methods for optimized AWT 1.1 style painting of some primitives. This should * accelerate painting of Swing greatly. When doing so, the backend must also @@ -126,6 +140,9 @@ import java.util.Map; * in plain Java because they involve lots of shuffling around with large * arrays. In fact, you really would want to let the graphics card to the * work, they are made for this. + *

  • Provide an accelerated implementation for fillShape(). For instance, + * OpenGL can fill shapes very efficiently. There are some considerations + * to be made though, see above for details.
  • * *

    * @@ -143,6 +160,12 @@ public abstract class AbstractGraphics2D */ private static final int AA_SAMPLING = 8; + /** + * Caches certain shapes to avoid massive creation of such Shapes in + * the various draw* and fill* methods. + */ + private static final ThreadLocal shapeCache = new ThreadLocal(); + /** * The transformation for this Graphics2D instance */ @@ -183,11 +206,6 @@ public abstract class AbstractGraphics2D */ private RenderingHints renderingHints; - /** - * The paint raster. - */ - private Raster paintRaster; - /** * The raster of the destination surface. This is where the painting is * performed. @@ -219,7 +237,7 @@ public abstract class AbstractGraphics2D * AbstractGraphics2D object and will be the most commonly used setting * in Swing rendering and should therefore be optimized as much as possible. */ - private boolean isOptimized; + private boolean isOptimized = true; /** * Creates a new AbstractGraphics2D instance. @@ -270,7 +288,6 @@ public abstract class AbstractGraphics2D public boolean drawImage(Image image, AffineTransform xform, ImageObserver obs) { - boolean ret = false; Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs), image.getHeight(obs)); return drawImageImpl(image, xform, obs, areaOfInterest); @@ -1143,14 +1160,31 @@ public abstract class AbstractGraphics2D { if (isOptimized) { - int tx = (int) transform.getTranslateX(); - int ty = (int) transform.getTranslateY(); - rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty); + rawDrawLine(x1, y1, x2, y2); } else { - Line2D line = new Line2D.Double(x1, y1, x2, y2); - draw(line); + ShapeCache sc = getShapeCache(); + if (sc.line == null) + sc.line = new Line2D.Float(); + sc.line.setLine(x1, y1, x2, y2); + draw(sc.line); + } + } + + public void drawRect(int x, int y, int w, int h) + { + if (isOptimized) + { + rawDrawRect(x, y, w, h); + } + else + { + ShapeCache sc = getShapeCache(); + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + draw(sc.rect); } } @@ -1166,13 +1200,15 @@ public abstract class AbstractGraphics2D { if (isOptimized) { - int tx = (int) transform.getTranslateX(); - int ty = (int) transform.getTranslateY(); - rawFillRect(x + tx, y + ty, width, height); + rawFillRect(x, y, width, height); } else { - fill(new Rectangle(x, y, width, height)); + ShapeCache sc = getShapeCache(); + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, width, height); + fill(sc.rect); } } @@ -1213,8 +1249,11 @@ public abstract class AbstractGraphics2D public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, - arcHeight)); + ShapeCache sc = getShapeCache(); + if (sc.roundRect == null) + sc.roundRect = new RoundRectangle2D.Float(); + sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight); + draw(sc.roundRect); } /** @@ -1230,8 +1269,11 @@ public abstract class AbstractGraphics2D public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, - arcHeight)); + ShapeCache sc = getShapeCache(); + if (sc.roundRect == null) + sc.roundRect = new RoundRectangle2D.Float(); + sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight); + fill(sc.roundRect); } /** @@ -1244,7 +1286,11 @@ public abstract class AbstractGraphics2D */ public void drawOval(int x, int y, int width, int height) { - draw(new Ellipse2D.Double(x, y, width, height)); + ShapeCache sc = getShapeCache(); + if (sc.ellipse == null) + sc.ellipse = new Ellipse2D.Float(); + sc.ellipse.setFrame(x, y, width, height); + draw(sc.ellipse); } /** @@ -1257,7 +1303,11 @@ public abstract class AbstractGraphics2D */ public void fillOval(int x, int y, int width, int height) { - fill(new Ellipse2D.Double(x, y, width, height)); + ShapeCache sc = getShapeCache(); + if (sc.ellipse == null) + sc.ellipse = new Ellipse2D.Float(); + sc.ellipse.setFrame(x, y, width, height); + fill(sc.ellipse); } /** @@ -1266,8 +1316,11 @@ public abstract class AbstractGraphics2D public void drawArc(int x, int y, int width, int height, int arcStart, int arcAngle) { - draw(new Arc2D.Double(x, y, width, height, arcStart, arcAngle, - Arc2D.OPEN)); + ShapeCache sc = getShapeCache(); + if (sc.arc == null) + sc.arc = new Arc2D.Float(); + sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN); + draw(sc.arc); } /** @@ -1276,8 +1329,11 @@ public abstract class AbstractGraphics2D public void fillArc(int x, int y, int width, int height, int arcStart, int arcAngle) { - fill(new Arc2D.Double(x, y, width, height, arcStart, arcAngle, - Arc2D.OPEN)); + ShapeCache sc = getShapeCache(); + if (sc.arc == null) + sc.arc = new Arc2D.Float(); + sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE); + draw(sc.arc); } public void drawPolyline(int[] xPoints, int[] yPoints, int npoints) @@ -1291,7 +1347,13 @@ public abstract class AbstractGraphics2D */ public void drawPolygon(int[] xPoints, int[] yPoints, int npoints) { - draw(new Polygon(xPoints, yPoints, npoints)); + ShapeCache sc = getShapeCache(); + if (sc.polygon == null) + sc.polygon = new Polygon(); + sc.polygon.xpoints = xPoints; + sc.polygon.ypoints = yPoints; + sc.polygon.npoints = npoints; + draw(sc.polygon); } /** @@ -1299,7 +1361,13 @@ public abstract class AbstractGraphics2D */ public void fillPolygon(int[] xPoints, int[] yPoints, int npoints) { - fill(new Polygon(xPoints, yPoints, npoints)); + ShapeCache sc = getShapeCache(); + if (sc.polygon == null) + sc.polygon = new Polygon(); + sc.polygon.xpoints = xPoints; + sc.polygon.ypoints = yPoints; + sc.polygon.npoints = npoints; + fill(sc.polygon); } /** @@ -1460,8 +1528,12 @@ public abstract class AbstractGraphics2D } /** - * Fills the specified shape. The shape has already been clipped against the - * current clip. + * Fills the specified shape. Override this if your backend can efficiently + * fill shapes. This is possible on many systems via a polygon fill + * method or something similar. But keep in mind that Shapes can be quite + * complex (non-convex, with holes etc), which is not necessarily supported + * by all polygon fillers. Also note that you must perform clipping + * before filling the shape. * * @param s the shape to fill * @param isFont true if the shape is a font outline @@ -1533,6 +1605,11 @@ public abstract class AbstractGraphics2D draw(new Line2D.Float(x0, y0, x1, y1)); } + protected void rawDrawRect(int x, int y, int w, int h) + { + draw(new Rectangle(x, y, w, h)); + } + /** * Draws a string in optimization mode. The implementation should respect the * clip and translation. It can assume that the clip is a rectangle and that @@ -1627,11 +1704,7 @@ public abstract class AbstractGraphics2D } /** - * Fills the specified polygon. This should be overridden by backends - * that support accelerated (native) polygon filling, which is the - * case for most toolkit window and offscreen image implementations. - * - * The polygon is already clipped when this method is called. + * Fills the specified polygon without anti-aliasing. */ private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D, Rectangle2D userBounds, @@ -1662,7 +1735,7 @@ public abstract class AbstractGraphics2D for (Iterator i = segs.iterator(); i.hasNext();) { PolyEdge edge = (PolyEdge) i.next(); - int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY)); + int yindex = (int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY); if (edgeTable[yindex] == null) // Create bucket when needed. edgeTable[yindex] = new ArrayList(); edgeTable[yindex].add(edge); // Add edge to the bucket of its line. @@ -1766,7 +1839,8 @@ public abstract class AbstractGraphics2D } /** - * Paints a scanline between x0 and x1. + * Paints a scanline between x0 and x1. Override this when your backend + * can efficiently draw/fill horizontal lines. * * @param x0 the left offset * @param x1 the right offset @@ -1972,8 +2046,7 @@ public abstract class AbstractGraphics2D // Render full scanline. //System.err.println("scanline: " + y); if (! emptyScanline) - fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx, - (int) minX); + fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX); } pCtx.dispose(); @@ -1986,7 +2059,7 @@ public abstract class AbstractGraphics2D * * @param alpha the alpha values in the scanline * @param x0 the beginning of the scanline - * @param y the y coordinate of the line + * @param yy the y coordinate of the line */ private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels, PaintContext pCtx, int offs) @@ -1997,7 +2070,6 @@ public abstract class AbstractGraphics2D Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1); //System.err.println("paintColorModel: " + pCtx.getColorModel()); WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster(); - int numBands = paintRaster.getNumBands(); ColorModel cm = pCtx.getColorModel(); double lastAlpha = 0.; int lastAlphaInt = 0; @@ -2156,10 +2228,10 @@ public abstract class AbstractGraphics2D private static Rectangle computeIntersection(int x, int y, int w, int h, Rectangle rect) { - int x2 = (int) rect.x; - int y2 = (int) rect.y; - int w2 = (int) rect.width; - int h2 = (int) rect.height; + int x2 = rect.x; + int y2 = rect.y; + int w2 = rect.width; + int h2 = rect.height; int dx = (x > x2) ? x : x2; int dy = (y > y2) ? y : y2; @@ -2266,4 +2338,20 @@ public abstract class AbstractGraphics2D deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY); return segs; } + + /** + * Returns the ShapeCache for the calling thread. + * + * @return the ShapeCache for the calling thread + */ + private ShapeCache getShapeCache() + { + ShapeCache sc = (ShapeCache) shapeCache.get(); + if (sc == null) + { + sc = new ShapeCache(); + shapeCache.set(sc); + } + return sc; + } } diff --git a/gnu/java/awt/java2d/ShapeCache.java b/gnu/java/awt/java2d/ShapeCache.java new file mode 100644 index 000000000..034b53cad --- /dev/null +++ b/gnu/java/awt/java2d/ShapeCache.java @@ -0,0 +1,85 @@ +/* ShapeCache.java -- Caches certain Shapes for reuse in AbstractGraphics2D + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.java2d; + +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.RoundRectangle2D; + +/** + * Caches certain Shape objects for reuse in AbstractGraphics2D. This avoids + * massive creation of such objects. + */ +public class ShapeCache +{ + + /** + * A cached Line2D. + */ + public Line2D line; + + /** + * A cached Rectangle. + */ + public Rectangle rect; + + /** + * A cached RoundRectangle2D. + */ + public RoundRectangle2D roundRect; + + /** + * A cached Ellipse2D. + */ + public Ellipse2D ellipse; + + /** + * A cached Arc2D. + */ + public Arc2D arc; + + /** + * A cached Polygon. + */ + public Polygon polygon; + +} -- cgit v1.2.1