1 /*
2 * Copyright 2018 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/utils/SkottieUtils.h"
9
10 namespace skottie_utils {
11
12 class CustomPropertyManager::PropertyInterceptor final : public skottie::PropertyObserver {
13 public:
PropertyInterceptor(CustomPropertyManager * mgr)14 explicit PropertyInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
15
onColorProperty(const char node_name[],const LazyHandle<skottie::ColorPropertyHandle> & c)16 void onColorProperty(const char node_name[],
17 const LazyHandle<skottie::ColorPropertyHandle>& c) override {
18 const auto key = fMgr->acceptKey(node_name, ".Color");
19 if (!key.empty()) {
20 fMgr->fColorMap[key].push_back(c());
21 }
22 }
23
onOpacityProperty(const char node_name[],const LazyHandle<skottie::OpacityPropertyHandle> & o)24 void onOpacityProperty(const char node_name[],
25 const LazyHandle<skottie::OpacityPropertyHandle>& o) override {
26 const auto key = fMgr->acceptKey(node_name, ".Opacity");
27 if (!key.empty()) {
28 fMgr->fOpacityMap[key].push_back(o());
29 }
30 }
31
onTransformProperty(const char node_name[],const LazyHandle<skottie::TransformPropertyHandle> & t)32 void onTransformProperty(const char node_name[],
33 const LazyHandle<skottie::TransformPropertyHandle>& t) override {
34 const auto key = fMgr->acceptKey(node_name, ".Transform");
35 if (!key.empty()) {
36 fMgr->fTransformMap[key].push_back(t());
37 }
38 }
39
onTextProperty(const char node_name[],const LazyHandle<skottie::TextPropertyHandle> & t)40 void onTextProperty(const char node_name[],
41 const LazyHandle<skottie::TextPropertyHandle>& t) override {
42 const auto key = fMgr->acceptKey(node_name, ".Text");
43 if (!key.empty()) {
44 fMgr->fTextMap[key].push_back(t());
45 }
46 }
47
onEnterNode(const char node_name[],PropertyObserver::NodeType node_type)48 void onEnterNode(const char node_name[], PropertyObserver::NodeType node_type) override {
49 if (node_name == nullptr) {
50 return;
51 }
52 fMgr->fCurrentNode =
53 fMgr->fCurrentNode.empty() ? node_name : fMgr->fCurrentNode + "." + node_name;
54 }
55
onLeavingNode(const char node_name[],PropertyObserver::NodeType node_type)56 void onLeavingNode(const char node_name[], PropertyObserver::NodeType node_type) override {
57 if (node_name == nullptr) {
58 return;
59 }
60 auto length = strlen(node_name);
61 fMgr->fCurrentNode =
62 fMgr->fCurrentNode.length() > length
63 ? fMgr->fCurrentNode.substr(
64 0, fMgr->fCurrentNode.length() - strlen(node_name) - 1)
65 : "";
66 }
67
68 private:
69 CustomPropertyManager* fMgr;
70 };
71
72 class CustomPropertyManager::MarkerInterceptor final : public skottie::MarkerObserver {
73 public:
MarkerInterceptor(CustomPropertyManager * mgr)74 explicit MarkerInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
75
onMarker(const char name[],float t0,float t1)76 void onMarker(const char name[], float t0, float t1) override {
77 // collect all markers
78 fMgr->fMarkers.push_back({ std::string(name), t0, t1 });
79 }
80
81 private:
82 CustomPropertyManager* fMgr;
83 };
84
CustomPropertyManager(Mode mode,const char * prefix)85 CustomPropertyManager::CustomPropertyManager(Mode mode, const char* prefix)
86 : fMode(mode)
87 , fPrefix(prefix ? prefix : "$")
88 , fPropertyInterceptor(sk_make_sp<PropertyInterceptor>(this))
89 , fMarkerInterceptor(sk_make_sp<MarkerInterceptor>(this)) {}
90
91 CustomPropertyManager::~CustomPropertyManager() = default;
92
acceptKey(const char * name,const char * suffix) const93 std::string CustomPropertyManager::acceptKey(const char* name, const char* suffix) const {
94 if (!SkStrStartsWith(name, fPrefix.c_str())) {
95 return std::string();
96 }
97
98 return fMode == Mode::kCollapseProperties
99 ? std::string(name)
100 : fCurrentNode + suffix;
101 }
102
getPropertyObserver() const103 sk_sp<skottie::PropertyObserver> CustomPropertyManager::getPropertyObserver() const {
104 return fPropertyInterceptor;
105 }
106
getMarkerObserver() const107 sk_sp<skottie::MarkerObserver> CustomPropertyManager::getMarkerObserver() const {
108 return fMarkerInterceptor;
109 }
110
111 template <typename T>
112 std::vector<CustomPropertyManager::PropKey>
getProps(const PropMap<T> & container) const113 CustomPropertyManager::getProps(const PropMap<T>& container) const {
114 std::vector<PropKey> props;
115
116 for (const auto& prop_list : container) {
117 SkASSERT(!prop_list.second.empty());
118 props.push_back(prop_list.first);
119 }
120
121 return props;
122 }
123
124 template <typename V, typename T>
get(const PropKey & key,const PropMap<T> & container) const125 V CustomPropertyManager::get(const PropKey& key, const PropMap<T>& container) const {
126 auto prop_group = container.find(key);
127
128 return prop_group == container.end()
129 ? V()
130 : prop_group->second.front()->get();
131 }
132
133 template <typename V, typename T>
set(const PropKey & key,const V & val,const PropMap<T> & container)134 bool CustomPropertyManager::set(const PropKey& key, const V& val, const PropMap<T>& container) {
135 auto prop_group = container.find(key);
136
137 if (prop_group == container.end()) {
138 return false;
139 }
140
141 for (auto& handle : prop_group->second) {
142 handle->set(val);
143 }
144
145 return true;
146 }
147
148 std::vector<CustomPropertyManager::PropKey>
getColorProps() const149 CustomPropertyManager::getColorProps() const {
150 return this->getProps(fColorMap);
151 }
152
getColor(const PropKey & key) const153 skottie::ColorPropertyValue CustomPropertyManager::getColor(const PropKey& key) const {
154 return this->get<skottie::ColorPropertyValue>(key, fColorMap);
155 }
156
setColor(const PropKey & key,const skottie::ColorPropertyValue & c)157 bool CustomPropertyManager::setColor(const PropKey& key, const skottie::ColorPropertyValue& c) {
158 return this->set(key, c, fColorMap);
159 }
160
161 std::vector<CustomPropertyManager::PropKey>
getOpacityProps() const162 CustomPropertyManager::getOpacityProps() const {
163 return this->getProps(fOpacityMap);
164 }
165
getOpacity(const PropKey & key) const166 skottie::OpacityPropertyValue CustomPropertyManager::getOpacity(const PropKey& key) const {
167 return this->get<skottie::OpacityPropertyValue>(key, fOpacityMap);
168 }
169
setOpacity(const PropKey & key,const skottie::OpacityPropertyValue & o)170 bool CustomPropertyManager::setOpacity(const PropKey& key, const skottie::OpacityPropertyValue& o) {
171 return this->set(key, o, fOpacityMap);
172 }
173
174 std::vector<CustomPropertyManager::PropKey>
getTransformProps() const175 CustomPropertyManager::getTransformProps() const {
176 return this->getProps(fTransformMap);
177 }
178
getTransform(const PropKey & key) const179 skottie::TransformPropertyValue CustomPropertyManager::getTransform(const PropKey& key) const {
180 return this->get<skottie::TransformPropertyValue>(key, fTransformMap);
181 }
182
setTransform(const PropKey & key,const skottie::TransformPropertyValue & t)183 bool CustomPropertyManager::setTransform(const PropKey& key,
184 const skottie::TransformPropertyValue& t) {
185 return this->set(key, t, fTransformMap);
186 }
187
188 std::vector<CustomPropertyManager::PropKey>
getTextProps() const189 CustomPropertyManager::getTextProps() const {
190 return this->getProps(fTextMap);
191 }
192
getText(const PropKey & key) const193 skottie::TextPropertyValue CustomPropertyManager::getText(const PropKey& key) const {
194 return this->get<skottie::TextPropertyValue>(key, fTextMap);
195 }
196
setText(const PropKey & key,const skottie::TextPropertyValue & o)197 bool CustomPropertyManager::setText(const PropKey& key, const skottie::TextPropertyValue& o) {
198 return this->set(key, o, fTextMap);
199 }
200
201 namespace {
202
203 class ExternalAnimationLayer final : public skottie::ExternalLayer {
204 public:
ExternalAnimationLayer(sk_sp<skottie::Animation> anim,const SkSize & size)205 ExternalAnimationLayer(sk_sp<skottie::Animation> anim, const SkSize& size)
206 : fAnimation(std::move(anim))
207 , fSize(size) {}
208
209 private:
render(SkCanvas * canvas,double t)210 void render(SkCanvas* canvas, double t) override {
211 fAnimation->seekFrameTime(t);
212
213 const auto dst_rect = SkRect::MakeSize(fSize);
214 fAnimation->render(canvas, &dst_rect);
215 }
216
217 const sk_sp<skottie::Animation> fAnimation;
218 const SkSize fSize;
219 };
220
221 } // namespace
222
ExternalAnimationPrecompInterceptor(sk_sp<skresources::ResourceProvider> rprovider,const char prefixp[])223 ExternalAnimationPrecompInterceptor::ExternalAnimationPrecompInterceptor(
224 sk_sp<skresources::ResourceProvider> rprovider,
225 const char prefixp[])
226 : fResourceProvider(std::move(rprovider))
227 , fPrefix(prefixp) {}
228
229 ExternalAnimationPrecompInterceptor::~ExternalAnimationPrecompInterceptor() = default;
230
onLoadPrecomp(const char[],const char name[],const SkSize & size)231 sk_sp<skottie::ExternalLayer> ExternalAnimationPrecompInterceptor::onLoadPrecomp(
232 const char[], const char name[], const SkSize& size) {
233 if (0 != strncmp(name, fPrefix.c_str(), fPrefix.size())) {
234 return nullptr;
235 }
236
237 auto data = fResourceProvider->load("", name + fPrefix.size());
238 if (!data) {
239 return nullptr;
240 }
241
242 auto anim = skottie::Animation::Builder()
243 .setPrecompInterceptor(sk_ref_sp(this))
244 .make(static_cast<const char*>(data->data()), data->size());
245
246 return anim ? sk_make_sp<ExternalAnimationLayer>(std::move(anim), size)
247 : nullptr;
248 }
249
250 } // namespace skottie_utils
251