Bug 1313898 - Part 3. Cache clip-path property in CSSMaskLayerUserData. draft
authorcku <cku@mozilla.com>
Fri, 04 Nov 2016 17:35:13 +0800
changeset 435434 fc1aed99fd3c6911eefd509b2002a13c98f62319
parent 435433 de0753d4d5c07fb08fac9becca89740f09e6405f
child 435435 136d4b09da92d61e5f8e9380b6f20020babe75de
push id35040
push userbmo:cku@mozilla.com
push dateTue, 08 Nov 2016 17:49:40 +0000
bugs1313898
milestone52.0a1
Bug 1313898 - Part 3. Cache clip-path property in CSSMaskLayerUserData. MozReview-Commit-ID: 1jijzRxHb72
layout/base/FrameLayerBuilder.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -46,16 +46,17 @@
 #include "mozilla/gfx/Tools.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/TextureWrapperImage.h"
 #include "mozilla/Unused.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
 #include "gfxPrefs.h"
+#include "nsSVGEffects.h"
 
 #include <algorithm>
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
@@ -1561,91 +1562,160 @@ struct MaskLayerUserData : public LayerU
   int32_t mAppUnitsPerDevPixel;
 };
 
 /*
  * User data for layers which will be used as masks for css positioned mask.
  */
 struct CSSMaskLayerUserData : public LayerUserData
 {
+  class UDRenderObserver final: public nsSVGRenderingObserverProperty {
+  public:
+    UDRenderObserver(nsIURI* aURI, nsIFrame* aFrame,
+                     bool aReferenceImage, CSSMaskLayerUserData* aUserData)
+      : nsSVGRenderingObserverProperty(aURI, aFrame, aReferenceImage),
+        mHost(aUserData)
+    { }
+  private:
+    virtual void DoUpdate() override {
+      mHost->mCorrupt = true;
+    }
+
+    CSSMaskLayerUserData* mHost;
+  };
+
+  NS_DECLARE_FRAME_PROPERTY_RELEASABLE(ClipPathProperty, UDRenderObserver)
+
   CSSMaskLayerUserData()
-    : mImageLayers(nsStyleImageLayers::LayerType::Mask)
+    : mFrame(nullptr),
+      mImageLayers(nsStyleImageLayers::LayerType::Mask),
+      mCorrupt(false)
   { }
 
-  CSSMaskLayerUserData(const nsIFrame* aFrame, const nsRect& aBound)
-    : mImageLayers(aFrame->StyleSVGReset()->mMask),
+  CSSMaskLayerUserData(nsIFrame* aFrame, const nsRect& aBound)
+    : mFrame(aFrame),
+      mImageLayers(aFrame->StyleSVGReset()->mMask),
       mContentRect(aFrame->GetContentRectRelativeToSelf()),
       mPaddingRect(aFrame->GetPaddingRectRelativeToSelf()),
       mBorderRect(aFrame->GetRectRelativeToSelf()),
       mMarginRect(aFrame->GetMarginRectRelativeToSelf()),
-      mBounds(aBound)
+      mBounds(aBound),
+      mCorrupt(false)
   {
-    mHash = Hash(aFrame->StyleSVGReset(), mBounds);
+    // 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.
+    nsSVGEffects::EffectProperties effectProperties =
+      nsSVGEffects::GetEffectProperties(mFrame);
+    mClipPathPropCache =
+      reinterpret_cast<uintptr_t>(effectProperties.mClipPath);
+
+    Hash();
+  }
+
+  void StartListen()
+  {
+    FrameProperties props = mFrame->Properties();
+    props.Delete(CSSMaskLayerUserData::ClipPathProperty());
+
+    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();
+      }
+    }
   }
 
   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;
+
+    mFrame = aOther.mFrame;
+
     mHash = aOther.mHash;
 
     return *this;
   }
 
   bool
   operator==(const CSSMaskLayerUserData& aOther) const
   {
     if (mHash != aOther.mHash) {
       return false;
     }
+    if (mCorrupt) {
+      return false;
+    }
+    // Compare css-position-mask props.
     if (mImageLayers.mLayers != aOther.mImageLayers.mLayers) {
       return false;
     }
     if (!mContentRect.IsEqualEdges(aOther.mContentRect) ||
         !mPaddingRect.IsEqualEdges(aOther.mPaddingRect) ||
         !mBorderRect.IsEqualEdges(aOther.mBorderRect) ||
         !mMarginRect.IsEqualEdges(aOther.mMarginRect)) {
       return false;
     }
+
+    if (mClipPathPropCache != aOther.mClipPathPropCache) {
+      return false;
+    }
+
     if (!mBounds.IsEqualEdges(aOther.mBounds)) {
       return false;
     }
 
     return true;
   }
 
 private:
-  static
-  uint32_t Hash(const nsStyleSVGReset* aSVGReset, const nsRect& aBound)
+  void Hash()
   {
+    const nsStyleSVGReset* aSVGReset =  mFrame->StyleSVGReset();
+
     uint32_t hash = 0;
 
+    // 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, HashBytes(&aBound, sizeof(aBound)));
-    return hash;
-  }
+    hash = AddToHash(hash, mClipPathPropCache);
+    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;
+  bool mCorrupt;
+
   uint32_t mHash;
 };
 
 /*
  * 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.
  */
@@ -3949,16 +4019,17 @@ ContainerState::SetupMaskLayerForCSSMask
   RefPtr<ImageContainer> imgContainer =
     imageData.CreateImageAndImageContainer();
   if (!imgContainer) {
     return;
   }
   maskLayer->SetContainer(imgContainer);
 
   *oldUserData = newUserData;
+  oldUserData->StartListen();
   aLayer->SetMaskLayer(maskLayer);
 }
 
 /*
  * Iterate through the non-clip items in aList and its descendants.
  * For each item we compute the effective clip rect. Each item is assigned
  * to a layer. We invalidate the areas in PaintedLayers where an item
  * has moved from one PaintedLayer to another. Also,