Bug 1385239 - Part 2. Remove aTransform parameter from PaintFilteredFrame. r=mstange
authorcku <cku@mozilla.com>
Fri, 25 Aug 2017 17:51:58 +0800
changeset 429680 9a6413d1fd0a02e60c109aa9f324288911f8ee52
parent 429679 45278d597320c6f107d21fcff591a5bac7c42a46
child 429681 114d87a3943b48a8cc1e9ca498bd7e7a306c95ac
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1385239
milestone57.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 1385239 - Part 2. Remove aTransform parameter from PaintFilteredFrame. r=mstange There are two callers of nsFilterInstance::PaintFilteredFrame: 1. nsSVGUtils::PaintFrameWithEffects at [1] This function is used while painting a filtered element on a path which display item painting is not supported yet, such as drawing elements inside a indirect painted SVG object, such as a mask, a clipPath or a gradient object. Let's say we have a masked element, which refers to an SVG mask, and there is a filtered element inside that SVG mask. Using nsFilterInstance::PaintFilteredFrame to paint that filtered frame in the mask, we have to pass a gfxContext and a transform matrix to it. The transform of the gfxContext 'target' that we pass in consists of a transform from the referenced frame, of the masked frame, to the masked frame. We also pass in a transform matrix 'aTransform', this matrix contains a transform from the the masked frame to the filtered frame in *device units*, which means it contains css-to-dev-px scaling factor. 2. nsSVGIntegrationUtils::PaintFilter at [2] This function is used by normal display item painting. The same, we pass a gfxContext 'context' and a transform matrix 'tm' into nsFilterInstance::PaintFilteredFrame. The transform matrix of 'context' consists of a transform from the referenced frame, of the filtered frame, to this filtered frame, but the scale factor was taken out . The transform matrix 'tm' we pass in contains scale transform from the referenced frame to the filtered frame in *device unit*. Inside nsFilterInstance::PaintFilteredFrame, we treat the transform matrix of 'aCtx' and 'aTransform' as parameters we pass in in #2 caller. So it can be failed in #1. For example, if the filtered frame inside a masked frame has a translation transform applied, since that translation was put in 'aTransfrom', but we only use the scale factor of 'aTransform' in nsFilterInstance::PaintFilteredFrame, translation factor disappears. In this patch, I unified the definition of parameters of nsFilterInstance::PaintFilteredFrame: 1. nsFilterInstance::PaintFilteredFrame(aCtx): the transform matrix of aCtx should be a transform from the referenced frame to the filtered frame in *css units*. Originally, the aCtx we passed in #1 is in device units, which should be fixed; the aCtx we passed in #2 does not even include css scaling factor, need be fixed too. 2. nsFilterInstance::PaintFilteredFrame(aTransform): this transform matrix should contain only scaling factor in device units. And I removed it in the end since I found we can get this value easily right inside the callee. [1] https://hg.mozilla.org/mozilla-central/file/ef585ac7c476/layout/svg/nsSVGUtils.cpp#l857 [2] https://hg.mozilla.org/mozilla-central/file/ef585ac7c476/layout/svg/nsSVGIntegrationUtils.cpp#l1114 MozReview-Commit-ID: gRV128NyQv
layout/svg/nsFilterInstance.cpp
layout/svg/nsFilterInstance.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGUtils.cpp
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -57,29 +57,45 @@ UserSpaceMetricsForFrame(nsIFrame* aFram
     return MakeUnique<SVGElementMetrics>(element);
   }
   return MakeUnique<NonSVGFrameUserSpaceMetrics>(aFrame);
 }
 
 void
 nsFilterInstance::PaintFilteredFrame(nsIFrame *aFilteredFrame,
                                      gfxContext* aCtx,
-                                     const gfxMatrix& aTransform,
                                      nsSVGFilterPaintCallback *aPaintCallback,
                                      const nsRegion *aDirtyArea,
                                      imgDrawingParams& aImgParams)
 {
   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
   UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
+
+  gfxContextMatrixAutoSaveRestore autoSR(aCtx);
+  gfxSize scaleFactors = aCtx->CurrentMatrix().ScaleFactors(true);
+  gfxMatrix scaleMatrix(scaleFactors.width, 0.0f,
+                        0.0f, scaleFactors.height,
+                        0.0f, 0.0f);
+
+  gfxMatrix reverseScaleMatrix = scaleMatrix;
+  DebugOnly<bool> invertible = reverseScaleMatrix.Invert();
+  MOZ_ASSERT(invertible);
+  // Pull scale vector out of aCtx's transform, put all scale factors, which
+  // includes css and css-to-dev-px scale, into scaleMatrixInDevUnits.
+  aCtx->SetMatrix(reverseScaleMatrix * aCtx->CurrentMatrix());
+
+  gfxMatrix scaleMatrixInDevUnits =
+    scaleMatrix * nsSVGUtils::GetCSSPxToDevPxMatrix(aFilteredFrame);
+
   // Hardcode InputIsTainted to true because we don't want JS to be able to
   // read the rendered contents of aFilteredFrame.
   nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
                             *metrics, filterChain, /* InputIsTainted */ true,
-                            aPaintCallback, aTransform, aDirtyArea, nullptr,
-                            nullptr, nullptr);
+                            aPaintCallback, scaleMatrixInDevUnits,
+                            aDirtyArea, nullptr, nullptr, nullptr);
   if (instance.IsInitialized()) {
     instance.Render(aCtx, aImgParams);
   }
 }
 
 nsRegion
 nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
                                          const nsRegion& aPreFilterDirtyRegion)
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -80,17 +80,16 @@ public:
   /**
    * Paint the given filtered frame.
    * @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
    *   frame space (i.e. relative to its origin, the top-left corner of its
    *   border box).
    */
   static void PaintFilteredFrame(nsIFrame *aFilteredFrame,
                                  gfxContext* aCtx,
-                                 const gfxMatrix& aTransform,
                                  nsSVGFilterPaintCallback *aPaintCallback,
                                  const nsRegion* aDirtyArea,
                                  imgDrawingParams& aImgParams);
 
   /**
    * Returns the post-filter area that could be dirtied when the given
    * pre-filter area of aFilteredFrame changes.
    * @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1089,30 +1089,19 @@ nsSVGIntegrationUtils::PaintFilter(const
     context.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
                                   nullptr, Matrix());
   }
 
   /* Paint the child and apply filters */
   RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
                                      offsets.offsetToUserSpaceInDevPx);
   nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
-  gfxSize scaleFactors = context.CurrentMatrix().ScaleFactors(true);
-  gfxMatrix scaleMatrix(scaleFactors.width, 0.0f,
-                        0.0f, scaleFactors.height,
-                        0.0f, 0.0f);
-  gfxMatrix reverseScaleMatrix = scaleMatrix;
-  DebugOnly<bool> invertible = reverseScaleMatrix.Invert();
-  MOZ_ASSERT(invertible);
-  context.SetMatrix(reverseScaleMatrix * context.CurrentMatrix());
 
-  gfxMatrix tm =
-    scaleMatrix * nsSVGUtils::GetCSSPxToDevPxMatrix(frame);
-  nsFilterInstance::PaintFilteredFrame(frame, &context,
-                                       tm, &callback, &dirtyRegion,
-                                       aParams.imgParams);
+  nsFilterInstance::PaintFilteredFrame(frame, &context, &callback,
+                                       &dirtyRegion, aParams.imgParams);
 
   if (opacity != 1.0f) {
     context.PopGroupAndBlend();
   }
 }
 
 class PaintFrameCallback : public gfxDrawingCallback {
 public:
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -848,19 +848,29 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
                                       aDirtyRect->width, aDirtyRect->height));
       tmpDirtyRegion =
         nsLayoutUtils::RoundGfxRectToAppRect(
           dirtyBounds, aFrame->PresContext()->AppUnitsPerCSSPixel()) -
         aFrame->GetPosition();
       dirtyRegion = &tmpDirtyRegion;
     }
 
+    gfxContextMatrixAutoSaveRestore autoSR(target);
+
+    // 'target' is currently scaled such that its user space units are CSS
+    // pixels (SVG user space units). But PaintFilteredFrame expects it to be
+    // scaled in such a way that its user space units are device pixels. So we
+    // have to adjust the scale.
+    gfxMatrix reverseScaleMatrix = nsSVGUtils::GetCSSPxToDevPxMatrix(aFrame);
+    DebugOnly<bool> invertible = reverseScaleMatrix.Invert();
+    target->SetMatrix(reverseScaleMatrix * aTransform *
+                      target->CurrentMatrix());
+
     SVGPaintCallback paintCallback;
-    nsFilterInstance::PaintFilteredFrame(aFrame, target,
-                                         aTransform, &paintCallback,
+    nsFilterInstance::PaintFilteredFrame(aFrame, target, &paintCallback,
                                          dirtyRegion, aImgParams);
   } else {
      svgFrame->PaintSVG(*target, aTransform, aImgParams, aDirtyRect);
   }
 
   if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
     aContext.PopClip();
   }