Merged gcj-eclipse branch to trunk.

From-SVN: r120621
This commit is contained in:
Tom Tromey
2007-01-09 19:58:05 +00:00
parent c648dedbde
commit 97b8365caf
17478 changed files with 606493 additions and 100744 deletions
@@ -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.
* </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
@@ -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.</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>
*
@@ -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);
@@ -982,7 +999,8 @@ public abstract class AbstractGraphics2D
else
copy.clip = new GeneralPath(clip);
copy.renderingHints = new RenderingHints(renderingHints);
copy.renderingHints = new RenderingHints(null);
copy.renderingHints.putAll(renderingHints);
copy.transform = new AffineTransform(transform);
// The remaining state is inmmutable and doesn't need to be copied.
return copy;
@@ -1143,14 +1161,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 +1201,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 +1250,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 +1270,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 +1287,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 +1304,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 +1317,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 +1330,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 +1348,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 +1362,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 +1529,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 <code>true</code> if the shape is a font outline
@@ -1533,6 +1606,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 +1705,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 +1736,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 +1840,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 +2047,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 +2060,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 +2071,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 +2229,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 +2339,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;
}
}
@@ -145,7 +145,52 @@ public class QuadSegment extends Segment
Point2D cp;
QuadSegment s;
if( plus )
if(!plus)
{
n1[0] = -n1[0];
n1[1] = -n1[1];
n2[0] = -n2[0];
n2[1] = -n2[1];
}
// Handle special cases where the control point is equal to an end point
// or end points are equal (ie, straight lines)
if (curve.getP1().equals(curve.getCtrlPt()))
{
cp = curve.getCtrlPt();
cp.setLocation(cp.getX() + n2[0], cp.getY() + n2[1]);
n1[0] = n2[0];
n1[1] = n2[1];
}
else if (curve.getP2().equals(curve.getCtrlPt()))
{
cp = curve.getCtrlPt();
cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
n2[0] = n1[0];
n2[1] = n1[1];
}
else if (curve.getP1().equals(curve.getP2()))
{
cp = curve.getCtrlPt();
double deltaX = curve.getX1() - curve.getCtrlX();
double deltaY = curve.getY1() - curve.getCtrlY();
double length = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
double ratio = radius / length;
deltaX *= ratio;
deltaY *= ratio;
if (plus)
cp.setLocation(cp.getX() + deltaX, cp.getY() + deltaY);
else
cp.setLocation(cp.getX() - deltaX, cp.getY() - deltaY);
}
else if (n1[0] == n2[0] && n1[1] == n2[1])
{
cp = curve.getCtrlPt();
cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
}
else
{
cp = lineIntersection(curve.getX1() + n1[0],
curve.getY1() + n1[1],
@@ -155,25 +200,11 @@ public class QuadSegment extends Segment
curve.getCtrlY() + n2[1],
curve.getX2() + n2[0],
curve.getY2() + n2[1], true);
s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
cp.getX(), cp.getY(),
curve.getX2() + n2[0], curve.getY2() + n2[1]);
}
else
{
cp = lineIntersection(curve.getX1() - n1[0],
curve.getY1() - n1[1],
curve.getCtrlX() - n1[0],
curve.getCtrlY() - n1[1],
curve.getCtrlX() - n2[0],
curve.getCtrlY() - n2[1],
curve.getX2() - n2[0],
curve.getY2() - n2[1], true);
s = new QuadSegment(curve.getX1() - n1[0], curve.getY1() - n1[1],
cp.getX(), cp.getY(),
curve.getX2() - n2[0], curve.getY2() - n2[1]);
}
s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
cp.getX(), cp.getY(),
curve.getX2() + n2[0], curve.getY2() + n2[1]);
return s;
}
@@ -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;
}
@@ -104,7 +104,7 @@ public class TexturePaintContext
double scaleY = anchor.getHeight() / image.getHeight();
transform = (AffineTransform) xform.clone();
transform.scale(scaleX, scaleY);
transform.translate(-anchor.getMinX(), -anchor.getMaxX());
transform.translate(-anchor.getMinX(), -anchor.getMinY());
transform = transform.createInverse();
}
catch (NoninvertibleTransformException ex)
@@ -177,6 +177,12 @@ public class TexturePaintContext
// The modulo operation gives us the replication effect.
dx = ((dx - minX) % width) + minX;
dy = ((dy - minY) % height) + minY;
// Handle possible negative values (replicating above the top-left)
if (dx < 0)
dx += width;
if (dy < 0)
dy += height;
// Copy the pixel.
pixel = source.getDataElements(dx, dy, pixel);