diff --git a/web-animations-2/Overview.bs b/web-animations-2/Overview.bs index 88355c12dcc..58a1cca0aef 100644 --- a/web-animations-2/Overview.bs +++ b/web-animations-2/Overview.bs @@ -106,6 +106,7 @@ previous level of this specification: * an animation effect-specific playback rate, * custom effects. +* Support for non-monotonic (scroll) timelines.

Timing model

@@ -149,6 +150,82 @@ Along with the following updated description:

Setting the timeline of an animation

+The procedure to set the timeline of an animation, +animation, to new timeline which may be null, is as +follows: + +1. Let old timeline be the current timeline of + animation, if any. +1. If new timeline is the same object as old timeline, + abort this procedure. +1. Let |previous play state| be |animation|'s [=play state=]. +1. Let |previous current time| be the |animation|'s [=current time=]. +1. Let |from finite timeline| be true if |old timeline| is not null and + not [=monotonically increasing=]. +1. Let |to finite timeline| be true if |timeline| is not null and not + [=monotonically increasing=]. +1. Let the timeline of animation be new timeline. +1. Set the flag |reset current time on resume| to false. +1. Perform the steps corresponding to the first matching + condition from the following, if any: + +
+ + : If |to finite timeline|, + + :: 1. [=Apply any pending playback rate=] on |animation| + 1. Let |seek time| be zero if [=playback=] rate ≥ 0, and + |animation|'s associated effect end otherwise. + 1. Update the animation based on the first matching condition if any: + +
+ + : If either of the following conditions are true: + * |previous play state| is 'running' or, + * |previous play state| is 'finished' + + :: Set |animation|'s [=start time=] to |seek time|. + + : If |previous play state| is 'paused': + + :: If |previous current time| is resolved: + + :: 1. Set the flag |reset current time on resume| to true. + 1. Set [=start time=] to unresolved. + 1. Set [=hold time=] to |previous current time|. + +

+ This step ensures that the [=current time=] is preserved + even in the case of a pause-pending animation with a resolved [=start time=]. +

+ + :: Otherwise + + :: 1. Set [=start time=] to |seek time|. + +

+ + : If |from finite timeline| and |previous current time| is resolved, + + :: Run the procedure to set the current time to + |previous current time|. + +
+ +1. If the [=start time=] of animation is resolved, make animation's hold time + unresolved. + +

+ This step ensures that the finished play state of + animation is not “sticky” but is re-evaluated + based on its updated current time. +

+ +1. Run the procedure to update an animation's finished state for + animation with the did seek flag set to false, and + the synchronously notify flag set to false. + Issue: If new timeline is null, we should ensure that custom effects get called with an unresolved iteration progress (unless a subsequent change in the same script execution context makes this @@ -194,9 +271,345 @@ descendant effects and custom effects such that the first condition is: > animation effect. +

Setting the current time of an +Animation

+ +The current time of an animation can be set to a new value to +seek the animation. +The procedure for setting the current time is defined in two parts. + +The procedure to silently set the current time of +an animation, animation, to seek time is as follows: + +1. If seek time is an unresolved time value, + then perform the following steps. + + 1. If the current time is resolved, then + throw a TypeError. + + 1. Abort these steps. + +1. Update either animation's hold time or + [=start time=] as follows: + +
+ + : If any of the following conditions are true: + + * animation's hold time is + resolved, or + * animation's [=start time=] + is unresolved, or + * animation has no associated timeline or the + associated timeline is + inactive, or + * animation's [=playback rate=] is 0, + + :: Set animation's hold time to seek time. + + : Otherwise, + :: Set animation's [=start time=] to the result of evaluating + |timeline time| - (|seek time| / [=playback rate=]) + where timeline time is the current time value + of timeline associated with animation. + +
+ +1. If animation has no associated timeline or the associated + timeline is inactive, + make animation's [=start time=] unresolved. + +

+ This preserves the invariant that when we don't have an active timeline it + is only possible to set either the [=start time=] + or the animation's current time. +

+ +1. Make animation's previous current time unresolved. + +1. Set the |reset current time on resume| flag to false. + + +The procedure to set the current time of an animation, +animation, to seek time is as follows: + +1. Run the steps to silently set the current time of + animation to seek time. +1. If animation has a pending pause task, synchronously + complete the pause operation by performing the following steps: + 1. Set animation's hold time to seek time. + 1. [=Apply any pending playback rate=] to |animation|. + 1. Make animation's [=start time=] unresolved. + 1. Cancel the pending pause task. + 1. Resolve animation's + current ready promise with animation. +1. Run the procedure to update an animation's finished state for + animation with the did seek flag set to true, and + the synchronously notify flag set to false. + +

Setting the start time of an +Animation

+ + +The procedure to set the start time +of animation, animation, to new start time, +is as follows: + +1. Let timeline time be the current time value of the + timeline that animation is associated with. + If there is no timeline associated with animation or the + associated timeline is inactive, + let the timeline time be unresolved. + +1. If timeline time is unresolved and new start + time is resolved, make animation's + hold time unresolved. + +

+ This preserves the invariant that when we don't have an active timeline it + is only possible to set either the [=start time=] + or the animation's current time. +

+ +1. Let previous current time be animation's current + time. + + Note: This is the current time after applying the changes from the + previous step which may cause the current time to become + unresolved. + +1. [=Apply any pending playback rate=] on |animation|. + +1. Set animation's [=start time=] to new start time. + +1. Set the |reset current time on resume| flag to false. + +1. Update animation's hold time based on the first matching + condition from the following, + +
+ + : If new start time is resolved, + :: If animation's [=playback rate=] is not zero, + make animation's hold time unresolved. + + : Otherwise (new start time is unresolved), + :: Set animation's hold time to previous current + time even if previous current time is + unresolved. + +
+ +1. If animation has a pending play task or + a pending pause task, cancel that task and + resolve animation's + current ready promise with animation. + +1. Run the procedure to update an animation's finished state for + animation with the did seek flag set to true, and + the synchronously notify flag set to false. +

Playing an animation

-The procedure to [=play an animation=] needs to include scheduling a task for +The procedure to play an animation, animation, given +a flag auto-rewind, is as follows: + +Note: The auto-rewind flag is provided for other specifications +that build on this model but do not require the rewinding behavior, such +as CSS Animations [[CSS-ANIMATIONS-1]]. + +1. Let aborted pause be a boolean flag that is true if + animation has a pending pause task, and false otherwise. +1. Let has pending ready promise be a boolean flag that is + initially false. +1. Let seek time be a time value that is initially unresolved. +1. Let has finite timeline be true if |animation| has an associated + timeline that is not [=monotonically increasing=]. +1. Let previous current time be the |animation|'s [=current time=] +1. If |reset current time on resume| is set: + + * Set previous current time to unresolved. + * Set the |reset curent time on resume| flag to false. + +1. Perform the steps corresponding to the first matching + condition from the following, if any: + +
+ + : If |animation|'s [=effective playback rate=] > 0, + the auto-rewind flag is true and either + animation's: + + * previous current time is unresolved, or + * previous current time < zero, or + * previous current timeassociated effect end, + + :: Set seek time to zero. + + : If |animation|'s [=effective playback rate=] < 0, + the auto-rewind flag is true and either + animation's: + + * previous current time is unresolved, or + * previous current time ≤ zero, or + * previous current time > associated effect end, + :: +
+ + : If associated effect end is positive infinity, + :: throw an "{{InvalidStateError}}" {{DOMException}} and + abort these steps. + : Otherwise, + :: Set seek time to |animation|'s associated effect end. + +
+ + : If |animation|'s [=effective playback rate=] = 0 and |animation|'s + [=current time=] is [=unresolved=], + + :: Set seek time to zero. + +
+ +1. If |seek time| is resolved, + +
+ + : If |has finite timeline| is true, + :: 1. Set animation's start time to seek time. + 1. Let |animation|'s [=hold time=] be unresolved. + 1. [=Apply any pending playback rate=] on |animation|. + : Otherwise, + :: Set animation's hold time to seek time. + +
+ +1. If animation's hold time is resolved, + let its [=start time=] be unresolved. + +1. If animation has a pending play task or a + pending pause task, + + 1. Cancel that task. + 1. Set has pending ready promise to true. + +1. If the following four conditions are all satisfied: + + * |animation|'s [=hold time=] is [=unresolved=], and + * |seek time| is [=unresolved=], and + * |aborted pause| is false, and + * |animation| does not have a [=pending playback rate=], + + abort this procedure. + +1. If has pending ready promise is false, + let animation's current ready promise be + a new promise in the relevant Realm of animation. + +1. Schedule a task to run as soon as animation is ready. + The task shall perform the following steps: + + 1. Assert that at least one of |animation|'s [=start time=] or [=hold + time=] is resolved. + + 1. Let ready time be the time value of + the timeline associated with animation at the moment + when animation became ready. + + 1. Perform the steps corresponding to the first matching condition below, + if any: + +
+ + : If |animation|'s [=hold time=] is resolved, + + :: 1. [=Apply any pending playback rate=] on |animation|. + + 1. Let |new start time| be the result of evaluating + |ready time| - [=hold time=] / [=playback rate=] + for |animation|. + If the [=playback rate=] is zero, let + |new start time| be simply |ready time|. + + 1. Set the [=start time=] of |animation| to |new start time|. + + 1. If |animation|'s [=playback rate=] is not 0, make |animation|'s + [=hold time=] [=unresolved=]. + + : If |animation|'s [=start time=] is resolved and |animation| has + a [=pending playback rate=], + + :: 1. Let |current time to match| be the result of evaluating + (|ready time| - [=start time=]) × + [=playback rate=] for |animation|. + + 1. [=Apply any pending playback rate=] on |animation|. + + 1. If |animation|'s [=playback rate=] is zero, let |animation|'s + [=hold time=] be |current time to match|. + + 1. Let |new start time| be the result of evaluating + |ready time| - |current time to match| / + [=playback rate=] for |animation|. + If the [=playback rate=] is zero, let |new start time| be simply + |ready time|. + + 1. Set the [=start time=] of |animation| to |new start time|. + +
+ + 1. Resolve animation's current + ready promise with animation. + + 1. Run the procedure to update an animation's finished state for + animation with the did seek flag set to false, + and the synchronously notify flag set to false. + +
+ Note that the order of the above two steps is important + since it means that an animation with zero-length associated + effect will resolve its current ready promise + before its current finished promise. +
+ + So long as the above task is scheduled but has yet to run, + animation is described as having a + pending play task. + While the task is running, however, |animation| does not have + a [=pending play task=]. + + If a user agent determines that |animation| is immediately ready, it + may schedule the above task as a microtask such that it runs at the next + microtask checkpoint, but it must + not perform the task synchronously. + +
+ + The above requirement to run the pending play task asynchronously + ensures that code such as the following behaves consistently between + implementations: + +
+    animation.play();
+    animation.ready.then(
+      () => { console.log('Playback commenced'); },
+      () => { console.log('Playback was canceled'); }
+    );
+    // Suppose some condition requires playback to be canceled...
+    animation.cancel();
+    // "Playback was canceled" will be printed to the console.
+    
+ + In the above code, were the [=pending play task=] run synchronously, the + [=current ready promise=] would not be rejected. + +
+ +1. Run the procedure to update an animation's finished state for + animation with the did seek flag set to false, and + the synchronously notify flag set to false. + +Issue: The procedure to [=play an animation=] needs to include scheduling a task for updating [=custom effects=].