Bug 1351535 - Part 6: Add ServoStyleSet::StyleSubtreeForReconstruct. r=bholley
MozReview-Commit-ID: CovU36o4lAV
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -209,23 +209,27 @@ ServoStyleSet::PreTraverseSync()
ResolveMappedAttrDeclarationBlocks();
// This is lazily computed and pseudo matching needs to access
// it so force computation early.
mPresContext->Document()->GetDocumentState();
}
void
-ServoStyleSet::PreTraverse()
+ServoStyleSet::PreTraverse(Element* aRoot)
{
PreTraverseSync();
// Process animation stuff that we should avoid doing during the parallel
// traversal.
- mPresContext->EffectCompositor()->PreTraverse();
+ if (aRoot) {
+ mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
+ } else {
+ mPresContext->EffectCompositor()->PreTraverse();
+ }
}
bool
ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
TraversalRootBehavior aRootBehavior,
TraversalRestyleBehavior
aRestyleBehavior)
{
@@ -233,37 +237,44 @@ ServoStyleSet::PrepareAndTraverseSubtree
// calling into the (potentially-parallel) Servo traversal, where a cache hit
// is necessary to avoid a data race when updating the cache.
mozilla::Unused << aRoot->OwnerDoc()->GetRootElement();
MOZ_ASSERT(!sInServoTraversal);
sInServoTraversal = true;
bool isInitial = !aRoot->HasServoData();
+ bool forReconstruct =
+ aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
bool postTraversalRequired =
Servo_TraverseSubtree(aRoot, mRawSet.get(), aRootBehavior, aRestyleBehavior);
- MOZ_ASSERT_IF(isInitial, !postTraversalRequired);
+ MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
+
+ auto root = const_cast<Element*>(aRoot);
// If there are still animation restyles needed, trigger a second traversal to
// update CSS animations' styles.
- if (mPresContext->EffectCompositor()->PreTraverse()) {
+ EffectCompositor* compositor = mPresContext->EffectCompositor();
+ if (forReconstruct ? compositor->PreTraverseInSubtree(root)
+ : compositor->PreTraverse()) {
if (Servo_TraverseSubtree(aRoot, mRawSet.get(),
aRootBehavior, aRestyleBehavior)) {
+ MOZ_ASSERT(!forReconstruct);
if (isInitial) {
// We're doing initial styling, and the additional animation
// traversal changed the styles that were set by the first traversal.
// This would normally require a post-traversal to update the style
// contexts, and the DOM now has dirty descendant bits and RestyleData
// in expectation of that post-traversal. But since this is actually
// the initial styling, there are no style contexts to update and no
// frames to apply the change hints to, so we don't need to do that
// post-traversal. Instead, just drop this state and tell the caller
// that no post-traversal is required.
MOZ_ASSERT(!postTraversalRequired);
- ServoRestyleManager::ClearRestyleStateFromSubtree(const_cast<Element*>(aRoot));
+ ServoRestyleManager::ClearRestyleStateFromSubtree(root);
} else {
postTraversalRequired = true;
}
}
}
sInServoTraversal = false;
return postTraversalRequired;
@@ -742,16 +753,28 @@ ServoStyleSet::StyleNewChildren(Element*
PrepareAndTraverseSubtree(aParent,
TraversalRootBehavior::UnstyledChildrenOnly,
TraversalRestyleBehavior::Normal);
// We can't assert that Servo_TraverseSubtree returns false, since aParent
// or some of its other children might have pending restyles.
}
void
+ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
+{
+ PreTraverse(aRoot);
+
+ DebugOnly<bool> postTraversalRequired =
+ PrepareAndTraverseSubtree(aRoot,
+ TraversalRootBehavior::Normal,
+ TraversalRestyleBehavior::ForReconstruct);
+ MOZ_ASSERT(!postTraversalRequired);
+}
+
+void
ServoStyleSet::NoteStyleSheetsChanged()
{
Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get());
}
#ifdef DEBUG
void
ServoStyleSet::AssertTreeIsClean()
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -232,16 +232,26 @@ public:
* Like the above, but skips the root node, and only styles unstyled children.
* When potentially appending multiple children, it's preferable to call
* StyleNewChildren on the node rather than making multiple calls to
* StyleNewSubtree on each child, since it allows for more parallelism.
*/
void StyleNewChildren(dom::Element* aParent);
/**
+ * Like StyleNewSubtree, but in response to a request to reconstruct frames
+ * for the given subtree, and so works on elements that already have
+ * styles. This will leave the subtree in a state just like after an initial
+ * styling, i.e. with new styles, no change hints, and with the dirty
+ * descendants bits cleared. No comparison of old and new styles is done,
+ * so no change hints will be processed.
+ */
+ void StyleSubtreeForReconstruct(dom::Element* aRoot);
+
+ /**
* Records that the contents of style sheets have changed since the last
* restyle. Calling this will ensure that the Stylist rebuilds its
* selector maps.
*/
void NoteStyleSheetsChanged();
#ifdef DEBUG
void AssertTreeIsClean();
@@ -309,18 +319,21 @@ private:
* Clear our cached mNonInheritingStyleContexts. We do this when we want to
* make sure those style contexts won't live too long (e.g. when rebuilding
* all style data or when shutting down the style set).
*/
void ClearNonInheritingStyleContexts();
/**
* Perform processes that we should do before traversing.
+ *
+ * When aRoot is null, the entire document is pre-traversed. Otherwise,
+ * only the subtree rooted at aRoot is pre-traversed.
*/
- void PreTraverse();
+ void PreTraverse(dom::Element* aRoot = nullptr);
// Subset of the pre-traverse steps that involve syncing up data
void PreTraverseSync();
already_AddRefed<ServoComputedValues> ResolveStyleLazily(dom::Element* aElement,
nsIAtom* aPseudoTag);
nsPresContext* mPresContext;
UniquePtr<RawServoStyleSet> mRawSet;