[skottie] Allow extra-normal Bezier interpolation AE/Lottie allow Bezier control Ys to be outside the [0..1] range. Update SkCubicMap to do the same. Bug: skia:8931 Change-Id: I54ee8dbb4e6e0a33a917500523c82fe56c854d4a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/205002 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/include/core/SkCubicMap.h b/include/core/SkCubicMap.h index 85ed7dd..1375c78 100644 --- a/include/core/SkCubicMap.h +++ b/include/core/SkCubicMap.h
@@ -16,7 +16,7 @@ * * pt[0] is implicitly { 0, 0 } * pt[3] is implicitly { 1, 1 } - * pts[1,2] are inside the unit square + * pts[1,2].X are inside the unit [0..1] */ class SK_API SkCubicMap { public:
diff --git a/modules/skottie/src/SkottieAnimator.cpp b/modules/skottie/src/SkottieAnimator.cpp index a5323b6..189f421 100644 --- a/modules/skottie/src/SkottieAnimator.cpp +++ b/modules/skottie/src/SkottieAnimator.cpp
@@ -57,7 +57,7 @@ return rec.cmidx < 0 ? lt - : SkTPin(fCubicMaps[rec.cmidx].computeYFromX(lt), 0.0f, 1.0f); + : fCubicMaps[rec.cmidx].computeYFromX(lt); } virtual int parseValue(const skjson::Value&, const AnimationBuilder* abuilder) = 0;
diff --git a/modules/skottie/src/SkottieValue.cpp b/modules/skottie/src/SkottieValue.cpp index eed53ae..5393849 100644 --- a/modules/skottie/src/SkottieValue.cpp +++ b/modules/skottie/src/SkottieValue.cpp
@@ -30,7 +30,6 @@ template <> void ValueTraits<ScalarValue>::Lerp(const ScalarValue& v0, const ScalarValue& v1, float t, ScalarValue* result) { - SkASSERT(t >= 0 && t <= 1); *result = v0 + (v1 - v0) * t; } @@ -183,7 +182,6 @@ template <> void ValueTraits<ShapeValue>::Lerp(const ShapeValue& v0, const ShapeValue& v1, float t, ShapeValue* result) { - SkASSERT(t >= 0 && t <= 1); SkASSERT(v0.fVertices.size() == v1.fVertices.size()); SkASSERT(v0.fClosed == v1.fClosed);
diff --git a/modules/skottie/tests/bezier-extranormal.json b/modules/skottie/tests/bezier-extranormal.json new file mode 100644 index 0000000..cc7f818 --- /dev/null +++ b/modules/skottie/tests/bezier-extranormal.json
@@ -0,0 +1,254 @@ +{ + "assets": [], + "ddd": 0, + "fr": 60, + "h": 500, + "ip": 0, + "layers": [ + { + "ao": 0, + "bm": 0, + "ddd": 0, + "ind": 1, + "ip": 0, + "ks": { + "a": { + "a": 0, + "ix": 1, + "k": [ + 0, + 0, + 0 + ] + }, + "o": { + "a": 0, + "ix": 11, + "k": 100 + }, + "p": { + "s": true, + "x": { + "a": 0, + "ix": 3, + "k": 250 + }, + "y": { + "a": 1, + "ix": 4, + "k": [ + { + "i": { + "x": [ + 0.978 + ], + "y": [ + 2.189 + ] + }, + "o": { + "x": [ + 0.29 + ], + "y": [ + -1.57 + ] + }, + "s": [ + 400 + ], + "t": 0 + }, + { + "s": [ + 100 + ], + "t": 238 + } + ] + } + }, + "r": { + "a": 0, + "ix": 10, + "k": 0 + }, + "s": { + "a": 0, + "ix": 6, + "k": [ + 100, + 100, + 100 + ] + } + }, + "nm": "Shape Layer 1", + "op": 300, + "shapes": [ + { + "d": 1, + "hd": false, + "mn": "ADBE Vector Shape - Ellipse", + "nm": "Ellipse Path 1", + "p": { + "a": 0, + "ix": 3, + "k": [ + 0, + 0 + ] + }, + "s": { + "a": 0, + "ix": 2, + "k": [ + 50, + 50 + ] + }, + "ty": "el" + }, + { + "bm": 0, + "c": { + "a": 0, + "ix": 4, + "k": [ + 1, + 0, + 0, + 1 + ] + }, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "o": { + "a": 0, + "ix": 5, + "k": 100 + }, + "r": 1, + "ty": "fl" + } + ], + "sr": 1, + "st": 0, + "ty": 4 + }, + { + "ao": 0, + "bm": 0, + "ddd": 0, + "ind": 2, + "ip": 0, + "ks": { + "a": { + "a": 0, + "ix": 1, + "k": [ + 250, + 1, + 0 + ] + }, + "o": { + "a": 0, + "ix": 11, + "k": 100 + }, + "p": { + "a": 0, + "ix": 2, + "k": [ + 250, + 400, + 0 + ] + }, + "r": { + "a": 0, + "ix": 10, + "k": 0 + }, + "s": { + "a": 0, + "ix": 6, + "k": [ + 100, + 100, + 100 + ] + } + }, + "nm": "Green Solid 1", + "op": 300, + "sc": "#00ff00", + "sh": 2, + "sr": 1, + "st": 0, + "sw": 500, + "ty": 1 + }, + { + "ao": 0, + "bm": 0, + "ddd": 0, + "ind": 3, + "ip": 0, + "ks": { + "a": { + "a": 0, + "ix": 1, + "k": [ + 250, + 1, + 0 + ] + }, + "o": { + "a": 0, + "ix": 11, + "k": 100 + }, + "p": { + "a": 0, + "ix": 2, + "k": [ + 250, + 100, + 0 + ] + }, + "r": { + "a": 0, + "ix": 10, + "k": 0 + }, + "s": { + "a": 0, + "ix": 6, + "k": [ + 100, + 100, + 100 + ] + } + }, + "nm": "Green Solid 1", + "op": 300, + "sc": "#00ff00", + "sh": 2, + "sr": 1, + "st": 0, + "sw": 500, + "ty": 1 + } + ], + "markers": [], + "nm": "negative bezier", + "op": 300, + "v": "5.5.0", + "w": 500 +} \ No newline at end of file
diff --git a/src/core/SkCubicMap.cpp b/src/core/SkCubicMap.cpp index 56aef11..7656009 100644 --- a/src/core/SkCubicMap.cpp +++ b/src/core/SkCubicMap.cpp
@@ -181,8 +181,8 @@ float b = fCoeff[1].fY; float c = fCoeff[2].fY; float y = ((a * t + b) * t + c) * t; - SkASSERT(y >= 0); - return std::min(y, 1.0f); + + return y; } static inline bool coeff_nearly_zero(float delta) { @@ -190,12 +190,13 @@ } SkCubicMap::SkCubicMap(SkPoint p1, SkPoint p2) { + // Clamp X values only (we allow Ys outside [0..1]). + p1.fX = SkTMin(SkTMax(p1.fX, 0.0f), 1.0f); + p2.fX = SkTMin(SkTMax(p2.fX, 0.0f), 1.0f); + Sk2s s1 = Sk2s::Load(&p1) * 3; Sk2s s2 = Sk2s::Load(&p2) * 3; - s1 = Sk2s::Min(Sk2s::Max(s1, 0), 3); - s2 = Sk2s::Min(Sk2s::Max(s2, 0), 3); - (Sk2s(1) + s1 - s2).store(&fCoeff[0]); (s2 - s1 - s1).store(&fCoeff[1]); s1.store(&fCoeff[2]);
diff --git a/tests/CubicMapTest.cpp b/tests/CubicMapTest.cpp index ff4aae4..db44dc0 100644 --- a/tests/CubicMapTest.cpp +++ b/tests/CubicMapTest.cpp
@@ -43,7 +43,7 @@ for (SkScalar x = dx; x < 1; x += dx) { SkScalar y = cmap.computeYFromX(x); // are we valid and (mostly) monotonic? - if (y < 0 || y > 1 || !nearly_le(prev_y, y)) { + if (!nearly_le(prev_y, y)) { cmap.computeYFromX(x); REPORTER_ASSERT(reporter, false); }