Bug 1313898 - Part 2. Paint non-trivial clip-path onto mask layer. draft
authorcku <cku@mozilla.com>
Fri, 04 Nov 2016 14:48:11 +0800
changeset 440217 5a11bcc7a13602d8d4b13d09c2960e921c814e6f
parent 440216 e1d8172b0c34077cbc814f1cebe059a2a77e85ae
child 440218 1c27edc0c02d958c57d28edd6fcf7788838f620d
child 440317 157d1a8bc6dc03cfd7d14a92a2b77a160f2d6801
push id36178
push userbmo:cku@mozilla.com
push dateThu, 17 Nov 2016 04:49:39 +0000
bugs1313898
milestone53.0a1
Bug 1313898 - Part 2. Paint non-trivial clip-path onto mask layer. MozReview-Commit-ID: HJUwhqsJ42M
layout/base/nsDisplayList.cpp
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -7122,20 +7122,23 @@ bool nsDisplayMask::ShouldPaintOnMaskLay
 {
   if (!aManager->IsCompositingCheap()) {
     return false;
   }
 
   nsSVGUtils::MaskUsage maskUsage;
   nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
 
-  if (!maskUsage.shouldGenerateMaskLayer ||
-      maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
-      maskUsage.shouldApplyBasicShape ||
-      maskUsage.shouldGenerateClipMaskLayer) {
+  if (!maskUsage.shouldGenerateMaskLayer &&
+      !maskUsage.shouldGenerateClipMaskLayer) {
+    return false;
+  }
+
+  if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
+      maskUsage.shouldApplyBasicShape) {
     return false;
   }
 
   if (!nsSVGIntegrationUtils::IsMaskResourceReady(mFrame)) {
     return false;
   }
 
   // XXX temporary disable drawing SVG mask onto mask layer before bug 1313877
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -473,20 +473,19 @@ PaintMaskSurface(const PaintFramesParams
                                          cssPxToDevPxMatrix,
                                          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()));
         aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
-                            drawRect.TopLeft(),
-                            DrawOptions(1.0, compositionOp));
+                             Point(0, 0),
+                             DrawOptions(1.0, compositionOp));
       }
     } else {
       gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
       maskContext->Multiply(gfxMatrix::Translation(-devPixelOffsetToUserSpace));
       nsRenderingContext rc(maskContext);
       nsCSSRendering::PaintBGParams  params =
         nsCSSRendering::PaintBGParams::ForSingleLayer(*presContext,
@@ -699,47 +698,100 @@ nsSVGIntegrationUtils::IsMaskResourceRea
 }
 
 DrawResult
 nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
 {
   nsSVGUtils::MaskUsage maskUsage;
   nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
                                  maskUsage);
-  MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer);
+  MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer ||
+             maskUsage.shouldGenerateClipMaskLayer);
 
   nsIFrame* frame = aParams.frame;
   if (!ValidateSVGFrame(frame)) {
     return DrawResult::SUCCESS;
   }
 
   if (maskUsage.opacity == 0.0f) {
     return DrawResult::SUCCESS;
   }
 
   gfxContext& ctx = aParams.ctx;
-
-  gfxContextMatrixAutoSaveRestore matSR(&ctx);
-
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
-  nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
-  bool opacityApplied = !HasNonSVGMask(maskFrames);
 
+  DrawResult result = DrawResult::SUCCESS;
   nsPoint offsetToBoundingBox;
   nsPoint offsetToUserSpace;
-  SetupContextMatrix(frame, aParams, offsetToBoundingBox,
-                     offsetToUserSpace, false);
+  gfxContextMatrixAutoSaveRestore matSR;
+  DrawTarget* target = ctx.GetDrawTarget();
+
+  // Paint mask onto ctx.
+  if (maskUsage.shouldGenerateMaskLayer) {
+    matSR.SetContext(&ctx);
+
+    SetupContextMatrix(frame, aParams, offsetToBoundingBox,
+                       offsetToUserSpace, false);
+    nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
+    bool opacityApplied = !HasNonSVGMask(maskFrames);
+    result = PaintMaskSurface(aParams, target,
+                              opacityApplied ? maskUsage.opacity : 1.0,
+                              firstFrame->StyleContext(), maskFrames,
+                              ctx.CurrentMatrix(), offsetToUserSpace);
+    if (result != DrawResult::SUCCESS) {
+      return result;
+    }
+  }
+
+  // Paint clip-path onto ctx.
+  if (maskUsage.shouldGenerateClipMaskLayer) {
+    matSR.Restore();
+    matSR.SetContext(&ctx);
+
+    SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
+                       offsetToUserSpace, false);
+    Matrix clipMaskTransform;
+    gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(frame);
 
-  return PaintMaskSurface(aParams, ctx.GetDrawTarget(),
-                            opacityApplied ? maskUsage.opacity : 1.0,
-                            firstFrame->StyleContext(), maskFrames,
-                            ctx.CurrentMatrix(), offsetToUserSpace);
+    bool isOK = true;
+    nsSVGClipPathFrame *clipPathFrame =
+      effectProperties.GetClipPathFrame(&isOK);
+    // XXX Bug 1317636. Split nsSVGClipPathFrame::GetClipMask into two
+    // functions:
+    // 1. nsSVGClipPathFrame::CreateClipMask
+    //    Create an A8 surface with right size for painting clip-path mask.
+    // 2. nsSVGClipPathFrame::PaintClipMask
+    //    Paint the content of clip-path _direct_ onto a given A8 surface.
+    // With this change, we can skip one extra draw call
+    // (DrawTarget::MaskSurface) bellow.
+    RefPtr<SourceSurface> clipMaskSurface =
+      clipPathFrame->GetClipMask(ctx, frame, cssPxToDevPxMatrix,
+                                 &clipMaskTransform, nullptr,
+                                 ToMatrix(ctx.CurrentMatrix()), &result);
+
+    if (clipMaskSurface) {
+      gfxContextMatrixAutoSaveRestore matRestore(&ctx);
+      ctx.Multiply(ThebesMatrix(clipMaskTransform));
+      CompositionOp op = maskUsage.shouldGenerateMaskLayer
+                         ? CompositionOp::OP_IN : CompositionOp::OP_OVER;
+      target->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)),
+                          clipMaskSurface,
+                          Point(),
+                          DrawOptions(1.0, op));
+    } else {
+      // Either entire surface is clipped out, or gfx buffer allocation
+      // failure in nsSVGClipPathFrame::GetClipMask.
+      return result;
+    }
+  }
+
+  return result;
 }
 
 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");
@@ -823,25 +875,25 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
     }
 
     if (maskUsage.shouldGenerateClipMaskLayer) {
       matSR.Restore();
       matSR.SetContext(&context);
 
       SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
                          offsetToUserSpace, false);
-      Matrix clippedMaskTransform;
+      Matrix clipMaskTransform;
       RefPtr<SourceSurface> clipMaskSurface =
         clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
-                                   &clippedMaskTransform, maskSurface,
+                                   &clipMaskTransform, maskSurface,
                                    maskTransform, &result);
 
       if (clipMaskSurface) {
         maskSurface = clipMaskSurface;
-        maskTransform = clippedMaskTransform;
+        maskTransform = clipMaskTransform;
       } else {
         // Either entire surface is clipped out, or gfx buffer allocation
         // failure in nsSVGClipPathFrame::GetClipMask.
         return result;
       }
     }
 
     // opacity != 1.0f.