From 7c47a254a78faa18bfc7e669e36621110a9ed40b Mon Sep 17 00:00:00 2001
From: Brian Birtles
spec:dom; type:interface; text:EventTarget
@@ -195,6 +201,10 @@ spec:css-backgrounds-3; type:property;
text:border-top-color
text:border-top
text:border-color
+spec:cssom-1;
+ type: dfn;
+ text: CSS declaration block
+spec:infra; type:dfn; text:list
@@ -592,6 +602,11 @@ a document's load event.
A timeline is considered to be inactive
when its time value is unresolved.
+A timeline is monotonically increasing if its
+reported [=timeline current time|current time=] is always greater than or equal
+than its previously reported [=timeline current time|current time=].
+
Specific types of [=timelines=] may define a procedure to convert a timeline time to an
origin-relative time for [=time value=] |time|, so that the [=time
@@ -621,6 +636,8 @@ a {{Document}} |doc| at timestamp |now|, run these steps:
+1. [=Remove replaced animations=] for |doc|.
+
1. [=Perform a microtask checkpoint=].
Note: This is to ensure that any microtasks queued up as a result of
@@ -681,6 +698,9 @@ Issue(2079): There must be a better term than “origin time”—
Prior to establishing the [=time origin=] for its associated document,
a [=document timeline=] is inactive.
+After a [=document timeline=] becomes [=inactive timeline|active=], it is
+[=monotonically increasing=].
+
A document timeline that is associated with a {{Document}} which is not
an active document is also considered to be
inactive.
@@ -2057,6 +2077,9 @@ is absent or has no observable result.
:: Queued whenever an animation enters the idle play state from
another state. Creating a new animation that is initially
idle does not generate a new cancel event.
+: replace
+:: Queued whenever an animation is automatically removed.
+ See [[#replacing-animations]].
Animation effects
@@ -3682,10 +3705,132 @@ as follows:
href="#the-effect-value-of-a-keyframe-animation-effect"
section>.
+Replacing animations
+
+
+elem.addEventListener('mousemove', evt => {
+ circle.animate(
+ { transform: `translate(${evt.clientX}, ${evt.clientY})` },
+ { duration: 500, fill: 'forwards' }
+ );
+});
+
Replace state
+
+An [=animation=] maintains a replace state that may be one of the
+following values:
+
+* ok
+* removed
+* persisted
+
+The initial value of an [=animation=]'s [=replace state=] is
+[=ok replace state|ok=].
+
+The [=animation effects=] of an [=animation=]
+whose [=replace state=] is [=removed replace state|removed=]
+are not included in the [=effect stacks=] of their [=target properties=].
+
+Performing replacement
+
+An [=animation=] is
+replaceable
+if all of the following conditions are true:
+
+* The existence of the [=animation=] is not prescribed by markup.
+ That is, it is not
+ a CSS animation with an [=owning element (animation)|owning element=], or
+ a CSS transition with an [=owning element (transition)|owning element=].
+* The [=animation=]'s [=play state=] is [=finished play state|finished=].
+* The [=animation=]'s [=replace state=] is not
+ [=removed replace state|removed=].
+* The [=animation=] is associated with a [=monotonically increasing=]
+ [=timeline=].
+* The [=animation=] has an associated [=target effect=].
+* The [=target effect=] associated with the [=animation=] is [=in effect=].
+* The [=target effect=] has an associated [=target element=].
+
+When asked to remove replaced animations
+for a {{Document}}, |doc|,
+then for every [=animation=], |animation|, that:
+
+* has an [=associated with an animation|associated=] [=animation effect=]
+ whose [=target element=] is a [=descendant=] of |doc|, and
+
+* is [=replaceable=], and
+
+* has a [=replace state=] of [=ok replace state|ok=], and
+
+* for which there exists for each [=target property=]
+ of every [=animation effect=]
+ [=associated with an animation|associated=] with |animation|,
+ an [=animation effect=] associated with a [=replaceable=] [=animation=]
+ with a higher [=composite order=] than |animation|
+ that includes the same [=target property=].
+
+perform the following steps:
+
+1. Set |animation|'s [=replace state=] to [=removed replace state|removed=].
+
+1. Create an {{AnimationPlaybackEvent}},
+ |replaceEvent|.
+
+1. Set |replaceEvent|'s {{Event/type}} attribute to
+ replace.
+
+1. Set |replaceEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
+ to the [=current time=] of |animation|.
+
+1. Set |replaceEvent|'s {{AnimationPlaybackEvent/timelineTime}}
+ attribute to the current time
+ of the [=timeline=] with which |animation| is associated.
+
+1. If |animation| has a [=document for timing=], then append
+ |replaceEvent| to its [=document for timing=]'s
+ [=pending animation event queue=] along with its target, |animation|.
+ For the [=scheduled event time=], use the result of converting
+ |animation|'s [=target effect end=] to an origin-relative time.
+
+ Otherwise, [=queue a task=] to [=dispatch=] |replaceEvent| at
+ |animation|.
+ The task source for this task is the [=DOM manipulation task
+ source=].
+
+Issue: According to the above logic,
+if the author calls {{Animation/persist()}} on an {{Animation}} prior to it
+being replaced, we will never dispatch a replace event.
+Does that suggest the event should be called “remove” instead?
+
Side effects of animation
For every property targeted by at least one animation effect that is
-current or in effect, the user agent must act as if the
+current or in effect,
+and which is associated with an [=animation=] whose [=replace state=]
+is not [=removed replace state|removed=],
+the user agent must act as if the
'will-change' property ([[!css-will-change-1]]) on the target element
includes the property.
@@ -3808,17 +3953,21 @@ interface Animation : EventTarget {
attribute double? currentTime;
attribute double playbackRate;
readonly attribute AnimationPlayState playState;
+ readonly attribute AnimationReplaceState replaceState;
readonly attribute boolean pending;
readonly attribute Promise<Animation> ready;
readonly attribute Promise<Animation> finished;
attribute EventHandler onfinish;
attribute EventHandler oncancel;
+ attribute EventHandler onreplace;
void cancel ();
void finish ();
void play ();
void pause ();
void updatePlaybackRate (double playbackRate);
void reverse ();
+ void persist ();
+ void commitStyles (optional sequence<DOMString> properties);
};
@@ -3900,6 +4049,8 @@ interface Animation : EventTarget {
: playState
:: The play state of this animation.
+: replaceState
+:: The replace state of this animation.
: pending
:: Returns true if this animation has a pending play task or
a pending pause task.
@@ -3911,6 +4062,8 @@ interface Animation : EventTarget {
:: The event handler for the finish event.
: oncancel
:: The event handler for the cancel event.
+: onreplace
+:: The event handler for the replace event.
@@ -3960,9 +4113,144 @@ interface Animation : EventTarget {
method unpauses the animation and, if the animation has already finished
playing in the reversed direction, seeks to the start of the target
effect.
+: void persist()
+:: Sets this animation's [=replace state=] to
+ [=persisted replace state|persisted=].
+: void commitStyles()
+:: Writes the current [=effect values=]
+ produced by this animation's [=animation effects=]
+ to their corresponding [=target elements=]' inline style
+ using the [=commit computed styles=] procedure
+ passing {{Animation/commitStyles(properties)/properties}}
+ as the list of property names.
+
+ CSSAnimation
or
+ CSSTransition
targeting a pseudo-element.
+
+ 1. Let |physicalProperties| be a [=ordered set|set=] of CSS property
+ names with the same contents as |longhandProperties| but
+ with each logical property name in |longhandProperties|
+ replaced with the [=equivalent physical properties=] based on the
+ computed value of 'writing-mode', 'direction', and
+ 'text-orientation' for |target|.
+
+ 1. Let |inline style| be the result of getting the
+ [=CSS declaration block=] corresponding to |target|'s
+ [=style attribute=].
+ If |target| does not [=has an attribute|have=]
+ a [=style attribute=],
+ let |inline style| be a new empty [=CSS declaration block=] with
+ the readonly flag unset and
+ owner node set to |target|.
+
+ 1. Let |targeted properties| be the [=ordered set|set=]
+ of physical longhand properties
+ that are a [=target property=] for at least one [=animation effect=]
+ [=associated with an animation|associated=] with |animation|
+ whose [=target element=] is |target|.
+
+ 1. For each property, |property|, in |targeted properties|:
+
+ 1. If |filterProperties| is true and |physicalProperties|
+ does not include |property|, proceed to the next
+ property.
+
+ 1. Let |partialEffectStack| be a copy of the [=effect stack=]
+ for |property| on |target|.
+
+ 1. If |animation|'s [=replace state=] is
+ [=removed replace state|removed=],
+ add all [=animation effects=]
+ [=associated with an animation|associated=] with |animation|
+ whose [=target element=] is |target| and which include
+ |property| as a [=target property=] to |partialEffectStack|.
+
+ 1. Remove from |partialEffectStack| any [=animation effects=]
+ whose [=associated with an animation|associated=] [=animation=]
+ has a higher [=composite order=] than |animation|.
+
+ 1. Let |effect value| be the result of calculating the result of
+ |partialEffectStack| for |property| using |target|'s computed
+ style (see [[#calculating-the-result-of-an-effect-stack]]).
+
+ 1. [=Set a CSS declaration=] |property| for |effect value| in
+ |inline style|.
+
+ 1. [=Update style attribute for=] |inline style|.
+
+Issue: The above needs to define what happens for the case of non-rendered
+ elements since they won't have a resolved ''writing-mode'' etc. to
+ resolve against.
+
The
AnimationPlayState
enumeration
@@ -3978,6 +4266,19 @@ enum AnimationPlayState { "idle", "running", "paused", "finished" };
:
:
sequence<Animation> getAnimations()
-:: Returns the set of {{Animation}} objects
- whose target effect is current or in effect and
- contains at least one animation effect whose
+:: Returns the set of [=relevant=] {{Animation}} objects
+ that contain at least one animation effect whose
target element is this object.
+ An [=animation=] is
+ relevant if:
+
+ * Its [=target effect=] is [=current=] or [=in effect=],
+ and
+ * Its [=replace state=] is not [=removed replace state|removed=].
+
The returned list is sorted using the composite order described
for the associated animations of effects in [[#the-effect-stack]].
@@ -5499,10 +5806,9 @@ partial interface Document {
:
sequence<Animation> getAnimations()
-:: Returns the set of {{Animation}} objects
- that have an associated target effect which is current or
- in effect and whose target element is a descendant
- of the document.
+:: Returns the set of [=relevant=] {{Animation}} objects
+ that have an associated target effect
+ whose target element is a descendant of the document.
The returned list is sorted using the composite order described
for the associated animations of effects in [[#the-effect-stack]].
@@ -5512,17 +5818,6 @@ partial interface Document {
any pending style changes to animation such as changes to animation-related
style properties that have yet to be processed.
- Issue(2054): Both this method and {{Animatable/getAnimations()}} on the
- {{Animatable}} interface mixin require retaining
- forwards-filling animation effects and their
- animations such that a document that
- repeatedly produces forwards-filling animations will consume
- memory in an unbounded fashion.
- We may need to revise this definition (previously these methods
- only returned animations whose target effect was
- current) or provide a loophole for implementations to
- discard old animations in such conditions.
-
finished
:: Corresponds to the finished play state.
+The
+
+AnimationReplaceState
enumeration
+enum AnimationReplaceState { "ok", "removed", "persisted" };
+
+
+: ok
+:: Corresponds to the [=ok replace state=].
+: removed
+:: Corresponds to the [=removed replace state=].
+: persisted
+:: Corresponds to the [=persisted replace state=].
+
The
Animation effects are represented in the Web Animations API by the
@@ -5451,11 +5752,17 @@ animation.play();AnimationEffect
interfaceExtensions to the
@@ -5845,6 +6140,15 @@ The following changes have been made since the #3193).
* Updated the steps for resolving which properties to use when calculating
[=computed keyframes=] when physical and logical properties are used.
+* Introduced steps for removing animations that have been overridden:
+ [[#replacing-animations]].
+ * Added a new [=replace event=] to signal when this process occurs.
+ * Added corresponding IDL members to the {{Animation}} interface:
+ {{Animation/replaceState}},
+ {{Animation/onreplace}},
+ {{Animation/persist}}.
+* Added the {{Animation/commitStyles}} method to the {{Animation}} interface
+ to allow preserving the result of an [=animation=] that has been removed.
The changelog
From 51abea5c47cc570fefa8e6fcb43ff129e524a1e0 Mon Sep 17 00:00:00 2001
From: Brian Birtles Element
interfacePerforming replacement
+Removing replaced animations
An [=animation=] is
replaceable
@@ -3795,35 +3795,30 @@ perform the following steps:
1. Set |animation|'s [=replace state=] to [=removed replace state|removed=].
1. Create an {{AnimationPlaybackEvent}},
- |replaceEvent|.
+ |removeEvent|.
-1. Set |replaceEvent|'s {{Event/type}} attribute to
- replace.
+1. Set |removeEvent|'s {{Event/type}} attribute to
+ remove.
-1. Set |replaceEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
+1. Set |removeEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
to the [=current time=] of |animation|.
-1. Set |replaceEvent|'s {{AnimationPlaybackEvent/timelineTime}}
+1. Set |removeEvent|'s {{AnimationPlaybackEvent/timelineTime}}
attribute to the current time
of the [=timeline=] with which |animation| is associated.
1. If |animation| has a [=document for timing=], then append
- |replaceEvent| to its [=document for timing=]'s
+ |removeEvent| to its [=document for timing=]'s
[=pending animation event queue=] along with its target, |animation|.
For the [=scheduled event time=], use the result of converting
|animation|'s [=target effect end=] to an origin-relative time.
- Otherwise, [=queue a task=] to [=dispatch=] |replaceEvent| at
+ Otherwise, [=queue a task=] to [=dispatch=] |removeEvent| at
|animation|.
The task source for this task is the [=DOM manipulation task
source=].
-Issue: According to the above logic,
-if the author calls {{Animation/persist()}} on an {{Animation}} prior to it
-being replaced, we will never dispatch a replace event.
-Does that suggest the event should be called “remove” instead?
-
Side effects of animation
For every property targeted by at least one animation effect that is
@@ -3959,7 +3954,7 @@ interface Animation : EventTarget {
readonly attribute Promise<Animation> finished;
attribute EventHandler onfinish;
attribute EventHandler oncancel;
- attribute EventHandler onreplace;
+ attribute EventHandler onremove;
void cancel ();
void finish ();
void play ();
@@ -4062,8 +4057,8 @@ interface Animation : EventTarget {
:: The event handler for the finish event.
: oncancel
:: The event handler for the cancel event.
-: onreplace
-:: The event handler for the replace event.
+: onremove
+:: The event handler for the remove event.
@@ -4127,8 +4122,8 @@ interface Animation : EventTarget {
InvalidStateError
+ : DOMException of type {{InvalidStateError}}
:: Raised if this animation's [=playback rate=] is zero, or if this
animation's [=playback rate=] is > zero and the
end time of this animation's target effect is infinity.
@@ -4185,11 +4185,8 @@ To commit computed styles for an [=animation=],
attribute=] [[!CSS-STYLE-ATTR]]
(for example, it is a pseudo-element or is an element in
a document format for which style attributes are not defined)
- proceed to the next item in |targets|.
-
- Issue: Should we throw an exception here? This is only likely to
- occur if the author recycles a CSSAnimation
or
- CSSTransition
targeting a pseudo-element.
+ throw a "{{NoModificationAllowedError}}" {{DOMException}}
+ and abort these steps.
1. Let |physicalProperties| be a [=ordered set|set=] of CSS property
names with the same contents as |longhandProperties| but
From 6d27bc9346f814dcfcedffa682cb2efc6753bac4 Mon Sep 17 00:00:00 2001
From: Brian Birtles The
AnimationPlayState
enumeration
From b4f26d41b609d4f48de65784374f8e277822ddef Mon Sep 17 00:00:00 2001
From: Brian Birtles
The
AnimationReplaceState
enumeration
-enum AnimationReplaceState { "ok", "removed", "persisted" };
+enum AnimationReplaceState { "active", "removed", "persisted" };
-: ok
-:: Corresponds to the [=ok replace state=].
+: active
+:: Corresponds to the [=active replace state=].
: removed
:: Corresponds to the [=removed replace state=].
: persisted
From 0c38b54821aa5b27d9643c6694e4f4cd5aa0ddc4 Mon Sep 17 00:00:00 2001
From: Brian Birtles
+
+ : If |propertyName| corresponds to a CSS shorthand property name,
+ :: append each longhand property
that |propertyName| maps to,
to |longhandProperties|.
- 1. Otherwise,
- append |propertyName| to |longhandProperties|.
+ : Otherwise,
+ :: append |propertyName| to |longhandProperties|.
+
+
1. Let |targets| be the [=ordered set|set=] of all [=target elements=]
for [=animation effects=] [=associated with an animation|associated=]
From 5f0df9a6abe809ba580f5a6b2d3fbc2cff336864 Mon Sep 17 00:00:00 2001
From: Brian Birtles