Bug 1313898 - Part 4. Cache svg mask property in CSSMaskLayerUserData. draft
authorcku <cku@mozilla.com>
Wed, 09 Nov 2016 00:33:44 +0800
changeset 435435 136d4b09da92d61e5f8e9380b6f20020babe75de
parent 435434 fc1aed99fd3c6911eefd509b2002a13c98f62319
child 435436 6051ce89277ffe83dc777fb5a628ec63d4d36773
push id35040
push userbmo:cku@mozilla.com
push dateTue, 08 Nov 2016 17:49:40 +0000
bugs1313898
milestone52.0a1
Bug 1313898 - Part 4. Cache svg mask property in CSSMaskLayerUserData. MozReview-Commit-ID: 2X90LyY3IJz
layout/base/FrameLayerBuilder.cpp
layout/base/nsDisplayList.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1577,17 +1577,42 @@ struct CSSMaskLayerUserData : public Lay
   private:
     virtual void DoUpdate() override {
       mHost->mCorrupt = true;
     }
 
     CSSMaskLayerUserData* mHost;
   };
 
+  class nsSVGMaskChainProp final : public nsISupports
+  {
+  public:
+    explicit nsSVGMaskChainProp(nsIFrame* aFrame,
+                bool aReferenceImage, CSSMaskLayerUserData* aUserData)
+    {
+      const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
+
+      for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
+        nsCOMPtr<nsIURI> maskUri = nsSVGEffects::GetMaskURI(aFrame, i);
+        UDRenderObserver* prop =
+          new UDRenderObserver(maskUri, aFrame, aReferenceImage, aUserData);
+        mProperties.AppendElement(prop);
+        prop->GetReferencedElement();
+      }
+    }
+
+    NS_DECL_ISUPPORTS
+
+  private:
+    virtual ~nsSVGMaskChainProp() {}
+    nsTArray<RefPtr<UDRenderObserver>> mProperties;
+  };
+
   NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, UDRenderObserver)
+  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MaskProperty, nsSVGMaskChainProp)
 
   CSSMaskLayerUserData()
     : mFrame(nullptr),
       mImageLayers(nsStyleImageLayers::LayerType::Mask),
       mCorrupt(false)
   { }
 
   CSSMaskLayerUserData(nsIFrame* aFrame, const nsRect& aBound)
@@ -1595,56 +1620,66 @@ struct CSSMaskLayerUserData : public Lay
       mImageLayers(aFrame->StyleSVGReset()->mMask),
       mContentRect(aFrame->GetContentRectRelativeToSelf()),
       mPaddingRect(aFrame->GetPaddingRectRelativeToSelf()),
       mBorderRect(aFrame->GetRectRelativeToSelf()),
       mMarginRect(aFrame->GetMarginRectRelativeToSelf()),
       mBounds(aBound),
       mCorrupt(false)
   {
-    // Once clip-path value changed, nsChangeHint_UpdateEffects is pass to 
-    // RestyleManager, ClipPathProperty in mFrame will be clean out then. By
-    // keeping the pointer value of ClipPathProperty, we are able to  know
-    // whether clip-path of mFrame change or not.
+    // Once clip-path/mask value changed, nsChangeHint_UpdateEffects is pass
+    // to  RestyleManager, ClipPathProperty/MaskProperty in mFrame will be
+    // clean out then. By keeping the pointer value of ClipPathProperty/
+    // MaskProperty, we are able to  know whether clip-path/mask of mFrame
+    // change or not.
     nsSVGEffects::EffectProperties effectProperties =
       nsSVGEffects::GetEffectProperties(mFrame);
     mClipPathPropCache =
       reinterpret_cast<uintptr_t>(effectProperties.mClipPath);
+    mSVGMaskPropCache =
+      reinterpret_cast<uintptr_t>(effectProperties.mMask);
 
     Hash();
   }
 
   void StartListen()
   {
     FrameProperties props = mFrame->Properties();
     props.Delete(CSSMaskLayerUserData::ClipPathProperty());
+    props.Delete(CSSMaskLayerUserData::MaskProperty());
 
     if (mFrame->StyleSVGReset()->mClipPath.GetType() ==
         StyleShapeSourceType::URL) {
       nsCOMPtr<nsIURI> pathURI = nsSVGEffects::GetClipPathURI(mFrame);
       if (pathURI) {
         UDRenderObserver* prop = new UDRenderObserver(pathURI, mFrame, false, this);
         NS_ADDREF(prop);
         props.Set(CSSMaskLayerUserData::ClipPathProperty(), prop);
         prop->GetReferencedElement();
       }
     }
+
+    nsSVGMaskChainProp* prop =
+      new nsSVGMaskChainProp(mFrame, false, this);
+    NS_ADDREF(prop);
+    props.Set(CSSMaskLayerUserData::MaskProperty(), prop);
   }
 
   CSSMaskLayerUserData& operator=(const CSSMaskLayerUserData& aOther)
   {
     mImageLayers = aOther.mImageLayers;
     mContentRect = aOther.mContentRect;
     mPaddingRect = aOther.mPaddingRect;
     mBorderRect = aOther.mBorderRect;
     mMarginRect = aOther.mMarginRect;
 
     mBounds = aOther.mBounds;
 
     mClipPathPropCache = aOther.mClipPathPropCache;
+    mSVGMaskPropCache = aOther.mSVGMaskPropCache;
 
     mFrame = aOther.mFrame;
 
     mHash = aOther.mHash;
 
     return *this;
   }
 
@@ -1666,16 +1701,19 @@ struct CSSMaskLayerUserData : public Lay
         !mBorderRect.IsEqualEdges(aOther.mBorderRect) ||
         !mMarginRect.IsEqualEdges(aOther.mMarginRect)) {
       return false;
     }
 
     if (mClipPathPropCache != aOther.mClipPathPropCache) {
       return false;
     }
+    if (mSVGMaskPropCache != aOther.mSVGMaskPropCache) {
+       return false;
+    }
 
     if (!mBounds.IsEqualEdges(aOther.mBounds)) {
       return false;
     }
 
     return true;
   }
 
@@ -1689,36 +1727,40 @@ private:
     // Hash css-position-mask props.
     const nsStyleImageLayers& imageLayers = aSVGReset->mMask;
     for (uint32_t i = 0; i < imageLayers.mLayers.Length(); i++) {
       const nsStyleImageLayers::Layer& newLayer = imageLayers.mLayers[i];
       hash = AddToHash(hash, HashBytes(&newLayer, sizeof(newLayer)));
     }
 
     hash = AddToHash(hash, mClipPathPropCache);
+    hash = AddToHash(hash, mSVGMaskPropCache);
     hash = AddToHash(hash, HashBytes(&mBounds, sizeof(mBounds)));
 
     mHash = hash;
   }
 
   nsIFrame* mFrame;
 
   nsStyleImageLayers mImageLayers;
   nsRect mContentRect;
   nsRect mPaddingRect;
   nsRect mBorderRect;
   nsRect mMarginRect;
   nsRect mBounds;
 
   uintptr_t mClipPathPropCache;
+  uintptr_t mSVGMaskPropCache;
   bool mCorrupt;
 
   uint32_t mHash;
 };
 
+NS_IMPL_ISUPPORTS(CSSMaskLayerUserData::nsSVGMaskChainProp, nsISupports)
+
 /*
  * A helper object to create a draw target for painting mask and create a
  * image container to hold the drawing result. The caller can then bind this
  * image container with a image mask layer via ImageLayer::SetContainer.
  */
 class MaskImageData
 {
 public:
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -7101,30 +7101,16 @@ bool nsDisplayMask::ShouldPaintOnMaskLay
   if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyBasicShape) {
     return false;
   }
 
   if (!nsSVGIntegrationUtils::IsMaskResourceReady(mFrame)) {
     return false;
   }
 
-  // XXX temporary disable drawing SVG mask onto mask layer before bug 1313877
-  // been fixed.
-  nsIFrame* firstFrame =
-    nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
-  nsSVGEffects::EffectProperties effectProperties =
-    nsSVGEffects::GetEffectProperties(firstFrame);
-  nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
-  for (size_t i = 0; i < maskFrames.Length() ; i++) {
-    nsSVGMaskFrame *maskFrame = maskFrames[i];
-    if (maskFrame) {
-      return false; // Found SVG mask.
-    }
-  }
-
   if (gfxPrefs::DrawMaskLayer()) {
     return false;
   }
 
   return true;
 }
 
 bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,