diff options
| author | Roman Kennke <roman@kennke.org> | 2006-05-19 22:23:01 +0000 |
|---|---|---|
| committer | Roman Kennke <roman@kennke.org> | 2006-05-19 22:23:01 +0000 |
| commit | 8db90d85a6da78514f90c4eb655cfe6ed63df0c4 (patch) | |
| tree | 113586542f29389ede8a968bfa60405ce12c0f41 /gnu/java/awt/java2d/AbstractGraphics2D.java | |
| parent | 224676ffe4b49e14fc104ccd206c538af07c8757 (diff) | |
| download | classpath-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.java | 486 |
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]; |
