mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Back out bug 996796 patch 18 through patch 25 (changesets fbe97c2db729 through 9719c08c3144) to fix 50%-of-the-time Android 4.0 debug orange from single assertion ("Why did this not get handled while processing mRestyleRoots?", layout/base/RestyleTracker.cpp, line 87) in gfx/tests/crashtests/815489.html .
This commit is contained in:
parent
fe9339c972
commit
a39da5881c
@ -890,7 +890,7 @@ RestyleManager::RestyleElement(Element* aElement,
|
||||
newContext->StyleFont()->mFont.size) {
|
||||
// The basis for 'rem' units has changed.
|
||||
newContext = nullptr;
|
||||
DoRebuildAllStyleData(aRestyleTracker, nsChangeHint(0), aRestyleHint);
|
||||
DoRebuildAllStyleData(aRestyleTracker, nsChangeHint(0));
|
||||
if (aMinHint == 0) {
|
||||
return;
|
||||
}
|
||||
@ -906,15 +906,8 @@ RestyleManager::RestyleElement(Element* aElement,
|
||||
ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint,
|
||||
aRestyleTracker, aRestyleHint);
|
||||
ProcessRestyledFrames(changeList);
|
||||
} else if (aRestyleHint & ~eRestyle_LaterSiblings) {
|
||||
// We're restyling an element with no frame, so we should try to
|
||||
// make one if its new style says it should have one. But in order
|
||||
// to try to honor the restyle hint (which we'd like to do so that,
|
||||
// for example, an animation-only style flush doesn't flush other
|
||||
// buffered style changes), we only do this if the restyle hint says
|
||||
// we have *some* restyling for this frame. This means we'll
|
||||
// potentially get ahead of ourselves in that case, but not as much
|
||||
// as we would if we didn't check the restyle hint.
|
||||
} else {
|
||||
// no frames, reconstruct for content
|
||||
FrameConstructor()->MaybeRecreateFramesForElement(aElement);
|
||||
}
|
||||
}
|
||||
@ -1413,13 +1406,7 @@ RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
|
||||
mPresContext->SetProcessingRestyles(true);
|
||||
|
||||
// FIXME (bug 1047928): Many of the callers probably don't need
|
||||
// eRestyle_Subtree because they're changing things that affect data
|
||||
// computation rather than selector matching; we could have a restyle
|
||||
// hint passed in, and substantially improve the performance of things
|
||||
// like pref changes and the restyling that we do for downloadable
|
||||
// font loads.
|
||||
DoRebuildAllStyleData(mPendingRestyles, aExtraHint, eRestyle_Subtree);
|
||||
DoRebuildAllStyleData(mPendingRestyles, aExtraHint);
|
||||
|
||||
mPresContext->SetProcessingRestyles(false);
|
||||
|
||||
@ -1432,8 +1419,7 @@ RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
|
||||
void
|
||||
RestyleManager::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
||||
nsChangeHint aExtraHint,
|
||||
nsRestyleHint aRestyleHint)
|
||||
nsChangeHint aExtraHint)
|
||||
{
|
||||
// Tell the style set to get the old rule tree out of the way
|
||||
// so we can recalculate while maintaining rule tree immutability
|
||||
@ -1442,19 +1428,6 @@ RestyleManager::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aRestyleHint & ~eRestyle_Subtree) {
|
||||
// We want this hint to apply to the root node's primary frame
|
||||
// rather than the root frame, since it's the primary frame that has
|
||||
// the styles for the root element (rather than the ancestors of the
|
||||
// primary frame whose mContent is the root node but which have
|
||||
// different styles). If we use up the hint for one of the
|
||||
// ancestors that we hit first, then we'll fail to do the restyling
|
||||
// we need to do.
|
||||
aRestyleTracker.AddPendingRestyle(mPresContext->Document()->GetRootElement(),
|
||||
aRestyleHint, nsChangeHint(0));
|
||||
aRestyleHint = nsRestyleHint(0);
|
||||
}
|
||||
|
||||
// Recalculate all of the style contexts for the document
|
||||
// Note that we can ignore the return value of ComputeStyleChangeFor
|
||||
// because we never need to reframe the root frame
|
||||
@ -1463,12 +1436,11 @@ RestyleManager::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
||||
// on us re-running rule matching here
|
||||
nsStyleChangeList changeList;
|
||||
// XXX Does it matter that we're passing aExtraHint to the real root
|
||||
// frame and not the root node's primary frame? (We could do
|
||||
// roughly what we do for aRestyleHint above.)
|
||||
// frame and not the root node's primary frame?
|
||||
// Note: The restyle tracker we pass in here doesn't matter.
|
||||
ComputeStyleChangeFor(mPresContext->PresShell()->GetRootFrame(),
|
||||
&changeList, aExtraHint,
|
||||
aRestyleTracker, aRestyleHint);
|
||||
aRestyleTracker, eRestyle_Subtree);
|
||||
// Process the required changes
|
||||
ProcessRestyledFrames(changeList);
|
||||
FlushOverflowChangedTracker();
|
||||
@ -1574,25 +1546,8 @@ RestyleManager::UpdateOnlyAnimationStyles()
|
||||
}
|
||||
mLastUpdateForThrottledAnimations = now;
|
||||
|
||||
nsTransitionManager* transitionManager = mPresContext->TransitionManager();
|
||||
nsAnimationManager* animationManager = mPresContext->AnimationManager();
|
||||
|
||||
transitionManager->SetInAnimationOnlyStyleUpdate(true);
|
||||
|
||||
RestyleTracker tracker(ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT);
|
||||
tracker.Init(this);
|
||||
|
||||
// FIXME: We should have the transition manager and animation manager
|
||||
// add only the elements for which animations are currently throttled
|
||||
// (i.e., animating on the compositor with main-thread style updates
|
||||
// suppressed).
|
||||
transitionManager->AddStyleUpdatesTo(tracker);
|
||||
animationManager->AddStyleUpdatesTo(tracker);
|
||||
|
||||
tracker.ProcessRestyles();
|
||||
|
||||
transitionManager->SetInAnimationOnlyStyleUpdate(false);
|
||||
mPresContext->TransitionManager()->UpdateAllThrottledStyles();
|
||||
mPresContext->AnimationManager()->UpdateAllThrottledStyles();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1988,8 +1943,7 @@ GetPrevContinuationWithSameStyle(nsIFrame* aFrame)
|
||||
*/
|
||||
static nsIFrame*
|
||||
GetNextContinuationWithSameStyle(nsIFrame* aFrame,
|
||||
nsStyleContext* aOldStyleContext,
|
||||
bool* aHaveMoreContinuations = nullptr)
|
||||
nsStyleContext* aOldStyleContext)
|
||||
{
|
||||
// See GetPrevContinuationWithSameStyle about {ib} splits.
|
||||
|
||||
@ -2019,9 +1973,6 @@ GetNextContinuationWithSameStyle(nsIFrame* aFrame,
|
||||
aOldStyleContext->GetParent() != nextStyle->GetParent(),
|
||||
"continuations should have the same style context");
|
||||
nextContinuation = nullptr;
|
||||
if (aHaveMoreContinuations) {
|
||||
*aHaveMoreContinuations = true;
|
||||
}
|
||||
}
|
||||
return nextContinuation;
|
||||
}
|
||||
@ -2384,24 +2335,13 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
|
||||
"eRestyle_LaterSiblings must not be part of aRestyleHint");
|
||||
|
||||
nsRestyleHint hintToRestore = nsRestyleHint(0);
|
||||
if (mContent && mContent->IsElement() &&
|
||||
// If we're we're resolving from the root of the frame tree (which
|
||||
// we do in DoRebuildAllStyleData), we need to avoid getting the
|
||||
// root's restyle data until we get to its primary frame, since
|
||||
// it's the primary frame that has the styles for the root element
|
||||
// (rather than the ancestors of the primary frame whose mContent
|
||||
// is the root node but which have different styles). If we use
|
||||
// up the hint for one of the ancestors that we hit first, then
|
||||
// we'll fail to do the restyling we need to do.
|
||||
(mContent->GetParent() || mContent->GetPrimaryFrame() == mFrame)) {
|
||||
if (mContent && mContent->IsElement()) {
|
||||
mContent->OwnerDoc()->FlushPendingLinkUpdates();
|
||||
RestyleTracker::RestyleData restyleData;
|
||||
if (mRestyleTracker.GetRestyleData(mContent->AsElement(), &restyleData)) {
|
||||
if (NS_UpdateHint(mHintsHandled, restyleData.mChangeHint)) {
|
||||
mChangeList->AppendChange(mFrame, mContent, restyleData.mChangeHint);
|
||||
}
|
||||
hintToRestore = restyleData.mRestyleHint;
|
||||
aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
|
||||
}
|
||||
}
|
||||
@ -2414,20 +2354,10 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
// TEMPORARY (until bug 918064): Call RestyleSelf for each
|
||||
// continuation or block-in-inline sibling.
|
||||
|
||||
bool haveMoreContinuations = false;
|
||||
for (nsIFrame* f = mFrame; f;
|
||||
f = GetNextContinuationWithSameStyle(f, oldContext,
|
||||
&haveMoreContinuations)) {
|
||||
f = GetNextContinuationWithSameStyle(f, oldContext)) {
|
||||
RestyleSelf(f, aRestyleHint);
|
||||
}
|
||||
|
||||
if (haveMoreContinuations && hintToRestore) {
|
||||
// If we have more continuations with different style (e.g., because
|
||||
// we're inside a ::first-letter or ::first-line), put the restyle
|
||||
// hint back.
|
||||
mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
|
||||
hintToRestore, nsChangeHint(0));
|
||||
}
|
||||
}
|
||||
|
||||
RestyleChildren(childRestyleHint);
|
||||
@ -2525,18 +2455,22 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint)
|
||||
"non pseudo-element frame without content node");
|
||||
newContext = styleSet->ResolveStyleForNonElement(parentContext);
|
||||
}
|
||||
else if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree))) {
|
||||
else if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) &&
|
||||
!prevContinuation) {
|
||||
// Unfortunately, if prevContinuation is non-null then we may have
|
||||
// already stolen the restyle tracker entry for this element while
|
||||
// processing prevContinuation. So we don't know whether aRestyleHint
|
||||
// should really be 0 here or whether it should be eRestyle_Self. Be
|
||||
// pessimistic and force an actual reresolve in that situation. The good
|
||||
// news is that in the common case when prevContinuation is non-null we
|
||||
// just used prevContinuationContext anyway and aren't reaching this code
|
||||
// to start with.
|
||||
|
||||
Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
|
||||
if (aRestyleHint == nsRestyleHint(0) &&
|
||||
!styleSet->IsInRuleTreeReconstruct()) {
|
||||
if (aRestyleHint == nsRestyleHint(0)) {
|
||||
newContext =
|
||||
styleSet->ReparentStyleContext(oldContext, parentContext, element);
|
||||
} else {
|
||||
// Use ResolveStyleWithReplacement either for actual replacements
|
||||
// or, with no replacements, as a substitute for
|
||||
// ReparentStyleContext that rebuilds the path in the rule tree
|
||||
// rather than reusing the rule node, as we need to do during a
|
||||
// rule tree reconstruct.
|
||||
newContext =
|
||||
styleSet->ResolveStyleWithReplacement(element, parentContext, oldContext,
|
||||
aRestyleHint);
|
||||
@ -2643,26 +2577,11 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint)
|
||||
NS_ASSERTION(extraPseudoTag &&
|
||||
extraPseudoTag != nsCSSAnonBoxes::mozNonElement,
|
||||
"extra style context is not pseudo element");
|
||||
if (!(aRestyleHint & (eRestyle_Self | eRestyle_Subtree))) {
|
||||
Element* element = extraPseudoType != nsCSSPseudoElements::ePseudo_AnonBox
|
||||
? mContent->AsElement() : nullptr;
|
||||
if (styleSet->IsInRuleTreeReconstruct()) {
|
||||
// Use ResolveStyleWithReplacement as a substitute for
|
||||
// ReparentStyleContext that rebuilds the path in the rule tree
|
||||
// rather than reusing the rule node, as we need to do during a
|
||||
// rule tree reconstruct.
|
||||
newExtraContext =
|
||||
styleSet->ResolveStyleWithReplacement(element, newContext,
|
||||
oldExtraContext,
|
||||
nsRestyleHint(0));
|
||||
} else {
|
||||
newExtraContext =
|
||||
styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
|
||||
}
|
||||
} else if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
|
||||
if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
|
||||
newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag,
|
||||
newContext);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Don't expect XUL tree stuff here, since it needs a comparator and
|
||||
// all.
|
||||
NS_ASSERTION(extraPseudoType <
|
||||
@ -2688,20 +2607,6 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint)
|
||||
void
|
||||
ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
|
||||
{
|
||||
// We'd like style resolution to be exact in the sense that an
|
||||
// animation-only style flush flushes only the styles it requests
|
||||
// flushing and doesn't update any other styles. This means avoiding
|
||||
// constructing new frames during such a flush.
|
||||
//
|
||||
// For a ::before or ::after, we'll do an eRestyle_Subtree due to
|
||||
// RestyleHintForOp in nsCSSRuleProcessor.cpp (via its
|
||||
// HasAttributeDependentStyle or HasStateDependentStyle), given that
|
||||
// we store pseudo-elements in selectors like they were children.
|
||||
//
|
||||
// Also, it's faster to skip the work we do on undisplayed children
|
||||
// and pseudo-elements when we can skip it.
|
||||
bool mightReframePseudos = aChildRestyleHint & eRestyle_Subtree;
|
||||
|
||||
RestyleUndisplayedChildren(aChildRestyleHint);
|
||||
|
||||
// Check whether we might need to create a new ::before frame.
|
||||
@ -2712,7 +2617,7 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
|
||||
// ReconstructFrame hint. Using an out of date style context could
|
||||
// trigger assertions about mismatched rule trees.
|
||||
if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
|
||||
mightReframePseudos) {
|
||||
aChildRestyleHint) {
|
||||
RestyleBeforePseudo();
|
||||
}
|
||||
|
||||
@ -2741,7 +2646,7 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
|
||||
// Check whether we might need to create a new ::after frame.
|
||||
// See comments above regarding :before.
|
||||
if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
|
||||
mightReframePseudos) {
|
||||
aChildRestyleHint) {
|
||||
RestyleAfterPseudo(lastContinuation);
|
||||
}
|
||||
}
|
||||
@ -2796,8 +2701,7 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
|
||||
|
||||
nsRestyleHint thisChildHint = aChildRestyleHint;
|
||||
RestyleTracker::RestyleData undisplayedRestyleData;
|
||||
Element* element = undisplayed->mContent->AsElement();
|
||||
if (mRestyleTracker.GetRestyleData(element,
|
||||
if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
|
||||
&undisplayedRestyleData)) {
|
||||
thisChildHint =
|
||||
nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
|
||||
@ -2806,18 +2710,12 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
|
||||
nsStyleSet* styleSet = mPresContext->StyleSet();
|
||||
if (thisChildHint & (eRestyle_Self | eRestyle_Subtree)) {
|
||||
undisplayedContext =
|
||||
styleSet->ResolveStyleFor(element,
|
||||
styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
|
||||
mFrame->StyleContext(),
|
||||
mTreeMatchContext);
|
||||
} else if (thisChildHint ||
|
||||
styleSet->IsInRuleTreeReconstruct()) {
|
||||
// Use ResolveStyleWithReplacement either for actual
|
||||
// replacements, or as a substitute for ReparentStyleContext
|
||||
// that rebuilds the path in the rule tree rather than reusing
|
||||
// the rule node, as we need to do during a rule tree
|
||||
// reconstruct.
|
||||
} else if (thisChildHint) {
|
||||
undisplayedContext =
|
||||
styleSet->ResolveStyleWithReplacement(element,
|
||||
styleSet->ResolveStyleWithReplacement(undisplayed->mContent->AsElement(),
|
||||
mFrame->StyleContext(),
|
||||
undisplayed->mStyle,
|
||||
thisChildHint);
|
||||
@ -2825,7 +2723,7 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
|
||||
undisplayedContext =
|
||||
styleSet->ReparentStyleContext(undisplayed->mStyle,
|
||||
mFrame->StyleContext(),
|
||||
element);
|
||||
undisplayed->mContent->AsElement());
|
||||
}
|
||||
const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
|
||||
if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
|
||||
|
@ -164,26 +164,6 @@ public:
|
||||
// whose updating is suppressed on the main thread (to save
|
||||
// unnecessary work), while leaving all other aspects of style
|
||||
// out-of-date.
|
||||
//
|
||||
// Performs an animation-only style flush to make styles from
|
||||
// throttled transitions up-to-date prior to processing an unrelated
|
||||
// style change, so that any transitions triggered by that style
|
||||
// change produce correct results.
|
||||
//
|
||||
// In more detail: when we're able to run animations on the
|
||||
// compositor, we sometimes "throttle" these animations by skipping
|
||||
// updating style data on the main thread. However, whenever we
|
||||
// process a normal (non-animation) style change, any changes in
|
||||
// computed style on elements that have transition-* properties set
|
||||
// may need to trigger new transitions; this process requires knowing
|
||||
// both the old and new values of the property. To do this correctly,
|
||||
// we need to have an up-to-date *old* value of the property on the
|
||||
// primary frame. So the purpose of the mini-flush is to update the
|
||||
// style for all throttled transitions and animations to the current
|
||||
// animation state without making any other updates, so that when we
|
||||
// process the queued style updates we'll have correct old data to
|
||||
// compare against. When we do this, we don't bother touching frames
|
||||
// other than primary frames.
|
||||
void UpdateOnlyAnimationStyles();
|
||||
|
||||
bool ThrottledAnimationStyleIsUpToDate() const {
|
||||
@ -199,8 +179,7 @@ public:
|
||||
// Helper that does part of the work of RebuildAllStyleData, shared by
|
||||
// RestyleElement for 'rem' handling.
|
||||
void DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
||||
nsChangeHint aExtraHint,
|
||||
nsRestyleHint aRestyleHint);
|
||||
nsChangeHint aExtraHint);
|
||||
|
||||
// See PostRestyleEventCommon below.
|
||||
void PostRestyleEvent(Element* aElement,
|
||||
|
@ -19,7 +19,6 @@
|
||||
namespace mozilla {
|
||||
|
||||
class RestyleManager;
|
||||
class ElementRestyler;
|
||||
|
||||
/**
|
||||
* Helper class that collects a list of frames that need
|
||||
@ -231,8 +230,6 @@ class RestyleTracker {
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
friend class ElementRestyler; // for AddPendingRestyleToTable
|
||||
|
||||
RestyleTracker(Element::FlagsType aRestyleBits) :
|
||||
mRestyleBits(aRestyleBits),
|
||||
mHaveLaterSiblingRestyles(false)
|
||||
@ -264,7 +261,7 @@ public:
|
||||
* if the element already had eRestyle_LaterSiblings set on it.
|
||||
*/
|
||||
bool AddPendingRestyle(Element* aElement, nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint);
|
||||
nsChangeHint aMinChangeHint);
|
||||
|
||||
/**
|
||||
* Process the restyles we've been tracking.
|
||||
@ -315,9 +312,6 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
bool AddPendingRestyleToTable(Element* aElement, nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint);
|
||||
|
||||
/**
|
||||
* Handle a single mPendingRestyles entry. aRestyleHint must not
|
||||
* include eRestyle_LaterSiblings; that needs to be dealt with
|
||||
@ -358,10 +352,9 @@ private:
|
||||
bool mHaveLaterSiblingRestyles;
|
||||
};
|
||||
|
||||
inline bool
|
||||
RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
inline bool RestyleTracker::AddPendingRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
{
|
||||
RestyleData existingData;
|
||||
existingData.mRestyleHint = nsRestyleHint(0);
|
||||
@ -384,17 +377,6 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
|
||||
mPendingRestyles.Put(aElement, existingData);
|
||||
|
||||
return hadRestyleLaterSiblings;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RestyleTracker::AddPendingRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
{
|
||||
bool hadRestyleLaterSiblings =
|
||||
AddPendingRestyleToTable(aElement, aRestyleHint, aMinChangeHint);
|
||||
|
||||
// We can only treat this element as a restyle root if we would
|
||||
// actually restyle its descendants (so either call
|
||||
// ReResolveStyleContext on it or just reframe it).
|
||||
|
@ -166,28 +166,6 @@ CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker)
|
||||
{
|
||||
PRCList* next = PR_LIST_HEAD(&mElementCollections);
|
||||
while (next != &mElementCollections) {
|
||||
ElementAnimationCollection* collection = static_cast<ElementAnimationCollection*>(next);
|
||||
next = PR_NEXT_LINK(next);
|
||||
|
||||
if (!collection->IsForElement()) {
|
||||
// We don't support compositor-driven animation of :before/:after
|
||||
// transitions or animations, so at least skip those.
|
||||
// FIXME: We'll need to handle this before using this for the
|
||||
// transitions redesign.
|
||||
continue;
|
||||
}
|
||||
|
||||
nsRestyleHint rshint = collection->IsForTransitions()
|
||||
? eRestyle_CSSTransitions : eRestyle_CSSAnimations;
|
||||
aTracker.AddPendingRestyle(collection->mElement, rshint, nsChangeHint(0));
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
CommonAnimationManager::ExtractComputedValueForTransition(
|
||||
nsCSSProperty aProperty,
|
||||
@ -207,6 +185,90 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
nsStyleSet* styleSet = mPresContext->StyleSet();
|
||||
nsRefPtr<nsStyleContext> newStyle =
|
||||
styleSet->ResolveStyleWithReplacement(aElement, aParentStyle, oldStyle,
|
||||
nsRestyleHint(eRestyle_CSSTransitions | eRestyle_CSSAnimations));
|
||||
|
||||
// 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, styleSet);
|
||||
|
||||
return newStyle;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
|
||||
|
||||
/* virtual */ void
|
||||
|
@ -34,7 +34,6 @@ class nsStyleChangeList;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RestyleTracker;
|
||||
class StyleAnimationValue;
|
||||
struct ElementPropertyTransition;
|
||||
struct ElementAnimationCollection;
|
||||
@ -68,11 +67,6 @@ public:
|
||||
*/
|
||||
void Disconnect();
|
||||
|
||||
// Tell the restyle tracker about all the styles that we're currently
|
||||
// animating, so that it can update the animation rule for these
|
||||
// elements.
|
||||
void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
|
||||
|
||||
enum FlushFlags {
|
||||
Can_Throttle,
|
||||
Cannot_Throttle
|
||||
@ -100,10 +94,82 @@ protected:
|
||||
nsIAtom* aElementProperty,
|
||||
nsCSSProperty aProperty);
|
||||
|
||||
// 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 mElementCollections;
|
||||
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(&mElementCollections); \
|
||||
while (next != &mElementCollections) { \
|
||||
ElementAnimationCollection* collection = \
|
||||
static_cast<ElementAnimationCollection*>(next); \
|
||||
next = PR_NEXT_LINK(next); \
|
||||
\
|
||||
if (collection->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 = collection->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-StyleAnimationValue pairs.
|
||||
*/
|
||||
@ -390,6 +456,7 @@ struct ElementAnimationCollection : public PRCList
|
||||
, mElementProperty(aElementProperty)
|
||||
, mManager(aManager)
|
||||
, mAnimationGeneration(0)
|
||||
, mFlushGeneration(aNow)
|
||||
, mNeedsRefreshes(true)
|
||||
#ifdef DEBUG
|
||||
, mCalledPropertyDtor(false)
|
||||
@ -462,18 +529,6 @@ struct ElementAnimationCollection : public PRCList
|
||||
mElementProperty == nsGkAtoms::transitionsProperty;
|
||||
}
|
||||
|
||||
bool IsForTransitions() const {
|
||||
return mElementProperty == nsGkAtoms::transitionsProperty ||
|
||||
mElementProperty == nsGkAtoms::transitionsOfBeforeProperty ||
|
||||
mElementProperty == nsGkAtoms::transitionsOfAfterProperty;
|
||||
}
|
||||
|
||||
bool IsForAnimations() const {
|
||||
return mElementProperty == nsGkAtoms::animationsProperty ||
|
||||
mElementProperty == nsGkAtoms::animationsOfBeforeProperty ||
|
||||
mElementProperty == nsGkAtoms::animationsOfAfterProperty;
|
||||
}
|
||||
|
||||
nsString PseudoElement()
|
||||
{
|
||||
if (IsForElement()) {
|
||||
@ -530,6 +585,11 @@ struct ElementAnimationCollection : 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;
|
||||
|
||||
// False when we know that our current style rule is valid
|
||||
// indefinitely into the future (because all of our animations are
|
||||
// either completed or paused). May be invalidated by a style change.
|
||||
|
@ -775,3 +775,56 @@ 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;
|
||||
|
||||
ElementAnimationCollection* collection;
|
||||
if (element &&
|
||||
(collection =
|
||||
GetElementAnimations(element,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement,
|
||||
false))) {
|
||||
// re-resolve our style
|
||||
newStyle = UpdateThrottledStyle(element, aParentStyle, aChangeList);
|
||||
// remove the current transition from the working set
|
||||
collection->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(&mElementCollections)) {
|
||||
// no throttled animations, leave early
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAllThrottledStylesInternal();
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,9 @@ public:
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
bool aCreateIfNeeded);
|
||||
|
||||
// Updates styles on throttled animations. See note on nsTransitionManager
|
||||
void UpdateAllThrottledStyles();
|
||||
|
||||
protected:
|
||||
virtual void ElementCollectionRemoved() MOZ_OVERRIDE
|
||||
{
|
||||
@ -159,6 +162,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();
|
||||
|
||||
|
@ -1345,9 +1345,6 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement,
|
||||
// only the path from the last change in the rule tree, like
|
||||
// ReplaceAnimationRule in nsStyleSet.cpp does. (That could then
|
||||
// perhaps share this code, too?)
|
||||
// But if we do that, we'll need to pass whether we are rebuilding the
|
||||
// rule tree from ElementRestyler::RestyleSelf to avoid taking that
|
||||
// path when we're rebuilding the rule tree.
|
||||
|
||||
nsTArray<RuleNodeInfo> rules;
|
||||
for (nsRuleNode* ruleNode = aOldRuleNode; !ruleNode->IsRoot();
|
||||
|
@ -318,10 +318,6 @@ class nsStyleSet
|
||||
// Note: EndReconstruct should not be called if BeginReconstruct fails
|
||||
void EndReconstruct();
|
||||
|
||||
bool IsInRuleTreeReconstruct() const {
|
||||
return mInReconstruct;
|
||||
}
|
||||
|
||||
// Let the style set know that a particular sheet is the quirks sheet. This
|
||||
// sheet must already have been added to the UA sheets. The pointer must not
|
||||
// be null. This should only be called once for a given style set.
|
||||
|
@ -72,6 +72,58 @@ ElementPropertyTransition::CurrentValuePortion() const
|
||||
* nsTransitionManager *
|
||||
*****************************************************************************/
|
||||
|
||||
void
|
||||
nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
|
||||
nsStyleContext* aParentStyle,
|
||||
nsStyleChangeList& aChangeList)
|
||||
{
|
||||
dom::Element* element;
|
||||
if (aContent->IsElement()) {
|
||||
element = aContent->AsElement();
|
||||
} else {
|
||||
element = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<nsStyleContext> newStyle;
|
||||
|
||||
ElementAnimationCollection* collection;
|
||||
if (element &&
|
||||
(collection =
|
||||
GetElementTransitions(element,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement,
|
||||
false))) {
|
||||
// re-resolve our style
|
||||
newStyle = UpdateThrottledStyle(element, aParentStyle, aChangeList);
|
||||
// remove the current transition from the working set
|
||||
collection->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(nsTransitionManager,
|
||||
GetElementTransitions)
|
||||
|
||||
void
|
||||
nsTransitionManager::UpdateAllThrottledStyles()
|
||||
{
|
||||
if (PR_CLIST_IS_EMPTY(&mElementCollections)) {
|
||||
// no throttled transitions, leave early
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAllThrottledStylesInternal();
|
||||
}
|
||||
|
||||
void
|
||||
nsTransitionManager::ElementCollectionRemoved()
|
||||
{
|
||||
@ -111,15 +163,6 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement,
|
||||
aNewStyleContext->HasPseudoElementData(),
|
||||
"pseudo type mismatch");
|
||||
|
||||
if (mInAnimationOnlyStyleUpdate) {
|
||||
// If we're doing an animation-only style update, return, since the
|
||||
// purpose of an animation-only style update is to update only the
|
||||
// animation styles so that we don't consider style changes
|
||||
// resulting from changes in the animation time for starting a
|
||||
// transition.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mPresContext->IsDynamic()) {
|
||||
// For print or print preview, ignore transitions.
|
||||
return nullptr;
|
||||
|
@ -67,7 +67,6 @@ class nsTransitionManager MOZ_FINAL
|
||||
public:
|
||||
nsTransitionManager(nsPresContext *aPresContext)
|
||||
: mozilla::css::CommonAnimationManager(aPresContext)
|
||||
, mInAnimationOnlyStyleUpdate(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -118,10 +117,6 @@ public:
|
||||
nsStyleContext *aOldStyleContext,
|
||||
nsStyleContext *aNewStyleContext);
|
||||
|
||||
void SetInAnimationOnlyStyleUpdate(bool aInAnimationOnlyUpdate) {
|
||||
mInAnimationOnlyStyleUpdate = aInAnimationOnlyUpdate;
|
||||
}
|
||||
|
||||
// nsIStyleRuleProcessor (parts)
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
|
||||
@ -139,6 +134,27 @@ public:
|
||||
|
||||
void FlushTransitions(FlushFlags aFlags);
|
||||
|
||||
// Performs a 'mini-flush' to make styles from throttled transitions
|
||||
// up-to-date prior to processing an unrelated style change, so that
|
||||
// any transitions triggered by that style change produce correct
|
||||
// results.
|
||||
//
|
||||
// In more detail: when we're able to run animations on the
|
||||
// compositor, we sometimes "throttle" these animations by skipping
|
||||
// updating style data on the main thread. However, whenever we
|
||||
// process a normal (non-animation) style change, any changes in
|
||||
// computed style on elements that have transition-* properties set
|
||||
// may need to trigger new transitions; this process requires knowing
|
||||
// both the old and new values of the property. To do this correctly,
|
||||
// we need to have an up-to-date *old* value of the property on the
|
||||
// primary frame. So the purpose of the mini-flush is to update the
|
||||
// style for all throttled transitions and animations to the current
|
||||
// animation state without making any other updates, so that when we
|
||||
// process the queued style updates we'll have correct old data to
|
||||
// compare against. When we do this, we don't bother touching frames
|
||||
// other than primary frames.
|
||||
void UpdateAllThrottledStyles();
|
||||
|
||||
ElementAnimationCollection* GetElementTransitions(
|
||||
mozilla::dom::Element *aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
@ -161,8 +177,13 @@ private:
|
||||
nsCSSPropertySet* aWhichStarted);
|
||||
void WalkTransitionRule(ElementDependentRuleProcessorData* aData,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
bool mInAnimationOnlyStyleUpdate;
|
||||
// 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);
|
||||
void UpdateAllThrottledStylesInternal();
|
||||
};
|
||||
|
||||
#endif /* !defined(nsTransitionManager_h_) */
|
||||
|
Loading…
Reference in New Issue
Block a user