From 25366fad43043f1bfe02135f9c18515639a3c9b0 Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Tue, 23 Jan 2018 13:37:59 -0500 Subject: [skottie] Initial mask support TBR= Change-Id: Ibf4baeb17f98e1ed359f04deefe2f1c09414540d Reviewed-on: https://skia-review.googlesource.com/98840 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- experimental/skottie/Skottie.cpp | 77 ++++++++++++++++++++++++++++++++----- experimental/sksg/SkSGGroup.h | 3 ++ experimental/sksg/SkSGPaintNode.cpp | 1 + experimental/sksg/SkSGPaintNode.h | 2 + 4 files changed, 74 insertions(+), 9 deletions(-) (limited to 'experimental') diff --git a/experimental/skottie/Skottie.cpp b/experimental/skottie/Skottie.cpp index 73818d0035..2199f51f2a 100644 --- a/experimental/skottie/Skottie.cpp +++ b/experimental/skottie/Skottie.cpp @@ -173,17 +173,18 @@ sk_sp AttachOpacity(const Json::Value& jtransform, AttachConte sk_sp AttachComposition(const Json::Value&, AttachContext* ctx); -sk_sp AttachPathGeometry(const Json::Value& jpath, AttachContext* ctx) { - SkASSERT(jpath.isObject()); - +sk_sp AttachPath(const Json::Value& jpath, AttachContext* ctx) { auto path_node = sksg::Path::Make(); - auto path_attached = BindProperty(jpath["ks"], ctx, path_node, - [](sksg::Path* node, const ShapeValue& p) { node->setPath(p); }); + return BindProperty(jpath, ctx, path_node, + [](sksg::Path* node, const ShapeValue& p) { node->setPath(p); }) + ? path_node + : nullptr; +} - if (path_attached) - LOG("** Attached path geometry - verbs: %d\n", path_node->getPath().countVerbs()); +sk_sp AttachPathGeometry(const Json::Value& jpath, AttachContext* ctx) { + SkASSERT(jpath.isObject()); - return path_attached ? path_node : nullptr; + return AttachPath(jpath["ks"], ctx); } sk_sp AttachRRectGeometry(const Json::Value& jrect, AttachContext* ctx) { @@ -881,6 +882,62 @@ struct AttachLayerContext { } }; +SkBlendMode MaskBlendMode(char mode) { + switch (mode) { + case 'a': return SkBlendMode::kSrcOver; // Additive + case 's': return SkBlendMode::kExclusion; // Subtract + case 'i': return SkBlendMode::kDstIn; // Intersect + case 'l': return SkBlendMode::kLighten; // Lighten + case 'd': return SkBlendMode::kDarken; // Darken + case 'f': return SkBlendMode::kDifference; // Difference + default: break; + } + + return SkBlendMode::kSrcOver; +} + +sk_sp AttachMask(const Json::Value& jmask, + AttachContext* ctx, + sk_sp childNode) { + if (!jmask.isArray()) + return childNode; + + auto mask_group = sksg::Group::Make(); + + for (const auto& m : jmask) { + if (!m.isObject()) + continue; + + const auto inverted = ParseBool(m["inv"], false); + // TODO + if (inverted) { + LogFail(m, "Unsupported inverse mask"); + continue; + } + + auto mask_path = AttachPath(m["pt"], ctx); + if (!mask_path) { + LogFail(m, "Could not parse mask path"); + continue; + } + + auto mode = ParseString(m["mode"], ""); + if (mode.size() != 1 || !strcmp(mode.c_str(), "n")) // "None" masks have no effect. + continue; + + auto mask_paint = sksg::Color::Make(SK_ColorBLACK); + mask_paint->setBlendMode(MaskBlendMode(mode.c_str()[0])); + BindProperty(m["o"], ctx, mask_paint, + [](sksg::Color* node, const ScalarValue& o) { node->setOpacity(o * 0.01f); }); + + mask_group->addChild(sksg::Draw::Make(std::move(mask_path), std::move(mask_paint))); + } + + return mask_group->empty() + ? childNode + : sksg::MaskEffect::Make(std::move(childNode), std::move(mask_group)); +} + sk_sp AttachLayer(const Json::Value& jlayer, AttachLayerContext* layerCtx) { if (!jlayer.isObject()) @@ -903,8 +960,10 @@ sk_sp AttachLayer(const Json::Value& jlayer, // Layer content. auto layer = gLayerAttachers[type](jlayer, layerCtx->fCtx); + // Optional layer mask. + layer = AttachMask(jlayer["masksProperties"], layerCtx->fCtx, std::move(layer)); + // Optional layer transform. if (auto layerMatrix = layerCtx->AttachLayerMatrix(jlayer)) { - // Optional layer transform. layer = sksg::Transform::Make(std::move(layer), std::move(layerMatrix)); } // Optional layer opacity. diff --git a/experimental/sksg/SkSGGroup.h b/experimental/sksg/SkSGGroup.h index f9126ea37f..482f10db8c 100644 --- a/experimental/sksg/SkSGGroup.h +++ b/experimental/sksg/SkSGGroup.h @@ -26,6 +26,9 @@ public: void addChild(sk_sp); void removeChild(const sk_sp&); + size_t size() const { return SkTo(fChildren.count()); } + bool empty() const { return fChildren.empty(); } + protected: Group(); ~Group() override; diff --git a/experimental/sksg/SkSGPaintNode.cpp b/experimental/sksg/SkSGPaintNode.cpp index bb5b714030..9220b0f0af 100644 --- a/experimental/sksg/SkSGPaintNode.cpp +++ b/experimental/sksg/SkSGPaintNode.cpp @@ -23,6 +23,7 @@ SkRect PaintNode::onRevalidate(InvalidationController*, const SkMatrix&) { fPaint.reset(); fPaint.setAntiAlias(fAntiAlias); + fPaint.setBlendMode(fBlendMode); fPaint.setStyle(fStyle); fPaint.setStrokeWidth(fStrokeWidth); fPaint.setStrokeMiter(fStrokeMiter); diff --git a/experimental/sksg/SkSGPaintNode.h b/experimental/sksg/SkSGPaintNode.h index 1085e27c0f..5c9563b3a6 100644 --- a/experimental/sksg/SkSGPaintNode.h +++ b/experimental/sksg/SkSGPaintNode.h @@ -26,6 +26,7 @@ public: SG_ATTRIBUTE(AntiAlias , bool , fAntiAlias ) SG_ATTRIBUTE(Opacity , SkScalar , fOpacity ) + SG_ATTRIBUTE(BlendMode , SkBlendMode , fBlendMode ) SG_ATTRIBUTE(StrokeWidth, SkScalar , fStrokeWidth) SG_ATTRIBUTE(StrokeMiter, SkScalar , fStrokeMiter) SG_ATTRIBUTE(Style , SkPaint::Style, fStyle ) @@ -46,6 +47,7 @@ private: fStrokeWidth = 1, fStrokeMiter = 4; bool fAntiAlias = false; + SkBlendMode fBlendMode = SkBlendMode::kSrcOver; SkPaint::Style fStyle = SkPaint::kFill_Style; SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join; SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap; -- cgit v1.2.3