Bug 1247218 - Should consider CSS transform when using non-scaling-stroke r=longsonr
authorviolet <violet.bugreport@gmail.com>
Sat, 20 Apr 2019 02:04:52 +0000
changeset 470272 4c5a5b50c951ff946b39c178b080762e63043111
parent 470271 3e46d5fddd21e7627b010165013bea891bffcace
child 470273 790205e92ab5c54c36c0afc0d3a0dfb98434b530
push id35891
push userrgurzau@mozilla.com
push dateSat, 20 Apr 2019 09:35:22 +0000
treeherdermozilla-central@6e082b675763 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1247218
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 1247218 - Should consider CSS transform when using non-scaling-stroke r=longsonr We remove initial x/y offset for nsSVGUtils::GetTransformMatrixInUserSpace so that it can be used in not-nondisplay context. Previously it was only used in nondisplay context, where x/y offset is always 0. Then we use this utility to get the transform matrix to judge whether we need special care for non-scaling-stroke. The old matrix doesn't account for CSS transform. Differential Revision: https://phabricator.services.mozilla.com/D28193
layout/reftests/svg/reftest.list
layout/reftests/svg/test_bug1247218-ref.html
layout/reftests/svg/test_bug1247218.html
layout/svg/nsSVGUtils.cpp
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -157,16 +157,17 @@ fuzzy-if(d2d&&layersGPUAccelerated,0-3,0
 == dynamic-rect-04.xhtml pass.svg
 == dynamic-rect-05.svg pass.svg
 == dynamic-reflow-01.svg dynamic-reflow-01-ref.svg
 == dynamic-small-object-scaled-up-01.svg pass.svg
 == dynamic-small-object-scaled-up-02.svg pass.svg
 == dynamic-stroke-01.svg pass.svg
 == dynamic-stroke-opacity-01.svg pass.svg
 == dynamic-stroke-width-01.svg pass.svg
+== test_bug1247218.html test_bug1247218-ref.html
 == dynamic-switch-01.svg pass.svg
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-01.svg dynamic-text-01-ref.svg # bug 1392106
 fuzzy-if(d2d&&layersGPUAccelerated,0-3,0-12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8
 fuzzy-if(d2d&&layersGPUAccelerated,0-2,0-10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7 # bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-05.svg pass.svg # bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-06.svg pass.svg # bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-07.svg dynamic-text-07-ref.svg # bug 1392106
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/test_bug1247218-ref.html
@@ -0,0 +1,3 @@
+<svg style="width: 500px; height: 500px; border: 1px solid green;">
+  <rect id="square" transform="translate(100,200) scale(1,2.5)" stroke="blue" vector-effect="non-scaling-stroke" stroke-width="6" x="50px" y="50px" width="50px" height="50px" fill="pink" />
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/test_bug1247218.html
@@ -0,0 +1,8 @@
+<style>
+  #square{
+    transform: translate(100px,200px) scale(1,2.5);
+  }
+</style>
+<svg style="width: 500px; height: 500px; border: 1px solid green;">
+  <rect id="square" stroke="blue" vector-effect="non-scaling-stroke" stroke-width="6" x="50px" y="50px" width="50px" height="50px" fill="pink" />
+</svg>
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1243,23 +1243,22 @@ bool nsSVGUtils::GetNonScalingStrokeTran
   if (aFrame->GetContent()->IsText()) {
     aFrame = aFrame->GetParent();
   }
 
   if (!aFrame->StyleSVGReset()->HasNonScalingStroke()) {
     return false;
   }
 
-  nsIContent* content = aFrame->GetContent();
-  MOZ_ASSERT(content->IsSVGElement(), "bad cast");
+  MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "should be an SVG element");
 
-  *aUserToOuterSVG = ThebesMatrix(
-      SVGContentUtils::GetCTM(static_cast<SVGElement*>(content), true));
+  nsSVGOuterSVGFrame* outer = nsSVGUtils::GetOuterSVGFrame(aFrame);
+  *aUserToOuterSVG = nsSVGUtils::GetTransformMatrixInUserSpace(aFrame, outer);
 
-  return !aUserToOuterSVG->IsIdentity();
+  return aUserToOuterSVG->HasNonTranslation();
 }
 
 // The logic here comes from _cairo_stroke_style_max_distance_from_path
 static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
                                              nsIFrame* aFrame,
                                              double aStyleExpansionFactor,
                                              const gfxMatrix& aMatrix) {
   double style_expansion =
@@ -1700,24 +1699,26 @@ gfxMatrix nsSVGUtils::GetCSSPxToDevPxMat
 gfxMatrix nsSVGUtils::GetTransformMatrixInUserSpace(const nsIFrame* aFrame,
                                                     const nsIFrame* aAncestor) {
   // We check element instead of aFrame directly because SVG element
   // may have non-SVG frame, <tspan> for example.
   MOZ_ASSERT(aFrame->GetContent() && aFrame->GetContent()->IsSVGElement(),
              "Only use this wrapper for SVG elements");
 
   Matrix mm;
-  auto trans = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
+  auto trans = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor,
+                                                     nsIFrame::IN_CSS_UNITS);
+
   trans.ProjectTo2D();
   trans.CanDraw2D(&mm);
   gfxMatrix ret = ThebesMatrix(mm);
 
-  float devPixelPerCSSPixel = float(AppUnitsPerCSSPixel()) /
-                              aFrame->PresContext()->AppUnitsPerDevPixel();
+  float initPositionX = NSAppUnitsToFloatPixels(aFrame->GetPosition().x,
+                                                AppUnitsPerCSSPixel()),
+        initPositionY = NSAppUnitsToFloatPixels(aFrame->GetPosition().y,
+                                                AppUnitsPerCSSPixel());
 
-  // The matrix obtained by nsIFrame::GetTransformMatrix is "from
-  // device space to device space", we need to change it to be "from
-  // user space to user space".
-  ret.PreScale(devPixelPerCSSPixel, devPixelPerCSSPixel);
-  ret.PostScale(1.f / devPixelPerCSSPixel, 1.f / devPixelPerCSSPixel);
+  // Remove the initial displacement to mimic the behavior
+  // of SVGElement::PrependLocalTransformsTo().
+  ret = ret.PreTranslate(-initPositionX, -initPositionY);
 
   return ret;
 }