Bug 1251115 - Fix incorrect rendering result while mask path is not resolvable. draft
authorCJKu <cku@mozilla.com>
Thu, 25 Feb 2016 14:53:21 +0800
changeset 334418 5d8fd29760a3c9114c40dfdc329f009d69e7c157
parent 332881 789a12291942763bc1e3a89f97e0b82dc1c9d00b
child 514910 58dafcf845bd9220f0e4d44ae845d17484314eb5
push id11548
push usercku@mozilla.com
push dateThu, 25 Feb 2016 06:54:37 +0000
bugs1251115
milestone47.0a1
Bug 1251115 - Fix incorrect rendering result while mask path is not resolvable. MozReview-Commit-ID: IGo30BOolRB
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -510,46 +510,58 @@ nsSVGIntegrationUtils::PaintFramesWithEf
 
   gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame);
 
   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);
 
-  bool complexEffects = false;
-  bool hasValidLayers = svgReset->mMask.HasLayerWithImage();
-
   // These are used if we require a temporary surface for a custom blend mode.
   RefPtr<gfxContext> target = &aContext;
   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 ? true : false;
+  if (!hasMaskToDraw) {
+    NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
+      if (svgReset->mMask.mLayers[i].mImage.IsComplete()) {
+        hasMaskToDraw = true;
+        break;
+      }
+    }
+  }
+
+  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->StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL
-      || svgMaskFrame || hasValidLayers) {
+      || hasMaskToDraw) {
     complexEffects = true;
 
     aContext.Save();
     nsRect clipRect =
       aFrame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
     aContext.Clip(NSRectToSnappedRect(clipRect,
                                   aFrame->PresContext()->AppUnitsPerDevPixel(),
                                   *drawTarget));
 
     Matrix maskTransform;
     RefPtr<SourceSurface> maskSurface;
     if (svgMaskFrame) {
+      // Generate maskSurface from a SVG mask.
       maskSurface = svgMaskFrame->GetMaskForMaskedFrame(&aContext,
                                                      aFrame,
                                                      cssPxToDevPxMatrix,
                                                      opacity,
                                                      &maskTransform);
-    } else if (hasValidLayers) {
+    } else if (hasMaskToDraw) {
+      // Create maskSuface.
       gfxRect clipRect = aContext.GetClipExtents();
       {
         gfxContextMatrixAutoSaveRestore matRestore(&aContext);
 
         aContext.SetMatrix(gfxMatrix());
         clipRect = aContext.GetClipExtents();
       }
       IntRect drawRect = RoundedOut(ToRect(clipRect));
@@ -557,17 +569,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       if (!targetDT) {
         aContext.Restore();
         return;
       }
 
       RefPtr<gfxContext> target = new gfxContext(targetDT);
       target->SetMatrix(matrixAutoSaveRestore.Matrix() * gfxMatrix::Translation(-drawRect.TopLeft()));
 
-      // Generate mask surface.
+      // Compose all mask-images onto maskSurface.
       uint32_t flags = aBuilder->GetBackgroundPaintFlags() |
                        nsCSSRendering::PAINTBG_MASK_IMAGE;
       nsRenderingContext rc(target);
       nsCSSRendering::PaintBackgroundWithSC(aFrame->PresContext(),
                                             rc,
                                             aFrame,
                                             aDirtyRect,
                                             aBorderArea,
@@ -579,17 +591,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       maskSurface = targetDT->Snapshot();
 
       // Compute mask transform.
       Matrix mat = ToMatrix(aContext.CurrentMatrix());
       mat.Invert();
       maskTransform = Matrix::Translation(drawRect.x, drawRect.y) * mat;
     }
 
-    if ((svgMaskFrame || hasValidLayers) && !maskSurface) {
+    if (hasMaskToDraw && !maskSurface) {
       // Entire surface is clipped out.
       aContext.Restore();
       return;
     }
 
     if (aFrame->StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
       // Create a temporary context to draw to so we can blend it back with
       // another operator.
@@ -619,18 +631,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
                                                                          &clippedMaskTransform, maskSurface, maskTransform);
 
       if (clipMaskSurface) {
         maskSurface = clipMaskSurface;
         maskTransform = clippedMaskTransform;
       }
     }
 
-    if (opacity != 1.0f || svgMaskFrame  || hasValidLayers ||
-        (clipPathFrame && !isTrivialClip)) {
+    if (opacity != 1.0f || hasMaskToDraw || (clipPathFrame && !isTrivialClip)) {
       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) {
@@ -664,18 +675,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
     aContext.Restore();
   }
 
   /* No more effects, we're done. */
   if (!complexEffects) {
     return;
   }
 
-  if (opacity != 1.0f || svgMaskFrame || hasValidLayers ||
-      (clipPathFrame && !isTrivialClip)) {
+  if (opacity != 1.0f || hasMaskToDraw || (clipPathFrame && !isTrivialClip)) {
     target->PopGroupAndBlend();
   }
 
   if (aFrame->StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
     RefPtr<DrawTarget> targetDT = target->GetDrawTarget();
     target = nullptr;
     RefPtr<SourceSurface> targetSurf = targetDT->Snapshot();