Bug 1371450 - Recreate style context only if the element was restyled during the traversal. r?emilio
MozReview-Commit-ID: CBYTB5FeikP
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -245,17 +245,20 @@ ServoRestyleManager::ClearRestyleStateFr
StyleChildrenIterator it(aElement);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (n->IsElement()) {
ClearRestyleStateFromSubtree(n->AsElement());
}
}
}
- Unused << Servo_TakeChangeHint(aElement, TraversalRestyleBehavior::Normal);
+ bool wasRestyled;
+ Unused << Servo_TakeChangeHint(aElement,
+ TraversalRestyleBehavior::Normal,
+ &wasRestyled);
aElement->UnsetHasDirtyDescendantsForServo();
aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
}
/**
* This struct takes care of encapsulating some common state that text nodes may
* need to track during the post-traversal.
@@ -462,17 +465,20 @@ ServoRestyleManager::ProcessPostTraversa
const bool isOutOfFlow =
aElement->GetPrimaryFrame() &&
aElement->GetPrimaryFrame()->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
// Grab the change hint from Servo.
// In case of flushing throttled animations, any restyle hints other than
// animations are preserved since they are the hints which will be processed
// in normal restyle later.
- nsChangeHint changeHint = Servo_TakeChangeHint(aElement, aRestyleBehavior);
+ bool wasRestyled;
+ nsChangeHint changeHint = Servo_TakeChangeHint(aElement,
+ aRestyleBehavior,
+ &wasRestyled);
// We should really fix the weird primary frame mapping for image maps
// (bug 135040)...
if (styleFrame && styleFrame->GetContent() != aElement) {
MOZ_ASSERT(styleFrame->IsImageFrame());
styleFrame = nullptr;
}
@@ -521,49 +527,36 @@ ServoRestyleManager::ProcessPostTraversa
if (!oldStyleContext) {
displayContentsNode =
PresContext()->FrameConstructor()->GetDisplayContentsNodeFor(aElement);
if (displayContentsNode) {
oldStyleContext = displayContentsNode->mStyle->AsServo();
}
}
- RefPtr<ServoComputedValues> computedValues =
- aRestyleState.StyleSet().ResolveServoStyle(aElement);
-
- // Note that we rely in the fact that we don't cascade pseudo-element styles
- // separately right now (that is, if a pseudo style changes, the normal style
- // changes too).
- //
- // Otherwise we should probably encode that information somehow to avoid
- // expensive checks in the common case.
- //
- // Also, we're going to need to check for pseudos of display: contents
- // elements, though that is buggy right now even in non-stylo mode, see
- // bug 1251799.
- const bool recreateContext = oldStyleContext &&
- oldStyleContext->ComputedValues() != computedValues;
-
Maybe<ServoRestyleState> thisFrameRestyleState;
if (styleFrame) {
auto type = isOutOfFlow
? ServoRestyleState::Type::OutOfFlow
: ServoRestyleState::Type::InFlow;
thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
}
// We can't really assume as used changes from display: contents elements (or
// other elements without frames).
ServoRestyleState& childrenRestyleState =
thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
RefPtr<ServoStyleContext> newContext = nullptr;
- if (recreateContext) {
+ if (wasRestyled && oldStyleContext) {
MOZ_ASSERT(styleFrame || displayContentsNode);
+ RefPtr<ServoComputedValues> computedValues =
+ aRestyleState.StyleSet().ResolveServoStyle(aElement);
+ MOZ_ASSERT(oldStyleContext->ComputedValues() != computedValues);
auto pseudo = aElement->GetPseudoElementType();
nsIAtom* pseudoTag = pseudo == CSSPseudoElementType::NotPseudo
? nullptr : nsCSSPseudoElements::GetPseudoAtom(pseudo);
newContext = aRestyleState.StyleSet().GetContext(
computedValues.forget(), aParentContext, pseudoTag, pseudo, aElement);
@@ -617,25 +610,25 @@ ServoRestyleManager::ProcessPostTraversa
const bool traverseElementChildren =
NeedsToTraverseElementChildren(*aElement, aRestyleBehavior);
const bool descendantsNeedFrames =
aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
const bool forThrottledAnimationFlush =
aRestyleBehavior == TraversalRestyleBehavior::ForThrottledAnimationFlush;
const bool traverseTextChildren =
- recreateContext || (!forThrottledAnimationFlush && descendantsNeedFrames);
- bool recreatedAnyContext = recreateContext;
+ wasRestyled || (!forThrottledAnimationFlush && descendantsNeedFrames);
+ bool recreatedAnyContext = wasRestyled;
if (traverseElementChildren || traverseTextChildren) {
nsStyleContext* upToDateContext =
- recreateContext ? newContext : oldStyleContext;
+ wasRestyled ? newContext : oldStyleContext;
StyleChildrenIterator it(aElement);
TextPostTraversalState textState(*upToDateContext,
- displayContentsNode && recreateContext,
+ displayContentsNode && wasRestyled,
childrenRestyleState);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (traverseElementChildren && n->IsElement()) {
recreatedAnyContext |= ProcessPostTraversal(n->AsElement(),
upToDateContext,
childrenRestyleState,
aRestyleBehavior);
} else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
@@ -643,17 +636,17 @@ ServoRestyleManager::ProcessPostTraversa
}
}
}
// We want to update frame pseudo-element styles after we've traversed our
// kids, because some of those updates (::first-line/::first-letter) need to
// modify the styles of the kids, and the child traversal above would just
// clobber those modifications.
- if (recreateContext && styleFrame) {
+ if (wasRestyled && styleFrame) {
UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
}
if (!forThrottledAnimationFlush) {
aElement->UnsetHasDirtyDescendantsForServo();
aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
}
aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -489,17 +489,18 @@ SERVO_BINDING_FUNC(Servo_Initialize, voi
SERVO_BINDING_FUNC(Servo_Shutdown, void)
// Restyle and change hints.
SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
nsRestyleHint restyle_hint, nsChangeHint change_hint)
SERVO_BINDING_FUNC(Servo_TakeChangeHint,
nsChangeHint,
RawGeckoElementBorrowed element,
- mozilla::TraversalRestyleBehavior restyle_behavior)
+ mozilla::TraversalRestyleBehavior restyle_behavior,
+ bool* was_restyled)
SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoComputedValuesStrong,
RawGeckoElementBorrowed element,
RawServoStyleSetBorrowed set)
SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoComputedValuesStrong,
RawGeckoElementBorrowed element,
mozilla::CSSPseudoElementType pseudo_type,
bool is_probe,
ServoComputedValuesBorrowedOrNull inherited_style,