Bug 620468 - Bail out earlier when computing CTM of an <svg> element with negative width/height attributes. r=longsonr
authorCameron McCormack <cam@mcc.id.au>
Sun, 19 Feb 2012 22:17:12 +1100
changeset 87195 94423051f0fd4641e65a34457ae6f0ced6ea509c
parent 87194 e6f6d622d2868ef646aaae2228209f56bf8c9da0
child 87196 d138ca47dbe23532b1161a94e3a604208cab1568
push id551
push userrcampbell@mozilla.com
push dateWed, 22 Feb 2012 16:49:06 +0000
treeherderfx-team@4f425ab85667 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs620468
milestone13.0a1
Bug 620468 - Bail out earlier when computing CTM of an <svg> element with negative width/height attributes. r=longsonr
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/test/getCTM-helper.svg
content/svg/content/test/test_getCTM.html
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -996,16 +996,20 @@ nsSVGSVGElement::GetViewBoxTransform() c
     nsSVGSVGElement *ctx = GetCtx();
     viewportWidth = mLengthAttributes[WIDTH].GetAnimValue(ctx);
     viewportHeight = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
   } else {
     viewportWidth = mViewportWidth;
     viewportHeight = mViewportHeight;
   }
 
+  if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
+    return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
+  }
+
   nsSVGViewBoxRect viewBox;
   if (mViewBox.IsValid()) {
     viewBox = mViewBox.GetAnimValue();
   } else {
     viewBox.x = viewBox.y = 0.0f;
     if (ShouldSynthesizeViewBox()) {
       // Special case -- fake a viewBox, using height & width attrs.
       // (Use |this| as context, since if we get here, we're outermost <svg>.)
--- a/content/svg/content/test/getCTM-helper.svg
+++ b/content/svg/content/test/getCTM-helper.svg
@@ -12,16 +12,19 @@
       <symbol id="sym" width="100" height="100">
         <rect id="symbolRect" width="0" height="0"
               transform="translate(70, 80)"/>
       </symbol>
     </defs>
     <svg id="inner" x="30" y="40" width="100" height="100">
       <g id="g1"/>
     </svg>
+    <svg id="inner-2" viewBox="0 0 10 10" width="-10" height="10">
+      <g id="g5"/>
+    </svg>
     <foreignObject id="fO" x="30" y="40" width="100" height="100" transform="translate(1, 1)">
       <!-- current layout implementation ignores x="50" and y="60".
            thus, I made getCTM and getScreenCTM do the same. -->
       <svg id="outer" x="50" y="60" width="100" height="100">
         <g id="g2" transform="translate(600, 700)"/>
       </svg>
     </foreignObject>
     <!-- something invalid -->
--- a/content/svg/content/test/test_getCTM.html
+++ b/content/svg/content/test/test_getCTM.html
@@ -30,16 +30,17 @@ function runTest()
 
   var root = doc.documentElement;
   var inner = doc.getElementById("inner");
   var g1 = doc.getElementById("g1");
   var outer = doc.getElementById("outer");
   var g2 = doc.getElementById("g2");
   var g3 = doc.getElementById("g3");
   var g4 = doc.getElementById("g4");
+  var g5 = doc.getElementById("g5");
   var sym = doc.getElementById("sym");
   var symbolRect = doc.getElementById("symbolRect");
   var fO = doc.getElementById("fO");
   /* Tests the consistency with nearestViewportElement
      (code is from test_viewport.html) */
   // root.nearestViewportElement == null
   is((function(){try{return root.getCTM()}catch(e){return e}})(), null, "root.getCTM()");
   // inner.nearestViewportElement == root
@@ -56,19 +57,21 @@ function runTest()
   // g3.nearestViewportElement == null
   is((function(){try{return g3.getCTM()}catch(e){return e}})(), null, "g3.getCTM()");
   // g4.nearestViewportElement == null
   is((function(){try{return g4.getCTM().e}catch(e){return e}})(), 1, "g4.getCTM().e");
   is((function(){try{return g4.getCTM().f}catch(e){return e}})(), 2, "g4.getCTM().f");
   // symbolRect.nearestViewportElement == sym
   is((function(){try{return symbolRect.getCTM().e}catch(e){return e}})(), 70, "symbolRect.getCTM().e");
   is((function(){try{return symbolRect.getCTM().f}catch(e){return e}})(), 80, "symbolRect.getCTM().f");
-  // fO.nearestViewportElement = <svg> with no 'id'
+  // fO.nearestViewportElement == <svg> with no 'id'
   is((function(){try{return fO.getCTM().e}catch(e){return e}})(), 2, "fO.getCTM().e");
   is((function(){try{return fO.getCTM().f}catch(e){return e}})(), 3, "fO.getCTM().f");
+  // g5.nearestViewportElement == inner-2 
+  is((function(){try{return g5.getCTM()}catch(e){return e}})(), null, "g5.getCTM()");
 
   /* Tests the consistency with farthestViewportElement
      (code is from test_viewport.html) */
   // root.farthestViewportElement == null (but actually == root)
   is((function(){try{return root.getScreenCTM().e}catch(e){return e}})(), 11, "root.getScreenCTM().e");
   is((function(){try{return root.getScreenCTM().f}catch(e){return e}})(), 22, "root.getScreenCTM().f");
   // inner.farthestViewportElement == root
   is((function(){try{return inner.getScreenCTM().e}catch(e){return e}})(), 45, "inner.getScreenCTM().e");
@@ -85,16 +88,18 @@ function runTest()
   // g3.farthestViewportElement == null (but actually == null)
   is((function(){try{return g3.getScreenCTM()}catch(e){return e}})(), null, "g3.getScreenCTM()");
   // symbolRect.farthestViewportElement == root
   is((function(){try{return symbolRect.getScreenCTM().e}catch(e){return e}})(), 85, "symbolRect.getScreenCTM().e");
   is((function(){try{return symbolRect.getScreenCTM().f}catch(e){return e}})(), 108, "symbolRect.getScreenCTM().f");
   // fO.farthestViewportElement == root
   is((function(){try{return fO.getScreenCTM().e}catch(e){return e}})(), 16, "symbolRect.getScreenCTM().e");
   is((function(){try{return fO.getScreenCTM().f}catch(e){return e}})(), 29, "symbolRect.getScreenCTM().f");
+  // g5.farthestViewportElement == root
+  is((function(){try{return g5.getScreenCTM()}catch(e){return e}})(), null, "g5.getScreenCTM()");
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTest, false);
 </script>
 </pre>
 </body>