Avoid unbounded listener growth on SkImage_Lazy when textures are purged

Generalizes the system used on SkPathRef where a GrTexture's key
destructor signals that a listener on the image can be removed via
the unique key custom data.

Removes texturesAreCacheable() from SkImageGenerator. This was used to
prevent unbounded growth in a narrow situation related to
GrBackendTextureImageGenerator.


Change-Id: I3c605da099acfac94751e793331e356a0979d359
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/274038
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 7222dcf..9217085 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -20,6 +20,7 @@
 #include "src/core/SkAutoMalloc.h"
 #include "src/core/SkBlendModePriv.h"
 #include "src/core/SkColorSpacePriv.h"
+#include "src/core/SkIDChangeListener.h"
 #include "src/core/SkImagePriv.h"
 #include "src/core/SkMaskFilterBase.h"
 #include "src/core/SkMessageBus.h"
@@ -117,6 +118,35 @@
     pixelRef->addGenIDChangeListener(new Invalidator(key, contextUniqueID));
 }
 
+sk_sp<SkIDChangeListener> GrMakeUniqueKeyInvalidationListener(GrUniqueKey* key,
+                                                              uint32_t contextID) {
+    class Listener : public SkIDChangeListener {
+    public:
+        Listener(const GrUniqueKey& key, uint32_t contextUniqueID) : fMsg(key, contextUniqueID) {}
+
+        void changed() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
+
+    private:
+        GrUniqueKeyInvalidatedMessage fMsg;
+    };
+
+    auto listener = sk_make_sp<Listener>(*key, contextID);
+
+    // We stick a SkData on the key that calls invalidateListener in its destructor.
+    auto invalidateListener = [](const void* ptr, void* /*context*/) {
+        auto listener = reinterpret_cast<const sk_sp<Listener>*>(ptr);
+        (*listener)->markShouldDeregister();
+        delete listener;
+    };
+    auto data = SkData::MakeWithProc(new sk_sp<Listener>(listener),
+                                     sizeof(sk_sp<Listener>),
+                                     invalidateListener,
+                                     nullptr);
+    SkASSERT(!key->getCustomData());
+    key->setCustomData(std::move(data));
+    return std::move(listener);
+}
+
 GrSurfaceProxyView GrCopyBaseMipMapToTextureProxy(GrRecordingContext* ctx,
                                                   GrSurfaceProxy* baseProxy,
                                                   GrSurfaceOrigin origin,