[web-animations] Fixing start time and pausing

Hi,

I've been trying to spec the behavior when setting the start time of 
animation player but I've come across some questions like:

* What happens if you set the start time while paused?
* Should you be able to set the start time while idle if the current 
time is already set?
* Should you be able to set the start time to null?
* What about the current time?
etc. etc.

I think these questions are easier to answer if we work out the 
invariants of the model and what these properties mean.

I had a go at doing that and, along the way, I noticed that we don't 
really need the pause flag.

Here's what I came up with:


Invariants / meaning of properties:

1. No current time means we're not applying any effect. This is the idle 
state.
    (The exception is that, at the API level, it can also mean 
"pause-pending" due to the weird behavior we discussed last time[1] that 
I'm still not crazy about.)

2. No start time means we're not playing.
    If we have no start time but we DO have a current time, then we're 
paused in some sense of the word. Either "pause-pending", 
"play-pending", or actually paused.
    (Actually, I think it would be more consistent if we preserved the 
start time while "pause-pending".)

3. Without an active timeline, you can only have EITHER a start time or 
a current time.
     (The start time and current time are tied together by the timeline 
time, so if there's no timeline time you can only set one side of the 
equation.)

4. If you have an active timeline and a resolved start time, the current 
time MUST be resolved.

The key point is 2. I think we can actually represent pausing by an 
unresolved start time. This simplifies the model and helps answer some 
of the tricky questions that arise about start times. In particular I 
think it would look something like this:

Q. What happens if you set the start time while paused?
A. Since pausing is represented by an unresolved start time (2), setting 
the start time to a resolved value plays the animation.
(In fact, 'play()' is just a way of resolving the start time that does a 
few extra steps like waiting until the UA is ready.)

Q. What happens if you set the start time to null while running?
A. Since pausing is represented by an unresolved start time (2), setting 
the start time to null pauses the animation.
(Again, 'pause()' is just a nice way of doing this. In fact, setting the 
start time to null directly actually allows authors to opt-out of the 
"wait to sync up with the compositor" behavior with the caveat that they 
may see the animation jump backwards.)

Q. What happens if you set the start time when you don't have an active 
timeline?
A. If gets set but no effect will be applied until the timeline becomes 
active. This allows scheduling animations before the animation starts. 
For example, a timeline that is inactive until some event happens should 
start playing the animations after that point at their scheduled times.

HOWEVER, based on (3) above, doing so would clear any current time that 
was set. Likewise, if you set the current time after that, the start 
time would be cleared.

Q. What happens if you call play() when you don't have an active timeline?
A. The player sits in the play-pending state until the timeline becomes 
active.

Comparing these two behaviors when the timeline is inactive:

  (i) Setting the start time -> animation is scheduled. Current time is 
unresolved, no effect is applied, start time is resolved. When the 
timeline becomes active the animation plays at its scheduled time. (This 
may cause a sudden change.)

  (ii) Calling play() -> animation is pending. Current time is resolved, 
effect is applied, start time is unresolved. When the timeline becomes 
active the animation plays from its current time.

Q. What about setting the current time to null (i.e. unresolved)?
A. Based on (4) above, this is not allowed when you have an active 
timeline. So the options are:
  (i) throw always
  (ii) throw only when there is an active timeline and resolved start time
  (iii) allow it and also make start time unresolved (this is basically 
what cancelling does)
  (iv) allow it and let the usual behavior take place
       if the animation is running we'll recalculate the current time 
meaning the change will be ignored
       if the animation is paused we'll end up in the idle state
       if the animation is idle we'll stay in the idle state
       if the animation is play-pending we'll just clear the animation 
effect until it starts playing
       if the animation is pause-pending we'll end up in the idle state

(I think (iv) is somehow more correct but (i) is probably ok in the 
short term. It's easier to drop the exception later.)

Apart from the above (mostly edge) cases, this doesn't represent a 
significant change to the observed behavior.

I made a start on writing up these changes here:

   https://github.com/w3c/web-animations/compare/startTimeFixes


On a slightly related note, with regards to changing timelines I think 
the following behavior makes sense:

* active timeline -> active timeline: preserve current time, update 
start time
   (This allows, e.g., driving an animation with a scroll-driven 
timeline / video-synced timeline and then subbing in the document 
timeline when the scroll-action / video playback finishes to let the 
animation run to completion.)

* active timeline -> inactive/no timeline: preserve current time, make 
start time unresolved
   (The current time is usually much more important that the start time. 
If the inactive timeline becomes active, the animation will pick up 
where it left off.)

* inactive/no timeline -> active/inactive/no timeline: we could preserve 
which ever was already set: current time / start time but I think it may 
actually be more consistent to only preserve the current time, if set, 
and treat start times as bound to a particular timeline.

If anyone has any suggestions let me know.

Best regards,

Brian


[1] http://lists.w3.org/Archives/Public/public-fx/2014OctDec/0009.html

Received on Tuesday, 21 October 2014 06:51:13 UTC