Bug 1304011 - Part 4. For css-mask, compute frame offset by the current frame. draft
authorcku <cku@mozilla.com>
Thu, 22 Sep 2016 13:38:55 +0800
changeset 417397 c0ba4ff3ac1c1fd5e6ee049b52853e4d690186c2
parent 417386 e8d114d2526d9a0b0aef1bc23ddf3226516a2eef
child 417398 2fd9df9b1b7b2732461290a871def7f1b511efd8
push id30394
push userbmo:cku@mozilla.com
push dateSat, 24 Sep 2016 19:14:17 +0000
bugs1304011
milestone52.0a1
Bug 1304011 - Part 4. For css-mask, compute frame offset by the current frame. MozReview-Commit-ID: K6ZUoiA9jrC
gfx/thebes/gfxContext.h
layout/svg/nsSVGIntegrationUtils.cpp
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -614,16 +614,17 @@ public:
         mContext = aContext;
         mMatrix = aContext->CurrentMatrix();
     }
 
     void Restore()
     {
         if (mContext) {
             mContext->SetMatrix(mMatrix);
+            mContext = nullptr;
         }
     }
 
     const gfxMatrix& Matrix()
     {
         MOZ_ASSERT(mContext, "mMatrix doesn't contain a useful matrix");
         return mMatrix;
     }
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -860,47 +860,67 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
   }
 
   bool shouldGenerateMask = (opacity != 1.0f || shouldGenerateClipMaskLayer ||
                              shouldGenerateMaskLayer);
 
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
   if (shouldGenerateMask) {
-    gfxContextMatrixAutoSaveRestore save(&context);
-    SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
-                       offsetToUserSpace, true);
+    gfxContextMatrixAutoSaveRestore matSR;
+
     Matrix maskTransform;
     RefPtr<SourceSurface> maskSurface;
+
     if (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, true);
       result = GenerateMaskSurface(aParams, opacity,
                                   firstFrame->StyleContext(),
                                   maskFrames, offsetToUserSpace,
                                   maskTransform, maskSurface);
-    }
-
-    if (shouldGenerateMaskLayer && !maskSurface) {
-      // Entire surface is clipped out.
-      return result;
+      context.PopClip();
+      if (!maskSurface) {
+        // Entire surface is clipped out.
+        return result;
+      }
     }
 
     if (shouldGenerateClipMaskLayer) {
+      matSR.Restore();
+      matSR.SetContext(&context);
+
+      SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
+                         offsetToUserSpace, true);
       Matrix clippedMaskTransform;
       RefPtr<SourceSurface> clipMaskSurface =
         clipPathFrame->GetClipMask(context, frame, cssPxToDevPxMatrix,
                                    &clippedMaskTransform, maskSurface,
                                    maskTransform, &result);
+      context.PopClip();
 
       if (clipMaskSurface) {
         maskSurface = clipMaskSurface;
         maskTransform = clippedMaskTransform;
       }
     }
-    // Pop the clip pushed in SetupContextMatrix.
-    context.PopClip();
+
+    // opacity != 1.0f.
+    if (!shouldGenerateClipMaskLayer && !shouldGenerateMaskLayer) {
+      MOZ_ASSERT(opacity != 1.0f);
+
+      matSR.SetContext(&context);
+      SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
+                         offsetToUserSpace, true);
+    }
 
     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 (shouldApplyClipPath || shouldApplyBasicShape) {
@@ -926,16 +946,22 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
   basic->SetTarget(oldCtx);
 
   if (shouldApplyClipPath || shouldApplyBasicShape) {
     context.Restore();
   }
 
   if (shouldGenerateMask) {
     target->PopGroupAndBlend();
+
+    if (!shouldGenerateClipMaskLayer && !shouldGenerateMaskLayer) {
+      MOZ_ASSERT(opacity != 1.0f);
+      // Pop the clip push by SetupContextMatrix
+      context.PopClip();
+    }
   }
 
   if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
     MOZ_ASSERT(target != &aParams.ctx);
     BlendToTarget(aParams, target, targetOffset);
   }
 
   return result;
@@ -975,17 +1001,17 @@ nsSVGIntegrationUtils::PaintFilter(const
   gfxContext& context = aParams.ctx;
   nsPoint offsetToBoundingBox;
   nsPoint offsetToUserSpace;
 
   // These are used if we require a temporary surface for a custom blend mode.
   // Clip the source context first, so that we can generate a smaller temporary
   // surface. (Since we will clip this context in SetupContextMatrix, a pair
   // of save/restore is needed.)
-  context.Save();
+  gfxContextAutoSaveRestore autoSR(&context);
   SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
                      offsetToUserSpace, true);
   IntPoint targetOffset;
   RefPtr<gfxContext> target =
     (aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
     ? RefPtr<gfxContext>(&aParams.ctx).forget()
     : CreateBlendTarget(aParams, targetOffset);
   if (!target) {
@@ -1010,17 +1036,16 @@ nsSVGIntegrationUtils::PaintFilter(const
     target->PopGroupAndBlend();
   }
 
   if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
     MOZ_ASSERT(target != &aParams.ctx);
     BlendToTarget(aParams, target, targetOffset);
   }
 
-  context.Restore();
   return result;
 }
 
 gfxMatrix
 nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(nsIFrame* aNonSVGFrame)
 {
   int32_t appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
   float devPxPerCSSPx =