• 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/SkottieJson.h"
11 #include "modules/sksg/include/SkSGRenderEffect.h"
12 #include "src/utils/SkJSON.h"
13 
14 #include <algorithm>
15 #include <iterator>
16 
17 namespace skottie {
18 namespace internal {
19 
EffectBuilder(const AnimationBuilder * abuilder,const SkSize & layer_size)20 EffectBuilder::EffectBuilder(const AnimationBuilder* abuilder, const SkSize& layer_size)
21     : fBuilder(abuilder)
22     , fLayerSize(layer_size) {}
23 
findBuilder(const skjson::ObjectValue & jeffect) const24 EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectValue& jeffect) const {
25     static constexpr struct BuilderInfo {
26         const char*    fName;
27         EffectBuilderT fBuilder;
28     } gBuilderInfo[] = {
29         { "ADBE Drop Shadow"    , &EffectBuilder::attachDropShadowEffect     },
30         { "ADBE Easy Levels2"   , &EffectBuilder::attachEasyLevelsEffect     },
31         { "ADBE Fill"           , &EffectBuilder::attachFillEffect           },
32         { "ADBE Gaussian Blur 2", &EffectBuilder::attachGaussianBlurEffect   },
33         { "ADBE Geometry2"      , &EffectBuilder::attachTransformEffect      },
34         { "ADBE HUE SATURATION" , &EffectBuilder::attachHueSaturationEffect  },
35         { "ADBE Invert"         , &EffectBuilder::attachInvertEffect         },
36         { "ADBE Linear Wipe"    , &EffectBuilder::attachLinearWipeEffect     },
37         { "ADBE Pro Levels2"    , &EffectBuilder::attachProLevelsEffect      },
38         { "ADBE Radial Wipe"    , &EffectBuilder::attachRadialWipeEffect     },
39         { "ADBE Ramp"           , &EffectBuilder::attachGradientEffect       },
40         { "ADBE Shift Channels" , &EffectBuilder::attachShiftChannelsEffect  },
41         { "ADBE Tile"           , &EffectBuilder::attachMotionTileEffect     },
42         { "ADBE Tint"           , &EffectBuilder::attachTintEffect           },
43         { "ADBE Tritone"        , &EffectBuilder::attachTritoneEffect        },
44         { "ADBE Venetian Blinds", &EffectBuilder::attachVenetianBlindsEffect },
45     };
46 
47     const skjson::StringValue* mn = jeffect["mn"];
48     if (mn) {
49         const BuilderInfo key { mn->begin(), nullptr };
50         const auto* binfo = std::lower_bound(std::begin(gBuilderInfo),
51                                              std::end  (gBuilderInfo),
52                                              key,
53                                              [](const BuilderInfo& a, const BuilderInfo& b) {
54                                                  return strcmp(a.fName, b.fName) < 0;
55                                              });
56 
57         if (binfo != std::end(gBuilderInfo) && !strcmp(binfo->fName, key.fName)) {
58             return binfo->fBuilder;
59         }
60     }
61 
62     // Some legacy clients rely solely on the 'ty' field and generate (non-BM) JSON
63     // without a valid 'mn' string.  TODO: we should update them and remove this fallback.
64     enum : int32_t {
65         kTint_Effect         = 20,
66         kFill_Effect         = 21,
67         kTritone_Effect      = 23,
68         kDropShadow_Effect   = 25,
69         kRadialWipe_Effect   = 26,
70         kGaussianBlur_Effect = 29,
71     };
72 
73     switch (ParseDefault<int>(jeffect["ty"], -1)) {
74         case         kTint_Effect: return &EffectBuilder::attachTintEffect;
75         case         kFill_Effect: return &EffectBuilder::attachFillEffect;
76         case      kTritone_Effect: return &EffectBuilder::attachTritoneEffect;
77         case   kDropShadow_Effect: return &EffectBuilder::attachDropShadowEffect;
78         case   kRadialWipe_Effect: return &EffectBuilder::attachRadialWipeEffect;
79         case kGaussianBlur_Effect: return &EffectBuilder::attachGaussianBlurEffect;
80         default: break;
81     }
82 
83     fBuilder->log(Logger::Level::kWarning, &jeffect,
84                   "Unsupported layer effect: %s", mn ? mn->begin() : "(unknown)");
85 
86     return nullptr;
87 }
88 
attachEffects(const skjson::ArrayValue & jeffects,sk_sp<sksg::RenderNode> layer) const89 sk_sp<sksg::RenderNode> EffectBuilder::attachEffects(const skjson::ArrayValue& jeffects,
90                                                      sk_sp<sksg::RenderNode> layer) const {
91     if (!layer) {
92         return nullptr;
93     }
94 
95     for (const skjson::ObjectValue* jeffect : jeffects) {
96         if (!jeffect) {
97             continue;
98         }
99 
100         const auto builder = this->findBuilder(*jeffect);
101         const skjson::ArrayValue* jprops = (*jeffect)["ef"];
102         if (!builder || !jprops) {
103             continue;
104         }
105 
106         const AnimationBuilder::AutoPropertyTracker apt(fBuilder, *jeffect);
107         layer = (this->*builder)(*jprops, std::move(layer));
108 
109         if (!layer) {
110             fBuilder->log(Logger::Level::kError, jeffect, "Invalid layer effect.");
111             return nullptr;
112         }
113     }
114 
115     return layer;
116 }
117 
GetPropValue(const skjson::ArrayValue & jprops,size_t prop_index)118 const skjson::Value& EffectBuilder::GetPropValue(const skjson::ArrayValue& jprops,
119                                                  size_t prop_index) {
120     static skjson::NullValue kNull;
121 
122     if (prop_index >= jprops.size()) {
123         return kNull;
124     }
125 
126     const skjson::ObjectValue* jprop = jprops[prop_index];
127 
128     return jprop ? (*jprop)["v"] : kNull;
129 }
130 
MaskFilterEffectBase(sk_sp<sksg::RenderNode> child,const SkSize & ls)131 MaskFilterEffectBase::MaskFilterEffectBase(sk_sp<sksg::RenderNode> child, const SkSize& ls)
132     : fMaskNode(sksg::MaskFilter::Make(nullptr))
133     , fMaskEffectNode(sksg::MaskFilterEffect::Make(std::move(child), fMaskNode))
134     , fLayerSize(ls) {}
135 
onSync()136 void MaskFilterEffectBase::onSync() {
137     const auto minfo = this->onMakeMask();
138 
139     fMaskEffectNode->setVisible(minfo.fVisible);
140     fMaskNode->setMaskFilter(std::move(minfo.fMask));
141 }
142 
143 } // namespace internal
144 } // namespace skottie
145