diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java')
-rw-r--r-- | libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java new file mode 100644 index 000000000..2c3481b6c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java @@ -0,0 +1,451 @@ +/* ScanlineConverter.java -- Rasterizes Shapes + Copyright (C) 2006, 2007 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 gnu.java.math.Fixed; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; + +/** + * Rasterizes {@link Shape} objects on an AbstractGraphics2D. + */ +public final class ScanlineConverter +{ + + /** + * The number of digits to use for fixed point arithmetics. + */ + private static int FIXED_DIGITS = 6; + + /** + * The fixed point constant for the number one. + */ + private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1); + + /** + * The actual number of scanlines. + */ + private int numScanlines; + + /** + * The number of scanlines. This can contain more elements than we have + * scanlines. The real number of scanlines is stored in + * {@link #numScanlines}. This can also contain null values for empty + * scanlines. + */ + private Scanline[] scanlines; + + /** + * The upper bounds which correspond to the index 0 in the scanline array. + * + * This is a fixed point value. + */ + private int upperBounds; + + /** + * The resolution of the scanline converter. + * + * This is a fixed point value. + */ + private int resolution; + + /** + * The number of significant bits for the 'Y' resolution. + */ + private int yResolution; + + /** + * One half step according to the resolution. This is stored to avoid + * unnecessary operations during rendering. + */ + private int halfStep; + + /** + * This is used in {@link #addShape(PathIterator, boolean)} to + * receive the coordinates of the path. + */ + private float[] coords; + + /** + * The active edges. + */ + private ActiveEdges activeEdges; + + private PolyEdge edgePool; + private PolyEdge edgePoolLast; + + private int minY; + private int maxY; + private int minX; + private int maxX; + + /** + * Holds and manages information about the pixel coverage. + */ + private ScanlineCoverage scanlineCoverage; + + /** + * Create a new ScanlineConverter. + */ + ScanlineConverter() + { + scanlines = new Scanline[10]; + coords = new float[6]; + activeEdges = new ActiveEdges(); + edgePool = new PolyEdge(); + edgePoolLast = edgePool; + scanlineCoverage = new ScanlineCoverage(); + } + + /** + * Renders the specified shape using the specified clip and transform. + * + * @param p the pixelizer that receives the coverage information + * @param shape the shape to render + * @param clip the clip + * @param trans the transform + */ + public void renderShape(Pixelizer p, Shape shape, Shape clip, + AffineTransform trans, int res, int yRes, + RenderingHints hints) + { + // TODO: Do something useful with the rendering hints. Like, adjusting + // the resolution. + + // Prepare resolution and upper bounds. + clear(); + setResolution(res, yRes); + + boolean haveClip = clip != null; + + // Add shapes. + float flatness = Fixed.floatValue(FIXED_DIGITS, resolution / 2); + PathIterator path = shape.getPathIterator(trans, flatness); + addShape(path, false); + if (haveClip) + { + path= clip.getPathIterator(trans, flatness); + addShape(path, true); + } + + setUpperBounds(minY); + + PolyEdge edge = edgePool; + while (edge != edgePoolLast) + { + addEdge(edge); + edge = edge.poolNext; + } + + int y = upperBounds; + 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. + index = scanlineIndex(y); + // If we go outside the scanline array we still need to render the + // remaining edges until they end. + scanline = index < scanlines.length ? scanlines[index] : null; + if (scanline != null) + { + edge = scanline.getEdges(); + while (edge != null) + { + activeEdges.add(edge); + edge = edge.scanlineNext; + } + } + + // Then we intersect all active edges with the current scanline + // and sort them according to their intersection points. + activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep); + + // Ok, now we can perform the actual scanlining. + int realY = Fixed.intValue(FIXED_DIGITS, y + resolution); + boolean push = lastRealY != realY; + + doScanline(p, y, push, haveClip); + + // Remove obsolete active edges. + //activeEdges.remove(y + halfStep); + // Go on with the next line... + y += resolution; + lastRealY = realY; + + } + } + + /** + * Clears all scanlines. + */ + private void clear() + { + // Reset edge pool. + edgePoolLast = edgePool; + + // Reset scanlines. + for (int i = scanlines.length - 1; i >= 0 ; i--) + { + Scanline sl = scanlines[i]; + if (sl != null) + sl.clear(); + } + + // Reset scanline coverage. + scanlineCoverage.clear(); + + // Reset bounds. + minY = Integer.MAX_VALUE; + maxY = Integer.MIN_VALUE; + minX = Integer.MAX_VALUE; + maxX = Integer.MIN_VALUE; + } + + /** + * Performs the scanlining on the current set of active edges. + * + * @param p the pixelizer to receive the pixel coverage data + * @param y the Y coordinate + * @param push true when the scanline is ready to be pushed to the + * pixelizer + * @param haveClip true when there's a clip, false otherwise + */ + private void doScanline(Pixelizer p, int y, boolean push, + boolean haveClip) + { + // First, rewind the scanline coverage. + scanlineCoverage.rewind(); + + // 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; + boolean inShape = false; + PolyEdge lastEdge = null; + int numEdges = activeEdges.getNumActiveEdges(); + for (int i = 0; i < numEdges; i++) + { + PolyEdge edge = activeEdges.getActiveEdge(i); + if (inClip && inShape) + { + assert lastEdge != null; + int x0 = lastEdge.xIntersection; + int x1 = edge.xIntersection; + assert x0 <= x1; + + int pix0 = Fixed.intValue(FIXED_DIGITS, x0); + int pix1 = Fixed.intValue(FIXED_DIGITS, x1); + int frac0 = ONE - Fixed.trunc(FIXED_DIGITS, x0); + int frac1 = ONE - Fixed.trunc(FIXED_DIGITS, x1); + // Only keep the first 4 digits after the point. + frac0 = frac0 >> (FIXED_DIGITS - yResolution); + frac1 = frac1 >> (FIXED_DIGITS - yResolution); + scanlineCoverage.add(pix0, 1 * (1 << yResolution), frac0); + scanlineCoverage.add(pix1, -1 * (1 << yResolution), -frac1); + } + if (edge.isClip) + inClip = ! inClip; + else + inShape = ! inShape; + + lastEdge = edge; + } + + // Push out the whole scanline to the pixelizer. + if (push && ! scanlineCoverage.isEmpty()) + { + p.renderScanline(Fixed.intValue(FIXED_DIGITS, y), scanlineCoverage); + scanlineCoverage.clear(); + } + } + + + /** + * Sets the resolution. A value of 0 rasterizes the shape normally without + * anti-aliasing. Greater values renders with a resolution of 2 ^ res. + * + * @param res the resolution + */ + private void setResolution(int res, int yRes) + { + int scanlinesPerPixel = 1 << res; + int one = Fixed.fixedValue(FIXED_DIGITS, 1); + resolution = one / (scanlinesPerPixel); + halfStep = resolution / 2; + + scanlineCoverage.setMaxCoverage(scanlinesPerPixel << yResolution); + + yResolution = yRes; + } + + /** + * Sets the vertical bounds of that shape that is beeing rendered. + * + * @param y0 the upper bounds + */ + private void setUpperBounds(int y0) + { + upperBounds = fit(y0); + } + + /** + * Add a shape to the scanline converter. + * + * @param path + * @param clip + */ + private void addShape(PathIterator path, boolean clip) + { + int startX = 0; + int startY = 0; + int lastX = 0; + int lastY = 0; + while (! path.isDone()) + { + int type = path.currentSegment(coords); + switch (type) + { + case PathIterator.SEG_MOVETO: + startX = lastX = Fixed.fixedValue(FIXED_DIGITS, coords[0]); + 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]); + int y = Fixed.fixedValue(FIXED_DIGITS, coords[1]); + edgePoolAdd(lastX, lastY, x, y, clip); + lastX = x; + 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); + lastX = startX; + lastY = startY; + break; + case PathIterator.SEG_CUBICTO: + case PathIterator.SEG_QUADTO: + default: + assert false; + } + path.next(); + } + } + + /** + * Adds an edge into the scanline array. + */ + private void addEdge(PolyEdge edge) + { + // Determine index. + int upper = Math.min(edge.y0, edge.y1); + // Fit to raster. + int index = scanlineIndex(upper); + // Grow array when necessary. + if (index >= scanlines.length) + { + int oldSize = scanlines.length; + int newSize = Math.max(oldSize + oldSize / 2 + 1, index + 10); + Scanline[] newScanlines = new Scanline[newSize]; + System.arraycopy(scanlines, 0, newScanlines, 0, oldSize); + scanlines = newScanlines; + } + + // Add edge. + if (scanlines[index] == null) + { + scanlines[index] = new Scanline(); + } + scanlines[index].addEdge(edge); + } + + /** + * Fits an Y coordinate to the grid. + * + * @param y the Y coordinate to fit + * + * @return the fitted Y coordinate + */ + private int fit(int y) + { + int val1 = Fixed.div(FIXED_DIGITS, y, resolution); + int rounded = Fixed.round(FIXED_DIGITS, val1); + return Fixed.mul(FIXED_DIGITS, rounded, resolution); + } + + /** + * Calculates the scanline index for the specified y coordinate. + * + * @param y the y coordinate as fixed point value + * + * @return the scanline index + */ + private int scanlineIndex(int y) + { + int fitted = fit(y); + // Cleverly skip the fixed point conversions here. + return (fitted - upperBounds)/ resolution; + } + + private void edgePoolAdd(int x0, int y0, int x1, int y1, boolean clip) + { + // Don't need no horizontal edges. + if (y0 != y1) + { + edgePoolLast.init(FIXED_DIGITS, x0, y0, x1, y1, clip); + if (edgePoolLast.poolNext == null) + { + edgePoolLast.poolNext = new PolyEdge(); + } + edgePoolLast = edgePoolLast.poolNext; + } + } +} |