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->HasServoData()) { // This can happen with display:none. Bug 1297249 tracks more investigation // and assertions here. return; } // Style the new subtree because we will most likely need it during subsequent // frame construction. Bug 1298281 tracks deferring this work in the lazy // frame construction case. StyleSet()->StyleNewSubtree(aChild); RestyleForInsertOrChange(aContainer, aChild); }
void ServoRestyleManager::ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent) { if (!aContainer->HasServoData()) { // This can happen with display:none. Bug 1297249 tracks more investigation // and assertions here. return; } // Style the new subtree because we will most likely need it during subsequent // frame construction. Bug 1298281 tracks deferring this work in the lazy // frame construction case. if (aFirstNewContent->GetNextSibling()) { aContainer->SetHasDirtyDescendantsForServo(); StyleSet()->StyleNewChildren(aContainer); } else { StyleSet()->StyleNewSubtree(aFirstNewContent); } RestyleForAppend(aContainer, aFirstNewContent); }
void ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint) { StyleSet()->ClearDataAndMarkDeviceDirty(); if (Element* root = mPresContext->Document()->GetRootElement()) { PostRestyleEvent(root, aRestyleHint, aExtraHint); } // TODO(emilio, bz): Extensions can add/remove stylesheets that can affect // non-inheriting anon boxes. It's not clear if we want to support that, but // if we do, we need to re-selector-match them here. }
void ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint) { NS_WARNING("stylo: ServoRestyleManager::RebuildAllStyleData not implemented"); // That said, we do know that rebuilding all style data in Gecko would get rid // of the old ruletree, and hence of the cached-on-the-root default computed // styles. So we know we need to clear them here. I think this is the only // way they could get cleared, in fact, though not _all_ calls that come // through here may need to clear them in practice. // // We probably need to do some actual restyling here too, though. And figure // out whether it actually matters that we may be recomputing the default // styles in too many cases. For one thing, we do a bunch of eager work here, // whereas we should really just set a bit that says to recompute the default // computed styles before the next time we restyle anything! StyleSet()->RecomputeDefaultComputedStyles(); }
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(); Element* root = doc->GetRootElement(); if (root) { for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) { ServoElementSnapshot* snapshot = iter.UserData(); Element* element = iter.Key(); // TODO: avoid the ComputeRestyleHint call if we already have the highest // explicit restyle hint? nsRestyleHint hint = styleSet->ComputeRestyleHint(element, snapshot); hint |= snapshot->ExplicitRestyleHint(); if (hint) { NoteRestyleHint(element, hint); } } if (root->IsDirtyForServo() || root->HasDirtyDescendantsForServo()) { mInStyleRefresh = true; styleSet->StyleDocument(/* aLeaveDirtyBits = */ true); // 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(); nsStyleChangeList changeList; RecreateStyleContexts(root, nullptr, styleSet, changeList); ProcessRestyledFrames(changeList); mInStyleRefresh = false; } } MOZ_ASSERT(!doc->IsDirtyForServo()); doc->UnsetHasDirtyDescendantsForServo(); mModifiedElements.Clear(); IncrementRestyleGeneration(); }
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(); }