void ServoRestyleManager::PostRestyleEvent(Element* aElement, nsRestyleHint aRestyleHint, nsChangeHint aMinChangeHint) { if (MOZ_UNLIKELY(IsDisconnected()) || MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) { return; } if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) { return; // Nothing to do. } // XXX This is a temporary hack to make style attribute change works. // In the future, we should be able to use this hint directly. if (aRestyleHint & eRestyle_StyleAttribute) { aRestyleHint |= eRestyle_Subtree; } // Note that unlike in Servo, we don't mark elements as dirty until we process // the restyle hints in ProcessPendingRestyles. if (aRestyleHint || aMinChangeHint) { ServoElementSnapshot* snapshot = SnapshotForElement(aElement); snapshot->AddExplicitRestyleHint(aRestyleHint); snapshot->AddExplicitChangeHint(aMinChangeHint); } PostRestyleEventInternal(false); }
void ServoRestyleManager::PostRestyleEvent(Element* aElement, nsRestyleHint aRestyleHint, nsChangeHint aMinChangeHint) { if (MOZ_UNLIKELY(IsDisconnected()) || MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) { return; } if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) { return; // Nothing to do. } // We allow posting change hints during restyling, but not restyle hints // themselves, since those would require us to re-traverse the tree. MOZ_ASSERT_IF(mInStyleRefresh, aRestyleHint == 0); // Processing change hints sometimes causes new change hints to be generated. // Doing this after the gecko post-traversal is problematic, so instead we just // queue them up for special handling. if (mReentrantChanges) { MOZ_ASSERT(aRestyleHint == 0); mReentrantChanges->AppendElement(ReentrantChange { aElement, aMinChangeHint }); return; } // XXX This is a temporary hack to make style attribute change works. // In the future, we should be able to use this hint directly. if (aRestyleHint & eRestyle_StyleAttribute) { aRestyleHint &= ~eRestyle_StyleAttribute; aRestyleHint |= eRestyle_Self | eRestyle_Subtree; } // XXX For now, convert eRestyle_Subtree into (eRestyle_Self | // eRestyle_SomeDescendants), which Servo will interpret as // RESTYLE_SELF | RESTYLE_DESCENDANTS, since this is a commonly // posted restyle hint that doesn't yet align with RestyleHint's // bits. if (aRestyleHint & eRestyle_Subtree) { aRestyleHint &= ~eRestyle_Subtree; aRestyleHint |= eRestyle_Self | eRestyle_SomeDescendants; } if (aRestyleHint || aMinChangeHint) { Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint); } PostRestyleEventInternal(false); }
void ServoRestyleManager::PostRestyleEvent(Element* aElement, nsRestyleHint aRestyleHint, nsChangeHint aMinChangeHint) { if (MOZ_UNLIKELY(IsDisconnected()) || MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) { return; } if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) { return; // Nothing to do. } // Note that unlike in Servo, we don't mark elements as dirty until we process // the restyle hints in ProcessPendingRestyles. if (aRestyleHint || aMinChangeHint) { ServoElementSnapshot* snapshot = SnapshotForElement(aElement); snapshot->AddExplicitRestyleHint(aRestyleHint); snapshot->AddExplicitChangeHint(aMinChangeHint); } PostRestyleEventInternal(false); }
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(); }