Skip to content

Commit

Permalink
Bug 1676791 - Part 5: Define the finite timeline and use it in Play()…
Browse files Browse the repository at this point in the history
… and Pause(). r=hiro

Based on w3c/csswg-drafts#4842, we define
"has finite timeline", which is a timeline that's not monotonically increasing.
We need this to update start time and hold time for scroll-timeline, so
we play scroll-linked animations as we expected, e.g. GetLocalTime() returns
the correct time value from GetCurrentTimeAsDuration().

Known issue: we still have bugs when setting "animation-play-state:paused".
Will do that in Bug 1741255.

Differential Revision: https://phabricator.services.mozilla.com/D131168
  • Loading branch information
BorisChiou committed Dec 8, 2021
1 parent 0072742 commit bc0659f
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 8 deletions.
36 changes: 28 additions & 8 deletions dom/animation/Animation.cpp
Expand Up @@ -493,7 +493,7 @@ void Animation::UpdatePlaybackRate(double aPlaybackRate) {
// https://drafts.csswg.org/web-animations/#play-state
AnimationPlayState Animation::PlayState() const {
Nullable<TimeDuration> currentTime = GetCurrentTimeAsDuration();
if (currentTime.IsNull() && !Pending()) {
if (currentTime.IsNull() && mStartTime.IsNull() && !Pending()) {
return AnimationPlayState::Idle;
}

Expand Down Expand Up @@ -1350,15 +1350,15 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
AutoMutationBatchForAnimation mb(*this);

bool abortedPause = mPendingState == PendingState::PausePending;

double effectivePlaybackRate = CurrentOrPendingPlaybackRate();

Nullable<TimeDuration> currentTime = GetCurrentTimeAsDuration();
Nullable<TimeDuration> seekTime;
if (effectivePlaybackRate > 0.0 &&
(currentTime.IsNull() || (aLimitBehavior == LimitBehavior::AutoRewind &&
(currentTime.Value() < TimeDuration() ||
currentTime.Value() >= EffectEnd())))) {
mHoldTime.SetValue(TimeDuration(0));
seekTime.SetValue(TimeDuration(0));
} else if (effectivePlaybackRate < 0.0 &&
(currentTime.IsNull() ||
(aLimitBehavior == LimitBehavior::AutoRewind &&
Expand All @@ -1368,9 +1368,19 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
return aRv.ThrowInvalidStateError(
"Can't rewind animation with infinite effect end");
}
mHoldTime.SetValue(TimeDuration(EffectEnd()));
seekTime.SetValue(TimeDuration(EffectEnd()));
} else if (effectivePlaybackRate == 0.0 && currentTime.IsNull()) {
mHoldTime.SetValue(TimeDuration(0));
seekTime.SetValue(TimeDuration(0));
}

if (!seekTime.IsNull()) {
if (HasFiniteTimeline()) {
mStartTime = seekTime;
mHoldTime.SetNull();
ApplyPendingPlaybackRate();
} else {
mHoldTime = seekTime;
}
}

bool reuseReadyPromise = false;
Expand All @@ -1390,7 +1400,8 @@ void Animation::PlayNoUpdate(ErrorResult& aRv, LimitBehavior aLimitBehavior) {
// (b) If we have timing changes (specifically a change to the playbackRate)
// that should be applied asynchronously.
//
if (mHoldTime.IsNull() && !abortedPause && !mPendingPlaybackRate) {
if (mHoldTime.IsNull() && seekTime.IsNull() && !abortedPause &&
!mPendingPlaybackRate) {
return;
}

Expand Down Expand Up @@ -1443,15 +1454,24 @@ void Animation::Pause(ErrorResult& aRv) {

AutoMutationBatchForAnimation mb(*this);

Nullable<TimeDuration> seekTime;
// If we are transitioning from idle, fill in the current time
if (GetCurrentTimeAsDuration().IsNull()) {
if (mPlaybackRate >= 0.0) {
mHoldTime.SetValue(TimeDuration(0));
seekTime.SetValue(TimeDuration(0));
} else {
if (EffectEnd() == TimeDuration::Forever()) {
return aRv.ThrowInvalidStateError("Can't seek to infinite effect end");
}
mHoldTime.SetValue(TimeDuration(EffectEnd()));
seekTime.SetValue(TimeDuration(EffectEnd()));
}
}

if (!seekTime.IsNull()) {
if (HasFiniteTimeline()) {
mStartTime = seekTime;
} else {
mHoldTime = seekTime;
}
}

Expand Down
4 changes: 4 additions & 0 deletions dom/animation/Animation.h
Expand Up @@ -557,6 +557,10 @@ class Animation : public DOMEventTargetHelper,
Document* GetRenderedDocument() const;
Document* GetTimelineDocument() const;

bool HasFiniteTimeline() const {
return mTimeline && !mTimeline->IsMonotonicallyIncreasing();
}

RefPtr<AnimationTimeline> mTimeline;
RefPtr<AnimationEffect> mEffect;
// The beginning of the delay period.
Expand Down
2 changes: 2 additions & 0 deletions dom/animation/AnimationTimeline.h
Expand Up @@ -101,6 +101,8 @@ class AnimationTimeline : public nsISupports, public nsWrapperCache {

virtual Document* GetDocument() const = 0;

virtual bool IsMonotonicallyIncreasing() const = 0;

virtual bool IsScrollTimeline() const { return false; }

protected:
Expand Down
2 changes: 2 additions & 0 deletions dom/animation/DocumentTimeline.h
Expand Up @@ -68,6 +68,8 @@ class DocumentTimeline final : public AnimationTimeline,

Document* GetDocument() const override { return mDocument; }

bool IsMonotonicallyIncreasing() const override { return true; }

protected:
TimeStamp GetCurrentTimeStamp() const;
nsRefreshDriver* GetRefreshDriver() const;
Expand Down
1 change: 1 addition & 0 deletions dom/animation/ScrollTimeline.h
Expand Up @@ -87,6 +87,7 @@ class ScrollTimeline final : public AnimationTimeline {
return {};
}
Document* GetDocument() const override { return mDocument; }
bool IsMonotonicallyIncreasing() const override { return false; }
bool IsScrollTimeline() const override { return true; }

void ScheduleAnimations() {
Expand Down

0 comments on commit bc0659f

Please sign in to comment.