Bug 1209525 - Protect GetGeometryBounds from a singular non-scaling-stroke transform. r=longsonr, a=lizzard
authorTom Klein <twointofive@gmail.com>
Wed, 30 Sep 2015 08:05:00 +0200
changeset 296266 d90ef52f0c349985729fc78fe372e5fb36a64000
parent 296265 5ca76d2f53b67c4d361f2a4fc5e9cd62b417e4d6
child 296267 9dfec714d1dfdddbccc0a86cbf00a8caf90b0efc
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr, lizzard
bugs1209525
milestone43.0a2
Bug 1209525 - Protect GetGeometryBounds from a singular non-scaling-stroke transform. r=longsonr, a=lizzard
dom/svg/SVGCircleElement.cpp
dom/svg/SVGEllipseElement.cpp
dom/svg/SVGLineElement.cpp
dom/svg/SVGRectElement.cpp
dom/svg/nsSVGPathGeometryElement.h
layout/svg/crashtests/1209525-1.svg
layout/svg/crashtests/crashtests.list
layout/svg/nsSVGPathGeometryFrame.cpp
--- a/dom/svg/SVGCircleElement.cpp
+++ b/dom/svg/SVGCircleElement.cpp
@@ -98,16 +98,17 @@ SVGCircleElement::GetGeometryBounds(Rect
   }
 
   if (aToBoundsSpace.IsRectilinear()) {
     // Optimize the case where we can treat the circle as a rectangle and
     // still get tight bounds.
     if (aStrokeOptions.mLineWidth > 0.f) {
       if (aToNonScalingStrokeSpace) {
         if (aToNonScalingStrokeSpace->IsRectilinear()) {
+          MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
           Rect userBounds(x - r, y - r, 2 * r, 2 * r);
           SVGContentUtils::RectilinearGetStrokeBounds(
             userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
             aStrokeOptions.mLineWidth, aBounds);
           return true;
         }
         return false;
       }
--- a/dom/svg/SVGEllipseElement.cpp
+++ b/dom/svg/SVGEllipseElement.cpp
@@ -109,16 +109,17 @@ SVGEllipseElement::GetGeometryBounds(Rec
   }
 
   if (aToBoundsSpace.IsRectilinear()) {
     // Optimize the case where we can treat the ellipse as a rectangle and
     // still get tight bounds.
     if (aStrokeOptions.mLineWidth > 0.f) {
       if (aToNonScalingStrokeSpace) {
         if (aToNonScalingStrokeSpace->IsRectilinear()) {
+          MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
           Rect userBounds(x - rx, y - ry, 2 * rx, 2 * ry);
           SVGContentUtils::RectilinearGetStrokeBounds(
             userBounds, aToBoundsSpace, *aToNonScalingStrokeSpace,
             aStrokeOptions.mLineWidth, aBounds);
           return true;
         }
         return false;
       }
--- a/dom/svg/SVGLineElement.cpp
+++ b/dom/svg/SVGLineElement.cpp
@@ -161,16 +161,17 @@ SVGLineElement::GetGeometryBounds(Rect* 
     aBounds->ExpandToEnclose(aToBoundsSpace * Point(x2, y2));
     return true;
   }
 
   // transform from non-scaling-stroke space to the space in which we compute
   // bounds
   Matrix nonScalingToBounds;
   if (aToNonScalingStrokeSpace) {
+    MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
     Matrix nonScalingToUser = aToNonScalingStrokeSpace->Inverse();
     nonScalingToBounds = nonScalingToUser * aToBoundsSpace;
   }
 
   if (aStrokeOptions.mLineCap == CapStyle::ROUND) {
     if (!aToBoundsSpace.IsRectilinear() ||
         (aToNonScalingStrokeSpace &&
          !aToNonScalingStrokeSpace->IsRectilinear())) {
--- a/dom/svg/SVGRectElement.cpp
+++ b/dom/svg/SVGRectElement.cpp
@@ -138,16 +138,17 @@ SVGRectElement::GetGeometryBounds(Rect* 
     if (rx != 0 || ry != 0) {
       return false;
     }
   }
 
   if (aStrokeOptions.mLineWidth > 0.f) {
     if (aToNonScalingStrokeSpace) {
       if (aToNonScalingStrokeSpace->IsRectilinear()) {
+        MOZ_ASSERT(!aToNonScalingStrokeSpace->IsSingular());
         rect = aToNonScalingStrokeSpace->TransformBounds(rect);
         // Note that, in principle, an author could cause the corners of the
         // rect to be beveled by specifying stroke-linejoin or setting
         // stroke-miterlimit to be less than sqrt(2). In that very unlikely
         // event the bounds that we calculate here may be too big if
         // aToBoundsSpace is non-rectilinear. This is likely to be so rare it's
         // not worth handling though.
         rect.Inflate(aStrokeOptions.mLineWidth / 2.f);
--- a/dom/svg/nsSVGPathGeometryElement.h
+++ b/dom/svg/nsSVGPathGeometryElement.h
@@ -79,16 +79,19 @@ public:
    *
    * If |aToNonScalingStrokeSpace| is non-null then |aBounds|, which is computed
    * in bounds space, has the property that it's the smallest (axis-aligned)
    * rectangular bound containing the image of this shape as stroked in
    * non-scaling-stroke space.  (When all transforms involved are rectilinear
    * the bounds of the image of |aBounds| in non-scaling-stroke space will be
    * tight, but if there are non-rectilinear transforms involved then that may
    * be impossible and this method will return false).
+   *
+   * If |aToNonScalingStrokeSpace| is non-null then |*aToNonScalingStrokeSpace|
+   * must be non-singular.
    */
   virtual bool GetGeometryBounds(Rect* aBounds, const StrokeOptions& aStrokeOptions,
                                  const Matrix& aToBoundsSpace,
                                  const Matrix* aToNonScalingStrokeSpace = nullptr) {
     return false;
   }
 
   /**
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/1209525-1.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     width="0" height="0">
+
+  <rect width="10" height="10" stroke="black"
+        vector-effect="non-scaling-stroke" />
+
+</svg>
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -186,8 +186,9 @@ load 974746-1.svg
 load 979407-1.svg
 load 979407-2.svg
 load 993443.svg
 load 1016145.svg
 load 1028512.svg
 load 1140080-1.svg
 load 1149542-1.svg
 load 1182496-1.html
+load 1209525-1.svg
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -482,16 +482,19 @@ nsSVGPathGeometryFrame::GetBBoxContribut
   }
 
   Rect simpleBounds;
   bool gotSimpleBounds = false;
   gfxMatrix userToOuterSVG;
   if (getStroke &&
       nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
     Matrix moz2dUserToOuterSVG = ToMatrix(userToOuterSVG);
+    if (moz2dUserToOuterSVG.IsSingular()) {
+      return bbox;
+    }
     gotSimpleBounds = element->GetGeometryBounds(&simpleBounds,
                                                  strokeOptions,
                                                  aToBBoxUserspace,
                                                  &moz2dUserToOuterSVG);
   } else {
     gotSimpleBounds = element->GetGeometryBounds(&simpleBounds,
                                                  strokeOptions,
                                                  aToBBoxUserspace);