1 /*
2 * Copyright 2019 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 "modules/skottie/src/effects/Effects.h"
9
10 #include "modules/skottie/src/SkottieJson.h"
11 #include "modules/sksg/include/SkSGRenderEffect.h"
12 #include "src/utils/SkJSON.h"
13
14 namespace skottie {
15 namespace internal {
16
EffectBuilder(const AnimationBuilder * abuilder,const SkSize & layer_size)17 EffectBuilder::EffectBuilder(const AnimationBuilder* abuilder, const SkSize& layer_size)
18 : fBuilder(abuilder)
19 , fLayerSize(layer_size) {}
20
findBuilder(const skjson::ObjectValue & jeffect) const21 EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectValue& jeffect) const {
22 // First, try assigned types.
23 enum : int32_t {
24 kTint_Effect = 20,
25 kFill_Effect = 21,
26 kTritone_Effect = 23,
27 kDropShadow_Effect = 25,
28 kRadialWipe_Effect = 26,
29 kGaussianBlur_Effect = 29,
30 };
31
32 const auto ty = ParseDefault<int>(jeffect["ty"], -1);
33
34 switch (ty) {
35 case kTint_Effect:
36 return &EffectBuilder::attachTintEffect;
37 case kFill_Effect:
38 return &EffectBuilder::attachFillEffect;
39 case kTritone_Effect:
40 return &EffectBuilder::attachTritoneEffect;
41 case kDropShadow_Effect:
42 return &EffectBuilder::attachDropShadowEffect;
43 case kRadialWipe_Effect:
44 return &EffectBuilder::attachRadialWipeEffect;
45 case kGaussianBlur_Effect:
46 return &EffectBuilder::attachGaussianBlurEffect;
47 default:
48 break;
49 }
50
51 // Some effects don't have an assigned type, but the data is still present.
52 // Try a name-based lookup.
53
54 static constexpr char kGradientEffectMN[] = "ADBE Ramp",
55 kHueSaturationMN[] = "ADBE HUE SATURATION",
56 kLevelsEffectMN[] = "ADBE Easy Levels2",
57 kLinearWipeEffectMN[] = "ADBE Linear Wipe",
58 kMotionTileEffectMN[] = "ADBE Tile",
59 kTransformEffectMN[] = "ADBE Geometry2",
60 kVenetianBlindsEffectMN[] = "ADBE Venetian Blinds";
61
62 if (const skjson::StringValue* mn = jeffect["mn"]) {
63 if (!strcmp(mn->begin(), kGradientEffectMN)) {
64 return &EffectBuilder::attachGradientEffect;
65 }
66 if (!strcmp(mn->begin(), kHueSaturationMN)) {
67 return &EffectBuilder::attachHueSaturationEffect;
68 }
69 if (!strcmp(mn->begin(), kLevelsEffectMN)) {
70 return &EffectBuilder::attachLevelsEffect;
71 }
72 if (!strcmp(mn->begin(), kLinearWipeEffectMN)) {
73 return &EffectBuilder::attachLinearWipeEffect;
74 }
75 if (!strcmp(mn->begin(), kMotionTileEffectMN)) {
76 return &EffectBuilder::attachMotionTileEffect;
77 }
78 if (!strcmp(mn->begin(), kTransformEffectMN)) {
79 return &EffectBuilder::attachTransformEffect;
80 }
81 if (!strcmp(mn->begin(), kVenetianBlindsEffectMN)) {
82 return &EffectBuilder::attachVenetianBlindsEffect;
83 }
84 }
85
86 fBuilder->log(Logger::Level::kWarning, nullptr, "Unsupported layer effect type: %d.", ty);
87
88 return nullptr;
89 }
90
attachEffects(const skjson::ArrayValue & jeffects,sk_sp<sksg::RenderNode> layer) const91 sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
92 sk_sp<sksg::RenderNode> layer) const {
93 if (!layer) {
94 return nullptr;
95 }
96
97 for (const skjson::ObjectValue* jeffect : jeffects) {
98 if (!jeffect) {
99 continue;
100 }
101
102 const auto builder = this->findBuilder(*jeffect);
103 const skjson::ArrayValue* jprops = (*jeffect)["ef"];
104 if (!builder || !jprops) {
105 continue;
106 }
107
108 const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect);
109 layer = (this->*builder)(*jprops, std::move(layer));
110
111 if (!layer) {
112 fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
113 return nullptr;
114 }
115 }
116
117 return layer;
118 }
119
GetPropValue(const skjson::ArrayValue & jprops,size_t prop_index)120 const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
121 size_t prop_index) {
122 static skjson::NullValue kNull;
123
124 if (prop_index >= jprops.size()) {
125 return kNull;
126 }
127
128 const skjson::ObjectValue* jprop = jprops[prop_index];
129
130 return jprop ? (*jprop)["v"] : kNull;
131 }
132
MaskFilterEffectBase(sk_sp<sksg::RenderNode> child,const SkSize & ls)133 MaskFilterEffectBase::MaskFilterEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
134 : fMaskNode(sksg::MaskFilter::Make(nullptr))
135 , fMaskEffectNode(sksg::MaskFilterEffect::Make(std::move(child), fMaskNode))
136 , fLayerSize(ls) {}
137
138 MaskFilterEffectBase::~MaskFilterEffectBase() = default;
139
apply() const140 void MaskFilterEffectBase::apply() const {
141 const auto minfo = this->onMakeMask();
142
143 fMaskEffectNode->setVisible(minfo.fVisible);
144 fMaskNode->setMaskFilter(std::move(minfo.fMask));
145 }
146
147 } // namespace internal
148 } // namespace skottie
149