Import GNU Classpath (libgcj-import-20070727).
libjava/ 2007-08-04 Matthias Klose <doko@ubuntu.com> Import GNU Classpath (libgcj-import-20070727). * Regenerate class and header files. * Regenerate auto* files. * include/jvm.h: * jni-libjvm.cc (Jv_JNI_InvokeFunctions): Rename type. * jni.cc (_Jv_JNIFunctions, _Jv_JNI_InvokeFunctions): Likewise. * jni.cc (_Jv_JNI_CallAnyMethodA, _Jv_JNI_CallAnyVoidMethodA, _Jv_JNI_CallMethodA, _Jv_JNI_CallVoidMethodA, _Jv_JNI_CallStaticMethodA, _Jv_JNI_CallStaticVoidMethodA, _Jv_JNI_NewObjectA, _Jv_JNI_SetPrimitiveArrayRegion): Constify jvalue parameter. * java/lang/reflect/natMethod.cc (_Jv_CallAnyMethodA): Likewise. * java/lang/VMFloat.java (toString, parseFloat): New. * gnu/awt/xlib/XToolkit.java (setAlwaysOnTop, isModalityTypeSupported, isModalExclusionTypeSupported): New (stub only). * gnu/awt/xlib/XCanvasPeer.java (requestFocus): Likewise. * gnu/awt/xlib/XFramePeer.java (updateMinimumSize, updateIconImages, updateFocusableWindowState, setModalBlocked, getBoundsPrivate, setAlwaysOnTop): Likewise. * gnu/awt/xlib/XFontPeer.java (canDisplay): Update signature. * scripts/makemake.tcl: Ignore gnu/javax/sound/sampled/gstreamer, ignore javax.sound.sampled.spi.MixerProvider, ignore .in files. * HACKING: Mention --enable-gstreamer-peer, removal of generated files. libjava/classpath/ 2007-08-04 Matthias Klose <doko@ubuntu.com> * java/util/EnumMap.java (clone): Add cast. From-SVN: r127204
This commit is contained in:
@@ -51,6 +51,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.Point;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -75,10 +76,10 @@ import java.awt.image.DataBuffer;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.SampleModel;
|
||||
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;
|
||||
|
||||
@@ -147,7 +148,7 @@ import java.util.Map;
|
||||
*/
|
||||
public abstract class AbstractGraphics2D
|
||||
extends Graphics2D
|
||||
implements Cloneable
|
||||
implements Cloneable, Pixelizer
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -155,13 +156,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.
|
||||
@@ -226,17 +220,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:
|
||||
@@ -931,8 +914,8 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
// Initialize clip if not already present.
|
||||
if (clip == null)
|
||||
clip = s;
|
||||
|
||||
setClip(s);
|
||||
|
||||
// This is so common, let's optimize this.
|
||||
else if (clip instanceof Rectangle && s instanceof Rectangle)
|
||||
{
|
||||
@@ -1174,7 +1157,9 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
if (isOptimized)
|
||||
{
|
||||
rawDrawLine(x1, y1, x2, y2);
|
||||
int tx = (int) transform.getTranslateX();
|
||||
int ty = (int) transform.getTranslateY();
|
||||
rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1214,7 +1199,8 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
if (isOptimized)
|
||||
{
|
||||
rawFillRect(x, y, width, height);
|
||||
rawFillRect(x + (int) transform.getTranslateX(),
|
||||
y + (int) transform.getTranslateY(), width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1352,8 +1338,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 +1358,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 +1373,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;
|
||||
@@ -1397,7 +1393,10 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
boolean ret;
|
||||
if (isOptimized)
|
||||
ret = rawDrawImage(image, x, y, observer);
|
||||
{
|
||||
ret = rawDrawImage(image, x + (int) transform.getTranslateX(),
|
||||
y + (int) transform.getTranslateY(), observer);
|
||||
}
|
||||
else
|
||||
{
|
||||
AffineTransform t = new AffineTransform();
|
||||
@@ -1559,17 +1558,15 @@ 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
|
||||
{
|
||||
Object v = renderingHints.get(RenderingHints.KEY_ANTIALIASING);
|
||||
antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
ScanlineConverter sc = getScanlineConverter();
|
||||
int resolution = 0;
|
||||
if (antialias)
|
||||
@@ -1577,7 +1574,7 @@ public abstract class AbstractGraphics2D
|
||||
// Adjust resolution according to rendering hints.
|
||||
resolution = 2;
|
||||
}
|
||||
sc.renderShape(this, s, clip, transform, resolution);
|
||||
sc.renderShape(this, s, clip, transform, resolution, renderingHints);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1609,12 +1606,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 +1667,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1718,10 +1727,38 @@ public abstract class AbstractGraphics2D
|
||||
* @param x1 the right offset
|
||||
* @param y the scanline
|
||||
*/
|
||||
protected void fillScanline(int x0, int x1, int y)
|
||||
public void renderScanline(int y, ScanlineCoverage c)
|
||||
{
|
||||
PaintContext pCtx = paintContext;
|
||||
int x0 = c.getMinX();
|
||||
int x1 = c.getMaxX();
|
||||
Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1);
|
||||
|
||||
// Do the anti aliasing thing.
|
||||
float coverageAlpha = 0;
|
||||
float maxCoverage = c.getMaxCoverage();
|
||||
ColorModel cm = pCtx.getColorModel();
|
||||
DataBuffer db = paintRaster.getDataBuffer();
|
||||
Point loc = new Point(paintRaster.getMinX(), paintRaster.getMinY());
|
||||
SampleModel sm = paintRaster.getSampleModel();
|
||||
WritableRaster writeRaster = Raster.createWritableRaster(sm, db, loc);
|
||||
WritableRaster alphaRaster = cm.getAlphaRaster(writeRaster);
|
||||
int pixel;
|
||||
ScanlineCoverage.Iterator iter = c.iterate();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
ScanlineCoverage.Range range = iter.next();
|
||||
coverageAlpha = range.getCoverage() / maxCoverage;
|
||||
if (coverageAlpha < 1.0)
|
||||
{
|
||||
for (int x = range.getXPos(); x < range.getXPosEnd(); x++)
|
||||
{
|
||||
pixel = alphaRaster.getSample(x, y, 0);
|
||||
pixel = (int) (pixel * coverageAlpha);
|
||||
alphaRaster.setSample(x, y, 0, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
ColorModel paintColorModel = pCtx.getColorModel();
|
||||
CompositeContext cCtx = composite.createContext(paintColorModel,
|
||||
getColorModel(),
|
||||
@@ -1733,66 +1770,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 +1948,5 @@ public abstract class AbstractGraphics2D
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Pixelizer.java -- Interface for the target of the rasterizer
|
||||
Copyright (C) 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;
|
||||
|
||||
/**
|
||||
* A pixelizer is responsible for actually manipulating the pixel of a drawing
|
||||
* surface after the scanline conversion process. It receives coverage
|
||||
* information for a scanline and adjusts the surface pixels accordingly.
|
||||
*/
|
||||
public interface Pixelizer
|
||||
{
|
||||
|
||||
/**
|
||||
* Renders the pixel for one scanline at the Y location <code>y</code>
|
||||
* and using the coverage information in <code>sc</code>.
|
||||
*
|
||||
* @param y the scanline Y coordinate
|
||||
* @param sc the coverage information
|
||||
*/
|
||||
void renderScanline(int y, ScanlineCoverage sc);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* ScanlineConverter.java -- Rasterizes Shapes
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
@@ -40,6 +40,7 @@ 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;
|
||||
@@ -47,7 +48,7 @@ import java.awt.geom.PathIterator;
|
||||
/**
|
||||
* Rasterizes {@link Shape} objects on an AbstractGraphics2D.
|
||||
*/
|
||||
final class ScanlineConverter
|
||||
public final class ScanlineConverter
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -56,10 +57,15 @@ final class ScanlineConverter
|
||||
private static int FIXED_DIGITS = 6;
|
||||
|
||||
/**
|
||||
* The fixed value for the number 1.
|
||||
* The fixed point constant for the number one.
|
||||
*/
|
||||
private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1);
|
||||
|
||||
/**
|
||||
* The number of significant bits for the Y resolution.
|
||||
*/
|
||||
private static int Y_RESOLUTION = 4;
|
||||
|
||||
/**
|
||||
* The actual number of scanlines.
|
||||
*/
|
||||
@@ -109,6 +115,13 @@ final class ScanlineConverter
|
||||
|
||||
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.
|
||||
@@ -120,18 +133,23 @@ final class ScanlineConverter
|
||||
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
|
||||
*/
|
||||
void renderShape(AbstractGraphics2D g, Shape shape, Shape clip,
|
||||
AffineTransform trans, int res)
|
||||
public void renderShape(Pixelizer p, Shape shape, Shape clip,
|
||||
AffineTransform trans, int res, RenderingHints hints)
|
||||
{
|
||||
// TODO: Do something useful with the rendering hints. Like, adjusting
|
||||
// the resolution.
|
||||
|
||||
// Prepare resolution and upper bounds.
|
||||
clear();
|
||||
setResolution(res);
|
||||
@@ -139,11 +157,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);
|
||||
}
|
||||
|
||||
@@ -157,11 +176,11 @@ final class ScanlineConverter
|
||||
}
|
||||
|
||||
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 +203,16 @@ final class ScanlineConverter
|
||||
activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep);
|
||||
|
||||
// Ok, now we can perform the actual scanlining.
|
||||
boolean push = lastIndex != index;
|
||||
doScanline(g, y, push, haveClip);
|
||||
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;
|
||||
lastIndex = index;
|
||||
lastRealY = realY;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,17 +232,31 @@ final class ScanlineConverter
|
||||
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(AbstractGraphics2D g, int y, boolean push,
|
||||
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;
|
||||
@@ -238,22 +272,16 @@ final class ScanlineConverter
|
||||
int x0 = lastEdge.xIntersection;
|
||||
int x1 = edge.xIntersection;
|
||||
assert x0 <= x1;
|
||||
if (push)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
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 - Y_RESOLUTION);
|
||||
frac1 = frac1 >> (FIXED_DIGITS - Y_RESOLUTION);
|
||||
scanlineCoverage.add(pix0, 1 * (1 << Y_RESOLUTION), frac0);
|
||||
scanlineCoverage.add(pix1, -1 * (1 << Y_RESOLUTION), -frac1);
|
||||
}
|
||||
if (edge.isClip)
|
||||
inClip = ! inClip;
|
||||
@@ -262,7 +290,15 @@ final class ScanlineConverter
|
||||
|
||||
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
|
||||
@@ -272,9 +308,12 @@ final class ScanlineConverter
|
||||
*/
|
||||
private void setResolution(int res)
|
||||
{
|
||||
int scanlinesPerPixel = 1 << res;
|
||||
int one = Fixed.fixedValue(FIXED_DIGITS, 1);
|
||||
resolution = one / (1 << res);
|
||||
resolution = one / (scanlinesPerPixel);
|
||||
halfStep = resolution / 2;
|
||||
|
||||
scanlineCoverage.setMaxCoverage(scanlinesPerPixel << Y_RESOLUTION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,6 +348,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 +359,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 +414,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,630 @@
|
||||
/* ScanlineCoverage.java -- Manages coverage information for a scanline
|
||||
Copyright (C) 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;
|
||||
|
||||
/**
|
||||
* Stores and handles the pixel converage for a scanline. The pixel coverage
|
||||
* is stored as sorted list of {@linke Covergage} entries, each of which holds
|
||||
* information about the coverage for the X and Y axis. This is utilized to
|
||||
* compute the actual coverage for each pixel on the scanline and finding
|
||||
* chunks of pixels with equal coverage quickly.
|
||||
*/
|
||||
public final class ScanlineCoverage
|
||||
{
|
||||
|
||||
/**
|
||||
* Iterates over the coverage list and calculates the actual coverage
|
||||
* ranges on a scanline.
|
||||
*/
|
||||
public final class Iterator
|
||||
{
|
||||
/**
|
||||
* This instance is reused in the iteration.
|
||||
*/
|
||||
private Range range;
|
||||
|
||||
/**
|
||||
* The pointer to the current item in the iteration.
|
||||
*/
|
||||
private Coverage currentItem;
|
||||
|
||||
/**
|
||||
* The current coverage value.
|
||||
*/
|
||||
private int currentCoverage;
|
||||
|
||||
/**
|
||||
* True when the current pixel coverage has already been handled, false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean handledPixelCoverage;
|
||||
|
||||
/**
|
||||
* Creates a new CoverageIterator.
|
||||
*/
|
||||
Iterator()
|
||||
{
|
||||
range = new Range();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next coverage range on the scanline. The returned object
|
||||
* will always be the same object, but with different values. Keep that
|
||||
* in mind when dealing with this object.
|
||||
*
|
||||
* @return the next coverage range on the scanline
|
||||
*/
|
||||
public Range next()
|
||||
{
|
||||
// TODO: Lump together the single-pixel coverage and the
|
||||
// between-pixel coverage when the pixel coverage delta is 0.
|
||||
if (handledPixelCoverage == false)
|
||||
{
|
||||
// Handle single pixel coverage.
|
||||
range.setXPos(currentItem.xPos);
|
||||
range.setLength(1);
|
||||
range.setCoverage(currentCoverage + currentItem.pixelCoverage);
|
||||
handledPixelCoverage = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle pixel span coverage.
|
||||
currentCoverage += currentItem.covDelta;
|
||||
range.setCoverage(currentCoverage);
|
||||
range.setXPos(currentItem.xPos + 1);
|
||||
currentItem = currentItem.next;
|
||||
range.setLength(currentItem.xPos - range.xPos);
|
||||
handledPixelCoverage = false;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@ true} when there are more coverage ranges to iterate,
|
||||
* {@ false} otherwise.
|
||||
*
|
||||
* @return {@ true} when there are more coverage ranges to iterate,
|
||||
* {@ false} otherwise
|
||||
*/
|
||||
public boolean hasNext()
|
||||
{
|
||||
boolean hasNext;
|
||||
if (currentItem != null && handledPixelCoverage == false)
|
||||
{
|
||||
// We have at least one more coverage item when there's a pixel
|
||||
// coverage piece left.
|
||||
hasNext = true;
|
||||
}
|
||||
else if (currentItem == null || currentItem.next == null
|
||||
|| currentItem.next == last)
|
||||
{
|
||||
hasNext = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasNext = true;
|
||||
}
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this iterator to the start of the list.
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
currentItem = head;
|
||||
currentCoverage = 0;
|
||||
handledPixelCoverage = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data object that carries information about pixel coverage on a scanline.
|
||||
* The data consists of a starting X position on the scanline, the
|
||||
* length of the range in pixels and the actual coverage value.
|
||||
´ */
|
||||
public static final class Range
|
||||
{
|
||||
/**
|
||||
* The X position on the scanline, in pixels.
|
||||
*/
|
||||
private int xPos;
|
||||
|
||||
/**
|
||||
* The length of the range, in pixels.
|
||||
*/
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* The actual coverage. The relation depends on
|
||||
* {@link ScanlineCoverage#maxCoverage}.
|
||||
*/
|
||||
private int coverage;
|
||||
|
||||
/**
|
||||
* Creates a new CoverageRange object.
|
||||
*/
|
||||
Range()
|
||||
{
|
||||
// Nothing to do. The values get initialized in the corresponding
|
||||
// setters.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the X start position (left) on the scanline. This value is
|
||||
* considered to be in pixels and device space.
|
||||
*
|
||||
* @param x the x position
|
||||
*/
|
||||
void setXPos(int x)
|
||||
{
|
||||
xPos = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the X start position (left) on the scanline. This value
|
||||
* is considered to be in pixels and device space.
|
||||
*
|
||||
* @return the X position on the scanline
|
||||
*/
|
||||
public int getXPos()
|
||||
{
|
||||
return xPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the pixel range. This is in pixel units.
|
||||
*
|
||||
* @param l the length of the range
|
||||
*/
|
||||
void setLength(int l)
|
||||
{
|
||||
length = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the range in pixel units.
|
||||
*
|
||||
* @return the length of the range in pixel units
|
||||
*/
|
||||
public int getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first X position after the range.
|
||||
*
|
||||
* @return the first X position after the range
|
||||
*/
|
||||
public int getXPosEnd()
|
||||
{
|
||||
return xPos + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the coverage of the pixel range. The relation of that value
|
||||
* depends on {@link ScanlineCoverage#maxCoverage}.
|
||||
*
|
||||
* @param cov the coverage value for the pixel range
|
||||
*/
|
||||
void setCoverage(int cov)
|
||||
{
|
||||
coverage = cov;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the coverage of the pixel range. The relation of this value
|
||||
* depends on {@link ScanlineCoverage#getMaxCoverage()}.
|
||||
*
|
||||
* @return the coverage of the pixel range
|
||||
*/
|
||||
public int getCoverage()
|
||||
{
|
||||
return coverage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "Coverage range: xPos=" + xPos + ", length=" + length
|
||||
+ ", coverage: " + coverage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* One bucket in the list.
|
||||
*/
|
||||
private static final class Coverage
|
||||
{
|
||||
/**
|
||||
* The X coordinate on the scanline to which this bucket belongs.
|
||||
*/
|
||||
int xPos;
|
||||
|
||||
/**
|
||||
* The coverage delta from the pixel at xPos to xPos + 1.
|
||||
*/
|
||||
int covDelta;
|
||||
|
||||
/**
|
||||
* The delta for the pixel at xPos. This is added to the pixel at xPos,
|
||||
* but not to the following pixel.
|
||||
*/
|
||||
int pixelCoverage;
|
||||
|
||||
/**
|
||||
* Implements a linked list. This points to the next element of the list.
|
||||
*/
|
||||
Coverage next;
|
||||
|
||||
/**
|
||||
* Returns the X coordinate for this entry.
|
||||
*
|
||||
* @return the X coordinate for this entry
|
||||
*/
|
||||
public int getXPos()
|
||||
{
|
||||
return xPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the coverage delta for this entry.
|
||||
*
|
||||
* @return the coverage delta for this entry
|
||||
*/
|
||||
public int getCoverageDelta()
|
||||
{
|
||||
return covDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation.
|
||||
*
|
||||
* @return a string representation
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "Coverage: xPos: " + xPos + ", covDelta: " + covDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this entry and all the following
|
||||
* in the linked list.
|
||||
*
|
||||
* @return a string representation of this entry and all the following
|
||||
* in the linked list
|
||||
*/
|
||||
public String list()
|
||||
{
|
||||
String str = toString();
|
||||
if (next != null)
|
||||
str = str + " --> " + next.list();
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The head of the sorted list of buckets.
|
||||
*/
|
||||
private Coverage head;
|
||||
|
||||
/**
|
||||
* The current bucket. We make use of the fact that the scanline converter
|
||||
* always scans the scanline (and thus this list) from left to right to
|
||||
* quickly find buckets or insertion points.
|
||||
*/
|
||||
private Coverage current;
|
||||
|
||||
/**
|
||||
* The item that is before current in the list.
|
||||
*/
|
||||
private Coverage currentPrev;
|
||||
|
||||
/**
|
||||
* The bucket after the last valid bucket. Unused buckets are not thrown
|
||||
* away and garbage collected. Instead, we keep them at the tail of the list
|
||||
* and reuse them when necessary.
|
||||
*/
|
||||
private Coverage last;
|
||||
|
||||
/**
|
||||
* The last valid entry.
|
||||
*/
|
||||
private Coverage lastPrev;
|
||||
|
||||
/**
|
||||
* The minimum X coordinate of this scanline.
|
||||
*/
|
||||
private int minX;
|
||||
|
||||
/**
|
||||
* The maximum X coordinate of this scanline.
|
||||
*/
|
||||
private int maxX;
|
||||
|
||||
/**
|
||||
* The maximum coverage value.
|
||||
*/
|
||||
private int maxCoverage;
|
||||
|
||||
/**
|
||||
* The iterator over the ranges of this scanline.
|
||||
*/
|
||||
private Iterator iterator;
|
||||
|
||||
/**
|
||||
* Creates a new ScanlineCoverage instance.
|
||||
*/
|
||||
public ScanlineCoverage()
|
||||
{
|
||||
iterator = new Iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the the next scan of the scanline begins and that the next
|
||||
* request will be at the beginning of this list. This makes searching and
|
||||
* sorting of this list very quick.
|
||||
*/
|
||||
public void rewind()
|
||||
{
|
||||
current = head;
|
||||
currentPrev = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the list. This does not throw away the old buckets but only
|
||||
* resets the end-pointer of the list to the first element. All buckets are
|
||||
* then unused and are reused when the list is filled again.
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
last = head;
|
||||
lastPrev = null;
|
||||
current = head;
|
||||
currentPrev = null;
|
||||
minX = Integer.MAX_VALUE;
|
||||
maxX = Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds the specified coverage to the pixel at the specified
|
||||
* X position.
|
||||
*
|
||||
* @param x the X position
|
||||
* @param xc the x coverage
|
||||
* @param yc the y coverage
|
||||
*/
|
||||
public void add(int x, int xc, int yc)
|
||||
{
|
||||
Coverage bucket = findOrInsert(x);
|
||||
bucket.covDelta += xc;
|
||||
bucket.pixelCoverage += yc;
|
||||
minX = Math.min(minX, x);
|
||||
maxX = Math.max(maxX, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum coverage value for the scanline.
|
||||
*
|
||||
* @return the maximum coverage value for the scanline
|
||||
*/
|
||||
public int getMaxCoverage()
|
||||
{
|
||||
return maxCoverage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum coverage value for the scanline.
|
||||
*
|
||||
* @param maxCov the maximum coverage value for the scanline
|
||||
*/
|
||||
void setMaxCoverage(int maxCov)
|
||||
{
|
||||
maxCoverage = maxCov;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum X coordinate of the current scanline.
|
||||
*
|
||||
* @return the maximum X coordinate of the current scanline
|
||||
*/
|
||||
public int getMaxX()
|
||||
{
|
||||
return maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum X coordinate of the current scanline.
|
||||
*
|
||||
* @return the minimum X coordinate of the current scanline
|
||||
*/
|
||||
public int getMinX()
|
||||
{
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the bucket in the list with the specified X coordinate.
|
||||
* If no such bucket is found, then a new one is fetched (either a cached
|
||||
* bucket from the end of the list or a newly allocated one) inserted at the
|
||||
* correct position and returned.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
*
|
||||
* @return a bucket to hold the coverage data
|
||||
*/
|
||||
private Coverage findOrInsert(int x)
|
||||
{
|
||||
// First search for a matching bucket.
|
||||
if (head == null)
|
||||
{
|
||||
// Special case: the list is still empty.
|
||||
// Testpoint 1.
|
||||
head = new Coverage();
|
||||
head.xPos = x;
|
||||
current = head;
|
||||
currentPrev = null;
|
||||
return head;
|
||||
}
|
||||
|
||||
// This performs a linear search, starting from the current bucket.
|
||||
// This is reasonably efficient because access to this list is always done
|
||||
// in a linear fashion and we are usually not more then 1 or 2 buckets away
|
||||
// from the one we're looking for.
|
||||
Coverage match = current;
|
||||
Coverage prev = currentPrev;
|
||||
while (match != last && match.xPos < x)
|
||||
{
|
||||
prev = match;
|
||||
match = match.next;
|
||||
}
|
||||
|
||||
// At this point we have either found an entry with xPos >= x, or reached
|
||||
// the end of the list (match == last || match == null).
|
||||
if (match == null)
|
||||
{
|
||||
// End of the list. No cached items to reuse.
|
||||
// Testpoint 2.
|
||||
match = new Coverage();
|
||||
match.xPos = x;
|
||||
if (prev != null)
|
||||
prev.next = match;
|
||||
current = match;
|
||||
currentPrev = prev;
|
||||
return match;
|
||||
}
|
||||
else if (match == last)
|
||||
{
|
||||
// End of the list. Reuse this item. Expand list.
|
||||
// Testpoint 3.
|
||||
last = match.next;
|
||||
lastPrev = match;
|
||||
match.xPos = x;
|
||||
match.covDelta = 0;
|
||||
match.pixelCoverage = 0;
|
||||
// Keep link to last element or null, indicating the end of the list.
|
||||
current = match;
|
||||
currentPrev = prev;
|
||||
return match;
|
||||
}
|
||||
|
||||
if (x == match.xPos)
|
||||
{
|
||||
// Special case: We have another coverage entry at the same location
|
||||
// as an already existing entry. Return this.
|
||||
// Testpoint 4.
|
||||
current = match;
|
||||
currentPrev = prev;
|
||||
return match;
|
||||
}
|
||||
else // x <= match.xPos
|
||||
{
|
||||
assert (x <= match.xPos);
|
||||
assert (prev == null ||x > prev.xPos);
|
||||
|
||||
// Create new entry, or reuse existing one.
|
||||
Coverage cov;
|
||||
if (last != null)
|
||||
{
|
||||
// Testpoint 5.
|
||||
cov = last;
|
||||
last = cov.next;
|
||||
lastPrev.next = last;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Testpoint 6.
|
||||
cov = new Coverage();
|
||||
}
|
||||
|
||||
cov.xPos = x;
|
||||
cov.covDelta = 0;
|
||||
cov.pixelCoverage = 0;
|
||||
|
||||
// Insert this item in the list.
|
||||
if (prev != null)
|
||||
{
|
||||
// Testpoint 5 & 6.
|
||||
prev.next = cov;
|
||||
cov.next = match;
|
||||
current = cov;
|
||||
currentPrev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Testpoint 7.
|
||||
assert (match == head);
|
||||
// Insert at head.
|
||||
head = cov;
|
||||
head.next = match;
|
||||
current = head;
|
||||
currentPrev = null;
|
||||
}
|
||||
return cov;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re-)Starts iterating the coverage values for the scanline.
|
||||
* Use the returned iterator to get the consecutive coverage ranges.
|
||||
*
|
||||
* @return the iterator
|
||||
*/
|
||||
public Iterator iterate()
|
||||
{
|
||||
iterator.reset();
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@ true} if this object has no entries for the current scanline,
|
||||
* {@ false} otherwise.
|
||||
*
|
||||
* @return {@ true} if this object has no entries for the current scanline,
|
||||
* {@ false} otherwise
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return head == null || head == last
|
||||
|| head.next == null || head.next == last;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user