diff --git a/experimental/skottie/SkottieAnimator.cpp b/experimental/skottie/SkottieAnimator.cpp index 6568d1b183..da00beb2fe 100644 --- a/experimental/skottie/SkottieAnimator.cpp +++ b/experimental/skottie/SkottieAnimator.cpp @@ -48,16 +48,20 @@ bool KeyframeIntervalBase::parse(const Json::Value& k, KeyframeIntervalBase* pre prev->fT1 = fT0; } - // default is linear lerp - static constexpr SkPoint kDefaultC0 = { 0, 0 }, - kDefaultC1 = { 1, 1 }; - const auto c0 = ParsePoint(k["i"], kDefaultC0), - c1 = ParsePoint(k["o"], kDefaultC1); + fHold = ParseBool(k["h"], false); - if (c0 != kDefaultC0 || c1 != kDefaultC1) { - fCubicMap = skstd::make_unique(); - // TODO: why do we have to plug these inverted? - fCubicMap->setPts(c1, c0); + if (!fHold) { + // default is linear lerp + static constexpr SkPoint kDefaultC0 = { 0, 0 }, + kDefaultC1 = { 1, 1 }; + const auto c0 = ParsePoint(k["i"], kDefaultC0), + c1 = ParsePoint(k["o"], kDefaultC1); + + if (c0 != kDefaultC0 || c1 != kDefaultC1) { + fCubicMap = skstd::make_unique(); + // TODO: why do we have to plug these inverted? + fCubicMap->setPts(c1, c0); + } } return true; @@ -65,6 +69,12 @@ bool KeyframeIntervalBase::parse(const Json::Value& k, KeyframeIntervalBase* pre float KeyframeIntervalBase::localT(float t) const { SkASSERT(this->isValid()); + + // 'hold' pins to v0 + if (fHold) { + return 0; + } + auto lt = (t - fT0) / (fT1 - fT0); if (fCubicMap) { diff --git a/experimental/skottie/SkottieAnimator.h b/experimental/skottie/SkottieAnimator.h index 4ab877ecaf..c03449d11a 100644 --- a/experimental/skottie/SkottieAnimator.h +++ b/experimental/skottie/SkottieAnimator.h @@ -29,7 +29,7 @@ public: float t0() const { return fT0; } float t1() const { return fT1; } - bool isValid() const { return fT0 < fT1; } + bool isValid() const { return fT0 < fT1 || fHold; } bool contains(float t) const { return t >= fT0 && t <= fT1; } protected: @@ -40,6 +40,8 @@ protected: // through the cubic (if applicable). float localT(float t) const; + bool isHold() const { return fHold; } + private: // Initialized for non-linear interpolation. std::unique_ptr fCubicMap; @@ -47,6 +49,8 @@ private: // Start/end times. float fT0 = 0, fT1 = 0; + + bool fHold = false; }; // Describes a keyframe interpolation interval (v0@t0) -> (v1@t1). @@ -56,10 +60,20 @@ public: bool parse(const Json::Value& k, KeyframeInterval* prev) { SkASSERT(k.isObject()); - return this->INHERITED::parse(k, prev) && - ValueTraits::Parse(k["s"], &fV0) && - ValueTraits::Parse(k["e"], &fV1) && - ValueTraits::Cardinality(fV0) == ValueTraits::Cardinality(fV1) && + if (!this->INHERITED::parse(k, prev) || + !ValueTraits::Parse(k["s"], &fV0)) { + return false; + } + + if (this->isHold()) { + // Hold v1 == v0. + fV1 = fV0; + } else if (!ValueTraits::Parse(k["e"], &fV1)) { + return false; + } + + + return ValueTraits::Cardinality(fV0) == ValueTraits::Cardinality(fV1) && (!prev || ValueTraits::Cardinality(fV0) == ValueTraits::Cardinality(prev->fV0)); }