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 "SkMatrix.h"
9 #include "Skottie.h"
10 #include "SkottieProperty.h"
11 #include "SkStream.h"
12
13 #include "Test.h"
14
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_Properties,reporter)32 DEF_TEST(Skottie_Properties, reporter) {
33 static constexpr char json[] = R"({
34 "v": "5.2.1",
35 "w": 100,
36 "h": 100,
37 "fr": 1,
38 "ip": 0,
39 "op": 1,
40 "layers": [
41 {
42 "ty": 4,
43 "nm": "layer_0",
44 "ind": 0,
45 "ip": 0,
46 "op": 1,
47 "ks": {
48 "o": { "a": 0, "k": 50 }
49 },
50 "shapes": [
51 {
52 "ty": "el",
53 "nm": "geometry_0",
54 "p": { "a": 0, "k": [ 50, 50 ] },
55 "s": { "a": 0, "k": [ 50, 50 ] }
56 },
57 {
58 "ty": "fl",
59 "nm": "fill_0",
60 "c": { "a": 0, "k": [ 1, 0, 0] }
61 },
62 {
63 "ty": "tr",
64 "nm": "shape_transform_0",
65 "o": { "a": 0, "k": 100 },
66 "s": { "a": 0, "k": [ 50, 50 ] }
67 }
68 ]
69 }
70 ]
71 })";
72
73 class TestPropertyObserver final : public PropertyObserver {
74 public:
75 struct ColorInfo {
76 SkString node_name;
77 SkColor color;
78 };
79
80 struct OpacityInfo {
81 SkString node_name;
82 float opacity;
83 };
84
85 struct TransformInfo {
86 SkString node_name;
87 skottie::TransformPropertyValue transform;
88 };
89
90 void onColorProperty(const char node_name[],
91 const PropertyObserver::LazyHandle<ColorPropertyHandle>& lh) override {
92 fColors.push_back({SkString(node_name), lh()->get()});
93 }
94
95 void onOpacityProperty(const char node_name[],
96 const PropertyObserver::LazyHandle<OpacityPropertyHandle>& lh) override {
97 fOpacities.push_back({SkString(node_name), lh()->get()});
98 }
99
100 void onTransformProperty(const char node_name[],
101 const PropertyObserver::LazyHandle<TransformPropertyHandle>& lh) override {
102 fTransforms.push_back({SkString(node_name), lh()->get()});
103 }
104
105 const std::vector<ColorInfo>& colors() const { return fColors; }
106 const std::vector<OpacityInfo>& opacities() const { return fOpacities; }
107 const std::vector<TransformInfo>& transforms() const { return fTransforms; }
108
109 private:
110 std::vector<ColorInfo> fColors;
111 std::vector<OpacityInfo> fOpacities;
112 std::vector<TransformInfo> fTransforms;
113 };
114
115 SkMemoryStream stream(json, strlen(json));
116 auto observer = sk_make_sp<TestPropertyObserver>();
117
118 auto animation = skottie::Animation::Builder()
119 .setPropertyObserver(observer)
120 .make(&stream);
121
122 REPORTER_ASSERT(reporter, animation);
123
124 const auto& colors = observer->colors();
125 REPORTER_ASSERT(reporter, colors.size() == 1);
126 REPORTER_ASSERT(reporter, colors[0].node_name.equals("fill_0"));
127 REPORTER_ASSERT(reporter, colors[0].color == 0xffff0000);
128
129 const auto& opacities = observer->opacities();
130 REPORTER_ASSERT(reporter, opacities.size() == 2);
131 REPORTER_ASSERT(reporter, opacities[0].node_name.equals("shape_transform_0"));
132 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(opacities[0].opacity, 100));
133 REPORTER_ASSERT(reporter, opacities[1].node_name.equals("layer_0"));
134 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(opacities[1].opacity, 50));
135
136 const auto& transforms = observer->transforms();
137 REPORTER_ASSERT(reporter, transforms.size() == 2);
138 REPORTER_ASSERT(reporter, transforms[0].node_name.equals("shape_transform_0"));
139 REPORTER_ASSERT(reporter, transforms[0].transform == skottie::TransformPropertyValue({
140 SkPoint::Make(0, 0),
141 SkPoint::Make(0, 0),
142 SkVector::Make(50, 50),
143 0,
144 0,
145 0
146 }));
147 REPORTER_ASSERT(reporter, transforms[1].node_name.equals("layer_0"));
148 REPORTER_ASSERT(reporter, transforms[1].transform == skottie::TransformPropertyValue({
149 SkPoint::Make(0, 0),
150 SkPoint::Make(0, 0),
151 SkVector::Make(100, 100),
152 0,
153 0,
154 0
155 }));
156 }
157
DEF_TEST(Skottie_Annotations,reporter)158 DEF_TEST(Skottie_Annotations, reporter) {
159 static constexpr char json[] = R"({
160 "v": "5.2.1",
161 "w": 100,
162 "h": 100,
163 "fr": 10,
164 "ip": 0,
165 "op": 100,
166 "layers": [
167 {
168 "ty": 1,
169 "ind": 0,
170 "ip": 0,
171 "op": 1,
172 "ks": {
173 "o": { "a": 0, "k": 50 }
174 },
175 "sw": 100,
176 "sh": 100,
177 "sc": "#ffffff"
178 }
179 ],
180 "markers": [
181 {
182 "cm": "marker_1",
183 "dr": 25,
184 "tm": 25
185 },
186 {
187 "cm": "marker_2",
188 "dr": 0,
189 "tm": 75
190 }
191 ]
192 })";
193
194 class TestMarkerObserver final : public MarkerObserver {
195 public:
196 void onMarker(const char name[], float t0, float t1) override {
197 fMarkers.push_back(std::make_tuple(name, t0, t1));
198 }
199
200 std::vector<std::tuple<std::string, float, float>> fMarkers;
201 };
202
203 SkMemoryStream stream(json, strlen(json));
204 auto observer = sk_make_sp<TestMarkerObserver>();
205
206 auto animation = skottie::Animation::Builder()
207 .setMarkerObserver(observer)
208 .make(&stream);
209
210 REPORTER_ASSERT(reporter, animation);
211
212 REPORTER_ASSERT(reporter, observer->fMarkers.size() == 2ul);
213 REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[0]) == "marker_1");
214 REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[0]) == 0.25f);
215 REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[0]) == 0.50f);
216 REPORTER_ASSERT(reporter, std::get<0>(observer->fMarkers[1]) == "marker_2");
217 REPORTER_ASSERT(reporter, std::get<1>(observer->fMarkers[1]) == 0.75f);
218 REPORTER_ASSERT(reporter, std::get<2>(observer->fMarkers[1]) == 0.75f);
219 }
220