xref: /aosp_15_r20/external/skia/modules/skottie/src/SkottieTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/core/SkStream.h"
9 #include "include/core/SkSurface.h"
10 #include "modules/skottie/include/Skottie.h"
11 #include "tests/Test.h"
12 
13 #include <cmath>
14 #include <string>
15 #include <tuple>
16 #include <vector>
17 
18 using namespace skottie;
19 
DEF_TEST(Skottie_OssFuzz8956,reporter)20 DEF_TEST(Skottie_OssFuzz8956, reporter) {
21     static constexpr char json[] =
22         "{\"v\":\" \",\"fr\":3,\"w\":4,\"h\":3,\"layers\":[{\"ty\": 1, \"sw\": 10, \"sh\": 10,"
23             " \"sc\":\"#ffffff\", \"ks\":{\"o\":{\"a\": true, \"k\":"
24             " [{\"t\": 0, \"s\": 0, \"e\": 1, \"i\": {\"x\":[]}}]}}}]}";
25 
26     SkMemoryStream stream(json, strlen(json));
27 
28     // Passes if parsing doesn't crash.
29     auto animation = Animation::Make(&stream);
30 }
31 
DEF_TEST(Skottie_Annotations,reporter)32 DEF_TEST(Skottie_Annotations, reporter) {
33     static constexpr char json[] = R"({
34                                      "v": "5.2.1",
35                                      "w": 100,
36                                      "h": 100,
37                                      "fr": 10,
38                                      "ip": 0,
39                                      "op": 100,
40                                      "layers": [
41                                        {
42                                          "ty": 1,
43                                          "ind": 0,
44                                          "ip": 0,
45                                          "op": 1,
46                                          "ks": {
47                                            "o": { "a": 0, "k": 50 }
48                                          },
49                                          "sw": 100,
50                                          "sh": 100,
51                                          "sc": "#ffffff"
52                                        }
53                                      ],
54                                      "markers": [
55                                        {
56                                            "cm": "marker_1",
57                                            "dr": 25,
58                                            "tm": 25
59                                        },
60                                        {
61                                            "cm": "marker_2",
62                                            "dr": 0,
63                                            "tm": 75
64                                        }
65                                      ]
66                                    })";
67 
68     class TestMarkerObserver final : public MarkerObserver {
69     public:
70         void onMarker(const char name[], float t0, float t1) override {
71             fMarkers.push_back(std::make_tuple(name, t0, t1));
72         }
73 
74         std::vector<std::tuple<std::string, float, float>> fMarkers;
75     };
76 
77     SkMemoryStream stream(json, strlen(json));
78     auto observer = sk_make_sp<TestMarkerObserver>();
79 
80     auto animation = skottie::Animation::Builder()
81             .setMarkerObserver(observer)
82             .make(&stream);
83 
84     REPORTER_ASSERT(reporter, animation);
85     REPORTER_ASSERT(reporter, animation->duration() == 10);
86     REPORTER_ASSERT(reporter, animation->inPoint()  == 0.0);
87     REPORTER_ASSERT(reporter, animation->outPoint() == 100.0);
88 
89     REPORTER_ASSERT(reporter, observer->fMarkers.size() == 2ul);
90     REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[0]) == "marker_1");
91     REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[0]) == 0.25f);
92     REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[0]) == 0.50f);
93     REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[1]) == "marker_2");
94     REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[1]) == 0.75f);
95     REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[1]) == 0.75f);
96 }
97 
DEF_TEST(Skottie_Image_Loading,reporter)98 DEF_TEST(Skottie_Image_Loading, reporter) {
99     class TestResourceProvider final : public skresources::ResourceProvider {
100     public:
101         TestResourceProvider(sk_sp<skresources::ImageAsset> single_asset,
102                              sk_sp<skresources::ImageAsset>  multi_asset)
103             : fSingleFrameAsset(std::move(single_asset))
104             , fMultiFrameAsset (std::move( multi_asset)) {}
105 
106     private:
107         sk_sp<ImageAsset> loadImageAsset(const char path[],
108                                          const char name[],
109                                          const char id[]) const override {
110             return strcmp(id, "single_frame")
111                     ? fMultiFrameAsset
112                     : fSingleFrameAsset;
113         }
114 
115         const sk_sp<skresources::ImageAsset> fSingleFrameAsset,
116                                              fMultiFrameAsset;
117     };
118 
119     auto make_animation = [&reporter] (sk_sp<skresources::ImageAsset> single_asset,
120                                        sk_sp<skresources::ImageAsset>  multi_asset,
121                                        bool deferred_image_loading) {
122         static constexpr char json[] = R"({
123                                          "v": "5.2.1",
124                                          "w": 100,
125                                          "h": 100,
126                                          "fr": 10,
127                                          "ip": 0,
128                                          "op": 100,
129                                          "assets": [
130                                            {
131                                              "id": "single_frame",
132                                              "p" : "single_frame.png",
133                                              "u" : "images/",
134                                              "w" : 500,
135                                              "h" : 500
136                                            },
137                                            {
138                                              "id": "multi_frame",
139                                              "p" : "multi_frame.png",
140                                              "u" : "images/",
141                                              "w" : 500,
142                                              "h" : 500
143                                            }
144                                          ],
145                                          "layers": [
146                                            {
147                                              "ty": 2,
148                                              "refId": "single_frame",
149                                              "ind": 0,
150                                              "ip": 0,
151                                              "op": 100,
152                                              "ks": {}
153                                            },
154                                            {
155                                              "ty": 2,
156                                              "refId": "multi_frame",
157                                              "ind": 1,
158                                              "ip": 0,
159                                              "op": 100,
160                                              "ks": {}
161                                            }
162                                          ]
163                                        })";
164 
165         SkMemoryStream stream(json, strlen(json));
166 
167         const auto flags = deferred_image_loading
168             ? static_cast<uint32_t>(skottie::Animation::Builder::kDeferImageLoading)
169             : 0;
170         auto animation =
171             skottie::Animation::Builder(flags)
172                 .setResourceProvider(sk_make_sp<TestResourceProvider>(std::move(single_asset),
173                                                                       std::move( multi_asset)))
174                 .make(&stream);
175 
176         REPORTER_ASSERT(reporter, animation);
177 
178         return  animation;
179     };
180 
181     class TestAsset final : public skresources::ImageAsset {
182     public:
183         explicit TestAsset(bool multi_frame) : fMultiFrame(multi_frame) {}
184 
185         const std::vector<float>& requestedFrames() const { return fRequestedFrames; }
186 
187     private:
188         bool isMultiFrame() override { return fMultiFrame; }
189 
190         sk_sp<SkImage> getFrame(float t) override {
191             fRequestedFrames.push_back(t);
192 
193             return SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10))->makeImageSnapshot();
194         }
195 
196         const bool fMultiFrame;
197 
198         std::vector<float> fRequestedFrames;
199     };
200 
201     {
202         auto single_asset = sk_make_sp<TestAsset>(false),
203               multi_asset = sk_make_sp<TestAsset>(true);
204 
205         // Default image loading: single-frame images are loaded upfront, multi-frame images are
206         // loaded on-demand.
207         auto animation = make_animation(single_asset, multi_asset, false);
208 
209         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
210         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 0);
211         REPORTER_ASSERT(reporter, SkScalarNearlyZero(single_asset->requestedFrames()[0]));
212 
213         animation->seekFrameTime(1);
214         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
215         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 1);
216         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[0], 1));
217 
218         animation->seekFrameTime(2);
219         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
220         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 2);
221         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[1], 2));
222     }
223 
224     {
225         auto single_asset = sk_make_sp<TestAsset>(false),
226               multi_asset = sk_make_sp<TestAsset>(true);
227 
228         // Deferred image loading: both single-frame and multi-frame images are loaded on-demand.
229         auto animation = make_animation(single_asset, multi_asset, true);
230 
231         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 0);
232         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 0);
233 
234         animation->seekFrameTime(1);
235         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
236         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 1);
237         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(single_asset->requestedFrames()[0], 1));
238         REPORTER_ASSERT(reporter, SkScalarNearlyEqual (multi_asset->requestedFrames()[0], 1));
239 
240         animation->seekFrameTime(2);
241         REPORTER_ASSERT(reporter, single_asset->requestedFrames().size() == 1);
242         REPORTER_ASSERT(reporter,  multi_asset->requestedFrames().size() == 2);
243         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(multi_asset->requestedFrames()[1], 2));
244     }
245 }
246 
DEF_TEST(Skottie_Layer_NoType,r)247 DEF_TEST(Skottie_Layer_NoType, r) {
248     static constexpr char json[] =
249         R"({
250              "v": "5.2.1",
251              "w": 100,
252              "h": 100,
253              "fr": 10,
254              "ip": 0,
255              "op": 100,
256              "layers": [
257                {
258                  "ind": 0,
259                  "ip": 0,
260                  "op": 100,
261                  "ks": {}
262                }
263              ]
264            })";
265 
266     SkMemoryStream stream(json, strlen(json));
267     auto anim = Animation::Make(&stream);
268 
269     // passes if we don't crash
270     REPORTER_ASSERT(r, anim);
271 }
272