Bug 1362000 - Part 1. nsDisplayMask is invalid if the resource frame(nsSVGMaskFrame/ nsSVGClipPathFrame) is invalid. draft
authorcku <cku@mozilla.com>
Fri, 12 May 2017 11:33:41 +0800
changeset 576728 eec1ad4b5bb7e94ca9cf845f73effbb7cae1bf05
parent 575938 d8762cb967423618ff0a488f14745f60964e5c49
child 628283 0ca668fda5b9f0377e5841b5a02ad1e8ff8c13d0
push id58454
push userbmo:cku@mozilla.com
push dateFri, 12 May 2017 04:18:28 +0000
bugs1362000
milestone55.0a1
Bug 1362000 - Part 1. nsDisplayMask is invalid if the resource frame(nsSVGMaskFrame/ nsSVGClipPathFrame) is invalid. This bug is becasue we keep using an invalid mask layer. There are two way to fix it: 1. Create a nsSVGRenderingObserver to receive mask/clip-path content change, and invalid masked/clipped frame. CSS filter uses this approach(please refers to nsSVGRenderingObserve in nsSVGEffects.cpp). 2. Overwrite nsDisplayMask::IsInvalid. This approach is better than the first one since we will not repaint masked/clipped frame but only regenerate mask-layer. MozReview-Commit-ID: 6LwqcM84G0o
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8416,16 +8416,41 @@ nsDisplayMask::PaintMask(nsDisplayListBu
                                                   mHandleOpacity, flags);
   ComputeMaskGeometry(params);
   image::DrawResult result = nsSVGIntegrationUtils::PaintMask(params);
 
   nsDisplayMaskGeometry::UpdateDrawResult(this, result);
   return (result == image::DrawResult::SUCCESS) ? true : false;
 }
 
+bool
+nsDisplayMask::IsInvalid(nsRect& aRect)
+{
+  nsIFrame* firstFrame =
+    nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
+  nsSVGEffects::EffectProperties effectProperties =
+    nsSVGEffects::GetEffectProperties(firstFrame);
+
+  // Check whether all SVG masks are valid.
+  nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
+  for (uint32_t i = 0; i < maskFrames.Length(); i++) {
+    if (maskFrames[i] && !maskFrames[i]->IsInvalid(aRect)) {
+      return true;
+    }
+  }
+
+  // Check whether clip-path is valid.
+  nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
+  if (clipPathFrame && !clipPathFrame->IsInvalid(aRect)) {
+    return true;
+  }
+
+  return nsDisplaySVGEffects::IsInvalid(aRect);
+}
+
 LayerState
 nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager,
                              const ContainerLayerParameters& aParameters)
 {
   if (ShouldPaintOnMaskLayer(aManager)) {
     return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
                                          mList, GetAnimatedGeometryRoot());
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -4409,16 +4409,19 @@ public:
    * Paint mask onto aMaskContext in mFrame's coordinate space.
    */
   bool PaintMask(nsDisplayListBuilder* aBuilder, gfxContext* aMaskContext);
 
   const nsTArray<nsRect>& GetDestRects()
   {
     return mDestRects;
   }
+
+  virtual bool IsInvalid(nsRect& aRect) override;
+
 private:
   // According to mask property and the capability of aManager, determine
   // whether paint mask onto a dedicate mask layer.
   bool ShouldPaintOnMaskLayer(LayerManager* aManager);
 
   nsTArray<nsRect> mDestRects;
 };