• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Composition.h"
11 #include "modules/skottie/src/Layer.h"
12 #include "modules/skottie/src/SkottieJson.h"
13 #include "modules/sksg/include/SkSGRenderEffect.h"
14 #include "src/utils/SkJSON.h"
15 
16 #include <algorithm>
17 #include <iterator>
18 
19 namespace skottie {
20 namespace internal {
21 
EffectBuilder(const AnimationBuilder * abuilder,const SkSize & layer_size,CompositionBuilder * cbuilder)22 EffectBuilder::EffectBuilder(const AnimationBuilder* abuilder,
23                              const SkSize& layer_size,
24                              CompositionBuilder* cbuilder)
25     : fBuilder(abuilder)
26     , fCompBuilder(cbuilder)
27     , fLayerSize(layer_size) {}
28 
findBuilder(const skjson::ObjectValue & jeffect) const29 EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectValue& jeffect) const {
30     static constexpr struct BuilderInfo {
31         const char*    fName;
32         EffectBuilderT fBuilder;
33     } gBuilderInfo[] = {
34         // alphabetized for binary search lookup
35         { "ADBE Black&White"            , &EffectBuilder::attachBlackAndWhiteEffect      },
36         { "ADBE Brightness & Contrast 2", &EffectBuilder::attachBrightnessContrastEffect },
37         { "ADBE Bulge"                  , &EffectBuilder::attachBulgeEffect              },
38         { "ADBE Corner Pin"             , &EffectBuilder::attachCornerPinEffect          },
39         { "ADBE Displacement Map"       , &EffectBuilder::attachDisplacementMapEffect    },
40         { "ADBE Drop Shadow"            , &EffectBuilder::attachDropShadowEffect         },
41         { "ADBE Easy Levels2"           , &EffectBuilder::attachEasyLevelsEffect         },
42         { "ADBE Fill"                   , &EffectBuilder::attachFillEffect               },
43         { "ADBE Fractal Noise"          , &EffectBuilder::attachFractalNoiseEffect       },
44         { "ADBE Gaussian Blur 2"        , &EffectBuilder::attachGaussianBlurEffect       },
45         { "ADBE Geometry2"              , &EffectBuilder::attachTransformEffect          },
46         { "ADBE HUE SATURATION"         , &EffectBuilder::attachHueSaturationEffect      },
47         { "ADBE Invert"                 , &EffectBuilder::attachInvertEffect             },
48         { "ADBE Linear Wipe"            , &EffectBuilder::attachLinearWipeEffect         },
49         { "ADBE Motion Blur"            , &EffectBuilder::attachDirectionalBlurEffect    },
50         { "ADBE Pro Levels2"            , &EffectBuilder::attachProLevelsEffect          },
51         { "ADBE Radial Wipe"            , &EffectBuilder::attachRadialWipeEffect         },
52         { "ADBE Ramp"                   , &EffectBuilder::attachGradientEffect           },
53         { "ADBE Shift Channels"         , &EffectBuilder::attachShiftChannelsEffect      },
54         { "ADBE Threshold2"             , &EffectBuilder::attachThresholdEffect          },
55         { "ADBE Tile"                   , &EffectBuilder::attachMotionTileEffect         },
56         { "ADBE Tint"                   , &EffectBuilder::attachTintEffect               },
57         { "ADBE Tritone"                , &EffectBuilder::attachTritoneEffect            },
58         { "ADBE Venetian Blinds"        , &EffectBuilder::attachVenetianBlindsEffect     },
59         { "CC Sphere"                   , &EffectBuilder::attachSphereEffect             },
60         { "CC Toner"                    , &EffectBuilder::attachCCTonerEffect            },
61         { "SkSL Shader"                 , &EffectBuilder::attachSkSLEffect               },
62     };
63 
64     const skjson::StringValue* mn = jeffect["mn"];
65     if (mn) {
66         const BuilderInfo key { mn->begin(), nullptr };
67         const auto* binfo = std::lower_bound(std::begin(gBuilderInfo),
68                                              std::end  (gBuilderInfo),
69                                              key,
70                                              [](const BuilderInfo& a, const BuilderInfo& b) {
71                                                  return strcmp(a.fName, b.fName) < 0;
72                                              });
73         if (binfo != std::end(gBuilderInfo) && !strcmp(binfo->fName, key.fName)) {
74             return binfo->fBuilder;
75         }
76     }
77 
78     // Some legacy clients rely solely on the 'ty' field and generate (non-BM) JSON
79     // without a valid 'mn' string.  TODO: we should update them and remove this fallback.
80     enum : int32_t {
81         kTint_Effect         = 20,
82         kFill_Effect         = 21,
83         kTritone_Effect      = 23,
84         kDropShadow_Effect   = 25,
85         kRadialWipe_Effect   = 26,
86         kGaussianBlur_Effect = 29,
87     };
88 
89     switch (ParseDefault<int>(jeffect["ty"], -1)) {
90         case         kTint_Effect: return &EffectBuilder::attachTintEffect;
91         case         kFill_Effect: return &EffectBuilder::attachFillEffect;
92         case      kTritone_Effect: return &EffectBuilder::attachTritoneEffect;
93         case   kDropShadow_Effect: return &EffectBuilder::attachDropShadowEffect;
94         case   kRadialWipe_Effect: return &EffectBuilder::attachRadialWipeEffect;
95         case kGaussianBlur_Effect: return &EffectBuilder::attachGaussianBlurEffect;
96         default: break;
97     }
98 
99     fBuilder->log(Logger::Level::kWarning, &jeffect,
100                   "Unsupported layer effect: %s", mn ? mn->begin() : "(unknown)");
101 
102     return nullptr;
103 }
104 
attachEffects(const skjson::ArrayValue & jeffects,sk_sp<sksg::RenderNode> layer) const105 sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
106                                                      sk_sp<sksg::RenderNode> layer) const {
107     if (!layer) {
108         return nullptr;
109     }
110 
111     for (const skjson::ObjectValue* jeffect : jeffects) {
112         if (!jeffect) {
113             continue;
114         }
115 
116         const auto builder = this->findBuilder(*jeffect);
117         const skjson::ArrayValue* jprops = (*jeffect)["ef"];
118         if (!builder || !jprops) {
119             continue;
120         }
121 
122         const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect, PropertyObserver::NodeType::EFFECT);
123         layer = (this->*builder)(*jprops, std::move(layer));
124 
125         if (!layer) {
126             fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
127             return nullptr;
128         }
129     }
130 
131     return layer;
132 }
133 
attachStyles(const skjson::ArrayValue & jstyles,sk_sp<sksg::RenderNode> layer) const134 sk_sp<sksg::RenderNode> EffectBuilder::attachStyles(const skjson::ArrayValue& jstyles,
135                                                      sk_sp<sksg::RenderNode> layer) const {
136 #if !defined(SKOTTIE_DISABLE_STYLES)
137     if (!layer) {
138         return nullptr;
139     }
140 
141     using StyleBuilder =
142         sk_sp<sksg::RenderNode> (EffectBuilder::*)(const skjson::ObjectValue&,
143                                                    sk_sp<sksg::RenderNode>) const;
144     static constexpr StyleBuilder gStyleBuilders[] = {
145         nullptr,                                 // 'ty': 0 -> stroke
146         &EffectBuilder::attachDropShadowStyle,   // 'ty': 1 -> drop shadow
147         &EffectBuilder::attachInnerShadowStyle,  // 'ty': 2 -> inner shadow
148         &EffectBuilder::attachOuterGlowStyle,    // 'ty': 3 -> outer glow
149         &EffectBuilder::attachInnerGlowStyle,    // 'ty': 4 -> inner glow
150     };
151 
152     for (const skjson::ObjectValue* jstyle : jstyles) {
153         if (!jstyle) {
154             continue;
155         }
156 
157         const auto style_type =
158                 ParseDefault<size_t>((*jstyle)["ty"], std::numeric_limits<size_t>::max());
159         auto builder = style_type < SK_ARRAY_COUNT(gStyleBuilders) ? gStyleBuilders[style_type]
160                                                                    : nullptr;
161 
162         if (!builder) {
163             fBuilder->log(Logger::Level::kWarning, jstyle, "Unsupported layer style.");
164             continue;
165         }
166 
167         layer = (this->*builder)(*jstyle, std::move(layer));
168     }
169 #endif // !defined(SKOTTIE_DISABLE_STYLES)
170 
171     return layer;
172 }
173 
GetPropValue(const skjson::ArrayValue & jprops,size_t prop_index)174 const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
175                                                  size_t prop_index) {
176     static skjson::NullValue kNull;
177 
178     if (prop_index >= jprops.size()) {
179         return kNull;
180     }
181 
182     const skjson::ObjectValue* jprop = jprops[prop_index];
183 
184     return jprop ? (*jprop)["v"] : kNull;
185 }
186 
MaskShaderEffectBase(sk_sp<sksg::RenderNode> child,const SkSize & ls)187 MaskShaderEffectBase::MaskShaderEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
188     : fMaskEffectNode(sksg::MaskShaderEffect::Make(std::move(child)))
189     , fLayerSize(ls) {}
190 
onSync()191 void MaskShaderEffectBase::onSync() {
192     const auto minfo = this->onMakeMask();
193 
194     fMaskEffectNode->setVisible(minfo.fVisible);
195     fMaskEffectNode->setShader(std::move(minfo.fMaskShader));
196 }
197 
198 } // namespace internal
199 } // namespace skottie
200