void ServoRestyleManager::ProcessPendingRestyles() { MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!"); MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!"); MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?"); 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; } // Create a AnimationsWithDestroyedFrame during restyling process to // stop animations and transitions on elements that have no frame at the end // of the restyling process. AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this); ServoStyleSet* styleSet = StyleSet(); nsIDocument* doc = PresContext()->Document(); // Ensure the refresh driver is active during traversal to avoid mutating // mActiveTimer and mMostRecentRefresh time. PresContext()->RefreshDriver()->MostRecentRefresh(); // Perform the Servo traversal, and the post-traversal if required. We do this // in a loop because certain rare paths in the frame constructor (like // uninstalling XBL bindings) can trigger additional style validations. mInStyleRefresh = true; if (mHaveNonAnimationRestyles) { ++mAnimationGeneration; } while (styleSet->StyleDocument()) { ClearSnapshots(); // Recreate style contexts, and queue up change hints (which also handle // lazy frame construction). nsStyleChangeList currentChanges(StyleBackendType::Servo); DocumentStyleRootIterator iter(doc); while (Element* root = iter.GetNextStyleRoot()) { ProcessPostTraversal(root, nullptr, styleSet, currentChanges); } // 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. ReentrantChangeList newChanges; mReentrantChanges = &newChanges; while (!currentChanges.IsEmpty()) { ProcessRestyledFrames(currentChanges); MOZ_ASSERT(currentChanges.IsEmpty()); for (ReentrantChange& change: newChanges) { currentChanges.AppendChange(change.mContent->GetPrimaryFrame(), change.mContent, change.mHint); } newChanges.Clear(); } mReentrantChanges = nullptr; IncrementRestyleGeneration(); } ClearSnapshots(); FlushOverflowChangedTracker(); mHaveNonAnimationRestyles = false; mInStyleRefresh = false; styleSet->AssertTreeIsClean(); // Note: We are in the scope of |animationsWithDestroyedFrame|, so // |mAnimationsWithDestroyedFrame| is still valid. MOZ_ASSERT(mAnimationsWithDestroyedFrame); mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames(); }
void 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(); nsIDocument* doc = PresContext()->Document(); // XXXbholley: Should this be while() per bug 1316247? if (HasPendingRestyles()) { mInStyleRefresh = true; styleSet->StyleDocument(); // First do any queued-up frame creation. (see bugs 827239 and 997506). // // XXXEmilio I'm calling this to avoid random behavior changes, since we // delay frame construction after styling we should re-check once our // model is more stable whether we can skip this call. // // Note this has to be *after* restyling, because otherwise frame // construction will find unstyled nodes, and that's not funny. PresContext()->FrameConstructor()->CreateNeededFrames(); // Recreate style contexts and queue up change hints. nsStyleChangeList currentChanges; DocumentStyleRootIterator iter(doc); while (Element* root = iter.GetNextStyleRoot()) { RecreateStyleContexts(root, nullptr, styleSet, currentChanges); } // 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. ReentrantChangeList newChanges; mReentrantChanges = &newChanges; while (!currentChanges.IsEmpty()) { ProcessRestyledFrames(currentChanges); MOZ_ASSERT(currentChanges.IsEmpty()); for (ReentrantChange& change: newChanges) { currentChanges.AppendChange(change.mContent->GetPrimaryFrame(), change.mContent, change.mHint); } newChanges.Clear(); } mReentrantChanges = nullptr; styleSet->AssertTreeIsClean(); mInStyleRefresh = false; } IncrementRestyleGeneration(); }