Bug 914847. Mini-flush for animations. r=dbaron

This commit is contained in:
Nicholas Cameron 2013-10-22 14:14:41 +02:00
parent 732d37067c
commit dd6d5fdd9f
9 changed files with 365 additions and 212 deletions

View File

@ -976,7 +976,8 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
// Initialise refresh tick counters for OMTA
mLastStyleUpdateForAllAnimations =
mLastUpdateThrottledStyle = mRefreshDriver->MostRecentRefresh();
mLastUpdateThrottledAnimationStyle =
mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
@ -1491,15 +1492,29 @@ nsPresContext::GetContainerExternal() const
}
bool
nsPresContext::ThrottledStyleIsUpToDate() const
nsPresContext::ThrottledTransitionStyleIsUpToDate() const
{
return mLastUpdateThrottledStyle == mRefreshDriver->MostRecentRefresh();
return
mLastUpdateThrottledTransitionStyle == mRefreshDriver->MostRecentRefresh();
}
void
nsPresContext::TickLastUpdateThrottledStyle()
nsPresContext::TickLastUpdateThrottledTransitionStyle()
{
mLastUpdateThrottledStyle = mRefreshDriver->MostRecentRefresh();
mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
}
bool
nsPresContext::ThrottledAnimationStyleIsUpToDate() const
{
return
mLastUpdateThrottledAnimationStyle == mRefreshDriver->MostRecentRefresh();
}
void
nsPresContext::TickLastUpdateThrottledAnimationStyle()
{
mLastUpdateThrottledAnimationStyle = mRefreshDriver->MostRecentRefresh();
}
bool

View File

@ -656,8 +656,10 @@ public:
/**
* Getter and setter for OMTA time counters
*/
bool ThrottledStyleIsUpToDate() const;
void TickLastUpdateThrottledStyle();
bool ThrottledTransitionStyleIsUpToDate() const;
void TickLastUpdateThrottledTransitionStyle();
bool ThrottledAnimationStyleIsUpToDate() const;
void TickLastUpdateThrottledAnimationStyle();
bool StyleUpdateForAllAnimationsIsUpToDate();
void TickLastStyleUpdateForAllAnimations();
@ -1226,8 +1228,10 @@ protected:
mozilla::TimeStamp mReflowStartTime;
// last time animations/transition styles were flushed to their primary frames
mozilla::TimeStamp mLastUpdateThrottledStyle;
// last time animations styles were flushed to their primary frames
mozilla::TimeStamp mLastUpdateThrottledAnimationStyle;
// last time transition styles were flushed to their primary frames
mozilla::TimeStamp mLastUpdateThrottledTransitionStyle;
// last time we did a full style flush
mozilla::TimeStamp mLastStyleUpdateForAllAnimations;

View File

@ -6013,6 +6013,7 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
nsPresContext* presContext = shell->GetPresContext();
if (presContext) {
presContext->TransitionManager()->UpdateAllThrottledStyles();
presContext->AnimationManager()->UpdateAllThrottledStyles();
}
}

View File

@ -3,8 +3,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxPlatform.h"
#include "AnimationCommon.h"
#include "nsTransitionManager.h"
#include "nsAnimationManager.h"
#include "gfxPlatform.h"
#include "nsRuleData.h"
#include "nsCSSValue.h"
#include "nsStyleContext.h"
@ -16,6 +19,9 @@
#include "nsDisplayList.h"
#include "mozilla/MemoryReporting.h"
#include "RestyleManager.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
using namespace mozilla::layers;
@ -136,6 +142,157 @@ CommonAnimationManager::ExtractComputedValueForTransition(
return result;
}
already_AddRefed<nsStyleContext>
CommonAnimationManager::ReparentContent(nsIContent* aContent,
nsStyleContext* aParentStyle)
{
nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent);
if (!primaryFrame) {
return nullptr;
}
dom::Element* element = aContent->IsElement()
? aContent->AsElement()
: nullptr;
nsRefPtr<nsStyleContext> newStyle =
styleSet->ReparentStyleContext(primaryFrame->StyleContext(),
aParentStyle, element);
primaryFrame->SetStyleContext(newStyle);
ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet);
return newStyle.forget();
}
/* static */ void
CommonAnimationManager::ReparentBeforeAndAfter(dom::Element* aElement,
nsIFrame* aPrimaryFrame,
nsStyleContext* aNewStyle,
nsStyleSet* aStyleSet)
{
if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
nsRefPtr<nsStyleContext> beforeStyle =
aStyleSet->ReparentStyleContext(before->StyleContext(),
aNewStyle, aElement);
before->SetStyleContext(beforeStyle);
}
if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
nsRefPtr<nsStyleContext> afterStyle =
aStyleSet->ReparentStyleContext(after->StyleContext(),
aNewStyle, aElement);
after->SetStyleContext(afterStyle);
}
}
// Ensure that the next repaint rebuilds the layer tree for aFrame. That
// means that changes to animations on aFrame's layer are propagated to
// the compositor, which is needed for correct behaviour of new
// transitions.
static void
ForceLayerRerendering(nsIFrame* aFrame, CommonElementAnimationData* aData)
{
if (aData->HasAnimationOfProperty(eCSSProperty_opacity)) {
if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
aFrame, nsDisplayItem::TYPE_OPACITY)) {
layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
}
if (aData->HasAnimationOfProperty(eCSSProperty_transform)) {
if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
aFrame, nsDisplayItem::TYPE_TRANSFORM)) {
layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
}
}
nsStyleContext*
CommonAnimationManager::UpdateThrottledStyle(dom::Element* aElement,
nsStyleContext* aParentStyle,
nsStyleChangeList& aChangeList)
{
NS_ASSERTION(mPresContext->TransitionManager()->GetElementTransitions(
aElement,
nsCSSPseudoElements::ePseudo_NotPseudoElement,
false) ||
mPresContext->AnimationManager()->GetElementAnimations(
aElement,
nsCSSPseudoElements::ePseudo_NotPseudoElement,
false), "element not animated");
nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement);
if (!primaryFrame) {
return nullptr;
}
nsStyleContext* oldStyle = primaryFrame->StyleContext();
nsRuleNode* ruleNode = oldStyle->RuleNode();
nsTArray<nsStyleSet::RuleAndLevel> rules;
do {
if (ruleNode->IsRoot()) {
break;
}
nsStyleSet::RuleAndLevel curRule;
curRule.mLevel = ruleNode->GetLevel();
if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
ElementAnimations* ea =
mPresContext->AnimationManager()->GetElementAnimations(
aElement,
oldStyle->GetPseudoType(),
false);
NS_ASSERTION(ea,
"Rule has level eAnimationSheet without animation on manager");
mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
curRule.mRule = ea->mStyleRule;
// FIXME: maybe not needed anymore:
ForceLayerRerendering(primaryFrame, ea);
} else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
ElementTransitions *et =
mPresContext->TransitionManager()->GetElementTransitions(
aElement,
oldStyle->GetPseudoType(),
false);
NS_ASSERTION(et,
"Rule has level eTransitionSheet without transition on manager");
et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
curRule.mRule = et->mStyleRule;
// FIXME: maybe not needed anymore:
ForceLayerRerendering(primaryFrame, et);
} else {
curRule.mRule = ruleNode->GetRule();
}
if (curRule.mRule) {
rules.AppendElement(curRule);
}
} while ((ruleNode = ruleNode->GetParent()));
nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
ResolveStyleForRules(aParentStyle, oldStyle, rules);
// We absolutely must call CalcStyleDifference in order to ensure the
// new context has all the structs cached that the old context had.
// We also need it for processing of the changes.
nsChangeHint styleChange =
oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
styleChange);
primaryFrame->SetStyleContext(newStyle);
ReparentBeforeAndAfter(aElement, primaryFrame, newStyle,
mPresContext->PresShell()->StyleSet());
return newStyle;
}
NS_IMPL_ISUPPORTS1(AnimValuesStyleRule, nsIStyleRule)
/* virtual */ void

View File

@ -17,6 +17,7 @@
#include "nsSMILKeySpline.h"
#include "nsStyleStruct.h"
#include "mozilla/Attributes.h"
#include "nsCSSPseudoElements.h"
class nsPresContext;
class nsIFrame;
@ -70,10 +71,82 @@ protected:
virtual void ElementDataRemoved() = 0;
void RemoveAllElementData();
// Update the style on aElement from the transition stored in this manager and
// the new parent style - aParentStyle. aElement must be transitioning or
// animated. Returns the updated style.
nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement,
nsStyleContext* aParentStyle,
nsStyleChangeList &aChangeList);
// Reparent the style of aContent and any :before and :after pseudo-elements.
already_AddRefed<nsStyleContext> ReparentContent(nsIContent* aContent,
nsStyleContext* aParentStyle);
// reparent :before and :after pseudo elements of aElement
static void ReparentBeforeAndAfter(dom::Element* aElement,
nsIFrame* aPrimaryFrame,
nsStyleContext* aNewStyle,
nsStyleSet* aStyleSet);
PRCList mElementData;
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
};
// The internals of UpdateAllThrottledStyles, used by nsAnimationManager and
// nsTransitionManager, see the comments in the declaration of the latter.
#define IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(class_, animations_getter_) \
void \
class_::UpdateAllThrottledStylesInternal() \
{ \
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); \
\
nsStyleChangeList changeList; \
\
/* update each transitioning element by finding its root-most ancestor
with a transition, and flushing the style on that ancestor and all
its descendants*/ \
PRCList *next = PR_LIST_HEAD(&mElementData); \
while (next != &mElementData) { \
CommonElementAnimationData* ea = \
static_cast<CommonElementAnimationData*>(next); \
next = PR_NEXT_LINK(next); \
\
if (ea->mFlushGeneration == now) { \
/* this element has been ticked already */ \
continue; \
} \
\
/* element is initialised to the starting element (i.e., one we know has
an animation) and ends up with the root-most animated ancestor,
that is, the element where we begin updates. */ \
dom::Element* element = ea->mElement; \
/* make a list of ancestors */ \
nsTArray<dom::Element*> ancestors; \
do { \
ancestors.AppendElement(element); \
} while ((element = element->GetParentElement())); \
\
/* walk down the ancestors until we find one with a throttled transition */\
for (int32_t i = ancestors.Length() - 1; i >= 0; --i) { \
if (animations_getter_(ancestors[i], \
nsCSSPseudoElements::ePseudo_NotPseudoElement, \
false)) { \
element = ancestors[i]; \
break; \
} \
} \
\
nsIFrame* primaryFrame; \
if (element && \
(primaryFrame = nsLayoutUtils::GetStyleFrame(element))) { \
UpdateThrottledStylesForSubtree(element, \
primaryFrame->StyleContext()->GetParent(), changeList); \
} \
} \
\
RestyleManager* restyleManager = mPresContext->RestyleManager(); \
restyleManager->ProcessRestyledFrames(changeList); \
restyleManager->FlushOverflowChangedTracker(); \
}
/**
* A style rule that maps property-nsStyleAnimation::Value pairs.
*/
@ -132,11 +205,12 @@ private:
struct CommonElementAnimationData : public PRCList
{
CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty,
CommonAnimationManager *aManager)
CommonAnimationManager *aManager, TimeStamp aNow)
: mElement(aElement)
, mElementProperty(aElementProperty)
, mManager(aManager)
, mAnimationGeneration(0)
, mFlushGeneration(aNow)
#ifdef DEBUG
, mCalledPropertyDtor(false)
#endif
@ -216,6 +290,11 @@ struct CommonElementAnimationData : public PRCList
// The refresh time associated with mStyleRule.
TimeStamp mStyleRuleRefreshTime;
// Generation counter for flushes of throttled animations.
// Used to prevent updating the styles twice for a given element during
// UpdateAllThrottledStyles.
TimeStamp mFlushGeneration;
#ifdef DEBUG
bool mCalledPropertyDtor;
#endif

View File

@ -4,13 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAnimationManager.h"
#include "nsTransitionManager.h"
#include "mozilla/MemoryReporting.h"
#include "nsPresContext.h"
#include "nsRuleProcessorData.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
#include "nsCSSRules.h"
#include "RestyleManager.h"
#include "nsStyleAnimation.h"
#include "nsEventDispatcher.h"
#include "nsLayoutUtils.h"
@ -21,10 +24,12 @@
using namespace mozilla;
using namespace mozilla::css;
ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager)
ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement,
nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager,
TimeStamp aNow)
: CommonElementAnimationData(aElement, aElementProperty,
aAnimationManager),
aAnimationManager, aNow),
mNeedsRefreshes(true)
{
}
@ -451,7 +456,8 @@ nsAnimationManager::GetElementAnimations(dom::Element *aElement,
aElement->GetProperty(propName));
if (!ea && aCreateIfNeeded) {
// FIXME: Consider arena-allocating?
ea = new ElementAnimations(aElement, propName, this);
ea = new ElementAnimations(aElement, propName, this,
mPresContext->RefreshDriver()->MostRecentRefresh());
nsresult rv = aElement->SetProperty(propName, ea,
ElementAnimationsPropertyDtor, false);
if (NS_FAILED(rv)) {
@ -1088,3 +1094,62 @@ nsAnimationManager::DoDispatchEvents()
}
}
}
void
nsAnimationManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle,
nsStyleChangeList& aChangeList)
{
dom::Element* element;
if (aContent->IsElement()) {
element = aContent->AsElement();
} else {
element = nullptr;
}
nsRefPtr<nsStyleContext> newStyle;
ElementAnimations* ea;
if (element &&
(ea = GetElementAnimations(element,
nsCSSPseudoElements::ePseudo_NotPseudoElement,
false))) {
// re-resolve our style
newStyle = UpdateThrottledStyle(element, aParentStyle, aChangeList);
// remove the current transition from the working set
ea->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
} else {
newStyle = ReparentContent(aContent, aParentStyle);
}
// walk the children
if (newStyle) {
for (nsIContent *child = aContent->GetFirstChild(); child;
child = child->GetNextSibling()) {
UpdateThrottledStylesForSubtree(child, newStyle, aChangeList);
}
}
}
IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(nsAnimationManager,
GetElementAnimations)
void
nsAnimationManager::UpdateAllThrottledStyles()
{
if (PR_CLIST_IS_EMPTY(&mElementData)) {
// no throttled animations, leave early
mPresContext->TickLastUpdateThrottledAnimationStyle();
return;
}
if (mPresContext->ThrottledAnimationStyleIsUpToDate()) {
// throttled transitions are up to date, leave early
return;
}
mPresContext->TickLastUpdateThrottledAnimationStyle();
UpdateAllThrottledStylesInternal();
}

View File

@ -128,7 +128,7 @@ struct ElementAnimations MOZ_FINAL
typedef mozilla::TimeDuration TimeDuration;
ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager);
nsAnimationManager *aAnimationManager, TimeStamp aNow);
// This function takes as input the start time, duration, and direction of an
// animation and returns the position in the current iteration. Note that
@ -275,6 +275,9 @@ public:
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
// Updates styles on throttled animations. See note on nsTransitionManager
void UpdateAllThrottledStyles();
protected:
virtual void ElementDataRemoved() MOZ_OVERRIDE
{
@ -298,6 +301,14 @@ private:
nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType);
// Update the animated styles of an element and its descendants.
// If the element has an animation, it is flushed back to its primary frame.
// If the element does not have an animation, then its style is reparented.
void UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle,
nsStyleChangeList &aChangeList);
void UpdateAllThrottledStylesInternal();
// The guts of DispatchEvents
void DoDispatchEvents();

View File

@ -40,8 +40,8 @@ ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement,
nsIAtom *aElementProperty,
nsTransitionManager *aTransitionManager,
TimeStamp aNow)
: CommonElementAnimationData(aElement, aElementProperty, aTransitionManager)
, mFlushGeneration(aNow)
: CommonElementAnimationData(aElement, aElementProperty,
aTransitionManager, aNow)
{
}
@ -209,122 +209,6 @@ ElementTransitions::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
* nsTransitionManager *
*****************************************************************************/
// reparent :before and :after pseudo elements of aElement
static void ReparentBeforeAndAfter(dom::Element* aElement,
nsIFrame* aPrimaryFrame,
nsStyleContext* aNewStyle,
nsStyleSet* aStyleSet)
{
if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
nsRefPtr<nsStyleContext> beforeStyle =
aStyleSet->ReparentStyleContext(before->StyleContext(),
aNewStyle, aElement);
before->SetStyleContext(beforeStyle);
}
if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
nsRefPtr<nsStyleContext> afterStyle =
aStyleSet->ReparentStyleContext(after->StyleContext(),
aNewStyle, aElement);
after->SetStyleContext(afterStyle);
}
}
// Ensure that the next repaint rebuilds the layer tree for aFrame. That
// means that changes to animations on aFrame's layer are propagated to
// the compositor, which is needed for correct behaviour of new
// transitions.
static void
ForceLayerRerendering(nsIFrame* aFrame, CommonElementAnimationData* aData)
{
if (aData->HasAnimationOfProperty(eCSSProperty_opacity)) {
if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
aFrame, nsDisplayItem::TYPE_OPACITY)) {
layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
}
if (aData->HasAnimationOfProperty(eCSSProperty_transform)) {
if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
aFrame, nsDisplayItem::TYPE_TRANSFORM)) {
layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
}
}
nsStyleContext*
nsTransitionManager::UpdateThrottledStyle(dom::Element* aElement,
nsStyleContext* aParentStyle,
nsStyleChangeList& aChangeList)
{
NS_ASSERTION(GetElementTransitions(aElement,
nsCSSPseudoElements::ePseudo_NotPseudoElement,
false), "element not transitioning");
nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement);
if (!primaryFrame) {
return nullptr;
}
nsStyleContext* oldStyle = primaryFrame->StyleContext();
nsRuleNode* ruleNode = oldStyle->RuleNode();
nsTArray<nsStyleSet::RuleAndLevel> rules;
do {
if (ruleNode->IsRoot()) {
break;
}
nsStyleSet::RuleAndLevel curRule;
curRule.mLevel = ruleNode->GetLevel();
if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
ElementAnimations* ea =
mPresContext->AnimationManager()->GetElementAnimations(aElement,
oldStyle->GetPseudoType(),
false);
NS_ASSERTION(ea, "Rule has level eAnimationSheet without animation on manager");
mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
curRule.mRule = ea->mStyleRule;
// FIXME: maybe not needed anymore:
ForceLayerRerendering(primaryFrame, ea);
} else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
ElementTransitions *et =
GetElementTransitions(aElement, oldStyle->GetPseudoType(), false);
NS_ASSERTION(et, "Rule has level eTransitionSheet without transition on manager");
et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
curRule.mRule = et->mStyleRule;
// FIXME: maybe not needed anymore:
ForceLayerRerendering(primaryFrame, et);
} else {
curRule.mRule = ruleNode->GetRule();
}
if (curRule.mRule) {
rules.AppendElement(curRule);
}
} while ((ruleNode = ruleNode->GetParent()));
nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
ResolveStyleForRules(aParentStyle, oldStyle, rules);
// We absolutely must call CalcStyleDifference in order to ensure the
// new context has all the structs cached that the old context had.
// We also need it for processing of the changes.
nsChangeHint styleChange =
oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
styleChange);
primaryFrame->SetStyleContext(newStyle);
ReparentBeforeAndAfter(aElement, primaryFrame, newStyle, mPresContext->PresShell()->StyleSet());
return newStyle;
}
void
nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle,
@ -349,17 +233,7 @@ nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
// remove the current transition from the working set
et->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
} else {
// reparent the element's style
nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent);
if (!primaryFrame) {
return;
}
newStyle = styleSet->ReparentStyleContext(primaryFrame->StyleContext(),
aParentStyle, element);
primaryFrame->SetStyleContext(newStyle);
ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet);
newStyle = ReparentContent(aContent, aParentStyle);
}
// walk the children
@ -371,68 +245,25 @@ nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
}
}
IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(nsTransitionManager,
GetElementTransitions)
void
nsTransitionManager::UpdateAllThrottledStyles()
{
if (PR_CLIST_IS_EMPTY(&mElementData)) {
// no throttled transitions, leave early
mPresContext->TickLastUpdateThrottledStyle();
mPresContext->TickLastUpdateThrottledTransitionStyle();
return;
}
if (mPresContext->ThrottledStyleIsUpToDate()) {
if (mPresContext->ThrottledTransitionStyleIsUpToDate()) {
// throttled transitions are up to date, leave early
return;
}
mPresContext->TickLastUpdateThrottledStyle();
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
nsStyleChangeList changeList;
// update each transitioning element by finding its root-most ancestor with a
// transition, and flushing the style on that ancestor and all its descendants
PRCList *next = PR_LIST_HEAD(&mElementData);
while (next != &mElementData) {
ElementTransitions* et = static_cast<ElementTransitions*>(next);
next = PR_NEXT_LINK(next);
if (et->mFlushGeneration == now) {
// this element has been ticked already
continue;
}
// element is initialised to the starting element (i.e., one we know has
// a transition) and ends up with the root-most transitioning ancestor,
// that is, the element where we begin updates.
dom::Element* element = et->mElement;
// make a list of ancestors
nsTArray<dom::Element*> ancestors;
do {
ancestors.AppendElement(element);
} while ((element = element->GetParentElement()));
// walk down the ancestors until we find one with a throttled transition
for (int32_t i = ancestors.Length() - 1; i >= 0; --i) {
if (GetElementTransitions(ancestors[i],
nsCSSPseudoElements::ePseudo_NotPseudoElement,
false)) {
element = ancestors[i];
break;
}
}
nsIFrame* primaryFrame;
if (element &&
(primaryFrame = nsLayoutUtils::GetStyleFrame(element))) {
UpdateThrottledStylesForSubtree(element,
primaryFrame->StyleContext()->GetParent(), changeList);
}
}
RestyleManager* restyleManager = mPresContext->RestyleManager();
restyleManager->ProcessRestyledFrames(changeList);
restyleManager->FlushOverflowChangedTracker();
mPresContext->TickLastUpdateThrottledTransitionStyle();
UpdateAllThrottledStylesInternal();
}
void
@ -526,7 +357,7 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement,
}
NS_WARN_IF_FALSE(!nsLayoutUtils::AreAsyncAnimationsEnabled() ||
mPresContext->ThrottledStyleIsUpToDate(),
mPresContext->ThrottledTransitionStyleIsUpToDate(),
"throttled animations not up to date");
// Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html

View File

@ -91,11 +91,6 @@ struct ElementTransitions MOZ_FINAL
// Either zero or one for each CSS property:
nsTArray<ElementPropertyTransition> mPropertyTransitions;
// Generation counter for flushes of throttled transitions.
// Used to prevent updating the styles twice for a given element during
// UpdateAllThrottledStyles.
mozilla::TimeStamp mFlushGeneration;
};
@ -203,6 +198,10 @@ public:
// other than primary frames.
void UpdateAllThrottledStyles();
ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
protected:
virtual void ElementDataRemoved() MOZ_OVERRIDE;
virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
@ -216,24 +215,15 @@ private:
nsStyleContext *aNewStyleContext,
bool *aStartedAny,
nsCSSPropertySet *aWhichStarted);
ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
void WalkTransitionRule(ElementDependentRuleProcessorData* aData,
nsCSSPseudoElements::Type aPseudoType);
// Update the animated styles of an element and its descendants.
// If the element has a transition, it is flushed back to its primary frame.
// If the element does not have a transition, then its style is reparented.
void UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle,
nsStyleChangeList &aChangeList);
// Update the style on aElement from the transition stored in this manager and
// the new parent style - aParentStyle. aElement must be transitioning or
// animated. Returns the updated style.
nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement,
nsStyleContext* aParentStyle,
nsStyleChangeList &aChangeList);
void UpdateAllThrottledStylesInternal();
};
#endif /* !defined(nsTransitionManager_h_) */