This implements a shape cache for AbstractGraphics2D. This cache keeps
instances of various Shapes around for reuse in the draw* and fill*
methods. This avoids massive creation of such objects and should help
with performance.
This patch also includes a little cleanup and some documentation update.
2006-09-29 Roman Kennke <[EMAIL PROTECTED]>
* 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.
/Roman
Index: gnu/java/awt/java2d/AbstractGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java,v
retrieving revision 1.11
diff -u -1 -5 -r1.11 AbstractGraphics2D.java
--- gnu/java/awt/java2d/AbstractGraphics2D.java 30 Jun 2006 23:19:28 -0000 1.11
+++ gnu/java/awt/java2d/AbstractGraphics2D.java 29 Sep 2006 12:35:51 -0000
@@ -88,74 +88,97 @@
/**
* This is a 100% Java implementation of the Java2D rendering pipeline. It is
* meant as a base class for Graphics2D implementations.
*
* <h2>Backend interface</h2>
* <p>
* The backend must at the very least provide a Raster which the the rendering
* pipeline can paint into. This must be implemented in
* [EMAIL PROTECTED] #getDestinationRaster()}. For some backends that might be enough, like
* when the target surface can be directly access via the raster (like in
* BufferedImages). Other targets need some way to synchronize the raster with
* the surface, which can be achieved by implementing the
* [EMAIL PROTECTED] #updateRaster(Raster, int, int, int, int)} method, which always gets
* called after a chunk of data got painted into the raster.
* </p>
+ * <p>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.</p>
+ * <p>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.</p>
* <p>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
* keep track of the clip and translation, probably by overriding
* some clip and translate methods. Don't forget to message super in such a
* case.</p>
*
* <h2>Acceleration options</h2>
* <p>
* The fact that it is
* pure Java makes it a little slow. However, there are several ways of
* accelerating the rendering pipeline:
* <ol>
* <li><em>Optimization hooks for AWT 1.1 - like graphics operations.</em>
* The most important methods from the [EMAIL PROTECTED] java.awt.Graphics} class
* have a corresponding <code>raw*</code> method, which get called when
* several optimization conditions are fullfilled. These conditions are
* described below. Subclasses can override these methods and delegate
* it directly to a native backend.</li>
* <li><em>Native PaintContexts and CompositeContext.</em> The implementations
* for the 3 PaintContexts and AlphaCompositeContext can be accelerated
* using native code. These have proved to two of the most performance
* critical points in the rendering pipeline and cannot really be done quickly
* 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.</li>
+ * <li>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.</li>
* </ol>
* </p>
*
* @author Roman Kennke ([EMAIL PROTECTED])
*/
public abstract class AbstractGraphics2D
extends Graphics2D
implements Cloneable
{
/**
* Accuracy of the sampling in the anti-aliasing shape filler.
* Lower values give more speed, while higher values give more quality.
* It is advisable to choose powers of two.
*/
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
*/
protected AffineTransform transform;
/**
* The foreground.
*/
private Paint paint;
/**
* The background.
*/
private Color background;
/**
@@ -172,66 +195,61 @@
* The current stroke setting.
*/
private Stroke stroke;
/**
* The current clip. This clip is in user coordinate space.
*/
private Shape clip;
/**
* The rendering hints.
*/
private RenderingHints renderingHints;
/**
- * The paint raster.
- */
- private Raster paintRaster;
-
- /**
* The raster of the destination surface. This is where the painting is
* performed.
*/
private WritableRaster destinationRaster;
/**
* Stores the alpha values for a scanline in the anti-aliasing shape
* renderer.
*/
private transient int[] alpha;
/**
* The edge table for the scanline conversion algorithms.
*/
private transient ArrayList[] edgeTable;
/**
* Indicates if certain graphics primitives can be rendered in an optimized
* fashion. This will be the case if the following conditions are met:
* - The transform may only be a translation, no rotation, shearing or
* scaling.
* - The paint must be a solid color.
* - The composite must be an AlphaComposite.SrcOver.
* - The clip must be a Rectangle.
* - The stroke must be a plain BasicStroke().
*
* These conditions represent the standard settings of a new
* 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.
*/
protected AbstractGraphics2D()
{
transform = new AffineTransform();
background = Color.WHITE;
composite = AlphaComposite.SrcOver;
stroke = new BasicStroke();
HashMap hints = new HashMap();
hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
hints.put(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_DEFAULT);
@@ -258,31 +276,30 @@
* user space conversion.
*
* This method is implemented to special case RenderableImages and
* RenderedImages and delegate to
* [EMAIL PROTECTED] #drawRenderableImage(RenderableImage, AffineTransform)} and
* [EMAIL PROTECTED] #drawRenderedImage(RenderedImage, AffineTransform)} accordingly.
* Other image types are not yet handled.
*
* @param image the image to be rendered
* @param xform the transform from image space to user space
* @param obs the image observer to be notified
*/
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);
}
/**
* Draws the specified image and apply the transform for image space ->
* user space conversion. This method only draw the part of the image
* specified by <code>areaOfInterest</code>.
*
* This method is implemented to special case RenderableImages and
* RenderedImages and delegate to
* [EMAIL PROTECTED] #drawRenderableImage(RenderableImage, AffineTransform)} and
* [EMAIL PROTECTED] #drawRenderedImage(RenderedImage, AffineTransform)} accordingly.
* Other image types are not yet handled.
@@ -1131,60 +1148,79 @@
rawCopyArea(x, y, width, height, dx, dy);
else
copyAreaImpl(x, y, width, height, dx, dy);
}
/**
* Draws a line from (x1, y1) to (x2, y2).
*
* This implementation transforms the coordinates and forwards the call to
* [EMAIL PROTECTED] #rawDrawLine}.
*/
public void drawLine(int x1, int y1, int x2, int y2)
{
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);
}
}
/**
* Fills a rectangle with the current paint.
*
* @param x the upper left corner, X coordinate
* @param y the upper left corner, Y coordinate
* @param width the width of the rectangle
* @param height the height of the rectangle
*/
public void fillRect(int x, int y, int width, int height)
{
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);
}
}
/**
* Fills a rectangle with the current background color.
*
* This implementation temporarily sets the foreground color to the
* background and forwards the call to [EMAIL PROTECTED] #fillRect(int, int, int, int)}.
*
* @param x the upper left corner, X coordinate
* @param y the upper left corner, Y coordinate
* @param width the width of the rectangle
* @param height the height of the rectangle
*/
public void clearRect(int x, int y, int width, int height)
@@ -1201,117 +1237,149 @@
}
/**
* Draws a rounded rectangle.
*
* @param x the x coordinate of the rectangle
* @param y the y coordinate of the rectangle
* @param width the width of the rectangle
* @param height the height of the rectangle
* @param arcWidth the width of the arcs
* @param arcHeight the height of the arcs
*/
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);
}
/**
* Fills a rounded rectangle.
*
* @param x the x coordinate of the rectangle
* @param y the y coordinate of the rectangle
* @param width the width of the rectangle
* @param height the height of the rectangle
* @param arcWidth the width of the arcs
* @param arcHeight the height of the arcs
*/
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);
}
/**
* Draws the outline of an oval.
*
* @param x the upper left corner of the bounding rectangle of the ellipse
* @param y the upper left corner of the bounding rectangle of the ellipse
* @param width the width of the ellipse
* @param height the height of the ellipse
*/
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);
}
/**
* Fills an oval.
*
* @param x the upper left corner of the bounding rectangle of the ellipse
* @param y the upper left corner of the bounding rectangle of the ellipse
* @param width the width of the ellipse
* @param height the height of the ellipse
*/
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);
}
/**
* Draws an arc.
*/
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);
}
/**
* Fills an arc.
*/
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)
{
// FIXME: Implement this.
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Draws the outline of a polygon.
*/
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);
}
/**
* Fills the outline of a polygon.
*/
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);
}
/**
* Draws the specified image at the specified location. This forwards
* to [EMAIL PROTECTED] #drawImage(Image, AffineTransform, ImageObserver)}.
*
* @param image the image to render
* @param x the x location to render to
* @param y the y location to render to
* @param observer the image observer to receive notification
*/
public boolean drawImage(Image image, int x, int y, ImageObserver observer)
{
boolean ret;
if (isOptimized)
@@ -1448,32 +1516,36 @@
ImageObserver observer)
{
// FIXME: Do something with bgcolor.
return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
}
/**
* Disposes this graphics object.
*/
public void dispose()
{
// Nothing special to do here.
}
/**
- * 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 <code>true</code> if the shape is a font outline
*/
protected void fillShape(Shape s, boolean isFont)
{
// Determine if we need to antialias stuff.
boolean antialias = false;
if (isFont)
{
Object v = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
// We default to antialiasing on for text as long as we have no
// good hinting implemented.
antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//|| v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
@@ -1521,30 +1593,35 @@
/**
* Draws a line in optimization mode. The implementation should respect the
* clip and translation. It can assume that the clip is a rectangle and that
* the transform is only a translating transform.
*
* @param x0 the starting point, X coordinate
* @param y0 the starting point, Y coordinate
* @param x1 the end point, X coordinate
* @param y1 the end point, Y coordinate
*/
protected void rawDrawLine(int x0, int y0, int x1, int y1)
{
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
* the transform is only a translating transform.
*
* @param text the string to be drawn
* @param x the start of the baseline, X coordinate
* @param y the start of the baseline, Y coordinate
*/
protected void rawDrawString(String text, int x, int y)
{
FontRenderContext ctx = getFontRenderContext();
GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
drawGlyphVector(gv, x, y);
}
@@ -1615,66 +1692,62 @@
copyAreaImpl(x, y, w, h, dx, dy);
}
// Private implementation methods.
/**
* Copies a rectangular area of the target raster to a different location.
*/
private void copyAreaImpl(int x, int y, int w, int h, int dx, int dy)
{
// FIXME: Implement this properly.
throw new UnsupportedOperationException("Not implemented yet.");
}
/**
- * 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,
Rectangle2D inclClipBounds)
{
// This is an implementation of a polygon scanline conversion algorithm
// described here:
// http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/scan/
// Create table of all edges.
// The edge buckets, sorted and indexed by their Y values.
double minX = deviceBounds2D.getMinX();
double minY = deviceBounds2D.getMinY();
double maxX = deviceBounds2D.getMaxX();
double maxY = deviceBounds2D.getMaxY();
double icMinY = inclClipBounds.getMinY();
double icMaxY = inclClipBounds.getMaxY();
Rectangle deviceBounds = new Rectangle((int) minX, (int) minY,
(int) Math.ceil(maxX) - (int) minX,
(int) Math.ceil(maxY) - (int) minY);
PaintContext pCtx = paint.createContext(getColorModel(), deviceBounds,
userBounds, transform, renderingHints);
ArrayList[] edgeTable = new ArrayList[(int) Math.ceil(icMaxY)
- (int) Math.ceil(icMinY) + 1];
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.
}
// TODO: The following could be useful for a future optimization.
// // Sort all the edges in the edge table within their buckets.
// for (int y = 0; y < edgeTable.length; y++)
// {
// if (edgeTable[y] != null)
// Collections.sort(edgeTable[y]);
// }
// The activeEdges list contains all the edges of the current scanline
// ordered by their intersection points with this scanline.
@@ -1754,31 +1827,32 @@
if (x0 < x1)
fillScanline(pCtx, x0, x1, y);
}
// Update state.
previous = edge;
if (edge.isClip)
insideClip = ! insideClip;
else
insideShape = ! insideShape;
}
}
pCtx.dispose();
}
/**
- * 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
* @param y the scanline
*/
protected void fillScanline(PaintContext pCtx, int x0, int x1, int y)
{
Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1);
ColorModel paintColorModel = pCtx.getColorModel();
CompositeContext cCtx = composite.createContext(paintColorModel,
getColorModel(),
renderingHints);
WritableRaster targetChild = destinationRaster.createWritableTranslatedChild(-x0,- y);
cCtx.compose(paintRaster, targetChild, targetChild);
updateRaster(destinationRaster, x0, y, x1 - x0, 1);
@@ -1960,56 +2034,54 @@
emptyScanline = false;
}
}
previous = edge;
if (edge.isClip)
insideClip = ! insideClip;
else
insideShape = ! insideShape;
}
yindex++;
}
firstSubline = 0;
// 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();
}
/**
* Fills a horizontal line between x0 and x1 for anti aliased rendering.
* the alpha array contains the deltas of the alpha values from one pixel
* to the next.
*
* @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)
{
CompositeContext cCtx = composite.createContext(pCtx.getColorModel(),
getColorModel(),
renderingHints);
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;
Object pixel = null;
int[] comps = null;
int x1 = x0 + numPixels;
for (int x = x0; x < x1; x++)
{
int i = x - offs;
if (alpha[i] != 0)
{
lastAlphaInt += alpha[i];
lastAlpha = (double) lastAlphaInt / (double) AA_SAMPLING;
alpha[i] = 0;
@@ -2144,34 +2216,34 @@
* @param x upper-left x coodinate of first rectangle
* @param y upper-left y coodinate of first rectangle
* @param w width of first rectangle
* @param h height of first rectangle
* @param rect a Rectangle object of the second rectangle
*
* @throws NullPointerException if rect is null
*
* @return a rectangle corresponding to the intersection of the
* two rectangles. An empty rectangle is returned if the rectangles
* do not overlap
*/
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;
int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
if (dw >= 0 && dh >= 0)
rect.setBounds(dx, dy, dw, dh);
else
rect.setBounds(0, 0, 0, 0);
return rect;
}
/**
@@ -2254,16 +2326,32 @@
segs.add(edge);
}
else if (segType == PathIterator.SEG_LINETO)
{
PolyEdge edge = new PolyEdge(segX, segY,
seg[0], seg[1], isClip);
segs.add(edge);
segX = seg[0];
segY = seg[1];
}
path.next();
}
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;
+ }
}
Index: gnu/java/awt/java2d/ShapeCache.java
===================================================================
RCS file: gnu/java/awt/java2d/ShapeCache.java
diff -N gnu/java/awt/java2d/ShapeCache.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gnu/java/awt/java2d/ShapeCache.java 29 Sep 2006 12:35:51 -0000
@@ -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;
+
+}