diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index 08652ec6ac63..47362bd19771 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -280,17 +280,21 @@ ServoRestyleManager::ProcessPendingRestyles() { MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!"); MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!"); + + if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) { + // PresShell::FlushPendingNotifications doesn't early-return in the case + // where the PreShell hasn't yet been initialized (and therefore we haven't + // yet done the initial style traversal of the DOM tree). We should arguably + // fix up the callers and assert against this case, but we just detect and + // handle it for now. + return; + } + if (!HasPendingRestyles()) { return; } ServoStyleSet* styleSet = StyleSet(); - if (!styleSet->StylingStarted()) { - // If something caused us to restyle, and we haven't started styling yet, - // do nothing. Everything is dirty, and we'll style it all later. - return; - } - nsIDocument* doc = PresContext()->Document(); Element* root = doc->GetRootElement(); if (root) { @@ -331,7 +335,7 @@ ServoRestyleManager::ProcessPendingRestyles() } MOZ_ASSERT(!doc->IsDirtyForServo()); - MOZ_ASSERT(!doc->HasDirtyDescendantsForServo()); + doc->UnsetHasDirtyDescendantsForServo(); mModifiedElements.Clear(); @@ -354,6 +358,20 @@ ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer, void ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild) { + if (aContainer == aContainer->OwnerDoc()) { + // If we're getting this notification for the insertion of a root element, + // that means either: + // (a) We initialized the PresShell before the root element existed, or + // (b) The root element was removed and it or another root is being + // inserted. + // + // Either way the whole tree is dirty, so we should style the document. + MOZ_ASSERT(aChild == aChild->OwnerDoc()->GetRootElement()); + MOZ_ASSERT(aChild->IsDirtyForServo()); + StyleSet()->StyleDocument(/* aLeaveDirtyBits = */ false); + return; + } + if (!aContainer->ServoData().get()) { // This can happen with display:none. Bug 1297249 tracks more investigation // and assertions here. diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index f97378067f12..6f76d4c5ff0e 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1682,8 +1682,15 @@ PresShell::Initialize(nscoord aWidth, nscoord aHeight) mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight)); - if (mStyleSet->IsServo()) { - mStyleSet->AsServo()->StartStyling(GetPresContext()); + if (mStyleSet->IsServo() && mDocument->GetRootElement()) { + // If we have the root element already, go ahead style it along with any + // descendants. + // + // Some things, like nsDocumentViewer::GetPageMode, recreate the PresShell + // while keeping the content tree alive (see bug 1292280) - so we + // unconditionally mark the root as dirty. + mDocument->GetRootElement()->SetIsDirtyForServo(); + mStyleSet->AsServo()->StyleDocument(/* aLeaveDirtyBits = */ false); } // Get the root frame from the frame manager diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 5f0ab284292d..d6b321376837 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -22,7 +22,6 @@ ServoStyleSet::ServoStyleSet() : mPresContext(nullptr) , mRawSet(Servo_StyleSet_Init()) , mBatching(0) - , mStylingStarted(false) { } @@ -73,24 +72,6 @@ ServoStyleSet::EndUpdate() return NS_OK; } -void -ServoStyleSet::StartStyling(nsPresContext* aPresContext) -{ - MOZ_ASSERT(!mStylingStarted); - - // Some things, like nsDocumentViewer::GetPageMode, recreate the presShell, - // while keeping the content tree alive. See bug 1292280. - // - // That's why we need to force a restyle. - nsIContent* root = mPresContext->Document()->GetRootElement(); - if (root) { - root->SetIsDirtyForServo(); - } - - StyleDocument(/* aLeaveDirtyBits = */ false); - mStylingStarted = true; -} - already_AddRefed ServoStyleSet::ResolveStyleFor(Element* aElement, nsStyleContext* aParentContext) @@ -484,21 +465,16 @@ ClearDirtyBits(nsIContent* aContent) void ServoStyleSet::StyleDocument(bool aLeaveDirtyBits) { - // Unconditionally clear the flag on the document so that HasPendingRestyles - // returns false. - nsIDocument* doc = mPresContext->Document(); - doc->UnsetHasDirtyDescendantsForServo(); - // Grab the root. - nsIContent* root = mPresContext->Document()->GetRootElement(); - if (!root) { - return; - } + nsIDocument* doc = mPresContext->Document(); + nsIContent* root = doc->GetRootElement(); + MOZ_ASSERT(root); // Restyle the document, clearing the dirty bits if requested. Servo_RestyleSubtree(root, mRawSet.get()); if (!aLeaveDirtyBits) { ClearDirtyBits(root); + doc->UnsetHasDirtyDescendantsForServo(); } } diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index 6fb17b27c2c1..031b471cd634 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -55,8 +55,6 @@ public: void BeginUpdate(); nsresult EndUpdate(); - void StartStyling(nsPresContext* aPresContext); - already_AddRefed ResolveStyleFor(dom::Element* aElement, nsStyleContext* aParentContext); @@ -128,7 +126,7 @@ public: /** * Performs a Servo traversal to compute style for all dirty nodes in the - * document. + * document. The root element must be non-null. * * If aLeaveDirtyBits is true, the dirty/dirty-descendant bits are not * cleared. @@ -155,8 +153,6 @@ public: */ void StyleNewChildren(nsIContent* aParent); - bool StylingStarted() const { return mStylingStarted; } - private: already_AddRefed GetContext(already_AddRefed, nsStyleContext* aParentContext, @@ -173,7 +169,6 @@ private: EnumeratedArray>> mSheets; int32_t mBatching; - bool mStylingStarted; }; } // namespace mozilla