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

This commit is contained in:
Nicholas Cameron 2013-10-22 14:14:41 +02:00
Родитель 671bba2fbd
Коммит 9aa2bb4046
9 изменённых файлов: 364 добавлений и 211 удалений

Просмотреть файл

@ -1055,7 +1055,8 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
// Initialise refresh tick counters for OMTA // Initialise refresh tick counters for OMTA
mLastStyleUpdateForAllAnimations = mLastStyleUpdateForAllAnimations =
mLastUpdateThrottledStyle = mRefreshDriver->MostRecentRefresh(); mLastUpdateThrottledAnimationStyle =
mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID); mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
@ -1579,15 +1580,29 @@ nsPresContext::GetDocShell() const
} }
bool bool
nsPresContext::ThrottledStyleIsUpToDate() const nsPresContext::ThrottledTransitionStyleIsUpToDate() const
{ {
return mLastUpdateThrottledStyle == mRefreshDriver->MostRecentRefresh(); return
mLastUpdateThrottledTransitionStyle == mRefreshDriver->MostRecentRefresh();
} }
void 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 bool

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -3,8 +3,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxPlatform.h"
#include "AnimationCommon.h" #include "AnimationCommon.h"
#include "nsTransitionManager.h"
#include "nsAnimationManager.h"
#include "gfxPlatform.h"
#include "nsRuleData.h" #include "nsRuleData.h"
#include "nsCSSValue.h" #include "nsCSSValue.h"
#include "nsStyleContext.h" #include "nsStyleContext.h"
@ -16,6 +19,9 @@
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "RestyleManager.h" #include "RestyleManager.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
using namespace mozilla::layers; using namespace mozilla::layers;
@ -142,6 +148,157 @@ CommonAnimationManager::ExtractComputedValueForTransition(
return result; 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) NS_IMPL_ISUPPORTS1(AnimValuesStyleRule, nsIStyleRule)
/* virtual */ void /* virtual */ void

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsSMILKeySpline.h" #include "nsSMILKeySpline.h"
#include "nsStyleStruct.h" #include "nsStyleStruct.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "nsCSSPseudoElements.h"
class nsPresContext; class nsPresContext;
class nsIFrame; class nsIFrame;
@ -71,10 +72,82 @@ protected:
virtual void ElementDataRemoved() = 0; virtual void ElementDataRemoved() = 0;
void RemoveAllElementData(); 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; PRCList mElementData;
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect) 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. * A style rule that maps property-nsStyleAnimation::Value pairs.
*/ */
@ -133,11 +206,12 @@ private:
struct CommonElementAnimationData : public PRCList struct CommonElementAnimationData : public PRCList
{ {
CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty, CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty,
CommonAnimationManager *aManager) CommonAnimationManager *aManager, TimeStamp aNow)
: mElement(aElement) : mElement(aElement)
, mElementProperty(aElementProperty) , mElementProperty(aElementProperty)
, mManager(aManager) , mManager(aManager)
, mAnimationGeneration(0) , mAnimationGeneration(0)
, mFlushGeneration(aNow)
#ifdef DEBUG #ifdef DEBUG
, mCalledPropertyDtor(false) , mCalledPropertyDtor(false)
#endif #endif
@ -217,6 +291,11 @@ struct CommonElementAnimationData : public PRCList
// The refresh time associated with mStyleRule. // The refresh time associated with mStyleRule.
TimeStamp mStyleRuleRefreshTime; 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 #ifdef DEBUG
bool mCalledPropertyDtor; bool mCalledPropertyDtor;
#endif #endif

Просмотреть файл

@ -4,13 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAnimationManager.h" #include "nsAnimationManager.h"
#include "nsTransitionManager.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsRuleProcessorData.h" #include "nsRuleProcessorData.h"
#include "nsStyleSet.h" #include "nsStyleSet.h"
#include "nsStyleChangeList.h"
#include "nsCSSRules.h" #include "nsCSSRules.h"
#include "RestyleManager.h"
#include "nsStyleAnimation.h" #include "nsStyleAnimation.h"
#include "nsEventDispatcher.h" #include "nsEventDispatcher.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
@ -22,10 +25,12 @@
using namespace mozilla; using namespace mozilla;
using namespace mozilla::css; using namespace mozilla::css;
ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty, ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement,
nsAnimationManager *aAnimationManager) nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager,
TimeStamp aNow)
: CommonElementAnimationData(aElement, aElementProperty, : CommonElementAnimationData(aElement, aElementProperty,
aAnimationManager), aAnimationManager, aNow),
mNeedsRefreshes(true) mNeedsRefreshes(true)
{ {
} }
@ -452,7 +457,8 @@ nsAnimationManager::GetElementAnimations(dom::Element *aElement,
aElement->GetProperty(propName)); aElement->GetProperty(propName));
if (!ea && aCreateIfNeeded) { if (!ea && aCreateIfNeeded) {
// FIXME: Consider arena-allocating? // 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, nsresult rv = aElement->SetProperty(propName, ea,
ElementAnimationsPropertyDtor, false); ElementAnimationsPropertyDtor, false);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -1093,3 +1099,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();
}

Просмотреть файл

@ -128,7 +128,7 @@ struct ElementAnimations MOZ_FINAL
typedef mozilla::TimeDuration TimeDuration; typedef mozilla::TimeDuration TimeDuration;
ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty, 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 // This function takes as input the start time, duration, and direction of an
// animation and returns the position in the current iteration. Note that // animation and returns the position in the current iteration. Note that
@ -275,6 +275,9 @@ public:
nsCSSPseudoElements::Type aPseudoType, nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded); bool aCreateIfNeeded);
// Updates styles on throttled animations. See note on nsTransitionManager
void UpdateAllThrottledStyles();
protected: protected:
virtual void ElementDataRemoved() MOZ_OVERRIDE virtual void ElementDataRemoved() MOZ_OVERRIDE
{ {
@ -298,6 +301,14 @@ private:
nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement, nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType); 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 // The guts of DispatchEvents
void DoDispatchEvents(); void DoDispatchEvents();

Просмотреть файл

@ -41,8 +41,8 @@ ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement,
nsIAtom *aElementProperty, nsIAtom *aElementProperty,
nsTransitionManager *aTransitionManager, nsTransitionManager *aTransitionManager,
TimeStamp aNow) TimeStamp aNow)
: CommonElementAnimationData(aElement, aElementProperty, aTransitionManager) : CommonElementAnimationData(aElement, aElementProperty,
, mFlushGeneration(aNow) aTransitionManager, aNow)
{ {
} }
@ -210,122 +210,6 @@ ElementTransitions::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
* nsTransitionManager * * 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 void
nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent, nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle, nsStyleContext* aParentStyle,
@ -350,17 +234,7 @@ nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
// remove the current transition from the working set // remove the current transition from the working set
et->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh(); et->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
} else { } else {
// reparent the element's style newStyle = ReparentContent(aContent, aParentStyle);
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);
} }
// walk the children // walk the children
@ -372,68 +246,25 @@ nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
} }
} }
IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(nsTransitionManager,
GetElementTransitions)
void void
nsTransitionManager::UpdateAllThrottledStyles() nsTransitionManager::UpdateAllThrottledStyles()
{ {
if (PR_CLIST_IS_EMPTY(&mElementData)) { if (PR_CLIST_IS_EMPTY(&mElementData)) {
// no throttled transitions, leave early // no throttled transitions, leave early
mPresContext->TickLastUpdateThrottledStyle(); mPresContext->TickLastUpdateThrottledTransitionStyle();
return; return;
} }
if (mPresContext->ThrottledStyleIsUpToDate()) { if (mPresContext->ThrottledTransitionStyleIsUpToDate()) {
// throttled transitions are up to date, leave early // throttled transitions are up to date, leave early
return; return;
} }
mPresContext->TickLastUpdateThrottledStyle(); mPresContext->TickLastUpdateThrottledTransitionStyle();
TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); UpdateAllThrottledStylesInternal();
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();
} }
void void
@ -527,7 +358,7 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement,
} }
NS_WARN_IF_FALSE(!nsLayoutUtils::AreAsyncAnimationsEnabled() || NS_WARN_IF_FALSE(!nsLayoutUtils::AreAsyncAnimationsEnabled() ||
mPresContext->ThrottledStyleIsUpToDate(), mPresContext->ThrottledTransitionStyleIsUpToDate(),
"throttled animations not up to date"); "throttled animations not up to date");
// Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html // Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html

Просмотреть файл

@ -91,11 +91,6 @@ struct ElementTransitions MOZ_FINAL
// Either zero or one for each CSS property: // Either zero or one for each CSS property:
nsTArray<ElementPropertyTransition> mPropertyTransitions; 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. // other than primary frames.
void UpdateAllThrottledStyles(); void UpdateAllThrottledStyles();
ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
protected: protected:
virtual void ElementDataRemoved() MOZ_OVERRIDE; virtual void ElementDataRemoved() MOZ_OVERRIDE;
virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
@ -216,24 +215,15 @@ private:
nsStyleContext *aNewStyleContext, nsStyleContext *aNewStyleContext,
bool *aStartedAny, bool *aStartedAny,
nsCSSPropertySet *aWhichStarted); nsCSSPropertySet *aWhichStarted);
ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
void WalkTransitionRule(ElementDependentRuleProcessorData* aData, void WalkTransitionRule(ElementDependentRuleProcessorData* aData,
nsCSSPseudoElements::Type aPseudoType); nsCSSPseudoElements::Type aPseudoType);
// Update the animated styles of an element and its descendants. // 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 has a transition, it is flushed back to its primary frame.
// If the element does not have a transition, then its style is reparented. // If the element does not have a transition, then its style is reparented.
void UpdateThrottledStylesForSubtree(nsIContent* aContent, void UpdateThrottledStylesForSubtree(nsIContent* aContent,
nsStyleContext* aParentStyle, nsStyleContext* aParentStyle,
nsStyleChangeList &aChangeList); nsStyleChangeList &aChangeList);
// Update the style on aElement from the transition stored in this manager and void UpdateAllThrottledStylesInternal();
// 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);
}; };
#endif /* !defined(nsTransitionManager_h_) */ #endif /* !defined(nsTransitionManager_h_) */