Bug 1346610 - Compute width and height only when necessary to avoid exponential time complexity r=longsonr
authorviolet <violet.bugreport@gmail.com>
Fri, 08 Mar 2019 07:27:24 +0000
changeset 521009 e1459b0afa258f53b7799447c063654e994e4d7f
parent 521008 3c21d47f9ddf9853519f2f7c49a1fe1ca5aa6463
child 521010 525dd00d5636fb4bae03be8b401bbc7ef668d4ac
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1346610
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1346610 - Compute width and height only when necessary to avoid exponential time complexity r=longsonr When only width is needed, we should not compute height, and vice versa. Otherwise there are exponentially repeated computations for nested svg elements, which will make the tab unresponsive due to 100% CPU usage for exponentially long time. Differential Revision: https://phabricator.services.mozilla.com/D20947
dom/svg/SVGViewportElement.cpp
dom/svg/crashtests/crashtests.list
dom/svg/crashtests/test_nested_svg.html
--- a/dom/svg/SVGViewportElement.cpp
+++ b/dom/svg/SVGViewportElement.cpp
@@ -200,29 +200,42 @@ gfx::Matrix SVGViewportElement::GetViewB
 //----------------------------------------------------------------------
 // SVGViewportElement
 
 float SVGViewportElement::GetLength(uint8_t aCtxType) {
   const SVGViewBoxRect* viewbox = GetViewBoxInternal().HasRect()
                                       ? &GetViewBoxInternal().GetAnimValue()
                                       : nullptr;
 
-  float h, w;
+  float h = 0.0f, w = 0.0f;
+  bool shouldComputeWidth =
+           (aCtxType == SVGContentUtils::X || aCtxType == SVGContentUtils::XY),
+       shouldComputeHeight =
+           (aCtxType == SVGContentUtils::Y || aCtxType == SVGContentUtils::XY);
+
   if (viewbox) {
     w = viewbox->width;
     h = viewbox->height;
   } else if (IsInner()) {
     SVGViewportElement* ctx = GetCtx();
-    w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
-    h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
+    if (shouldComputeWidth) {
+      w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
+    }
+    if (shouldComputeHeight) {
+      h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
+    }
   } else if (ShouldSynthesizeViewBox()) {
-    w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
-                                           mViewportWidth, this);
-    h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
-                                           mViewportHeight, this);
+    if (shouldComputeWidth) {
+      w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
+                                             mViewportWidth, this);
+    }
+    if (shouldComputeHeight) {
+      h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
+                                             mViewportHeight, this);
+    }
   } else {
     w = mViewportWidth;
     h = mViewportHeight;
   }
 
   w = std::max(w, 0.0f);
   h = std::max(h, 0.0f);
 
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -86,8 +86,9 @@ load 1347617-2.svg
 load 1347617-3.svg
 load 1402798.html
 load 1419250-1.html
 load 1420492.html
 load 1477853.html
 load 1486488.html
 load 1493447.html
 skip-if(Android) load 1507961-1.html  # times out on Android due to the test size
+load test_nested_svg.html
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/test_nested_svg.html
@@ -0,0 +1,63 @@
+<!-- if not handled properly, this file will cause 100% CPU for exponentially long time -->
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>
+<svg>