Bug 1313898 - Part 3. Cache clip-path property in CSSMaskLayerUserData.
MozReview-Commit-ID: 1jijzRxHb72
--- 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,