diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index c23e9e6d74d0..0374253ce0c9 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -221,9 +221,11 @@ void KeyframeEffectReadOnly::GetComputedTimingAsDict( ComputedTimingProperties& aRetVal) const { + double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1; const Nullable currentTime = GetLocalTime(); GetComputedTimingDictionary(GetComputedTimingAt(currentTime, - SpecifiedTiming()), + SpecifiedTiming(), + playbackRate), currentTime, SpecifiedTiming(), aRetVal); @@ -232,7 +234,8 @@ KeyframeEffectReadOnly::GetComputedTimingAsDict( ComputedTiming KeyframeEffectReadOnly::GetComputedTimingAt( const Nullable& aLocalTime, - const TimingParams& aTiming) + const TimingParams& aTiming, + double aPlaybackRate) { const StickyTimeDuration zeroDuration; @@ -271,9 +274,15 @@ KeyframeEffectReadOnly::GetComputedTimingAt( // Calculate the time within the active interval. // https://w3c.github.io/web-animations/#active-time StickyTimeDuration activeTime; - if (localTime >= - std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration), - result.mEndTime)) { + + StickyTimeDuration beforeActiveBoundary = + std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime); + StickyTimeDuration activeAfterBoundary = + std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration), + result.mEndTime); + + if (localTime > activeAfterBoundary || + (aPlaybackRate >= 0 && localTime == activeAfterBoundary)) { result.mPhase = ComputedTiming::AnimationPhase::After; if (!result.FillsForwards()) { // The animation isn't active or filling at this time. @@ -282,8 +291,8 @@ KeyframeEffectReadOnly::GetComputedTimingAt( activeTime = std::max(std::min(result.mActiveDuration, result.mActiveDuration + aTiming.mEndDelay), zeroDuration); - } else if (localTime < - std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime)) { + } else if (localTime < beforeActiveBoundary || + (aPlaybackRate < 0 && localTime == beforeActiveBoundary)) { result.mPhase = ComputedTiming::AnimationPhase::Before; if (!result.FillsBackwards()) { // The animation isn't active or filling at this time. @@ -391,6 +400,15 @@ KeyframeEffectReadOnly::GetComputedTimingAt( return result; } +ComputedTiming +KeyframeEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const +{ + double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1; + return GetComputedTimingAt(GetLocalTime(), + aTiming ? *aTiming : SpecifiedTiming(), + playbackRate); +} + // https://w3c.github.io/web-animations/#in-play bool KeyframeEffectReadOnly::IsInPlay() const diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index be1171138098..a7ba2d53305a 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -264,16 +264,13 @@ public: // (because it is not currently active and is not filling at this time). static ComputedTiming GetComputedTimingAt(const Nullable& aLocalTime, - const TimingParams& aTiming); + const TimingParams& aTiming, + double aPlaybackRate); // Shortcut for that gets the computed timing using the current local time as // calculated from the timeline time. ComputedTiming - GetComputedTiming(const TimingParams* aTiming = nullptr) const - { - return GetComputedTimingAt(GetLocalTime(), - aTiming ? *aTiming : SpecifiedTiming()); - } + GetComputedTiming(const TimingParams* aTiming = nullptr) const; void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override; diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 37b6d1f4930a..ad55aa88ba0e 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -652,7 +652,8 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint) ComputedTiming computedTiming = dom::KeyframeEffectReadOnly::GetComputedTimingAt( - Nullable(elapsedDuration), timing); + Nullable(elapsedDuration), timing, + animation.playbackRate()); MOZ_ASSERT(!computedTiming.mProgress.IsNull(), "iteration progress should not be null"); diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index d5e1b1b91306..8987a0017510 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -91,7 +91,8 @@ ElementPropertyTransition::UpdateStartValueFromReplacedTransition() TimeStamp::Now(), mReplacedTransition->mStartTime, mReplacedTransition->mPlaybackRate), - mReplacedTransition->mTiming); + mReplacedTransition->mTiming, + mReplacedTransition->mPlaybackRate); if (!computedTiming.mProgress.IsNull()) { double valuePosition = diff --git a/testing/web-platform/meta/web-animations/timing-model/animation-effects/phases-and-states.html.ini b/testing/web-platform/meta/web-animations/timing-model/animation-effects/phases-and-states.html.ini deleted file mode 100644 index 2df07f090d13..000000000000 --- a/testing/web-platform/meta/web-animations/timing-model/animation-effects/phases-and-states.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[phases-and-states.html] - type: testharness - [Phase calculation for a simple animation effect with negative playback rate] - expected: FAIL - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1286476