Bug 1234485 - Part 12. Extract PaintMaskSurface from GenerateMaskSurface. draft
authorcku <cku@mozilla.com>
Wed, 02 Nov 2016 15:10:46 +0800
changeset 435843 833e117c064861a661004af56c9b15985dd3e9eb
parent 435842 8fa51e31b56cb6949c51877905891b1d28a47dcf
child 435858 7cd22406f83d754c9607b08220d894244dc15b57
push id35137
push userbmo:cku@mozilla.com
push dateWed, 09 Nov 2016 09:16:18 +0000
bugs1234485
milestone52.0a1
Bug 1234485 - Part 12. Extract PaintMaskSurface from GenerateMaskSurface. MozReview-Commit-ID: Bg4Kt6yCtNe
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -424,100 +424,67 @@ HasNonSVGMask(const nsTArray<nsSVGMaskFr
     }
   }
 
   return false;
 }
 
 typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
 
+/**
+ * Paint css-positioned-mask onto a given target(aMaskDT).
+ */
 static DrawResult
-GenerateMaskSurface(const PaintFramesParams& aParams,
-                    float aOpacity, nsStyleContext* aSC,
-                    const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
-                    const nsPoint& aOffsetToUserSpace,
-                    Matrix& aOutMaskTransform,
-                    RefPtr<SourceSurface>& aOutMaskSurface,
-                    bool& aOpacityApplied)
+PaintMaskSurface(const PaintFramesParams& aParams,
+                 DrawTarget* aMaskDT, float aOpacity, nsStyleContext* aSC,
+                 const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+                 const gfxMatrix& aMaskSurfaceMatrix,
+                 const nsPoint& aOffsetToUserSpace)
 {
+  MOZ_ASSERT(aMaskFrames.Length() > 0);
+  MOZ_ASSERT(aMaskDT->GetFormat() == SurfaceFormat::A8);
+
   const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
-  MOZ_ASSERT(aMaskFrames.Length() > 0);
-
   gfxMatrix cssPxToDevPxMatrix =
     nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
 
-  gfxContext& ctx = aParams.ctx;
-
-  // There is only one SVG mask.
-  if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
-    aOpacityApplied = true;
-    aOutMaskSurface =
-      aMaskFrames[0]->GetMaskForMaskedFrame(&ctx, aParams.frame,
-                                            cssPxToDevPxMatrix, aOpacity,
-                                            &aOutMaskTransform,
-                                            svgReset->mMask.mLayers[0].mMaskMode);
-    return DrawResult::SUCCESS;
-  }
-
-  const IntRect& maskSurfaceRect = aParams.maskRect;
-  if (maskSurfaceRect.IsEmpty()) {
-    return DrawResult::SUCCESS;
-  }
-
-  RefPtr<DrawTarget> maskDT =
-      ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
-                                                   SurfaceFormat::A8);
-  if (!maskDT || !maskDT->IsValid()) {
-    return DrawResult::TEMPORARY_ERROR;
-  }
-
-  RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(maskDT);
-  MOZ_ASSERT(maskContext);
-
   nsPresContext* presContext = aParams.frame->PresContext();
   gfxPoint devPixelOffsetToUserSpace =
     nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
                                    presContext->AppUnitsPerDevPixel());
 
-  // Set ctx's matrix on maskContext, offset by the maskSurfaceRect's position.
-  // This makes sure that we combine the masks in device space.
-  gfxMatrix maskSurfaceMatrix =
-    ctx.CurrentMatrix() * gfxMatrix::Translation(-maskSurfaceRect.TopLeft());
-  maskContext->SetMatrix(maskSurfaceMatrix);
-
-  // Set aAppliedOpacity as true only if all mask layers are svg mask.
-  // In this case, we will apply opacity into the final mask surface, so the
-  // caller does not need to apply it again.
-  aOpacityApplied = !HasNonSVGMask(aMaskFrames);
+  RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(aMaskDT);
+  MOZ_ASSERT(maskContext);
+  maskContext->SetMatrix(aMaskSurfaceMatrix);
 
   // Multiple SVG masks interleave with image mask. Paint each layer onto
-  // maskDT one at a time.
+  // aMaskDT one at a time.
   for (int i = aMaskFrames.Length() - 1; i >= 0 ; i--) {
     nsSVGMaskFrame *maskFrame = aMaskFrames[i];
 
     CompositionOp compositionOp = (i == int(aMaskFrames.Length() - 1))
       ? CompositionOp::OP_OVER
       : nsCSSRendering::GetGFXCompositeMode(svgReset->mMask.mLayers[i].mComposite);
 
     // maskFrame != nullptr means we get a SVG mask.
     // maskFrame == nullptr means we get an image mask.
     if (maskFrame) {
       Matrix svgMaskMatrix;
       RefPtr<SourceSurface> svgMask =
         maskFrame->GetMaskForMaskedFrame(maskContext, aParams.frame,
                                          cssPxToDevPxMatrix,
-                                         aOpacityApplied ? aOpacity : 1.0,
+                                         aOpacity,
                                          &svgMaskMatrix,
                                          svgReset->mMask.mLayers[i].mMaskMode);
       if (svgMask) {
         gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
         maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
         Rect drawRect = IntRectToRect(IntRect(IntPoint(0, 0), svgMask->GetSize()));
-        maskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
+        aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
                             drawRect.TopLeft(),
                             DrawOptions(1.0, compositionOp));
       }
     } else {
       gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
       maskContext->Multiply(gfxMatrix::Translation(-devPixelOffsetToUserSpace));
       nsRenderingContext rc(maskContext);
@@ -534,16 +501,77 @@ GenerateMaskSurface(const PaintFramesPar
         nsCSSRendering::PaintBackgroundWithSC(params, aSC,
                                               *aParams.frame->StyleBorder());
       if (result != DrawResult::SUCCESS) {
         return result;
       }
     }
   }
 
+  return DrawResult::SUCCESS;
+}
+
+static DrawResult
+CreateAndPaintMaskSurface(const PaintFramesParams& aParams,
+                          float aOpacity, nsStyleContext* aSC,
+                          const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+                          const nsPoint& aOffsetToUserSpace,
+                          Matrix& aOutMaskTransform,
+                          RefPtr<SourceSurface>& aOutMaskSurface,
+                          bool& aOpacityApplied)
+{
+  const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
+  MOZ_ASSERT(aMaskFrames.Length() > 0);
+
+  gfxContext& ctx = aParams.ctx;
+
+  // There is only one SVG mask.
+  if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
+    gfxMatrix cssPxToDevPxMatrix =
+    nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(aParams.frame);
+
+    aOpacityApplied = true;
+    aOutMaskSurface =
+      aMaskFrames[0]->GetMaskForMaskedFrame(&ctx, aParams.frame,
+                                            cssPxToDevPxMatrix, aOpacity,
+                                            &aOutMaskTransform,
+                                            svgReset->mMask.mLayers[0].mMaskMode);
+    return DrawResult::SUCCESS;
+  }
+
+  const IntRect& maskSurfaceRect = aParams.maskRect;
+  if (maskSurfaceRect.IsEmpty()) {
+    return DrawResult::SUCCESS;
+  }
+
+  RefPtr<DrawTarget> maskDT =
+      ctx.GetDrawTarget()->CreateSimilarDrawTarget(maskSurfaceRect.Size(),
+                                                   SurfaceFormat::A8);
+  if (!maskDT || !maskDT->IsValid()) {
+    return DrawResult::TEMPORARY_ERROR;
+  }
+
+  // Set aAppliedOpacity as true only if all mask layers are svg mask.
+  // In this case, we will apply opacity into the final mask surface, so the
+  // caller does not need to apply it again.
+  aOpacityApplied = !HasNonSVGMask(aMaskFrames);
+
+  // Set context's matrix on maskContext, offset by the maskSurfaceRect's
+  // position. This makes sure that we combine the masks in device space.
+  gfxMatrix maskSurfaceMatrix =
+    ctx.CurrentMatrix() * gfxMatrix::Translation(-aParams.maskRect.TopLeft());
+
+  DrawResult result = PaintMaskSurface(aParams, maskDT,
+                                       aOpacityApplied ? aOpacity : 1.0,
+                                       aSC, aMaskFrames, maskSurfaceMatrix,
+                                       aOffsetToUserSpace);
+  if (result != DrawResult::SUCCESS) {
+    return result;
+  }
+
   aOutMaskTransform = ToMatrix(maskSurfaceMatrix);
   if (!aOutMaskTransform.Invert()) {
     return DrawResult::SUCCESS;
   }
 
   aOutMaskSurface = maskDT->Snapshot();
   return DrawResult::SUCCESS;
 }
@@ -752,60 +780,44 @@ nsSVGIntegrationUtils::IsMaskResourceRea
 DrawResult
 nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
 {
   MaskUsage maskUsage;
   DetermineMaskUsage(aParams.frame, aParams.handleOpacity, maskUsage);
   MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
 
   nsIFrame* frame = aParams.frame;
-  DrawResult result = DrawResult::SUCCESS;
   if (!ValidateSVGFrame(frame)) {
-    return result;
+    return DrawResult::SUCCESS;
   }
 
   if (maskUsage.opacity == 0.0f) {
     return DrawResult::SUCCESS;
   }
 
   gfxContext& ctx = aParams.ctx;
 
-  Matrix maskTransform;
-  RefPtr<SourceSurface> maskSurface;
-
   gfxContextMatrixAutoSaveRestore matSR(&ctx);
 
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
   nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
-  bool opacityApplied = false;
+  bool opacityApplied = !HasNonSVGMask(maskFrames);
 
   nsPoint offsetToBoundingBox;
   nsPoint offsetToUserSpace;
   SetupContextMatrix(frame, aParams, offsetToBoundingBox,
                      offsetToUserSpace, false);
-  result = GenerateMaskSurface(aParams, maskUsage.opacity,
-                               firstFrame->StyleContext(),
-                               maskFrames, offsetToUserSpace,
-                               maskTransform, maskSurface, opacityApplied);
-  if (!maskSurface) {
-    // Entire surface is clipped out.
-    return result;
-  }
 
-  ctx.Multiply(ThebesMatrix(maskTransform));
-
-  DrawTarget* target = ctx.GetDrawTarget();
-  MOZ_ASSERT(target->GetFormat() == SurfaceFormat::A8);
-  Rect drawingRect(Point(0, 0), Size(target->GetSize()));
-  target->DrawSurface(maskSurface, drawingRect, drawingRect);
-
-  return result;
+  return PaintMaskSurface(aParams, ctx.GetDrawTarget(),
+                            opacityApplied ? maskUsage.opacity : 1.0,
+                            firstFrame->StyleContext(), maskFrames,
+                            ctx.CurrentMatrix(), offsetToUserSpace);
 }
 
 DrawResult
 nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
 {
   MOZ_ASSERT(UsingMaskOrClipPathForFrame(aParams.frame),
              "Should not use this method when no mask or clipPath effect"
              "on this frame");
@@ -871,20 +883,21 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
     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, false);
-      result = GenerateMaskSurface(aParams, maskUsage.opacity,
-                                  firstFrame->StyleContext(),
-                                  maskFrames, offsetToUserSpace,
-                                  maskTransform, maskSurface, opacityApplied);
+      result = CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
+                                         firstFrame->StyleContext(),
+                                         maskFrames, offsetToUserSpace,
+                                         maskTransform, maskSurface,
+                                         opacityApplied);
       if (!maskSurface) {
         // Entire surface is clipped out.
         return result;
       }
     }
 
     if (maskUsage.shouldGenerateClipMaskLayer) {
       matSR.Restore();