We have already resolved to make calling Finish() clear the pause state (see
https://lists.w3.org/Archives/Public/public-fx/2015AprJun/0038.html, item 2).
Doing that involves resolving the start time when the animation is paused.
Furthermore, as a separate change, we resolved to make the finished promise not
resolve when the animation is paused. That suggests making UpdateFinishedState()
only resolve the finished promise when PlayState() == Finished rather than using
IsFinished() which returns true even if the animation is paused.
However, if we compare PlayState() == Finished in UpdateFinishedState() then we
will *not* resolve the finished promise when the animation is play-pending since
PlayState() == Pending in that case (pause-pending is ok since the call to
SetCurrentTime will cause a transition to the Paused state). Furthermore, the
existing call to cancel the pending play task will effectively leave this
animation forever pending. Hence, in this patch we unconditionally fill in the
start time.
--HG--
extra : rebase_source : 499ad0530eac0ee62c8ed2df41360c45abc34816
This is much easier to read at call sites and prevents accidentally using the
default value when another value might be more suitable.
--HG--
extra : rebase_source : b1c05d8bf7b97744e53f2ecc676561f3a4a80888
The point of making pausing async is to allow time to sync up the current time
with the compositor. Setting the current time manually should simply force it to
the specified time and complete the pause action, not abort it. (We do a similar
thing for a pending play. For a pending play we're waiting to establish
a suitable start time. Manually setting the start time in that case simply
forces the start time to the specified time and completes the play operation.)
--HG--
extra : rebase_source : 614ed9ef01204e4137783c0d48e975eb8febbe2a
Animation::ResumeAt contains an assertion that, when we exit the play-pending
state, checks we either have a resolved start time or a resolved hold time.
That's normally true but if we are aborting a pause on animation that is
finished we can end up with a resolved start time (since we don't clear the
start time when we're aborting a pause) and a resolved hold time (either
because the regular finishing behavior set one, or, because play() applied
auto-rewinding behavior and set it).
In that case we should actually respect the hold time and update the start time
when resuming the animation. However, ResumeAt won't update the start time if it
is already set.
This patch fixes that by clearing the start time in DoPlay in the case where we
are aborting a pause and have a hold time.
--HG--
extra : rebase_source : 83f980d6cbc34375274f30f6527992b4fec7f639
This patch makes Cancel() call PostUpdate which clobbers certain state in style
so that animated style is correctly flushed when an animation is cancelled.
The main difficulty with this is that we *don't* want to call this when we're
cancelling an animation as a result of a style update or else we'll trigger
needless work. The pattern elsewhere has been to define a *FromStyle() method
for this case (e.g. CSSAnimation::PlayFromStyle, PauseFromStyle). This isn't
ideal because there's always the danger we will forget to call the appropriate
*FromStyle method. It is, however, consistent. Hopefully in bug 1151731 we'll
find a better way of expressing this.
This patch also updates the method names on PendingAnimationTracker but leaves
a number of local variables which will be fixed in a subsequent patch.
--HG--
rename : dom/animation/PendingPlayerTracker.cpp => dom/animation/PendingAnimationTracker.cpp
rename : dom/animation/PendingPlayerTracker.h => dom/animation/PendingAnimationTracker.h
This patch is a fairly minimal rename of the AnimationPlayer interface. It
leaves a bunch of local variables and helper classes still using the word
"player". These will be addressed in subsequent patches that don't require DOM
peer review.
--HG--
rename : dom/animation/AnimationPlayer.cpp => dom/animation/Animation.cpp
rename : dom/animation/AnimationPlayer.h => dom/animation/Animation.h
rename : dom/webidl/AnimationPlayer.webidl => dom/webidl/Animation.webidl
This patch also tightens up a one or two references to 'target effect' replacing
them with just 'effect'. This is because 'target effect' is longer and easily
confused with 'target element'. 'effect' should be sufficient. 'target element'
is a term from the Web Animations specification and in that context, simply
referring to the 'effect' would sound a little odd.
There are still some other references to "source" in AnimationPlayer such as
HasInPlayerSource and UpdateSourceContent. These are renamed in a subsequent
patch (that doesn't require DOM peer review).
We define KeyframeEffectReadonly in KeyframeEffect.cpp since Web Animations also
defines KeyframeEffect and when we come to implement that I expect we'll define
it in the same class, maybe even using the same object.
This patch also adds a few missing includes in places where
KeyframeEffectReadonly is used so that we're not just cargo-culting it in.
--HG--
rename : dom/animation/Animation.cpp => dom/animation/KeyframeEffect.cpp
rename : dom/animation/Animation.h => dom/animation/KeyframeEffect.h
rename : dom/animation/test/css-animations/test_animation-name.html => dom/animation/test/css-animations/test_effect-name.html
rename : dom/animation/test/css-animations/test_animation-target.html => dom/animation/test/css-animations/test_effect-target.html
rename : dom/animation/test/css-transitions/test_animation-name.html => dom/animation/test/css-transitions/test_effect-name.html
rename : dom/animation/test/css-transitions/test_animation-target.html => dom/animation/test/css-transitions/test_effect-target.html
rename : dom/webidl/Animation.webidl => dom/webidl/KeyframeEffect.webidl
Most of this is fairly obvious. However, the addition of 'override' to
ElementPropertyTransition::Name() is not strictly necessary. It was simply added
because while making these changes I accidentally dropped the 'virtual' keyword
from the method in the superclass and the compiler didn't complain. Adding this
will hopefully make it harder to create the same bug in the future.
--HG--
rename : dom/animation/test/css-animations/test_animation-effect-name.html => dom/animation/test/css-animations/test_animation-name.html
rename : dom/animation/test/css-transitions/test_animation-effect-name.html => dom/animation/test/css-transitions/test_animation-name.html
This is a bit awkward. We lazily set mName to the transition property and then
return it. The reasons for this approach are:
* We don't really want to eagerly fill in mName for all transitions since in
99% of cases we'll never use it and this will lead to wasted allocations.
* The signature of Name() returns a const nsString reference. This is because
Name() is used when building CSS Animations (to compare different copies of
the same animation when updating). For that case we don't really want to
generate unnecessary copies of nsString objects so we return a reference.
However, that means for transitions as well we need to return a reference so
we can't just generate a temporary string on-demand.
As a result we also have to const-cast ourselves so we can update the mName
member. We could make mName mutable but seeing as it's only set once, the
const_cast seems more appropriate.
The tests in dom/animation/tests/ use an old version of idlharness.js that
doesn't support inherited interfaces. As discussed in bug 1152619 we're not
looking at updating these old tests (under dom/imptests) at the moment which
means we won't be able to update the IDL tests in dom/animation/tests/ to
continue passing once we introduce DocumentTimeline as a subinterface of
AnimationTimeline.
As a result, this patch simply the removes the IDL tests for this interface from
dom/animation/tests. However, we have a test for this interface in
web-platform-tests where I've set up a pull request to apply the required
renaming so we should eventually get test coverage for this renaming.
https://github.com/w3c/web-platform-tests/pull/1748
In the long run, all the tests in dom/animation/tests should end up in
web-platform-tests. The main reason they aren't there yet is that most of them
test the mapping between the Web Animations API and CSS and there's currently no
spec defining that so there's no place to put them in the web-platform-tests
repository.
There are a few tests for animation timeline which could be landed in
web-platform-tests (and then removed from dom/animation/tests) but we need to
discuss with Google if this is the desired behavior or not first. For the time
being I have a branch setup for that and I'm leaving the tests in
dom/animation/tests so we continue to test what *we* think the behavior should
be in the meantime. That branch is here:
https://github.com/birtles/web-platform-tests/compare/rename-animation-timeline...birtles:add-hidden-iframe-tests
(I don't understand the motivation for the changes to how it was set,
but this just switches to having two variables for the two uses.)
This fixes the test failures in test_animations_omta.html with OMT
animations enabled.
This patch (finally) puts pausing animations in the pending player map so that
they are resolved asynchronously.
Since this changes the pausing behavior this patch updates a number of tests so
that they continue to pass.
When a pending pause operation is interrupted by a play operation we should
preserve the original start time of the animation so that it appears to continue
moving uninterrupted. At the same time, however, for consistency with other
calls to play(), the operation should complete asynchronously.
This patch adds the method that is called when an asynchronous pause operation
has completed. It is not used yet, however, since we don't yet put
AnimationPlayer objects in the pause-pending map.
This patch (after stepping through the call graph) affects the following
places:
* CommonAnimationManager::GetAnimationsForCompositor, which is used
only by nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer,
which already checks the individual animations (so really no change)
* AnimationPlayerCollection::CanThrottleAnimation
* ActiveLayerTracker::IsStyleAnimated
* nsLayoutUtils::HasAnimationsForCompositor
* nsLayoutUtils::HasAnimations (which is used only to check whether we
can make the 0-opacity optimization)
I believe it makes sense to change all of these locations (although in
the long term we want to throttle (or similar) more animations).
Without this patch, I believe we're forcing the creation of an opacity
layer because we think we have animations to send to it.
This is the main patch for the bug; it makes us use the mechanism added
in bug 1125455 to avoid sending animations that aren't currently
applying to the compositor.
Patch 7 is needed to make this code rerun in all the cases where we need
to rerun it, though.
This patch renames the confusing IsRunning method since IsRunning() is *not*
the same as (PlayState() == AnimationPlayState::Running). It also removes
the old definition to make better re-use of PlayState() and IsInPlay().
This patch adds a method for testing if an animation is "in play" which is
a term defined in the Web Animations spec. This is in preparation for removing
some slightly redundant code in IsRunning and aligning better with the spec.
In preparation for introducing IsInPlay (where "in play" is a term in the Web
Animations spec), this patch aligns the existing IsCurrent with the definition
in the spec that says an animation effect is only current if it is attached
to an animation (player in our current naming) that is not finished. In order
to ensure that we need to pass the animation/player into the method.
This actually changes the behavior of IsCurrent since now we will return false
for animations that are finished. As far as I can tell, all the call sites that
are requesting current animations should only be concerned with animations that
are actually running. If not, they need to be adjusted to look for animations
that are either current or in effect.
This patch simply updates the method that cancels pending plays to also cancel
pending pauses. As it stands, for some of places where this is called it might
not be appropriate to cancel pending pauses but we will adjust each of these
call sites one-by-one in subsequent patches in this series.
IsPaused is used in nsAnimationManager to detect if a newly created animation
should be paused. It is also used inside AnimationPlayer::IsRunning which is
used to determine what animations to send to the compositor (we don't send
paused animations to the compositor). In all these cases we want to treat paused
animations and pause-pending animations alike.
This patch updates IsPaused to include also pause-pending animations. At the
same time it renames IsPaused to IsPausedOrPausing to reflect the change in
behavior.
This patch also adjusts a few nearby one-line functions to put the opening brace
on a new line since apparently this is what the coding style says to do.
This won't actually do anything yet because:
(a) We don't yet add pause-pending players to the PendingPlayerTracker
(b) We never mark pausing players as pending so
AnimationPlayer::TriggerOnNextTick will just ignore them.
These methods will soon be used to start animations that are waiting to start
and also to finish pausing animations that are waiting to pause. As a result
we rename them to TriggerXXX since that's a bit more generic.
There are still references to StartXXX within PendingPlayerTracker. These will
be updated in a subsequent patch once we have the appropriate methods available
on AnimationPlayer to call.
This patch extends the PendingPlayerTracker which is currently used to record
which animations are waiting to play, such that it can also handle animations
which are waiting to complete a pause operation.
It doesn't yet do anything with the pause-pending animations, that will come
in another patch.
A number of animation tests assume that pausing happens instantaneously. This
patch adjust many of those tests so that they will continue to work when
pausing happens asynchronously. In many cases this is possible because we
know the ready promise on AnimationPlayer (soon to be Animation) objects will
be resolved so we can wait on it and it will resolve immediately now, but when
asynchronous pausing is introduced the test the promise won't resolve until
after the pause operation is complete.
There are some tests that can't be so easily adjusted and we will have to fix
these at the same time as we turn on async pausing. However, taking care of
this set of tests now should reduce the size of subsequent patches in this
series.
Now that we have separate tests for checking the initial state of startTime we
can remove these checks from tests for setting the startTime.
Also, while we're at it, we needn't check the playState and animationPlayState
since these should be covered by other tests.
Note that this increases memory use for completed transitions since we
don't throw away the data when the transitions complete. That said,
this matches what we do for CSS Animations, and it's needed (once we
switch to the new rules for starting transitions) to maintain the
invariant that unrelated style changes don't trigger transitions.
The storage issues could be optimized in the future if it turns out to
be a problem, but I think that's unlikely, given that we'll never store
more than one for any element+property combination.
After starting layer animations we set the same start time on content
animations but we don't apply it until the next tick (see bug 1112480 for
background). However, in some circumstances, we can end up creating layer
animations again within the same refresh driver tick. In this case, we should
initialize the animations with the same start time as we previously used.
This patch exposes the pending start time set on content animations so that,
if set, we can use it when building layer animations.
Now that we don't actually start pending animations until the following refresh
driver tick we no longer need to be able to fast-forward the AnimationTimeline
between ticks.
When a player is made pending, we rely on it being added to a pending player
tracker that will eventually start the player. However, there are a few
situations where this might not happen. For example, we can't find a pending
player tracker (e.g. there's no source content or the source content isn't
attached to a document), or the pending player tracker disappeared.
In these cases we still want to ensure that such a player does actually get
started. This patch attempts to detect such situations and start players
accordingly.
There are, unfortunately, currently no tests for this. I have been unsuccessful
in recreating any of the situations these tests are supposed to cover.
This patch switches on the new, "actually start the player in the next refresh
driver tick" behavior. It updates PendingPlayerTracker, adding
a StartPendingPlayersOnNextTick method which calls the appropriate method on
AnimationPlayer. The existing StartPendingPlayers is renamed to
StartPendingPlayersNow and is used for testing only.
Furthermore, since we now expect AnimationPlayer::StartOnNextTick to be
functional, AnimationPlayer::DoPlay is updated to use it when there is no
document available. This should make playing an animation player always
asynchronous, that is, always transition to the pending state temporarily
(unless we are already playing).
Earlier in this patch series we added AnimationPlayer::StartOnNextTick which
takes a ready time parameter expressed in timeline time. In order to call this
method when painting finishes we need to convert the TimeStamp recorded when
painting finished to a timeline time. However, when the timeline is driven by
a refresh driver under test control we can no longer meaningfully do this
conversion since there is no correspondence between the notion of time used to
record the time when painting finished (wallclock time) and the notion of time
used by the timeline (which has been arbitrarily adjusted by test code).
We need a way to detect this situation so that we know not to call
ToTimelineTime in that case.
Alternatively, we could make ToTimelineTime automatically return a null value
when its refresh driver is under test control. However, in this situation
ToTimelineTime can still actually be used to convert a TimeStamp to a timeline
time as long as the TimeStamp is from the same refresh driver. Indeed,
GetCurrentTime does exactly that. So if we were to go down that route we would
have to provide a way for GetCurrentTime to work around that restriction.
For now, this patch puts the onus on the caller of ToTimelineTime to check if
the timeline is under test control first (unless they are passing a TimeStamp
from the same refresh driver, in which case there is no need to check).
This patch makes AnimationPlayer act on requests to StartOnNextTick by checking
for mPendingReadyTime on each tick.
We also check that the ready time is not in the future since currently it might
be possible that we get multiple calls to AnimationPlayer::Tick within a single
refresh driver tick.
Note that this patch shouldn't actually produce any observable change yet,
however, since we don't call StartOnNextTick anywhere.
Adds a method that schedules an animation player to begin on the next tick using
the supplied time as the start time.
We don't call this yet, however, but simply add the method and the
mPendingReadyTime member it sets.
In addition to AnimationPlayer::StartNow, this patch series also makes
AnimationPlayer::Tick start animations.
Since these methods will share a lot of code we first factor out a common
ResumeAt method to encapsulate the common code.
In this patch series we adjust the behavior of animation starting so that the
animation does not actually start until the following refresh driver tick. This
requires some tweaks to tests to ensure they continue to pass.
This patch adds a test that we correctly incorporate the delay when setting
a layer animation's initialCurrentTime.
The notion of 'current time' on layer animations differs from that on main
thread animations in that it does not incorporate the animation delay.
Instead, we wait until an animation's delay has complete before putting it
on the layer and then it we add without delay.
For animations that are still waiting to start we need to factor this delay into
the initialCurrentTime stored on the layer animation so that when we update
the animation's start time it represents the time *after* the delay has
finished. Previously we failed to do this but no tests failed since all existing
tests for delay rely on DOMWindowUtils.advanceTimeAndRefresh which avoids this
particular code path (since we don't add pending animations to layers while
the refresh driver is under test control).
This patch adds a test for animation delay that does not rely on
DOMWindowUtils.advanceTimeAndRefresh which has been confirmed to fail if we
don't incorporate the delay in our calculation of initialCurrentTime.
This patch (finally!) introduces the delayed start behavior. It updates
AnimationPlayer::DoPlay to put animations in the PendingPlayerTracker from
where they are triggered.
This patch also updates nsTransitionManager to set the animation's source
before calling Play as otherwise the AnimationPlayer won't be able to access
the pending player tracker (which it locates by navigating AnimationPlayer ->
Animation (source content) -> target element -> composed doc -> pending player
tracker). In future, when we support setting the AnimationPlayer.source property
we will make this more robust so that the order in which these steps are
performed doesn't matter.
This patch also updates a couple of tests to reflect the fact that
AnimationPlayer will now return the pending state.
This patch adds a test that we correctly incorporate the delay when setting
a layer animation's initialCurrentTime.
The notion of 'current time' on layer animations differs from that on main
thread animations in that it does not incorporate the animation delay.
Instead, we wait until an animation's delay has complete before putting it
on the layer and then it we add without delay.
For animations that are still waiting to start we need to factor this delay into
the initialCurrentTime stored on the layer animation so that when we update
the animation's start time it represents the time *after* the delay has
finished. Previously we failed to do this but no tests failed since all existing
tests for delay rely on DOMWindowUtils.advanceTimeAndRefresh which avoids this
particular code path (since we don't add pending animations to layers while
the refresh driver is under test control).
This patch adds a test for animation delay that does not rely on
DOMWindowUtils.advanceTimeAndRefresh which has been confirmed to fail if we
don't incorporate the delay in our calculation of initialCurrentTime.
This patch (finally!) introduces the delayed start behavior. It updates
AnimationPlayer::DoPlay to put animations in the PendingPlayerTracker from
where they are triggered.
This patch also updates nsTransitionManager to set the animation's source
before calling Play as otherwise the AnimationPlayer won't be able to access
the pending player tracker (which it locates by navigating AnimationPlayer ->
Animation (source content) -> target element -> composed doc -> pending player
tracker). In future, when we support setting the AnimationPlayer.source property
we will make this more robust so that the order in which these steps are
performed doesn't matter.
This patch also updates a couple of tests to reflect the fact that
AnimationPlayer will now return the pending state.
In the future we will want to specifically just update source content without
necessarily triggering any other actions that might take place on a tick (like
queuing events).
We want to time animations from when their first frame is painted. However,
interruptible reflow complicates this since, for a given set of pending
animations, some may be painted whilst others are not. To simplify this we
simply force an uninterruptible reflow when we have animations that are
waiting to start.
We would like to trigger animations from the point when the first frame of the
animation is painted. However, some animations will never trigger a paint (e.g.
animations with an empty keyframes rule). These animations should start start
however. To ensure this, whenever an animation is newly pending we schedule
a paint.
This patch adds a reference from PendingPlayerTracker back to the document
object that owns it. This is used in the next patch in this series to find the
document's root frame for scheduling a paint.
Normally animation players get times from their timeline which is based on the
refresh driver for their associated document. However, for animations that
we time from when their first frame has been rendered, we want to record the
actual time when painting finished as their start time. If we wait until the
next refresh driver tick then the delay between playing an animation and its
actual start will be too great.
In this patch, we introduce a mechanism for fast-forwarding a timeline to a
time between the current refresh driver time and the next refresh driver tick.
By adjusting the timeline rather than the player we maintain a consistent state
(in fact, if we just naively set the animation player start time to the
timestamp value we recorded when painting finished it will appear to start in
the future and the animation will temporarily jump from playing, to waiting to
start, then back to playing again on the next refresh driver tick).
To be completely consistent, however, when we fast-forward the timeline we
should tell all animation players listening to the timeline to mark their
target element as needing a style flush. Otherwise we may be able to observe an
inconsistency between some animation players' current time and the computed
style of their targets.
We don't, however, currently know which players are observing a given timeline.
We will likely introduce that in the near future (in order to implement
AnimationTimeline.getAnimationPlayers) and fix the inconsistency in timing then.
A test later in the patch series verifies this inconsistency so it is easy to
fix in future.
An alternative approach would be to simply record the time when animation should
start, send that time to the compositor but don't actually update the animation
start time on the main thread until the subsequent refresh driver tick. Such
an approach is complex as it introduces an additional state--"finished pending
but not yet started". We will attempt to switch to that approach in bug 1112480.