summaryrefslogtreecommitdiff
path: root/gnu/java/awt/java2d/AbstractGraphics2D.java
diff options
context:
space:
mode:
authorRoman Kennke <roman@kennke.org>2006-05-19 22:23:01 +0000
committerRoman Kennke <roman@kennke.org>2006-05-19 22:23:01 +0000
commit8db90d85a6da78514f90c4eb655cfe6ed63df0c4 (patch)
tree113586542f29389ede8a968bfa60405ce12c0f41 /gnu/java/awt/java2d/AbstractGraphics2D.java
parent224676ffe4b49e14fc104ccd206c538af07c8757 (diff)
downloadclasspath-8db90d85a6da78514f90c4eb655cfe6ed63df0c4.tar.gz
2006-05-19 Roman Kennke <kennke@aicas.com>
* gnu/java/awt/java2d/AbstractGraphics2D.java Added class docs. (pixel): Removed obsolete field. (draw(Shape)): Removed commented out code. (drawImage): Formatting. (drawString): Added optimization hook. (setPaint): Removed rawSetForeground(). (getFontRenderContext): Return context with correct transform. (drawGlyphVector): Draw complete outline in one go. (copyArea): Added optimization hook. (clearRect): Added optimization hook. (drawImage): Added optimization hook. (fillShape): (Temporarily) Set antialiasing off by default for font rendering. Adjust the shape by some bits to improve rendering. Pass clip bounds to the render methods. (drawPixel): Removed. (rawSetPixel): Removed. (rawSetForeground): Removed. (rawDrawLine): Default impl calls standard pipeline. (rawDrawString): New method, calls standard pipeline for rendering. (rawClearRect): New method, calls standard pipeline for rendering. (rawFillRect): New method, calls standard pipeline for rendering. (rawDrawImage): New method, calls standard pipeline for rendering. (rawCopyArea): New method. (copyAreaImpl): New method. (rawFillShape): Renamed to fillShapeImpl(). Small optimization for rendering. (fillShapeAntialias): Fixed AA rendering. (fillScanlineAA): Fixed AA rendering. (getSegments): Take offset into account.
Diffstat (limited to 'gnu/java/awt/java2d/AbstractGraphics2D.java')
-rw-r--r--gnu/java/awt/java2d/AbstractGraphics2D.java486
1 files changed, 257 insertions, 229 deletions
diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java
index 02e6e71c6..7df9949e6 100644
--- a/gnu/java/awt/java2d/AbstractGraphics2D.java
+++ b/gnu/java/awt/java2d/AbstractGraphics2D.java
@@ -84,7 +84,48 @@ import java.util.Iterator;
import java.util.Map;
/**
- * Implements general and shared behaviour for Graphics2D implementation.
+ * 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
+ * {@link #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
+ * {@link #updateRaster(Raster, int, int, int, int)} method, which always gets
+ * called after a chunk of data got painted into the raster.
+ * </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 {@link 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>
+ * </ol>
+ * </p>
*
* @author Roman Kennke (kennke@aicas.com)
*/
@@ -146,11 +187,6 @@ public abstract class AbstractGraphics2D
private Raster paintRaster;
/**
- * A cached pixel array.
- */
- private int[] pixel;
-
- /**
* The raster of the destination surface. This is where the painting is
* performed.
*/
@@ -168,7 +204,7 @@ public abstract class AbstractGraphics2D
private transient ArrayList[] edgeTable;
/**
- * Indicates if cerain graphics primitives can be rendered in an optimized
+ * 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.
@@ -198,8 +234,6 @@ public abstract class AbstractGraphics2D
hints.put(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_DEFAULT);
renderingHints = new RenderingHints(hints);
-
- pixel = new int[4];
}
/**
@@ -212,15 +246,7 @@ public abstract class AbstractGraphics2D
{
// Stroke the shape.
Shape strokedShape = stroke.createStrokedShape(shape);
-
- // Clip the stroked shape.
-// Shape clipped = clipShape(strokedShape);
-// if (clipped != null)
-// {
-// // Fill the shape.
-// fillShape(clipped, false);
-// }
- // FIXME: Clipping doesn't seem to work.
+ // Fill the stroked shape.
fillShape(strokedShape, false);
}
@@ -239,7 +265,8 @@ public abstract class AbstractGraphics2D
* @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)
+ public boolean drawImage(Image image, AffineTransform xform,
+ ImageObserver obs)
{
boolean ret = false;
Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs),
@@ -435,9 +462,14 @@ public abstract class AbstractGraphics2D
*/
public void drawString(String text, int x, int y)
{
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
- drawGlyphVector(gv, x, y);
+ if (isOptimized)
+ rawDrawString(text, x, y);
+ else
+ {
+ FontRenderContext ctx = getFontRenderContext();
+ GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
+ drawGlyphVector(gv, x, y);
+ }
}
/**
@@ -530,7 +562,6 @@ public abstract class AbstractGraphics2D
else
{
updateOptimization();
- rawSetForeground((Color) paint);
}
}
}
@@ -887,8 +918,7 @@ public abstract class AbstractGraphics2D
public FontRenderContext getFontRenderContext()
{
- //return new FontRenderContext(transform, false, false);
- return new FontRenderContext(new AffineTransform(), false, false);
+ return new FontRenderContext(transform, false, true);
}
/**
@@ -901,22 +931,15 @@ public abstract class AbstractGraphics2D
public void drawGlyphVector(GlyphVector gv, float x, float y)
{
int numGlyphs = gv.getNumGlyphs();
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
-
-// // TODO: We could use fill(gv.getOutline()), but that seems to be
- // slightly more inefficient.
+ translate(x, y);
+ // TODO: We could use fill(gv.getOutline()), but that seems to be
+ // slightly more inefficient.
for (int i = 0; i < numGlyphs; i++)
{
- //fill(gv.getGlyphVisualBounds(i));
- GeneralPath p = new GeneralPath(gv.getGlyphOutline(i));
- p.transform(t);
- //Shape clipped = clipShape(p);
- //if (clipped != null)
- // fillShape(clipped, true);
- // FIXME: Clipping doesn't seem to work correctly.
- fillShape(p, true);
+ Shape o = gv.getGlyphOutline(i);
+ fillShape(o, true);
}
+ translate(-x, -y);
}
/**
@@ -1093,8 +1116,10 @@ public abstract class AbstractGraphics2D
public void copyArea(int x, int y, int width, int height, int dx, int dy)
{
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
+ if (isOptimized)
+ rawCopyArea(x, y, width, height, dx, dy);
+ else
+ copyAreaImpl(x, y, width, height, dx, dy);
}
/**
@@ -1153,11 +1178,15 @@ public abstract class AbstractGraphics2D
*/
public void clearRect(int x, int y, int width, int height)
{
- Paint savedForeground = getPaint();
- setPaint(getBackground());
- //System.err.println("clearRect transform type: " + transform.getType());
- fillRect(x, y, width, height);
- setPaint(savedForeground);
+ if (isOptimized)
+ rawClearRect(x, y, width, height);
+ else
+ {
+ Paint savedForeground = getPaint();
+ setPaint(getBackground());
+ fillRect(x, y, width, height);
+ setPaint(savedForeground);
+ }
}
/**
@@ -1273,9 +1302,16 @@ public abstract class AbstractGraphics2D
*/
public boolean drawImage(Image image, int x, int y, ImageObserver observer)
{
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- return drawImage(image, t, observer);
+ boolean ret;
+ if (isOptimized)
+ ret = rawDrawImage(image, x, y, observer);
+ else
+ {
+ AffineTransform t = new AffineTransform();
+ t.translate(x, y);
+ ret = drawImage(image, t, observer);
+ }
+ return ret;
}
/**
@@ -1428,8 +1464,8 @@ public abstract class AbstractGraphics2D
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);
+ antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ //|| v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
}
else
{
@@ -1437,68 +1473,25 @@ public abstract class AbstractGraphics2D
antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON);
}
+ double offs = 0.5;
+ if (antialias)
+ offs = offs / AA_SAMPLING;
+
Rectangle2D userBounds = s.getBounds2D();
Rectangle2D deviceBounds = new Rectangle2D.Double();
- ArrayList segs = getSegments(s, transform, deviceBounds, false);
+ ArrayList segs = getSegments(s, transform, deviceBounds, false, offs);
Rectangle2D clipBounds = new Rectangle2D.Double();
- ArrayList clipSegs = getSegments(clip, transform, clipBounds, true);
+ ArrayList clipSegs = getSegments(clip, transform, clipBounds, true, offs);
segs.addAll(clipSegs);
Rectangle2D inclClipBounds = new Rectangle2D.Double();
Rectangle2D.union(clipBounds, deviceBounds, inclClipBounds);
if (segs.size() > 0)
{
if (antialias)
- fillShapeAntialias(segs, deviceBounds, userBounds);
+ fillShapeAntialias(segs, deviceBounds, userBounds, inclClipBounds);
else
- rawFillShape(segs, deviceBounds, userBounds, inclClipBounds);
- }
- }
-
- /**
- * Draws one pixel in the target coordinate space. This method draws the
- * specified pixel by getting the painting pixel for that coordinate
- * from the paintContext and compositing the pixel with the compositeContext.
- * The resulting pixel is then set by calling {@link #rawSetPixel}.
- *
- * @param x the x coordinate
- * @param y the y coordinate
- */
- protected void drawPixel(int x, int y)
- {
- // FIXME: Implement efficient compositing.
- if (! (paint instanceof Color))
- {
- int[] paintPixel = paintRaster.getPixel(x, y, pixel);
- Color c = new Color(paintPixel[0], paintPixel[1], paintPixel[2]);
- rawSetForeground(c);
+ fillShapeImpl(segs, deviceBounds, userBounds, inclClipBounds);
}
- rawSetPixel(x, y);
- }
-
- /**
- * Draws a pixel in the target coordinate space using the specified color.
- *
- * @param x the x coordinate
- * @param y the y coordinate
- */
- protected void rawSetPixel(int x, int y)
- {
- // FIXME: Provide default implementation or remove method.
- }
-
- /**
- * Sets the foreground color for drawing.
- *
- * @param c the color to set
- */
- protected void rawSetForeground(Color c)
- {
- // Probably remove method.
- }
-
- protected void rawSetForeground(int r, int g, int b)
- {
- rawSetForeground(new Color(r, g, b));
}
/**
@@ -1520,7 +1513,8 @@ public abstract class AbstractGraphics2D
/**
* Draws a line in optimization mode. The implementation should respect the
- * clip but can assume that it is a rectangle.
+ * 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
@@ -1529,63 +1523,41 @@ public abstract class AbstractGraphics2D
*/
protected void rawDrawLine(int x0, int y0, int x1, int y1)
{
- // This is an implementation of Bresenham's line drawing algorithm.
- int dy = y1 - y0;
- int dx = x1 - x0;
- int stepx, stepy;
+ draw(new Line2D.Float(x0, y0, x1, y1));
+ }
- if (dy < 0)
- {
- dy = -dy;
- stepy = -1;
- }
- else
- {
- stepy = 1;
- }
- if (dx < 0)
- {
- dx = -dx;
- stepx = -1;
- }
- else
- {
- stepx = 1;
- }
- dy <<= 1;
- dx <<= 1;
+ /**
+ * 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);
+ }
- drawPixel(x0, y0);
- if (dx > dy)
- {
- int fraction = dy - (dx >> 1); // same as 2*dy - dx
- while (x0 != x1)
- {
- if (fraction >= 0)
- {
- y0 += stepy;
- fraction -= dx;
- }
- x0 += stepx;
- fraction += dy;
- drawPixel(x0, y0);
- }
- }
- else
- {
- int fraction = dx - (dy >> 1);
- while (y0 != y1)
- {
- if (fraction >= 0)
- {
- x0 += stepx;
- fraction -= dy;
- }
- y0 += stepy;
- fraction += dx;
- drawPixel(x0, y0);
- }
- }
+ /**
+ * Clears a rectangle 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 x the upper left corner, X coordinate
+ * @param y the upper left corner, Y coordinate
+ * @param w the width
+ * @param h the height
+ */
+ protected void rawClearRect(int x, int y, int w, int h)
+ {
+ Paint savedForeground = getPaint();
+ setPaint(getBackground());
+ rawFillRect(x, y, w, h);
+ setPaint(savedForeground);
}
/**
@@ -1599,15 +1571,52 @@ public abstract class AbstractGraphics2D
*/
protected void rawFillRect(int x, int y, int w, int h)
{
- int x2 = x + w;
- int y2 = y + h;
- for (int xc = x; xc < x2; xc++)
- {
- for (int yc = y; yc < y2; yc++)
- {
- drawPixel(xc, yc);
- }
- }
+ fill(new Rectangle(x, y, w, h));
+ }
+
+ /**
+ * Draws an image in optimization mode. The implementation should respect
+ * the clip but can assume that it is a rectangle.
+ *
+ * @param image the image to be painted
+ * @param x the location, X coordinate
+ * @param y the location, Y coordinate
+ * @param obs the image observer to be notified
+ *
+ * @return <code>true</code> when the image is painted completely,
+ * <code>false</code> if it is still rendered
+ */
+ protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs)
+ {
+ AffineTransform t = new AffineTransform();
+ t.translate(x, y);
+ return drawImage(image, t, obs);
+ }
+
+ /**
+ * Copies a rectangular region to another location.
+ *
+ * @param x the upper left corner, X coordinate
+ * @param y the upper left corner, Y coordinate
+ * @param w the width
+ * @param h the height
+ * @param dx
+ * @param dy
+ */
+ protected void rawCopyArea(int x, int y, int w, int h, int dx, int dy)
+ {
+ 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.");
}
/**
@@ -1617,9 +1626,9 @@ public abstract class AbstractGraphics2D
*
* The polygon is already clipped when this method is called.
*/
- protected void rawFillShape(ArrayList segs, Rectangle2D deviceBounds2D,
- Rectangle2D userBounds,
- Rectangle2D inclClipBounds)
+ private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D,
+ Rectangle2D userBounds,
+ Rectangle2D inclClipBounds)
{
// This is an implementation of a polygon scanline conversion algorithm
// described here:
@@ -1736,14 +1745,11 @@ public abstract class AbstractGraphics2D
fillScanline(pCtx, x0, x1, y);
}
// Update state.
- if (edge.y1 > y)
- {
- previous = edge;
- if (edge.isClip)
- insideClip = ! insideClip;
- else
- insideShape = ! insideShape;
- }
+ previous = edge;
+ if (edge.isClip)
+ insideClip = ! insideClip;
+ else
+ insideShape = ! insideShape;
}
}
pCtx.dispose();
@@ -1775,7 +1781,8 @@ public abstract class AbstractGraphics2D
* @param segs the line segments which define the shape which is to be filled
*/
private void fillShapeAntialias(ArrayList segs, Rectangle2D deviceBounds2D,
- Rectangle2D userBounds)
+ Rectangle2D userBounds,
+ Rectangle2D inclClipBounds)
{
// This is an implementation of a polygon scanline conversion algorithm
// described here:
@@ -1787,24 +1794,28 @@ public abstract class AbstractGraphics2D
double minY = deviceBounds2D.getMinY();
double maxX = deviceBounds2D.getMaxX();
double maxY = deviceBounds2D.getMaxY();
-
+ double icMinY = inclClipBounds.getMinY();
+ double icMaxY = inclClipBounds.getMaxY();
+ double icMinX = inclClipBounds.getMinX();
+ double icMaxX = inclClipBounds.getMaxX();
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,
+ PaintContext pCtx = paint.createContext(ColorModel.getRGBdefault(),
+ deviceBounds,
userBounds, transform,
renderingHints);
// This array will contain the oversampled transparency values for
// each pixel in the scanline.
- int numScanlines = (int) Math.ceil(maxY) - (int) minY;
- int numScanlinePixels = (int) Math.ceil(maxX) - (int) minX + 1;
+ int numScanlines = (int) Math.ceil(icMaxY) - (int) icMinY;
+ int numScanlinePixels = (int) Math.ceil(icMaxX) - (int) icMinX + 1;
if (alpha == null || alpha.length < (numScanlinePixels + 1))
alpha = new int[numScanlinePixels + 1];
- int firstLine = (int) minY;
+ int firstLine = (int) icMinY;
//System.err.println("minY: " + minY);
- int firstSubline = (int) (Math.ceil((minY - Math.floor(minY)) * AA_SAMPLING));
+ int firstSubline = (int) (Math.ceil((icMinY - Math.floor(icMinY)) * AA_SAMPLING));
double firstLineDouble = firstLine + firstSubline / (double) AA_SAMPLING;
//System.err.println("firstSubline: " + firstSubline);
@@ -1849,8 +1860,11 @@ public abstract class AbstractGraphics2D
// Scan all lines.
int yindex = 0;
//System.err.println("firstLine: " + firstLine + ", maxY: " + maxY + ", firstSubline: " + firstSubline);
- for (int y = firstLine; y <= maxY; y++)
+ for (int y = firstLine; y <= icMaxY; y++)
{
+ int leftX = (int) icMaxX;
+ int rightX = (int) icMinX;
+ boolean emptyScanline = true;
for (int subY = firstSubline; subY < AA_SAMPLING; subY++)
{
//System.err.println("scanline: " + y + ", subScanline: " + subY);
@@ -1907,17 +1921,16 @@ public abstract class AbstractGraphics2D
// Now draw all pixels inside the polygon.
// This is the last edge that intersected the scanline.
PolyEdge previous = null; // Gets initialized below.
- boolean active = false;
+ boolean insideClip = false;
+ boolean insideShape = false;
//System.err.println("scanline: " + y + ", subscanline: " + subY);
for (Iterator i = activeEdges.iterator(); i.hasNext();)
{
PolyEdge edge = (PolyEdge) i.next();
- // Only fill scanline, if the current edge actually intersects
- // the scanline. There may be edges that lie completely
- // within the current scanline.
- //System.err.println("previous: " + previous);
- //System.err.println("edge: " + edge);
- if (active)
+ if (edge.y1 <= (y + (subY / (double) AA_SAMPLING)))
+ continue;
+
+ if (insideClip && insideShape)
{
// TODO: Use integer arithmetics here.
if (edge.y1 > (y + (subY / (double) AA_SAMPLING)))
@@ -1928,32 +1941,30 @@ public abstract class AbstractGraphics2D
int x1 = (int) Math.min(Math.max(edge.xIntersection, minX), maxX);
//System.err.println("minX: " + minX + ", x0: " + x0 + ", x1: " + x1 + ", maxX: " + maxX);
// TODO: Pull out cast.
- alpha[x0 - (int) minX]++;
- alpha[x1 - (int) minX + 1]--;
- previous = edge;
- active = false;
+ int left = x0 - (int) minX;
+ int right = x1 - (int) minX + 1;
+ alpha[left]++;
+ alpha[right]--;
+ leftX = Math.min(x0, leftX);
+ rightX = Math.max(x1+2, rightX);
+ emptyScanline = false;
}
}
+ previous = edge;
+ if (edge.isClip)
+ insideClip = ! insideClip;
else
- {
- // TODO: Use integer arithmetics here.
- if (edge.y1 > (y + (subY / (double) AA_SAMPLING)))
- {
- //System.err.println(edge);
- previous = edge;
- active = true;
- }
- }
+ insideShape = ! insideShape;
}
yindex++;
}
firstSubline = 0;
// Render full scanline.
//System.err.println("scanline: " + y);
- fillScanlineAA(alpha, (int) minX, (int) y, numScanlinePixels, pCtx);
+ if (! emptyScanline)
+ fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx,
+ (int) minX);
}
- if (paint instanceof Color && composite == AlphaComposite.SrcOver)
- rawSetForeground((Color) paint);
pCtx.dispose();
}
@@ -1967,40 +1978,54 @@ public abstract class AbstractGraphics2D
* @param x0 the beginning of the scanline
* @param y the y coordinate of the line
*/
- private void fillScanlineAA(int[] alpha, int x0, int y, int numScanlinePixels,
- PaintContext pCtx)
+ private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels,
+ PaintContext pCtx, int offs)
{
- // FIXME: This doesn't work. Fixit.
CompositeContext cCtx = composite.createContext(pCtx.getColorModel(),
getColorModel(),
renderingHints);
- Raster paintRaster = pCtx.getRaster(x0, y, numScanlinePixels, 1);
- System.err.println("paintColorModel: " + pCtx.getColorModel());
+ Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1);
+ //System.err.println("paintColorModel: " + pCtx.getColorModel());
WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster();
int numBands = paintRaster.getNumBands();
- int[] pixels = new int[numScanlinePixels + paintRaster.getNumBands()];
- pixels = paintRaster.getPixels(x0, y, numScanlinePixels, 1, pixels);
ColorModel cm = pCtx.getColorModel();
-
double lastAlpha = 0.;
int lastAlphaInt = 0;
- int[] components = new int[4];
-
- for (int i = 0; i < pixels.length; i++)
+
+ 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 = lastAlphaInt / AA_SAMPLING;
+ lastAlpha = (double) lastAlphaInt / (double) AA_SAMPLING;
+ alpha[i] = 0;
+ }
+ pixel = paintRaster.getDataElements(x - x0, 0, pixel);
+ comps = cm.getComponents(pixel, comps, 0);
+ if (cm.hasAlpha() && ! cm.isAlphaPremultiplied())
+ comps[comps.length - 1] *= lastAlpha;
+ else
+ {
+ int max;
+ if (cm.hasAlpha())
+ max = comps.length - 2;
+ else
+ max = comps.length - 1;
+ for (int j = 0; j < max; j++)
+ comps[j] *= lastAlpha;
}
- components = cm.getComponents(pixel[i], components, 0);
- components[0] = (int) (components[0] * lastAlpha);
- pixel[i] = cm.getDataElement(components, 0);
+ pixel = cm.getDataElements(comps, 0, pixel);
+ aaRaster.setDataElements(x - x0, 0, pixel);
}
- aaRaster.setPixels(0, 0, numScanlinePixels, 1, pixels);
- cCtx.compose(aaRaster, destinationRaster, destinationRaster);
- updateRaster(destinationRaster, x0, y, numScanlinePixels, 1);
+ WritableRaster targetChild =
+ destinationRaster.createWritableTranslatedChild(-x0, -yy);
+ cCtx.compose(aaRaster, targetChild, targetChild);
+ updateRaster(destinationRaster, x0, yy, numPixels, 1);
cCtx.dispose();
}
@@ -2144,7 +2169,8 @@ public abstract class AbstractGraphics2D
* @return a list of PolyEdge that form the shape in device space
*/
private ArrayList getSegments(Shape s, AffineTransform t,
- Rectangle2D deviceBounds, boolean isClip)
+ Rectangle2D deviceBounds, boolean isClip,
+ double offs)
{
// Flatten the path. TODO: Determine the best flattening factor
// wrt to speed and quality.
@@ -2187,12 +2213,14 @@ public abstract class AbstractGraphics2D
else if (segType == PathIterator.SEG_CLOSE)
{
// Close the polyline.
- PolyEdge edge = new PolyEdge(segX, segY, polyX, polyY, isClip);
+ PolyEdge edge = new PolyEdge(segX, segY - offs,
+ polyX, polyY - offs, isClip);
segs.add(edge);
}
else if (segType == PathIterator.SEG_LINETO)
{
- PolyEdge edge = new PolyEdge(segX, segY, seg[0], seg[1], isClip);
+ PolyEdge edge = new PolyEdge(segX, segY - offs,
+ seg[0], seg[1] - offs, isClip);
segs.add(edge);
segX = seg[0];
segY = seg[1];