Add an SkColorSpaceXformer image filter cache

The cache is scoped with the SkColorSpaceXformer object.

This ensures we're not transforming nodes with a degree > 1 multiple
times, and preserves the DAG topology.

Change-Id: I0b072cdac95f9f1c34e0565ed4f258aba986e1ae
Reviewed-on: https://skia-review.googlesource.com/21726
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/core/SkColorSpaceXformer.cpp b/src/core/SkColorSpaceXformer.cpp
index 1e5206e..301a7f1 100644
--- a/src/core/SkColorSpaceXformer.cpp
+++ b/src/core/SkColorSpaceXformer.cpp
@@ -10,12 +10,15 @@
 #include "SkColorSpaceXform_Base.h"
 #include "SkDrawLooper.h"
 #include "SkGradientShader.h"
+#include "SkImage.h"
 #include "SkImage_Base.h"
 #include "SkImageFilter.h"
 #include "SkImagePriv.h"
 #include "SkMakeUnique.h"
 #include "SkShaderBase.h"
 
+SkColorSpaceXformer::~SkColorSpaceXformer() {}
+
 std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
     std::unique_ptr<SkColorSpaceXform> fromSRGB = SkColorSpaceXform_Base::New(
             SkColorSpace::MakeSRGB().get(), dst.get(), SkTransferFunctionBehavior::kIgnore);
@@ -50,7 +53,18 @@
 }
 
 sk_sp<SkImageFilter> SkColorSpaceXformer::apply(const SkImageFilter* imageFilter) {
-    return imageFilter ? imageFilter->makeColorSpace(this) : nullptr;
+    if (!imageFilter) {
+        return nullptr;
+    }
+
+    if (auto* xformedFilter = fFilterCache.find(imageFilter->fUniqueID)) {
+        return sk_ref_sp(xformedFilter->get());
+    }
+
+    auto xformedFilter = imageFilter->makeColorSpace(this);
+    fFilterCache.set(imageFilter->fUniqueID, xformedFilter);
+
+    return xformedFilter;
 }
 
 sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
diff --git a/src/core/SkColorSpaceXformer.h b/src/core/SkColorSpaceXformer.h
index f780071..75db040 100644
--- a/src/core/SkColorSpaceXformer.h
+++ b/src/core/SkColorSpaceXformer.h
@@ -8,15 +8,25 @@
 #ifndef SkColorSpaceXformer_DEFINED
 #define SkColorSpaceXformer_DEFINED
 
-#include "SkColorSpaceXform.h"
-#include "SkImage.h"
-#include "SkShader.h"
-#include "SkImageFilter.h"
+#include "SkColor.h"
+#include "SkRefCnt.h"
+#include "SkTHash.h"
+
+class SkBitmap;
+class SkColorFilter;
+class SkColorSpace;
+class SkColorSpaceXform;
+class SkImage;
+class SkImageFilter;
+class SkPaint;
+class SkShader;
 
 class SkColorSpaceXformer : public SkNoncopyable {
 public:
     static std::unique_ptr<SkColorSpaceXformer> Make(sk_sp<SkColorSpace> dst);
 
+    ~SkColorSpaceXformer();
+
     sk_sp<SkImage> apply(const SkImage*);
     sk_sp<SkImage> apply(const SkBitmap&);
     sk_sp<SkColorFilter> apply(const SkColorFilter*);
@@ -29,10 +39,12 @@
     sk_sp<SkColorSpace> dst() const { return fDst; }
 
 private:
-    SkColorSpaceXformer() {}
+    SkColorSpaceXformer() = default;
 
     sk_sp<SkColorSpace>                fDst;
     std::unique_ptr<SkColorSpaceXform> fFromSRGB;
+
+    SkTHashMap<uint32_t, sk_sp<SkImageFilter>> fFilterCache;
 };
 
 #endif
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 0860df7..0bd6c2c 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkColorMatrixFilter.h"
+#include "SkColorSpace.h"
 #include "SkColorSpaceXformer.h"
 #if SK_SUPPORT_GPU
     #include "GrFragmentProcessor.h"