Bug 612118 - Make .getBBox() on a non-rendered element not throw. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 17 Apr 2020 00:28:52 +0000
changeset 524542 de7d485e3a0f412139d33ceec7c966aa7aef53ef
parent 524541 c6490dad74acd8a7979c52e6a7af5be6c647f220
child 524543 bfcd0afd5e0289a2c917025014629546b6b7e06c
push id113242
push userealvarez@mozilla.com
push dateFri, 17 Apr 2020 00:29:58 +0000
treeherderautoland@de7d485e3a0f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs612118
milestone77.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 612118 - Make .getBBox() on a non-rendered element not throw. r=heycam Differential Revision: https://phabricator.services.mozilla.com/D71228
dom/svg/SVGTransformableElement.cpp
dom/svg/SVGTransformableElement.h
dom/svg/crashtests/369291-1.svg
dom/svg/crashtests/crashtests.list
dom/webidl/SVGGraphicsElement.webidl
testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getBBox-01.html
--- a/dom/svg/SVGTransformableElement.cpp
+++ b/dom/svg/SVGTransformableElement.cpp
@@ -153,48 +153,49 @@ SVGAnimatedTransformList* SVGTransformab
 SVGElement* SVGTransformableElement::GetNearestViewportElement() {
   return SVGContentUtils::GetNearestViewportElement(this);
 }
 
 SVGElement* SVGTransformableElement::GetFarthestViewportElement() {
   return SVGContentUtils::GetOuterSVGElement(this);
 }
 
+static already_AddRefed<SVGRect> ZeroBBox(SVGTransformableElement& aOwner) {
+  return MakeAndAddRef<SVGRect>(&aOwner, Rect {0, 0, 0, 0});
+}
+
 already_AddRefed<SVGRect> SVGTransformableElement::GetBBox(
-    const SVGBoundingBoxOptions& aOptions, ErrorResult& rv) {
+    const SVGBoundingBoxOptions& aOptions) {
   nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
 
   if (!frame || (frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
-    rv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
+    return ZeroBBox(*this);
   }
   nsSVGDisplayableFrame* svgframe = do_QueryFrame(frame);
 
   if (!svgframe) {
     if (!nsSVGUtils::IsInSVGTextSubtree(frame)) {
-      rv.Throw(NS_ERROR_NOT_IMPLEMENTED);  // XXX: outer svg
-      return nullptr;
+      return ZeroBBox(*this);
     }
 
     // For <tspan>, <textPath>, the frame is an nsInlineFrame or
     // nsBlockFrame, |svgframe| will be a nullptr.
     // We implement their getBBox directly here instead of in
     // nsSVGUtils::GetBBox, because nsSVGUtils::GetBBox is more
     // or less used for other purpose elsewhere. e.g. gradient
     // code assumes GetBBox of <tspan> returns the bbox of the
     // outer <text>.
     // TODO: cleanup this sort of usecase of nsSVGUtils::GetBBox,
     // then move this code nsSVGUtils::GetBBox.
     SVGTextFrame* text =
         static_cast<SVGTextFrame*>(nsLayoutUtils::GetClosestFrameOfType(
             frame->GetParent(), LayoutFrameType::SVGText));
 
     if (text->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
-      rv.Throw(NS_ERROR_FAILURE);
-      return nullptr;
+      return ZeroBBox(*this);
     }
 
     gfxRect rec = text->TransformFrameRectFromTextChild(
         frame->GetRectRelativeToSelf(), frame);
 
     // Should also add the |x|, |y| of the SVGTextFrame itself, since
     // the result obtained by TransformFrameRectFromTextChild doesn't
     // include them.
--- a/dom/svg/SVGTransformableElement.h
+++ b/dom/svg/SVGTransformableElement.h
@@ -31,18 +31,17 @@ class SVGTransformableElement : public S
 
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override = 0;
 
   // WebIDL
   already_AddRefed<DOMSVGAnimatedTransformList> Transform();
   SVGElement* GetNearestViewportElement();
   SVGElement* GetFarthestViewportElement();
   MOZ_CAN_RUN_SCRIPT
-  already_AddRefed<SVGRect> GetBBox(const SVGBoundingBoxOptions& aOptions,
-                                    ErrorResult& rv);
+  already_AddRefed<SVGRect> GetBBox(const SVGBoundingBoxOptions&);
   already_AddRefed<SVGMatrix> GetCTM();
   already_AddRefed<SVGMatrix> GetScreenCTM();
   already_AddRefed<SVGMatrix> GetTransformToElement(
       SVGGraphicsElement& aElement, ErrorResult& rv);
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
 
deleted file mode 100644
--- a/dom/svg/crashtests/369291-1.svg
+++ /dev/null
@@ -1,22 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg"
-     xmlns:html="http://www.w3.org/1999/xhtml"
-     onload="setTimeout(boom, 30);"
-     class="reftest-wait">
-
-<html:script>
-
-function boom()
-{
-  try {
-    document.getElementById("defs").getBBox();
-  } catch(e) {
-    // getBBox is expected to throw, because defs is not displayed.
-    document.documentElement.removeAttribute("class");
-  }
-}
-
-</html:script>
-
-<defs id="defs" />
-
-</svg>
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -1,16 +1,15 @@
 load 307322-1.svg
 load 327705-1.svg
 load 336994-1.html
 load 344888-1.svg
 load 345445-1.svg
 load 360836-1.svg
 load 369051-1.svg
-load 369291-1.svg
 load 369291-2.svg
 load 369568-1.svg
 load 374882-1.svg
 load 380101-1.svg 
 load 381777-1.svg
 load 383685-1.svg
 load 385096.html
 load 385554-1.html
--- a/dom/webidl/SVGGraphicsElement.webidl
+++ b/dom/webidl/SVGGraphicsElement.webidl
@@ -19,17 +19,17 @@ dictionary SVGBoundingBoxOptions {
 
 [Exposed=Window]
 interface SVGGraphicsElement : SVGElement {
   readonly attribute SVGAnimatedTransformList transform;
 
   readonly attribute SVGElement? nearestViewportElement;
   readonly attribute SVGElement? farthestViewportElement;
 
-  [NewObject, Throws]
+  [NewObject]
   SVGRect getBBox(optional SVGBoundingBoxOptions aOptions = {});
   // Not implemented
   // SVGRect getStrokeBBox();
   SVGMatrix? getCTM();
   SVGMatrix? getScreenCTM();
   [Throws]
   SVGMatrix getTransformToElement(SVGGraphicsElement element);
 };
--- a/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getBBox-01.html
+++ b/testing/web-platform/tests/svg/types/scripted/SVGGraphicsElement.getBBox-01.html
@@ -64,16 +64,19 @@ const EPSILON = Math.pow(2, -24); // flo
 function assert_rect_approx_equals(rect, expected, epsilon) {
   assert_approx_equals(rect.x, expected.x, epsilon, "x");
   assert_approx_equals(rect.y, expected.y, epsilon, "y");
   assert_approx_equals(rect.width, expected.width, epsilon, "width");
   assert_approx_equals(rect.height, expected.height, epsilon, "height");
 }
 
 test(function() {
+  assert_rect_approx_equals(document.createElementNS("http://www.w3.org/2000/svg", "rect").getBBox(), {"x":0, "y":0, "width":0, "height":0 }, EPSILON);
+}, "getBBox on detached element");
+test(function() {
   assert_rect_approx_equals(document.getElementById("p1").getBBox(), {"x":0, "y":0, "width":0, "height":0 }, EPSILON);
 }, "getBBox on polygon with no points attribute");
 test(function() {
   assert_rect_approx_equals(document.getElementById("p3").getBBox(), {"x":0, "y":0, "width":0, "height":0}, EPSILON);
 }, "getBBox on polyline with no points attribute");
 test(function() {
   assert_rect_approx_equals(document.getElementById("p2").getBBox(), {"x":0, "y":0, "width":0, "height":0 }, EPSILON);
 }, "getBBox on path with no d attribute");