Bug 1228280 - Part 2. Change the parameters of nsSVGIntegrationUtils::PaintFramesWithEffects; draft
authorCJKu <cku@mozilla.com>
Thu, 19 May 2016 12:40:45 +0800
changeset 368597 75d1d38339a51967c6c75615b74e24a8fe017036
parent 368596 7735670c60d9ccf56762d6779cc57f6dd83dacd3
child 368598 c2e590bac05459b3657f1dce07f4b2b44bbe9430
push id18601
push usercku@mozilla.com
push dateThu, 19 May 2016 04:45:09 +0000
bugs1228280
milestone49.0a1
Bug 1228280 - Part 2. Change the parameters of nsSVGIntegrationUtils::PaintFramesWithEffects; MozReview-Commit-ID: FJjPTwwb4HR
layout/base/nsDisplayList.cpp
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGIntegrationUtils.h
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -6665,20 +6665,22 @@ nsDisplaySVGEffects::HitTest(nsDisplayLi
 }
 
 void
 nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
                                   nsRenderingContext* aCtx,
                                   LayerManager* aManager)
 {
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
-  nsSVGIntegrationUtils::PaintFramesWithEffects(*aCtx->ThebesContext(), mFrame,
-                                                mVisibleRect,
-                                                borderArea,
-                                                aBuilder, aManager);
+  nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
+                                                  mFrame,  mVisibleRect,
+                                                  borderArea, aBuilder,
+                                                  aManager);
+
+  nsSVGIntegrationUtils::PaintFramesWithEffects(params);
 }
 
 LayerState
 nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters)
 {
   return LAYER_SVG_EFFECTS;
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -405,124 +405,119 @@ public:
 
 private:
   nsDisplayListBuilder* mBuilder;
   LayerManager* mLayerManager;
   nsPoint mOffset;
 };
 
 void
-nsSVGIntegrationUtils::PaintFramesWithEffects(gfxContext& aContext,
-                                              nsIFrame* aFrame,
-                                              const nsRect& aDirtyRect,
-                                              const nsRect& aBorderArea,
-                                              nsDisplayListBuilder* aBuilder,
-                                              LayerManager *aLayerManager)
+nsSVGIntegrationUtils::PaintFramesWithEffects(const PaintFramesParams& aParams)
 {
 #ifdef DEBUG
-  NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
+  NS_ASSERTION(!(aParams.frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
                (NS_SVGDisplayListPaintingEnabled() &&
-                !(aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)),
+                !(aParams.frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)),
                "Should not use nsSVGIntegrationUtils on this SVG frame");
 #endif
 
   /* SVG defines the following rendering model:
    *
    *  1. Render geometry
    *  2. Apply filter
    *  3. Apply clipping, masking, group opacity
    *
    * We follow this, but perform a couple of optimizations:
    *
    * + Use cairo's clipPath when representable natively (single object
    *   clip region).
    *
    * + Merge opacity and masking if both used together.
    */
-
-  const nsIContent* content = aFrame->GetContent();
-  bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
+  nsIFrame* frame = aParams.frame;
+  const nsIContent* content = frame->GetContent();
+  bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
   if (hasSVGLayout) {
-    nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
-    if (!svgChildFrame || !aFrame->GetContent()->IsSVGElement()) {
+    nsISVGChildFrame *svgChildFrame = do_QueryFrame(frame);
+    if (!svgChildFrame || !frame->GetContent()->IsSVGElement()) {
       NS_ASSERTION(false, "why?");
       return;
     }
     if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
       return; // The SVG spec says not to draw _anything_
     }
   }
 
-  float opacity = aFrame->StyleEffects()->mOpacity;
+  float opacity = frame->StyleEffects()->mOpacity;
   if (opacity == 0.0f) {
     return;
   }
   if (opacity != 1.0f &&
-      hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
+      hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(frame)) {
     opacity = 1.0f;
   }
 
   /* Properties are added lazily and may have been removed by a restyle,
      so make sure all applicable ones are set again. */
   nsIFrame* firstFrame =
-    nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
+    nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
   bool isOK = effectProperties.HasNoFilterOrHasValidFilter();
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
 
   bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
-
-  DrawTarget* drawTarget = aContext.GetDrawTarget();
-  gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&aContext);
+  gfxContext& context = aParams.ctx;
+  DrawTarget* drawTarget = context.GetDrawTarget();
+  gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
 
   nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
-  nsPoint offsetToBoundingBox = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset;
+  nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
   if (!firstFrame->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. */
     offsetToBoundingBox = nsPoint(
-      aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
-      aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
+      frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
+      frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
   }
 
   // After applying only "offsetToBoundingBox", aCtx would have its origin at
-  // the top left corner of aFrame's bounding box (over all continuations).
+  // 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 aCtx 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);
+  gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
   nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
                       nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
   nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace;
 
   NS_ASSERTION(hasSVGLayout || offsetToBoundingBox == offsetToUserSpace,
                "For non-SVG frames there shouldn't be any additional offset");
 
   gfxPoint devPixelOffsetToUserSpace =
     nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
-                                   aFrame->PresContext()->AppUnitsPerDevPixel());
-  aContext.SetMatrix(aContext.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
+                                   frame->PresContext()->AppUnitsPerDevPixel());
+  context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
 
-  gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame);
+  gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
 
   const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
   // Keep moving forward even if svgMaskFrame is nullptr or isOK is false.
   // This source is not a svg mask, but it still can be a correct mask image.
   nsSVGMaskFrame *svgMaskFrame = effectProperties.GetMaskFrame(&isOK);
 
   // These are used if we require a temporary surface for a custom blend mode.
-  RefPtr<gfxContext> target = &aContext;
+  RefPtr<gfxContext> target = &aParams.ctx;
   IntPoint targetOffset;
 
   // hasMaskToDraw is true means we have at least one drawable mask resource.
   // We need to apply mask only if hasMaskToDraw is true.
   bool hasMaskToDraw = (svgMaskFrame != nullptr);
   if (!hasMaskToDraw) {
     NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
       if (!svgReset->mMask.mLayers[i].mImage.IsEmpty()) {
@@ -531,121 +526,123 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       }
     }
   }
 
   bool complexEffects = false;
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
   if (opacity != 1.0f ||  (clipPathFrame && !isTrivialClip)
-      || aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
+      || frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
       || hasMaskToDraw) {
     complexEffects = true;
 
-    aContext.Save();
+    context.Save();
     nsRect clipRect =
-      aFrame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
-    aContext.Clip(NSRectToSnappedRect(clipRect,
-                                  aFrame->PresContext()->AppUnitsPerDevPixel(),
+      frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
+    context.Clip(NSRectToSnappedRect(clipRect,
+                                  frame->PresContext()->AppUnitsPerDevPixel(),
                                   *drawTarget));
 
     Matrix maskTransform;
     RefPtr<SourceSurface> maskSurface;
     if (svgMaskFrame) {
       // Generate maskSurface from a SVG mask.
-      maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&aContext,
-                                                        aFrame,
+      maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&context,
+                                                        aParams.frame,
                                                         cssPxToDevPxMatrix,
                                                         opacity,
                                                         &maskTransform,
                                                         svgReset->mMask.mLayers[0].mMaskMode);
     } else if (hasMaskToDraw) {
       // Create maskSuface.
-      gfxRect clipRect = aContext.GetClipExtents();
+      gfxRect clipRect = context.GetClipExtents();
       {
-        gfxContextMatrixAutoSaveRestore matRestore(&aContext);
+        gfxContextMatrixAutoSaveRestore matRestore(&context);
 
-        aContext.SetMatrix(gfxMatrix());
-        clipRect = aContext.GetClipExtents();
+        context.SetMatrix(gfxMatrix());
+        clipRect = context.GetClipExtents();
       }
       IntRect drawRect = RoundedOut(ToRect(clipRect));
 
       // Mask composition result on CoreGraphic::A8 surface is not correct
       // when mask-mode is not add(source over). Switch to skia when CG backend
       // detected.
       RefPtr<DrawTarget> targetDT =
-        (aContext.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
+        (context.GetDrawTarget()->GetBackendType() == BackendType::COREGRAPHICS) ?
           Factory::CreateDrawTarget(BackendType::SKIA, drawRect.Size(),
                                     SurfaceFormat::A8) :
-          aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
+          context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(),
                                                             SurfaceFormat::A8);
 
       if (!targetDT || !targetDT->IsValid()) {
-        aContext.Restore();
+        context.Restore();
         return;
       }
 
       RefPtr<gfxContext> target = gfxContext::ForDrawTarget(targetDT);
       MOZ_ASSERT(target); // alrady checked the draw target above
       target->SetMatrix(matrixAutoSaveRestore.Matrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
 
       // Compose all mask-images onto maskSurface.
       nsRenderingContext rc(target);
       nsCSSRendering::PaintBGParams params =
-        nsCSSRendering::PaintBGParams::ForAllLayers(*aFrame->PresContext(), rc,
-                                                    aDirtyRect, aBorderArea,
-                                                    aFrame,
-                                                    aBuilder->GetBackgroundPaintFlags() |
+        nsCSSRendering::PaintBGParams::ForAllLayers(*aParams.frame->PresContext(),
+                                                    rc,
+                                                    aParams.dirtyRect,
+                                                    aParams.borderArea,
+                                                    aParams.frame,
+                                                    aParams.builder->GetBackgroundPaintFlags() |
                                                     nsCSSRendering::PAINTBG_MASK_IMAGE);
 
       // FIXME We should use the return value, see bug 1258510.
       Unused << nsCSSRendering::PaintBackgroundWithSC(params,
                                                       firstFrame->StyleContext(),
-                                                      *aFrame->StyleBorder());
+                                                      *frame->StyleBorder());
       maskSurface = targetDT->Snapshot();
 
       // Compute mask transform.
-      Matrix mat = ToMatrix(aContext.CurrentMatrix());
+      Matrix mat = ToMatrix(context.CurrentMatrix());
       mat.Invert();
       maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
     }
 
     if (hasMaskToDraw && !maskSurface) {
       // Entire surface is clipped out.
-      aContext.Restore();
+      context.Restore();
       return;
     }
 
-    if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
+    if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
       // Create a temporary context to draw to so we can blend it back with
       // another operator.
       gfxRect clipRect;
       {
-        gfxContextMatrixAutoSaveRestore matRestore(&aContext);
+        gfxContextMatrixAutoSaveRestore matRestore(&context);
 
-        aContext.SetMatrix(gfxMatrix());
-        clipRect = aContext.GetClipExtents();
+        context.SetMatrix(gfxMatrix());
+        clipRect = context.GetClipExtents();
       }
 
       IntRect drawRect = RoundedOut(ToRect(clipRect));
 
-      RefPtr<DrawTarget> targetDT = aContext.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
+      RefPtr<DrawTarget> targetDT = context.GetDrawTarget()->CreateSimilarDrawTarget(drawRect.Size(), SurfaceFormat::B8G8R8A8);
       if (!targetDT || !targetDT->IsValid()) {
-        aContext.Restore();
+        context.Restore();
         return;
       }
       target = gfxContext::ForDrawTarget(targetDT);
       MOZ_ASSERT(target); // already checked the draw target above
-      target->SetMatrix(aContext.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
+      target->SetMatrix(context.CurrentMatrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
       targetOffset = drawRect.TopLeft();
     }
 
     if (clipPathFrame && !isTrivialClip) {
       Matrix clippedMaskTransform;
-      RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(aContext, aFrame, cssPxToDevPxMatrix,
+      RefPtr<SourceSurface> clipMaskSurface = clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
                                                                          &clippedMaskTransform, maskSurface, maskTransform);
 
       if (clipMaskSurface) {
         maskSurface = clipMaskSurface;
         maskTransform = clippedMaskTransform;
       }
     }
 
@@ -653,67 +650,68 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
     }
   }
 
   /* 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 (clipPathFrame && isTrivialClip) {
-    aContext.Save();
-    clipPathFrame->ApplyClipPath(aContext, aFrame, cssPxToDevPxMatrix);
+    context.Save();
+    clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
   } else if (!clipPathFrame && svgReset->HasClipPath()) {
-    aContext.Save();
-    nsCSSClipPathInstance::ApplyBasicShapeClip(aContext, aFrame);
+    context.Save();
+    nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
   }
 
   /* Paint the child */
   if (effectProperties.HasValidFilter()) {
-    RegularFramePaintCallback callback(aBuilder, aLayerManager,
+    RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
                                        offsetToUserSpace);
 
-    nsRegion dirtyRegion = aDirtyRect - offsetToBoundingBox;
-    gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aFrame);
-    nsFilterInstance::PaintFilteredFrame(aFrame, target->GetDrawTarget(),
+    nsRegion dirtyRegion = aParams.dirtyRect - offsetToBoundingBox;
+    gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(frame);
+    nsFilterInstance::PaintFilteredFrame(frame, target->GetDrawTarget(),
                                          tm, &callback, &dirtyRegion);
   } else {
     target->SetMatrix(matrixAutoSaveRestore.Matrix());
-    BasicLayerManager* basic = static_cast<BasicLayerManager*>(aLayerManager);
+    BasicLayerManager* basic = static_cast<BasicLayerManager*>(aParams.layerManager);
     RefPtr<gfxContext> oldCtx = basic->GetTarget();
     basic->SetTarget(target);
-    aLayerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
+    aParams.layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
+                                          aParams.builder);
     basic->SetTarget(oldCtx);
   }
 
   if ((clipPathFrame && isTrivialClip) ||
       (!clipPathFrame && svgReset->HasClipPath())) {
-    aContext.Restore();
+    context.Restore();
   }
 
   /* No more effects, we're done. */
   if (!complexEffects) {
     return;
   }
 
   if (opacity != 1.0f || hasMaskToDraw || (clipPathFrame && !isTrivialClip)) {
     target->PopGroupAndBlend();
   }
 
-  if (aFrame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
+  if (frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
     RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
     target = nullptr;
     RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();
 
-    aContext.SetMatrix(gfxMatrix()); // This will be restored right after.
+    context.SetMatrix(gfxMatrix()); // This will be restored right after.
     RefPtr<gfxPattern> pattern = new gfxPattern(targetSurf, Matrix::Translation(targetOffset.x, targetOffset.y));
-    aContext.SetPattern(pattern);
-    aContext.Paint();
+    context.SetPattern(pattern);
+    context.Paint();
   }
 
-  aContext.Restore();
+  context.Restore();
 }
 
 gfxMatrix
 nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame)
 {
   int32_t appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
   float devPxPerCSSPx =
     1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -118,25 +118,39 @@ public:
 
   /**
    * Returns true if the given point is not clipped out by effects.
    * @param aPt in appunits relative to aFrame
    */
   static bool
   HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt);
 
+  struct PaintFramesParams {
+    gfxContext& ctx;
+    nsIFrame* frame;
+    const nsRect& dirtyRect;
+    const nsRect& borderArea;
+    nsDisplayListBuilder* builder;
+    mozilla::layers::LayerManager* layerManager;
+    explicit PaintFramesParams(gfxContext& aCtx, nsIFrame* aFrame,
+                               const nsRect& aDirtyRect,
+                               const nsRect& aBorderArea,
+                               nsDisplayListBuilder* aBuilder,
+                               mozilla::layers::LayerManager* aLayerManager)
+      : ctx(aCtx), frame(aFrame), dirtyRect(aDirtyRect),
+        borderArea(aBorderArea), builder(aBuilder),
+        layerManager(aLayerManager)
+    { }
+  };
+
   /**
    * Paint non-SVG frame with SVG effects.
    */
   static void
-  PaintFramesWithEffects(gfxContext& aCtx,
-                         nsIFrame* aFrame, const nsRect& aDirtyRect,
-                         const nsRect& aBorderArea,
-                         nsDisplayListBuilder* aBuilder,
-                         mozilla::layers::LayerManager* aManager);
+  PaintFramesWithEffects(const PaintFramesParams& aParams);
 
   /**
    * SVG frames expect to paint in SVG user units, which are equal to CSS px
    * units. This method provides a transform matrix to multiply onto a
    * gfxContext's current transform to convert the context's current units from
    * its usual dev pixels to SVG user units/CSS px to keep the SVG code happy.
    */
   static gfxMatrix