Purge clip masks when they are no longer findable.

This improves memory usage when the content contains frequently changing clips implemented as masks.

BUG=chromium:676459

Change-Id: I06ea5f9fe1cff9564ea136bad9fe97f6ecd77ad9
Reviewed-on: https://skia-review.googlesource.com/6629
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkMessageBus.h b/src/core/SkMessageBus.h
deleted file mode 100644
index 79f5c02..0000000
--- a/src/core/SkMessageBus.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkMessageBus_DEFINED
-#define SkMessageBus_DEFINED
-
-#include "SkMutex.h"
-#include "SkOnce.h"
-#include "SkTArray.h"
-#include "SkTDArray.h"
-#include "SkTypes.h"
-
-template <typename Message>
-class SkMessageBus : SkNoncopyable {
-public:
-    // Post a message to be received by all Inboxes for this Message type.  Threadsafe.
-    static void Post(const Message& m);
-
-    class Inbox {
-    public:
-        Inbox();
-        ~Inbox();
-
-        // Overwrite out with all the messages we've received since the last call.  Threadsafe.
-        void poll(SkTArray<Message>* out);
-
-    private:
-        SkTArray<Message>  fMessages;
-        SkMutex            fMessagesMutex;
-
-        friend class SkMessageBus;
-        void receive(const Message& m);  // SkMessageBus is a friend only to call this.
-    };
-
-private:
-    SkMessageBus();
-    static SkMessageBus* Get();
-
-    SkTDArray<Inbox*> fInboxes;
-    SkMutex           fInboxesMutex;
-};
-
-// This must go in a single .cpp file, not some .h, or we risk creating more than one global
-// SkMessageBus per type when using shared libraries.  NOTE: at most one per file will compile.
-#define DECLARE_SKMESSAGEBUS_MESSAGE(Message)                      \
-    template <>                                                    \
-    SkMessageBus<Message>* SkMessageBus<Message>::Get() {          \
-        static SkOnce once;                                        \
-        static SkMessageBus<Message>* bus;                         \
-        once([] { bus = new SkMessageBus<Message>(); });           \
-        return bus;                                                \
-    }
-
-//   ----------------------- Implementation of SkMessageBus::Inbox -----------------------
-
-template<typename Message>
-SkMessageBus<Message>::Inbox::Inbox() {
-    // Register ourselves with the corresponding message bus.
-    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
-    SkAutoMutexAcquire lock(bus->fInboxesMutex);
-    bus->fInboxes.push(this);
-}
-
-template<typename Message>
-SkMessageBus<Message>::Inbox::~Inbox() {
-    // Remove ourselves from the corresponding message bus.
-    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
-    SkAutoMutexAcquire lock(bus->fInboxesMutex);
-    // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
-    for (int i = 0; i < bus->fInboxes.count(); i++) {
-        if (this == bus->fInboxes[i]) {
-            bus->fInboxes.removeShuffle(i);
-            break;
-        }
-    }
-}
-
-template<typename Message>
-void SkMessageBus<Message>::Inbox::receive(const Message& m) {
-    SkAutoMutexAcquire lock(fMessagesMutex);
-    fMessages.push_back(m);
-}
-
-template<typename Message>
-void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
-    SkASSERT(messages);
-    messages->reset();
-    SkAutoMutexAcquire lock(fMessagesMutex);
-    fMessages.swap(messages);
-}
-
-//   ----------------------- Implementation of SkMessageBus -----------------------
-
-template <typename Message>
-SkMessageBus<Message>::SkMessageBus() {}
-
-template <typename Message>
-/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
-    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
-    SkAutoMutexAcquire lock(bus->fInboxesMutex);
-    for (int i = 0; i < bus->fInboxes.count(); i++) {
-        bus->fInboxes[i]->receive(m);
-    }
-}
-
-#endif  // SkMessageBus_DEFINED
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index a7bcce4..7b50d52 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -27,6 +27,7 @@
 typedef GrReducedClip::ElementList ElementList;
 
 static const int kMaxAnalyticElements = 4;
+const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
 
 bool GrClipStackClip::quickContains(const SkRect& rect) const {
     if (!fStack || fStack->isWideOpen()) {
@@ -341,9 +342,9 @@
         if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
             // The clip geometry is complex enough that it will be more efficient to create it
             // entirely in software
-            result = CreateSoftwareClipMask(context, reducedClip);
+            result = this->createSoftwareClipMask(context, reducedClip);
         } else {
-            result = CreateAlphaClipMask(context, reducedClip);
+            result = this->createAlphaClipMask(context, reducedClip);
         }
 
         if (result) {
@@ -384,9 +385,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Create a 8-bit clip mask in alpha
 
-static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
+static void create_clip_mask_key(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey::Builder builder(key, kDomain, 3);
+    GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag);
     builder[0] = clipGenID;
     // SkToS16 because image filters outset layers to a size indicated by the filter, which can
     // sometimes result in negative coordinates from clip space.
@@ -394,11 +395,25 @@
     builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16);
 }
 
-sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context,
-                                                      const GrReducedClip& reducedClip) {
+static void add_invalidate_on_pop_message(const SkClipStack& stack, int32_t clipGenID,
+                                          const GrUniqueKey& clipMaskKey) {
+    SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
+    while (const Element* element = iter.prev()) {
+        if (element->getGenID() == clipGenID) {
+            std::unique_ptr<GrUniqueKeyInvalidatedMessage> msg(
+                    new GrUniqueKeyInvalidatedMessage(clipMaskKey));
+            element->addResourceInvalidationMessage(std::move(msg));
+            return;
+        }
+    }
+    SkDEBUGFAIL("Gen ID was not found in stack.");
+}
+
+sk_sp<GrTexture> GrClipStackClip::createAlphaClipMask(GrContext* context,
+                                                      const GrReducedClip& reducedClip) const {
     GrResourceProvider* resourceProvider = context->resourceProvider();
     GrUniqueKey key;
-    GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
+    create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
     if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
         return sk_sp<GrTexture>(texture);
     }
@@ -423,13 +438,14 @@
     }
 
     texture->resourcePriv().setUniqueKey(key);
+    add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
     return texture;
 }
 
-sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrContext* context,
-                                                         const GrReducedClip& reducedClip) {
+sk_sp<GrTexture> GrClipStackClip::createSoftwareClipMask(GrContext* context,
+                                                         const GrReducedClip& reducedClip) const {
     GrUniqueKey key;
-    GetClipMaskKey(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
+    create_clip_mask_key(reducedClip.elementsGenID(), reducedClip.ibounds(), &key);
     if (GrTexture* texture = context->textureProvider()->findAndRefTextureByUniqueKey(key)) {
         return sk_sp<GrTexture>(texture);
     }
@@ -493,6 +509,6 @@
     }
 
     tex->resourcePriv().setUniqueKey(key);
-
+    add_invalidate_on_pop_message(*fStack, reducedClip.elementsGenID(), key);
     return sk_ref_sp(tex);
 }
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index f5b8411..1c4d40b 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -40,6 +40,9 @@
 
     bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override;
 
+    sk_sp<GrTexture> testingOnly_createClipMask(GrContext*) const;
+    static const char kMaskTestTag[];
+
 private:
     static bool PathNeedsSWRenderer(GrContext* context,
                                     bool hasUserStencilSettings,
@@ -51,18 +54,15 @@
 
     // Creates an alpha mask of the clip. The mask is a rasterization of elements through the
     // rect specified by clipSpaceIBounds.
-    static sk_sp<GrTexture> CreateAlphaClipMask(GrContext*, const GrReducedClip&);
+    sk_sp<GrTexture> createAlphaClipMask(GrContext*, const GrReducedClip&) const;
 
     // Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture.
-    static sk_sp<GrTexture> CreateSoftwareClipMask(GrContext*, const GrReducedClip&);
+    sk_sp<GrTexture> createSoftwareClipMask(GrContext*, const GrReducedClip&) const;
 
-   static bool UseSWOnlyPath(GrContext*,
-                             bool hasUserStencilSettings,
-                             const GrRenderTargetContext*,
-                             const GrReducedClip&);
-
-    static GrTexture* CreateCachedMask(int width, int height, const GrUniqueKey& key,
-                                       bool renderTarget);
+    static bool UseSWOnlyPath(GrContext*,
+                              bool hasUserStencilSettings,
+                              const GrRenderTargetContext*,
+                              const GrReducedClip&);
 
     SkIPoint                 fOrigin;
     sk_sp<const SkClipStack> fStack;