Merge pull request #27 from bourgesl/master

Marlin-renderer bug fix in the path clipper
diff --git a/src/share/classes/sun/java2d/marlin/DDasher.java b/src/share/classes/sun/java2d/marlin/DDasher.java
index cb1ce79..98d540f 100644
--- a/src/share/classes/sun/java2d/marlin/DDasher.java
+++ b/src/share/classes/sun/java2d/marlin/DDasher.java
@@ -47,6 +47,8 @@
     static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial
     static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT);
 
+    static final double EPS = 1e-6d;
+
     // More than 24 bits of mantissa means we can no longer accurately
     // measure the number of times cycled through the dash array so we
     // punt and override the phase to just be 0 past that point.
@@ -361,7 +363,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -416,13 +418,13 @@
         boolean _dashOn = dashOn;
         double _phase = phase;
 
-        double leftInThisDashSegment, d;
+        double leftInThisDashSegment, rem;
 
         while (true) {
-            d = _dash[_idx];
-            leftInThisDashSegment = d - _phase;
+            leftInThisDashSegment = _dash[_idx] - _phase;
+            rem = len - leftInThisDashSegment;
 
-            if (len <= leftInThisDashSegment) {
+            if (rem <= EPS) {
                 _curCurvepts[0] = x1;
                 _curCurvepts[1] = y1;
 
@@ -431,8 +433,8 @@
                 // Advance phase within current dash segment
                 _phase += len;
 
-                // TODO: compare double values using epsilon:
-                if (len == leftInThisDashSegment) {
+                // compare values using epsilon:
+                if (Math.abs(rem) <= EPS) {
                     _phase = 0.0d;
                     _idx = (_idx + 1) % _dashLen;
                     _dashOn = !_dashOn;
@@ -440,17 +442,12 @@
                 break;
             }
 
-            if (_phase == 0.0d) {
-                _curCurvepts[0] = cx0 + d * cx;
-                _curCurvepts[1] = cy0 + d * cy;
-            } else {
-                _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
-                _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
-            }
+            _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
+            _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
 
             goTo(_curCurvepts, 0, 4, _dashOn);
 
-            len -= leftInThisDashSegment;
+            len = rem;
             // Advance to next dash segment
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -506,18 +503,18 @@
             _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
         }
 
-        double leftInThisDashSegment, d;
+        double leftInThisDashSegment, rem;
 
         while (true) {
-            d = _dash[_idx];
-            leftInThisDashSegment = d - _phase;
+            leftInThisDashSegment = _dash[_idx] - _phase;
+            rem = len - leftInThisDashSegment;
 
-            if (len <= leftInThisDashSegment) {
+            if (rem <= EPS) {
                 // Advance phase within current dash segment
                 _phase += len;
 
-                // TODO: compare double values using epsilon:
-                if (len == leftInThisDashSegment) {
+                // compare values using epsilon:
+                if (Math.abs(rem) <= EPS) {
                     _phase = 0.0d;
                     _idx = (_idx + 1) % _dashLen;
                     _dashOn = !_dashOn;
@@ -525,7 +522,7 @@
                 break;
             }
 
-            len -= leftInThisDashSegment;
+            len = rem;
             // Advance to next dash segment
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -579,7 +576,9 @@
         goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
 
         _phase += _li.lastSegLen();
-        if (_phase >= _dash[_idx]) {
+
+        // compare values using epsilon:
+        if (_phase + EPS >= _dash[_idx]) {
             _phase = 0.0d;
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -938,7 +937,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1024,7 +1023,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
diff --git a/src/share/classes/sun/java2d/marlin/DHelpers.java b/src/share/classes/sun/java2d/marlin/DHelpers.java
index 6136e3f..cb9f944 100644
--- a/src/share/classes/sun/java2d/marlin/DHelpers.java
+++ b/src/share/classes/sun/java2d/marlin/DHelpers.java
@@ -243,7 +243,7 @@
         final double y12 = pts[3] - pts[1];
         // if the curve is already parallel to either axis we gain nothing
         // from rotating it.
-        if ((y12 != 0.0d && x12 != 0.0d)) {
+        if ((y12 != 0.0d) && (x12 != 0.0d)) {
             // we rotate it so that the first vector in the control polygon is
             // parallel to the x-axis. This will ensure that rotated quarter
             // circles won't be subdivided.
diff --git a/src/share/classes/sun/java2d/marlin/DStroker.java b/src/share/classes/sun/java2d/marlin/DStroker.java
index 5fecec8..bd14b8f 100644
--- a/src/share/classes/sun/java2d/marlin/DStroker.java
+++ b/src/share/classes/sun/java2d/marlin/DStroker.java
@@ -540,7 +540,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -634,6 +634,9 @@
         emitReverse();
 
         this.prev = CLOSE;
+        this.cx0 = sx0;
+        this.cy0 = sy0;
+        this.cOutCode = sOutCode;
 
         if (opened) {
             // do not emit close
@@ -668,7 +671,9 @@
         //          i.e. if caps must be drawn or not ?
         // Solution: use the ClosedPathDetector before Stroker to determine
         // if the path is a closed path or not
-        if (!rdrCtx.closedPath) {
+        if (rdrCtx.closedPath) {
+            emitReverse();
+        } else {
             if (outcode == 0) {
                 // current point = end's cap:
                 if (capStyle == CAP_ROUND) {
@@ -693,8 +698,6 @@
                     }
                 }
             }
-        } else {
-            emitReverse();
         }
         emitClose();
     }
@@ -1058,7 +1061,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1206,7 +1209,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
diff --git a/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java
index 353f9de..1766729 100644
--- a/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java
+++ b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java
@@ -530,6 +530,9 @@
 
         private boolean outside = false;
 
+        // The starting point of the path
+        private double sx0, sy0;
+
         // The current point (TODO stupid repeated info)
         private double cx0, cy0;
 
@@ -630,17 +633,26 @@
             finishPath();
 
             out.closePath();
+
+            // back to starting point:
+            this.cOutCode = DHelpers.outcode(sx0, sy0, clipRect);
+            this.cx0 = sx0;
+            this.cy0 = sy0;
         }
 
         @Override
         public void moveTo(final double x0, final double y0) {
             finishPath();
 
-            this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
-            this.outside = false;
             out.moveTo(x0, y0);
+
+            // update starting point:
+            this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
             this.cx0 = x0;
             this.cy0 = y0;
+
+            this.sx0 = x0;
+            this.sy0 = y0;
         }
 
         @Override
@@ -655,7 +667,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -754,7 +766,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -816,7 +828,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1153,13 +1165,13 @@
 
         @Override
         public void moveTo(double x0, double y0) {
-            log("moveTo (" + x0 + ", " + y0 + ')');
+            log("p.moveTo(" + x0 + ", " + y0 + ");");
             out.moveTo(x0, y0);
         }
 
         @Override
         public void lineTo(double x1, double y1) {
-            log("lineTo (" + x1 + ", " + y1 + ')');
+            log("p.lineTo(" + x1 + ", " + y1 + ");");
             out.lineTo(x1, y1);
         }
 
@@ -1168,25 +1180,26 @@
                             double x2, double y2,
                             double x3, double y3)
         {
-            log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ") P3(" + x3 + ", " + y3 + ')');
+            log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2  + ", " + x3 + ", " + y3 + ");");
             out.curveTo(x1, y1, x2, y2, x3, y3);
         }
 
         @Override
-        public void quadTo(double x1, double y1, double x2, double y2) {
-            log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ')');
+        public void quadTo(double x1, double y1,
+                           double x2, double y2) {
+            log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2  + ");");
             out.quadTo(x1, y1, x2, y2);
         }
 
         @Override
         public void closePath() {
-            log("closePath");
+            log("p.closePath();");
             out.closePath();
         }
 
         @Override
         public void pathDone() {
-            log("pathDone");
+            log("p.pathDone();");
             out.pathDone();
         }
 
diff --git a/src/share/classes/sun/java2d/marlin/Dasher.java b/src/share/classes/sun/java2d/marlin/Dasher.java
index c28311b..c69fe09 100644
--- a/src/share/classes/sun/java2d/marlin/Dasher.java
+++ b/src/share/classes/sun/java2d/marlin/Dasher.java
@@ -48,6 +48,8 @@
     static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01
     static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT);
 
+    static final float EPS = 1e-6f;
+
     // More than 24 bits of mantissa means we can no longer accurately
     // measure the number of times cycled through the dash array so we
     // punt and override the phase to just be 0 past that point.
@@ -362,7 +364,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -417,13 +419,13 @@
         boolean _dashOn = dashOn;
         float _phase = phase;
 
-        float leftInThisDashSegment, d;
+        float leftInThisDashSegment, rem;
 
         while (true) {
-            d = _dash[_idx];
-            leftInThisDashSegment = d - _phase;
+            leftInThisDashSegment = _dash[_idx] - _phase;
+            rem = len - leftInThisDashSegment;
 
-            if (len <= leftInThisDashSegment) {
+            if (rem <= EPS) {
                 _curCurvepts[0] = x1;
                 _curCurvepts[1] = y1;
 
@@ -432,8 +434,8 @@
                 // Advance phase within current dash segment
                 _phase += len;
 
-                // TODO: compare float values using epsilon:
-                if (len == leftInThisDashSegment) {
+                // compare values using epsilon:
+                if (Math.abs(rem) <= EPS) {
                     _phase = 0.0f;
                     _idx = (_idx + 1) % _dashLen;
                     _dashOn = !_dashOn;
@@ -441,17 +443,12 @@
                 break;
             }
 
-            if (_phase == 0.0f) {
-                _curCurvepts[0] = cx0 + d * cx;
-                _curCurvepts[1] = cy0 + d * cy;
-            } else {
-                _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
-                _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
-            }
+            _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
+            _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
 
             goTo(_curCurvepts, 0, 4, _dashOn);
 
-            len -= leftInThisDashSegment;
+            len = rem;
             // Advance to next dash segment
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -507,18 +504,18 @@
             _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
         }
 
-        float leftInThisDashSegment, d;
+        float leftInThisDashSegment, rem;
 
         while (true) {
-            d = _dash[_idx];
-            leftInThisDashSegment = d - _phase;
+            leftInThisDashSegment = _dash[_idx] - _phase;
+            rem = len - leftInThisDashSegment;
 
-            if (len <= leftInThisDashSegment) {
+            if (rem <= EPS) {
                 // Advance phase within current dash segment
                 _phase += len;
 
-                // TODO: compare float values using epsilon:
-                if (len == leftInThisDashSegment) {
+                // compare values using epsilon:
+                if (Math.abs(rem) <= EPS) {
                     _phase = 0.0f;
                     _idx = (_idx + 1) % _dashLen;
                     _dashOn = !_dashOn;
@@ -526,7 +523,7 @@
                 break;
             }
 
-            len -= leftInThisDashSegment;
+            len = rem;
             // Advance to next dash segment
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -580,7 +577,9 @@
         goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
 
         _phase += _li.lastSegLen();
-        if (_phase >= _dash[_idx]) {
+
+        // compare values using epsilon:
+        if (_phase + EPS >= _dash[_idx]) {
             _phase = 0.0f;
             _idx = (_idx + 1) % _dashLen;
             _dashOn = !_dashOn;
@@ -939,7 +938,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1025,7 +1024,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
diff --git a/src/share/classes/sun/java2d/marlin/Helpers.java b/src/share/classes/sun/java2d/marlin/Helpers.java
index 513d287..2043ab3 100644
--- a/src/share/classes/sun/java2d/marlin/Helpers.java
+++ b/src/share/classes/sun/java2d/marlin/Helpers.java
@@ -251,7 +251,7 @@
         final float y12 = pts[3] - pts[1];
         // if the curve is already parallel to either axis we gain nothing
         // from rotating it.
-        if ((y12 != 0.0f && x12 != 0.0f)) {
+        if ((y12 != 0.0f) && (x12 != 0.0f)) {
             // we rotate it so that the first vector in the control polygon is
             // parallel to the x-axis. This will ensure that rotated quarter
             // circles won't be subdivided.
diff --git a/src/share/classes/sun/java2d/marlin/Stroker.java b/src/share/classes/sun/java2d/marlin/Stroker.java
index 1e18941..255e0fe 100644
--- a/src/share/classes/sun/java2d/marlin/Stroker.java
+++ b/src/share/classes/sun/java2d/marlin/Stroker.java
@@ -542,7 +542,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -636,6 +636,9 @@
         emitReverse();
 
         this.prev = CLOSE;
+        this.cx0 = sx0;
+        this.cy0 = sy0;
+        this.cOutCode = sOutCode;
 
         if (opened) {
             // do not emit close
@@ -670,7 +673,9 @@
         //          i.e. if caps must be drawn or not ?
         // Solution: use the ClosedPathDetector before Stroker to determine
         // if the path is a closed path or not
-        if (!rdrCtx.closedPath) {
+        if (rdrCtx.closedPath) {
+            emitReverse();
+        } else {
             if (outcode == 0) {
                 // current point = end's cap:
                 if (capStyle == CAP_ROUND) {
@@ -695,8 +700,6 @@
                     }
                 }
             }
-        } else {
-            emitReverse();
         }
         emitClose();
     }
@@ -1060,7 +1063,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1208,7 +1211,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
diff --git a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
index fb4c34f..f8af398 100644
--- a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
+++ b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
@@ -531,6 +531,9 @@
 
         private boolean outside = false;
 
+        // The starting point of the path
+        private float sx0, sy0;
+
         // The current point (TODO stupid repeated info)
         private float cx0, cy0;
 
@@ -631,17 +634,26 @@
             finishPath();
 
             out.closePath();
+
+            // back to starting point:
+            this.cOutCode = Helpers.outcode(sx0, sy0, clipRect);
+            this.cx0 = sx0;
+            this.cy0 = sy0;
         }
 
         @Override
         public void moveTo(final float x0, final float y0) {
             finishPath();
 
-            this.cOutCode = Helpers.outcode(x0, y0, clipRect);
-            this.outside = false;
             out.moveTo(x0, y0);
+
+            // update starting point:
+            this.cOutCode = Helpers.outcode(x0, y0, clipRect);
             this.cx0 = x0;
             this.cy0 = y0;
+
+            this.sx0 = x0;
+            this.sy0 = y0;
         }
 
         @Override
@@ -656,7 +668,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -755,7 +767,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -817,7 +829,7 @@
 
                 // basic rejection criteria:
                 if (sideCode == 0) {
-                    // ovelap clip:
+                    // overlap clip:
                     if (subdivide) {
                         // avoid reentrance
                         subdivide = false;
@@ -1154,13 +1166,13 @@
 
         @Override
         public void moveTo(float x0, float y0) {
-            log("moveTo (" + x0 + ", " + y0 + ')');
+            log("p.moveTo(" + x0 + ", " + y0 + ");");
             out.moveTo(x0, y0);
         }
 
         @Override
         public void lineTo(float x1, float y1) {
-            log("lineTo (" + x1 + ", " + y1 + ')');
+            log("p.lineTo(" + x1 + ", " + y1 + ");");
             out.lineTo(x1, y1);
         }
 
@@ -1169,25 +1181,26 @@
                             float x2, float y2,
                             float x3, float y3)
         {
-            log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ") P3(" + x3 + ", " + y3 + ')');
+            log("p.curveTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2  + ", " + x3 + ", " + y3 + ");");
             out.curveTo(x1, y1, x2, y2, x3, y3);
         }
 
         @Override
-        public void quadTo(float x1, float y1, float x2, float y2) {
-            log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ')');
+        public void quadTo(float x1, float y1,
+                           float x2, float y2) {
+            log("p.quadTo(" + x1 + ", " + y1 + ", " + x2 + ", " + y2  + ");");
             out.quadTo(x1, y1, x2, y2);
         }
 
         @Override
         public void closePath() {
-            log("closePath");
+            log("p.closePath();");
             out.closePath();
         }
 
         @Override
         public void pathDone() {
-            log("pathDone");
+            log("p.pathDone();");
             out.pathDone();
         }
 
diff --git a/src/share/classes/sun/java2d/marlin/Version.java b/src/share/classes/sun/java2d/marlin/Version.java
index 5a6976f..1be4736 100644
--- a/src/share/classes/sun/java2d/marlin/Version.java
+++ b/src/share/classes/sun/java2d/marlin/Version.java
@@ -27,7 +27,7 @@
 
 public final class Version {
 
-    private static final String VERSION = "marlin-0.9.3-Unsafe-OpenJDK";
+    private static final String VERSION = "marlin-0.9.3.1-Unsafe-OpenJDK";
 
     public static String getVersion() {
         return VERSION;