Bug 1224207 - Part 1. Split SetupContext into ComputeEffectOffset and TranslateToUserSpace. r=mstange
☠☠ backed out by f9aae3308f05 ☠ ☠
authorcku <cku@mozilla.com>
Mon, 23 Jan 2017 02:36:41 +0800
changeset 341412 d23079bc188ee40cc4a8275bed3065e939537add
parent 341411 60a5029865aaf52c413a2553088db8395452d5fd
child 341413 958379e4f61cc97f3f81c4a4da31ffbff3c099d2
push id86727
push userkwierso@gmail.com
push dateThu, 09 Feb 2017 00:21:26 +0000
treeherdermozilla-inbound@55a4f5189115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1224207
milestone54.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 1224207 - Part 1. Split SetupContext into ComputeEffectOffset and TranslateToUserSpace. r=mstange We need ComputeEffectOffset along in the following patch. MozReview-Commit-ID: GoIZ07IqoQ3
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -648,71 +648,96 @@ ValidateSVGFrame(nsIFrame* aFrame)
       // The SVG spec says not to draw _anything_
       return false;
     }
   }
 
   return true;
 }
 
-/**
- * Setup transform matrix of a gfx context by a specific frame. Depend on
- * aClipCtx, this function may clip that context by the visual overflow area
- * of aFrame.
- *
- * @param aFrame is the target frame.
- * @param aOffsetToBoundingBox returns the offset between the reference frame
- *        and the bounding box of aFrame.
- * @oaram aOffsetToUserSpace returns the offset between the reference frame and
- *        the user space coordinate of aFrame.
- */
-static void
-SetupContextMatrix(nsIFrame* aFrame, const PaintFramesParams& aParams,
-                   nsPoint& aOffsetToBoundingBox, nsPoint& aOffsetToUserSpace)
+struct EffectOffsets {
+  // The offset between the reference frame and the bounding box of the
+  // target frame in app unit.
+  nsPoint  offsetToBoundingBox;
+  // The offset between the reference frame and the bounding box of the
+  // target frame in device unit.
+  gfxPoint offsetToBoundingBoxInDevPx;
+  // The offset between the reference frame and the bounding box of the
+  // target frame in app unit.
+  nsPoint  offsetToUserSpace;
+  // The offset between the reference frame and the bounding box of the
+  // target frame in device unit.
+  gfxPoint offsetToUserSpaceInDevPx;
+};
+
+EffectOffsets
+ComputeEffectOffset(nsIFrame* aFrame, const PaintFramesParams& aParams)
 {
-  aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(aFrame) -
-                         nsSVGIntegrationUtils::GetOffsetToBoundingBox(aFrame);
+  EffectOffsets result;
+
+  result.offsetToBoundingBox =
+    aParams.builder->ToReferenceFrame(aFrame) -
+    nsSVGIntegrationUtils::GetOffsetToBoundingBox(aFrame);
   if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
     /* Snap the offset if the reference frame is not a SVG frame,
      * since other frames will be snapped to pixel when rendering. */
-    aOffsetToBoundingBox = nsPoint(
-      aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
-      aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
+    result.offsetToBoundingBox =
+      nsPoint(
+        aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(result.offsetToBoundingBox.x),
+        aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(result.offsetToBoundingBox.y));
   }
 
   // After applying only "aOffsetToBoundingBox", aParams.ctx would have its
   // origin at the top left corner of frame's bounding box (over all
   // continuations).
   // However, SVG painting needs the origin to be located at the origin of the
   // SVG frame's "user space", i.e. the space in which, for example, the
   // frame's BBox lives.
   // SVG geometry frames and foreignObject frames apply their own offsets, so
   // their position is relative to their user space. So for these frame types,
   // if we want aParams.ctx to be in user space, we first need to subtract the
   // frame's position so that SVG painting can later add it again and the
   // frame is painted in the right place.
-
   gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame);
   nsPoint toUserSpace =
     nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
             nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
 
-  aOffsetToUserSpace = aOffsetToBoundingBox - toUserSpace;
+  result.offsetToUserSpace = result.offsetToBoundingBox - toUserSpace;
 
 #ifdef DEBUG
   bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
-  NS_ASSERTION(hasSVGLayout || aOffsetToBoundingBox == aOffsetToUserSpace,
+  NS_ASSERTION(hasSVGLayout ||
+               result.offsetToBoundingBox == result.offsetToUserSpace,
                "For non-SVG frames there shouldn't be any additional offset");
 #endif
 
-  gfxPoint devPixelOffsetToUserSpace =
-    nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
+  result.offsetToUserSpaceInDevPx =
+    nsLayoutUtils::PointToGfxPoint(result.offsetToUserSpace,
+                                   aFrame->PresContext()->AppUnitsPerDevPixel());
+  result.offsetToBoundingBoxInDevPx =
+    nsLayoutUtils::PointToGfxPoint(result.offsetToBoundingBox,
                                    aFrame->PresContext()->AppUnitsPerDevPixel());
-  gfxContext& context = aParams.ctx;
-  context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
+
+  return result;
+}
+
+/**
+ * Setup transform matrix of a gfx context by a specific frame. Move the
+ * origin of aParams.ctx to the user space of aFrame.
+ */
+static EffectOffsets
+MoveContextOriginToUserSpace(nsIFrame* aFrame, const PaintFramesParams& aParams)
+{
+  EffectOffsets offset = ComputeEffectOffset(aFrame, aParams);
+
+  aParams.ctx.SetMatrix(
+    aParams.ctx.CurrentMatrix().Translate(offset.offsetToUserSpaceInDevPx));
+
+  return offset;
 }
 
 bool
 nsSVGIntegrationUtils::IsMaskResourceReady(nsIFrame* aFrame)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
   nsSVGEffects::EffectProperties effectProperties =
@@ -793,26 +818,23 @@ nsSVGIntegrationUtils::PaintMask(const P
   bool shouldPushOpacity = (maskUsage.opacity != 1.0) &&
                            (maskFrames.Length() != 1);
   if (shouldPushOpacity) {
     ctx.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, maskUsage.opacity);
     autoPop.SetContext(&ctx);
   }
 
   gfxContextMatrixAutoSaveRestore matSR;
-  nsPoint offsetToBoundingBox;
-  nsPoint offsetToUserSpace;
 
   // Paint clip-path-basic-shape onto ctx
   gfxContextAutoSaveRestore basicShapeSR;
   if (maskUsage.shouldApplyBasicShape) {
     matSR.SetContext(&ctx);
 
-    SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                       offsetToUserSpace);
+    MoveContextOriginToUserSpace(firstFrame, aParams);
 
     basicShapeSR.SetContext(&ctx);
     nsCSSClipPathInstance::ApplyBasicShapeClip(ctx, frame);
     if (!maskUsage.shouldGenerateMaskLayer) {
       // Only have basic-shape clip-path effect. Fill clipped region by
       // opaque white.
       ctx.SetColor(Color(1.0, 1.0, 1.0, 1.0));
       ctx.Fill();
@@ -821,34 +843,33 @@ nsSVGIntegrationUtils::PaintMask(const P
     }
   }
 
   // Paint mask onto ctx.
   if (maskUsage.shouldGenerateMaskLayer) {
     matSR.Restore();
     matSR.SetContext(&ctx);
 
-    SetupContextMatrix(frame, aParams, offsetToBoundingBox,
-                       offsetToUserSpace);
+    EffectOffsets offsets = MoveContextOriginToUserSpace(frame, aParams);
     result = PaintMaskSurface(aParams, maskTarget,
                               shouldPushOpacity ?  1.0 : maskUsage.opacity,
                               firstFrame->StyleContext(), maskFrames,
-                              ctx.CurrentMatrix(), offsetToUserSpace);
+                              ctx.CurrentMatrix(),
+                              offsets.offsetToUserSpace);
     if (result != DrawResult::SUCCESS) {
       return result;
     }
   }
 
   // Paint clip-path onto ctx.
   if (maskUsage.shouldGenerateClipMaskLayer || maskUsage.shouldApplyClipPath) {
     matSR.Restore();
     matSR.SetContext(&ctx);
 
-    SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                       offsetToUserSpace);
+    MoveContextOriginToUserSpace(firstFrame, aParams);
     Matrix clipMaskTransform;
     gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
 
     nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
     RefPtr<SourceSurface> maskSurface =
       maskUsage.shouldGenerateMaskLayer ? maskTarget->Snapshot() : nullptr;
     result =
       clipPathFrame->PaintClipMask(ctx, frame, cssPxToDevPxMatrix,
@@ -903,19 +924,16 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
 
   gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
   nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
 
-  nsPoint offsetToBoundingBox;
-  nsPoint offsetToUserSpace;
-
   bool shouldGenerateMask = (maskUsage.opacity != 1.0f ||
                              maskUsage.shouldGenerateClipMaskLayer ||
                              maskUsage.shouldGenerateMaskLayer);
   bool shouldPushMask = false;
 
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
   if (shouldGenerateMask) {
@@ -926,22 +944,21 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
     bool opacityApplied = false;
 
     if (maskUsage.shouldGenerateMaskLayer) {
       matSR.SetContext(&context);
 
       // For css-mask, we want to generate a mask for each continuation frame,
       // so we setup context matrix by the position of the current frame,
       // instead of the first continuation frame.
-      SetupContextMatrix(frame, aParams, offsetToBoundingBox,
-                         offsetToUserSpace);
+      EffectOffsets offsets = MoveContextOriginToUserSpace(frame, aParams);
       MaskPaintResult paintResult =
         CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
                                   firstFrame->StyleContext(),
-                                  maskFrames, offsetToUserSpace);
+                                  maskFrames, offsets.offsetToUserSpace);
 
       if (paintResult.transparentBlackMask) {
         return paintResult.result;
       }
 
       result &= paintResult.result;
       maskSurface = paintResult.maskSurface;
       if (maskSurface) {
@@ -951,18 +968,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
         opacityApplied = paintResult.opacityApplied;
       }
     }
 
     if (maskUsage.shouldGenerateClipMaskLayer) {
       matSR.Restore();
       matSR.SetContext(&context);
 
-      SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                         offsetToUserSpace);
+      MoveContextOriginToUserSpace(firstFrame, aParams);
       Matrix clipMaskTransform;
       DrawResult clipMaskResult;
       RefPtr<SourceSurface> clipMaskSurface;
       Tie(clipMaskResult, clipMaskSurface) =
         clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
                                    &clipMaskTransform, maskSurface,
                                    maskTransform);
 
@@ -979,18 +995,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
     }
 
     // opacity != 1.0f.
     if (!maskUsage.shouldGenerateClipMaskLayer &&
         !maskUsage.shouldGenerateMaskLayer) {
       MOZ_ASSERT(maskUsage.opacity != 1.0f);
 
       matSR.SetContext(&context);
-      SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                         offsetToUserSpace);
+      MoveContextOriginToUserSpace(firstFrame, aParams);
       shouldPushMask = true;
     }
 
     if (shouldPushMask) {
       if (aParams.layerManager->GetRoot()->GetContentFlags() &
           Layer::CONTENT_COMPONENT_ALPHA) {
         context.PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA,
                                            opacityApplied
@@ -1006,18 +1021,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
   }
 
   /* If this frame has only a trivial clipPath, set up cairo's clipping now so
    * we can just do normal painting and get it clipped appropriately.
    */
   if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
     gfxContextMatrixAutoSaveRestore matSR(&context);
 
-    SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                       offsetToUserSpace);
+    MoveContextOriginToUserSpace(firstFrame, aParams);
 
     MOZ_ASSERT(!maskUsage.shouldApplyClipPath ||
                !maskUsage.shouldApplyBasicShape);
     if (maskUsage.shouldApplyClipPath) {
       clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
     } else {
       nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
     }
@@ -1093,32 +1107,29 @@ nsSVGIntegrationUtils::PaintFilter(const
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
   if (effectProperties.HasInvalidFilter()) {
     return DrawResult::NOT_READY;
   }
 
   gfxContext& context = aParams.ctx;
-  nsPoint offsetToBoundingBox;
-  nsPoint offsetToUserSpace;
 
   gfxContextAutoSaveRestore autoSR(&context);
-  SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                     offsetToUserSpace);
+  EffectOffsets offsets = MoveContextOriginToUserSpace(firstFrame, aParams);
 
   if (opacity != 1.0f) {
     context.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
                                   nullptr, Matrix());
   }
 
   /* Paint the child and apply filters */
   RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
-                                     offsetToUserSpace);
-  nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
+                                     offsets.offsetToUserSpace);
+  nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
   gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
   DrawResult result =
     nsFilterInstance::PaintFilteredFrame(frame, context.GetDrawTarget(),
                                          tm, &callback, &dirtyRegion);
 
   if (opacity != 1.0f) {
     context.PopGroupAndBlend();
   }