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