[skottie] Optimize color filter layerization

Use the deferred paint override mechanism, similar to opacity.

Change-Id: I78fa7f5d73ef333480ec72b0cb663819b1de2404
Reviewed-on: https://skia-review.googlesource.com/146527
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/sksg/include/SkSGRenderNode.h b/modules/sksg/include/SkSGRenderNode.h
index df69270..efa9934 100644
--- a/modules/sksg/include/SkSGRenderNode.h
+++ b/modules/sksg/include/SkSGRenderNode.h
@@ -9,6 +9,8 @@
 #define SkSGRenderNode_DEFINED
 
 #include "SkSGNode.h"
+
+#include "SkColorFilter.h"
 #include "SkTLazy.h"
 
 class SkCanvas;
@@ -36,7 +38,8 @@
     // These are deferred until we can determine whether they can be applied to the individual
     // draw paints, or whether they require content isolation (applied to a layer).
     struct RenderContext {
-        float fOpacity = 1;
+        sk_sp<SkColorFilter> fColorFilter;
+        float                fOpacity = 1;
 
         // Returns true if the paint was modified.
         bool modulatePaint(SkPaint*) const;
@@ -62,8 +65,9 @@
 
         operator const RenderContext* () const { return fCtx.get(); }
 
-        // Add opacity to a render node sub-DAG.
+        // Add (cumulative) paint overrides to a render node sub-DAG.
         ScopedRenderContext&& modulateOpacity(float opacity);
+        ScopedRenderContext&& modulateColorFilter(sk_sp<SkColorFilter>);
 
         // Force content isolation for a node sub-DAG by applying the RenderContext
         // overrides via a layer.
diff --git a/modules/sksg/src/SkSGColorFilter.cpp b/modules/sksg/src/SkSGColorFilter.cpp
index ab21117..3ad2287 100644
--- a/modules/sksg/src/SkSGColorFilter.cpp
+++ b/modules/sksg/src/SkSGColorFilter.cpp
@@ -7,7 +7,6 @@
 
 #include "SkSGColorFilter.h"
 
-#include "SkCanvas.h"
 #include "SkColorFilter.h"
 #include "SkSGColor.h"
 
@@ -20,15 +19,9 @@
     if (this->bounds().isEmpty())
         return;
 
-    SkAutoCanvasRestore acr(canvas, false);
+    const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateColorFilter(fColorFilter);
 
-    if (fColorFilter) {
-        SkPaint p;
-        p.setColorFilter(fColorFilter);
-        canvas->saveLayer(this->bounds(), &p);
-    }
-
-    this->INHERITED::onRender(canvas, ctx);
+    this->INHERITED::onRender(canvas, local_ctx);
 }
 
 ColorModeFilter::ColorModeFilter(sk_sp<RenderNode> child, sk_sp<Color> color, SkBlendMode mode)
diff --git a/modules/sksg/src/SkSGOpacityEffect.cpp b/modules/sksg/src/SkSGOpacityEffect.cpp
index bb2fadf..cc72c14 100644
--- a/modules/sksg/src/SkSGOpacityEffect.cpp
+++ b/modules/sksg/src/SkSGOpacityEffect.cpp
@@ -7,10 +7,6 @@
 
 #include "SkSGOpacityEffect.h"
 
-#include "SkCanvas.h"
-
-#include <math.h>
-
 namespace sksg {
 
 OpacityEffect::OpacityEffect(sk_sp<RenderNode> child, float opacity)
diff --git a/modules/sksg/src/SkSGRenderNode.cpp b/modules/sksg/src/SkSGRenderNode.cpp
index 417cae9..bfaad0e 100644
--- a/modules/sksg/src/SkSGRenderNode.cpp
+++ b/modules/sksg/src/SkSGRenderNode.cpp
@@ -23,8 +23,10 @@
     const auto initial_alpha = paint->getAlpha(),
                        alpha = SkToU8(sk_float_round2int(initial_alpha * fOpacity));
 
-    if (alpha != initial_alpha) {
+    if (alpha != initial_alpha || fColorFilter) {
         paint->setAlpha(alpha);
+        paint->setColorFilter(SkColorFilter::MakeComposeFilter(fColorFilter,
+                                                               paint->refColorFilter()));
         return true;
     }
 
@@ -64,6 +66,15 @@
 }
 
 RenderNode::ScopedRenderContext&&
+RenderNode::ScopedRenderContext::modulateColorFilter(sk_sp<SkColorFilter> cf) {
+    if (cf) {
+        auto* ctx = this->writableContext();
+        ctx->fColorFilter = SkColorFilter::MakeComposeFilter(std::move(ctx->fColorFilter), cf);
+    }
+    return std::move(*this);
+}
+
+RenderNode::ScopedRenderContext&&
 RenderNode::ScopedRenderContext::setIsolation(const SkRect& bounds, bool isolation) {
     if (isolation && fCtx.get()) {
         SkPaint layer_paint;