From 8deab3ac1eefdb2135281d74c9497a326b186c2e Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Fri, 29 Jun 2018 13:05:03 -0400 Subject: [skottie] Fix 'subtract' masks Empirically, AE applies subtract masks as inverted intersect masks: it applies the opacity *outside* the mask geometry. Adjust the masking logic accordingly. TBR= Change-Id: If8d9dedbed9ce01b623b6c86ea91e494823d5dc5 Reviewed-on: https://skia-review.googlesource.com/138580 Reviewed-by: Florin Malita Commit-Queue: Florin Malita --- modules/skottie/src/Skottie.cpp | 62 ++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) (limited to 'modules') diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp index a4c796c869..5c0ed97b4d 100644 --- a/modules/skottie/src/Skottie.cpp +++ b/modules/skottie/src/Skottie.cpp @@ -945,18 +945,28 @@ private: } }; -SkBlendMode MaskBlendMode(char mode) { +struct MaskInfo { + SkBlendMode fBlendMode; + bool fInvertGeometry; +}; + +const MaskInfo* GetMaskInfo(char mode) { + static constexpr MaskInfo k_add_info = { SkBlendMode::kSrcOver , false }; + static constexpr MaskInfo k_int_info = { SkBlendMode::kSrcIn , false }; + // AE 'subtract' is the same as 'intersect' + inverted geometry + // (draws the opacity-adjusted paint *outside* the shape). + static constexpr MaskInfo k_sub_info = { SkBlendMode::kSrcIn , true }; + static constexpr MaskInfo k_dif_info = { SkBlendMode::kDifference, false }; + 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 + case 'a': return &k_add_info; + case 'f': return &k_dif_info; + case 'i': return &k_int_info; + case 's': return &k_sub_info; default: break; } - return SkBlendMode::kSrcOver; + return nullptr; } sk_sp AttachMask(const skjson::ArrayValue* jmask, @@ -977,26 +987,40 @@ sk_sp AttachMask(const skjson::ArrayValue* jmask, for (const skjson::ObjectValue* m : *jmask) { if (!m) continue; - auto mask_path = AttachPath((*m)["pt"], ctx); - if (!mask_path) { - LogFail(*m, "Could not parse mask path"); + SkString mode; + if (!Parse((*m)["mode"], &mode) || mode.size() != 1) { + LogFail((*m)["mode"], "Invalid mask mode"); + continue; + } + + if (mode[0] == 'n') { + // "None" masks have no effect. continue; } - mask_path->setFillType(ParseDefault((*m)["inv"], false) - ? SkPath::kInverseWinding_FillType - : SkPath::kWinding_FillType); + const auto* mask_info = GetMaskInfo(mode[0]); + if (!mask_info) { + LOG("?? Unsupported mask mode: '%c'\n", mode[0]); + continue; + } - SkString mode; - if (!Parse((*m)["mode"], &mode) || - mode.size() != 1 || - !strcmp(mode.c_str(), "n")) { // "None" masks have no effect. + auto mask_path = AttachPath((*m)["pt"], ctx); + if (!mask_path) { + LogFail(*m, "Could not parse mask path"); continue; } + // "inv" is cumulative with mask info fInvertGeometry + const auto inverted = + (mask_info->fInvertGeometry != ParseDefault((*m)["inv"], false)); + mask_path->setFillType(inverted ? SkPath::kInverseWinding_FillType + : SkPath::kWinding_FillType); + auto mask_paint = sksg::Color::Make(SK_ColorBLACK); mask_paint->setAntiAlias(true); - mask_paint->setBlendMode(MaskBlendMode(mode.c_str()[0])); + // First mask in the stack initializes the mask buffer. + mask_paint->setBlendMode(mask_stack.empty() ? SkBlendMode::kSrc + : mask_info->fBlendMode); has_opacity |= BindProperty((*m)["o"], &ctx->fAnimators, [mask_paint](const ScalarValue& o) { -- cgit v1.2.3