Re: [csswg-drafts] [web-animations-1] Make updating the playback rate asynchronous

I started working on this and I wanted to make a few notes.

Firstly, I think there are probably three different models for how this *could* behave.

**A. Setting the playback rate does the following _three_ things:**

1. Makes the _start time_ `unresolved`
2. Sets the _hold time_ (just until the async task runs)
3. Updates the _playback rate_

Note that the above three are a set.

If we decide, for example, _not_ to make the _start time_ `unresolved`, then the relationship between _start time_, _current time_, and _playback rate_ will be broken. Furthermore, we'd violate the invariant that only one of the _start time_ and _hold time_ can be set at any given moment.

Likewise, if we _do_ clear the _start time_, but don't set the _hold time_, we won't be able to calculate a _current time_ until the async task runs which would be weird.

**B. Setting the playback rate does nothing until the async task runs**

This is pretty attractive because then everything happens as a batch. It means storing extra state but is otherwise possibly simpler.

However, it's a bit weird from a JS point of view. e.g.

```js
anim.playbackRate = 2;
console.log(anim.playbackRate); // --> '1'? Huh?
```

**C. Setting the playback rate updates the values reported to JS but internally we don't update the state until the async task runs**

This, I think, is actually more complex still.

It seems (A) is the right way to do this and I believe it might match what Chrome does.

In terms of spec changes, I think most of the procedures just need updating to say to cancel the pending playback rate change task in places where we cancel pending play/pause tasks.

As for the procedure to update the playback rate, it seems quite complex.

Considering the desired behavior by playback state I think we have something like:

**Playing**

1. Set the _hold time_ to the _current time_
1. Make _start time_ `unresolved`
1. Update _playback rate_ to the new value
1. Create new ready Promise
1. Wait until we are ready to play with the new playback rate
   1. Calculate the _previous time_ as the current time we'd get from using _ready time_ as the timeline time, and the old _start time_ and _playback rate_.
   1. Do necessary parts of the _silently set the current time_ procedure to update the _start time_ based on the updated playback rate so that the current time matches _previous time_ (and using _ready time_ as the _timeline time_).
   1. Resolve the promise

**Paused/Finished/Idle**
No change needed: these can happen synchronously.
(Ideally we can just do the same as for 'playing' but run the task synchronously and not create new Promise objects.)

**Play pending**
I'm pretty sure we can make the async task from updating the playback rate work in this case. However, there are some odd cases too.

Like if we do:

```js
// Animation is running
anim.playbackRate = 2;
anim.play();
```

When we finish syncing with the compositor, we should calculate the _start time_ from the running time, not the (temporary) hold time.

There might be some way to make the pending play task handle this and re-use it. I'm not sure.

**Pause pending**
In this case, we want to update not the start time, but the hold time using the _previous time_ we calculate above.


I'm not really sure yet how we should factor this out. e.g.

* Should we have a playback rate pending change task which has context "pausing" or "playing" so it knows whether to update the start time or hold time?
* Or should we re-use the play pending task and pause pending task and pass in extra context that tell us:
  * How to calculate the equivalent hold time
  * Something that tell us that when we are doing the pause *not* to preserve the existing hold time

I suspect a variant on the second approach where we just some sort of previous-playback-rate-to-start-time ratio is enough to both:

* allow us to calculate the correct "previous time"
* indicate that we should update the hold time

-- 
GitHub Notification of comment by birtles
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2059#issuecomment-349193523 using your GitHub account

Received on Tuesday, 5 December 2017 04:41:01 UTC