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