Bug 1188251 part 3 - Add AnimationCollection::RequestRestyle; r=dholbert

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).
This commit is contained in:
Brian Birtles 2015-08-17 13:59:44 +09:00
parent b71ee27f2f
commit 0cf13fbef2
4 changed files with 49 additions and 21 deletions

View File

@ -28,7 +28,6 @@
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
using mozilla::layers::Layer;
using mozilla::dom::Animation;
using mozilla::dom::KeyframeEffectReadOnly;
@ -824,6 +823,8 @@ void
AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
EnsureStyleRuleFlags aFlags)
{
mHasPendingAnimationRestyle = false;
if (!mNeedsRefreshes) {
mStyleRuleRefreshTime = aRefreshTime;
return;
@ -964,6 +965,29 @@ AnimationCollection::CanThrottleAnimation(TimeStamp aTime)
return true;
}
void
AnimationCollection::RequestRestyle(RestyleType aRestyleType)
{
nsPresContext* presContext = mManager->PresContext();
if (!presContext) {
// Pres context will be null after the manager is disconnected.
return;
}
switch (aRestyleType) {
case RestyleType::Throttled:
presContext->Document()->SetNeedStyleFlush();
break;
case RestyleType::Standard:
if (!mHasPendingAnimationRestyle) {
mHasPendingAnimationRestyle = true;
PostRestyleForAnimation(presContext);
}
break;
}
}
void
AnimationCollection::UpdateAnimationGeneration(nsPresContext* aPresContext)
{

View File

@ -249,6 +249,7 @@ struct AnimationCollection : public PRCList
, mAnimationGeneration(0)
, mCheckGeneration(0)
, mNeedsRefreshes(true)
, mHasPendingAnimationRestyle(false)
#ifdef DEBUG
, mCalledPropertyDtor(false)
#endif
@ -290,6 +291,16 @@ struct AnimationCollection : public PRCList
CanAnimate_AllowPartial = 2
};
enum class RestyleType {
// Animation style has changed but the compositor is applying the same
// change so we might be able to defer updating the main thread until it
// becomes necessary.
Throttled,
// Animation style has changed and needs to be updated on the main thread.
Standard
};
void RequestRestyle(RestyleType aRestyleType);
private:
static bool
CanAnimatePropertyOnCompositor(const dom::Element *aElement,
@ -434,6 +445,12 @@ public:
// either completed or paused). May be invalidated by a style change.
bool mNeedsRefreshes;
private:
// Whether or not we have already posted for animation restyle.
// This is used to avoid making redundant requests and is reset each time
// the animation restyle is performed.
bool mHasPendingAnimationRestyle;
#ifdef DEBUG
bool mCalledPropertyDtor;
#endif

View File

@ -962,7 +962,6 @@ void
nsAnimationManager::FlushAnimations(FlushFlags aFlags)
{
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
bool didThrottle = false;
for (PRCList *l = PR_LIST_HEAD(&mElementCollections);
l != &mElementCollections;
l = PR_NEXT_LINK(l)) {
@ -987,15 +986,9 @@ nsAnimationManager::FlushAnimations(FlushFlags aFlags)
canThrottleTick &= (*iter)->CanThrottle();
}
if (!canThrottleTick) {
collection->PostRestyleForAnimation(mPresContext);
} else {
didThrottle = true;
}
}
if (didThrottle) {
mPresContext->Document()->SetNeedStyleFlush();
collection->RequestRestyle(canThrottleTick ?
AnimationCollection::RestyleType::Throttled :
AnimationCollection::RestyleType::Standard);
}
MaybeStartOrStopObservingRefreshDriver();

View File

@ -915,7 +915,6 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags)
}
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
bool didThrottle = false;
// Post restyle events for frames that are transitioning.
{
PRCList *next = PR_LIST_HEAD(&mElementCollections);
@ -958,16 +957,11 @@ nsTransitionManager::FlushTransitions(FlushFlags aFlags)
collection->mElementProperty ==
nsGkAtoms::transitionsOfAfterProperty,
"Unexpected element property; might restyle too much");
if (!canThrottleTick) {
collection->PostRestyleForAnimation(mPresContext);
} else {
didThrottle = true;
}
}
}
if (didThrottle) {
mPresContext->Document()->SetNeedStyleFlush();
collection->RequestRestyle(canThrottleTick ?
AnimationCollection::RestyleType::Throttled :
AnimationCollection::RestyleType::Standard);
}
}
MaybeStartOrStopObservingRefreshDriver();