Bug 1253476 - Make Animation::Tick do finish actions synchronously; r=hiro

Animation::UpdateTiming takes a SyncNotifyFlag parameter. This is passed to
UpdateFinishedState where it determines how we handle finish actions.

If it is async we queue a microtask where we re-evaluate if the animation is
finished or not before queuing events / resolving promises.

That allows code like the following to _not_ trigger finish events:

```
const animation = elem.animate({...}, 1000);
animation.currentTime += 1000;
animation.effect.updateTiming({ duration: 2000 });
```

(Since the check that the animation is finished will run in a microtask _after_
the call to updateTiming.)

When the flag is "sync" we still don't _actually_ run the finish actions
entirely synchronously: the finished promise is resolved synchronously, but
resolving a promise actually queues a microtask for each callback. Likewise, the
finish event is queued synchronously, but not dispatched.

Since there should be no opportunity for script to run between when we call
Animation::Tick and when we run the next microtask checkpoint (currently at the
end of DocumentTimeline::WillRefresh but that will change slightly in the next
patch in this series) there is no need to introduce the extra "async" microtask
for re-evaluating an animation's finished state. Instead it should be possible
to use the "sync" finishing behavior. Such a change should be unobservable to
Web content but will reduce indirection somewhat.

Differential Revision: https://phabricator.services.mozilla.com/D30318

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brian Birtles 2019-05-20 05:20:17 +00:00
parent 5fe06d1f3c
commit af5c2027d2

View File

@ -650,7 +650,7 @@ void Animation::Tick() {
FinishPendingAt(mTimeline->GetCurrentTimeAsDuration().Value());
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
if (!mEffect) {
return;
@ -1179,7 +1179,7 @@ void Animation::ResumeAt(const TimeDuration& aReadyTime) {
mPendingState = PendingState::NotPending;
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Sync);
// If we had a pending playback rate, we will have now applied it so we need
// to notify observers.