From ca716f70836f0eafbff6d6c4243ef72dd420da79 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 27 Apr 2022 18:48:59 +0000 Subject: [PATCH] Bug 1765911 - Support cloning Patterns with internal weak references. r=aosmond Currently calling Pattern::Clone() produces a heap-allocated Pattern with RefPtrs to any internal resources such as SourceSurfaces or GradientStops. While this is okay if the Pattern is transient, this causes problems if the clone is long-lived and causes via the RefPtr the stored resource to stay alive, even when there are no other external references to the resource. In the case of DrawTargetWebgl's PathCache, we need to be able to create Pattern clones that have internal weak references, while also still supporting the original use-case of strong references. To this end we template-ize some of the Pattern derivatives so that we can make either strong or weak versions according to use-case. This case way we store a weak clone of a Pattern in the PathCache key, the reference will automatically invalidate itself when all other external strong references to it go away, without having to do external crawling of the PathCache to constantly prune the last reference manually. Differential Revision: https://phabricator.services.mozilla.com/D144381 --- dom/canvas/DrawTargetWebgl.cpp | 2 +- dom/canvas/DrawTargetWebglInternal.h | 9 +- gfx/2d/2D.h | 259 ++++++++++++++++++--------- mfbt/ThreadSafeWeakPtr.h | 6 + 4 files changed, 187 insertions(+), 89 deletions(-) diff --git a/dom/canvas/DrawTargetWebgl.cpp b/dom/canvas/DrawTargetWebgl.cpp index bc33f4a6e9d2..5d026db2bfb7 100644 --- a/dom/canvas/DrawTargetWebgl.cpp +++ b/dom/canvas/DrawTargetWebgl.cpp @@ -1807,7 +1807,7 @@ already_AddRefed PathCache::FindOrInsertEntry( } Pattern* pattern = nullptr; if (aPattern) { - pattern = aPattern->Clone(); + pattern = aPattern->CloneWeak(); if (!pattern) { return nullptr; } diff --git a/dom/canvas/DrawTargetWebglInternal.h b/dom/canvas/DrawTargetWebglInternal.h index 4d8272550e42..a7cb61e6c48f 100644 --- a/dom/canvas/DrawTargetWebglInternal.h +++ b/dom/canvas/DrawTargetWebglInternal.h @@ -72,6 +72,8 @@ class CacheEntry : public RefCounted { const IntRect& GetBounds() const { return mBounds; } HashNumber GetHash() const { return mHash; } + virtual bool IsValid() const { return true; } + protected: virtual void RemoveFromList() = 0; @@ -173,7 +175,9 @@ class TextureHandle : public RefCounted, void SetCacheEntry(const RefPtr& aEntry) { mCacheEntry = aEntry; } // Note as used if there is corresponding surface or cache entry. - bool IsUsed() const { return mSurface || mCacheEntry; } + bool IsUsed() const { + return mSurface || (mCacheEntry && mCacheEntry->IsValid()); + } private: bool mValid = true; @@ -360,6 +364,9 @@ class PathCacheEntry : public CacheEntryImpl { const Point& GetOrigin() const { return mOrigin; } + // Valid if either a mask (no pattern) or there is valid pattern. + bool IsValid() const override { return !mPattern || mPattern->IsValid(); } + private: // The actual path geometry supplied SkPath mPath; diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 0565c6971be0..b637294991e8 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -251,7 +251,7 @@ struct ShadowOptions { * matching DrawTarget. Not adhering to this condition will make a draw call * fail. */ -class GradientStops : public external::AtomicRefCounted { +class GradientStops : public SupportsThreadSafeWeakPtr { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops) virtual ~GradientStops() = default; @@ -275,8 +275,15 @@ class Pattern { virtual PatternType GetType() const = 0; - /** Instantiate a new clone with the same pattern type and values. */ - virtual Pattern* Clone() const { return nullptr; } + /** Instantiate a new clone with the same pattern type and values. Any + * internal strong references will be converted to weak references. */ + virtual Pattern* CloneWeak() const { return nullptr; } + + /** Whether the pattern holds an internal weak reference. */ + virtual bool IsWeak() const { return false; } + + /** Whether any internal weak references still point to a target. */ + virtual bool IsValid() const { return true; } /** Determine if the pattern type and values exactly match. */ virtual bool operator==(const Pattern& aOther) const = 0; @@ -285,6 +292,19 @@ class Pattern { protected: Pattern() = default; + + // Utility functions to check if a weak reference is still valid. + template + static inline bool IsRefValid(const RefPtr& aPtr) { + // RefPtrs are always valid. + return true; + } + + template + static inline bool IsRefValid(const ThreadSafeWeakPtr& aPtr) { + // Weak refs are only valid if they aren't dead. + return !aPtr.IsDead(); + } }; class ColorPattern : public Pattern { @@ -295,7 +315,7 @@ class ColorPattern : public Pattern { PatternType GetType() const override { return PatternType::COLOR; } - Pattern* Clone() const override { return new ColorPattern(mColor); } + Pattern* CloneWeak() const override { return new ColorPattern(mColor); } bool operator==(const Pattern& aOther) const override { if (aOther.GetType() != PatternType::COLOR) { @@ -313,150 +333,201 @@ class ColorPattern : public Pattern { * stored in a separate object and are backend dependent. This class itself * may be used on the stack. */ -class LinearGradientPattern : public Pattern { +template