• 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 Sharpen"                , &EffectBuilder::attachSharpenEffect            },
54         { "ADBE Shift Channels"         , &EffectBuilder::attachShiftChannelsEffect      },
55         { "ADBE Threshold2"             , &EffectBuilder::attachThresholdEffect          },
56         { "ADBE Tile"                   , &EffectBuilder::attachMotionTileEffect         },
57         { "ADBE Tint"                   , &EffectBuilder::attachTintEffect               },
58         { "ADBE Tritone"                , &EffectBuilder::attachTritoneEffect            },
59         { "ADBE Venetian Blinds"        , &EffectBuilder::attachVenetianBlindsEffect     },
60         { "CC Sphere"                   , &EffectBuilder::attachSphereEffect             },
61         { "CC Toner"                    , &EffectBuilder::attachCCTonerEffect            },
62         { "SkSL Color Filter"           , &EffectBuilder::attachSkSLColorFilter          },
63         { "SkSL Shader"                 , &EffectBuilder::attachSkSLShader               },
64     };
65 
66     const skjson::StringValue* mn = jeffect["mn"];
67     if (mn) {
68         const BuilderInfo key { mn->begin(), nullptr };
69         const auto* binfo = std::lower_bound(std::begin(gBuilderInfo),
70                                              std::end  (gBuilderInfo),
71                                              key,
72                                              [](const BuilderInfo& a, const BuilderInfo& b) {
73                                                  return strcmp(a.fName, b.fName) < 0;
74                                              });
75         if (binfo != std::end(gBuilderInfo) && !strcmp(binfo->fName, key.fName)) {
76             return binfo->fBuilder;
77         }
78     }
79 
80     // Some legacy clients rely solely on the 'ty' field and generate (non-BM) JSON
81     // without a valid 'mn' string.  TODO: we should update them and remove this fallback.
82     enum : int32_t {
83         kTint_Effect         = 20,
84         kFill_Effect         = 21,
85         kTritone_Effect      = 23,
86         kDropShadow_Effect   = 25,
87         kRadialWipe_Effect   = 26,
88         kGaussianBlur_Effect = 29,
89     };
90 
91     switch (ParseDefault<int>(jeffect["ty"], -1)) {
92         case         kTint_Effect: return &EffectBuilder::attachTintEffect;
93         case         kFill_Effect: return &EffectBuilder::attachFillEffect;
94         case      kTritone_Effect: return &EffectBuilder::attachTritoneEffect;
95         case   kDropShadow_Effect: return &EffectBuilder::attachDropShadowEffect;
96         case   kRadialWipe_Effect: return &EffectBuilder::attachRadialWipeEffect;
97         case kGaussianBlur_Effect: return &EffectBuilder::attachGaussianBlurEffect;
98         default: break;
99     }
100 
101     fBuilder->log(Logger::Level::kWarning, &jeffect,
102                   "Unsupported layer effect: %s", mn ? mn->begin() : "(unknown)");
103 
104     return nullptr;
105 }
106 
attachEffects(const skjson::ArrayValue & jeffects,sk_sp<sksg::RenderNode> layer) const107 sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
108                                                      sk_sp<sksg::RenderNode> layer) const {
109     if (!layer) {
110         return nullptr;
111     }
112 
113     for (const skjson::ObjectValue* jeffect : jeffects) {
114         if (!jeffect) {
115             continue;
116         }
117 
118         const auto builder = this->findBuilder(*jeffect);
119         const skjson::ArrayValue* jprops = (*jeffect)["ef"];
120         if (!builder || !jprops) {
121             continue;
122         }
123 
124         const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect, PropertyObserver::NodeType::EFFECT);
125         layer = (this->*builder)(*jprops, std::move(layer));
126 
127         if (!layer) {
128             fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
129             return nullptr;
130         }
131     }
132 
133     return layer;
134 }
135 
attachStyles(const skjson::ArrayValue & jstyles,sk_sp<sksg::RenderNode> layer) const136 sk_sp<sksg::RenderNode> EffectBuilder::attachStyles(const skjson::ArrayValue& jstyles,
137                                                      sk_sp<sksg::RenderNode> layer) const {
138 #if !defined(SKOTTIE_DISABLE_STYLES)
139     if (!layer) {
140         return nullptr;
141     }
142 
143     using StyleBuilder =
144         sk_sp<sksg::RenderNode> (EffectBuilder::*)(const skjson::ObjectValue&,
145                                                    sk_sp<sksg::RenderNode>) const;
146     static constexpr StyleBuilder gStyleBuilders[] = {
147         nullptr,                                 // 'ty': 0 -> stroke
148         &EffectBuilder::attachDropShadowStyle,   // 'ty': 1 -> drop shadow
149         &EffectBuilder::attachInnerShadowStyle,  // 'ty': 2 -> inner shadow
150         &EffectBuilder::attachOuterGlowStyle,    // 'ty': 3 -> outer glow
151         &EffectBuilder::attachInnerGlowStyle,    // 'ty': 4 -> inner glow
152     };
153 
154     for (const skjson::ObjectValue* jstyle : jstyles) {
155         if (!jstyle) {
156             continue;
157         }
158 
159         const auto style_type =
160                 ParseDefault<size_t>((*jstyle)["ty"], std::numeric_limits<size_t>::max());
161         auto builder = style_type < std::size(gStyleBuilders) ? gStyleBuilders[style_type]
162                                                               : nullptr;
163 
164         if (!builder) {
165             fBuilder->log(Logger::Level::kWarning, jstyle, "Unsupported layer style.");
166             continue;
167         }
168 
169         layer = (this->*builder)(*jstyle, std::move(layer));
170     }
171 #endif // !defined(SKOTTIE_DISABLE_STYLES)
172 
173     return layer;
174 }
175 
GetPropValue(const skjson::ArrayValue & jprops,size_t prop_index)176 const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
177                                                  size_t prop_index) {
178     static skjson::NullValue kNull;
179 
180     if (prop_index >= jprops.size()) {
181         return kNull;
182     }
183 
184     const skjson::ObjectValue* jprop = jprops[prop_index];
185 
186     return jprop ? (*jprop)["v"] : kNull;
187 }
188 
MaskShaderEffectBase(sk_sp<sksg::RenderNode> child,const SkSize & ls)189 MaskShaderEffectBase::MaskShaderEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
190     : fMaskEffectNode(sksg::MaskShaderEffect::Make(std::move(child)))
191     , fLayerSize(ls) {}
192 
onSync()193 void MaskShaderEffectBase::onSync() {
194     const auto minfo = this->onMakeMask();
195 
196     fMaskEffectNode->setVisible(minfo.fVisible);
197     fMaskEffectNode->setShader(std::move(minfo.fMaskShader));
198 }
199 
200 } // namespace internal
201 } // namespace skottie
202