Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Keyframe.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
12#include "src/utils/SkJSON.h"
13#include "tests/Test.h"
14
15#include <cmath>
16
17using namespace skottie;
18using namespace skottie::internal;
19
20namespace {
21
22template <typename T>
23class MockProperty final : public AnimatablePropertyContainer {
24public:
25 explicit MockProperty(const char* jprop) {
26 AnimationBuilder abuilder(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
27 nullptr, nullptr,
28 {100, 100}, 10, 1, 0);
29 skjson::DOM json_dom(jprop, strlen(jprop));
30
31 fDidBind = this->bind(abuilder, json_dom.root(), &fValue);
32 }
33
34 explicit operator bool() const { return fDidBind; }
35
36 const T& operator()(float t) { this->seek(t); return fValue; }
37
38private:
39 void onSync() override {}
40
41 T fValue = T();
42 bool fDidBind;
43};
44
45} // namespace
46
47DEF_TEST(Skottie_Keyframe, reporter) {
48 {
49 MockProperty<ScalarValue> prop(R"({})");
51 }
52 {
53 MockProperty<ScalarValue> prop(R"({ "a": 1, "k": [] })");
55 }
56 {
57 // New style
58 MockProperty<ScalarValue> prop(R"({
59 "a": 1,
60 "k": [
61 { "t": 1, "s": 1 },
62 { "t": 2, "s": 2 },
63 { "t": 3, "s": 4 }
64 ]
65 })");
67 REPORTER_ASSERT(reporter, !prop.isStatic());
76 }
77 {
78 // New style hold (hard stops)
79 MockProperty<ScalarValue> prop(R"({
80 "a": 1,
81 "k": [
82 { "t": 1, "s": 1, "h": true },
83 { "t": 2, "s": 2, "h": true },
84 { "t": 3, "s": 4, "h": true }
85 ]
86 })");
88 REPORTER_ASSERT(reporter, !prop.isStatic());
92 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(prop(std::nextafter(2.f, 0.f)), 1));
95 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(prop(std::nextafter(3.f, 0.f)), 2));
98 }
99 {
100 // Legacy style
101 MockProperty<ScalarValue> prop(R"({
102 "a": 1,
103 "k": [
104 { "t": 1, "s": 1, "e": 2 },
105 { "t": 2, "s": 2, "e": 4 },
106 { "t": 3 }
107 ]
108 })");
110 REPORTER_ASSERT(reporter, !prop.isStatic());
119 }
120 {
121 // Legacy style hold (hard stops)
122 MockProperty<ScalarValue> prop(R"({
123 "a": 1,
124 "k": [
125 { "t": 1, "s": 1, "e": 2, "h": true },
126 { "t": 2, "s": 2, "e": 4, "h": true },
127 { "t": 3 }
128 ]
129 })");
131 REPORTER_ASSERT(reporter, !prop.isStatic());
135 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(prop(std::nextafter(2.f, 0.f)), 1));
138 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(prop(std::nextafter(3.f, 0.f)), 2));
141 }
142 {
143 // Static scalar prop (all equal keyframes, using float kf Value)
144 MockProperty<ScalarValue> prop(R"({
145 "a": 1,
146 "k": [
147 { "t": 1, "s": 42, "e": 42 },
148 { "t": 2, "s": 42, "e": 42 },
149 { "t": 3 }
150 ]
151 })");
153 REPORTER_ASSERT(reporter, prop.isStatic());
155 }
156 {
157 // Static vector prop (all equal keyframes, using uint32 kf Value)
158 MockProperty<Vec2Value> prop(R"({
159 "a": 1,
160 "k": [
161 { "t": 1, "s": [4,2], "e": [4,2] },
162 { "t": 2, "s": [4,2], "e": [4,2] },
163 { "t": 3 }
164 ]
165 })");
167 REPORTER_ASSERT(reporter, prop.isStatic());
170 }
171 {
172 // Spatial interpolation [100,100]->[200,200], with supernormal easing:
173 // https://cubic-bezier.com/#.5,-0.5,.5,1.5
174 MockProperty<Vec2Value> prop(R"({
175 "a": 1,
176 "k": [
177 { "t": 0, "s": [100,100],
178 "o":{"x":[0.5], "y":[-0.5]}, "i":{"x":[0.5], "y":[1.5]},
179 "to": [10,15], "ti": [-10,-5]
180 },
181 { "t": 1, "s": [200,200]
182 }
183 ]
184 })");
186 REPORTER_ASSERT(reporter, !prop.isStatic());
187
188 // Not linear.
191
192 // Subnormal region triggers extrapolation.
193 REPORTER_ASSERT(reporter, prop(0.15f).x < 100);
194 REPORTER_ASSERT(reporter, prop(0.15f).y < 100);
195
196 // Supernormal region triggers extrapolation.
197 REPORTER_ASSERT(reporter, prop(0.85f).x > 200);
198 REPORTER_ASSERT(reporter, prop(0.85f).y > 200);
199 }
200}
reporter
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
bool bind(const AnimationBuilder &, const skjson::ObjectValue *, T *)
StateChanged seek(float t)
Definition Animator.h:35
double y
double x
#define T
static SkScalar prop(SkScalar radius, SkScalar newSize, SkScalar oldSize)
Definition rrect.cpp:83