Bug 972041 - getCTM should account for CSS transform r=longsonr
authorviolet <violet.bugreport@gmail.com>
Sat, 27 Apr 2019 08:42:51 +0000
changeset 530455 bbd172d048d70b795867273c09ed7aec32c4d799
parent 530454 c151677139852ef5443ec1c908f49f4cba07c7fc
child 530456 2c949afac54e02d3e11c78c80d0b3c8c5cd7091f
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs972041
milestone68.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 972041 - getCTM should account for CSS transform r=longsonr We use nsSVGUtils::GetTransformMatrixInUserSpace to support CSS transform in getCTM. Differential Revision: https://phabricator.services.mozilla.com/D28969
dom/svg/SVGContentUtils.cpp
dom/svg/test/test_getCTM.html
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -14,21 +14,23 @@
 #include "gfxPlatform.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/SVGContextPaint.h"
 #include "mozilla/TextUtils.h"
 #include "nsComputedDOMStyle.h"
+#include "nsContainerFrame.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
+#include "nsSVGUtils.h"
 #include "nsWhitespaceTokenizer.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/ComputedStyle.h"
@@ -461,25 +463,47 @@ SVGViewportElement* SVGContentUtils::Get
     }
     element = element->GetFlattenedTreeParent();
   }
   return nullptr;
 }
 
 static gfx::Matrix GetCTMInternal(SVGElement* aElement, bool aScreenCTM,
                                   bool aHaveRecursed) {
-  gfxMatrix matrix = aElement->PrependLocalTransformsTo(
-      gfxMatrix(), aHaveRecursed ? eAllTransforms : eUserSpaceToParent);
+  auto getLocalTransformHelper =
+      [](SVGElement const* e, bool shouldIncludeChildToUserSpace) -> gfxMatrix {
+    gfxMatrix ret;
+
+    if (auto* f = e->GetPrimaryFrame()) {
+      ret = nsSVGUtils::GetTransformMatrixInUserSpace(f, f->GetParent());
+    } else {
+      // FIXME: Ideally we should also return the correct matrix
+      // for display:none, but currently transform related code relies
+      // heavily on the present of a frame.
+      // For now we just fall back to |PrependLocalTransformsTo| which
+      // doesn't account for CSS transform.
+      ret = e->PrependLocalTransformsTo({}, eUserSpaceToParent);
+    }
+
+    if (shouldIncludeChildToUserSpace) {
+      ret = e->PrependLocalTransformsTo({}, eChildToUserSpace) * ret;
+    }
+
+    return ret;
+  };
+
+  gfxMatrix matrix = getLocalTransformHelper(aElement, aHaveRecursed);
+
   SVGElement* element = aElement;
   nsIContent* ancestor = aElement->GetFlattenedTreeParent();
 
   while (ancestor && ancestor->IsSVGElement() &&
          !ancestor->IsSVGElement(nsGkAtoms::foreignObject)) {
     element = static_cast<SVGElement*>(ancestor);
-    matrix *= element->PrependLocalTransformsTo(gfxMatrix());  // i.e. *A*ppend
+    matrix *= getLocalTransformHelper(element, true);
     if (!aScreenCTM && SVGContentUtils::EstablishesViewport(element)) {
       if (!element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG) &&
           !element->NodeInfo()->Equals(nsGkAtoms::symbol, kNameSpaceID_SVG)) {
         NS_ERROR("New (SVG > 1.1) SVG viewport establishing element?");
         return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);  // singular
       }
       // XXX spec seems to say x,y translation should be undone for IsInnerSVG
       return gfx::ToMatrix(matrix);
@@ -496,17 +520,17 @@ static gfx::Matrix GetCTMInternal(SVGEle
   }
   if (element == aElement && !aHaveRecursed) {
     // We get here when getScreenCTM() is called on an outer-<svg>.
     // Consistency with other elements would have us include only the
     // eFromUserSpace transforms, but we include the eAllTransforms
     // transforms in this case since that's what we've been doing for
     // a while, and it keeps us consistent with WebKit and Opera (if not
     // really with the ambiguous spec).
-    matrix = aElement->PrependLocalTransformsTo(gfxMatrix());
+    matrix = getLocalTransformHelper(aElement, true);
   }
 
   if (auto* f = element->GetPrimaryFrame()) {
     if (f->IsSVGOuterSVGFrame()) {
       nsMargin bp = f->GetUsedBorderAndPadding();
       matrix.PostTranslate(
           NSAppUnitsToFloatPixels(bp.left, AppUnitsPerCSSPixel()),
           NSAppUnitsToFloatPixels(bp.top, AppUnitsPerCSSPixel()));
--- a/dom/svg/test/test_getCTM.html
+++ b/dom/svg/test/test_getCTM.html
@@ -4,41 +4,46 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=366697
 -->
 <head>
   <title>Test for Bug 366697</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <style>
     #padsvg1 { padding-left: 27px; padding-top: 43px; }
+    #transrect1 { transform: scale(2,3); }
   </style>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=366697">Mozilla Bug 366697</a>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 
 <iframe id="svg" src="getCTM-helper.svg"></iframe>
 
 <svg id="padsvg1" width="100" height="100">
-  <rect width="10" height="10" />
+  <rect id="transrect1" width="10" height="10" />
 </svg>
 
 <pre id="test">
 <script class="testbody" type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
 function runTest() {
   var doc = $("svg").contentWindow.document;
 
   /* Minimal */
   var buggy = doc.getElementById("buggy");
   is(buggy.getCTM().e, 30, "buggy.getCTM().e");
   is(buggy.getCTM().f, 40, "buggy.getCTM().f");
 
+  var transrect1 = document.getElementById("transrect1");
+  is(transrect1.getCTM().a, 2, "transrect1.getCTM().a");
+  is(transrect1.getCTM().d, 3, "transrect1.getCTM().d");
+
   var padsvg1 = document.getElementById("padsvg1");
   is(padsvg1.getScreenCTM().e - padsvg1.getBoundingClientRect().x, 27, "padsvg1.getScreenCTM().e");
   is(padsvg1.getScreenCTM().f - padsvg1.getBoundingClientRect().y, 43, "padsvg1.getScreenCTM().f");
 
   var root = doc.documentElement;
   var inner = doc.getElementById("inner");
   var g1 = doc.getElementById("g1");
   var outer = doc.getElementById("outer");