libjava/classpath/ChangeLog.gcj:
2007-05-31 Matthias Klose <doko@ubuntu.com> * javax/management/NotificationBroadcasterSupport.java (getNotificationInfo): Add cast. * native/jni/qt-peer/Makefile.am (AM_CXXFLAGS): Add libstdc++ include directories. * native/jni/qt-peer/Makefile.in: Regenerate. libjava/ChangeLog: 2007-06-03 Matthias Klose <doko@ubuntu.com> * java/io/natFileWin32.cc (setFilePermissions): New (stub only). _access: Handle EXEC query, stub only. 2007-06-03 Matthias Klose <doko@ubuntu.com> Merged from classpath: * gnu/java/nio/SelectorProviderImpl.java: Whitespace merge. * java/lang/System.java(inheritedChannel): New. * java/lang/Character.java: Remove stray`;'. * java/net/MulticastSocket.java: Merged. * java/text/DateFormatSymbols.java(getInstance): New, comment updates. * java/text/Collator.java(getInstance): Merged. * java/util/Calendar.java: New attributes ALL_STYLES, SHORT, LONG. getDisplayName, getDisplayNames: New. * java/util/logging/Logger.java: Merged. * Regenerate .class and .h files. 2007-06-03 Matthias Klose <doko@ubuntu.com> * java/io/File.java: Merge with classpath-0.95, new method setFilePermissions, new attribute EXEC. * java/io/natFilePosix.cc (setFilePermissions): New. _access: Handle EXEC query. * classpath/lib/java/io/File.class, java/io/File.h: Regenerate. 2007-06-03 Matthias Klose <doko@ubuntu.com> Imported GNU Classpath 0.95. * classpath/Makefile.in, classpath/native/jni/midi-dssi/Makefile.in, classpath/native/jni/classpath/Makefile.in, classpath/native/jni/Makefile.in, classpath/native/jni/gconf-peer/Makefile.in, classpath/native/jni/java-io/Makefile.in, classpath/native/jni/native-lib/Makefile.in, classpath/native/jni/java-util/Makefile.in, classpath/native/jni/midi-alsa/Makefile.in, classpath/native/jni/java-lang/Makefile.in, classpath/native/jni/java-nio/Makefile.in, classpath/native/jni/java-net/Makefile.in, classpath/native/jni/xmlj/Makefile.in, classpath/native/jni/qt-peer/Makefile.in, classpath/native/jni/gtk-peer/Makefile.in, classpath/native/Makefile.in, classpath/native/jawt/Makefile.in, classpath/native/fdlibm/Makefile.in, classpath/native/plugin/Makefile.in, classpath/resource/Makefile.in, classpath/scripts/Makefile.in, classpath/tools/Makefile.in, classpath/doc/Makefile.in, classpath/doc/api/Makefile.in, classpath/lib/Makefile.in, classpath/external/Makefile.in, classpath/external/jsr166/Makefile.in, classpath/external/sax/Makefile.in, classpath/external/w3c_dom/Makefile.in, classpath/external/relaxngDatatype/Makefile.in, classpath/include/Makefile.in, classpath/examples/Makefile.in: Regenerate. * classpath/config.guess, classpath/config.sub, classpath/ltmain.sh : Update. * classpath/configure, classpath/depcomp, classpath/missing, classpath/aclocal.m4, classpath/install-sh: Regenerate. * gnu/classpath/Configuration.java (CLASSPATH_VERSION): Now 0.95. * sources.am: Regenerate. * Makefile.in: Regenerate. * Update the .class files and generated CNI header files, add new .class and generated CNI header files. * Remove generated files for removed java source files: classpath/gnu/java/net/BASE64.java, classpath/gnu/java/security/util/Base64.java, classpath/gnu/java/awt/peer/gtk/GThreadMutex.java, classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java, classpath/gnu/java/awt/font/autofit/Scaler.java, classpath/gnu/classpath/jdwp/util/Value.java, classpath/gnu/javax/net/ssl/Base64.java. * Remove empty directories. * Makefile.am(nat_source_files): Add natVMOperatingSystemMXBeanImpl.cc. * java/lang/Class.java(setAccessible): Merge from classpath. * java/util/Locale.java: Remove. * gnu/java/lang/management/VMOperatingSystemMXBeanImpl.java, gnu/java/lang/management/natVMOperatingSystemMXBeanImpl.cc: New. * gcj/javaprims.h: Update class declarations. * scripts/classes.pl: Update usage. * HACKING: Mention to build all peers. From-SVN: r125302
This commit is contained in:
parent
af333b9a7f
commit
e1bea0c068
2951 changed files with 80982 additions and 68583 deletions
|
@ -67,8 +67,6 @@ import java.awt.geom.Ellipse2D;
|
|||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
|
@ -82,7 +80,6 @@ import java.awt.image.renderable.RenderableImage;
|
|||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -153,6 +150,11 @@ public abstract class AbstractGraphics2D
|
|||
implements Cloneable
|
||||
{
|
||||
|
||||
/**
|
||||
* The default font to use on the graphics object.
|
||||
*/
|
||||
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.
|
||||
|
@ -164,7 +166,14 @@ public abstract class AbstractGraphics2D
|
|||
* Caches certain shapes to avoid massive creation of such Shapes in
|
||||
* the various draw* and fill* methods.
|
||||
*/
|
||||
private static final ThreadLocal shapeCache = new ThreadLocal();
|
||||
private static final ThreadLocal<ShapeCache> shapeCache =
|
||||
new ThreadLocal<ShapeCache>();
|
||||
|
||||
/**
|
||||
* The scanline converters by thread.
|
||||
*/
|
||||
private static final ThreadLocal<ScanlineConverter> scanlineConverters =
|
||||
new ThreadLocal<ScanlineConverter>();
|
||||
|
||||
/**
|
||||
* The transformation for this Graphics2D instance
|
||||
|
@ -176,6 +185,11 @@ public abstract class AbstractGraphics2D
|
|||
*/
|
||||
private Paint paint;
|
||||
|
||||
/**
|
||||
* The paint context during rendering.
|
||||
*/
|
||||
private PaintContext paintContext;
|
||||
|
||||
/**
|
||||
* The background.
|
||||
*/
|
||||
|
@ -239,6 +253,17 @@ public abstract class AbstractGraphics2D
|
|||
*/
|
||||
private boolean isOptimized = true;
|
||||
|
||||
private static final BasicStroke STANDARD_STROKE = new BasicStroke();
|
||||
|
||||
private static final HashMap STANDARD_HINTS;
|
||||
static {
|
||||
HashMap hints = new HashMap();
|
||||
hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
|
||||
hints.put(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_DEFAULT);
|
||||
STANDARD_HINTS = hints;
|
||||
}
|
||||
/**
|
||||
* Creates a new AbstractGraphics2D instance.
|
||||
*/
|
||||
|
@ -247,13 +272,8 @@ public abstract class AbstractGraphics2D
|
|||
transform = new AffineTransform();
|
||||
background = Color.WHITE;
|
||||
composite = AlphaComposite.SrcOver;
|
||||
stroke = new BasicStroke();
|
||||
HashMap hints = new HashMap();
|
||||
hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
|
||||
hints.put(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_DEFAULT);
|
||||
renderingHints = new RenderingHints(hints);
|
||||
stroke = STANDARD_STROKE;
|
||||
renderingHints = new RenderingHints(STANDARD_HINTS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -958,15 +978,8 @@ public abstract class AbstractGraphics2D
|
|||
*/
|
||||
public void drawGlyphVector(GlyphVector gv, float x, float y)
|
||||
{
|
||||
int numGlyphs = gv.getNumGlyphs();
|
||||
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++)
|
||||
{
|
||||
Shape o = gv.getGlyphOutline(i);
|
||||
fillShape(o, true);
|
||||
}
|
||||
fillShape(gv.getOutline(), true);
|
||||
translate(-x, -y);
|
||||
}
|
||||
|
||||
|
@ -1557,21 +1570,14 @@ public abstract class AbstractGraphics2D
|
|||
antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
Rectangle2D userBounds = s.getBounds2D();
|
||||
Rectangle2D deviceBounds = new Rectangle2D.Double();
|
||||
ArrayList segs = getSegments(s, transform, deviceBounds, false);
|
||||
Rectangle2D clipBounds = new Rectangle2D.Double();
|
||||
ArrayList clipSegs = getSegments(clip, transform, clipBounds, true);
|
||||
segs.addAll(clipSegs);
|
||||
Rectangle2D inclClipBounds = new Rectangle2D.Double();
|
||||
Rectangle2D.union(clipBounds, deviceBounds, inclClipBounds);
|
||||
if (segs.size() > 0)
|
||||
ScanlineConverter sc = getScanlineConverter();
|
||||
int resolution = 0;
|
||||
if (antialias)
|
||||
{
|
||||
if (antialias)
|
||||
fillShapeAntialias(segs, deviceBounds, userBounds, inclClipBounds);
|
||||
else
|
||||
fillShapeImpl(segs, deviceBounds, userBounds, inclClipBounds);
|
||||
// Adjust resolution according to rendering hints.
|
||||
resolution = 2;
|
||||
}
|
||||
sc.renderShape(this, s, clip, transform, resolution);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1704,141 +1710,6 @@ public abstract class AbstractGraphics2D
|
|||
throw new UnsupportedOperationException("Not implemented yet.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified polygon without anti-aliasing.
|
||||
*/
|
||||
private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D,
|
||||
Rectangle2D userBounds,
|
||||
Rectangle2D inclClipBounds)
|
||||
{
|
||||
// This is an implementation of a polygon scanline conversion algorithm
|
||||
// described here:
|
||||
// http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/scan/
|
||||
|
||||
// Create table of all edges.
|
||||
// The edge buckets, sorted and indexed by their Y values.
|
||||
|
||||
double minX = deviceBounds2D.getMinX();
|
||||
double minY = deviceBounds2D.getMinY();
|
||||
double maxX = deviceBounds2D.getMaxX();
|
||||
double maxY = deviceBounds2D.getMaxY();
|
||||
double icMinY = inclClipBounds.getMinY();
|
||||
double icMaxY = inclClipBounds.getMaxY();
|
||||
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,
|
||||
userBounds, transform, renderingHints);
|
||||
|
||||
ArrayList[] edgeTable = new ArrayList[(int) Math.ceil(icMaxY)
|
||||
- (int) Math.ceil(icMinY) + 1];
|
||||
|
||||
for (Iterator i = segs.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
int yindex = (int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY);
|
||||
if (edgeTable[yindex] == null) // Create bucket when needed.
|
||||
edgeTable[yindex] = new ArrayList();
|
||||
edgeTable[yindex].add(edge); // Add edge to the bucket of its line.
|
||||
}
|
||||
|
||||
// TODO: The following could be useful for a future optimization.
|
||||
// // Sort all the edges in the edge table within their buckets.
|
||||
// for (int y = 0; y < edgeTable.length; y++)
|
||||
// {
|
||||
// if (edgeTable[y] != null)
|
||||
// Collections.sort(edgeTable[y]);
|
||||
// }
|
||||
|
||||
// The activeEdges list contains all the edges of the current scanline
|
||||
// ordered by their intersection points with this scanline.
|
||||
ArrayList activeEdges = new ArrayList();
|
||||
PolyEdgeComparator comparator = new PolyEdgeComparator();
|
||||
|
||||
// Scan all relevant lines.
|
||||
int minYInt = (int) Math.ceil(icMinY);
|
||||
|
||||
Rectangle devClip = getDeviceBounds();
|
||||
int scanlineMax = (int) Math.min(maxY, devClip.getMaxY());
|
||||
for (int y = minYInt; y < scanlineMax; y++)
|
||||
{
|
||||
ArrayList bucket = edgeTable[y - minYInt];
|
||||
// Update all the x intersections in the current activeEdges table
|
||||
// and remove entries that are no longer in the scanline.
|
||||
for (Iterator i = activeEdges.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
if (y > edge.y1)
|
||||
i.remove();
|
||||
else
|
||||
{
|
||||
edge.xIntersection += edge.slope;
|
||||
//edge.xIntersection = edge.x0 + edge.slope * (y - edge.y0);
|
||||
//System.err.println("edge.xIntersection: " + edge.xIntersection);
|
||||
}
|
||||
}
|
||||
|
||||
if (bucket != null)
|
||||
activeEdges.addAll(bucket);
|
||||
|
||||
// Sort current edges. We are using a bubble sort, because the order
|
||||
// of the intersections will not change in most situations. They
|
||||
// will only change, when edges intersect each other.
|
||||
int size = activeEdges.size();
|
||||
if (size > 1)
|
||||
{
|
||||
for (int i = 1; i < size; i++)
|
||||
{
|
||||
PolyEdge e1 = (PolyEdge) activeEdges.get(i - 1);
|
||||
PolyEdge e2 = (PolyEdge) activeEdges.get(i);
|
||||
if (comparator.compare(e1, e2) > 0)
|
||||
{
|
||||
// Swap e2 with its left neighbor until it 'fits'.
|
||||
int j = i;
|
||||
do
|
||||
{
|
||||
activeEdges.set(j, e1);
|
||||
activeEdges.set(j - 1, e2);
|
||||
j--;
|
||||
if (j >= 1)
|
||||
e1 = (PolyEdge) activeEdges.get(j - 1);
|
||||
} while (j >= 1 && comparator.compare(e1, e2) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now draw all pixels inside the polygon.
|
||||
// This is the last edge that intersected the scanline.
|
||||
PolyEdge previous = null; // Gets initialized below.
|
||||
boolean insideShape = false;
|
||||
boolean insideClip = false;
|
||||
//System.err.println("scanline: " + y);
|
||||
for (Iterator i = activeEdges.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
if (edge.y1 <= y)
|
||||
continue;
|
||||
|
||||
// Draw scanline when we are inside the shape AND inside the
|
||||
// clip.
|
||||
if (insideClip && insideShape)
|
||||
{
|
||||
int x0 = (int) previous.xIntersection;
|
||||
int x1 = (int) edge.xIntersection;
|
||||
if (x0 < x1)
|
||||
fillScanline(pCtx, x0, x1, y);
|
||||
}
|
||||
// Update state.
|
||||
previous = edge;
|
||||
if (edge.isClip)
|
||||
insideClip = ! insideClip;
|
||||
else
|
||||
insideShape = ! insideShape;
|
||||
}
|
||||
}
|
||||
pCtx.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints a scanline between x0 and x1. Override this when your backend
|
||||
* can efficiently draw/fill horizontal lines.
|
||||
|
@ -1847,8 +1718,9 @@ public abstract class AbstractGraphics2D
|
|||
* @param x1 the right offset
|
||||
* @param y the scanline
|
||||
*/
|
||||
protected void fillScanline(PaintContext pCtx, int x0, int x1, int y)
|
||||
protected void fillScanline(int x0, int x1, int y)
|
||||
{
|
||||
PaintContext pCtx = paintContext;
|
||||
Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1);
|
||||
ColorModel paintColorModel = pCtx.getColorModel();
|
||||
CompositeContext cCtx = composite.createContext(paintColorModel,
|
||||
|
@ -1860,198 +1732,6 @@ public abstract class AbstractGraphics2D
|
|||
cCtx.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills arbitrary shapes in an anti-aliased fashion.
|
||||
*
|
||||
* @param segs the line segments which define the shape which is to be filled
|
||||
*/
|
||||
private void fillShapeAntialias(ArrayList segs, Rectangle2D deviceBounds2D,
|
||||
Rectangle2D userBounds,
|
||||
Rectangle2D inclClipBounds)
|
||||
{
|
||||
// This is an implementation of a polygon scanline conversion algorithm
|
||||
// described here:
|
||||
// http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/scan/
|
||||
// The antialiasing is implemented using a sampling technique, we do
|
||||
// not scan whole lines but fractions of the line.
|
||||
|
||||
double minX = deviceBounds2D.getMinX();
|
||||
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(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(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) icMinY;
|
||||
//System.err.println("minY: " + minY);
|
||||
int firstSubline = (int) (Math.ceil((icMinY - Math.floor(icMinY)) * AA_SAMPLING));
|
||||
double firstLineDouble = firstLine + firstSubline / (double) AA_SAMPLING;
|
||||
//System.err.println("firstSubline: " + firstSubline);
|
||||
|
||||
// Create table of all edges.
|
||||
// The edge buckets, sorted and indexed by their Y values.
|
||||
//System.err.println("numScanlines: " + numScanlines);
|
||||
if (edgeTable == null
|
||||
|| edgeTable.length < numScanlines * AA_SAMPLING + AA_SAMPLING)
|
||||
edgeTable = new ArrayList[numScanlines * AA_SAMPLING + AA_SAMPLING];
|
||||
|
||||
//System.err.println("firstLineDouble: " + firstLineDouble);
|
||||
|
||||
for (Iterator i = segs.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
int yindex = (int) (Math.ceil((edge.y0 - firstLineDouble) * AA_SAMPLING));
|
||||
//System.err.println("yindex: " + yindex + " for y0: " + edge.y0);
|
||||
// Initialize edge's slope and initial xIntersection.
|
||||
edge.slope = ((edge.x1 - edge.x0) / (edge.y1 - edge.y0)) / AA_SAMPLING;
|
||||
if (edge.y0 == edge.y1) // Horizontal edge.
|
||||
edge.xIntersection = Math.min(edge.x0, edge.x1);
|
||||
else
|
||||
{
|
||||
double alignedFirst = Math.ceil(edge.y0 * AA_SAMPLING) / AA_SAMPLING;
|
||||
edge.xIntersection = edge.x0 + (edge.slope * AA_SAMPLING) * (alignedFirst - edge.y0);
|
||||
}
|
||||
//System.err.println(edge);
|
||||
// FIXME: Sanity check should not be needed when clipping works.
|
||||
if (yindex >= 0 && yindex < edgeTable.length)
|
||||
{
|
||||
if (edgeTable[yindex] == null) // Create bucket when needed.
|
||||
edgeTable[yindex] = new ArrayList();
|
||||
edgeTable[yindex].add(edge); // Add edge to the bucket of its line.
|
||||
}
|
||||
}
|
||||
|
||||
// The activeEdges list contains all the edges of the current scanline
|
||||
// ordered by their intersection points with this scanline.
|
||||
ArrayList activeEdges = new ArrayList();
|
||||
PolyEdgeComparator comparator = new PolyEdgeComparator();
|
||||
|
||||
// Scan all lines.
|
||||
int yindex = 0;
|
||||
//System.err.println("firstLine: " + firstLine + ", maxY: " + maxY + ", firstSubline: " + firstSubline);
|
||||
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);
|
||||
ArrayList bucket = edgeTable[yindex];
|
||||
// Update all the x intersections in the current activeEdges table
|
||||
// and remove entries that are no longer in the scanline.
|
||||
for (Iterator i = activeEdges.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
// TODO: Do the following using integer arithmetics.
|
||||
if ((y + ((double) subY / (double) AA_SAMPLING)) > edge.y1)
|
||||
i.remove();
|
||||
else
|
||||
{
|
||||
edge.xIntersection += edge.slope;
|
||||
//System.err.println("edge: " + edge);
|
||||
//edge.xIntersection = edge.x0 + edge.slope * (y - edge.y0);
|
||||
//System.err.println("edge.xIntersection: " + edge.xIntersection);
|
||||
}
|
||||
}
|
||||
|
||||
if (bucket != null)
|
||||
{
|
||||
activeEdges.addAll(bucket);
|
||||
edgeTable[yindex].clear();
|
||||
}
|
||||
|
||||
// Sort current edges. We are using a bubble sort, because the order
|
||||
// of the intersections will not change in most situations. They
|
||||
// will only change, when edges intersect each other.
|
||||
int size = activeEdges.size();
|
||||
if (size > 1)
|
||||
{
|
||||
for (int i = 1; i < size; i++)
|
||||
{
|
||||
PolyEdge e1 = (PolyEdge) activeEdges.get(i - 1);
|
||||
PolyEdge e2 = (PolyEdge) activeEdges.get(i);
|
||||
if (comparator.compare(e1, e2) > 0)
|
||||
{
|
||||
// Swap e2 with its left neighbor until it 'fits'.
|
||||
int j = i;
|
||||
do
|
||||
{
|
||||
activeEdges.set(j, e1);
|
||||
activeEdges.set(j - 1, e2);
|
||||
j--;
|
||||
if (j >= 1)
|
||||
e1 = (PolyEdge) activeEdges.get(j - 1);
|
||||
} while (j >= 1 && comparator.compare(e1, e2) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now draw all pixels inside the polygon.
|
||||
// This is the last edge that intersected the scanline.
|
||||
PolyEdge previous = null; // Gets initialized below.
|
||||
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();
|
||||
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)))
|
||||
{
|
||||
//System.err.println(edge);
|
||||
// TODO: Eliminate the aligments.
|
||||
int x0 = (int) Math.min(Math.max(previous.xIntersection, minX), maxX);
|
||||
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.
|
||||
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
|
||||
insideShape = ! insideShape;
|
||||
}
|
||||
yindex++;
|
||||
}
|
||||
firstSubline = 0;
|
||||
// Render full scanline.
|
||||
//System.err.println("scanline: " + y);
|
||||
if (! emptyScanline)
|
||||
fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX);
|
||||
}
|
||||
|
||||
pCtx.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills a horizontal line between x0 and x1 for anti aliased rendering.
|
||||
|
@ -2113,7 +1793,6 @@ public abstract class AbstractGraphics2D
|
|||
cCtx.dispose();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this graphics object. This must be called by subclasses in
|
||||
* order to correctly initialize the state of this object.
|
||||
|
@ -2121,13 +1800,8 @@ public abstract class AbstractGraphics2D
|
|||
protected void init()
|
||||
{
|
||||
setPaint(Color.BLACK);
|
||||
setFont(new Font("SansSerif", Font.PLAIN, 12));
|
||||
setFont(FONT);
|
||||
isOptimized = true;
|
||||
|
||||
// FIXME: Should not be necessary. A clip of null should mean
|
||||
// 'clip against device bounds.
|
||||
destinationRaster = getDestinationRaster();
|
||||
clip = getDeviceBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2266,80 +1940,6 @@ public abstract class AbstractGraphics2D
|
|||
p.transform(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified shape into a list of segments.
|
||||
*
|
||||
* @param s the shape to convert
|
||||
* @param t the transformation to apply before converting
|
||||
* @param deviceBounds an output parameter; holds the bounding rectangle of
|
||||
* s in device space after return
|
||||
* @param isClip true when the shape is a clip, false for normal shapes;
|
||||
* this influences the settings in the created PolyEdge instances.
|
||||
*
|
||||
* @return a list of PolyEdge that form the shape in device space
|
||||
*/
|
||||
private ArrayList getSegments(Shape s, AffineTransform t,
|
||||
Rectangle2D deviceBounds, boolean isClip)
|
||||
{
|
||||
// Flatten the path. TODO: Determine the best flattening factor
|
||||
// wrt to speed and quality.
|
||||
PathIterator path = s.getPathIterator(getTransform(), 1.0);
|
||||
|
||||
// Build up polygons and let the native backend render this using
|
||||
// rawFillShape() which would provide a default implementation for
|
||||
// drawPixel using a PolyScan algorithm.
|
||||
double[] seg = new double[6];
|
||||
|
||||
// TODO: Use ArrayList<PolyEdge> here when availble.
|
||||
ArrayList segs = new ArrayList();
|
||||
double segX = 0.; // The start point of the current edge.
|
||||
double segY = 0.;
|
||||
double polyX = 0.; // The start point of the current polygon.
|
||||
double polyY = 0.;
|
||||
|
||||
double minX = Integer.MAX_VALUE;
|
||||
double maxX = Integer.MIN_VALUE;
|
||||
double minY = Integer.MAX_VALUE;
|
||||
double maxY = Integer.MIN_VALUE;
|
||||
|
||||
//System.err.println("fill polygon");
|
||||
while (! path.isDone())
|
||||
{
|
||||
int segType = path.currentSegment(seg);
|
||||
minX = Math.min(minX, seg[0]);
|
||||
maxX = Math.max(maxX, seg[0]);
|
||||
minY = Math.min(minY, seg[1]);
|
||||
maxY = Math.max(maxY, seg[1]);
|
||||
|
||||
//System.err.println("segment: " + segType + ", " + seg[0] + ", " + seg[1]);
|
||||
if (segType == PathIterator.SEG_MOVETO)
|
||||
{
|
||||
segX = seg[0];
|
||||
segY = seg[1];
|
||||
polyX = seg[0];
|
||||
polyY = seg[1];
|
||||
}
|
||||
else if (segType == PathIterator.SEG_CLOSE)
|
||||
{
|
||||
// Close the polyline.
|
||||
PolyEdge edge = new PolyEdge(segX, segY,
|
||||
polyX, polyY, isClip);
|
||||
segs.add(edge);
|
||||
}
|
||||
else if (segType == PathIterator.SEG_LINETO)
|
||||
{
|
||||
PolyEdge edge = new PolyEdge(segX, segY,
|
||||
seg[0], seg[1], isClip);
|
||||
segs.add(edge);
|
||||
segX = seg[0];
|
||||
segY = seg[1];
|
||||
}
|
||||
path.next();
|
||||
}
|
||||
deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY);
|
||||
return segs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ShapeCache for the calling thread.
|
||||
*
|
||||
|
@ -2347,7 +1947,7 @@ public abstract class AbstractGraphics2D
|
|||
*/
|
||||
private ShapeCache getShapeCache()
|
||||
{
|
||||
ShapeCache sc = (ShapeCache) shapeCache.get();
|
||||
ShapeCache sc = shapeCache.get();
|
||||
if (sc == null)
|
||||
{
|
||||
sc = new ShapeCache();
|
||||
|
@ -2355,4 +1955,20 @@ public abstract class AbstractGraphics2D
|
|||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scanline converter for this thread.
|
||||
*
|
||||
* @return the scanline converter for this thread
|
||||
*/
|
||||
private ScanlineConverter getScanlineConverter()
|
||||
{
|
||||
ScanlineConverter sc = scanlineConverters.get();
|
||||
if (sc == null)
|
||||
{
|
||||
sc = new ScanlineConverter();
|
||||
scanlineConverters.set(sc);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue