diff options
| author | Roman Kennke <roman@kennke.org> | 2007-05-08 13:27:30 +0000 |
|---|---|---|
| committer | Roman Kennke <roman@kennke.org> | 2007-05-08 13:27:30 +0000 |
| commit | bfb5cc0ebd613f1b359bbfafe35f9264411cae19 (patch) | |
| tree | 30d46d64d713f0c358ed915549d7e0ae2298eeab /gnu/java/awt/java2d | |
| parent | b61e8e8112f60e7e8978b2fd36da36d3fe5686dd (diff) | |
| download | classpath-bfb5cc0ebd613f1b359bbfafe35f9264411cae19.tar.gz | |
2007-05-08 Roman Kennke <roman@kennke.org>
* gnu/java/awt/java2d/AbstractGraphics2D.java
(AA_SAMPLING): Removed.
(alpha): Removed field.
(edgeTable): Removed field.
(fillScanlineAA): Removed obsolete method.
(drawPolyline): Implemented by using a GeneralPath.
(drawPolygon): Reset the cached polygon.
(fillPolygon): Reset the cached polygon.
(fillShape): Default to antialias on for text.
(rawDrawLine): Use ShapeCache.
(rawDrawRect): Use ShapeCache.
(rawFillRect): Use ShapeCache.
(fillScanlineAA): New method for antialiased rendering.
* gnu/java/awt/java2d/ScanlineConverter.java
(scanlinesPerPixel): New field.
(minX,maxX): New fields.
(scanlineYCov,scanlineXCov): New fields.
(slPix0): New field.
(alphaRes): New field.
(renderShape): Add antialiasing functionality.
(doScanline): Add antialiasing functionality.
(setResolution): Add antialiasing functionality.
(addShape): Determine span in X direction.
(fit): Fix thinko.
* gnu/java/awt/java2d/ShapeCache.java
(polyline): New field for caching polylines.
Diffstat (limited to 'gnu/java/awt/java2d')
| -rw-r--r-- | gnu/java/awt/java2d/AbstractGraphics2D.java | 123 | ||||
| -rw-r--r-- | gnu/java/awt/java2d/ScanlineConverter.java | 113 | ||||
| -rw-r--r-- | gnu/java/awt/java2d/ShapeCache.java | 5 |
3 files changed, 131 insertions, 110 deletions
diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java index f6c5ff0cb..0b1dd8d6e 100644 --- a/gnu/java/awt/java2d/AbstractGraphics2D.java +++ b/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -78,7 +78,6 @@ import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -156,13 +155,6 @@ public abstract class AbstractGraphics2D private static final Font FONT = new Font("SansSerif", Font.PLAIN, 12); /** - * 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. */ @@ -227,17 +219,6 @@ public abstract class AbstractGraphics2D 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 @@ -1352,8 +1333,16 @@ public abstract class AbstractGraphics2D public void drawPolyline(int[] xPoints, int[] yPoints, int npoints) { - // FIXME: Implement this. - throw new UnsupportedOperationException("Not yet implemented"); + ShapeCache sc = getShapeCache(); + if (sc.polyline == null) + sc.polyline = new GeneralPath(); + GeneralPath p = sc.polyline; + p.reset(); + if (npoints > 0) + p.moveTo(xPoints[0], yPoints[0]); + for (int i = 1; i < npoints; i++) + p.lineTo(xPoints[i], yPoints[i]); + fill(p); } /** @@ -1364,6 +1353,7 @@ public abstract class AbstractGraphics2D ShapeCache sc = getShapeCache(); if (sc.polygon == null) sc.polygon = new Polygon(); + sc.polygon.reset(); sc.polygon.xpoints = xPoints; sc.polygon.ypoints = yPoints; sc.polygon.npoints = npoints; @@ -1378,6 +1368,7 @@ public abstract class AbstractGraphics2D ShapeCache sc = getShapeCache(); if (sc.polygon == null) sc.polygon = new Polygon(); + sc.polygon.reset(); sc.polygon.xpoints = xPoints; sc.polygon.ypoints = yPoints; sc.polygon.npoints = npoints; @@ -1559,10 +1550,9 @@ public abstract class AbstractGraphics2D 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); + // We default to antialiasing for text rendering. + antialias = (v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON + || v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); } else { @@ -1609,12 +1599,20 @@ public abstract class AbstractGraphics2D */ protected void rawDrawLine(int x0, int y0, int x1, int y1) { - draw(new Line2D.Float(x0, y0, x1, y1)); + ShapeCache sc = getShapeCache(); + if (sc.line == null) + sc.line = new Line2D.Float(); + sc.line.setLine(x0, y0, x1, y1); + draw(sc.line); } protected void rawDrawRect(int x, int y, int w, int h) { - draw(new Rectangle(x, y, w, h)); + ShapeCache sc = getShapeCache(); + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + draw(sc.rect); } /** @@ -1662,7 +1660,11 @@ public abstract class AbstractGraphics2D */ protected void rawFillRect(int x, int y, int w, int h) { - fill(new Rectangle(x, y, w, h)); + ShapeCache sc = getShapeCache(); + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + fill(sc.rect); } /** @@ -1734,66 +1736,6 @@ public abstract class AbstractGraphics2D /** - * 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 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(); - 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; - } - 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; - } - pixel = cm.getDataElements(comps, 0, pixel); - aaRaster.setDataElements(x - x0, 0, pixel); - } - - WritableRaster targetChild = - destinationRaster.createWritableTranslatedChild(-x0, -yy); - cCtx.compose(aaRaster, targetChild, targetChild); - updateRaster(destinationRaster, x0, yy, numPixels, 1); - - cCtx.dispose(); - } - - /** * Initializes this graphics object. This must be called by subclasses in * order to correctly initialize the state of this object. */ @@ -1971,4 +1913,9 @@ public abstract class AbstractGraphics2D } return sc; } + + protected void fillScanlineAA(int x0, int x1, int y, int alpha2) + { + System.err.println("override!"); + } } diff --git a/gnu/java/awt/java2d/ScanlineConverter.java b/gnu/java/awt/java2d/ScanlineConverter.java index 9f9d8921f..5254af901 100644 --- a/gnu/java/awt/java2d/ScanlineConverter.java +++ b/gnu/java/awt/java2d/ScanlineConverter.java @@ -87,6 +87,8 @@ final class ScanlineConverter */ private int resolution; + private int scanlinesPerPixel; + /** * One half step according to the resolution. This is stored to avoid * unnecessary operations during rendering. @@ -109,6 +111,13 @@ final class ScanlineConverter private int minY; private int maxY; + private int minX; + private int maxX; + + private int[] scanlineYCov; + private int[] scanlineXCov; + private int slPix0; + private int alphaRes; /** * Create a new ScanlineConverter. @@ -139,11 +148,12 @@ final class ScanlineConverter boolean haveClip = clip != null; // Add shapes. - PathIterator path = shape.getPathIterator(trans, resolution); + float flatness = Fixed.floatValue(FIXED_DIGITS, resolution / 2); + PathIterator path = shape.getPathIterator(trans, flatness); addShape(path, false); if (haveClip) { - path= clip.getPathIterator(trans, resolution); + path= clip.getPathIterator(trans, flatness); addShape(path, true); } @@ -156,12 +166,26 @@ final class ScanlineConverter edge = edge.poolNext; } + // For AA: Prepare the scanline pixels array. + if (resolution < ONE) + { + int x0 = Fixed.intValue(FIXED_DIGITS, minX); + int x1 = Fixed.intValue(FIXED_DIGITS, maxX) + 1; + int span = x1 - x0; + if (scanlineYCov == null || span >= scanlineYCov.length) + { + scanlineYCov = new int[span]; + scanlineXCov = new int[span]; + } + slPix0 = x0; + } + int y = upperBounds; - int lastIndex = scanlineIndex(y - resolution); int index; activeEdges.clear(); // The render loop... Scanline scanline = null; + int lastRealY = Fixed.intValue(FIXED_DIGITS, y); while (y <= maxY) { // First we put together our list of active edges. @@ -184,15 +208,16 @@ final class ScanlineConverter activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep); // Ok, now we can perform the actual scanlining. - boolean push = lastIndex != index; + int realY = Fixed.intValue(FIXED_DIGITS, y + resolution); + boolean push = lastRealY != realY; doScanline(g, y, push, haveClip); // Remove obsolete active edges. //activeEdges.remove(y + halfStep); - // Go on with the next line... y += resolution; - lastIndex = index; + lastRealY = realY; + } } @@ -215,6 +240,8 @@ final class ScanlineConverter // Reset bounds. minY = Integer.MAX_VALUE; maxY = Integer.MIN_VALUE; + minX = Integer.MAX_VALUE; + maxX = Integer.MIN_VALUE; } /** @@ -223,6 +250,7 @@ final class ScanlineConverter private void doScanline(AbstractGraphics2D g, int y, boolean push, boolean haveClip) { + // We begin outside the clip and outside the shape. We only draw when // we are inside the clip AND inside the shape. boolean inClip = ! haveClip; @@ -238,21 +266,24 @@ final class ScanlineConverter int x0 = lastEdge.xIntersection; int x1 = edge.xIntersection; assert x0 <= x1; - if (push) + if (resolution == ONE) { - if (resolution == ONE) - { - // Non-AA rendering. - g.fillScanline(Fixed.intValue(FIXED_DIGITS, x0), - Fixed.intValue(FIXED_DIGITS, x1 - resolution), - Fixed.intValue(FIXED_DIGITS, y)); - } - else - { - // AA rendering. - // FIXME: Implement. - System.err.println("Implement AA rendering."); - } + // Non-AA rendering. + g.fillScanline(Fixed.intValue(FIXED_DIGITS, x0 + resolution / 2), + Fixed.intValue(FIXED_DIGITS, x1 - resolution / 2), + Fixed.intValue(FIXED_DIGITS, y)); + } + else + { + int pix0 = Fixed.intValue(FIXED_DIGITS, x0); + int frac0 = ONE - (x0 - Fixed.floor(FIXED_DIGITS, x0)); + int pix1 = Fixed.intValue(FIXED_DIGITS, x1); + int frac1 = ONE - (x1 - Fixed.floor(FIXED_DIGITS, x1)); + //System.err.println("render scanline AA: " + Fixed.floatValue(FIXED_DIGITS, y) + ", " + pix0 + ", " + pix1 + "(" + Fixed.floatValue(FIXED_DIGITS, x0) + ", " + Fixed.floatValue(FIXED_DIGITS, x1) +")"); + scanlineYCov[pix0 - slPix0] += alphaRes; + scanlineYCov[pix1 - slPix0] -= alphaRes; + scanlineXCov[pix0 - slPix0] += frac0; + scanlineXCov[pix1 - slPix0] += frac1; } } if (edge.isClip) @@ -262,7 +293,39 @@ final class ScanlineConverter lastEdge = edge; } - } + + // For AA we push out the scanline when necessary. + if (push && ONE > resolution) + { + // Push out AA'ed scanline. + int rx1 = 0; + int alpha = 0; + for (int idx = 0; idx < scanlineYCov.length; idx++) + { + rx1 = slPix0 + idx; + if (scanlineYCov[idx] != 0) + { + // Render transitioning pixel with x coverage included. + int transAlpha = alpha + (scanlineYCov[idx] * scanlineXCov[idx]) / (scanlinesPerPixel * 64); + //System.err.println("pixel: " + rx1 + " old alpha: " + alpha + " ycov:" + scanlineYCov[idx] + " xcov: " + scanlineXCov[idx] + " tAlpha: " + transAlpha); + g.fillScanlineAA(rx1, rx1, + Fixed.intValue(FIXED_DIGITS, y), + Math.max(Math.min(transAlpha, 255), 0)); + alpha = alpha + scanlineYCov[idx]; + } + else if (alpha > 0) + { + //System.err.println("pixel: " + rx1 + " alpha: " + alpha); + g.fillScanlineAA(rx1, rx1, + Fixed.intValue(FIXED_DIGITS, y), + Math.min(alpha, 255)); + } + scanlineYCov[idx] = 0; + scanlineXCov[idx] = 0; + } + } + } + /** * Sets the resolution. A value of 0 rasterizes the shape normally without @@ -272,9 +335,11 @@ final class ScanlineConverter */ private void setResolution(int res) { + scanlinesPerPixel = 1 << res; int one = Fixed.fixedValue(FIXED_DIGITS, 1); resolution = one / (1 << res); halfStep = resolution / 2; + alphaRes = 256 >> res; } /** @@ -309,6 +374,8 @@ final class ScanlineConverter startY = lastY = Fixed.fixedValue(FIXED_DIGITS, coords[1]); minY = Math.min(startY, minY); maxY = Math.max(startY, maxY); + minX = Math.min(startX, minX); + maxX = Math.max(startX, maxX); break; case PathIterator.SEG_LINETO: int x = Fixed.fixedValue(FIXED_DIGITS, coords[0]); @@ -318,6 +385,8 @@ final class ScanlineConverter lastY = y; minY = Math.min(lastY, minY); maxY = Math.max(lastY, maxY); + minX = Math.min(lastX, minX); + maxX = Math.max(lastX, maxX); break; case PathIterator.SEG_CLOSE: edgePoolAdd(lastX, lastY, startX, startY, clip); @@ -371,7 +440,7 @@ final class ScanlineConverter { int val1 = Fixed.div(FIXED_DIGITS, y, resolution); int rounded = Fixed.round(FIXED_DIGITS, val1); - return Fixed.div(FIXED_DIGITS, rounded, resolution); + return Fixed.mul(FIXED_DIGITS, rounded, resolution); } /** diff --git a/gnu/java/awt/java2d/ShapeCache.java b/gnu/java/awt/java2d/ShapeCache.java index 034b53cad..89a9ac4ab 100644 --- a/gnu/java/awt/java2d/ShapeCache.java +++ b/gnu/java/awt/java2d/ShapeCache.java @@ -42,6 +42,7 @@ import java.awt.Polygon; import java.awt.Rectangle; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.RoundRectangle2D; @@ -82,4 +83,8 @@ public class ShapeCache */ public Polygon polygon; + /** + * A cached polyline. + */ + public GeneralPath polyline; } |
