diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp index d3d0ac9860a22..2d30292fdadce 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 @@ sk_sp AttachPolystarGeometry(const skjson::ObjectValue& jsta return std::move(path_node); } -sk_sp AttachColor(const skjson::ObjectValue& jcolor, AttachContext* ctx) { +sk_sp AttachColor(const skjson::ObjectValue& jcolor, AttachContext* ctx, + const char prop_name[]) { auto color_node = sksg::Color::Make(SK_ColorBLACK); - BindProperty(jcolor["c"], &ctx->fAnimators, + BindProperty(jcolor[prop_name], &ctx->fAnimators, [color_node](const VectorValue& c) { color_node->setColor(ValueTraits::As(c)); }); @@ -357,7 +359,7 @@ sk_sp AttachStroke(const skjson::ObjectValue& jstroke, AttachCo } sk_sp AttachColorFill(const skjson::ObjectValue& jfill, AttachContext* ctx) { - return AttachPaint(jfill, ctx, AttachColor(jfill, ctx)); + return AttachPaint(jfill, ctx, AttachColor(jfill, ctx, "c")); } sk_sp AttachGradientFill(const skjson::ObjectValue& jfill, AttachContext* ctx) { @@ -365,7 +367,7 @@ sk_sp AttachGradientFill(const skjson::ObjectValue& jfill, Atta } sk_sp 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 AttachGradientStroke(const skjson::ObjectValue& jstroke, @@ -1106,14 +1108,55 @@ sk_sp AttachMask(const skjson::ArrayValue* jmask, return sksg::MaskEffect::Make(std::move(childNode), std::move(mask_group)); } + +sk_sp AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props, + AttachContext* ctx, + sk_sp layer) { + if (!jeffect_props) return layer; + + sk_sp color_node; + + for (const skjson::ObjectValue* jprop : *jeffect_props) { + if (!jprop) continue; + + switch (const auto ty = ParseDefault((*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 AttachLayerEffects(const skjson::ArrayValue& jeffects, + AttachContext* ctx, + sk_sp layer) { + for (const skjson::ObjectValue* jeffect : jeffects) { + if (!jeffect) continue; + + switch (const auto ty = ParseDefault((*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 AttachLayer(const skjson::ObjectValue* jlayer, AttachLayerContext* layerCtx) { if (!jlayer) return nullptr; - if (!(*jlayer)["ef"].is()) { - LOG("?? Unsupported layer effect.\n"); - } - using LayerAttacher = sk_sp (*)(const skjson::ObjectValue&, AttachContext*); static constexpr LayerAttacher gLayerAttachers[] = { AttachCompLayer, // 'ty': 0 @@ -1157,6 +1200,11 @@ sk_sp AttachLayer(const skjson::ObjectValue* jlayer, 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 0000000000000..9a7a837cecdce --- /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); + + void onRender(SkCanvas*) const final; + + sk_sp fColorFilter; + +private: + typedef EffectNode INHERITED; +}; + +/** + * Concrete SkModeColorFilter Effect node. + * + */ +class ColorModeFilter final : public ColorFilter { +public: + ~ColorModeFilter() override; + + static sk_sp Make(sk_sp child, sk_sp color, + SkBlendMode mode) { + return (child && color) + ? sk_sp(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, sk_sp, SkBlendMode); + + sk_sp fColor; + SkBlendMode fMode; + + typedef ColorFilter INHERITED; +}; + +} // namespace sksg + +#endif // SkSGColorFilter_DEFINED diff --git a/modules/sksg/sksg.gni b/modules/sksg/sksg.gni index bb6034471cb73..2e4e83bc5edcd 100644 --- a/modules/sksg/sksg.gni +++ b/modules/sksg/sksg.gni @@ -9,6 +9,7 @@ _src = get_path_info("src", "abspath") 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 0000000000000..d10b0ce050229 --- /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 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 child, sk_sp 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