src/share/classes/sun/java2d/pisces/Dasher.java

Print this page

        

@@ -179,37 +179,41 @@
         this.x0 = x1;
         this.y0 = y1;
     }
 
     public void lineTo(int x1, int y1) {
+        long MAX = java.lang.Integer.MAX_VALUE;
+        long MIN = java.lang.Integer.MIN_VALUE;
         while (true) {
+            // We use longs in this method to avoid overflows.
+
             int d = dash[idx] - phase;
-            int lx = x1 - x0;
-            int ly = y1 - y0;
+            long xLen = (long)x1 - x0;
+            long yLen = (long)y1 - y0;
 
             // Compute segment length in the untransformed
             // coordinate system
             // IMPL NOTE - use fixed point
 
-            int l;
+            long origLen;
             if (symmetric) {
-                l = (int)((PiscesMath.hypot(lx, ly)*65536L)/ldet);
+                origLen = (int)((PiscesMath.hypot(xLen, yLen)*65536L)/ldet);
             } else{
-                long la = ((long)ly*m00 - (long)lx*m10)/ldet;
-                long lb = ((long)ly*m01 - (long)lx*m11)/ldet;
-                l = (int)PiscesMath.hypot(la, lb);
+                long origXLen = (m11*xLen - m01*yLen)/ldet;
+                long origYLen = (m00*yLen - m10*xLen)/ldet;
+                origLen = PiscesMath.hypot(origXLen, origYLen);
             }
 
-            if (l < d) {
+            if (origLen < d) {
                 goTo(x1, y1);
                 // Advance phase within current dash segment
-                phase += l;
+                phase += origLen;
                 return;
             }
 
-            long t;
-            int xsplit, ysplit;
+            long t; // the ratio (olddash/oldlinelength) * 2^16
+            long xsplit, ysplit;
 //             // For zero length dashses, SE appears to move 1/8 unit
 //             // in device space
 //             if (d == 0) {
 //                 double dlx = lx/65536.0;
 //                 double dly = ly/65536.0;

@@ -218,15 +222,30 @@
 //                 double dxsplit = (x0/65536.0) + dt*dlx;
 //                 double dysplit = (y0/65536.0) + dt*dly;
 //                 xsplit = (int)(dxsplit*65536.0);
 //                 ysplit = (int)(dysplit*65536.0);
 //             } else {
-                t = ((long)d << 16)/l;
-                xsplit = x0 + (int)(t*(x1 - x0) >> 16);
-                ysplit = y0 + (int)(t*(y1 - y0) >> 16);
+            t = ((long)d << 16)/origLen;
+            xsplit = x0 + (t * xLen >> 16);
+            ysplit = y0 + (t * yLen >> 16);
 //             }
-            goTo(xsplit, ysplit);
+
+            // If java math had infinite precision, xsplit and ysplit would
+            // be guaranteed never to go outside of the range [MIN, MAX], but
+            // it isn't, and an overflow here would be hard to diagnose, so 
+            // the efficiency trade off is worth it.
+            // Note: I have not proven mathematicaly there there is, indeed,
+            // some input that could would overflow here, so it might be
+            // nice to try to prove that overflow is impossible. If it is,
+            // the next 6 lines can be eliminated.
+            if (xsplit > MAX || xsplit < MIN) {
+                xsplit = (xsplit > MAX) ? MAX : MIN;
+            }
+            if (ysplit > MAX || ysplit < MIN) {
+                ysplit = (ysplit > MAX) ? MAX : MIN;
+            }
+            goTo((int)xsplit, (int)ysplit);
 
             // Advance to next dash segment
             idx = (idx + 1) % dash.length;
             dashOn = !dashOn;
             phase = 0;