mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1180120 - Part 7: Add eRestyleResult_StopWithStyleChange. r=dbaron
This commit is contained in:
parent
f7742cef5d
commit
d32a93dce9
@ -2876,6 +2876,114 @@ ElementRestyler::MustCheckUndisplayedContent(nsIContent*& aUndisplayedParent)
|
||||
return !!aUndisplayedParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for MoveStyleContextsForChildren, below. Appends the style
|
||||
* contexts to be moved to mFrame's current (new) style context to
|
||||
* aContextsToMove.
|
||||
*/
|
||||
bool
|
||||
ElementRestyler::MoveStyleContextsForContentChildren(
|
||||
nsIFrame* aParent,
|
||||
nsStyleContext* aOldContext,
|
||||
nsTArray<nsStyleContext*>& aContextsToMove)
|
||||
{
|
||||
nsIFrame::ChildListIterator lists(aParent);
|
||||
for (; !lists.IsDone(); lists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame* child = childFrames.get();
|
||||
// Bail out if we have out-of-flow frames.
|
||||
// FIXME: It might be safe to just continue here instead of bailing out.
|
||||
if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
||||
return false;
|
||||
}
|
||||
if (GetPrevContinuationWithSameStyle(child)) {
|
||||
continue;
|
||||
}
|
||||
// Bail out if we have placeholder frames.
|
||||
// FIXME: It is probably safe to just continue here instead of bailing out.
|
||||
if (nsGkAtoms::placeholderFrame == child->GetType()) {
|
||||
return false;
|
||||
}
|
||||
nsStyleContext* sc = child->StyleContext();
|
||||
if (sc->GetParent() != aOldContext) {
|
||||
return false;
|
||||
}
|
||||
nsIAtom* type = child->GetType();
|
||||
if (type == nsGkAtoms::letterFrame ||
|
||||
type == nsGkAtoms::lineFrame) {
|
||||
return false;
|
||||
}
|
||||
if (sc->HasChildThatUsesGrandancestorStyle()) {
|
||||
// XXX Not sure if we need this?
|
||||
return false;
|
||||
}
|
||||
nsIAtom* pseudoTag = sc->GetPseudo();
|
||||
if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
|
||||
return false;
|
||||
}
|
||||
aContextsToMove.AppendElement(sc);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses to child elements (through the current frame's same style
|
||||
* continuations, just like RestyleChildren does) and moves any style context
|
||||
* for those children to be parented under mFrame's current (new) style
|
||||
* context.
|
||||
*
|
||||
* False is returned if it encounters any conditions on the child elements'
|
||||
* frames and style contexts that means it is impossible to move a
|
||||
* style context. If false is returned, no style contexts will have been
|
||||
* moved.
|
||||
*/
|
||||
bool
|
||||
ElementRestyler::MoveStyleContextsForChildren(nsStyleContext* aOldContext)
|
||||
{
|
||||
// Bail out if there are undisplayed or display:contents children.
|
||||
// FIXME: We could get this to work if we need to.
|
||||
nsIContent* undisplayedParent;
|
||||
if (MustCheckUndisplayedContent(undisplayedParent)) {
|
||||
nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
|
||||
if (fc->GetAllUndisplayedContentIn(undisplayedParent) ||
|
||||
fc->GetAllDisplayContentsIn(undisplayedParent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<nsStyleContext*> contextsToMove;
|
||||
|
||||
MOZ_ASSERT(!MustReframeForBeforePseudo(),
|
||||
"shouldn't need to reframe ::before as we would have had "
|
||||
"eRestyle_Subtree and wouldn't get in here");
|
||||
|
||||
DebugOnly<nsIFrame*> lastContinuation;
|
||||
for (nsIFrame* f = mFrame; f;
|
||||
f = GetNextContinuationWithSameStyle(f, f->StyleContext())) {
|
||||
lastContinuation = f;
|
||||
if (!MoveStyleContextsForContentChildren(f, aOldContext, contextsToMove)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!MustReframeForAfterPseudo(lastContinuation),
|
||||
"shouldn't need to reframe ::after as we would have had "
|
||||
"eRestyle_Subtree and wouldn't get in here");
|
||||
|
||||
nsStyleContext* newParent = mFrame->StyleContext();
|
||||
for (nsStyleContext* child : contextsToMove) {
|
||||
// We can have duplicate entries in contextsToMove, so only move
|
||||
// each style context once.
|
||||
if (child->GetParent() != newParent) {
|
||||
child->MoveTo(newParent);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recompute style for mFrame (which should not have a prev continuation
|
||||
* with the same style), all of its next continuations with the same
|
||||
@ -2962,6 +3070,8 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
|
||||
nsRefPtr<nsStyleContext> oldContext = mFrame->StyleContext();
|
||||
|
||||
nsTArray<SwapInstruction> swaps;
|
||||
|
||||
// TEMPORARY (until bug 918064): Call RestyleSelf for each
|
||||
// continuation or block-in-inline sibling.
|
||||
|
||||
@ -2976,7 +3086,8 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
|
||||
bool haveMoreContinuations = false;
|
||||
for (nsIFrame* f = mFrame; f; ) {
|
||||
RestyleResult thisResult = RestyleSelf(f, thisRestyleHint, &swappedStructs);
|
||||
RestyleResult thisResult =
|
||||
RestyleSelf(f, thisRestyleHint, &swappedStructs, swaps);
|
||||
|
||||
if (thisResult != eRestyleResult_Stop) {
|
||||
// Calls to RestyleSelf for later same-style continuations must not
|
||||
@ -2985,8 +3096,9 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
|
||||
if (result == eRestyleResult_Stop) {
|
||||
// We received eRestyleResult_Stop for earlier same-style
|
||||
// continuations, and eRestyleResult_Continue(AndForceDescendants) for
|
||||
// this one; go back and force-restyle the earlier continuations.
|
||||
// continuations, and eRestyleResult_StopWithStyleChange or
|
||||
// eRestyleResult_Continue(AndForceDescendants) for this one; go
|
||||
// back and force-restyle the earlier continuations.
|
||||
result = thisResult;
|
||||
f = mFrame;
|
||||
continue;
|
||||
@ -3066,6 +3178,50 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == eRestyleResult_StopWithStyleChange &&
|
||||
!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
||||
MOZ_ASSERT(mFrame->StyleContext() != oldContext,
|
||||
"eRestyleResult_StopWithStyleChange should only be returned "
|
||||
"if we got a new style context or we will reconstruct");
|
||||
MOZ_ASSERT(swappedStructs == 0,
|
||||
"should have ensured we didn't swap structs when "
|
||||
"returning eRestyleResult_StopWithStyleChange");
|
||||
|
||||
// We need to ensure that all of the frames that inherit their style
|
||||
// from oldContext are able to be moved across to newContext.
|
||||
// MoveStyleContextsForChildren will check for certain conditions
|
||||
// to ensure it is safe to move all of the relevant child style
|
||||
// contexts to newContext. If these conditions fail, it will
|
||||
// return false, and we'll have to continue restyling.
|
||||
const bool canStop = MoveStyleContextsForChildren(oldContext);
|
||||
|
||||
if (canStop) {
|
||||
// Send the accessibility notifications that RestyleChildren otherwise
|
||||
// would have sent.
|
||||
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
||||
InitializeAccessibilityNotifications(mFrame->StyleContext());
|
||||
SendAccessibilityNotifications();
|
||||
}
|
||||
|
||||
mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
|
||||
if (aRestyleHint & eRestyle_SomeDescendants) {
|
||||
AddPendingRestylesForDescendantsMatchingSelectors(mContent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Turns out we couldn't stop restyling here. Process the struct
|
||||
// swaps that RestyleSelf would've done had we not returned
|
||||
// eRestyleResult_StopWithStyleChange.
|
||||
for (SwapInstruction& swap : swaps) {
|
||||
LOG_RESTYLE("swapping style structs between %p and %p",
|
||||
swap.mOldContext.get(), swap.mNewContext.get());
|
||||
swap.mOldContext->SwapStyleData(swap.mNewContext, swap.mStructsToSwap);
|
||||
swappedStructs |= swap.mStructsToSwap;
|
||||
}
|
||||
swaps.Clear();
|
||||
}
|
||||
|
||||
if (!swappedStructs) {
|
||||
// If we swapped any structs from the old context, then we need to keep
|
||||
// it alive until after the RestyleChildren call so that we can fix up
|
||||
@ -3122,8 +3278,10 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
||||
* conditions that would preclude stopping restyling, and
|
||||
* eRestyleResult_Continue if it does.
|
||||
*/
|
||||
ElementRestyler::RestyleResult
|
||||
ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
void
|
||||
ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange)
|
||||
{
|
||||
// We can't handle situations where the primary style context of a frame
|
||||
// has not had any style data changes, but its additional style contexts
|
||||
@ -3131,7 +3289,9 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
// style contexts.
|
||||
if (aSelf->GetAdditionalStyleContext(0)) {
|
||||
LOG_RESTYLE_CONTINUE("there are additional style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Style changes might have moved children between the two nsLetterFrames
|
||||
@ -3143,12 +3303,16 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
|
||||
if (type == nsGkAtoms::letterFrame) {
|
||||
LOG_RESTYLE_CONTINUE("frame is a letter frame");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == nsGkAtoms::lineFrame) {
|
||||
LOG_RESTYLE_CONTINUE("frame is a line frame");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Some style computations depend not on the parent's style, but a grandparent
|
||||
@ -3161,19 +3325,25 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
nsStyleContext* oldContext = aSelf->StyleContext();
|
||||
if (oldContext->HasChildThatUsesGrandancestorStyle()) {
|
||||
LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// We ignore all situations that involve :visited style.
|
||||
if (oldContext->GetStyleIfVisited()) {
|
||||
LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
nsStyleContext* parentContext = oldContext->GetParent();
|
||||
if (parentContext && parentContext->GetStyleIfVisited()) {
|
||||
LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// We also ignore frames for pseudos, as their style contexts have
|
||||
@ -3184,7 +3354,9 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
nsIAtom* pseudoTag = oldContext->GetPseudo();
|
||||
if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
|
||||
LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* parent = mFrame->GetParent();
|
||||
@ -3196,23 +3368,37 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
|
||||
nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
|
||||
if (parentPseudoTag && parentPseudoTag != nsCSSAnonBoxes::mozNonElement) {
|
||||
LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
// Parent style context pseudo-ness doesn't affect whether we can
|
||||
// return eRestyleResult_StopWithStyleChange.
|
||||
//
|
||||
// If we had later conditions to check in this function, we would
|
||||
// continue to check them, in case we set aCanStopWithStyleChange to
|
||||
// false.
|
||||
}
|
||||
}
|
||||
|
||||
return eRestyleResult_Stop;
|
||||
}
|
||||
|
||||
ElementRestyler::RestyleResult
|
||||
void
|
||||
ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
nsStyleContext* aNewContext)
|
||||
nsStyleContext* aNewContext,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange)
|
||||
{
|
||||
// If we've already determined that we must continue styling, we don't
|
||||
// need to check anything.
|
||||
if (aRestyleResult == eRestyleResult_Continue && !aCanStopWithStyleChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep restyling if the new style context has any style-if-visted style, so
|
||||
// that we can avoid the style context tree surgery having to deal to deal
|
||||
// with visited styles.
|
||||
if (aNewContext->GetStyleIfVisited()) {
|
||||
LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// If link-related information has changed, or the pseudo for the frame has
|
||||
@ -3222,11 +3408,23 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
if (oldContext->IsLinkContext() != aNewContext->IsLinkContext() ||
|
||||
oldContext->RelevantLinkVisited() != aNewContext->RelevantLinkVisited() ||
|
||||
oldContext->GetPseudo() != aNewContext->GetPseudo() ||
|
||||
oldContext->GetPseudoType() != aNewContext->GetPseudoType() ||
|
||||
oldContext->RuleNode() != aNewContext->RuleNode()) {
|
||||
oldContext->GetPseudoType() != aNewContext->GetPseudoType()) {
|
||||
LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
|
||||
"visited/pseudo/rulenodes");
|
||||
return eRestyleResult_Continue;
|
||||
"visited/pseudo");
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldContext->RuleNode() != aNewContext->RuleNode()) {
|
||||
LOG_RESTYLE_CONTINUE("the old and new style contexts have different "
|
||||
"rulenodes");
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
// Continue to check other conditions if aCanStopWithStyleChange might
|
||||
// still need to be set to false.
|
||||
if (!aCanStopWithStyleChange) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the old and new style contexts differ in their
|
||||
@ -3237,31 +3435,37 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
aNewContext->HasTextDecorationLines()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
|
||||
" and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldContext->HasPseudoElementData() !=
|
||||
aNewContext->HasPseudoElementData()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
|
||||
" and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldContext->ShouldSuppressLineBreak() !=
|
||||
aNewContext->ShouldSuppressLineBreak()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_SUPPRESS_LINEBREAK differs"
|
||||
"between old and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldContext->IsInDisplayNoneSubtree() !=
|
||||
aNewContext->IsInDisplayNoneSubtree()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_IN_DISPLAY_NONE_SUBTREE differs between old"
|
||||
" and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
aRestyleResult = eRestyleResult_Continue;
|
||||
aCanStopWithStyleChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
return eRestyleResult_Stop;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3305,7 +3509,8 @@ ElementRestyler::CanReparentStyleContext(nsRestyleHint aRestyleHint)
|
||||
ElementRestyler::RestyleResult
|
||||
ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
nsRestyleHint aRestyleHint,
|
||||
uint32_t* aSwappedStructs)
|
||||
uint32_t* aSwappedStructs,
|
||||
nsTArray<SwapInstruction>& aSwaps)
|
||||
{
|
||||
MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
|
||||
"eRestyle_LaterSiblings must not be part of aRestyleHint");
|
||||
@ -3323,14 +3528,44 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
RestyleManager::RestyleHintToString(aRestyleHint).get());
|
||||
LOG_RESTYLE_INDENT();
|
||||
|
||||
RestyleResult result;
|
||||
// Initially assume that it is safe to stop restyling.
|
||||
//
|
||||
// Throughout most of this function, we update the following two variables
|
||||
// independently. |result| is set to eRestyleResult_Continue when we
|
||||
// detect a condition that would not allow us to return eRestyleResult_Stop.
|
||||
// |canStopWithStyleChange| is set to false when we detect a condition
|
||||
// that would not allow us to return eRestyleResult_StopWithStyleChange.
|
||||
//
|
||||
// Towards the end of this function, we reconcile these two variables --
|
||||
// if |canStopWithStyleChange| is true, we convert |result| into
|
||||
// eRestyleResult_StopWithStyleChange.
|
||||
RestyleResult result = eRestyleResult_Stop;
|
||||
bool canStopWithStyleChange = true;
|
||||
|
||||
if (aRestyleHint & ~eRestyle_SomeDescendants) {
|
||||
// If we are doing any restyling of the current element, or if we're
|
||||
// forced to continue, we must.
|
||||
result = eRestyleResult_Continue;
|
||||
} else {
|
||||
result = ComputeRestyleResultFromFrame(aSelf);
|
||||
|
||||
// If we have to restyle children, we can't return
|
||||
// eRestyleResult_StopWithStyleChange.
|
||||
if (aRestyleHint & (eRestyle_Subtree | eRestyle_Force |
|
||||
eRestyle_ForceDescendants)) {
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We only consider returning eRestyleResult_StopWithStyleChange if this
|
||||
// is the root of the restyle. (Otherwise, we would need to track the
|
||||
// style changes of the ancestors we just restyled.)
|
||||
if (!mIsRootOfRestyle) {
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
|
||||
// Look at the frame and its current style context for conditions
|
||||
// that would change our RestyleResult.
|
||||
ComputeRestyleResultFromFrame(aSelf, result, canStopWithStyleChange);
|
||||
|
||||
nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE;
|
||||
nsRefPtr<nsStyleContext> oldContext = aSelf->StyleContext();
|
||||
nsStyleSet* styleSet = mPresContext->StyleSet();
|
||||
@ -3378,6 +3613,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
LOG_RESTYLE_CONTINUE("we had a provider frame");
|
||||
// Continue restyling past the odd style context inheritance.
|
||||
result = eRestyleResult_Continue;
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
|
||||
if (providerFrame != aSelf->GetParent()) {
|
||||
@ -3515,6 +3751,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
newContext = oldContext;
|
||||
// Never consider stopping restyling at the root.
|
||||
result = eRestyleResult_Continue;
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3524,22 +3761,21 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
(const char*) "");
|
||||
|
||||
if (newContext != oldContext) {
|
||||
if (result == eRestyleResult_Stop) {
|
||||
if (oldContext->IsShared()) {
|
||||
// If the old style context was shared, then we can't return
|
||||
// eRestyleResult_Stop and patch its parent to point to the
|
||||
// new parent style context, as that change might not be valid
|
||||
// for the other frames sharing the style context.
|
||||
LOG_RESTYLE_CONTINUE("the old style context is shared");
|
||||
result = eRestyleResult_Continue;
|
||||
} else {
|
||||
// Look at some details of the new style context to see if it would
|
||||
// be safe to stop restyling, if we discover it has the same style
|
||||
// data as the old style context.
|
||||
result = ComputeRestyleResultFromNewContext(aSelf, newContext);
|
||||
}
|
||||
if (oldContext->IsShared()) {
|
||||
// If the old style context was shared, then we can't return
|
||||
// eRestyleResult_Stop and patch its parent to point to the
|
||||
// new parent style context, as that change might not be valid
|
||||
// for the other frames sharing the style context.
|
||||
LOG_RESTYLE_CONTINUE("the old style context is shared");
|
||||
result = eRestyleResult_Continue;
|
||||
}
|
||||
|
||||
// Look at some details of the new style context to see if it would
|
||||
// be safe to stop restyling, if we discover it has the same style
|
||||
// data as the old style context.
|
||||
ComputeRestyleResultFromNewContext(aSelf, newContext,
|
||||
result, canStopWithStyleChange);
|
||||
|
||||
uint32_t equalStructs = 0;
|
||||
uint32_t samePointerStructs = 0;
|
||||
|
||||
@ -3569,6 +3805,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
if (changedStyle) {
|
||||
LOG_RESTYLE_CONTINUE("TryStartingTransition changed the new style context");
|
||||
result = eRestyleResult_Continue;
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
CaptureChange(oldContext, newContext, assumeDifferenceHint,
|
||||
&equalStructs, &samePointerStructs);
|
||||
@ -3582,6 +3819,25 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
}
|
||||
}
|
||||
|
||||
if (canStopWithStyleChange) {
|
||||
// If any inherited struct pointers are different, or if any
|
||||
// reset struct pointers are different and we have descendants
|
||||
// that rely on those reset struct pointers, we can't return
|
||||
// eRestyleResult_StopWithStyleChange.
|
||||
if ((samePointerStructs & NS_STYLE_INHERITED_STRUCT_MASK) !=
|
||||
NS_STYLE_INHERITED_STRUCT_MASK) {
|
||||
LOG_RESTYLE("can't return eRestyleResult_StopWithStyleChange since "
|
||||
"there is different inherited data");
|
||||
canStopWithStyleChange = false;
|
||||
} else if ((samePointerStructs & NS_STYLE_RESET_STRUCT_MASK) !=
|
||||
NS_STYLE_RESET_STRUCT_MASK &&
|
||||
oldContext->HasChildThatUsesResetStyle()) {
|
||||
LOG_RESTYLE("can't return eRestyleResult_StopWithStyleChange since "
|
||||
"there is different reset data and descendants use it");
|
||||
canStopWithStyleChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == eRestyleResult_Stop) {
|
||||
// Since we currently have eRestyleResult_Stop, we know at this
|
||||
// point that all of our style structs are equal in terms of styles.
|
||||
@ -3616,6 +3872,21 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
}
|
||||
}
|
||||
|
||||
// From this point we no longer do any assignments of
|
||||
// eRestyleResult_Continue to |result|. If canStopWithStyleChange is true,
|
||||
// it means that we can convert |result| (whether it is
|
||||
// eRestyleResult_Continue or eRestyleResult_Stop) into
|
||||
// eRestyleResult_StopWithStyleChange.
|
||||
if (canStopWithStyleChange) {
|
||||
LOG_RESTYLE("converting %s into eRestyleResult_StopWithStyleChange",
|
||||
RestyleResultToString(result).get());
|
||||
result = eRestyleResult_StopWithStyleChange;
|
||||
}
|
||||
|
||||
if (aRestyleHint & eRestyle_ForceDescendants) {
|
||||
result = eRestyleResult_ContinueAndForceDescendants;
|
||||
}
|
||||
|
||||
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
|
||||
// If the frame gets regenerated, let it keep its old context,
|
||||
// which is important to maintain various invariants about
|
||||
@ -3639,10 +3910,20 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
LOG_RESTYLE("not swapping style structs, since the new context is "
|
||||
"shared");
|
||||
} else {
|
||||
LOG_RESTYLE("swapping style structs between %p and %p",
|
||||
oldContext.get(), newContext.get());
|
||||
oldContext->SwapStyleData(newContext, equalStructs);
|
||||
*aSwappedStructs |= equalStructs;
|
||||
if (result == eRestyleResult_StopWithStyleChange) {
|
||||
LOG_RESTYLE("recording a style struct swap between %p and %p to "
|
||||
"do if eRestyleResult_StopWithStyleChange fails",
|
||||
oldContext.get(), newContext.get());
|
||||
SwapInstruction* swap = aSwaps.AppendElement();
|
||||
swap->mOldContext = oldContext;
|
||||
swap->mNewContext = newContext;
|
||||
swap->mStructsToSwap = equalStructs;
|
||||
} else {
|
||||
LOG_RESTYLE("swapping style structs between %p and %p",
|
||||
oldContext.get(), newContext.get());
|
||||
oldContext->SwapStyleData(newContext, equalStructs);
|
||||
*aSwappedStructs |= equalStructs;
|
||||
}
|
||||
#ifdef RESTYLE_LOGGING
|
||||
uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
|
||||
if (structs) {
|
||||
@ -3669,6 +3950,10 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
// parent, but we don't have that information here.
|
||||
mSwappedStructOwners.AppendElement(newContext->GetParent());
|
||||
}
|
||||
} else {
|
||||
if (aRestyleHint & eRestyle_ForceDescendants) {
|
||||
result = eRestyleResult_ContinueAndForceDescendants;
|
||||
}
|
||||
}
|
||||
oldContext = nullptr;
|
||||
|
||||
@ -3743,10 +4028,6 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
|
||||
}
|
||||
}
|
||||
|
||||
if (aRestyleHint & eRestyle_ForceDescendants) {
|
||||
result = eRestyleResult_ContinueAndForceDescendants;
|
||||
}
|
||||
|
||||
LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
|
||||
|
||||
return result;
|
||||
@ -3924,8 +4205,16 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame,
|
||||
selectorsForDescendants.AppendElements(
|
||||
aRestyleHintData.mSelectorsForDescendants);
|
||||
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
|
||||
for (nsIFrame* ibSibling = aFrame; ibSibling;
|
||||
ibSibling = GetNextBlockInInlineSibling(propTable, ibSibling)) {
|
||||
nsIFrame* nextIBSibling;
|
||||
for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) {
|
||||
nextIBSibling = GetNextBlockInInlineSibling(propTable, ibSibling);
|
||||
|
||||
if (nextIBSibling) {
|
||||
// Don't allow some ib-split siblings to be processed with
|
||||
// eRestyleResult_StopWithStyleChange and others not.
|
||||
aRestyleHint |= eRestyle_Force;
|
||||
}
|
||||
|
||||
// Outer loop over ib-split siblings
|
||||
for (nsIFrame* cont = ibSibling; cont; cont = cont->GetNextContinuation()) {
|
||||
if (GetPrevContinuationWithSameStyle(cont)) {
|
||||
@ -4592,6 +4881,9 @@ ElementRestyler::RestyleResultToString(RestyleResult aRestyleResult)
|
||||
case eRestyleResult_Stop:
|
||||
result.AssignLiteral("eRestyleResult_Stop");
|
||||
break;
|
||||
case eRestyleResult_StopWithStyleChange:
|
||||
result.AssignLiteral("eRestyleResult_StopWithStyleChange");
|
||||
break;
|
||||
case eRestyleResult_Continue:
|
||||
result.AssignLiteral("eRestyleResult_Continue");
|
||||
break;
|
||||
|
@ -620,9 +620,13 @@ private:
|
||||
// the work of the earlier values is also done.
|
||||
enum RestyleResult {
|
||||
|
||||
// do not restyle children
|
||||
// we left the old style context on the frame; do not restyle children
|
||||
eRestyleResult_Stop = 1,
|
||||
|
||||
// we got a new style context on this frame, but we know that children
|
||||
// do not depend on the changed values; do not restyle children
|
||||
eRestyleResult_StopWithStyleChange,
|
||||
|
||||
// continue restyling children
|
||||
eRestyleResult_Continue,
|
||||
|
||||
@ -630,12 +634,20 @@ private:
|
||||
eRestyleResult_ContinueAndForceDescendants
|
||||
};
|
||||
|
||||
struct SwapInstruction
|
||||
{
|
||||
nsRefPtr<nsStyleContext> mOldContext;
|
||||
nsRefPtr<nsStyleContext> mNewContext;
|
||||
uint32_t mStructsToSwap;
|
||||
};
|
||||
|
||||
/**
|
||||
* First half of Restyle().
|
||||
*/
|
||||
RestyleResult RestyleSelf(nsIFrame* aSelf,
|
||||
nsRestyleHint aRestyleHint,
|
||||
uint32_t* aSwappedStructs);
|
||||
uint32_t* aSwappedStructs,
|
||||
nsTArray<SwapInstruction>& aSwaps);
|
||||
|
||||
/**
|
||||
* Restyle the children of this frame (and, in turn, their children).
|
||||
@ -674,6 +686,11 @@ private:
|
||||
*/
|
||||
void AddLayerChangesForAnimation();
|
||||
|
||||
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
|
||||
nsStyleContext* aOldContext,
|
||||
nsTArray<nsStyleContext*>& aContextsToMove);
|
||||
bool MoveStyleContextsForChildren(nsStyleContext* aOldContext);
|
||||
|
||||
/**
|
||||
* Helpers for RestyleSelf().
|
||||
*/
|
||||
@ -682,9 +699,13 @@ private:
|
||||
nsChangeHint aChangeToAssume,
|
||||
uint32_t* aEqualStructs,
|
||||
uint32_t* aSamePointerStructs);
|
||||
RestyleResult ComputeRestyleResultFromFrame(nsIFrame* aSelf);
|
||||
RestyleResult ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
nsStyleContext* aNewContext);
|
||||
void ComputeRestyleResultFromFrame(nsIFrame* aSelf,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange);
|
||||
void ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
nsStyleContext* aNewContext,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange);
|
||||
|
||||
// Helpers for RestyleChildren().
|
||||
void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint);
|
||||
|
@ -41,6 +41,14 @@ class imgIContainer;
|
||||
// NS_STYLE_INHERIT_BIT defined in nsStyleStructFwd.h
|
||||
#define NS_STYLE_INHERIT_MASK 0x000ffffff
|
||||
|
||||
// Bits for inherited structs.
|
||||
#define NS_STYLE_INHERITED_STRUCT_MASK \
|
||||
((nsStyleStructID_size_t(1) << nsStyleStructID_Inherited_Count) - 1)
|
||||
// Bits for reset structs.
|
||||
#define NS_STYLE_RESET_STRUCT_MASK \
|
||||
(((nsStyleStructID_size_t(1) << nsStyleStructID_Reset_Count) - 1) \
|
||||
<< nsStyleStructID_Inherited_Count)
|
||||
|
||||
// Additional bits for nsStyleContext's mBits:
|
||||
// See nsStyleContext::HasTextDecorationLines
|
||||
#define NS_STYLE_HAS_TEXT_DECORATION_LINES 0x001000000
|
||||
|
@ -65,4 +65,6 @@ eStyleStruct_BackendOnly = nsStyleStructID_Length
|
||||
// A bit corresponding to each struct ID
|
||||
#define NS_STYLE_INHERIT_BIT(sid_) (1 << uint64_t(eStyleStruct_##sid_))
|
||||
|
||||
typedef decltype(nsStyleStructID(0) + nsStyleStructID(0)) nsStyleStructID_size_t;
|
||||
|
||||
#endif /* nsStyleStructFwd_h_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user