зеркало из https://github.com/mozilla/gecko-dev.git
Bug 914847. Mini-flush for animations. r=dbaron
This commit is contained in:
Родитель
671bba2fbd
Коммит
9aa2bb4046
|
@ -1055,7 +1055,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);
|
||||
|
||||
|
@ -1579,15 +1580,29 @@ nsPresContext::GetDocShell() 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
|
||||
|
|
|
@ -664,8 +664,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();
|
||||
|
||||
|
@ -1240,8 +1242,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;
|
||||
|
||||
|
|
|
@ -6211,6 +6211,7 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
|||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (presContext) {
|
||||
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
|
||||
* 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;
|
||||
|
||||
|
@ -142,6 +148,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
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsSMILKeySpline.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIFrame;
|
||||
|
@ -71,10 +72,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.
|
||||
*/
|
||||
|
@ -133,11 +206,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
|
||||
|
@ -217,6 +291,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
|
||||
|
|
|
@ -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"
|
||||
|
@ -22,10 +25,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)
|
||||
{
|
||||
}
|
||||
|
@ -452,7 +457,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)) {
|
||||
|
@ -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;
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement,
|
|||
nsIAtom *aElementProperty,
|
||||
nsTransitionManager *aTransitionManager,
|
||||
TimeStamp aNow)
|
||||
: CommonElementAnimationData(aElement, aElementProperty, aTransitionManager)
|
||||
, mFlushGeneration(aNow)
|
||||
: CommonElementAnimationData(aElement, aElementProperty,
|
||||
aTransitionManager, aNow)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -210,122 +210,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,
|
||||
|
@ -350,17 +234,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
|
||||
|
@ -372,68 +246,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
|
||||
|
@ -527,7 +358,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
|
||||
|
|
|
@ -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_) */
|
||||
|
|
Загрузка…
Ссылка в новой задаче