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;
+
+}

Reply via email to