Do some minor revisions in struct ComputedTiming.
1. Use Nullable<double> mProgress, so remove the static const kNullProgress.
The generated ComputedTimingProperties dictionary uses "Nullable" variable,
so we replace the origin type in ComputedTiming to make it more consistent
with that in ComputedTimingProperties dictionary.
2. Use scoped enums for AnimationPhase.
The bulk of this commit was generated with a script, executed at the top
level of a typical source code checkout. The only non-machine-generated
part was modifying MFBT's moz.build to reflect the new naming.
CLOSED TREE makes big refactorings like this a piece of cake.
# The main substitution.
find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \
xargs perl -p -i -e '
s/nsRefPtr\.h/RefPtr\.h/g; # handle includes
s/nsRefPtr ?</RefPtr</g; # handle declarations and variables
'
# Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h.
perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h
# Handle nsRefPtr.h itself, a couple places that define constructors
# from nsRefPtr, and code generators specially. We do this here, rather
# than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename
# things like nsRefPtrHashtable.
perl -p -i -e 's/nsRefPtr/RefPtr/g' \
mfbt/nsRefPtr.h \
xpcom/glue/nsCOMPtr.h \
xpcom/base/OwningNonNull.h \
ipc/ipdl/ipdl/lower.py \
ipc/ipdl/ipdl/builtin.py \
dom/bindings/Codegen.py \
python/lldbutils/lldbutils/utils.py
# In our indiscriminate substitution above, we renamed
# nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up.
find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \
xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g'
if [ -d .git ]; then
git mv mfbt/nsRefPtr.h mfbt/RefPtr.h
else
hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h
fi
This patch renames AnimationCollection::mNeedsRefreshes to indicate that it
no longer has any relationship to whether or not we observe the refresh driver.
In order to sort between events that have the same timestamp we use the
sort order of the corresponding animations so we need to store a pointer
to the animation along with the event.
This patch lines up the parameters of AnimationEventInfo and
TransitionEventInfo constructors so that they are more logical and consistent.
Specifically, it groups the element and pseudo type together since they
form a logical pair denoting the event target. For AnimationEventInfo this
patch also places the type of event before the common event parameters since
the event type seems to be more significant.
This patch also performs some miscelleaneous housekeeping: removing some
unnecessary namespace prefixes, whitespace fixes, and making
TransitionEventInfo use the same concrete type to store the target element
as AnimationEventInfo (dom::Element instead of nsIContent).
The Web Animations specification has replaced the term "sequence number" with
references to a global animation list. This patch applies similar naming
to our animation structures.
We currently determine if we need refresh driver ticks when composing style
but sometimes we might not need ticks for composing style but we might need
one more tick in order to queue a final end event. Currently, this doesn't
seem to be a problem because FlushAnimations calls Animation::Tick where we
queue up events. When we remove the call to Animation::Tick from
FlushAnimations in order to make FlushAnimations purely responsible for
posting restyles, however, we will create a situation where we might mark an
animation collection as no longer needing refreshes and not simultaneously
queueing the corresponding event. If another animation collection is deleted in
the meantime we may trigger the code that causes us to disassociate from the
refresh driver and the corresponding event will never be dispatched.
Long-term (bug 1195180) we will check if it we can stop observing the refresh
driver and queue events in the same step. Until then, this patch adds a method
to detect this particular situation and uses it to avoid unregistering from
the refresh driver while we still have end events to queue.
In bug 1195180 we plan to tick animations from their timeline where they
are stored in a hashtable. As a result, we will not visit them in order of
their associated target element (indeed, part of the reason we are doing
this is to support animations that do not have, or even have multiple target
elements).
The current animation mutation observer batching mechanism, however, assumes
that we visit each target element in turn and make all the necessary work at
once. In order to support visiting animations in a potentially random order
this patch reworks the animation mutation observer batching mechanism so that
it can support batching multiple elements at once.
When updating the cascade results between transitions and animations, if we
detect a change we force an update by taking the following steps:
a. Updating the animation generation on the restyle manager
b. Updating the animation generation on the collection
c. Iterating over all the properties animated by the collection and, for
each property that we can animate on the compositor, posting a restyle
event with the appropriate change hint (nsChangeHint_UpdateTransformLayer
or nsChangeHint_UpdateTransformOpacity)
d. Marking the collection as needing refreshes
e. Clearing the style rule refresh time so we generate a new style rule in
EnsureStyleRuleFor
As it turns out, the newly-added
AnimationCollection::RequestRestyle(RestyleType::Layer) already performs a, b,
d, and e. It also:
* Ensures we are observing the refresh driver if need be (should have no effect
in this case)
* Clears the last animation style update time on the pres context so that
subsequent calls to FlushPendingNotifications will update animation style
(it seems like we probably should have been doing this for changes to cascade
results anyway)
* Posts a restyle event with restyle hint eRestyle_CSSTransitions or
eRestyle_CSSAnimations
* Marks the document as needing a style flush (irrelevant since posting
a restyle event does this anyway)
The only missing piece that would prevent using RequestRestyle in place of this
code when updating cascade results is (c) from the list above. However, (c)
should not be necessary since ElementRestyler::AddLayerChangesForAnimation()
explicitly checks for out-of-date layer animation generation numbers and adds
the appropriate change hints (nsChangeHint_UpdateTransformLayer etc.) to the
change list.
EnsureStyleRuleFor contains logic for performing throttled updates to the style
rule but it is only used in one case: inside
nsTransitionManager::UpdateCascadeResults to determine what properties are
being animated by CSS animations.
We would like to remove throttling logic from EnsureStyleRuleFor altogether but
if that one case where it is currently used is run on every tick then removing
this logic could effectively mean we end up updating the style rule on every
tick. Fortunately nsTransitionManager::UpdateCascadeResults is only called
in the following cases:
1. From nsTransitionManager::StyleContextChanged (via
TransitionManager::UpdateCascadeResultsWithTransitions), when we are
processing style changes for transitions.
2. From AnimationCollection::EnsureStyleRuleFor (via
nsAnimationManager::MaybeUpdateCascadeResults and
nsTransitionManager::UpdateCascadeResultsWithAnimations), when we are
updating the animation style rule from CSS animations.
3. From nsAnimationManager::CheckAnimationRule (via
TransitionManager::UpdateCascadeResultsWithAnimationsToBeDestroyed), when
we are processing style changes for CSS animations.
None of these things should be happenning on a regular throttle-able tick so by
removing this logic we shouldn't be causing any additional work.
I have verified, using a test case that combines transitions and animations on
the same property, that we have the same behavior with regard to calling
EnsureStyleRuleFor both before and after this patch (specifically we avoid
calling it altogether while running only the transition but when the animation
starts and clobbers the transition we end up calling EnsureStyleRuleFor once on
each tick).
nsTransitionManager::WillRefresh and nsAnimationManager::WillRefresh are now
identical and all methods they call exist on CommonAnimationManager so we
can unify them there.
The implementations of FlushAnimations and FlushTransitions should now be all
but equivalent so this patch combines them into a single implementation on
CommonAnimationManager.
Regarding some of the minor differences between the two methods:
* The combined implementation drops the check for an empty list of collections
found only in FlushTransitions. This seems like a very minor optimization
that could possibly cause us to fail to unregister from the refresh driver
if we forgot to do so when removing the last collection.
* The combined implementation uses the loop implementation from FlushAnimations
since it is more compact.
This patch also removes the extra nested scope since it doesn't seem necessary.
There are a couple of assertions that only exist in FlushTransitions (and not
FlushAnimations). This patch moves them to RequestRestyle since they appear to
apply to either transitions or animations equally. By eliminating this
difference between FlushTransitions and FlushAnimations we should then be
in a position to combine them into a common method on the base class.
This patch moves the additional checks (beyond those of Animation::CanThrottle)
from FlushAnimations/FlushTransitions to AnimationCollection::RequestRestyle.
These checks are on a per-collection basis hence it makes sense for the
collection to perform them. This also moves logic out of the managers which is
needed if we want to support script-based animations without introducing another
manager.
Ultimately we want to move throttling logic to AnimationCollection and
Animation::Tick (and later to KeyframeEffect::SetParentTime). This is so that
we can support script-generated animations without having to introduce yet
another manager.
To that end this patch introduces a method on AnimationCollection that can be
called from Animation::Tick to perform the necessary notifications needed to
update style.
Later in this patch series we will extend RequestRestyle to incorporate more of
the throttling logic and further extend it to cover some of the other
notifications such as updating layers.
This patch tracks whether or not we have already posted a restyle for animation
to avoid making redundant calls. Calls to nsIDocument::SetNeedStyleFlush are
cheap and more difficult to detect when they have completed so we don't filter
redundant calls in the Restyle::Throttled case.
If mHasPendingAnimationRestyle is set and AnimationCommon::EnsureStyleRuleFor
is *never* called then we could arrive at situation where we fail to make post
further restyles for animation.
I have verified that if we fail to reset mHasPendingAnimationRestyle at the
appropriate point (e.g. resetting it at the end of EnsureStyleRuleFor *after*
the early-returns) then a number of existing tests fail.
Furthermore, I have observed that it is reset by the beginning of each tick
in almost every case except for a few instances of browser mochitests such as
browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js.
In this case, during the async cleanup of the test, we have an opacity
transition on a vbox element that becomes display:none and appears to be skipped
during restyling. However, even in this case, EnsureStyleRuleFor is called
within one or at most two ticks and mHasPendingAnimationRestyle flag is cleared
(i.e. it does not get stuck).
In FlushTransitions and FlushAnimations we use different mechanisms to see if a
transition/animation can be throttled on the current tick.
FlushTransitions calls Animation::CanThrottle whilst FlushAnimations calls
EnsureStyleRuleFor and checks if the rule has changed or not. These are not as
completely different as they might seem at first since, internally,
EnsureStyleRuleFor calls Animation::CanThrottle.
We would like to unify this behavior and simply use Animation::CanThrottle in
FlushAnimations as we do in FlushTransitions.
First, however, we have to account for the differences in these approaches:
1. Using the result of EnsureStyleRuleFor means we may *not* call
PostRestyleForAnimation if an animation collection's mNeedsRefreshes member
is false.
This member is false when all animations have finished (or there are no
animations in the collection). In this case EnsureStyleRuleFor will not
update the style rule and we will end up assuming the tick can be throttled.
*However*, in the case that all animations are finished
Animation::CanThrottle will *also* return true (technically it will return
false until we compose style for the first time after becoming finished but
beyond that one moment it will return true) so skipping this check by using
Animation::CanThrottle instead of EnsureStyleRuleFor should not
make a significant difference.
2. Using the result of EnsureStyleRuleFor will mean that if we have already
updated the style rule within a given tick we will avoid calling
PostRestyleForAnimation (and call SetNeedStyleFlush instead). This can
happen the first time we call FlushAnimations from
PresShell::FlushPendingNotifications. (When we call FlushAnimations from
nsAnimationManager::WillRefresh mStyleRuleRefreshTime will be stale and we
won't apply this optimization. Furthermore after the first call to
PresShell::FlushPendingNotifications we will typically skip calling
FlushAnimations since PresShell::StyleUpdateForAllAnimationsIsUpToDate will
typically return true).
This seems like a possibly useful optimization although it is surprising we
don't do the same for transitions. Note that this optimization applies
regardless of whether we are performing a throttleable flush or not. That is,
even if we pass CommonAnimationManager::Cannot_Throttle we will still end up
throttling the tick in this case. Furthermore, we will mark the document as
needing a style flush even though this does not appear to be necessary.
This patch copies this optimization (checking if mStyleRuleRefreshTime) to
FlushAnimations so we can maintain this behavior when calling
Animation::CanThrottle instead of EnsureStyleRuleFor. It also applies the
same behavior to FlushTransitions for consistency (and so we can later
combine FlushAnimations and FlushTransitions).
Note that we apply this optimization *before* calling Tick since it should
only apply once we have already Tick'ed the animations in the collection.
We will first hit FlushAnimations as a result of the refresh driver calling
nsAnimationManager/nsTransitionManager::WillRefresh at which point
mStyleRuleRefreshTime should be stale. Using this order not only saves
redundant work but also makes moving the restyle code to Animation later on
more straightforward.
(In future we will divorce WillRefresh and FlushAnimations and only call
Tick in WillRefresh and only perform this optimization FlushAnimations.)
3. Using the result of EnsureStyleRuleFor means that while checking if we can
throttle or not we also update the style rule in FlushAnimations. That seems
like an odd side-effect particularly since FlushTransitions doesn't do the
same thing.
There is no longer anything in FlushTransitions that modifies the set of
transitions. I believe this changed as of bug 960465, specifically changeset
https://hg.mozilla.org/mozilla-central/rev/b2ee72589c18, so that this code is
no longer needed.
By removing this we can further align FlushAnimations and FlushTransitions.
This patch updates the logic in nsTransitionManager::FlushTransitions that deals
with detecting newly-started (i.e. when the delay phase has just finished) or
newly-finished animations. The existing logic had the following behavior:
* Calling SetIsFinishedTransition for newly-finished transitions.
This is no longer needed since by this point all consumers of
IsFinishedTransition have been updated to use alternative means for testing
if an animation is relevant.
* Setting transitionStartedOrEnded to true so that we would post an animation
restyle.
We can achieve this same effect by simplying updating the canThrottleTick
flag using the result of calling Animation::CanThrottle on each animation.
Animation::CanThrottle will return false for a newly-started or
newly-finished animation (it returns false for a newly-started animation
since the animation's mIsRunningOnCompositor flag won't yet be true at that
point.)
* Updating the animation generation for newly-started and newly-finished
animations in order to trigger a layer update.
At least that appears to be the intention of this code. However, it currently
has no effect since the animation generation on the pres context is not
incremented in any context I could find where a newly started/finished
animation might be detected.
For this third case, this patch adds tests to ensure that transitions are
correctly added and removed from the compositor when they start and finish.
This is because most of the existing tests in test_animations_omta.html cover
only CSS animations.
As noted in the comments in the test, if a tick lands at the exact beginning of
a transition we will typically not send it to the layer until the following tick
because the RestyleManager will filter out the seemingly redundant change (i.e.
no change to the computed style). Presumably updating the animation generation
was intended to avoid this.
This same behavior is true of CSS animations (and the same kind of comment
appears elsewhere in test_animations_omta.html). Long-term this is probably
worth fixing so that when a transition is triggered we get it to the compositor
one tick earlier which should improve responsiveness when the main thread is
busy and the interval between ticks is long. Furthermore, we should do the same
for both all type of animations, not just transitions.
Currently, however, this patch preserves the existing behavior and helps narrow
the difference between transitions and animations so we can apply this
optimization to both.
This patch generalizes the logic in
nsTransitionManager::PruneCompletedTransitions to consider all transitions that
are no longer current (i.e. not running or scheduled to run) rather than
those marked as finished.
Of particular note, this patch removes the check for finished transitions in
the case when we can't animate the current change. This case occurs when either
we have a non-transition style change that happens to coincide with the current
transition value, or a style change to something we can't interpolate to. In
either case it's not clear why we would cancel the existing transition only if
it is still in motion and not if it is finished. It seems like it should be
cancelled in either case and hence this patch removes this check.
The other change relates to detecting reversing transitions. In this case we do
need to distinguish between transitions that have finished and those that have
not. For this purpose, checking if the animation is current should be
sufficient. (Note that comparing for PlayState() == Finished would not be enough
since we want to also exclude *idle*, i.e. cancelled, animations too.)
In StyleContextChanged, when we drop a transition, we also update the animation
generation, unless the transition is finished. This is so that we will update
animations on layers accordingly. For all intents and purposes this is
equivalent to only updating the animation generation if the animation is
current.
Even in the case where the transition has *just* finished, it will either
already be considered finished and the regular animation tick (which uses the
same refresh driver time as we see in StyleContextChanged) will have triggered
an unthrottled sample to take the animation off the compositor (since
Animation::CanThrottle detects newly finished animations), or it will be not yet
finished in which case HasCurrentEffect will return true. If anything changed
timing properties in the time between running the refresh driver tick and
calling StyleContextChanged (such as seeking the Animation) it will also trigger
a layer update.
This patch also removes an unncessary assertion in
ElementPropertyTransition::CurrentValuePortion. This functions operates
sensibly even for finished transitions (due to the way it manages the fill
mode). It is up to the call site to determine whether it should be calling this
function on a finished transition or not.
This patch causes transition events to be dispatched as a separate step after
sampling the transitions. Eventually this will allow us to sample transitions
from their timeline (independently of where they came from and in potentially
any order) by separating the concepts of sampling and event dispatch.
This patch moves the logic for queueing events out of the logic for flushing
transitions making it a separate step. It still doesn't delay the dispatch of
those events into a separate step, however. That is done in a subsequent patch.
This patch also makes sure to clear any queued events when the nsPresShell that
owns the transition manager is destroyed. We don't expect CSSTransition::Tick to
be called anywhere except nsTransitionManger::FlushTransitions so there
shouldn't be any orphaned events but for completeness it seems best to add this
now. (Later, when we tick transitions from their timeline we will need this.)
This patch introduces a separate flag to CSSTransition for tracking if a
transition is newly-finished so we can correctly dispatch the transitionend
event. Although, this may seem to be redundant with the "IsFinishedTransition"
we also track, that state will soon be removed in bug 1181392 and hence this
flag will be needed then.
Note that Animation already has flags mIsPreviousStateFinished and
mFinishedAtLastComposeStyle which would appear to be similar however,
- mIsPreviousStateFinished will be removed in bug 1178665 and is updated more
often than we queue events so it is not useful here.
- mFinishedAtLastComposeStyle is used to determine if we can throttle a style
update and is also updated more frequently than we queue events and hence
can't be used here.
Once we guarantee one call to Tick() per frame we may be able to simplify this
by tracking "state on last tick" but for now we need this additional flag on
CSSTransition. CSSAnimation has a similar flag for this
(mPreviousPhaseOrIteration) which we may be able to unify at the same point.
This simply uses the DelayedEventDispatcher in place of the previous array of
TransitionEventInfo objects. Doing the actual delayed dispatch is performed in
a separate patch.
Prior to this patch, CSSAnimation defined a method for converting an
nsCSSPseudoElements::Type to a nsString (but only for the set of
pseudo-elements that can have animations). We would like to re-use this
when setting up transition events so this patch moves it to
AnimationCollection. Re-using this method more widely means we can make
a few further simplifications to the code.
This patch causes transition events to be dispatched as a separate step after
sampling the transitions. Eventually this will allow us to sample transitions
from their timeline (independently of where they came from and in potentially
any order) by separating the concepts of sampling and event dispatch.
This patch moves the logic for queueing events out of the logic for flushing
transitions making it a separate step. It still doesn't delay the dispatch of
those events into a separate step, however. That is done in a subsequent patch.
This patch also makes sure to clear any queued events when the nsPresShell that
owns the transition manager is destroyed. We don't expect CSSTransition::Tick to
be called anywhere except nsTransitionManger::FlushTransitions so there
shouldn't be any orphaned events but for completeness it seems best to add this
now. (Later, when we tick transitions from their timeline we will need this.)
This patch introduces a separate flag to CSSTransition for tracking if a
transition is newly-finished so we can correctly dispatch the transitionend
event. Although, this may seem to be redundant with the "IsFinishedTransition"
we also track, that state will soon be removed in bug 1181392 and hence this
flag will be needed then.
Note that Animation already has flags mIsPreviousStateFinished and
mFinishedAtLastComposeStyle which would appear to be similar however,
- mIsPreviousStateFinished will be removed in bug 1178665 and is updated more
often than we queue events so it is not useful here.
- mFinishedAtLastComposeStyle is used to determine if we can throttle a style
update and is also updated more frequently than we queue events and hence
can't be used here.
Once we guarantee one call to Tick() per frame we may be able to simplify this
by tracking "state on last tick" but for now we need this additional flag on
CSSTransition. CSSAnimation has a similar flag for this
(mPreviousPhaseOrIteration) which we may be able to unify at the same point.
This simply uses the DelayedEventDispatcher in place of the previous array of
TransitionEventInfo objects. Doing the actual delayed dispatch is performed in
a separate patch.
Prior to this patch, CSSAnimation defined a method for converting an
nsCSSPseudoElements::Type to a nsString (but only for the set of
pseudo-elements that can have animations). We would like to re-use this
when setting up transition events so this patch moves it to
AnimationCollection. Re-using this method more widely means we can make
a few further simplifications to the code.
The connection between an Animation and an AnimationTimeline is optional. That
is, it is possible to have an Animation without an AnimationTimeline. Until now
we have often just assumed the timeline will be set but eventually we need to
support the possibility of the timeline being null. Indeed, later in this patch
series we will set the timeline out-of-band (i.e. not in the constructor) using
SetTimeline which opens up the possibility that timeline will be null for
a period of time.
This patch paves the way for having an optional timeline by storing the global
used for, e.g. creating promises, on the Animation object itself.
Earlier in this patch series we added an assertion to the destructor for
CSSAnimation and CSSTransition to check that the owning element has been
cleared when the animation is destroyed.
This assertion fails, however, for transitions because there are a two
code paths where a transition may be destroyed without being cancelled.
This patch adjusts those two code paths to ensure transitions are always
cancelled before being destroyed.