Bug 1371450 - Don't traverse normal dirty elements in ProcessPostTraversal when we process throttled animations restyle for event handling. r?emilio
When we process throttled animations restyle for event handling, we skip normal
traversal at all, so after Servo_TraverseSubtree, normally there remains
unstyled elements which have to be processed in normal traversal later. These
elements should be skipped in ProcessPostTraversal too since it's not yet styled!
MozReview-Commit-ID: LgyWQpiFZ8e
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -428,20 +428,37 @@ UpdateFramePseudoElementStyles(nsIFrame*
if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(aRestyleState);
}
UpdateBackdropIfNeeded(
aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
}
+static inline bool
+NeedsToTraverseElementChildren(const Element& aParent,
+ TraversalRestyleBehavior aRestyleBehavior)
+{
+ if (aParent.HasAnimationOnlyDirtyDescendantsForServo()) {
+ return true;
+ }
+
+ if (aRestyleBehavior != TraversalRestyleBehavior::ForThrottledAnimationFlush) {
+ return aParent.HasDirtyDescendantsForServo() ||
+ aParent.HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
+ }
+ return false;
+}
+
bool
-ServoRestyleManager::ProcessPostTraversal(Element* aElement,
- nsStyleContext* aParentContext,
- ServoRestyleState& aRestyleState)
+ServoRestyleManager::ProcessPostTraversal(
+ Element* aElement,
+ nsStyleContext* aParentContext,
+ ServoRestyleState& aRestyleState,
+ TraversalRestyleBehavior aRestyleBehavior)
{
nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
// NOTE(emilio): This is needed because for table frames the bit is set on the
// table wrapper (which is the primary frame), not on the table itself.
const bool isOutOfFlow =
aElement->GetPrimaryFrame() &&
aElement->GetPrimaryFrame()->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
@@ -590,53 +607,58 @@ ServoRestyleManager::ProcessPostTraversa
// We can sometimes reach this when the animated style is being removed.
// Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
// style or not, we need to call it *after* setting |newContext| to
// |styleFrame| to ensure the animated transform has been removed first.
AddLayerChangesForAnimation(
styleFrame, aElement, aRestyleState.ChangeList());
}
+ const bool traverseElementChildren =
+ NeedsToTraverseElementChildren(*aElement, aRestyleBehavior);
const bool descendantsNeedFrames =
aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
- const bool traverseElementChildren =
- aElement->HasDirtyDescendantsForServo() ||
- aElement->HasAnimationOnlyDirtyDescendantsForServo() ||
- descendantsNeedFrames;
- const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
+ const bool forThrottledAnimationFlush =
+ aRestyleBehavior == TraversalRestyleBehavior::ForThrottledAnimationFlush;
+ const bool traverseTextChildren =
+ recreateContext || (!forThrottledAnimationFlush && descendantsNeedFrames);
bool recreatedAnyContext = recreateContext;
if (traverseElementChildren || traverseTextChildren) {
nsStyleContext* upToDateContext =
recreateContext ? newContext : oldStyleContext;
StyleChildrenIterator it(aElement);
TextPostTraversalState textState(*upToDateContext,
displayContentsNode && recreateContext,
childrenRestyleState);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (traverseElementChildren && n->IsElement()) {
- recreatedAnyContext |= ProcessPostTraversal(
- n->AsElement(), upToDateContext, childrenRestyleState);
+ recreatedAnyContext |= ProcessPostTraversal(n->AsElement(),
+ upToDateContext,
+ childrenRestyleState,
+ aRestyleBehavior);
} else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
recreatedAnyContext |= ProcessPostTraversalForText(n, textState);
}
}
}
// 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) {
UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
}
- aElement->UnsetHasDirtyDescendantsForServo();
+ if (!forThrottledAnimationFlush) {
+ aElement->UnsetHasDirtyDescendantsForServo();
+ aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
+ }
aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
- aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
return recreatedAnyContext;
}
bool
ServoRestyleManager::ProcessPostTraversalForText(
nsIContent* aTextNode,
TextPostTraversalState& aPostTraversalState)
{
@@ -798,17 +820,21 @@ ServoRestyleManager::DoProcessPendingRes
// Recreate style contexts, and queue up change hints (which also handle
// lazy frame construction).
{
AutoRestyleTimelineMarker marker(
mPresContext->GetDocShell(), forThrottledAnimationFlush);
DocumentStyleRootIterator iter(doc);
while (Element* root = iter.GetNextStyleRoot()) {
ServoRestyleState state(*styleSet, currentChanges);
- anyStyleChanged |= ProcessPostTraversal(root, nullptr, state);
+ if (!forThrottledAnimationFlush ||
+ root->HasAnimationOnlyDirtyDescendantsForServo()) {
+ anyStyleChanged |=
+ ProcessPostTraversal(root, nullptr, state, aRestyleBehavior);
+ }
}
}
// Process the change hints.
//
// Unfortunately, the frame constructor can generate new change hints while
// processing existing ones. We redirect those into a secondary queue and
// iterate until there's nothing left.
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -185,17 +185,18 @@ private:
*
* Returns whether any style did actually change. There may be cases where we
* didn't need to change any style after all, for example, when a content
* attribute changes that happens not to have any effect on the style of that
* element or any descendant or sibling.
*/
bool ProcessPostTraversal(Element* aElement,
nsStyleContext* aParentContext,
- ServoRestyleState& aRestyleState);
+ ServoRestyleState& aRestyleState,
+ TraversalRestyleBehavior aRestyleBehavior);
struct TextPostTraversalState;
bool ProcessPostTraversalForText(nsIContent* aTextNode,
TextPostTraversalState& aState);
inline ServoStyleSet* StyleSet() const
{
MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),