Bug 875069 - nsSVGPathGeometryFrame::NotifySVGChanged needs to take account of stroke-width and non-scaling-stroke. r=dholbert, a=akeybl
authorJonathan Watt <jwatt@jwatt.org>
Thu, 23 May 2013 15:30:14 +0100
changeset 142960 9356e183b1c827f0ff74d38b6c46f0020efc612a
parent 142959 ebfdc93638dd57728997ef8162f1b685cf32263a
child 142961 6d5e8bc3b0657651c90eae8b6896ab36637e4cd4
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert, akeybl
bugs875069
milestone23.0a2
Bug 875069 - nsSVGPathGeometryFrame::NotifySVGChanged needs to take account of stroke-width and non-scaling-stroke. r=dholbert, a=akeybl
layout/reftests/svg/non-scaling-stroke-03-ref.svg
layout/reftests/svg/non-scaling-stroke-03.svg
layout/reftests/svg/reftest.list
layout/reftests/svg/stroke-width-percentage-02-ref.svg
layout/reftests/svg/stroke-width-percentage-02a.svg
layout/reftests/svg/stroke-width-percentage-02b.svg
layout/reftests/svg/stroke-width-percentage-03-iframe.svg
layout/reftests/svg/stroke-width-percentage-03-ref.xhtml
layout/reftests/svg/stroke-width-percentage-03.xhtml
layout/svg/nsSVGPathGeometryFrame.cpp
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/non-scaling-stroke-03-ref.svg
@@ -0,0 +1,7 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+  <line x1="100" y1="100" x2="100" y2="200" stroke="blue" stroke-width="10"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/non-scaling-stroke-03.svg
@@ -0,0 +1,23 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
+  <title>Test non-scaling-stroke repainting when ancestor transforms change</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+  <script>
+
+function doTest() {
+  document.getElementById("g").setAttribute("transform", "scale(2)");
+  document.documentElement.removeAttribute('class');
+}
+
+document.addEventListener("MozReftestInvalidate", doTest, false);
+setTimeout(doTest, 4000); // fallback for running outside reftest
+
+  </script>
+  <g id="g">
+    <line x1="50" y1="50" x2="50" y2="100" stroke="blue" stroke-width="10"
+          style="vector-effect:non-scaling-stroke;"/>
+  </g>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -194,16 +194,17 @@ fuzzy-if(Android,9,980) == gradient-live
 pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-01.svg mask-type-01-ref.svg
 pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-02.svg mask-type-01-ref.svg
 pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-03.svg mask-type-01-ref.svg
 pref(layout.css.masking.enabled,true) fuzzy-if(d2d,1,6400) == mask-type-04.svg mask-type-01-ref.svg
 == nested-viewBox-01.svg pass.svg
 == nesting-invalid-01.svg nesting-invalid-01-ref.svg
 == non-scaling-stroke-01.svg non-scaling-stroke-01-ref.svg 
 fuzzy-if(Android,9,61) fuzzy-if(!contentSameGfxBackendAsCanvas,1,99) == non-scaling-stroke-02.svg non-scaling-stroke-02-ref.svg 
+== non-scaling-stroke-03.svg non-scaling-stroke-03-ref.svg 
 == objectBoundingBox-and-clipPath.svg pass.svg
 # Bug 588684
 random-if(gtk2Widget) == objectBoundingBox-and-fePointLight-01.svg objectBoundingBox-and-fePointLight-01-ref.svg
 random-if(gtk2Widget) == objectBoundingBox-and-fePointLight-02.svg objectBoundingBox-and-fePointLight-02-ref.svg
 == objectBoundingBox-and-mask.svg pass.svg
 == objectBoundingBox-and-mask-02.svg pass.svg
 == objectBoundingBox-and-pattern-01a.svg objectBoundingBox-and-pattern-01-ref.svg
 == objectBoundingBox-and-pattern-01b.svg objectBoundingBox-and-pattern-01-ref.svg
@@ -253,16 +254,19 @@ pref(svg.paint-order.enabled,true) == pa
 == rect-03.svg pass.svg
 == rect-04.svg pass.svg
 == rect-with-rx-and-ry-01.svg pass.svg
 == rect-with-rx-or-ry-01.svg rect-with-rx-or-ry-01-ref.svg
 == rootElement-null-01.svg pass.svg
 == script-empty-01.svg pass.svg
 == selector-01.svg pass.svg
 == stroke-width-percentage-01.svg pass.svg
+== stroke-width-percentage-02a.svg stroke-width-percentage-02-ref.svg
+== stroke-width-percentage-02b.svg stroke-width-percentage-02-ref.svg
+== stroke-width-percentage-03.xhtml stroke-width-percentage-03-ref.xhtml
 == style-property-on-script-element-01.svg pass.svg
 == style-without-type-attribute.svg pass.svg
 == svg-in-foreignObject-01.xhtml svg-in-foreignObject-01-ref.xhtml
 == svg-in-foreignObject-02.xhtml svg-in-foreignObject-01-ref.xhtml # reuse -01-ref.xhtml
 == switch-01.svg pass.svg
 == suspend-01.svg pass.svg
 == suspend-02.svg pass.svg
 == suspend-03.svg pass.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-02-ref.svg
@@ -0,0 +1,7 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+  <rect width="100" height="50" fill="blue"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-02a.svg
@@ -0,0 +1,27 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
+  <title>Test percentage stroke-width repaints after viewport size change</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+  <script>
+
+function doTest() {
+  document.getElementById("inner").setAttribute("width", "100");
+  document.getElementById("inner").setAttribute("height", "100");
+  document.documentElement.removeAttribute('class');
+}
+
+document.addEventListener("MozReftestInvalidate", doTest, false);
+setTimeout(doTest, 4000); // fallback for running outside reftest
+
+  </script>
+  <svg id="inner" width="50" height="50">
+    <!-- Don't give the line's x/y attributes percentages since that
+         may trigger reflow in which case this test wouldn't be
+         testing what we intend!
+    -->
+    <line x1="50" x2="50" y2="50" stroke="blue" stroke-width="100%"/>
+  </svg>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-02b.svg
@@ -0,0 +1,26 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait"
+     id="outer" style="width:50px; height:50px;">
+  <title>Test percentage stroke-width repaints after viewport size change</title>
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+  <script>
+
+function doTest() {
+  document.getElementById("outer").style.width = "100px";
+  document.getElementById("outer").style.height = "100px";
+  document.documentElement.removeAttribute('class');
+}
+
+document.addEventListener("MozReftestInvalidate", doTest, false);
+setTimeout(doTest, 4000); // fallback for running outside reftest
+
+  </script>
+  <!-- Don't give the line's x/y attributes percentages since that
+       may trigger reflow in which case this test wouldn't be
+       testing what we intend!
+  -->
+  <line x1="50" x2="50" y2="50" stroke="blue" stroke-width="100%"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-03-iframe.svg
@@ -0,0 +1,13 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+
+  <!-- Don't give the line's x/y attributes percentages since that
+       may trigger reflow in which case this test wouldn't be
+       testing what we intend!
+  -->
+  <line x1="50" x2="50" y2="50" stroke="blue" stroke-width="100%"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-03-ref.xhtml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <body>
+    <div id="container" style="width: 100px; height: 50px; background: blue;">
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-width-percentage-03.xhtml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=875069 -->
+<!--
+    This test checks that when the content area of the window resizes without
+    any style change that we reflow stroked SVG elements that have
+    'vector-effect' set to 'non-scaling-stroke' and that are under a
+    transformed ancestor. We use an iframe to allow us to resize the content
+    area of the embedded document without changing its style.
+
+    This test should end up rendering a blue square, 100px by 50px.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"
+      class="reftest-wait">
+  <head>
+    <style>
+
+#frame {
+  /* width and height are given the same value since percentage stroke resolves
+     as sqrt(width^2 + height^2).
+  */
+  width: 50px;
+  height: 50px;
+  border: 0;
+}
+
+    </style>
+    <script>
+
+function doTest() {
+  document.getElementById("frame").style.width = "100px";
+  document.getElementById("frame").style.height = "100px";
+  document.documentElement.removeAttribute("class");
+}
+
+window.addEventListener("MozReftestInvalidate", doTest, false);
+setTimeout(doTest, 4000); // fallback for running outside reftest
+
+    </script>
+  </head>
+  <body>
+    <iframe id="frame" src="stroke-width-percentage-03-iframe.svg"></iframe>
+  </body>
+</html>
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -355,20 +355,41 @@ nsSVGPathGeometryFrame::NotifySVGChanged
 
   // Changes to our ancestors may affect how we render when we are rendered as
   // part of our ancestor (specifically, if our coordinate context changes size
   // and we have percentage lengths defining our geometry, then we need to be
   // reflowed). However, ancestor changes cannot affect how we render when we
   // are rendered as part of any rendering observers that we may have.
   // Therefore no need to notify rendering observers here.
 
-  if ((aFlags & COORD_CONTEXT_CHANGED) &&
-      static_cast<nsSVGPathGeometryElement*>(mContent)->GeometryDependsOnCoordCtx()) {
+  // Don't try to be too smart trying to avoid the ScheduleReflowSVG calls
+  // for the stroke properties examined below. Checking HasStroke() is not
+  // enough, since what we care about is whether we include the stroke in our
+  // overflow rects or not, and we sometimes deliberately include stroke
+  // when it's not visible. See the complexities of GetBBoxContribution.
+
+  if (aFlags & COORD_CONTEXT_CHANGED) {
+    // Stroke currently contributes to our mRect, which is why we have to take
+    // account of stroke-width here. Note that we do not need to take account
+    // of stroke-dashoffset since, although that can have a percentage value
+    // that is resolved against our coordinate context, it does not affect our
+    // mRect.
+    if (static_cast<nsSVGPathGeometryElement*>(mContent)->GeometryDependsOnCoordCtx() ||
+        StyleSVG()->mStrokeWidth.HasPercent()) {
+      nsSVGUtils::ScheduleReflowSVG(this);
+    }
+  }
+
+  if ((aFlags & TRANSFORM_CHANGED) &&
+      StyleSVGReset()->mVectorEffect ==
+        NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE) {
+    // Stroke currently contributes to our mRect, and our stroke depends on
+    // the transform to our outer-<svg> if |vector-effect:non-scaling-stroke|.
     nsSVGUtils::ScheduleReflowSVG(this);
-  }
+  } 
 }
 
 SVGBBox
 nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
                                             uint32_t aFlags)
 {
   SVGBBox bbox;