[skottie] Initial Fill layer effect support
Overwrite the layer content color with a color filter.
TBR=
Change-Id: I39f920225affb2641cc11ab1f0c1456d89b47cb7
Reviewed-on: https://skia-review.googlesource.com/145730
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index d3d0ac9..2d30292 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -17,6 +17,7 @@
#include "SkPoint.h"
#include "SkSGClipEffect.h"
#include "SkSGColor.h"
+#include "SkSGColorFilter.h"
#include "SkSGDraw.h"
#include "SkSGGeometryTransform.h"
#include "SkSGGradient.h"
@@ -258,9 +259,10 @@
return std::move(path_node);
}
-sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue& jcolor, AttachContext* ctx) {
+sk_sp<sksg::Color> AttachColor(const skjson::ObjectValue& jcolor, AttachContext* ctx,
+ const char prop_name[]) {
auto color_node = sksg::Color::Make(SK_ColorBLACK);
- BindProperty<VectorValue>(jcolor["c"], &ctx->fAnimators,
+ BindProperty<VectorValue>(jcolor[prop_name], &ctx->fAnimators,
[color_node](const VectorValue& c) {
color_node->setColor(ValueTraits<VectorValue>::As<SkColor>(c));
});
@@ -357,7 +359,7 @@
}
sk_sp<sksg::PaintNode> AttachColorFill(const skjson::ObjectValue& jfill, AttachContext* ctx) {
- return AttachPaint(jfill, ctx, AttachColor(jfill, ctx));
+ return AttachPaint(jfill, ctx, AttachColor(jfill, ctx, "c"));
}
sk_sp<sksg::PaintNode> AttachGradientFill(const skjson::ObjectValue& jfill, AttachContext* ctx) {
@@ -365,7 +367,7 @@
}
sk_sp<sksg::PaintNode> AttachColorStroke(const skjson::ObjectValue& jstroke, AttachContext* ctx) {
- return AttachStroke(jstroke, ctx, AttachPaint(jstroke, ctx, AttachColor(jstroke, ctx)));
+ return AttachStroke(jstroke, ctx, AttachPaint(jstroke, ctx, AttachColor(jstroke, ctx, "c")));
}
sk_sp<sksg::PaintNode> AttachGradientStroke(const skjson::ObjectValue& jstroke,
@@ -1106,14 +1108,55 @@
return sksg::MaskEffect::Make(std::move(childNode), std::move(mask_group));
}
+
+sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props,
+ AttachContext* ctx,
+ sk_sp<sksg::RenderNode> layer) {
+ if (!jeffect_props) return layer;
+
+ sk_sp<sksg::Color> color_node;
+
+ for (const skjson::ObjectValue* jprop : *jeffect_props) {
+ if (!jprop) continue;
+
+ switch (const auto ty = ParseDefault<int>((*jprop)["ty"], -1)) {
+ case 2: // color
+ color_node = AttachColor(*jprop, ctx, "v");
+ break;
+ default:
+ LOG("?? Ignoring unsupported fill effect poperty type: %d\n", ty);
+ break;
+ }
+ }
+
+ return color_node
+ ? sksg::ColorModeFilter::Make(std::move(layer), std::move(color_node), SkBlendMode::kSrcIn)
+ : nullptr;
+}
+
+sk_sp<sksg::RenderNode> AttachLayerEffects(const skjson::ArrayValue& jeffects,
+ AttachContext* ctx,
+ sk_sp<sksg::RenderNode> layer) {
+ for (const skjson::ObjectValue* jeffect : jeffects) {
+ if (!jeffect) continue;
+
+ switch (const auto ty = ParseDefault<int>((*jeffect)["ty"], -1)) {
+ case 21: // Fill
+ layer = AttachFillLayerEffect((*jeffect)["ef"], ctx, std::move(layer));
+ break;
+ default:
+ LOG("?? Unsupported layer effect type: %d\n", ty);
+ break;
+ }
+ }
+
+ return layer;
+}
+
sk_sp<sksg::RenderNode> AttachLayer(const skjson::ObjectValue* jlayer,
AttachLayerContext* layerCtx) {
if (!jlayer) return nullptr;
- if (!(*jlayer)["ef"].is<skjson::NullValue>()) {
- LOG("?? Unsupported layer effect.\n");
- }
-
using LayerAttacher = sk_sp<sksg::RenderNode> (*)(const skjson::ObjectValue&, AttachContext*);
static constexpr LayerAttacher gLayerAttachers[] = {
AttachCompLayer, // 'ty': 0
@@ -1157,6 +1200,11 @@
layer = AttachOpacity(*jtransform, &local_ctx, std::move(layer));
}
+ // Optional layer effects.
+ if (const skjson::ArrayValue* jeffects = (*jlayer)["ef"]) {
+ layer = AttachLayerEffects(*jeffects, &local_ctx, std::move(layer));
+ }
+
class LayerController final : public sksg::GroupAnimator {
public:
LayerController(sksg::AnimatorList&& layer_animators,
diff --git a/modules/sksg/include/SkSGColorFilter.h b/modules/sksg/include/SkSGColorFilter.h
new file mode 100644
index 0000000..9a7a837
--- /dev/null
+++ b/modules/sksg/include/SkSGColorFilter.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSGColorFilter_DEFINED
+#define SkSGColorFilter_DEFINED
+
+#include "SkSGEffectNode.h"
+
+#include "SkBlendMode.h"
+
+class SkColorFilter;
+
+namespace sksg {
+
+class Color;
+
+/**
+ * Base class for nodes which apply a color filter when rendering their descendants.
+ *
+ */
+class ColorFilter : public EffectNode {
+protected:
+ explicit ColorFilter(sk_sp<RenderNode>);
+
+ void onRender(SkCanvas*) const final;
+
+ sk_sp<SkColorFilter> fColorFilter;
+
+private:
+ typedef EffectNode INHERITED;
+};
+
+/**
+ * Concrete SkModeColorFilter Effect node.
+ *
+ */
+class ColorModeFilter final : public ColorFilter {
+public:
+ ~ColorModeFilter() override;
+
+ static sk_sp<ColorModeFilter> Make(sk_sp<RenderNode> child, sk_sp<Color> color,
+ SkBlendMode mode) {
+ return (child && color)
+ ? sk_sp<ColorModeFilter>(new ColorModeFilter(std::move(child), std::move(color), mode))
+ : nullptr;
+ }
+
+ SG_ATTRIBUTE(Mode , SkBlendMode, fMode )
+
+protected:
+ SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+
+private:
+ ColorModeFilter(sk_sp<RenderNode>, sk_sp<Color>, SkBlendMode);
+
+ sk_sp<Color> fColor;
+ SkBlendMode fMode;
+
+ typedef ColorFilter INHERITED;
+};
+
+} // namespace sksg
+
+#endif // SkSGColorFilter_DEFINED
diff --git a/modules/sksg/sksg.gni b/modules/sksg/sksg.gni
index bb60344..2e4e83b 100644
--- a/modules/sksg/sksg.gni
+++ b/modules/sksg/sksg.gni
@@ -9,6 +9,7 @@
skia_sksg_sources = [
"$_src/SkSGClipEffect.cpp",
"$_src/SkSGColor.cpp",
+ "$_src/SkSGColorFilter.cpp",
"$_src/SkSGDraw.cpp",
"$_src/SkSGEffectNode.cpp",
"$_src/SkSGGeometryNode.cpp",
diff --git a/modules/sksg/src/SkSGColorFilter.cpp b/modules/sksg/src/SkSGColorFilter.cpp
new file mode 100644
index 0000000..d10b0ce
--- /dev/null
+++ b/modules/sksg/src/SkSGColorFilter.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSGColorFilter.h"
+
+#include "SkCanvas.h"
+#include "SkColorFilter.h"
+#include "SkSGColor.h"
+
+namespace sksg {
+
+ColorFilter::ColorFilter(sk_sp<RenderNode> child)
+ : INHERITED(std::move(child)) {}
+
+void ColorFilter::onRender(SkCanvas* canvas) const {
+ if (this->bounds().isEmpty())
+ return;
+
+ SkAutoCanvasRestore acr(canvas, false);
+
+ if (fColorFilter) {
+ SkPaint p;
+ p.setColorFilter(fColorFilter);
+ canvas->saveLayer(this->bounds(), &p);
+ }
+
+ this->INHERITED::onRender(canvas);
+}
+
+ColorModeFilter::ColorModeFilter(sk_sp<RenderNode> child, sk_sp<Color> color, SkBlendMode mode)
+ : INHERITED(std::move(child))
+ , fColor(std::move(color))
+ , fMode(mode) {
+ this->observeInval(fColor);
+}
+
+ColorModeFilter::~ColorModeFilter() {
+ this->unobserveInval(fColor);
+}
+
+SkRect ColorModeFilter::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
+ SkASSERT(this->hasInval());
+
+ fColor->revalidate(ic, ctm);
+ fColorFilter = SkColorFilter::MakeModeFilter(fColor->getColor(), fMode);
+
+ return this->INHERITED::onRevalidate(ic, ctm);
+}
+
+} // namespace sksg