1 /*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkottiePriv.h"
9
10 #include "SkJSON.h"
11 #include "SkottieJson.h"
12 #include "SkottieValue.h"
13 #include "SkSGColor.h"
14 #include "SkSGColorFilter.h"
15
16 namespace skottie {
17 namespace internal {
18
19 namespace {
20
AttachFillLayerEffect(const skjson::ArrayValue * jeffect_props,const AnimationBuilder * abuilder,AnimatorScope * ascope,sk_sp<sksg::RenderNode> layer)21 sk_sp<sksg::RenderNode> AttachFillLayerEffect(const skjson::ArrayValue* jeffect_props,
22 const AnimationBuilder* abuilder,
23 AnimatorScope* ascope,
24 sk_sp<sksg::RenderNode> layer) {
25 if (!jeffect_props) return nullptr;
26
27 // Effect properties are index-based.
28 enum {
29 kFillMask_Index = 0,
30 kAllMasks_Index = 1,
31 kColor_Index = 2,
32 kInvert_Index = 3,
33 kHFeather_Index = 4,
34 kVFeather_Index = 5,
35 kOpacity_Index = 6,
36
37 kMax_Index = kOpacity_Index,
38 };
39
40 if (jeffect_props->size() <= kMax_Index) {
41 return nullptr;
42 }
43
44 const skjson::ObjectValue* color_prop = (*jeffect_props)[ kColor_Index];
45 const skjson::ObjectValue* opacity_prop = (*jeffect_props)[kOpacity_Index];
46 if (!color_prop || !opacity_prop) {
47 return nullptr;
48 }
49
50 sk_sp<sksg::Color> color_node = abuilder->attachColor(*color_prop, ascope, "v");
51 if (!color_node) {
52 return nullptr;
53 }
54
55 abuilder->bindProperty<ScalarValue>((*opacity_prop)["v"], ascope,
56 [color_node](const ScalarValue& o) {
57 const auto c = color_node->getColor();
58 const auto a = sk_float_round2int_no_saturate(SkTPin(o, 0.0f, 1.0f) * 255);
59 color_node->setColor(SkColorSetA(c, a));
60 });
61
62 return sksg::ColorModeFilter::Make(std::move(layer),
63 std::move(color_node),
64 SkBlendMode::kSrcIn);
65 }
66
67 } // namespace
68
attachLayerEffects(const skjson::ArrayValue & jeffects,AnimatorScope * ascope,sk_sp<sksg::RenderNode> layer) const69 sk_sp<sksg::RenderNode> AnimationBuilder::attachLayerEffects(const skjson::ArrayValue& jeffects,
70 AnimatorScope* ascope,
71 sk_sp<sksg::RenderNode> layer) const {
72 for (const skjson::ObjectValue* jeffect : jeffects) {
73 if (!jeffect) continue;
74
75 switch (const auto ty = ParseDefault<int>((*jeffect)["ty"], -1)) {
76 case 21: // Fill
77 layer = AttachFillLayerEffect((*jeffect)["ef"], this, ascope, std::move(layer));
78 break;
79 default:
80 this->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
81 break;
82 }
83
84 if (!layer) {
85 this->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
86 return nullptr;
87 }
88 }
89
90 return layer;
91 }
92
93 } // namespace internal
94 } // namespace skottie
95