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.
AnimationCollection::HasAnimationOfProperty uses IsFinishedTransition to filter
out transitions that should otherwise be ignored. This is used in the following
places:
1. nsLayoutUtils::HasAnimations
The is only used by nsIFrame::BuildDisplayListForStackingContext to see if
there are any opacity animations
For this case, simply returning *current* animations would be sufficient
(since finished but filling animations should have already filled in the
display opacity)
2. CommonAnimationManager::GetAnimationsForCompositor
This should really only return *current* animations--that is, animations that
are running or scheduled to run. Finished animations never run on the
compositor. Indeed, only *playing* animations run on the compositor but, as
we will see in some of the cases below, it is sometimes useful to know that
an animation *will* run on the compositor in the near future (e.g. so we can
pre-render content).
The places where GetAnimationsForCompositor is used are:
- When building layers to add animations to layers in nsDisplayList--in this
case we skip any animations that aren't playing so if
GetAnimationsForCompositor only returned current animations that would be
more than sufficient.
- In nsLayoutUtils::HasAnimationsForCompositor. This in turn is used:
- In ChooseScaleAndSetTransform to see if the transform is being animated
on the compositor. If so, it calls
nsLayoutUtils::ComputeSuitableScaleForAnimation (which also calls
GetAnimationsForCompositor) and passes the result to
GetMinAndMaxScaleForAnimationProperty which we have already adjusted in
part 4 of this patch series to only deal with *relevant* animations
Relevant animations include both current animations and in effect
animations but we don't run forwards-filling animations on the compositor
so GetAnimationsForCompositor should NOT return them. Current animations
should be enough. In fact, playing animations should be enough but we
might want to pre-render layers at a suitable size during their delay
phase so returning current animations is probably ok.
- In nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay to add a fuzz
factor to the overflow rect for frames undergoing a transform animation
on the compositor. In this case too current animations should be
sufficient.
- In nsDisplayOpacity::NeedsActiveLayer to say "yes" if we are animating
opacity on the compositor. Presumably in this case it would be good to
say "yes" if the animation is in the delay phase too (as it currently
does). After the animation is finished, we should drop the layer, i.e.
current animations should be sufficient.
- In nsDisplayTransform::ShouldPrerenderTransformedContent. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to pre-render
transformed content for animations that are current.
- In nsDisplayTransform::GetLayerState. As with
nsDisplayOpacity::NeedsActiveLayer, we only need to return active here
for current animations.
- In nsIFrame::IsTransformed. Here we test the display style to see if
there is a transform and also check if transform is being animated on the
compositor. As a result, we really only need HasAnimationsForCompositor
to return true for animations that are playing--otherwise the display
style will tell us if we're transformed or not. Returning true for all
current compositor animations (which is a superset of playing), however,
should not cause problems (we already return true for even more than
that).
- In nsIFrame::HasOpacityInternal which is much the same as
nsIFrame::IsTransformed and hence current should be fine.
3. AnimationCollection::CanThrottleAnimation
Here, HasAnimationOfProperty is used when looking for animations that would
disqualify us from throttling the animation by having an out-of-date layer
generation or being a transform animation that affects scroll and so requires
that we do the occasional main thread sample to update scrollbars.
It would seem like current animations are enough here too. One interesting
case is where we *had* a compositor animation but it has finished or been
cancelled. In that case, the animation won't be current and we should not
throttle the animation since we need to take it off its layer.
It turns out checking for current animations is still ok in this case too.
The reasoning is as follows:
- If the animation is newly-finished, we'll pick that up in
Animation::CanThrottle and return false then.
- If the animation is newly-idle then there are two cases:
If the cancelled animation was the only compositor animation then
AnimationCollection::CanPerformOnCompositorThread will notice that there
are no playing compositor animations and return false and
AnimationCollection::CanThrottleAnimation will never be called.
If there are other compositor animations running, then
AnimationCollection::CanThrottleAnimation will still return false because
whatever cancelled the animation will update the animation generation and
we'll notice the mismatch between the layer animation generation and the
animation generation on the collection.
Based on the above analysis it appears that making
AnimationCollection::HasAnimationOfProperty return only current animations (and
simulatneously renaming it to HasCurrentAnimationOfProperty) is safe. Indeed, in
effect, we already do this for transitions but not for animations. This patch
generalizes this behavior to all animations.
This patch also updates test_animations_omta.html since it was incorrectly
testing that a finished opacity animation was still running on the compositor.
Finished animations should not run on the compositor and the changes in this
patch cause that to happen. The reason we don't just update this test to check
for RunningOn.MainThread is that for opacity animations, unlike transform
animations, we can't detect if an opacity on a layer was set by animation or
not. As a result, for opacity animations we typically test the opacity on
either the main thread or compositor in order to allow for the case where an
animation-set opacity is still lingering on the compositor.
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 extracts a utility class for queueing up a series of EventInfo
objects (of templated type) and then dispatching them. This covers the event
queuing behavior in nsAnimationManager so that we can reuse it in
nsTransitionManager.
The long-term plan is to drop the mozilla::css namespace altogether. Before we
go to much further with refactoring code in AnimationCommon, we should drop
usage of the mozilla::css namespace. Specifically, this patch moves the
CommonAnimationManager and AnimValuesStyleRule classes to the mozilla namespace.
This patch prepares the way for script-generated events by making
event dispatch a separate process that happens after sampling animations.
This will allow us to sample animations from their associated timeline
(removing the need for a further manager to tracker script-generated
animations).
Furthermore, once we sample animations from timelines the order in which they
are sampled is likely to be more or less random so by making event dispatch at
separate step, we have an opportunity to sort the events and dispatch in
a consistent and sensible order. It also ensures that event callbacks will
not be run until all animations (including transitions) have been updated
ensuring they see a consistent view of timing properties.
This patch only affects event handling for CSS animations. Transitions will
be dealt with in a subsequent patch.
There was a bug introduced in to animation_utils.js in
https://hg.mozilla.org/mozilla-central/rev/496e867cd2cd (bug 1070745). This
patch fixes this bug so we can be sure testing events correctly before messing
with them.
After this change, we have ShallowSizeOf{In,Ex}cludingThis(), which don't do
anything to measure children. (They can be combined with iteration to measure
children.)
This is because patch 4 now uses AddAndRemoveTransform hints for changes
that are other than adding and removing a transform. There's still a
little bit of transform-related stuff there too (which I did make
conditional in patch 2).
Note that this now uses AddAndRemoveTransform hints for changes that are
other than adding and removing a transform. Since there's still a
little bit of transform-related stuff there too (which I did make
conditional), I figure it's probably best to leave the name as-is,
although I'd be open to renaming it as well.
As expected, without the patch, the filter and perspective tests fail,
but the added transform test passes. All the tests pass locally with
the patch.
This is a temporary preference to allow for testing-in-the-wild by a larger
audience, for nightly builds. When 1177263 is fixed this can be removed.
---
layout/style/nsCSSParser.cpp | 14 ++++++++++++++
modules/libpref/init/all.js | 6 ++++++
2 files changed, 20 insertions(+)
After this change, we have PLDHashTable::ShallowSizeOf{In,Ex}cludingThis(),
which don't do anything to measure children. (They can be combined with
iteration to measure children.)
This patch also removes the PL_DHashTableSizeOf{In,Ex}cludingThis() functions.
They're not necessary because the methods can be used instead.
Finally, the patch deliberately converts some SizeOfExcludingThis() calls to
SizeOfIncludingThis(). These are all done on heap pointers so this change is
valid.