Bug 978712 - Prevent non-running transitions and animations (animations or transitions during their delay period, and animations after they finish) from repeatedly poking layer activity because we think we can run them on the compositor. r=heycam

This changes the behavior of the CanPerformOnCompositorThread methods of
both ElementAnimations and ElementTransitions to check that the
respective animations or transitions are actually running.  This is ok
because:
 - The main caller is nsLayoutUtils::HasAnimationsForCompositor, and all
   of its callers pretty clearly want the more restricted behavior (they're
   concerned with layer activity)
 - The only other callers of these functions are
   nsAnimationManager::FlushAnimations and
   nsTransitionManager::FlushTransitions (determining when to do
   throttling), nsAnimationManager::GetAnimationsForCompositor (whose
   only caller,
   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer, also checks
   IsRunningAt).  I think these also all want or are fine with having
   the IsRunningAt check.

As to the actual changes:
 - In the animation manager, I think it's a mistake that
   ElementAnimation::IsRunningAt didn't already check
   mIterationDuration, since we throw out animations with a bad
   iteration-duration in ElementAnimations::EnsureStyleRuleFor.  So this
   makes that change as well.
 - In the transition manager, IsRunningAt already checks
   !IsRemovedSentinel().

I've confirmed in gdb on a device that this fixes the repeated
nsIFrame::SchedulePaint calls that were the symptom of this bug.

I believe this patch also makes it so that a short animation of a
property that can't be animated on the compositor doesn't prevent the
entire duration of the animation of a property that can from being
throttled (having the main thread style updates suppressed).
This commit is contained in:
L. David Baron 2014-03-06 22:08:57 -08:00
parent 0461432ae1
commit 38a6cfb99b
4 changed files with 32 additions and 6 deletions

View File

@ -327,7 +327,7 @@ ElementAnimations::EnsureStyleRuleFor(TimeStamp aRefreshTime,
bool
ElementAnimation::IsRunningAt(TimeStamp aTime) const
{
if (IsPaused()) {
if (IsPaused() || mIterationDuration.ToMilliseconds() <= 0.0) {
return false;
}
@ -398,8 +398,7 @@ ElementAnimations::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
bool hasTransform = false;
for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
const ElementAnimation& anim = mAnimations[animIdx];
if (anim.mIterationDuration.ToMilliseconds() <= 0.0) {
// No animation data
if (!anim.IsRunningAt(now)) {
continue;
}

View File

@ -174,8 +174,21 @@ struct ElementAnimations MOZ_FINAL
aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint);
}
// True if this animation can be performed on the compositor thread.
// If aFlags contains CanAnimate_AllowPartial, returns whether the
// state of this element's animations at the current refresh driver
// time contains animation data that can be done on the compositor
// thread. (This is useful for determining whether a layer should be
// active, or whether to send data to the layer.)
// If aFlags does not contain CanAnimate_AllowPartial, returns whether
// the state of this element's animations at the current refresh driver
// time can be fully represented by data sent to the compositor.
// (This is useful for determining whether throttle the animation
// (suppress main-thread style updates).)
// Note that when CanPerformOnCompositorThread returns true, it also,
// as a side-effect, notifies the ActiveLayerTracker. FIXME: This
// should probably move to the relevant callers.
virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
// False when we know that our current style rule is valid

View File

@ -171,10 +171,10 @@ ElementTransitions::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
bool existsProperty = false;
for (uint32_t i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
const ElementPropertyTransition& pt = mPropertyTransitions[i];
if (pt.IsRemovedSentinel()) {
if (!pt.IsRunningAt(now)) {
continue;
}
existsProperty = true;
if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,

View File

@ -87,6 +87,20 @@ struct ElementTransitions MOZ_FINAL
void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
// If aFlags contains CanAnimate_AllowPartial, returns whether the
// state of this element's transitions at the current refresh driver
// time contains transition data that can be done on the compositor
// thread. (This is useful for determining whether a layer should be
// active, or whether to send data to the layer.)
// If aFlags does not contain CanAnimate_AllowPartial, returns whether
// the state of this element's transitions at the current refresh driver
// time can be fully represented by data sent to the compositor.
// (This is useful for determining whether throttle the transition
// (suppress main-thread style updates).)
// Note that when CanPerformOnCompositorThread returns true, it also,
// as a side-effect, notifies the ActiveLayerTracker. FIXME: This
// should probably move to the relevant callers.
virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
// Either zero or one for each CSS property: