Bug 610594 - "ABORT: F.6.6.3 should prevent this. Will sqrt(-num)!". r=longsonr, a=blocking
authorJonathan Watt <jwatt@jwatt.org>
Mon, 03 Jan 2011 09:26:28 +0000
changeset 59784 6a8cca708a48039ffcf110c3f32dbf7707b4aa23
parent 59783 c20f34eefa5dbe69a12d310b202b47761d6fcb58
child 59785 1c414527a96bdfd2bebe14a8ee6f5048e03d24e1
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewerslongsonr, blocking
bugs610594
milestone2.0b9pre
Bug 610594 - "ABORT: F.6.6.3 should prevent this. Will sqrt(-num)!". r=longsonr, a=blocking
content/svg/content/src/SVGPathData.cpp
layout/svg/crashtests/610594-1.html
layout/svg/crashtests/crashtests.list
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -549,19 +549,19 @@ SVGPathData::GetMarkerPositioningData(ns
       segEndAngle = AngleOfVector(segEnd - cp1);
       i += 4;
       break;
     }
 
     case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
     case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
     {
-      float rx = mData[i];
-      float ry = mData[i+1];
-      float angle = mData[i+2];
+      double rx = mData[i];
+      double ry = mData[i+1];
+      double angle = mData[i+2];
       PRBool largeArcFlag = mData[i+3] != 0.0f;
       PRBool sweepFlag = mData[i+4] != 0.0f;
       if (segType == nsIDOMSVGPathSeg::PATHSEG_ARC_ABS) {
         segEnd = gfxPoint(mData[i+5], mData[i+6]);
       } else {
         segEnd = segStart + gfxPoint(mData[i+5], mData[i+6]);
       }
 
@@ -590,56 +590,57 @@ SVGPathData::GetMarkerPositioningData(ns
         i += 7;
         break;
       }
       rx = fabs(rx); // F.6.6.1
       ry = fabs(ry);
 
       // F.6.5.1:
       angle = angle * M_PI/180.0;
-      float x1p = cos(angle) * (segStart.x - segEnd.x) / 2.0
-                + sin(angle) * (segStart.y - segEnd.y) / 2.0;
-      float y1p = -sin(angle) * (segStart.x - segEnd.x) / 2.0
-                 + cos(angle)  *(segStart.y - segEnd.y) / 2.0;
+      double x1p =  cos(angle) * (segStart.x - segEnd.x) / 2.0
+                  + sin(angle) * (segStart.y - segEnd.y) / 2.0;
+      double y1p = -sin(angle) * (segStart.x - segEnd.x) / 2.0
+                  + cos(angle) * (segStart.y - segEnd.y) / 2.0;
 
       // This is the root in F.6.5.2 and the numerator under that root:
-      float root;
-      float numerator = rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p;
+      double root;
+      double numerator = rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p;
 
-      if (numerator < 0.0) {
-        // F.6.6 step 3 - |numerator < 0.0| is equivalent to the result of
-        // F.6.6.2 (lamedh) being greater than one. What we have here is radii
-        // that do not reach between segStart and segEnd, so we need to correct
-        // them.
-        float lamedh = 1.0 - numerator/(rx*rx*ry*ry); // equiv to eqn F.6.6.2
-        float s = sqrt(lamedh);
+      if (numerator >= 0.0) {
+        root = sqrt(numerator/(rx*rx*y1p*y1p + ry*ry*x1p*x1p));
+        if (largeArcFlag == sweepFlag)
+          root = -root;
+      } else {
+        // F.6.6 step 3 - |numerator < 0.0|. This is equivalent to the result
+        // of F.6.6.2 (lamedh) being greater than one. What we have here is
+        // ellipse radii that are too small for the ellipse to reach between
+        // segStart and segEnd. We scale the radii up uniformly so that the
+        // ellipse is just big enough to fit (i.e. to the point where there is
+        // exactly one solution).
+
+        double lamedh = 1.0 - numerator/(rx*rx*ry*ry); // equiv to eqn F.6.6.2
+        double s = sqrt(lamedh);
         rx *= s;  // F.6.6.3
         ry *= s;
-        // rx and ry changed, so we have to recompute numerator
-        numerator = rx*rx*ry*ry - rx*rx*y1p*y1p - ry*ry*x1p*x1p;
-        NS_ABORT_IF_FALSE(numerator >= 0,
-                          "F.6.6.3 should prevent this. Will sqrt(-num)!");
+        root = 0.0;
       }
-      root = sqrt(numerator/(rx*rx*y1p*y1p + ry*ry*x1p*x1p));
-      if (largeArcFlag == sweepFlag)
-        root = -root;
+
+      double cxp =  root * rx * y1p / ry;  // F.6.5.2
+      double cyp = -root * ry * x1p / rx;
 
-      float cxp =  root * rx * y1p / ry;  // F.6.5.2
-      float cyp = -root * ry * x1p / rx;
-
-      float theta, delta;
-      theta = CalcVectorAngle(1.0, 0.0,  (x1p-cxp)/rx, (y1p-cyp)/ry); // F.6.5.5
-      delta  = CalcVectorAngle((x1p-cxp)/rx, (y1p-cyp)/ry,
-                               (-x1p-cxp)/rx, (-y1p-cyp)/ry);         // F.6.5.6
+      double theta, delta;
+      theta = CalcVectorAngle(1.0, 0.0, (x1p-cxp)/rx, (y1p-cyp)/ry); // F.6.5.5
+      delta = CalcVectorAngle((x1p-cxp)/rx, (y1p-cyp)/ry,
+                              (-x1p-cxp)/rx, (-y1p-cyp)/ry);         // F.6.5.6
       if (!sweepFlag && delta > 0)
         delta -= 2.0 * M_PI;
       else if (sweepFlag && delta < 0)
         delta += 2.0 * M_PI;
 
-      float tx1, ty1, tx2, ty2;
+      double tx1, ty1, tx2, ty2;
       tx1 = -cos(angle)*rx*sin(theta) - sin(angle)*ry*cos(theta);
       ty1 = -sin(angle)*rx*sin(theta) + cos(angle)*ry*cos(theta);
       tx2 = -cos(angle)*rx*sin(theta+delta) - sin(angle)*ry*cos(theta+delta);
       ty2 = -sin(angle)*rx*sin(theta+delta) + cos(angle)*ry*cos(theta+delta);
 
       if (delta < 0.0f) {
         tx1 = -tx1;
         ty1 = -ty1;
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/610594-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<svg><path d="M 0 5 a 2 5 -30 104 -5" marker-mid="url(#q)"></path></svg>
+</body>
+</html>
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -92,12 +92,14 @@ load 522394-1.svg
 load 522394-2.svg
 load 522394-3.svg
 load extref-test-1.xhtml
 load 566216-1.svg
 load 587336-1.html
 load 590291-1.svg
 load 601999-1.html
 load 605626-1.svg
+load 610594-1.html
 load 610954-1.html
 load 612662-1.svg
 load 612662-2.svg
+
 load 621598-1.svg