summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancis Kung <fkung@redhat.com>2006-07-27 20:59:41 +0000
committerFrancis Kung <fkung@redhat.com>2006-07-27 20:59:41 +0000
commitc85d2bb435ae16ab1e6765b0f6e241aaeba9932b (patch)
tree51ea4fd0829e7406e4b3dc338cbfc31d2bbb0e12
parentacd96c927546bf72dd29df5bb8a0cca8ede496c2 (diff)
downloadclasspath-c85d2bb435ae16ab1e6765b0f6e241aaeba9932b.tar.gz
2006-07-27 Francis Kung <fkung@redhat.com>classpath-0_92-branch-point
* gnu/java/awt/java2d/CubicSegment.java: Added import. (cp1): Renamed from first(). (c2): Renamed from last(). (first): Renamed to cp1(). (getDisplacedSegments): Implemented. (last): Renamed to cp2(). * gnu/java/awt/java2d/LineSegment.java (cp1): Renamed from first(). (c2): Renamed from last(). (first): Renamed to cp1(). (last): Renamed to cp2(). * gnu/java/awt/java2d/QuadSegment.java (cp1): Renamed from first(). (c2): Renamed from last(). (first): Renamed to cp1(). (last): Renamed to cp2(). * gnu/java/awt/java2d/Segment.java: Added comments. (first): New field. (Segment): Keep track of first element in list. (add): Update first & last element variables. (cp1): Renamed from first(). (c2): Renamed from last(). (first()): Renamed to cp1() to reduce ambiguity. (last()): Renamed to cp2() to reduce ambiguity. (reverseAll): Update first element variable.. * gnu/java/awt/peer/gtk/CairoGraphics2D.java (draw): Remove flattening path iterator. * java/awt/BasicStroke.java: Clarified comments. (addSegments): Refactored some code into joinSegments and joinInnerSegments. (capEnd): Rename of Segment.first() and Segment.end(). (joinInnerSegments): New method. (joinOuterSegments): New method. (joinSegments): Refactored some code into joinOuterSegments. (solidStroke): Connect segments together properly.
-rw-r--r--ChangeLog38
-rw-r--r--gnu/java/awt/java2d/CubicSegment.java78
-rw-r--r--gnu/java/awt/java2d/LineSegment.java4
-rw-r--r--gnu/java/awt/java2d/QuadSegment.java4
-rw-r--r--gnu/java/awt/java2d/Segment.java37
-rw-r--r--gnu/java/awt/peer/gtk/CairoGraphics2D.java19
-rw-r--r--java/awt/BasicStroke.java120
7 files changed, 205 insertions, 95 deletions
diff --git a/ChangeLog b/ChangeLog
index 740ecd896..71b390299 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2006-07-27 Francis Kung <fkung@redhat.com>
+
+ * gnu/java/awt/java2d/CubicSegment.java: Added import.
+ (cp1): Renamed from first().
+ (c2): Renamed from last().
+ (first): Renamed to cp1().
+ (getDisplacedSegments): Implemented.
+ (last): Renamed to cp2().
+ * gnu/java/awt/java2d/LineSegment.java
+ (cp1): Renamed from first().
+ (c2): Renamed from last().
+ (first): Renamed to cp1().
+ (last): Renamed to cp2().
+ * gnu/java/awt/java2d/QuadSegment.java
+ (cp1): Renamed from first().
+ (c2): Renamed from last().
+ (first): Renamed to cp1().
+ (last): Renamed to cp2().
+ * gnu/java/awt/java2d/Segment.java: Added comments.
+ (first): New field.
+ (Segment): Keep track of first element in list.
+ (add): Update first & last element variables.
+ (cp1): Renamed from first().
+ (c2): Renamed from last().
+ (first()): Renamed to cp1() to reduce ambiguity.
+ (last()): Renamed to cp2() to reduce ambiguity.
+ (reverseAll): Update first element variable..
+ * gnu/java/awt/peer/gtk/CairoGraphics2D.java
+ (draw): Remove flattening path iterator.
+ * java/awt/BasicStroke.java: Clarified comments.
+ (addSegments): Refactored some code into joinSegments and
+ joinInnerSegments.
+ (capEnd): Rename of Segment.first() and Segment.end().
+ (joinInnerSegments): New method.
+ (joinOuterSegments): New method.
+ (joinSegments): Refactored some code into joinOuterSegments.
+ (solidStroke): Connect segments together properly.
+
2006-07-27 Tom Tromey <tromey@redhat.com>
PR classpath/28486:
diff --git a/gnu/java/awt/java2d/CubicSegment.java b/gnu/java/awt/java2d/CubicSegment.java
index 7d169b78e..bf66be870 100644
--- a/gnu/java/awt/java2d/CubicSegment.java
+++ b/gnu/java/awt/java2d/CubicSegment.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package gnu.java.awt.java2d;
+import java.awt.geom.CubicCurve2D;
import java.awt.geom.Point2D;
/**
@@ -100,28 +101,67 @@ public class CubicSegment extends Segment
}
/**
- * Get the "top" and "bottom" segments of this segment.
- * First array element is p0 + normal, second is p0 - normal.
+ * Get the "top" and "bottom" segments of this segment. First array element is
+ * p0 + normal, second is p0 - normal.
*/
public Segment[] getDisplacedSegments(double radius)
{
+ // It is, apparently, impossible to derive a curve parallel to a bezier
+ // curve (unless it's a straight line), so we have no choice but to
+ // approximate the displaced segments. Similar to FlattenPathIterator.
+
+ Segment segmentTop = null;
+ Segment segmentBottom = null;
this.radius = radius;
- double x0 = P1.getX();
- double y0 = P1.getY();
- double x1 = cp1.getX();
- double y1 = cp1.getY();
- double x2 = cp2.getX();
- double y2 = cp2.getY();
- double x3 = P2.getX();
- double y3 = P2.getY();
- double[] p1 = normal(x0, y0, x1, y1);
- double[] p2 = normal(x2, y2, x3, y3);
-
- // FIXME: Doesn't compile.
- // return new Segment[]{s1, s2};
- return new Segment[0];
- }
+ CubicCurve2D[] curves = new CubicCurve2D[10];
+ curves[0] = new CubicCurve2D.Double(P1.getX(), P1.getY(), cp1.getX(),
+ cp1.getY(), cp2.getX(), cp2.getY(),
+ P2.getX(), P2.getY());
+ int numCurves = 1;
+
+ // Hard-coded a recursion limit of 10 and flatness of 1... should we make
+ // this an option somewhere?
+ while (numCurves > 0)
+ {
+ // The curve is flat enough, or we've reached our recursion limit,
+ // so take the current start/end points and add it as a line segment
+ // to our final approximated curves
+ if (curves[numCurves - 1].getFlatnessSq() <= (radius / 3) || numCurves == 10)
+ {
+ Segment[] displaced = new LineSegment(
+ curves[numCurves - 1].getP1(),
+ curves[numCurves - 1].getP2()).getDisplacedSegments(radius);
+ if (segmentTop == null)
+ {
+ segmentTop = displaced[0];
+ segmentBottom = displaced[1];
+ }
+ else
+ {
+ segmentTop.add(displaced[0]);
+ segmentBottom.add(displaced[1]);
+ }
+ numCurves--;
+ }
+
+ // Otherwise, subdivide again and continue
+ else
+ {
+ CubicCurve2D left = new CubicCurve2D.Double();
+ CubicCurve2D right = new CubicCurve2D.Double();
+ curves[numCurves - 1].subdivide(left, right);
+ curves[numCurves - 1] = right;
+ curves[numCurves] = left;
+ curves[numCurves - 1] = right;
+ curves[numCurves] = left;
+ numCurves++;
+ }
+ }
+
+ return new Segment[] { segmentTop, segmentBottom };
+ }
+
public void reverse()
{
Point2D temp = P1;
@@ -132,12 +172,12 @@ public class CubicSegment extends Segment
cp2 = temp;
}
- public double[] first()
+ public double[] cp1()
{
return new double[]{cp1.getX(), cp1.getY()};
}
- public double[] last()
+ public double[] cp2()
{
return new double[]{cp2.getX(), cp2.getY()};
}
diff --git a/gnu/java/awt/java2d/LineSegment.java b/gnu/java/awt/java2d/LineSegment.java
index 4a34aa563..0395fd0af 100644
--- a/gnu/java/awt/java2d/LineSegment.java
+++ b/gnu/java/awt/java2d/LineSegment.java
@@ -106,12 +106,12 @@ public class LineSegment extends Segment
P2 = p;
}
- public double[] first()
+ public double[] cp1()
{
return new double[]{P2.getX(), P2.getY()};
}
- public double[] last()
+ public double[] cp2()
{
return new double[]{P1.getX(), P1.getY()};
}
diff --git a/gnu/java/awt/java2d/QuadSegment.java b/gnu/java/awt/java2d/QuadSegment.java
index c76804840..5e15fe881 100644
--- a/gnu/java/awt/java2d/QuadSegment.java
+++ b/gnu/java/awt/java2d/QuadSegment.java
@@ -217,12 +217,12 @@ public class QuadSegment extends Segment
P2 = p;
}
- public double[] first()
+ public double[] cp1()
{
return new double[]{cp.getX(), cp.getY()};
}
- public double[] last()
+ public double[] cp2()
{
return new double[]{cp.getX(), cp.getY()};
}
diff --git a/gnu/java/awt/java2d/Segment.java b/gnu/java/awt/java2d/Segment.java
index 9a985f696..df1f67605 100644
--- a/gnu/java/awt/java2d/Segment.java
+++ b/gnu/java/awt/java2d/Segment.java
@@ -42,24 +42,38 @@ import java.awt.geom.Point2D;
public abstract class Segment implements Cloneable
{
- // segment type, PathIterator segment types are used.
+ // Start and end points of THIS segment
public Point2D P1;
public Point2D P2;
+
+ // Segments can be linked together internally as a linked list
+ public Segment first;
public Segment next;
public Segment last;
+
+ // Half the stroke width
protected double radius;
+ /**
+ * Create a new, empty segment
+ */
public Segment()
{
P1 = P2 = null;
+ first = this;
next = null;
last = this;
}
+ /**
+ * Add a segment to the polygon
+ * @param newsegment segment to add
+ */
public void add(Segment newsegment)
{
+ newsegment.first = first;
last.next = newsegment;
- last = last.next;
+ last = last.next.last;
}
/**
@@ -68,6 +82,7 @@ public abstract class Segment implements Cloneable
public void reverseAll()
{
reverse();
+ first = last;
Segment v = next;
Segment former = this;
next = null;
@@ -91,7 +106,7 @@ public abstract class Segment implements Cloneable
/**
* Get the normal vector to the slope of the line.
- * Returns: 0.5*width*(norm of derivative of the (x0,y0)-(x1,y1) vector)
+ * @return vector of length radius, normal to the (x0,y0)-(x1,y1) vector)
*/
protected double[] normal(double x0, double y0, double x1, double y1)
{
@@ -117,6 +132,9 @@ public abstract class Segment implements Cloneable
return new double[]{ dx, dy };
}
+ /**
+ * Reverse the current segment
+ */
public abstract void reverse();
/**
@@ -125,7 +143,16 @@ public abstract class Segment implements Cloneable
*/
public abstract Segment[] getDisplacedSegments(double radius);
- public abstract double[] first();
- public abstract double[] last();
+ /**
+ * Returns the coordinates of the first control point, or the start point
+ * for a line segment.
+ */
+ public abstract double[] cp1();
+
+ /**
+ * Returns the coordinates of the second control point, or the end point
+ * for a line segment.
+ */
+ public abstract double[] cp2();
}
diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index 158965c76..e264300c5 100644
--- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -921,21 +921,12 @@ public abstract class CairoGraphics2D extends Graphics2D
public void draw(Shape s)
{
if ((stroke != null && ! (stroke instanceof BasicStroke))
- || (comp instanceof AlphaComposite
- && ((AlphaComposite) comp).getAlpha() != 1.0))
+ || (comp instanceof AlphaComposite && ((AlphaComposite) comp).getAlpha() != 1.0))
{
- // FIXME: This is a hack to work around BasicStrokes's current
- // limitations wrt cubic curves.
- // See CubicSegment.getDisplacedSegments().
- if (stroke instanceof BasicStroke)
- {
- PathIterator flatten = s.getPathIterator(null, 1.0);
- GeneralPath p = new GeneralPath();
- p.append(flatten, false);
- s = p;
- }
- fill(stroke.createStrokedShape(s));
- return;
+ // Cairo doesn't support stroking with alpha, so we create the stroked
+ // shape and fill with alpha instead
+ fill(stroke.createStrokedShape(s));
+ return;
}
createPath(s);
diff --git a/java/awt/BasicStroke.java b/java/awt/BasicStroke.java
index a7e958890..160a3eb0f 100644
--- a/java/awt/BasicStroke.java
+++ b/java/awt/BasicStroke.java
@@ -117,6 +117,7 @@ public class BasicStroke implements Stroke
/** The dash phase. */
private final float phase;
+ // The inner and outer paths of the stroke
private Segment start, end;
/**
@@ -434,8 +435,8 @@ public class BasicStroke implements Stroke
else
addSegments(p);
- x = coords[0];
- y = coords[1];
+ x = coords[2];
+ y = coords[3];
break;
case PathIterator.SEG_CUBICTO:
@@ -451,17 +452,25 @@ public class BasicStroke implements Stroke
else
addSegments(p);
- x = coords[0];
- y = coords[1];
+ x = coords[4];
+ y = coords[5];
break;
case PathIterator.SEG_CLOSE:
- p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width/2.0);
- addSegments(p);
+ if (x == x0 && y == y0)
+ {
+ joinSegments(new Segment[] { start.first, end.first });
+ }
+ else
+ {
+ p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width / 2.0);
+ addSegments(p);
+ }
convertPath(output, start);
convertPath(output, end);
start = end = null;
pathOpen = false;
+ output.setWindingRule(GeneralPath.WIND_EVEN_ODD);
break;
}
pi.next();
@@ -498,7 +507,7 @@ public class BasicStroke implements Stroke
}
/**
- * Convert and add the linked list of Segments in s to a GeneralPath p.
+ * Append the Segments in s to the GeneralPath p
*/
private void convertPath(GeneralPath p, Segment s)
{
@@ -526,18 +535,28 @@ public class BasicStroke implements Stroke
p.closePath();
}
-
+
/**
- * Add to segments to start and end, joining the outer pair and
+ * Add the segments to start and end (the inner and outer edges of the stroke)
*/
private void addSegments(Segment[] segments)
{
- double[] p0 = start.last.last();
+ joinSegments(segments);
+ start.add(segments[0]);
+ end.add(segments[1]);
+ }
+
+ private void joinSegments(Segment[] segments)
+ {
+ double[] p0 = start.last.cp2();
double[] p1 = new double[]{start.last.P2.getX(), start.last.P2.getY()};
- double[] p2 = new double[]{segments[0].P1.getX(), segments[0].P1.getY()};
- double[] p3 = segments[0].first();
+ double[] p2 = new double[]{segments[0].first.P1.getX(), segments[0].first.P1.getY()};
+ double[] p3 = segments[0].cp1();
Point2D p;
+ p = lineIntersection(p0[0],p0[1],p1[0],p1[1],
+ p2[0],p2[1],p3[0],p3[1], false);
+
double det = (p1[0] - p0[0])*(p3[1] - p2[1]) -
(p3[0] - p2[0])*(p1[1] - p0[1]);
@@ -545,42 +564,14 @@ public class BasicStroke implements Stroke
{
// start and segment[0] form the 'inner' part of a join,
// connect the overlapping segments
- p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], false);
- if( p == null )
- {
- // Dodgy.
- start.add(new LineSegment(start.last.P2, segments[0].P1));
- p = new Point2D.Double((segments[0].P1.getX()+ start.last.P2.getX())/2.0,
- (segments[0].P1.getY()+ start.last.P2.getY())/2.0);
- }
- else
- segments[0].P1 = start.last.P2 = p;
-
- start.add( segments[0] );
- joinSegments(end, segments[1], p);
+ joinInnerSegments(start, segments[0], p);
+ joinOuterSegments(end, segments[1], p);
}
else
{
// end and segment[1] form the 'inner' part
- p0 = end.last.last();
- p1 = new double[]{end.last.P2.getX(), end.last.P2.getY()};
- p2 = new double[]{segments[1].P1.getX(), segments[1].P1.getY()};
- p3 = segments[1].first();
-
- p = lineIntersection(p0[0],p0[1],p1[0],p1[1],
- p2[0],p2[1],p3[0],p3[1], false);
- if( p == null )
- {
- // Dodgy.
- end.add(new LineSegment(end.last.P2, segments[1].P1));
- p = new Point2D.Double((segments[1].P1.getX()+ end.last.P2.getX())/2.0,
- (segments[1].P1.getY()+ end.last.P2.getY())/2.0);
- }
- else
- segments[1].P1 = end.last.P2 = p;
-
- end.add( segments[1] );
- joinSegments(start, segments[0], p);
+ joinInnerSegments(end, segments[1], p);
+ joinOuterSegments(start, segments[0], p);
}
}
@@ -601,7 +592,7 @@ public class BasicStroke implements Stroke
break;
case CAP_SQUARE:
- p0 = a.last.last();
+ p0 = a.last.cp2();
p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()};
dx = p1[0] - p0[0];
dy = p1[1] - p0[1];
@@ -616,7 +607,7 @@ public class BasicStroke implements Stroke
break;
case CAP_ROUND:
- p0 = a.last.last();
+ p0 = a.last.cp2();
p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()};
dx = p1[0] - p0[0];
dy = p1[1] - p0[1];
@@ -675,7 +666,7 @@ public class BasicStroke implements Stroke
* insideP is the inside intersection point of the join, needed for
* calculating miter lengths.
*/
- private void joinSegments(Segment a, Segment b, Point2D insideP)
+ private void joinOuterSegments(Segment a, Segment b, Point2D insideP)
{
double[] p0, p1;
double dx, dy, l;
@@ -684,10 +675,10 @@ public class BasicStroke implements Stroke
switch( join )
{
case JOIN_MITER:
- p0 = a.last.last();
+ p0 = a.last.cp2();
p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()};
double[] p2 = new double[]{b.P1.getX(), b.P1.getY()};
- double[] p3 = b.first();
+ double[] p3 = b.cp1();
Point2D p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], true);
if( p == null || insideP == null )
a.add(new LineSegment(a.last.P2, b.P1));
@@ -704,7 +695,7 @@ public class BasicStroke implements Stroke
break;
case JOIN_ROUND:
- p0 = a.last.last();
+ p0 = a.last.cp2();
p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()};
dx = p1[0] - p0[0];
dy = p1[1] - p0[1];
@@ -714,7 +705,7 @@ public class BasicStroke implements Stroke
c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy);
p0 = new double[]{b.P1.getX(), b.P1.getY()};
- p1 = b.first();
+ p1 = b.cp1();
dx = p0[0] - p1[0]; // backwards direction.
dy = p0[1] - p1[1];
@@ -729,6 +720,29 @@ public class BasicStroke implements Stroke
a.add(new LineSegment(a.last.P2, b.P1));
break;
}
- a.add(b);
}
-}
+
+ /**
+ * Join a and b segments, removing any overlap
+ */
+ private void joinInnerSegments(Segment a, Segment b, Point2D p)
+ {
+ double[] p0 = a.last.cp2();
+ double[] p1 = new double[] { a.last.P2.getX(), a.last.P2.getY() };
+ double[] p2 = new double[] { b.P1.getX(), b.P1.getY() };
+ double[] p3 = b.cp1();
+
+ if (p == null)
+ {
+ // Dodgy.
+ a.add(new LineSegment(a.last.P2, b.P1));
+ p = new Point2D.Double((b.P1.getX() + a.last.P2.getX()) / 2.0,
+ (b.P1.getY() + a.last.P2.getY()) / 2.0);
+ }
+ else
+ // This assumes segments a and b are single segments, which is
+ // incorrect - if they are a linked list of segments (ie, passed in
+ // from a flattening operation), this produces strange results!!
+ a.last.P2 = b.P1 = p;
+ }
+}