LCOV - code coverage report
Current view: top level - layout/base - ServoRestyleManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 435 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 39 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/ServoRestyleManager.h"
       8             : 
       9             : #include "mozilla/AutoRestyleTimelineMarker.h"
      10             : #include "mozilla/AutoTimelineMarker.h"
      11             : #include "mozilla/DocumentStyleRootIterator.h"
      12             : #include "mozilla/ServoBindings.h"
      13             : #include "mozilla/ServoStyleSet.h"
      14             : #include "mozilla/Unused.h"
      15             : #include "mozilla/ViewportFrame.h"
      16             : #include "mozilla/dom/ChildIterator.h"
      17             : #include "mozilla/dom/ElementInlines.h"
      18             : #include "nsBlockFrame.h"
      19             : #include "nsBulletFrame.h"
      20             : #include "nsPlaceholderFrame.h"
      21             : #include "nsContentUtils.h"
      22             : #include "nsCSSFrameConstructor.h"
      23             : #include "nsPrintfCString.h"
      24             : #include "nsRefreshDriver.h"
      25             : #include "nsStyleChangeList.h"
      26             : 
      27             : using namespace mozilla::dom;
      28             : 
      29             : namespace mozilla {
      30             : 
      31             : #ifdef DEBUG
      32             : static bool
      33           0 : IsAnonBox(const nsIFrame& aFrame)
      34             : {
      35           0 :   return aFrame.StyleContext()->IsAnonBox();
      36             : }
      37             : 
      38             : static const nsIFrame*
      39           0 : FirstContinuationOrPartOfIBSplit(const nsIFrame* aFrame)
      40             : {
      41           0 :   if (!aFrame) {
      42           0 :     return nullptr;
      43             :   }
      44             : 
      45           0 :   return nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
      46             : }
      47             : 
      48             : static const nsIFrame*
      49           0 : ExpectedOwnerForChild(const nsIFrame& aFrame)
      50             : {
      51           0 :   if (IsAnonBox(aFrame)) {
      52           0 :     return aFrame.GetParent()->IsViewportFrame() ? nullptr : aFrame.GetParent();
      53             :   }
      54             : 
      55           0 :   if (aFrame.IsBulletFrame()) {
      56           0 :     return aFrame.GetParent();
      57             :   }
      58             : 
      59           0 :   const nsIFrame* parent = FirstContinuationOrPartOfIBSplit(aFrame.GetParent());
      60             : 
      61           0 :   if (aFrame.IsTableFrame()) {
      62           0 :     MOZ_ASSERT(parent->IsTableWrapperFrame());
      63           0 :     parent = FirstContinuationOrPartOfIBSplit(parent->GetParent());
      64             :   }
      65             : 
      66             :   // We've handled already anon boxes and bullet frames, so now we're looking at
      67             :   // a frame of a DOM element or pseudo. Hop through anon and line-boxes
      68             :   // generated by our DOM parent, and go find the owner frame for it.
      69           0 :   while (parent && (IsAnonBox(*parent) || parent->IsLineFrame())) {
      70           0 :     auto* pseudo = parent->StyleContext()->GetPseudo();
      71           0 :     if (pseudo == nsCSSAnonBoxes::tableWrapper) {
      72           0 :       const nsIFrame* tableFrame = parent->PrincipalChildList().FirstChild();
      73           0 :       MOZ_ASSERT(tableFrame->IsTableFrame());
      74             :       // Handle :-moz-table and :-moz-inline-table.
      75           0 :       parent = IsAnonBox(*tableFrame) ? parent->GetParent() : tableFrame;
      76             :     } else {
      77           0 :       parent = parent->GetParent();
      78             :     }
      79           0 :     parent = FirstContinuationOrPartOfIBSplit(parent);
      80             :   }
      81             : 
      82           0 :   return parent;
      83             : }
      84             : 
      85             : void
      86           0 : ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const
      87             : {
      88           0 :   MOZ_ASSERT(mOwner);
      89           0 :   MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
      90           0 :   MOZ_ASSERT(ExpectedOwnerForChild(*mOwner) == aParent.mOwner);
      91           0 : }
      92             : 
      93             : nsChangeHint
      94           0 : ServoRestyleState::ChangesHandledFor(const nsIFrame& aFrame) const
      95             : {
      96           0 :   if (!mOwner) {
      97           0 :     MOZ_ASSERT(!mChangesHandled);
      98           0 :     return mChangesHandled;
      99             :   }
     100             : 
     101           0 :   MOZ_ASSERT(mOwner == ExpectedOwnerForChild(aFrame),
     102             :              "Missed some frame in the hierarchy?");
     103           0 :   return mChangesHandled;
     104             : }
     105             : #endif
     106             : 
     107           0 : ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
     108             :   : RestyleManager(StyleBackendType::Servo, aPresContext)
     109           0 :   , mReentrantChanges(nullptr)
     110             : {
     111           0 : }
     112             : 
     113             : void
     114           0 : ServoRestyleManager::PostRestyleEvent(Element* aElement,
     115             :                                       nsRestyleHint aRestyleHint,
     116             :                                       nsChangeHint aMinChangeHint)
     117             : {
     118           0 :   MOZ_ASSERT(!(aMinChangeHint & nsChangeHint_NeutralChange),
     119             :              "Didn't expect explicit change hints to be neutral!");
     120           0 :   if (MOZ_UNLIKELY(IsDisconnected()) ||
     121           0 :       MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
     122           0 :     return;
     123             :   }
     124             : 
     125             :   // We allow posting restyles from within change hint handling, but not from
     126             :   // within the restyle algorithm itself.
     127           0 :   MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
     128             : 
     129           0 :   if (aRestyleHint == 0 && !aMinChangeHint) {
     130           0 :     return; // Nothing to do.
     131             :   }
     132             : 
     133             :   // Assuming the restyle hints will invalidate cached style for
     134             :   // getComputedStyle, since we don't know if any of the restyling that we do
     135             :   // would affect undisplayed elements.
     136           0 :   if (aRestyleHint) {
     137           0 :     IncrementUndisplayedRestyleGeneration();
     138             :   }
     139             : 
     140             :   // Processing change hints sometimes causes new change hints to be generated,
     141             :   // and very occasionally, additional restyle hints. We collect the change
     142             :   // hints manually to avoid re-traversing the DOM to find them.
     143           0 :   if (mReentrantChanges && !aRestyleHint) {
     144           0 :     mReentrantChanges->AppendElement(ReentrantChange { aElement, aMinChangeHint });
     145           0 :     return;
     146             :   }
     147             : 
     148           0 :   if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
     149           0 :     mHaveNonAnimationRestyles = true;
     150             :   }
     151             : 
     152           0 :   if (aRestyleHint & eRestyle_LaterSiblings) {
     153           0 :     aRestyleHint &= ~eRestyle_LaterSiblings;
     154             : 
     155           0 :     nsRestyleHint siblingHint = eRestyle_Subtree;
     156           0 :     Element* current = aElement->GetNextElementSibling();
     157           0 :     while (current) {
     158           0 :       Servo_NoteExplicitHints(current, siblingHint, nsChangeHint(0));
     159           0 :       current = current->GetNextElementSibling();
     160             :     }
     161             :   }
     162             : 
     163           0 :   if (aRestyleHint || aMinChangeHint) {
     164           0 :     Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
     165             :   }
     166             : }
     167             : 
     168             : void
     169           0 : ServoRestyleManager::PostRestyleEventForCSSRuleChanges()
     170             : {
     171           0 :   mRestyleForCSSRuleChanges = true;
     172           0 :   mPresContext->PresShell()->EnsureStyleFlush();
     173           0 : }
     174             : 
     175             : /* static */ void
     176           0 : ServoRestyleManager::PostRestyleEventForAnimations(
     177             :   Element* aElement,
     178             :   CSSPseudoElementType aPseudoType,
     179             :   nsRestyleHint aRestyleHint)
     180             : {
     181             :   Element* elementToRestyle =
     182           0 :     EffectCompositor::GetElementToRestyle(aElement, aPseudoType);
     183             : 
     184           0 :   if (!elementToRestyle) {
     185             :     // FIXME: Bug 1371107: When reframing happens,
     186             :     // EffectCompositor::mElementsToRestyle still has unbinded old pseudo
     187             :     // element. We should drop it.
     188           0 :     return;
     189             :   }
     190             : 
     191           0 :   Servo_NoteExplicitHints(elementToRestyle, aRestyleHint, nsChangeHint(0));
     192             : }
     193             : 
     194             : void
     195           0 : ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
     196             :                                          nsRestyleHint aRestyleHint)
     197             : {
     198             :    // NOTE(emilio): GeckoRestlyeManager does a sync style flush, which seems not
     199             :    // to be needed in my testing.
     200           0 :   PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
     201           0 : }
     202             : 
     203             : void
     204           0 : ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
     205             :                                                   nsRestyleHint aRestyleHint)
     206             : {
     207           0 :   StyleSet()->ClearDataAndMarkDeviceDirty();
     208             : 
     209           0 :   DocumentStyleRootIterator iter(mPresContext->Document());
     210           0 :   while (Element* root = iter.GetNextStyleRoot()) {
     211           0 :     PostRestyleEvent(root, aRestyleHint, aExtraHint);
     212           0 :   }
     213             : 
     214             :   // TODO(emilio, bz): Extensions can add/remove stylesheets that can affect
     215             :   // non-inheriting anon boxes. It's not clear if we want to support that, but
     216             :   // if we do, we need to re-selector-match them here.
     217           0 : }
     218             : 
     219             : /* static */ void
     220           0 : ServoRestyleManager::ClearServoDataFromSubtree(Element* aElement)
     221             : {
     222           0 :   if (!aElement->HasServoData()) {
     223           0 :     MOZ_ASSERT(!aElement->HasDirtyDescendantsForServo());
     224           0 :     MOZ_ASSERT(!aElement->HasAnimationOnlyDirtyDescendantsForServo());
     225           0 :     return;
     226             :   }
     227             : 
     228           0 :   StyleChildrenIterator it(aElement);
     229           0 :   for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
     230           0 :     if (n->IsElement()) {
     231           0 :       ClearServoDataFromSubtree(n->AsElement());
     232             :     }
     233             :   }
     234             : 
     235           0 :   aElement->ClearServoData();
     236           0 :   aElement->UnsetHasDirtyDescendantsForServo();
     237           0 :   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
     238             : }
     239             : 
     240             : /* static */ void
     241           0 : ServoRestyleManager::ClearRestyleStateFromSubtree(Element* aElement)
     242             : {
     243           0 :   if (aElement->HasDirtyDescendantsForServo() ||
     244           0 :       aElement->HasAnimationOnlyDirtyDescendantsForServo()) {
     245           0 :     StyleChildrenIterator it(aElement);
     246           0 :     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
     247           0 :       if (n->IsElement()) {
     248           0 :         ClearRestyleStateFromSubtree(n->AsElement());
     249             :       }
     250             :     }
     251             :   }
     252             : 
     253           0 :   Unused << Servo_TakeChangeHint(aElement);
     254           0 :   aElement->UnsetHasDirtyDescendantsForServo();
     255           0 :   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
     256           0 :   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
     257           0 : }
     258             : 
     259             : /**
     260             :  * This struct takes care of encapsulating some common state that text nodes may
     261             :  * need to track during the post-traversal.
     262             :  *
     263             :  * This is currently used to properly compute change hints when the parent
     264             :  * element of this node is a display: contents node, and also to avoid computing
     265             :  * the style for text children more than once per element.
     266             :  */
     267           0 : struct ServoRestyleManager::TextPostTraversalState
     268             : {
     269             : public:
     270           0 :   TextPostTraversalState(nsStyleContext& aParentContext,
     271             :                          bool aDisplayContentsParentStyleChanged,
     272             :                          ServoRestyleState& aParentRestyleState)
     273           0 :     : mParentContext(aParentContext)
     274             :     , mParentRestyleState(aParentRestyleState)
     275             :     , mStyle(nullptr)
     276             :     , mShouldPostHints(aDisplayContentsParentStyleChanged)
     277             :     , mShouldComputeHints(aDisplayContentsParentStyleChanged)
     278           0 :     , mComputedHint(nsChangeHint_Empty)
     279           0 :   {}
     280             : 
     281           0 :   nsStyleChangeList& ChangeList() { return mParentRestyleState.ChangeList(); }
     282             : 
     283           0 :   nsStyleContext& ComputeStyle(nsIContent* aTextNode)
     284             :   {
     285           0 :     if (!mStyle) {
     286           0 :       mStyle = mParentRestyleState.StyleSet().ResolveStyleForText(
     287           0 :         aTextNode, &mParentContext);
     288             :     }
     289           0 :     MOZ_ASSERT(mStyle);
     290           0 :     return *mStyle;
     291             :   }
     292             : 
     293           0 :   void ComputeHintIfNeeded(nsIContent* aContent,
     294             :                            nsIFrame* aTextFrame,
     295             :                            nsStyleContext& aNewContext)
     296             :   {
     297           0 :     MOZ_ASSERT(aTextFrame);
     298           0 :     MOZ_ASSERT(aNewContext.GetPseudo() == nsCSSAnonBoxes::mozText);
     299             : 
     300           0 :     if (MOZ_LIKELY(!mShouldPostHints)) {
     301           0 :       return;
     302             :     }
     303             : 
     304           0 :     nsStyleContext* oldContext = aTextFrame->StyleContext();
     305           0 :     MOZ_ASSERT(oldContext->GetPseudo() == nsCSSAnonBoxes::mozText);
     306             : 
     307             :     // We rely on the fact that all the text children for the same element share
     308             :     // style to avoid recomputing style differences for all of them.
     309             :     //
     310             :     // TODO(emilio): The above may not be true for ::first-{line,letter}, but
     311             :     // we'll cross that bridge when we support those in stylo.
     312           0 :     if (mShouldComputeHints) {
     313           0 :       mShouldComputeHints = false;
     314             :       uint32_t equalStructs, samePointerStructs;
     315           0 :       mComputedHint =
     316           0 :         oldContext->CalcStyleDifference(&aNewContext,
     317             :                                         &equalStructs,
     318             :                                         &samePointerStructs);
     319           0 :       mComputedHint = NS_RemoveSubsumedHints(
     320           0 :         mComputedHint, mParentRestyleState.ChangesHandledFor(*aTextFrame));
     321             :     }
     322             : 
     323           0 :     if (mComputedHint) {
     324           0 :       mParentRestyleState.ChangeList().AppendChange(
     325           0 :         aTextFrame, aContent, mComputedHint);
     326             :     }
     327             :   }
     328             : 
     329             : private:
     330             :   nsStyleContext& mParentContext;
     331             :   ServoRestyleState& mParentRestyleState;
     332             :   RefPtr<nsStyleContext> mStyle;
     333             :   bool mShouldPostHints;
     334             :   bool mShouldComputeHints;
     335             :   nsChangeHint mComputedHint;
     336             : };
     337             : 
     338             : // Find the first-letter frame for the given element, if any.  Returns null to
     339             : // indicate there isn't one.
     340             : static nsIFrame*
     341           0 : FindFirstLetterFrameForElement(const Element* aElement)
     342             : {
     343           0 :   nsIFrame* frame = aElement->GetPrimaryFrame();
     344           0 :   if (!frame) {
     345           0 :     return nullptr;
     346             :   }
     347             :   // The first-letter frame will always be inside the content insertion frame,
     348             :   // which will always be a block if we have a first-letter frame at all.
     349           0 :   frame = frame->GetContentInsertionFrame();
     350           0 :   if (!frame) {
     351             :     // We're a leaf; certainly no first-letter frame.
     352           0 :     return nullptr;
     353             :   }
     354             : 
     355           0 :   if (!frame->IsFrameOfType(nsIFrame::eBlockFrame)) {
     356           0 :     return nullptr;
     357             :   }
     358             : 
     359           0 :   return static_cast<nsBlockFrame*>(frame)->GetFirstLetter();
     360             : }
     361             : 
     362             : static void
     363           0 : UpdateBackdropIfNeeded(nsIFrame* aFrame,
     364             :                        ServoStyleSet& aStyleSet,
     365             :                        nsStyleChangeList& aChangeList)
     366             : {
     367           0 :   const nsStyleDisplay* display = aFrame->StyleContext()->StyleDisplay();
     368           0 :   if (display->mTopLayer != NS_STYLE_TOP_LAYER_TOP) {
     369           0 :     return;
     370             :   }
     371             : 
     372             :   // Elements in the top layer are guaranteed to have absolute or fixed
     373             :   // position per https://fullscreen.spec.whatwg.org/#new-stacking-layer.
     374           0 :   MOZ_ASSERT(display->IsAbsolutelyPositionedStyle());
     375             : 
     376             :   nsIFrame* backdropPlaceholder =
     377           0 :     aFrame->GetChildList(nsIFrame::kBackdropList).FirstChild();
     378           0 :   if (!backdropPlaceholder) {
     379           0 :     return;
     380             :   }
     381             : 
     382           0 :   MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame());
     383             :   nsIFrame* backdropFrame =
     384           0 :     nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder);
     385           0 :   MOZ_ASSERT(backdropFrame->IsBackdropFrame());
     386           0 :   MOZ_ASSERT(backdropFrame->StyleContext()->GetPseudoType() ==
     387             :              CSSPseudoElementType::backdrop);
     388             : 
     389             :   RefPtr<nsStyleContext> newContext =
     390           0 :     aStyleSet.ResolvePseudoElementStyle(aFrame->GetContent()->AsElement(),
     391             :                                         CSSPseudoElementType::backdrop,
     392             :                                         aFrame->StyleContext(),
     393           0 :                                         /* aPseudoElement = */ nullptr);
     394             : 
     395             :   // NOTE(emilio): We can't use the changes handled for the owner of the
     396             :   // backdrop frame, since it's out of flow, and parented to the viewport frame.
     397           0 :   MOZ_ASSERT(backdropFrame->GetParent()->IsViewportFrame());
     398           0 :   ServoRestyleState state(aStyleSet, aChangeList);
     399           0 :   aFrame->UpdateStyleOfOwnedChildFrame(backdropFrame, newContext, state);
     400             : }
     401             : 
     402             : static void
     403           0 : UpdateFirstLetterIfNeeded(nsIFrame* aFrame, ServoRestyleState& aRestyleState)
     404             : {
     405           0 :   if (!aFrame->HasFirstLetterChild()) {
     406           0 :     return;
     407             :   }
     408             : 
     409             :   // We need to find the block the first-letter is associated with so we can
     410             :   // find the right element for the first-letter's style resolution.  Might as
     411             :   // well just delegate the whole thing to that block.
     412           0 :   nsIFrame* block = aFrame;
     413           0 :   while (!block->IsFrameOfType(nsIFrame::eBlockFrame)) {
     414           0 :     block = block->GetParent();
     415             :   }
     416           0 :   static_cast<nsBlockFrame*>(block->FirstContinuation())->
     417           0 :     UpdateFirstLetterStyle(aRestyleState);
     418             : }
     419             : 
     420             : static void
     421           0 : UpdateFramePseudoElementStyles(nsIFrame* aFrame,
     422             :                                ServoRestyleState& aRestyleState)
     423             : {
     424             :   // first-letter needs to be updated before first-line, because first-line can
     425             :   // change the style of the first-letter.
     426           0 :   UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
     427             : 
     428           0 :   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
     429           0 :     static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(aRestyleState);
     430             :   }
     431             : 
     432           0 :   UpdateBackdropIfNeeded(
     433           0 :     aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
     434           0 : }
     435             : 
     436             : bool
     437           0 : ServoRestyleManager::ProcessPostTraversal(Element* aElement,
     438             :                                           nsStyleContext* aParentContext,
     439             :                                           ServoRestyleState& aRestyleState)
     440             : {
     441           0 :   nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
     442             : 
     443             :   // NOTE(emilio): This is needed because for table frames the bit is set on the
     444             :   // table wrapper (which is the primary frame), not on the table itself.
     445             :   const bool isOutOfFlow =
     446           0 :     aElement->GetPrimaryFrame() &&
     447           0 :     aElement->GetPrimaryFrame()->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
     448             : 
     449             :   // Grab the change hint from Servo.
     450           0 :   nsChangeHint changeHint = Servo_TakeChangeHint(aElement);
     451             : 
     452             :   // We should really fix the weird primary frame mapping for image maps
     453             :   // (bug 135040)...
     454           0 :   if (styleFrame && styleFrame->GetContent() != aElement) {
     455           0 :     MOZ_ASSERT(styleFrame->IsImageFrame());
     456           0 :     styleFrame = nullptr;
     457             :   }
     458             : 
     459             :   // Handle lazy frame construction by posting a reconstruct for any lazily-
     460             :   // constructed roots.
     461           0 :   if (aElement->HasFlag(NODE_NEEDS_FRAME)) {
     462           0 :     changeHint |= nsChangeHint_ReconstructFrame;
     463           0 :     MOZ_ASSERT(!styleFrame);
     464             :   }
     465             : 
     466           0 :   if (styleFrame && !isOutOfFlow) {
     467           0 :     changeHint = NS_RemoveSubsumedHints(
     468             :       changeHint, aRestyleState.ChangesHandledFor(*styleFrame));
     469             :   }
     470             : 
     471             :   // Although we shouldn't generate non-ReconstructFrame hints for elements with
     472             :   // no frames, we can still get them here if they were explicitly posted by
     473             :   // PostRestyleEvent, such as a RepaintFrame hint when a :link changes to be
     474             :   // :visited.  Skip processing these hints if there is no frame.
     475           0 :   if ((styleFrame || (changeHint & nsChangeHint_ReconstructFrame)) && changeHint) {
     476           0 :     aRestyleState.ChangeList().AppendChange(styleFrame, aElement, changeHint);
     477             :   }
     478             : 
     479             :   // If our change hint is reconstruct, we delegate to the frame constructor,
     480             :   // which consumes the new style and expects the old style to be on the frame.
     481             :   //
     482             :   // XXXbholley: We should teach the frame constructor how to clear the dirty
     483             :   // descendants bit to avoid the traversal here.
     484           0 :   if (changeHint & nsChangeHint_ReconstructFrame) {
     485           0 :     ClearRestyleStateFromSubtree(aElement);
     486           0 :     return true;
     487             :   }
     488             : 
     489             :   // TODO(emilio): We could avoid some refcount traffic here, specially in the
     490             :   // ServoComputedValues case, which uses atomic refcounting.
     491             :   //
     492             :   // Hold the old style context alive, because it could become a dangling
     493             :   // pointer during the replacement. In practice it's not a huge deal, but
     494             :   // better not playing with dangling pointers if not needed.
     495             :   RefPtr<ServoStyleContext> oldStyleContext =
     496           0 :     styleFrame ? styleFrame->StyleContext()->AsServo() : nullptr;
     497             : 
     498           0 :   UndisplayedNode* displayContentsNode = nullptr;
     499             :   // FIXME(emilio, bug 1303605): This can be simpler for Servo.
     500             :   // Note that we intentionally don't check for display: none content.
     501           0 :   if (!oldStyleContext) {
     502             :     displayContentsNode =
     503           0 :       PresContext()->FrameConstructor()->GetDisplayContentsNodeFor(aElement);
     504           0 :     if (displayContentsNode) {
     505           0 :       oldStyleContext = displayContentsNode->mStyle->AsServo();
     506             :     }
     507             :   }
     508             : 
     509             :   RefPtr<ServoComputedValues> computedValues =
     510           0 :     aRestyleState.StyleSet().ResolveServoStyle(aElement);
     511             : 
     512             :   // Note that we rely in the fact that we don't cascade pseudo-element styles
     513             :   // separately right now (that is, if a pseudo style changes, the normal style
     514             :   // changes too).
     515             :   //
     516             :   // Otherwise we should probably encode that information somehow to avoid
     517             :   // expensive checks in the common case.
     518             :   //
     519             :   // Also, we're going to need to check for pseudos of display: contents
     520             :   // elements, though that is buggy right now even in non-stylo mode, see
     521             :   // bug 1251799.
     522           0 :   const bool recreateContext = oldStyleContext &&
     523           0 :     oldStyleContext->ComputedValues() != computedValues;
     524             : 
     525           0 :   Maybe<ServoRestyleState> thisFrameRestyleState;
     526           0 :   if (styleFrame) {
     527             :     auto type = isOutOfFlow
     528           0 :       ? ServoRestyleState::Type::OutOfFlow
     529           0 :       : ServoRestyleState::Type::InFlow;
     530             : 
     531           0 :     thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
     532             :   }
     533             : 
     534             :   // We can't really assume as used changes from display: contents elements (or
     535             :   // other elements without frames).
     536             :   ServoRestyleState& childrenRestyleState =
     537           0 :     thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
     538             : 
     539           0 :   RefPtr<ServoStyleContext> newContext = nullptr;
     540           0 :   if (recreateContext) {
     541           0 :     MOZ_ASSERT(styleFrame || displayContentsNode);
     542             : 
     543           0 :     auto pseudo = aElement->GetPseudoElementType();
     544             :     nsIAtom* pseudoTag = pseudo == CSSPseudoElementType::NotPseudo
     545           0 :       ? nullptr : nsCSSPseudoElements::GetPseudoAtom(pseudo);
     546             : 
     547           0 :     newContext = aRestyleState.StyleSet().GetContext(
     548           0 :       computedValues.forget(), aParentContext, pseudoTag, pseudo, aElement);
     549             : 
     550           0 :     newContext->ResolveSameStructsAs(PresContext(), oldStyleContext);
     551             : 
     552             :     // We want to walk all the continuations here, even the ones with different
     553             :     // styles.  In practice, the only reason we get continuations with different
     554             :     // styles here is ::first-line (::first-letter never affects element
     555             :     // styles).  But in that case, newContext is the right context for the
     556             :     // _later_ continuations anyway (the ones not affected by ::first-line), not
     557             :     // the earlier ones, so there is no point stopping right at the point when
     558             :     // we'd actually be setting the right style context.
     559             :     //
     560             :     // This does mean that we may be setting the wrong style context on our
     561             :     // initial continuations; ::first-line fixes that up after the fact.
     562           0 :     for (nsIFrame* f = styleFrame; f; f = f->GetNextContinuation()) {
     563           0 :       f->SetStyleContext(newContext);
     564             :     }
     565             : 
     566           0 :     if (MOZ_UNLIKELY(displayContentsNode)) {
     567           0 :       MOZ_ASSERT(!styleFrame);
     568           0 :       displayContentsNode->mStyle = newContext;
     569             :     }
     570             : 
     571           0 :     if (styleFrame) {
     572           0 :       styleFrame->UpdateStyleOfOwnedAnonBoxes(childrenRestyleState);
     573             :     }
     574             : 
     575           0 :     if (!aElement->GetParent()) {
     576             :       // This is the root.  Update styles on the viewport as needed.
     577             :       ViewportFrame* viewport =
     578           0 :         do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
     579           0 :       if (viewport) {
     580             :         // NB: The root restyle state, not the one for our children!
     581           0 :         viewport->UpdateStyle(aRestyleState);
     582             :       }
     583             :     }
     584             : 
     585             :     // Some changes to animations don't affect the computed style and yet still
     586             :     // require the layer to be updated. For example, pausing an animation via
     587             :     // the Web Animations API won't affect an element's style but still
     588             :     // requires to update the animation on the layer.
     589             :     //
     590             :     // We can sometimes reach this when the animated style is being removed.
     591             :     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
     592             :     // style or not, we need to call it *after* setting |newContext| to
     593             :     // |styleFrame| to ensure the animated transform has been removed first.
     594           0 :     AddLayerChangesForAnimation(
     595           0 :       styleFrame, aElement, aRestyleState.ChangeList());
     596             :   }
     597             : 
     598             :   const bool descendantsNeedFrames =
     599           0 :     aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
     600             :   const bool traverseElementChildren =
     601           0 :     aElement->HasDirtyDescendantsForServo() ||
     602           0 :     aElement->HasAnimationOnlyDirtyDescendantsForServo() ||
     603           0 :     descendantsNeedFrames;
     604           0 :   const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
     605           0 :   bool recreatedAnyContext = recreateContext;
     606           0 :   if (traverseElementChildren || traverseTextChildren) {
     607             :     nsStyleContext* upToDateContext =
     608           0 :       recreateContext ? newContext : oldStyleContext;
     609             : 
     610           0 :     StyleChildrenIterator it(aElement);
     611             :     TextPostTraversalState textState(*upToDateContext,
     612           0 :                                      displayContentsNode && recreateContext,
     613           0 :                                      childrenRestyleState);
     614           0 :     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
     615           0 :       if (traverseElementChildren && n->IsElement()) {
     616           0 :         recreatedAnyContext |= ProcessPostTraversal(
     617             :           n->AsElement(), upToDateContext, childrenRestyleState);
     618           0 :       } else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
     619           0 :         recreatedAnyContext |= ProcessPostTraversalForText(n, textState);
     620             :       }
     621             :     }
     622             :   }
     623             : 
     624             :   // We want to update frame pseudo-element styles after we've traversed our
     625             :   // kids, because some of those updates (::first-line/::first-letter) need to
     626             :   // modify the styles of the kids, and the child traversal above would just
     627             :   // clobber those modifications.
     628           0 :   if (recreateContext && styleFrame) {
     629           0 :     UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
     630             :   }
     631             : 
     632           0 :   aElement->UnsetHasDirtyDescendantsForServo();
     633           0 :   aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
     634           0 :   aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
     635           0 :   return recreatedAnyContext;
     636             : }
     637             : 
     638             : bool
     639           0 : ServoRestyleManager::ProcessPostTraversalForText(
     640             :     nsIContent* aTextNode,
     641             :     TextPostTraversalState& aPostTraversalState)
     642             : {
     643             :   // Handle lazy frame construction.
     644           0 :   if (aTextNode->HasFlag(NODE_NEEDS_FRAME)) {
     645           0 :     aPostTraversalState.ChangeList().AppendChange(
     646           0 :       nullptr, aTextNode, nsChangeHint_ReconstructFrame);
     647           0 :     return true;
     648             :   }
     649             : 
     650             :   // Handle restyle.
     651           0 :   nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
     652           0 :   if (!primaryFrame) {
     653           0 :     return false;
     654             :   }
     655             : 
     656           0 :   nsStyleContext& newContext = aPostTraversalState.ComputeStyle(aTextNode);
     657           0 :   aPostTraversalState.ComputeHintIfNeeded(aTextNode, primaryFrame, newContext);
     658             : 
     659             :   // We want to walk all the continuations here, even the ones with different
     660             :   // styles.  In practice, the only reasons we get continuations with different
     661             :   // styles are ::first-line and ::first-letter.  But in those cases,
     662             :   // newContext is the right context for the _later_ continuations anyway (the
     663             :   // ones not affected by ::first-line/::first-letter), not the earlier ones,
     664             :   // so there is no point stopping right at the point when we'd actually be
     665             :   // setting the right style context.
     666             :   //
     667             :   // This does mean that we may be setting the wrong style context on our
     668             :   // initial continuations; ::first-line/::first-letter fix that up after the
     669             :   // fact.
     670           0 :   for (nsIFrame* f = primaryFrame; f; f = f->GetNextContinuation()) {
     671           0 :     f->SetStyleContext(&newContext);
     672             :   }
     673             : 
     674           0 :   return true;
     675             : }
     676             : 
     677             : void
     678           0 : ServoRestyleManager::ClearSnapshots()
     679             : {
     680           0 :   for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
     681           0 :     iter.Key()->UnsetFlags(ELEMENT_HAS_SNAPSHOT | ELEMENT_HANDLED_SNAPSHOT);
     682           0 :     iter.Remove();
     683             :   }
     684           0 : }
     685             : 
     686             : ServoElementSnapshot&
     687           0 : ServoRestyleManager::SnapshotFor(Element* aElement)
     688             : {
     689           0 :   MOZ_ASSERT(!mInStyleRefresh);
     690             : 
     691             :   // NOTE(emilio): We can handle snapshots from a one-off restyle of those that
     692             :   // we do to restyle stuff for reconstruction, for example.
     693             :   //
     694             :   // It seems to be the case that we always flush in between that happens and
     695             :   // the next attribute change, so we can assert that we haven't handled the
     696             :   // snapshot here yet. If this assertion didn't hold, we'd need to unset that
     697             :   // flag from here too.
     698             :   //
     699             :   // Can't wait to make ProcessPendingRestyles the only entry-point for styling,
     700             :   // so this becomes much easier to reason about. Today is not that day though.
     701           0 :   MOZ_ASSERT(aElement->HasServoData());
     702           0 :   MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
     703             : 
     704           0 :   ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
     705           0 :   aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
     706             : 
     707           0 :   nsIPresShell* presShell = mPresContext->PresShell();
     708           0 :   presShell->EnsureStyleFlush();
     709             : 
     710           0 :   return *snapshot;
     711             : }
     712             : 
     713             : /* static */ nsIFrame*
     714           0 : ServoRestyleManager::FrameForPseudoElement(const Element* aElement,
     715             :                                            nsIAtom* aPseudoTagOrNull)
     716             : {
     717           0 :   if (!aPseudoTagOrNull) {
     718           0 :     return nsLayoutUtils::GetStyleFrame(aElement);
     719             :   }
     720             : 
     721           0 :   if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
     722           0 :     Element* pseudoElement = nsLayoutUtils::GetBeforePseudo(aElement);
     723           0 :     return pseudoElement ? nsLayoutUtils::GetStyleFrame(pseudoElement) : nullptr;
     724             :   }
     725             : 
     726           0 :   if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
     727           0 :     Element* pseudoElement = nsLayoutUtils::GetAfterPseudo(aElement);
     728           0 :     return pseudoElement ? nsLayoutUtils::GetStyleFrame(pseudoElement) : nullptr;
     729             :   }
     730             : 
     731           0 :   if (aPseudoTagOrNull == nsCSSPseudoElements::firstLetter) {
     732           0 :     return FindFirstLetterFrameForElement(aElement);
     733             :   }
     734             : 
     735           0 :   if (aPseudoTagOrNull == nsCSSPseudoElements::firstLine) {
     736             :     // TODO(emilio, bz): Figure out the best way to diff these styles.
     737           0 :     return nullptr;
     738             :   }
     739             : 
     740           0 :   MOZ_CRASH("Unkown pseudo-element given to "
     741             :             "ServoRestyleManager::FrameForPseudoElement");
     742             :   return nullptr;
     743             : }
     744             : 
     745             : void
     746           0 : ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
     747             :                                                 aRestyleBehavior)
     748             : {
     749           0 :   MOZ_ASSERT(PresContext()->Document(), "No document?  Pshaw!");
     750           0 :   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
     751           0 :   MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?");
     752             : 
     753           0 :   if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) {
     754             :     // PresShell::FlushPendingNotifications doesn't early-return in the case
     755             :     // where the PreShell hasn't yet been initialized (and therefore we haven't
     756             :     // yet done the initial style traversal of the DOM tree). We should arguably
     757             :     // fix up the callers and assert against this case, but we just detect and
     758             :     // handle it for now.
     759           0 :     return;
     760             :   }
     761             : 
     762             :   // Create a AnimationsWithDestroyedFrame during restyling process to
     763             :   // stop animations and transitions on elements that have no frame at the end
     764             :   // of the restyling process.
     765           0 :   AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this);
     766             : 
     767           0 :   ServoStyleSet* styleSet = StyleSet();
     768           0 :   nsIDocument* doc = PresContext()->Document();
     769             :   bool animationOnly = aRestyleBehavior ==
     770           0 :                          TraversalRestyleBehavior::ForAnimationOnly;
     771             : 
     772             :   // Ensure the refresh driver is active during traversal to avoid mutating
     773             :   // mActiveTimer and mMostRecentRefresh time.
     774           0 :   PresContext()->RefreshDriver()->MostRecentRefresh();
     775             : 
     776             : 
     777             :   // Perform the Servo traversal, and the post-traversal if required. We do this
     778             :   // in a loop because certain rare paths in the frame constructor (like
     779             :   // uninstalling XBL bindings) can trigger additional style validations.
     780           0 :   mInStyleRefresh = true;
     781           0 :   if (mHaveNonAnimationRestyles && !animationOnly) {
     782           0 :     ++mAnimationGeneration;
     783             :   }
     784             : 
     785           0 :   TraversalRestyleBehavior restyleBehavior = mRestyleForCSSRuleChanges
     786           0 :     ? TraversalRestyleBehavior::ForCSSRuleChanges
     787           0 :     : TraversalRestyleBehavior::Normal;
     788           0 :   while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
     789             :                        : styleSet->StyleDocument(restyleBehavior)) {
     790           0 :     if (!animationOnly) {
     791           0 :       ClearSnapshots();
     792             :     }
     793             : 
     794           0 :     nsStyleChangeList currentChanges(StyleBackendType::Servo);
     795           0 :     bool anyStyleChanged = false;
     796             : 
     797             :     // Recreate style contexts, and queue up change hints (which also handle
     798             :     // lazy frame construction).
     799             :     {
     800             :       AutoRestyleTimelineMarker marker(
     801           0 :         mPresContext->GetDocShell(), animationOnly);
     802           0 :       DocumentStyleRootIterator iter(doc);
     803           0 :       while (Element* root = iter.GetNextStyleRoot()) {
     804           0 :         ServoRestyleState state(*styleSet, currentChanges);
     805           0 :         anyStyleChanged |= ProcessPostTraversal(root, nullptr, state);
     806           0 :       }
     807             :     }
     808             : 
     809             :     // Process the change hints.
     810             :     //
     811             :     // Unfortunately, the frame constructor can generate new change hints while
     812             :     // processing existing ones. We redirect those into a secondary queue and
     813             :     // iterate until there's nothing left.
     814             :     {
     815             :       AutoTimelineMarker marker(
     816           0 :         mPresContext->GetDocShell(), "StylesApplyChanges");
     817           0 :       ReentrantChangeList newChanges;
     818           0 :       mReentrantChanges = &newChanges;
     819           0 :       while (!currentChanges.IsEmpty()) {
     820           0 :         ProcessRestyledFrames(currentChanges);
     821           0 :         MOZ_ASSERT(currentChanges.IsEmpty());
     822           0 :         for (ReentrantChange& change: newChanges)  {
     823           0 :           if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
     824           0 :               !change.mContent->GetPrimaryFrame()) {
     825             :             // SVG Elements post change hints without ensuring that the primary
     826             :             // frame will be there after that (see bug 1366142).
     827             :             //
     828             :             // Just ignore those, since we can't really process them.
     829           0 :             continue;
     830             :           }
     831           0 :           currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
     832           0 :                                       change.mContent, change.mHint);
     833             :         }
     834           0 :         newChanges.Clear();
     835             :       }
     836           0 :       mReentrantChanges = nullptr;
     837             :     }
     838             : 
     839           0 :     if (anyStyleChanged) {
     840             :       // Maybe no styles changed when:
     841             :       //
     842             :       //  * Only explicit change hints were posted in the first place.
     843             :       //  * When an attribute or state change in the content happens not to need
     844             :       //    a restyle after all.
     845             :       //
     846             :       // In any case, we don't need to increment the restyle generation in that
     847             :       // case.
     848           0 :       IncrementRestyleGeneration();
     849             :     }
     850             :   }
     851             : 
     852           0 :   FlushOverflowChangedTracker();
     853             : 
     854           0 :   if (!animationOnly) {
     855           0 :     ClearSnapshots();
     856           0 :     styleSet->AssertTreeIsClean();
     857           0 :     mHaveNonAnimationRestyles = false;
     858             :   }
     859           0 :   mRestyleForCSSRuleChanges = false;
     860           0 :   mInStyleRefresh = false;
     861             : 
     862             :   // Now that everything has settled, see if we have enough free rule nodes in
     863             :   // the tree to warrant sweeping them.
     864           0 :   styleSet->MaybeGCRuleTree();
     865             : 
     866             :   // Note: We are in the scope of |animationsWithDestroyedFrame|, so
     867             :   //       |mAnimationsWithDestroyedFrame| is still valid.
     868           0 :   MOZ_ASSERT(mAnimationsWithDestroyedFrame);
     869           0 :   mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
     870             : }
     871             : 
     872             : void
     873           0 : ServoRestyleManager::ProcessPendingRestyles()
     874             : {
     875           0 :   DoProcessPendingRestyles(TraversalRestyleBehavior::Normal);
     876           0 : }
     877             : 
     878             : void
     879           0 : ServoRestyleManager::UpdateOnlyAnimationStyles()
     880             : {
     881             :   // Bug 1365855: We also need to implement this for SMIL.
     882           0 :   bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
     883           0 :   if (!doCSS) {
     884           0 :     return;
     885             :   }
     886             : 
     887           0 :   DoProcessPendingRestyles(TraversalRestyleBehavior::ForAnimationOnly);
     888             : }
     889             : 
     890             : void
     891           0 : ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
     892             :                                          EventStates aChangedBits)
     893             : {
     894           0 :   MOZ_ASSERT(!mInStyleRefresh);
     895             : 
     896           0 :   if (!aContent->IsElement()) {
     897           0 :     return;
     898             :   }
     899             : 
     900           0 :   Element* aElement = aContent->AsElement();
     901             :   nsChangeHint changeHint;
     902             :   nsRestyleHint restyleHint;
     903             : 
     904           0 :   if (!aElement->HasServoData()) {
     905           0 :     return;
     906             :   }
     907             : 
     908             :   // NOTE: restyleHint here is effectively always 0, since that's what
     909             :   // ServoStyleSet::HasStateDependentStyle returns. Servo computes on
     910             :   // ProcessPendingRestyles using the ElementSnapshot, but in theory could
     911             :   // compute it sequentially easily.
     912             :   //
     913             :   // Determine what's the best way to do it, and how much work do we save
     914             :   // processing the restyle hint early (i.e., computing the style hint here
     915             :   // sequentially, potentially saving the snapshot), vs lazily (snapshot
     916             :   // approach).
     917             :   //
     918             :   // If we take the sequential approach we need to specialize Servo's restyle
     919             :   // hints system a bit more, and mesure whether we save something storing the
     920             :   // restyle hint in the table and deferring the dirtiness setting until
     921             :   // ProcessPendingRestyles (that's a requirement if we store snapshots though),
     922             :   // vs processing the restyle hint in-place, dirtying the nodes on
     923             :   // PostRestyleEvent.
     924             :   //
     925             :   // If we definitely take the snapshot approach, we should take rid of
     926             :   // HasStateDependentStyle, etc (though right now they're no-ops).
     927           0 :   ContentStateChangedInternal(aElement, aChangedBits, &changeHint,
     928           0 :                               &restyleHint);
     929             : 
     930             :   // Don't bother taking a snapshot if no rules depend on these state bits.
     931             :   //
     932             :   // We always take a snapshot for the LTR/RTL event states, since Servo doesn't
     933             :   // track those bits in the same way, and we know that :dir() rules are always
     934             :   // present in UA style sheets.
     935           0 :   if (!aChangedBits.HasAtLeastOneOfStates(DIRECTION_STATES) &&
     936           0 :       !StyleSet()->HasStateDependency(*aElement, aChangedBits)) {
     937           0 :     return;
     938             :   }
     939             : 
     940           0 :   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
     941           0 :   EventStates previousState = aElement->StyleState() ^ aChangedBits;
     942           0 :   snapshot.AddState(previousState);
     943             : 
     944           0 :   if (Element* parent = aElement->GetFlattenedTreeParentElementForStyle()) {
     945           0 :     parent->NoteDirtyDescendantsForServo();
     946             :   }
     947             : 
     948           0 :   if (restyleHint || changeHint) {
     949           0 :     Servo_NoteExplicitHints(aElement, restyleHint, changeHint);
     950             :   }
     951             : 
     952             :   // Assuming we need to invalidate cached style in getComputedStyle for
     953             :   // undisplayed elements, since we don't know if it is needed.
     954           0 :   IncrementUndisplayedRestyleGeneration();
     955             : }
     956             : 
     957             : static inline bool
     958           0 : AttributeInfluencesOtherPseudoClassState(const Element& aElement,
     959             :                                          const nsIAtom* aAttribute)
     960             : {
     961             :   // We must record some state for :-moz-browser-frame and
     962             :   // :-moz-table-border-nonzero.
     963           0 :   if (aAttribute == nsGkAtoms::mozbrowser) {
     964           0 :     return aElement.IsAnyOfHTMLElements(nsGkAtoms::iframe, nsGkAtoms::frame);
     965             :   }
     966             : 
     967           0 :   if (aAttribute == nsGkAtoms::border) {
     968           0 :     return aElement.IsHTMLElement(nsGkAtoms::table);
     969             :   }
     970             : 
     971           0 :   return false;
     972             : }
     973             : 
     974             : static inline bool
     975           0 : NeedToRecordAttrChange(const ServoStyleSet& aStyleSet,
     976             :                        const Element& aElement,
     977             :                        int32_t aNameSpaceID,
     978             :                        nsIAtom* aAttribute,
     979             :                        bool* aInfluencesOtherPseudoClassState)
     980             : {
     981           0 :   *aInfluencesOtherPseudoClassState =
     982           0 :     AttributeInfluencesOtherPseudoClassState(aElement, aAttribute);
     983             : 
     984             :   // If the attribute influences one of the pseudo-classes that are backed by
     985             :   // attributes, we just record it.
     986           0 :   if (*aInfluencesOtherPseudoClassState) {
     987           0 :     return true;
     988             :   }
     989             : 
     990             :   // We assume that id and class attributes are used in class/id selectors, and
     991             :   // thus record them.
     992             :   //
     993             :   // TODO(emilio): We keep a filter of the ids in use somewhere in the StyleSet,
     994             :   // presumably we could try to filter the old and new id, but it's not clear
     995             :   // it's worth it.
     996           0 :   if (aNameSpaceID == kNameSpaceID_None &&
     997           0 :       (aAttribute == nsGkAtoms::id || aAttribute == nsGkAtoms::_class)) {
     998           0 :     return true;
     999             :   }
    1000             : 
    1001             :   // We always record lang="", even though we force a subtree restyle when it
    1002             :   // changes, since it can change how its siblings match :lang(..) due to
    1003             :   // selectors like :lang(..) + div.
    1004           0 :   if (aAttribute == nsGkAtoms::lang) {
    1005           0 :     return true;
    1006             :   }
    1007             : 
    1008             :   // Otherwise, just record the attribute change if a selector in the page may
    1009             :   // reference it from an attribute selector.
    1010           0 :   return aStyleSet.MightHaveAttributeDependency(aElement, aAttribute);
    1011             : }
    1012             : 
    1013             : void
    1014           0 : ServoRestyleManager::AttributeWillChange(Element* aElement,
    1015             :                                          int32_t aNameSpaceID,
    1016             :                                          nsIAtom* aAttribute, int32_t aModType,
    1017             :                                          const nsAttrValue* aNewValue)
    1018             : {
    1019           0 :   TakeSnapshotForAttributeChange(aElement, aNameSpaceID, aAttribute);
    1020           0 : }
    1021             : 
    1022             : void
    1023           0 : ServoRestyleManager::ClassAttributeWillBeChangedBySMIL(Element* aElement)
    1024             : {
    1025             :   TakeSnapshotForAttributeChange(aElement, kNameSpaceID_None,
    1026           0 :                                  nsGkAtoms::_class);
    1027           0 : }
    1028             : 
    1029             : void
    1030           0 : ServoRestyleManager::TakeSnapshotForAttributeChange(Element* aElement,
    1031             :                                                     int32_t aNameSpaceID,
    1032             :                                                     nsIAtom* aAttribute)
    1033             : {
    1034           0 :   MOZ_ASSERT(!mInStyleRefresh);
    1035             : 
    1036           0 :   if (!aElement->HasServoData()) {
    1037           0 :     return;
    1038             :   }
    1039             : 
    1040             :   bool influencesOtherPseudoClassState;
    1041           0 :   if (!NeedToRecordAttrChange(*StyleSet(),
    1042             :                               *aElement,
    1043             :                               aNameSpaceID,
    1044             :                               aAttribute,
    1045             :                               &influencesOtherPseudoClassState)) {
    1046           0 :     return;
    1047             :   }
    1048             : 
    1049             :   // We cannot tell if the attribute change will affect the styles of
    1050             :   // undisplayed elements, because we don't actually restyle those elements
    1051             :   // during the restyle traversal. So just assume that the attribute change can
    1052             :   // cause the style to change.
    1053           0 :   IncrementUndisplayedRestyleGeneration();
    1054             : 
    1055           0 :   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
    1056           0 :   snapshot.AddAttrs(aElement, aNameSpaceID, aAttribute);
    1057             : 
    1058           0 :   if (influencesOtherPseudoClassState) {
    1059           0 :     snapshot.AddOtherPseudoClassState(aElement);
    1060             :   }
    1061             : 
    1062           0 :   if (Element* parent = aElement->GetFlattenedTreeParentElementForStyle()) {
    1063           0 :     parent->NoteDirtyDescendantsForServo();
    1064             :   }
    1065             : }
    1066             : 
    1067             : // For some attribute changes we must restyle the whole subtree:
    1068             : //
    1069             : // * <td> is affected by the cellpadding on its ancestor table
    1070             : // * lang="" and xml:lang="" can affect all descendants due to :lang()
    1071             : //
    1072             : static inline bool
    1073           0 : AttributeChangeRequiresSubtreeRestyle(const Element& aElement, nsIAtom* aAttr)
    1074             : {
    1075           0 :   if (aAttr == nsGkAtoms::cellpadding) {
    1076           0 :     return aElement.IsHTMLElement(nsGkAtoms::table);
    1077             :   }
    1078             : 
    1079           0 :   return aAttr == nsGkAtoms::lang;
    1080             : }
    1081             : 
    1082             : void
    1083           0 : ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
    1084             :                                       nsIAtom* aAttribute, int32_t aModType,
    1085             :                                       const nsAttrValue* aOldValue)
    1086             : {
    1087           0 :   MOZ_ASSERT(!mInStyleRefresh);
    1088             : 
    1089           0 :   if (nsIFrame* primaryFrame = aElement->GetPrimaryFrame()) {
    1090           0 :     primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
    1091             :   }
    1092             : 
    1093           0 :   auto changeHint = nsChangeHint(0);
    1094           0 :   auto restyleHint = nsRestyleHint(0);
    1095             : 
    1096           0 :   changeHint |= aElement->GetAttributeChangeHint(aAttribute, aModType);
    1097             : 
    1098           0 :   if (aAttribute == nsGkAtoms::style) {
    1099           0 :     restyleHint |= eRestyle_StyleAttribute;
    1100           0 :   } else if (AttributeChangeRequiresSubtreeRestyle(*aElement, aAttribute)) {
    1101           0 :     restyleHint |= eRestyle_Subtree;
    1102           0 :   } else if (aElement->IsAttributeMapped(aAttribute)) {
    1103           0 :     restyleHint |= eRestyle_Self;
    1104             :   }
    1105             : 
    1106           0 :   if (restyleHint || changeHint) {
    1107           0 :     Servo_NoteExplicitHints(aElement, restyleHint, changeHint);
    1108             :   }
    1109             : 
    1110           0 :   if (restyleHint) {
    1111             :     // Assuming we need to invalidate cached style in getComputedStyle for
    1112             :     // undisplayed elements, since we don't know if it is needed.
    1113           0 :     IncrementUndisplayedRestyleGeneration();
    1114             :   }
    1115           0 : }
    1116             : 
    1117             : nsresult
    1118           0 : ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
    1119             : {
    1120           0 :   NS_WARNING("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
    1121           0 :   return NS_OK;
    1122             : }
    1123             : 
    1124             : } // namespace mozilla

Generated by: LCOV version 1.13