1 /*
2 * Copyright 2021 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 <iostream>
9 #include "include/core/SkStream.h"
10 #include "modules/skottie/include/Skottie.h"
11 #include "modules/skottie/include/SkottieProperty.h"
12 #include "tests/Test.h"
13
14 using namespace skottie;
15
16 namespace {
17
18 class FakeScalarExpressionEvaluator : public ExpressionEvaluator<float> {
19 public:
evaluate(float t)20 float evaluate(float t) override { return 7.0f; }
21 };
22
23 class FakeVectorExpressionEvaluator : public ExpressionEvaluator<std::vector<float>> {
24 public:
evaluate(float t)25 std::vector<float> evaluate(float t) override { return {0.1f, 0.2f, 0.3f, 1.0f}; }
26 };
27
28 class FakeStringExpressionEvaluator : public ExpressionEvaluator<SkString> {
29 public:
evaluate(float t)30 SkString evaluate(float t) override { return SkString("Hello, world!"); }
31 };
32
33 class FakeExpressionManager : public ExpressionManager {
34 public:
createNumberExpressionEvaluator(const char expression[])35 sk_sp<ExpressionEvaluator<float>> createNumberExpressionEvaluator(
36 const char expression[]) override {
37 return sk_make_sp<FakeScalarExpressionEvaluator>();
38 }
39
createStringExpressionEvaluator(const char expression[])40 sk_sp<ExpressionEvaluator<SkString>> createStringExpressionEvaluator(
41 const char expression[]) override {
42 return sk_make_sp<FakeStringExpressionEvaluator>();
43 }
44
createArrayExpressionEvaluator(const char expression[])45 sk_sp<ExpressionEvaluator<std::vector<float>>> createArrayExpressionEvaluator(
46 const char expression[]) override {
47 return sk_make_sp<FakeVectorExpressionEvaluator>();
48 }
49 };
50
51 class FakePropertyObserver : public PropertyObserver {
52 public:
onOpacityProperty(const char node_name[],const LazyHandle<OpacityPropertyHandle> & opacity_handle)53 void onOpacityProperty(const char node_name[],
54 const LazyHandle<OpacityPropertyHandle>& opacity_handle) override {
55 opacity_handle_.reset(opacity_handle().release());
56 }
57
onTransformProperty(const char node_name[],const LazyHandle<TransformPropertyHandle> & transform_handle)58 void onTransformProperty(const char node_name[],
59 const LazyHandle<TransformPropertyHandle>& transform_handle) override {
60 transform_handle_.reset(transform_handle().release());
61 }
62
onColorProperty(const char node_name[],const LazyHandle<ColorPropertyHandle> & color_handle)63 void onColorProperty(const char node_name[],
64 const LazyHandle<ColorPropertyHandle>& color_handle) override {
65 color_handle_.reset(color_handle().release());
66 }
67
onTextProperty(const char node_name[],const LazyHandle<TextPropertyHandle> & text_handle)68 void onTextProperty(const char node_name[],
69 const LazyHandle<TextPropertyHandle>& text_handle) override {
70 text_handle_.reset(text_handle().release());
71 }
72
73 std::unique_ptr<OpacityPropertyHandle> opacity_handle_;
74 std::unique_ptr<TransformPropertyHandle> transform_handle_;
75 std::unique_ptr<ColorPropertyHandle> color_handle_;
76 std::unique_ptr<TextPropertyHandle> text_handle_;
77 };
78 } // namespace
79
DEF_TEST(Skottie_Expression,r)80 DEF_TEST(Skottie_Expression, r) {
81 static constexpr char json[] =
82 R"({
83 "v": "5.2.1",
84 "w": 100,
85 "h": 100,
86 "fr": 10,
87 "ip": 0,
88 "op": 100,
89 "layers": [
90 {
91 "ip": 0,
92 "op": 100,
93 "ty": 1,
94 "nm": "My Layer",
95 "sr": 1,
96 "ks": {
97 "o": {
98 "a": 0,
99 "k": 100,
100 "ix": 11,
101 "x": "fake; return value is specified by the FakeScalarExpressionEvaluator."
102 },
103 "r": {
104 "a": 0,
105 "k": 0,
106 "ix": 10
107 },
108 "p": {
109 "a": 0,
110 "k": [
111 50,
112 50,
113 0
114 ],
115 "ix": 2,
116 "l": 2
117 },
118 "a": {
119 "a": 0,
120 "k": [
121 50,
122 50,
123 0
124 ],
125 "ix": 1,
126 "l": 2,
127 "x": "fake; return value is specified by the FakeArrayExpressionEvaluator."
128 },
129 "s": {
130 "a": 0,
131 "k": [
132 100,
133 100,
134 100
135 ],
136 "ix": 6,
137 "l": 2
138 }
139 },
140 "ef": [
141 {
142 "ty": 21,
143 "nm": "Fill",
144 "np": 9,
145 "mn": "ADBE Fill",
146 "ix": 1,
147 "en": 1,
148 "ef": [
149 {
150 "ty": 10,
151 "nm": "Fill Mask",
152 "mn": "ADBE Fill-0001",
153 "ix": 1,
154 "v": {
155 "a": 0,
156 "k": 0,
157 "ix": 1
158 }
159 },
160 {
161 "ty": 7,
162 "nm": "All Masks",
163 "mn": "ADBE Fill-0007",
164 "ix": 2,
165 "v": {
166 "a": 0,
167 "k": 0,
168 "ix": 2
169 }
170 },
171 {
172 "ty": 2,
173 "nm": "Color",
174 "mn": "ADBE Fill-0002",
175 "ix": 3,
176 "v": {
177 "a": 0,
178 "k": [
179 1,
180 0,
181 0,
182 1
183 ],
184 "ix": 3,
185 "x": "fake; return value is specified by the FakeArrayExpressionEvaluator."
186 }
187 },
188 {
189 "ty": 7,
190 "nm": "Invert",
191 "mn": "ADBE Fill-0006",
192 "ix": 4,
193 "v": {
194 "a": 0,
195 "k": 0,
196 "ix": 4
197 }
198 },
199 {
200 "ty": 0,
201 "nm": "Horizontal Feather",
202 "mn": "ADBE Fill-0003",
203 "ix": 5,
204 "v": {
205 "a": 0,
206 "k": 0,
207 "ix": 5
208 }
209 },
210 {
211 "ty": 0,
212 "nm": "Vertical Feather",
213 "mn": "ADBE Fill-0004",
214 "ix": 6,
215 "v": {
216 "a": 0,
217 "k": 0,
218 "ix": 6
219 }
220 },
221 {
222 "ty": 0,
223 "nm": "Opacity",
224 "mn": "ADBE Fill-0005",
225 "ix": 7,
226 "v": {
227 "a": 0,
228 "k": 1,
229 "ix": 7
230 }
231 }
232 ]
233 }
234 ],
235 "ao": 0,
236 "sw": 100,
237 "sh": 100,
238 "sc": "#000000",
239 "st": 0,
240 "bm": 0
241 }
242 ]
243 })";
244
245 SkMemoryStream stream(json, strlen(json));
246
247 auto em = sk_make_sp<FakeExpressionManager>();
248 auto observer = sk_make_sp<FakePropertyObserver>();
249
250 auto anim = Animation::Builder()
251 .setExpressionManager(em)
252 .setPropertyObserver(observer)
253 .make(&stream);
254
255 REPORTER_ASSERT(r, anim);
256
257 anim->seekFrameTime(0);
258
259 REPORTER_ASSERT(r, SkScalarNearlyEqual(observer->opacity_handle_->get(), 7.0f));
260 SkPoint anchor_point = observer->transform_handle_->get().fAnchorPoint;
261 REPORTER_ASSERT(r, SkScalarNearlyEqual(anchor_point.fX, 0.1f));
262 REPORTER_ASSERT(r, SkScalarNearlyEqual(anchor_point.fY, 0.2f));
263 REPORTER_ASSERT(r, (observer->color_handle_->get() == SkColor4f{0.1f, 0.2f, 0.3f, 1.0f}.toSkColor()));
264 }
265
DEF_TEST(Skottie_ExpressionText,r)266 DEF_TEST(Skottie_ExpressionText, r) {
267 static constexpr char text_json[] =
268 R"({
269 "layers":[
270 {
271 "ty":5,
272 "ks":{
273 "a":{
274 "k":[
275 0,
276 0
277 ]
278 },
279 "p":{
280 "k":[
281 128,
282 144
283 ]
284 },
285 "o":{
286 "k":100
287 }
288 },
289 "ind":0,
290 "ip":0,
291 "op":2,
292 "nm":"TextLayer_0",
293 "t":{
294 "d":{
295 "k":[
296 {
297 "t":0,
298 "s":{
299 "f": "Helvetica",
300 "s":14,
301 "t":"will be replaced.",
302 "j":0,
303 "ps":[
304 0,
305 0
306 ],
307 "sz":[
308 384,
309 360
310 ],
311 "fc":[
312 0.95686274766921997,
313 0.37254902720451355,
314 0.25490197539329529,
315 1
316 ],
317 "lh":16
318 }
319 }
320 ],
321 "x": "fake; return value is specified by the FakeStringExpressionEvaluator."
322 }
323 }
324 }
325 ],
326 "ip":0,
327 "op":2,
328 "fr":25,
329 "w":1280,
330 "h":720,
331 "ddd":false,
332 "v":"5.2.2",
333 "nm":"skottie_animation",
334 "fonts":{
335 "list":[
336 {
337 "fName": "Helvetica",
338 "fFamily":"external_font_family",
339 "fStyle":"Regular"
340 }
341 ]
342 }
343 })";
344
345 SkMemoryStream stream(text_json, strlen(text_json));
346
347 auto em = sk_make_sp<FakeExpressionManager>();
348 auto observer = sk_make_sp<FakePropertyObserver>();
349
350 auto anim = Animation::Builder()
351 .setExpressionManager(em)
352 .setPropertyObserver(observer)
353 .make(&stream);
354
355 REPORTER_ASSERT(r, anim);
356
357 anim->seekFrameTime(0);
358
359 REPORTER_ASSERT(r, observer->text_handle_->get().fText == SkString("Hello, world!"));
360 }
361