diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index 2d4e9f49bec4..84c6ffbf0679 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -1046,25 +1046,7 @@ ServoRestyleManager::SnapshotFor(Element* aElement) aElement->SetFlags(ELEMENT_HAS_SNAPSHOT); // Now that we have a snapshot, make sure a restyle is triggered. - // - // If we have any later siblings, we need to flag the restyle on the parent, - // so that a traversal from the restyle root is guaranteed to reach those - // siblings (since the snapshot may generate hints for later siblings). - if (aElement->GetNextElementSibling()) { - Element* parent = aElement->GetFlattenedTreeParentElementForStyle(); - MOZ_ASSERT(parent); - // The parent will only be outside of the composed doc if we're mid-unbind. - // - // FIXME(emilio): Make the traversal lazily mark the parent as dirty if - // needed to avoid this problem altogether, plus being better perf-wise. - if (parent->IsInComposedDoc()) { - parent->NoteDirtyForServo(); - parent->SetHasDirtyDescendantsForServo(); - } - } else { - aElement->NoteDirtyForServo(); - } - + aElement->NoteDirtyForServo(); return *snapshot; } diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index e376e0857fdb..c7c9fe42fbec 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -969,14 +969,30 @@ ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) // Do the first traversal. DocumentStyleRootIterator iter(doc->GetServoRestyleRoot()); while (Element* root = iter.GetNextStyleRoot()) { - MOZ_ASSERT(MayTraverseFrom(const_cast(root))); + MOZ_ASSERT(MayTraverseFrom(root)); - // If there were text nodes inserted into the document (but not elements), - // there may be lazy frame construction to do even if no styling is required. - postTraversalRequired |= root->HasFlag(NODE_DESCENDANTS_NEED_FRAMES); + Element* parent = root->GetFlattenedTreeParentElementForStyle(); + MOZ_ASSERT_IF(parent, + !parent->HasAnyOfFlags(Element::kAllServoDescendantBits)); - bool required = Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags); - postTraversalRequired |= required; + postTraversalRequired |= + Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags); + postTraversalRequired |= + root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME); + + if (parent) { + MOZ_ASSERT(root == doc->GetServoRestyleRoot()); + if (parent->HasDirtyDescendantsForServo()) { + // If any style invalidation was triggered in our siblings, then we may + // need to post-traverse them, even if the root wasn't restyled after + // all. + doc->SetServoRestyleRoot( + parent, + doc->GetServoRestyleRootDirtyBits() | + ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO); + postTraversalRequired = true; + } + } } // If there are still animation restyles needed, trigger a second traversal to @@ -995,8 +1011,10 @@ ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags) nsINode* styleRoot = doc->GetServoRestyleRoot(); Element* root = styleRoot->IsElement() ? styleRoot->AsElement() : rootElement; - bool required = Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags); - postTraversalRequired |= required; + postTraversalRequired |= + Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags); + postTraversalRequired |= + root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME); } return postTraversalRequired; @@ -1430,8 +1448,8 @@ ServoStyleSet::MaybeGCRuleTree() Servo_MaybeGCRuleTree(mRawSet.get()); } -bool -ServoStyleSet::MayTraverseFrom(Element* aElement) +/* static */ bool +ServoStyleSet::MayTraverseFrom(const Element* aElement) { MOZ_ASSERT(aElement->IsInComposedDoc()); Element* parent = aElement->GetFlattenedTreeParentElementForStyle(); diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index 622f90c45a40..9368e5ba331e 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -333,7 +333,7 @@ public: * * Most traversal callsites don't need to check this, but some do. */ - bool MayTraverseFrom(dom::Element* aElement); + static bool MayTraverseFrom(const dom::Element* aElement); #ifdef DEBUG void AssertTreeIsClean();