LCOV - code coverage report
Current view: top level - layout/base - RestyleManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 312 1296 24.1 %
Date: 2018-08-07 16:35:00 Functions: 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/RestyleManager.h"
       8             : 
       9             : #include "mozilla/AutoRestyleTimelineMarker.h"
      10             : #include "mozilla/AutoTimelineMarker.h"
      11             : #include "mozilla/ComputedStyle.h"
      12             : #include "mozilla/ComputedStyleInlines.h"
      13             : #include "mozilla/DocumentStyleRootIterator.h"
      14             : #include "mozilla/ServoBindings.h"
      15             : #include "mozilla/ServoStyleSetInlines.h"
      16             : #include "mozilla/Unused.h"
      17             : #include "mozilla/ViewportFrame.h"
      18             : #include "mozilla/dom/ChildIterator.h"
      19             : #include "mozilla/dom/ElementInlines.h"
      20             : 
      21             : #include "Layers.h"
      22             : #include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
      23             : #include "nsAnimationManager.h"
      24             : #include "nsBlockFrame.h"
      25             : #include "nsBulletFrame.h"
      26             : #include "nsContentUtils.h"
      27             : #include "nsCSSFrameConstructor.h"
      28             : #include "nsCSSRendering.h"
      29             : #include "nsIFrame.h"
      30             : #include "nsIFrameInlines.h"
      31             : #include "nsImageFrame.h"
      32             : #include "nsIPresShellInlines.h"
      33             : #include "nsPlaceholderFrame.h"
      34             : #include "nsPrintfCString.h"
      35             : #include "nsRefreshDriver.h"
      36             : #include "nsStyleChangeList.h"
      37             : #include "nsStyleUtil.h"
      38             : #include "nsTransitionManager.h"
      39             : #include "StickyScrollContainer.h"
      40             : #include "mozilla/EffectSet.h"
      41             : #include "mozilla/IntegerRange.h"
      42             : #include "mozilla/ViewportFrame.h"
      43             : #include "SVGObserverUtils.h"
      44             : #include "SVGTextFrame.h"
      45             : #include "ActiveLayerTracker.h"
      46             : #include "nsSVGIntegrationUtils.h"
      47             : 
      48             : #ifdef ACCESSIBILITY
      49             : #include "nsAccessibilityService.h"
      50             : #endif
      51             : 
      52             : using namespace mozilla::dom;
      53             : 
      54             : namespace mozilla {
      55             : 
      56           0 : RestyleManager::RestyleManager(nsPresContext* aPresContext)
      57             :   : mPresContext(aPresContext)
      58             :   , mRestyleGeneration(1)
      59             :   , mUndisplayedRestyleGeneration(1)
      60             :   , mInStyleRefresh(false)
      61           0 :   , mAnimationGeneration(0)
      62             : {
      63           0 :   MOZ_ASSERT(mPresContext);
      64           0 : }
      65             : 
      66             : void
      67           0 : RestyleManager::ContentInserted(nsIContent* aChild)
      68             : {
      69           0 :   MOZ_ASSERT(aChild->GetParentNode());
      70           0 :   RestyleForInsertOrChange(aChild);
      71           0 : }
      72             : 
      73             : void
      74           0 : RestyleManager::ContentAppended(nsIContent* aFirstNewContent)
      75             : {
      76           0 :   MOZ_ASSERT(aFirstNewContent->GetParent());
      77             : 
      78             :   // The container cannot be a document, but might be a ShadowRoot.
      79           0 :   if (!aFirstNewContent->GetParentNode()->IsElement()) {
      80             :     return;
      81             :   }
      82           0 :   Element* container = aFirstNewContent->GetParentNode()->AsElement();
      83             : 
      84             : #ifdef DEBUG
      85             :   {
      86           0 :     for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
      87           0 :       NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
      88             :                    "anonymous nodes should not be in child lists");
      89             :     }
      90             :   }
      91             : #endif
      92             :   uint32_t selectorFlags =
      93           0 :     container->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
      94           0 :                              ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
      95           0 :   if (selectorFlags == 0)
      96             :     return;
      97             : 
      98           0 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
      99             :     // see whether we need to restyle the container
     100           0 :     bool wasEmpty = true; // :empty or :-moz-only-whitespace
     101           0 :     for (nsIContent* cur = container->GetFirstChild();
     102           0 :          cur != aFirstNewContent;
     103           0 :          cur = cur->GetNextSibling()) {
     104             :       // We don't know whether we're testing :empty or :-moz-only-whitespace,
     105             :       // so be conservative and assume :-moz-only-whitespace (i.e., make
     106             :       // IsSignificantChild less likely to be true, and thus make us more
     107             :       // likely to restyle).
     108           0 :       if (nsStyleUtil::IsSignificantChild(cur, false)) {
     109             :         wasEmpty = false;
     110             :         break;
     111             :       }
     112             :     }
     113           0 :     if (wasEmpty) {
     114           0 :       RestyleForEmptyChange(container);
     115           0 :       return;
     116             :     }
     117             :   }
     118             : 
     119           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     120           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     121             :     // Restyling the container is the most we can do here, so we're done.
     122           0 :     return;
     123             :   }
     124             : 
     125           0 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     126             :     // restyle the last element child before this node
     127           0 :     for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
     128           0 :          cur;
     129           0 :          cur = cur->GetPreviousSibling()) {
     130           0 :       if (cur->IsElement()) {
     131           0 :         PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, nsChangeHint(0));
     132           0 :         break;
     133             :       }
     134             :     }
     135             :   }
     136             : }
     137             : 
     138             : void
     139           0 : RestyleManager::RestyleForEmptyChange(Element* aContainer)
     140             : {
     141             :   // In some cases (:empty + E, :empty ~ E), a change in the content of
     142             :   // an element requires restyling its parent's siblings.
     143           0 :   nsRestyleHint hint = eRestyle_Subtree;
     144           0 :   nsIContent* grandparent = aContainer->GetParent();
     145           0 :   if (grandparent &&
     146           0 :       (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
     147           0 :     hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
     148             :   }
     149           0 :   PostRestyleEvent(aContainer, hint, nsChangeHint(0));
     150           0 : }
     151             : 
     152             : void
     153           0 : RestyleManager::MaybeRestyleForEdgeChildChange(Element* aContainer,
     154             :                                                nsIContent* aChangedChild)
     155             : {
     156           0 :   MOZ_ASSERT(aContainer->GetFlags() & NODE_HAS_EDGE_CHILD_SELECTOR);
     157           0 :   MOZ_ASSERT(aChangedChild->GetParent() == aContainer);
     158             :   // restyle the previously-first element child if it is after this node
     159           0 :   bool passedChild = false;
     160           0 :   for (nsIContent* content = aContainer->GetFirstChild();
     161           0 :        content;
     162           0 :        content = content->GetNextSibling()) {
     163           0 :     if (content == aChangedChild) {
     164             :       passedChild = true;
     165             :       continue;
     166             :     }
     167           0 :     if (content->IsElement()) {
     168           0 :       if (passedChild) {
     169           0 :         PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     170           0 :                          nsChangeHint(0));
     171             :       }
     172             :       break;
     173             :     }
     174             :   }
     175             :   // restyle the previously-last element child if it is before this node
     176           0 :   passedChild = false;
     177           0 :   for (nsIContent* content = aContainer->GetLastChild();
     178           0 :        content;
     179           0 :        content = content->GetPreviousSibling()) {
     180           0 :     if (content == aChangedChild) {
     181             :       passedChild = true;
     182             :       continue;
     183             :     }
     184           0 :     if (content->IsElement()) {
     185           0 :       if (passedChild) {
     186           0 :         PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     187           0 :                          nsChangeHint(0));
     188             :       }
     189             :       break;
     190             :     }
     191             :   }
     192           0 : }
     193             : 
     194             : // Needed since we can't use PostRestyleEvent on non-elements (with
     195             : // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
     196             : // eRestyle_LaterSiblings) as appropriate).
     197             : static void
     198           0 : RestyleSiblingsStartingWith(RestyleManager* aRestyleManager,
     199             :                             nsIContent* aStartingSibling /* may be null */)
     200             : {
     201           0 :   for (nsIContent* sibling = aStartingSibling; sibling;
     202           0 :        sibling = sibling->GetNextSibling()) {
     203           0 :     if (sibling->IsElement()) {
     204             :       aRestyleManager->
     205           0 :         PostRestyleEvent(sibling->AsElement(),
     206             :                          nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
     207           0 :                          nsChangeHint(0));
     208           0 :       break;
     209             :     }
     210             :   }
     211           0 : }
     212             : 
     213             : template<typename CharT>
     214             : bool
     215           0 : WhitespaceOnly(const CharT* aBuffer, size_t aUpTo)
     216             : {
     217           0 :   for (auto index : IntegerRange(aUpTo)) {
     218           0 :     if (!dom::IsSpaceCharacter(aBuffer[index])) {
     219             :       return false;
     220             :     }
     221             :   }
     222             :   return true;
     223             : }
     224             : 
     225             : template<typename CharT>
     226             : bool
     227           0 : WhitespaceOnlyChangedOnAppend(const CharT* aBuffer,
     228             :                               size_t aOldLength,
     229             :                               size_t aNewLength)
     230             : {
     231           0 :   MOZ_ASSERT(aOldLength <= aNewLength);
     232           0 :   if (!WhitespaceOnly(aBuffer, aOldLength)) {
     233             :     // The old text was already not whitespace-only.
     234             :     return false;
     235             :   }
     236             : 
     237           0 :   return !WhitespaceOnly(aBuffer + aOldLength, aNewLength - aOldLength);
     238             : }
     239             : 
     240             : static bool
     241           0 : HasAnySignificantSibling(Element* aContainer, nsIContent* aChild)
     242             : {
     243           0 :   MOZ_ASSERT(aChild->GetParent() == aContainer);
     244           0 :   for (nsIContent* child = aContainer->GetFirstChild();
     245           0 :        child;
     246           0 :        child = child->GetNextSibling()) {
     247           0 :     if (child == aChild) {
     248             :       continue;
     249             :     }
     250             :     // We don't know whether we're testing :empty or :-moz-only-whitespace,
     251             :     // so be conservative and assume :-moz-only-whitespace (i.e., make
     252             :     // IsSignificantChild less likely to be true, and thus make us more
     253             :     // likely to restyle).
     254           0 :     if (nsStyleUtil::IsSignificantChild(child, false)) {
     255             :       return true;
     256             :     }
     257             :   }
     258             : 
     259             :   return false;
     260             : }
     261             : 
     262             : void
     263           0 : RestyleManager::CharacterDataChanged(nsIContent* aContent,
     264             :                                      const CharacterDataChangeInfo& aInfo)
     265             : {
     266           0 :   nsINode* parent = aContent->GetParentNode();
     267           0 :   MOZ_ASSERT(parent, "How were we notified of a stray node?");
     268             : 
     269           0 :   uint32_t slowSelectorFlags = parent->GetFlags() & NODE_ALL_SELECTOR_FLAGS;
     270           0 :   if (!(slowSelectorFlags & (NODE_HAS_EMPTY_SELECTOR |
     271             :                              NODE_HAS_EDGE_CHILD_SELECTOR))) {
     272             :     // Nothing to do, no other slow selector can change as a result of this.
     273             :     return;
     274             :   }
     275             : 
     276           0 :   if (!aContent->IsText()) {
     277             :     // Doesn't matter to styling (could be a processing instruction or a
     278             :     // comment), it can't change whether any selectors match or don't.
     279             :     return;
     280             :   }
     281             : 
     282             : 
     283           0 :   if (MOZ_UNLIKELY(!parent->IsElement())) {
     284           0 :     MOZ_ASSERT(parent->IsShadowRoot());
     285             :     return;
     286             :   }
     287             : 
     288           0 :   if (MOZ_UNLIKELY(aContent->IsRootOfAnonymousSubtree())) {
     289             :     // This is an anonymous node and thus isn't in child lists, so isn't taken
     290             :     // into account for selector matching the relevant selectors here.
     291             :     return;
     292             :   }
     293             : 
     294             :   // Handle appends specially since they're common and we can know both the old
     295             :   // and the new text exactly.
     296             :   //
     297             :   // TODO(emilio): This could be made much more general if :-moz-only-whitespace
     298             :   // / :-moz-first-node and :-moz-last-node didn't exist. In that case we only
     299             :   // need to know whether we went from empty to non-empty, and that's trivial to
     300             :   // know, with CharacterDataChangeInfo...
     301           0 :   if (!aInfo.mAppend) {
     302             :     // FIXME(emilio): This restyles unnecessarily if the text node is the only
     303             :     // child of the parent element. Fortunately, it's uncommon to have such
     304             :     // nodes and this not being an append.
     305             :     //
     306             :     // See the testcase in bug 1427625 for a test-case that triggers this.
     307           0 :     RestyleForInsertOrChange(aContent);
     308           0 :     return;
     309             :   }
     310             : 
     311           0 :   const nsTextFragment* text = aContent->GetText();
     312             : 
     313           0 :   const size_t oldLength = aInfo.mChangeStart;
     314           0 :   const size_t newLength = text->GetLength();
     315             : 
     316           0 :   const bool emptyChanged = !oldLength && newLength;
     317             : 
     318           0 :   const bool whitespaceOnlyChanged = text->Is2b()
     319           0 :     ? WhitespaceOnlyChangedOnAppend(text->Get2b(), oldLength, newLength)
     320           0 :     : WhitespaceOnlyChangedOnAppend(text->Get1b(), oldLength, newLength);
     321             : 
     322           0 :   if (!emptyChanged && !whitespaceOnlyChanged) {
     323             :     return;
     324             :   }
     325             : 
     326           0 :   if (slowSelectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     327           0 :     if (!HasAnySignificantSibling(parent->AsElement(), aContent)) {
     328             :       // We used to be empty, restyle the parent.
     329           0 :       RestyleForEmptyChange(parent->AsElement());
     330           0 :       return;
     331             :     }
     332             :   }
     333             : 
     334           0 :   if (slowSelectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     335           0 :     MaybeRestyleForEdgeChildChange(parent->AsElement(), aContent);
     336             :   }
     337             : }
     338             : 
     339             : // Restyling for a ContentInserted or CharacterDataChanged notification.
     340             : // This could be used for ContentRemoved as well if we got the
     341             : // notification before the removal happened (and sometimes
     342             : // CharacterDataChanged is more like a removal than an addition).
     343             : // The comments are written and variables are named in terms of it being
     344             : // a ContentInserted notification.
     345             : void
     346           0 : RestyleManager::RestyleForInsertOrChange(nsIContent* aChild)
     347             : {
     348           0 :   nsINode* parentNode = aChild->GetParentNode();
     349             : 
     350           0 :   MOZ_ASSERT(parentNode);
     351             :   // The container might be a document or a ShadowRoot.
     352           0 :   if (!parentNode->IsElement()) {
     353             :     return;
     354             :   }
     355           0 :   Element* container = parentNode->AsElement();
     356             : 
     357           0 :   NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
     358             :                "anonymous nodes should not be in child lists");
     359           0 :   uint32_t selectorFlags = container->GetFlags() & NODE_ALL_SELECTOR_FLAGS;
     360           0 :   if (selectorFlags == 0)
     361             :     return;
     362             : 
     363           0 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     364             :     // See whether we need to restyle the container due to :empty /
     365             :     // :-moz-only-whitespace.
     366           0 :     const bool wasEmpty = !HasAnySignificantSibling(container, aChild);
     367           0 :     if (wasEmpty) {
     368             :       // FIXME(emilio): When coming from CharacterDataChanged this can restyle
     369             :       // unnecessarily. Also can restyle unnecessarily if aChild is not
     370             :       // significant anyway, though that's more unlikely.
     371           0 :       RestyleForEmptyChange(container);
     372           0 :       return;
     373             :     }
     374             :   }
     375             : 
     376           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     377           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     378             :     // Restyling the container is the most we can do here, so we're done.
     379           0 :     return;
     380             :   }
     381             : 
     382           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     383             :     // Restyle all later siblings.
     384           0 :     RestyleSiblingsStartingWith(this, aChild->GetNextSibling());
     385             :   }
     386             : 
     387           0 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     388           0 :     MaybeRestyleForEdgeChildChange(container, aChild);
     389             :   }
     390             : }
     391             : 
     392             : void
     393           0 : RestyleManager::ContentRemoved(nsIContent* aOldChild,
     394             :                                nsIContent* aFollowingSibling)
     395             : {
     396           0 :   MOZ_ASSERT(aOldChild->GetParentNode());
     397             : 
     398             :   // Computed style data isn't useful for detached nodes, and we'll need to
     399             :   // recompute it anyway if we ever insert the nodes back into a document.
     400           0 :   if (aOldChild->IsElement()) {
     401           0 :     RestyleManager::ClearServoDataFromSubtree(aOldChild->AsElement());
     402             :   }
     403             : 
     404             :   // The container might be a document or a ShadowRoot.
     405           0 :   if (!aOldChild->GetParentNode()->IsElement()) {
     406             :     return;
     407             :   }
     408           0 :   Element* container = aOldChild->GetParentNode()->AsElement();
     409             : 
     410           0 :   if (aOldChild->IsRootOfAnonymousSubtree()) {
     411             :     // This should be an assert, but this is called incorrectly in
     412             :     // HTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
     413             :     // up the logs.  Make it an assert again when that's fixed.
     414           0 :     MOZ_ASSERT(aOldChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
     415             :                "anonymous nodes should not be in child lists (bug 439258)");
     416             :   }
     417           0 :   uint32_t selectorFlags = container->GetFlags() & NODE_ALL_SELECTOR_FLAGS;
     418           0 :   if (selectorFlags == 0)
     419             :     return;
     420             : 
     421           0 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     422             :     // see whether we need to restyle the container
     423           0 :     bool isEmpty = true; // :empty or :-moz-only-whitespace
     424           0 :     for (nsIContent* child = container->GetFirstChild();
     425           0 :          child;
     426           0 :          child = child->GetNextSibling()) {
     427             :       // We don't know whether we're testing :empty or :-moz-only-whitespace,
     428             :       // so be conservative and assume :-moz-only-whitespace (i.e., make
     429             :       // IsSignificantChild less likely to be true, and thus make us more
     430             :       // likely to restyle).
     431           0 :       if (nsStyleUtil::IsSignificantChild(child, false)) {
     432             :         isEmpty = false;
     433             :         break;
     434             :       }
     435             :     }
     436           0 :     if (isEmpty) {
     437           0 :       RestyleForEmptyChange(container);
     438           0 :       return;
     439             :     }
     440             :   }
     441             : 
     442           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     443           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     444             :     // Restyling the container is the most we can do here, so we're done.
     445           0 :     return;
     446             :   }
     447             : 
     448           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     449             :     // Restyle all later siblings.
     450           0 :     RestyleSiblingsStartingWith(this, aFollowingSibling);
     451             :   }
     452             : 
     453           0 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     454             :     // restyle the now-first element child if it was after aOldChild
     455           0 :     bool reachedFollowingSibling = false;
     456           0 :     for (nsIContent* content = container->GetFirstChild();
     457           0 :          content;
     458           0 :          content = content->GetNextSibling()) {
     459           0 :       if (content == aFollowingSibling) {
     460           0 :         reachedFollowingSibling = true;
     461             :         // do NOT continue here; we might want to restyle this node
     462             :       }
     463           0 :       if (content->IsElement()) {
     464           0 :         if (reachedFollowingSibling) {
     465           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     466           0 :                            nsChangeHint(0));
     467             :         }
     468             :         break;
     469             :       }
     470             :     }
     471             :     // restyle the now-last element child if it was before aOldChild
     472           0 :     reachedFollowingSibling = (aFollowingSibling == nullptr);
     473           0 :     for (nsIContent* content = container->GetLastChild();
     474           0 :          content;
     475           0 :          content = content->GetPreviousSibling()) {
     476           0 :       if (content->IsElement()) {
     477           0 :         if (reachedFollowingSibling) {
     478           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree, nsChangeHint(0));
     479             :         }
     480             :         break;
     481             :       }
     482           0 :       if (content == aFollowingSibling) {
     483           0 :         reachedFollowingSibling = true;
     484             :       }
     485             :     }
     486             :   }
     487             : }
     488             : 
     489             : /**
     490             :  * Calculates the change hint and the restyle hint for a given content state
     491             :  * change.
     492             :  *
     493             :  * This is called from both Restyle managers.
     494             :  */
     495             : void
     496           0 : RestyleManager::ContentStateChangedInternal(Element* aElement,
     497             :                                             EventStates aStateMask,
     498             :                                             nsChangeHint* aOutChangeHint)
     499             : {
     500           0 :   MOZ_ASSERT(!mInStyleRefresh);
     501           0 :   MOZ_ASSERT(aOutChangeHint);
     502             : 
     503           0 :   *aOutChangeHint = nsChangeHint(0);
     504             :   // Any change to a content state that affects which frames we construct
     505             :   // must lead to a frame reconstruct here if we already have a frame.
     506             :   // Note that we never decide through non-CSS means to not create frames
     507             :   // based on content states, so if we already don't have a frame we don't
     508             :   // need to force a reframe -- if it's needed, the HasStateDependentStyle
     509             :   // call will handle things.
     510           0 :   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
     511           0 :   if (primaryFrame) {
     512             :     // If it's generated content, ignore LOADING/etc state changes on it.
     513           0 :     if (!primaryFrame->IsGeneratedContentFrame() &&
     514           0 :         aStateMask.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
     515             :                                          NS_EVENT_STATE_USERDISABLED |
     516             :                                          NS_EVENT_STATE_SUPPRESSED |
     517             :                                          NS_EVENT_STATE_LOADING)) {
     518           0 :       *aOutChangeHint = nsChangeHint_ReconstructFrame;
     519             :     } else {
     520           0 :       uint8_t app = primaryFrame->StyleDisplay()->mAppearance;
     521           0 :       if (app) {
     522           0 :         nsITheme* theme = PresContext()->GetTheme();
     523           0 :         if (theme &&
     524           0 :             theme->ThemeSupportsWidget(PresContext(), primaryFrame, app)) {
     525           0 :           bool repaint = false;
     526           0 :           theme->WidgetStateChanged(primaryFrame, app, nullptr, &repaint,
     527           0 :                                     nullptr);
     528           0 :           if (repaint) {
     529           0 :             *aOutChangeHint |= nsChangeHint_RepaintFrame;
     530             :           }
     531             :         }
     532             :       }
     533             :     }
     534             : 
     535           0 :     primaryFrame->ContentStatesChanged(aStateMask);
     536             :   }
     537             : 
     538           0 :   if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
     539             :     // Exposing information to the page about whether the link is
     540             :     // visited or not isn't really something we can worry about here.
     541             :     // FIXME: We could probably do this a bit better.
     542           0 :     *aOutChangeHint |= nsChangeHint_RepaintFrame;
     543             :   }
     544           0 : }
     545             : 
     546             : /* static */ nsCString
     547           0 : RestyleManager::RestyleHintToString(nsRestyleHint aHint)
     548             : {
     549           0 :   nsCString result;
     550           0 :   bool any = false;
     551             :   const char* names[] = {
     552             :     "Self", "SomeDescendants", "Subtree", "LaterSiblings", "CSSTransitions",
     553             :     "CSSAnimations", "StyleAttribute", "StyleAttribute_Animations",
     554             :     "Force", "ForceDescendants"
     555           0 :   };
     556           0 :   uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
     557           0 :   uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
     558           0 :   for (uint32_t i = 0; i < ArrayLength(names); i++) {
     559           0 :     if (hint & (1 << i)) {
     560           0 :       if (any) {
     561           0 :         result.AppendLiteral(" | ");
     562             :       }
     563           0 :       result.AppendPrintf("eRestyle_%s", names[i]);
     564           0 :       any = true;
     565             :     }
     566             :   }
     567           0 :   if (rest) {
     568           0 :     if (any) {
     569           0 :       result.AppendLiteral(" | ");
     570             :     }
     571           0 :     result.AppendPrintf("0x%0x", rest);
     572             :   } else {
     573           0 :     if (!any) {
     574           0 :       result.AppendLiteral("0");
     575             :     }
     576             :   }
     577           0 :   return result;
     578             : }
     579             : 
     580             : #ifdef DEBUG
     581             : /* static */ nsCString
     582           0 : RestyleManager::ChangeHintToString(nsChangeHint aHint)
     583             : {
     584           0 :   nsCString result;
     585           0 :   bool any = false;
     586             :   const char* names[] = {
     587             :     "RepaintFrame", "NeedReflow", "ClearAncestorIntrinsics",
     588             :     "ClearDescendantIntrinsics", "NeedDirtyReflow", "SyncFrameView",
     589             :     "UpdateCursor", "UpdateEffects", "UpdateOpacityLayer",
     590             :     "UpdateTransformLayer", "ReconstructFrame", "UpdateOverflow",
     591             :     "UpdateSubtreeOverflow", "UpdatePostTransformOverflow",
     592             :     "UpdateParentOverflow",
     593             :     "ChildrenOnlyTransform", "RecomputePosition", "UpdateContainingBlock",
     594             :     "BorderStyleNoneChange", "UpdateTextPath", "SchedulePaint",
     595             :     "NeutralChange", "InvalidateRenderingObservers",
     596             :     "ReflowChangesSizeOrPosition", "UpdateComputedBSize",
     597             :     "UpdateUsesOpacity", "UpdateBackgroundPosition",
     598             :     "AddOrRemoveTransform", "CSSOverflowChange",
     599             :     "UpdateWidgetProperties", "UpdateTableCellSpans",
     600             :     "VisibilityChange"
     601           0 :   };
     602             :   static_assert(nsChangeHint_AllHints ==
     603             :                   static_cast<uint32_t>((1ull << ArrayLength(names)) - 1),
     604             :                 "Name list doesn't match change hints.");
     605           0 :   uint32_t hint = aHint & static_cast<uint32_t>((1ull << ArrayLength(names)) - 1);
     606           0 :   uint32_t rest = aHint & ~static_cast<uint32_t>((1ull << ArrayLength(names)) - 1);
     607           0 :   if ((hint & NS_STYLE_HINT_REFLOW) == NS_STYLE_HINT_REFLOW) {
     608           0 :     result.AppendLiteral("NS_STYLE_HINT_REFLOW");
     609           0 :     hint = hint & ~NS_STYLE_HINT_REFLOW;
     610           0 :     any = true;
     611           0 :   } else if ((hint & nsChangeHint_AllReflowHints) == nsChangeHint_AllReflowHints) {
     612           0 :     result.AppendLiteral("nsChangeHint_AllReflowHints");
     613           0 :     hint = hint & ~nsChangeHint_AllReflowHints;
     614           0 :     any = true;
     615           0 :   } else if ((hint & NS_STYLE_HINT_VISUAL) == NS_STYLE_HINT_VISUAL) {
     616           0 :     result.AppendLiteral("NS_STYLE_HINT_VISUAL");
     617           0 :     hint = hint & ~NS_STYLE_HINT_VISUAL;
     618           0 :     any = true;
     619             :   }
     620           0 :   for (uint32_t i = 0; i < ArrayLength(names); i++) {
     621           0 :     if (hint & (1u << i)) {
     622           0 :       if (any) {
     623           0 :         result.AppendLiteral(" | ");
     624             :       }
     625           0 :       result.AppendPrintf("nsChangeHint_%s", names[i]);
     626           0 :       any = true;
     627             :     }
     628             :   }
     629             :   if (rest) {
     630             :     if (any) {
     631             :       result.AppendLiteral(" | ");
     632             :     }
     633             :     result.AppendPrintf("0x%0x", rest);
     634             :   } else {
     635           0 :     if (!any) {
     636           0 :       result.AppendLiteral("nsChangeHint(0)");
     637             :     }
     638             :   }
     639           0 :   return result;
     640             : }
     641             : #endif
     642             : 
     643             : /**
     644             :  * Frame construction helpers follow.
     645             :  */
     646             : #ifdef DEBUG
     647             : static bool gInApplyRenderingChangeToTree = false;
     648             : #endif
     649             : 
     650             : /**
     651             :  * Sync views on aFrame and all of aFrame's descendants (following placeholders),
     652             :  * if aChange has nsChangeHint_SyncFrameView.
     653             :  * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants
     654             :  * (following placeholders), if aChange has nsChangeHint_RepaintFrame.
     655             :  * aFrame should be some combination of nsChangeHint_SyncFrameView,
     656             :  * nsChangeHint_RepaintFrame, nsChangeHint_UpdateOpacityLayer and
     657             :  * nsChangeHint_SchedulePaint, nothing else.
     658             : */
     659             : static void SyncViewsAndInvalidateDescendants(nsIFrame* aFrame,
     660             :                                               nsChangeHint aChange);
     661             : 
     662             : static void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
     663             : 
     664             : /**
     665             :  * To handle nsChangeHint_ChildrenOnlyTransform we must iterate over the child
     666             :  * frames of the SVG frame concerned. This helper function is used to find that
     667             :  * SVG frame when we encounter nsChangeHint_ChildrenOnlyTransform to ensure
     668             :  * that we iterate over the intended children, since sometimes we end up
     669             :  * handling that hint while processing hints for one of the SVG frame's
     670             :  * ancestor frames.
     671             :  *
     672             :  * The reason that we sometimes end up trying to process the hint for an
     673             :  * ancestor of the SVG frame that the hint is intended for is due to the way we
     674             :  * process restyle events. ApplyRenderingChangeToTree adjusts the frame from
     675             :  * the restyled element's principle frame to one of its ancestor frames based
     676             :  * on what nsCSSRendering::FindBackground returns, since the background style
     677             :  * may have been propagated up to an ancestor frame. Processing hints using an
     678             :  * ancestor frame is fine in general, but nsChangeHint_ChildrenOnlyTransform is
     679             :  * a special case since it is intended to update the children of a specific
     680             :  * frame.
     681             :  */
     682             : static nsIFrame*
     683           0 : GetFrameForChildrenOnlyTransformHint(nsIFrame* aFrame)
     684             : {
     685           0 :   if (aFrame->IsViewportFrame()) {
     686             :     // This happens if the root-<svg> is fixed positioned, in which case we
     687             :     // can't use aFrame->GetContent() to find the primary frame, since
     688             :     // GetContent() returns nullptr for ViewportFrame.
     689           0 :     aFrame = aFrame->PrincipalChildList().FirstChild();
     690             :   }
     691             :   // For an nsHTMLScrollFrame, this will get the SVG frame that has the
     692             :   // children-only transforms:
     693           0 :   aFrame = aFrame->GetContent()->GetPrimaryFrame();
     694           0 :   if (aFrame->IsSVGOuterSVGFrame()) {
     695           0 :     aFrame = aFrame->PrincipalChildList().FirstChild();
     696           0 :     MOZ_ASSERT(aFrame->IsSVGOuterSVGAnonChildFrame(),
     697             :                "Where is the nsSVGOuterSVGFrame's anon child??");
     698             :   }
     699           0 :   MOZ_ASSERT(aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer),
     700             :              "Children-only transforms only expected on SVG frames");
     701           0 :   return aFrame;
     702             : }
     703             : 
     704             : // Returns true if this function managed to successfully move a frame, and
     705             : // false if it could not process the position change, and a reflow should
     706             : // be performed instead.
     707             : static bool
     708           0 : RecomputePosition(nsIFrame* aFrame)
     709             : {
     710             :   // Don't process position changes on table frames, since we already handle
     711             :   // the dynamic position change on the table wrapper frame, and the
     712             :   // reflow-based fallback code path also ignores positions on inner table
     713             :   // frames.
     714           0 :   if (aFrame->IsTableFrame()) {
     715             :     return true;
     716             :   }
     717             : 
     718           0 :   const nsStyleDisplay* display = aFrame->StyleDisplay();
     719             :   // Changes to the offsets of a non-positioned element can safely be ignored.
     720           0 :   if (display->mPosition == NS_STYLE_POSITION_STATIC) {
     721             :     return true;
     722             :   }
     723             : 
     724             :   // Don't process position changes on frames which have views or the ones which
     725             :   // have a view somewhere in their descendants, because the corresponding view
     726             :   // needs to be repositioned properly as well.
     727           0 :   if (aFrame->HasView() ||
     728           0 :       (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
     729           0 :     StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     730           0 :     return false;
     731             :   }
     732             : 
     733             :   // Flexbox and Grid layout supports CSS Align and the optimizations below
     734             :   // don't support that yet.
     735           0 :   if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
     736           0 :     nsIFrame* ph = aFrame->GetPlaceholderFrame();
     737           0 :     if (ph && ph->HasAnyStateBits(PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN)) {
     738           0 :       StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     739           0 :       return false;
     740             :     }
     741             :   }
     742             : 
     743           0 :   aFrame->SchedulePaint();
     744             : 
     745             :   // For relative positioning, we can simply update the frame rect
     746           0 :   if (display->IsRelativelyPositionedStyle()) {
     747             :     // Move the frame
     748           0 :     if (display->mPosition == NS_STYLE_POSITION_STICKY) {
     749             :       // Update sticky positioning for an entire element at once, starting with
     750             :       // the first continuation or ib-split sibling.
     751             :       // It's rare that the frame we already have isn't already the first
     752             :       // continuation or ib-split sibling, but it can happen when styles differ
     753             :       // across continuations such as ::first-line or ::first-letter, and in
     754             :       // those cases we will generally (but maybe not always) do the work twice.
     755             :       nsIFrame* firstContinuation =
     756           0 :         nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
     757             : 
     758           0 :       StickyScrollContainer::ComputeStickyOffsets(firstContinuation);
     759             :       StickyScrollContainer* ssc =
     760             :         StickyScrollContainer::GetStickyScrollContainerForFrame(
     761           0 :           firstContinuation);
     762           0 :       if (ssc) {
     763           0 :         ssc->PositionContinuations(firstContinuation);
     764             :       }
     765             :     } else {
     766           0 :       MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition,
     767             :                  "Unexpected type of positioning");
     768           0 :       for (nsIFrame* cont = aFrame; cont;
     769             :            cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
     770           0 :         nsIFrame* cb = cont->GetContainingBlock();
     771           0 :         nsMargin newOffsets;
     772           0 :         WritingMode wm = cb->GetWritingMode();
     773           0 :         const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size());
     774             : 
     775           0 :         ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets);
     776           0 :         NS_ASSERTION(newOffsets.left == -newOffsets.right &&
     777             :                      newOffsets.top == -newOffsets.bottom,
     778             :                      "ComputeRelativeOffsets should return valid results");
     779             : 
     780             :         // ReflowInput::ApplyRelativePositioning would work here, but
     781             :         // since we've already checked mPosition and aren't changing the frame's
     782             :         // normal position, go ahead and add the offsets directly.
     783             :         // First, we need to ensure that the normal position is stored though.
     784             :         bool hasProperty;
     785           0 :         nsPoint normalPosition = cont->GetNormalPosition(&hasProperty);
     786           0 :         if (!hasProperty) {
     787           0 :           cont->AddProperty(nsIFrame::NormalPositionProperty(),
     788           0 :                             new nsPoint(normalPosition));
     789             :         }
     790           0 :         cont->SetPosition(normalPosition +
     791           0 :                           nsPoint(newOffsets.left, newOffsets.top));
     792             :       }
     793             :     }
     794             : 
     795             :     return true;
     796             :   }
     797             : 
     798             :   // For the absolute positioning case, set up a fake HTML reflow state for
     799             :   // the frame, and then get the offsets and size from it. If the frame's size
     800             :   // doesn't need to change, we can simply update the frame position. Otherwise
     801             :   // we fall back to a reflow.
     802             :   RefPtr<gfxContext> rc =
     803           0 :     aFrame->PresShell()->CreateReferenceRenderingContext();
     804             : 
     805             :   // Construct a bogus parent reflow state so that there's a usable
     806             :   // containing block reflow state.
     807           0 :   nsIFrame* parentFrame = aFrame->GetParent();
     808           0 :   WritingMode parentWM = parentFrame->GetWritingMode();
     809           0 :   WritingMode frameWM = aFrame->GetWritingMode();
     810           0 :   LogicalSize parentSize = parentFrame->GetLogicalSize();
     811             : 
     812           0 :   nsFrameState savedState = parentFrame->GetStateBits();
     813             :   ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame, rc,
     814           0 :                                 parentSize);
     815           0 :   parentFrame->RemoveStateBits(~nsFrameState(0));
     816           0 :   parentFrame->AddStateBits(savedState);
     817             : 
     818             :   // The bogus parent state here was created with no parent state of its own,
     819             :   // and therefore it won't have an mCBReflowInput set up.
     820             :   // But we may need one (for InitCBReflowInput in a child state), so let's
     821             :   // try to create one here for the cases where it will be needed.
     822           0 :   Maybe<ReflowInput> cbReflowInput;
     823           0 :   nsIFrame* cbFrame = parentFrame->GetContainingBlock();
     824           0 :   if (cbFrame && (aFrame->GetContainingBlock() != parentFrame ||
     825           0 :                   parentFrame->IsTableFrame())) {
     826           0 :     LogicalSize cbSize = cbFrame->GetLogicalSize();
     827           0 :     cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, rc, cbSize);
     828           0 :     cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin();
     829           0 :     cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding();
     830           0 :     cbReflowInput->ComputedPhysicalBorderPadding() =
     831           0 :       cbFrame->GetUsedBorderAndPadding();
     832           0 :     parentReflowInput.mCBReflowInput = cbReflowInput.ptr();
     833             :   }
     834             : 
     835           0 :   NS_WARNING_ASSERTION(parentSize.ISize(parentWM) != NS_INTRINSICSIZE &&
     836             :                        parentSize.BSize(parentWM) != NS_INTRINSICSIZE,
     837             :                        "parentSize should be valid");
     838           0 :   parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0));
     839           0 :   parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0));
     840           0 :   parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
     841             : 
     842           0 :   parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding();
     843           0 :   parentReflowInput.ComputedPhysicalBorderPadding() =
     844           0 :     parentFrame->GetUsedBorderAndPadding();
     845           0 :   LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM);
     846           0 :   availSize.BSize(frameWM) = NS_INTRINSICSIZE;
     847             : 
     848           0 :   ViewportFrame* viewport = do_QueryFrame(parentFrame);
     849             :   nsSize cbSize = viewport ?
     850           0 :     viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size()
     851           0 :     : aFrame->GetContainingBlock()->GetSize();
     852             :   const nsMargin& parentBorder =
     853           0 :     parentReflowInput.mStyleBorder->GetComputedBorder();
     854           0 :   cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
     855           0 :   LogicalSize lcbSize(frameWM, cbSize);
     856             :   ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput, aFrame,
     857           0 :                           availSize, &lcbSize);
     858           0 :   nsSize computedSize(reflowInput.ComputedWidth(),
     859           0 :                       reflowInput.ComputedHeight());
     860           0 :   computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight();
     861           0 :   if (computedSize.height != NS_INTRINSICSIZE) {
     862           0 :     computedSize.height +=
     863           0 :       reflowInput.ComputedPhysicalBorderPadding().TopBottom();
     864             :   }
     865           0 :   nsSize size = aFrame->GetSize();
     866             :   // The RecomputePosition hint is not used if any offset changed between auto
     867             :   // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
     868             :   // element height will be its intrinsic height, and since 'top' and 'bottom''s
     869             :   // auto-ness hasn't changed, the old height must also be its intrinsic
     870             :   // height, which we can assume hasn't changed (or reflow would have
     871             :   // been triggered).
     872           0 :   if (computedSize.width == size.width &&
     873           0 :       (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
     874             :     // If we're solving for 'left' or 'top', then compute it here, in order to
     875             :     // match the reflow code path.
     876           0 :     if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) {
     877           0 :       reflowInput.ComputedPhysicalOffsets().left = cbSize.width -
     878           0 :                                           reflowInput.ComputedPhysicalOffsets().right -
     879           0 :                                           reflowInput.ComputedPhysicalMargin().right -
     880           0 :                                           size.width -
     881           0 :                                           reflowInput.ComputedPhysicalMargin().left;
     882             :     }
     883             : 
     884           0 :     if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) {
     885           0 :       reflowInput.ComputedPhysicalOffsets().top = cbSize.height -
     886           0 :                                          reflowInput.ComputedPhysicalOffsets().bottom -
     887           0 :                                          reflowInput.ComputedPhysicalMargin().bottom -
     888           0 :                                          size.height -
     889           0 :                                          reflowInput.ComputedPhysicalMargin().top;
     890             :     }
     891             : 
     892             :     // Move the frame
     893           0 :     nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left +
     894           0 :                 reflowInput.ComputedPhysicalMargin().left,
     895           0 :                 parentBorder.top + reflowInput.ComputedPhysicalOffsets().top +
     896           0 :                 reflowInput.ComputedPhysicalMargin().top);
     897           0 :     aFrame->SetPosition(pos);
     898             : 
     899             :     return true;
     900             :   }
     901             : 
     902             :   // Fall back to a reflow
     903           0 :   StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     904           0 :   return false;
     905             : }
     906             : 
     907             : static bool
     908           0 : HasBoxAncestor(nsIFrame* aFrame)
     909             : {
     910           0 :   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
     911           0 :     if (f->IsXULBoxFrame()) {
     912             :       return true;
     913             :     }
     914             :   }
     915             :   return false;
     916             : }
     917             : 
     918             : /**
     919             :  * Return true if aFrame's subtree has placeholders for out-of-flow content
     920             :  * whose 'position' style's bit in aPositionMask is set.
     921             :  */
     922             : static bool
     923           0 : FrameHasPositionedPlaceholderDescendants(nsIFrame* aFrame,
     924             :                                          uint32_t aPositionMask)
     925             : {
     926           0 :   MOZ_ASSERT(aPositionMask & (1 << NS_STYLE_POSITION_FIXED));
     927             : 
     928           0 :   for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
     929           0 :     for (nsIFrame* f : lists.CurrentList()) {
     930           0 :       if (f->IsPlaceholderFrame()) {
     931             :         nsIFrame* outOfFlow =
     932           0 :           nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
     933             :         // If SVG text frames could appear here, they could confuse us since
     934             :         // they ignore their position style ... but they can't.
     935           0 :         NS_ASSERTION(!nsSVGUtils::IsInSVGTextSubtree(outOfFlow),
     936             :                      "SVG text frames can't be out of flow");
     937           0 :         if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
     938           0 :           return true;
     939             :         }
     940             :       }
     941           0 :       uint32_t positionMask = aPositionMask;
     942             :       // NOTE:  It's tempting to check f->IsAbsPosContainingBlock() or
     943             :       // f->IsFixedPosContainingBlock() here.  However, that would only
     944             :       // be testing the *new* style of the frame, which might exclude
     945             :       // descendants that currently have this frame as an abs-pos
     946             :       // containing block.  Taking the codepath where we don't reframe
     947             :       // could lead to an unsafe call to
     948             :       // cont->MarkAsNotAbsoluteContainingBlock() before we've reframed
     949             :       // the descendant and taken it off the absolute list.
     950           0 :       if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
     951             :         return true;
     952             :       }
     953             :     }
     954             :   }
     955           0 :   return false;
     956             : }
     957             : 
     958             : static bool
     959           0 : NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame)
     960             : {
     961             :   static_assert(0 <= NS_STYLE_POSITION_ABSOLUTE &&
     962             :                 NS_STYLE_POSITION_ABSOLUTE < 32, "Style constant out of range");
     963             :   static_assert(0 <= NS_STYLE_POSITION_FIXED &&
     964             :                 NS_STYLE_POSITION_FIXED < 32, "Style constant out of range");
     965             : 
     966             :   uint32_t positionMask;
     967             :   // Don't call aFrame->IsPositioned here, since that returns true if
     968             :   // the frame already has a transform, and we want to ignore that here
     969           0 :   if (aFrame->IsAbsolutelyPositioned() || aFrame->IsRelativelyPositioned()) {
     970             :     // This frame is a container for abs-pos descendants whether or not it
     971             :     // has a transform.
     972             :     // So abs-pos descendants are no problem; we only need to reframe if
     973             :     // we have fixed-pos descendants.
     974             :     positionMask = 1 << NS_STYLE_POSITION_FIXED;
     975             :   } else {
     976             :     // This frame may not be a container for abs-pos descendants already.
     977             :     // So reframe if we have abs-pos or fixed-pos descendants.
     978           0 :     positionMask =
     979             :       (1 << NS_STYLE_POSITION_FIXED) | (1 << NS_STYLE_POSITION_ABSOLUTE);
     980             :   }
     981           0 :   for (nsIFrame* f = aFrame; f;
     982             :        f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
     983           0 :     if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
     984             :       return true;
     985             :     }
     986             :   }
     987             :   return false;
     988             : }
     989             : 
     990             : static void
     991           0 : DoApplyRenderingChangeToTree(nsIFrame* aFrame,
     992             :                              nsChangeHint aChange)
     993             : {
     994           0 :   MOZ_ASSERT(gInApplyRenderingChangeToTree,
     995             :              "should only be called within ApplyRenderingChangeToTree");
     996             : 
     997           0 :   for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) {
     998             :     // Invalidate and sync views on all descendant frames, following placeholders.
     999             :     // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because
    1000             :     // there can't be any out-of-flows or popups that need to be transformed;
    1001             :     // all out-of-flow descendants of the transformed element must also be
    1002             :     // descendants of the transformed frame.
    1003           0 :     SyncViewsAndInvalidateDescendants(aFrame,
    1004             :       nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
    1005             :                               nsChangeHint_SyncFrameView |
    1006             :                               nsChangeHint_UpdateOpacityLayer |
    1007           0 :                               nsChangeHint_SchedulePaint)));
    1008             :     // This must be set to true if the rendering change needs to
    1009             :     // invalidate content.  If it's false, a composite-only paint
    1010             :     // (empty transaction) will be scheduled.
    1011           0 :     bool needInvalidatingPaint = false;
    1012             : 
    1013             :     // if frame has view, will already be invalidated
    1014           0 :     if (aChange & nsChangeHint_RepaintFrame) {
    1015             :       // Note that this whole block will be skipped when painting is suppressed
    1016             :       // (due to our caller ApplyRendingChangeToTree() discarding the
    1017             :       // nsChangeHint_RepaintFrame hint).  If you add handling for any other
    1018             :       // hints within this block, be sure that they too should be ignored when
    1019             :       // painting is suppressed.
    1020           0 :       needInvalidatingPaint = true;
    1021           0 :       aFrame->InvalidateFrameSubtree();
    1022           0 :       if ((aChange & nsChangeHint_UpdateEffects) &&
    1023           0 :           aFrame->IsFrameOfType(nsIFrame::eSVG) &&
    1024           0 :           !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
    1025             :         // Need to update our overflow rects:
    1026           0 :         nsSVGUtils::ScheduleReflowSVG(aFrame);
    1027             :       }
    1028             : 
    1029           0 :       ActiveLayerTracker::NotifyNeedsRepaint(aFrame);
    1030             :     }
    1031          16 :     if (aChange & nsChangeHint_UpdateTextPath) {
    1032           0 :       if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
    1033             :         // Invalidate and reflow the entire SVGTextFrame:
    1034           0 :         NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
    1035             :                      "expected frame for a <textPath> element");
    1036           0 :         nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType(
    1037           0 :           aFrame, LayoutFrameType::SVGText);
    1038           0 :         NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame");
    1039           0 :         static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange();
    1040             :       } else {
    1041           0 :         MOZ_ASSERT(false, "unexpected frame got nsChangeHint_UpdateTextPath");
    1042             :       }
    1043             :     }
    1044          16 :     if (aChange & nsChangeHint_UpdateOpacityLayer) {
    1045             :       // FIXME/bug 796697: we can get away with empty transactions for
    1046             :       // opacity updates in many cases.
    1047           0 :       needInvalidatingPaint = true;
    1048             : 
    1049           6 :       ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity);
    1050           6 :       if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
    1051             :         // SVG effects paints the opacity without using
    1052             :         // nsDisplayOpacity. We need to invalidate manually.
    1053           0 :         aFrame->InvalidateFrameSubtree();
    1054             :       }
    1055             :     }
    1056           0 :     if ((aChange & nsChangeHint_UpdateTransformLayer) &&
    1057           0 :         aFrame->IsTransformed()) {
    1058           0 :       ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform);
    1059             :       // If we're not already going to do an invalidating paint, see
    1060             :       // if we can get away with only updating the transform on a
    1061             :       // layer for this frame, and not scheduling an invalidating
    1062             :       // paint.
    1063           0 :       if (!needInvalidatingPaint) {
    1064             :         nsDisplayItem::Layer* layer;
    1065           0 :         needInvalidatingPaint |= !aFrame->TryUpdateTransformOnly(&layer);
    1066             : 
    1067           0 :         if (!needInvalidatingPaint) {
    1068             :           // Since we're not going to paint, we need to resend animation
    1069             :           // data to the layer.
    1070           0 :           MOZ_ASSERT(layer, "this can't happen if there's no layer");
    1071             :           nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(
    1072           0 :             layer, nullptr, nullptr, aFrame, eCSSProperty_transform);
    1073             :         }
    1074             :       }
    1075             :     }
    1076          16 :     if (aChange & nsChangeHint_ChildrenOnlyTransform) {
    1077           0 :       needInvalidatingPaint = true;
    1078             :       nsIFrame* childFrame =
    1079           0 :         GetFrameForChildrenOnlyTransformHint(aFrame)->PrincipalChildList().FirstChild();
    1080           0 :       for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
    1081           0 :         ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
    1082             :       }
    1083             :     }
    1084          16 :     if (aChange & nsChangeHint_SchedulePaint) {
    1085           0 :       needInvalidatingPaint = true;
    1086             :     }
    1087           0 :     aFrame->SchedulePaint(needInvalidatingPaint
    1088             :                             ? nsIFrame::PAINT_DEFAULT
    1089           0 :                             : nsIFrame::PAINT_COMPOSITE_ONLY);
    1090             :   }
    1091          16 : }
    1092             : 
    1093             : static void
    1094           0 : SyncViewsAndInvalidateDescendants(nsIFrame* aFrame, nsChangeHint aChange)
    1095             : {
    1096          18 :   MOZ_ASSERT(gInApplyRenderingChangeToTree,
    1097             :              "should only be called within ApplyRenderingChangeToTree");
    1098             : 
    1099          18 :   NS_ASSERTION(nsChangeHint_size_t(aChange) ==
    1100             :                           (aChange & (nsChangeHint_RepaintFrame |
    1101             :                                       nsChangeHint_SyncFrameView |
    1102             :                                       nsChangeHint_UpdateOpacityLayer |
    1103             :                                       nsChangeHint_SchedulePaint)),
    1104             :                "Invalid change flag");
    1105             : 
    1106          18 :   if (aChange & nsChangeHint_SyncFrameView) {
    1107          14 :     aFrame->SyncFrameViewProperties();
    1108             :   }
    1109             : 
    1110           0 :   nsIFrame::ChildListIterator lists(aFrame);
    1111           0 :   for (; !lists.IsDone(); lists.Next()) {
    1112           8 :     for (nsIFrame* child : lists.CurrentList()) {
    1113           0 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    1114             :         // only do frames that don't have placeholders
    1115           2 :         if (child->IsPlaceholderFrame()) {
    1116             :           // do the out-of-flow frame and its continuations
    1117             :           nsIFrame* outOfFlowFrame =
    1118           0 :             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
    1119           0 :           DoApplyRenderingChangeToTree(outOfFlowFrame, aChange);
    1120           2 :         } else if (lists.CurrentID() == nsIFrame::kPopupList) {
    1121           0 :           DoApplyRenderingChangeToTree(child, aChange);
    1122             :         } else { // regular frame
    1123           2 :           SyncViewsAndInvalidateDescendants(child, aChange);
    1124             :         }
    1125             :       }
    1126             :     }
    1127             :   }
    1128          18 : }
    1129             : 
    1130             : static void
    1131          16 : ApplyRenderingChangeToTree(nsIPresShell* aPresShell,
    1132             :                            nsIFrame* aFrame,
    1133             :                            nsChangeHint aChange)
    1134             : {
    1135             :   // We check StyleDisplay()->HasTransformStyle() in addition to checking
    1136             :   // IsTransformed() since we can get here for some frames that don't support
    1137             :   // CSS transforms.
    1138          32 :   NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
    1139             :                aFrame->IsTransformed() ||
    1140             :                aFrame->StyleDisplay()->HasTransformStyle(),
    1141             :                "Unexpected UpdateTransformLayer hint");
    1142             : 
    1143           0 :   if (aPresShell->IsPaintingSuppressed()) {
    1144             :     // Don't allow synchronous rendering changes when painting is turned off.
    1145          12 :     aChange &= ~nsChangeHint_RepaintFrame;
    1146          12 :     if (!aChange) {
    1147             :       return;
    1148             :     }
    1149             :   }
    1150             : 
    1151             : // Trigger rendering updates by damaging this frame and any
    1152             : // continuations of this frame.
    1153             : #ifdef DEBUG
    1154           0 :   gInApplyRenderingChangeToTree = true;
    1155             : #endif
    1156          32 :   if (aChange & nsChangeHint_RepaintFrame) {
    1157             :     // If the frame's background is propagated to an ancestor, walk up to
    1158             :     // that ancestor and apply the RepaintFrame change hint to it.
    1159             :     ComputedStyle* bgSC;
    1160             :     nsIFrame* propagatedFrame = aFrame;
    1161           0 :     while (!nsCSSRendering::FindBackground(propagatedFrame, &bgSC)) {
    1162           0 :       propagatedFrame = propagatedFrame->GetParent();
    1163           0 :       NS_ASSERTION(aFrame, "root frame must paint");
    1164             :     }
    1165             : 
    1166           0 :     if (propagatedFrame != aFrame) {
    1167           0 :       DoApplyRenderingChangeToTree(propagatedFrame, nsChangeHint_RepaintFrame);
    1168           0 :       aChange &= ~nsChangeHint_RepaintFrame;
    1169           0 :       if (!aChange) {
    1170           0 :         return;
    1171             :       }
    1172             :     }
    1173             :   }
    1174           0 :   DoApplyRenderingChangeToTree(aFrame, aChange);
    1175             : #ifdef DEBUG
    1176          16 :   gInApplyRenderingChangeToTree = false;
    1177             : #endif
    1178             : }
    1179             : 
    1180             : static void
    1181           0 : AddSubtreeToOverflowTracker(nsIFrame* aFrame,
    1182             :                             OverflowChangedTracker& aOverflowChangedTracker)
    1183             : {
    1184           0 :   if (aFrame->FrameMaintainsOverflow()) {
    1185             :     aOverflowChangedTracker.AddFrame(aFrame,
    1186           0 :                                      OverflowChangedTracker::CHILDREN_CHANGED);
    1187             :   }
    1188           0 :   nsIFrame::ChildListIterator lists(aFrame);
    1189           0 :   for (; !lists.IsDone(); lists.Next()) {
    1190           0 :     for (nsIFrame* child : lists.CurrentList()) {
    1191           0 :       AddSubtreeToOverflowTracker(child, aOverflowChangedTracker);
    1192             :     }
    1193             :   }
    1194           0 : }
    1195             : 
    1196             : static void
    1197          12 : StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint)
    1198             : {
    1199             :   nsIPresShell::IntrinsicDirty dirtyType;
    1200          12 :   if (aHint & nsChangeHint_ClearDescendantIntrinsics) {
    1201           0 :     NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics,
    1202             :                  "Please read the comments in nsChangeHint.h");
    1203          12 :     NS_ASSERTION(aHint & nsChangeHint_NeedDirtyReflow,
    1204             :                  "ClearDescendantIntrinsics requires NeedDirtyReflow");
    1205             :     dirtyType = nsIPresShell::eStyleChange;
    1206           0 :   } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
    1207           0 :              aFrame->HasAnyStateBits(
    1208             :                NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
    1209             :     dirtyType = nsIPresShell::eStyleChange;
    1210           0 :   } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) {
    1211             :     dirtyType = nsIPresShell::eTreeChange;
    1212           0 :   } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
    1213           0 :              HasBoxAncestor(aFrame)) {
    1214             :     // The frame's computed BSize is changing, and we have a box ancestor
    1215             :     // whose cached intrinsic height may need to be updated.
    1216             :     dirtyType = nsIPresShell::eTreeChange;
    1217             :   } else {
    1218           0 :     dirtyType = nsIPresShell::eResize;
    1219             :   }
    1220             : 
    1221             :   nsFrameState dirtyBits;
    1222           0 :   if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    1223             :     dirtyBits = nsFrameState(0);
    1224          10 :   } else if ((aHint & nsChangeHint_NeedDirtyReflow) ||
    1225             :              dirtyType == nsIPresShell::eStyleChange) {
    1226             :     dirtyBits = NS_FRAME_IS_DIRTY;
    1227             :   } else {
    1228           0 :     dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
    1229             :   }
    1230             : 
    1231             :   // If we're not going to clear any intrinsic sizes on the frames, and
    1232             :   // there are no dirty bits to set, then there's nothing to do.
    1233          12 :   if (dirtyType == nsIPresShell::eResize && !dirtyBits)
    1234             :     return;
    1235             : 
    1236             :   nsIPresShell::ReflowRootHandling rootHandling;
    1237          12 :   if (aHint & nsChangeHint_ReflowChangesSizeOrPosition) {
    1238             :     rootHandling = nsIPresShell::ePositionOrSizeChange;
    1239             :   } else {
    1240           0 :     rootHandling = nsIPresShell::eNoPositionOrSizeChange;
    1241             :   }
    1242             : 
    1243             :   do {
    1244           0 :     aFrame->PresShell()->FrameNeedsReflow(
    1245           0 :       aFrame, dirtyType, dirtyBits, rootHandling);
    1246          12 :     aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
    1247          12 :   } while (aFrame);
    1248             : }
    1249             : 
    1250             : // Get the next sibling which might have a frame.  This only considers siblings
    1251             : // that stylo post-traversal looks at, so only elements and text.  In
    1252             : // particular, it ignores comments.
    1253             : static nsIContent*
    1254           0 : NextSiblingWhichMayHaveFrame(nsIContent* aContent)
    1255             : {
    1256           0 :   for (nsIContent* next = aContent->GetNextSibling();
    1257           0 :        next;
    1258           0 :        next = next->GetNextSibling()) {
    1259          16 :     if (next->IsElement() || next->IsText()) {
    1260             :       return next;
    1261             :     }
    1262             :   }
    1263             : 
    1264             :   return nullptr;
    1265             : }
    1266             : 
    1267             : void
    1268           0 : RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
    1269             : {
    1270          26 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    1271             :                "Someone forgot a script blocker");
    1272             : 
    1273             :   // See bug 1378219 comment 9:
    1274             :   // Recursive calls here are a bit worrying, but apparently do happen in the
    1275             :   // wild (although not currently in any of our automated tests). Try to get a
    1276             :   // stack from Nightly/Dev channel to figure out what's going on and whether
    1277             :   // it's OK.
    1278           0 :   MOZ_DIAGNOSTIC_ASSERT(!mDestroyedFrames, "ProcessRestyledFrames recursion");
    1279             : 
    1280          52 :   if (aChangeList.IsEmpty()) {
    1281           0 :     return;
    1282             :   }
    1283             : 
    1284             :   // If mDestroyedFrames is null, we want to create a new hashtable here
    1285             :   // and destroy it on exit; but if it is already non-null (because we're in
    1286             :   // a recursive call), we will continue to use the existing table to
    1287             :   // accumulate destroyed frames, and NOT clear mDestroyedFrames on exit.
    1288             :   // We use a MaybeClearDestroyedFrames helper to conditionally reset the
    1289             :   // mDestroyedFrames pointer when this method returns.
    1290             :   typedef decltype(mDestroyedFrames) DestroyedFramesT;
    1291             :   class MOZ_RAII MaybeClearDestroyedFrames
    1292             :   {
    1293             :   private:
    1294             :     DestroyedFramesT& mDestroyedFramesRef; // ref to caller's mDestroyedFrames
    1295             :     const bool        mResetOnDestruction;
    1296             :   public:
    1297             :     explicit MaybeClearDestroyedFrames(DestroyedFramesT& aTarget)
    1298          26 :       : mDestroyedFramesRef(aTarget)
    1299          52 :       , mResetOnDestruction(!aTarget) // reset only if target starts out null
    1300             :     {
    1301             :     }
    1302           0 :     ~MaybeClearDestroyedFrames()
    1303           0 :     {
    1304          26 :       if (mResetOnDestruction) {
    1305           0 :         mDestroyedFramesRef.reset(nullptr);
    1306             :       }
    1307          26 :     }
    1308             :   };
    1309             : 
    1310           0 :   MaybeClearDestroyedFrames maybeClear(mDestroyedFrames);
    1311          52 :   if (!mDestroyedFrames) {
    1312          26 :     mDestroyedFrames = MakeUnique<nsTHashtable<nsPtrHashKey<const nsIFrame>>>();
    1313             :   }
    1314             : 
    1315           0 :   AUTO_PROFILER_LABEL("RestyleManager::ProcessRestyledFrames", LAYOUT);
    1316             : 
    1317          26 :   nsPresContext* presContext = PresContext();
    1318          26 :   nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor();
    1319             : 
    1320             :   // Handle nsChangeHint_CSSOverflowChange, by either updating the
    1321             :   // scrollbars on the viewport, or upgrading the change hint to frame-reconstruct.
    1322           0 :   for (nsStyleChangeData& data : aChangeList) {
    1323           0 :     if (data.mHint & nsChangeHint_CSSOverflowChange) {
    1324           0 :       data.mHint &= ~nsChangeHint_CSSOverflowChange;
    1325           0 :       bool doReconstruct = true; // assume the worst
    1326             : 
    1327             :       // Only bother with this if we're html/body, since:
    1328             :       //  (a) It'd be *expensive* to reframe these particular nodes.  They're
    1329             :       //      at the root, so reframing would mean rebuilding the world.
    1330             :       //  (b) It's often *unnecessary* to reframe for "overflow" changes on
    1331             :       //      these particular nodes.  In general, the only reason we reframe
    1332             :       //      for "overflow" changes is so we can construct (or destroy) a
    1333             :       //      scrollframe & scrollbars -- and the html/body nodes often don't
    1334             :       //      need their own scrollframe/scrollbars because they coopt the ones
    1335             :       //      on the viewport (which always exist). So depending on whether
    1336             :       //      that's happening, we can skip the reframe for these nodes.
    1337           0 :       if (data.mContent->IsAnyOfHTMLElements(nsGkAtoms::body,
    1338             :                                              nsGkAtoms::html)) {
    1339             :         // If the restyled element provided/provides the scrollbar styles for
    1340             :         // the viewport before and/or after this restyle, AND it's not coopting
    1341             :         // that responsibility from some other element (which would need
    1342             :         // reconstruction to make its own scrollframe now), THEN: we don't need
    1343             :         // to reconstruct - we can just reflow, because no scrollframe is being
    1344             :         // added/removed.
    1345             :         nsIContent* prevOverrideNode =
    1346           0 :           presContext->GetViewportScrollbarStylesOverrideElement();
    1347             :         nsIContent* newOverrideNode =
    1348           0 :           presContext->UpdateViewportScrollbarStylesOverride();
    1349             : 
    1350           0 :         if (data.mContent == prevOverrideNode ||
    1351           0 :             data.mContent == newOverrideNode) {
    1352             :           // If we get here, the restyled element provided the scrollbar styles
    1353             :           // for viewport before this restyle, OR it will provide them after.
    1354           0 :           if (!prevOverrideNode || !newOverrideNode ||
    1355             :               prevOverrideNode == newOverrideNode) {
    1356             :             // If we get here, the restyled element is NOT replacing (or being
    1357             :             // replaced by) some other element as the viewport's
    1358             :             // scrollbar-styles provider. (If it were, we'd potentially need to
    1359             :             // reframe to create a dedicated scrollframe for whichever element
    1360             :             // is being booted from providing viewport scrollbar styles.)
    1361             :             //
    1362             :             // Under these conditions, we're OK to assume that this "overflow"
    1363             :             // change only impacts the root viewport's scrollframe, which
    1364             :             // already exists, so we can simply reflow instead of reframing.
    1365             :             // When requesting this reflow, we send the exact same change hints
    1366             :             // that "width" and "height" would send (since conceptually,
    1367             :             // adding/removing scrollbars is like changing the available
    1368             :             // space).
    1369             :             data.mHint |= (nsChangeHint_ReflowHintsForISizeChange |
    1370           0 :                            nsChangeHint_ReflowHintsForBSizeChange);
    1371           0 :             doReconstruct = false;
    1372             :           }
    1373             :         }
    1374             :       }
    1375           0 :       if (doReconstruct) {
    1376           0 :         data.mHint |= nsChangeHint_ReconstructFrame;
    1377             :       }
    1378             :     }
    1379             :   }
    1380             : 
    1381           0 :   bool didUpdateCursor = false;
    1382             : 
    1383          98 :   for (size_t i = 0; i < aChangeList.Length(); ++i) {
    1384             : 
    1385             :     // Collect and coalesce adjacent siblings for lazy frame construction.
    1386             :     // Eventually it would be even better to make RecreateFramesForContent
    1387             :     // accept a range and coalesce all adjacent reconstructs (bug 1344139).
    1388             :     size_t lazyRangeStart = i;
    1389           0 :     while (i < aChangeList.Length() &&
    1390           0 :            aChangeList[i].mContent &&
    1391           0 :            aChangeList[i].mContent->HasFlag(NODE_NEEDS_FRAME) &&
    1392           0 :            (i == lazyRangeStart ||
    1393          32 :             NextSiblingWhichMayHaveFrame(aChangeList[i - 1].mContent) ==
    1394           0 :               aChangeList[i].mContent))
    1395             :     {
    1396           0 :       MOZ_ASSERT(aChangeList[i].mHint & nsChangeHint_ReconstructFrame);
    1397          26 :       MOZ_ASSERT(!aChangeList[i].mFrame);
    1398           0 :       ++i;
    1399             :     }
    1400           0 :     if (i != lazyRangeStart) {
    1401           0 :       nsIContent* start = aChangeList[lazyRangeStart].mContent;
    1402          54 :       nsIContent* end = NextSiblingWhichMayHaveFrame(aChangeList[i-1].mContent);
    1403          18 :       if (!end) {
    1404             :         frameConstructor->ContentAppended(
    1405             :             start,
    1406          18 :             nsCSSFrameConstructor::InsertionKind::Sync);
    1407             :       } else {
    1408             :         frameConstructor->ContentRangeInserted(
    1409             :             start,
    1410             :             end,
    1411             :             nullptr,
    1412           0 :             nsCSSFrameConstructor::InsertionKind::Sync);
    1413             :       }
    1414             :     }
    1415          92 :     for (size_t j = lazyRangeStart; j < i; ++j) {
    1416          56 :       MOZ_ASSERT(!aChangeList[j].mContent->GetPrimaryFrame() ||
    1417             :                  !aChangeList[j].mContent->HasFlag(NODE_NEEDS_FRAME));
    1418             :     }
    1419          80 :     if (i == aChangeList.Length()) {
    1420             :       break;
    1421             :     }
    1422             : 
    1423           0 :     const nsStyleChangeData& data = aChangeList[i];
    1424           0 :     nsIFrame* frame = data.mFrame;
    1425           0 :     nsIContent* content = data.mContent;
    1426          23 :     nsChangeHint hint = data.mHint;
    1427           0 :     bool didReflowThisFrame = false;
    1428             : 
    1429          60 :     NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) ||
    1430             :                  (hint & nsChangeHint_NeedReflow),
    1431             :                  "Reflow hint bits set without actually asking for a reflow");
    1432             : 
    1433             :     // skip any frame that has been destroyed due to a ripple effect
    1434          46 :     if (frame && mDestroyedFrames->Contains(frame)) {
    1435             :       continue;
    1436             :     }
    1437             : 
    1438          46 :     if (frame && frame->GetContent() != content) {
    1439             :       // XXXbz this is due to image maps messing with the primary frame of
    1440             :       // <area>s.  See bug 135040.  Remove this block once that's fixed.
    1441           0 :       frame = nullptr;
    1442           0 :       if (!(hint & nsChangeHint_ReconstructFrame)) {
    1443             :         continue;
    1444             :       }
    1445             :     }
    1446             : 
    1447           0 :     if ((hint & nsChangeHint_UpdateContainingBlock) && frame &&
    1448           0 :         !(hint & nsChangeHint_ReconstructFrame)) {
    1449           0 :       if (NeedToReframeForAddingOrRemovingTransform(frame) ||
    1450           0 :           frame->IsFieldSetFrame() ||
    1451           0 :           frame->GetContentInsertionFrame() != frame) {
    1452             :         // The frame has positioned children that need to be reparented, or
    1453             :         // it can't easily be converted to/from being an abs-pos container
    1454             :         // correctly.
    1455             :         hint |= nsChangeHint_ReconstructFrame;
    1456             :       } else {
    1457           0 :         for (nsIFrame* cont = frame; cont;
    1458             :              cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1459             :           // Normally frame construction would set state bits as needed,
    1460             :           // but we're not going to reconstruct the frame so we need to set them.
    1461             :           // It's because we need to set this state on each affected frame
    1462             :           // that we can't coalesce nsChangeHint_UpdateContainingBlock hints up
    1463             :           // to ancestors (i.e. it can't be an change hint that is handled for
    1464             :           // descendants).
    1465           0 :           if (cont->IsAbsPosContainingBlock()) {
    1466           0 :             if (!cont->IsAbsoluteContainer() &&
    1467           0 :                 (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
    1468           0 :               cont->MarkAsAbsoluteContainingBlock();
    1469             :             }
    1470             :           } else {
    1471           0 :             if (cont->IsAbsoluteContainer()) {
    1472           0 :               if (cont->HasAbsolutelyPositionedChildren()) {
    1473             :                 // If |cont| still has absolutely positioned children,
    1474             :                 // we can't call MarkAsNotAbsoluteContainingBlock.  This
    1475             :                 // will remove a frame list that still has children in
    1476             :                 // it that we need to keep track of.
    1477             :                 // The optimization of removing it isn't particularly
    1478             :                 // important, although it does mean we skip some tests.
    1479           0 :                 NS_WARNING("skipping removal of absolute containing block");
    1480             :               } else {
    1481           0 :                 cont->MarkAsNotAbsoluteContainingBlock();
    1482             :               }
    1483             :             }
    1484             :           }
    1485             :         }
    1486             :       }
    1487             :     }
    1488             : 
    1489           0 :     if ((hint & nsChangeHint_AddOrRemoveTransform) && frame &&
    1490           0 :         !(hint & nsChangeHint_ReconstructFrame)) {
    1491           0 :       for (nsIFrame* cont = frame; cont;
    1492             :            cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1493           0 :         if (cont->StyleDisplay()->HasTransform(cont)) {
    1494             :           cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
    1495             :         }
    1496             :         // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still be
    1497             :         // transformed by other means. It's OK to have the bit even if it's
    1498             :         // not needed.
    1499             :       }
    1500             :     }
    1501             : 
    1502          46 :     if (hint & nsChangeHint_ReconstructFrame) {
    1503             :       // If we ever start passing true here, be careful of restyles
    1504             :       // that involve a reframe and animations.  In particular, if the
    1505             :       // restyle we're processing here is an animation restyle, but
    1506             :       // the style resolution we will do for the frame construction
    1507             :       // happens async when we're not in an animation restyle already,
    1508             :       // problems could arise.
    1509             :       // We could also have problems with triggering of CSS transitions
    1510             :       // on elements whose frames are reconstructed, since we depend on
    1511             :       // the reconstruction happening synchronously.
    1512             :       frameConstructor->RecreateFramesForContent(
    1513           0 :         content, nsCSSFrameConstructor::InsertionKind::Sync);
    1514             :     } else {
    1515           0 :       NS_ASSERTION(frame, "This shouldn't happen");
    1516             : 
    1517          32 :       if (!frame->FrameMaintainsOverflow()) {
    1518             :         // frame does not maintain overflow rects, so avoid calling
    1519             :         // FinishAndStoreOverflow on it:
    1520             :         hint &= ~(nsChangeHint_UpdateOverflow |
    1521             :                   nsChangeHint_ChildrenOnlyTransform |
    1522             :                   nsChangeHint_UpdatePostTransformOverflow |
    1523             :                   nsChangeHint_UpdateParentOverflow);
    1524             :       }
    1525             : 
    1526          32 :       if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) {
    1527             :         // Frame can not be transformed, and thus a change in transform will
    1528             :         // have no effect and we should not use the
    1529             :         // nsChangeHint_UpdatePostTransformOverflow hint.
    1530             :         hint &= ~nsChangeHint_UpdatePostTransformOverflow;
    1531             :       }
    1532             : 
    1533          32 :       if (hint & nsChangeHint_AddOrRemoveTransform) {
    1534             :         // When dropping a running transform animation we will first add an
    1535             :         // nsChangeHint_UpdateTransformLayer hint as part of the animation-only
    1536             :         // restyle. During the subsequent regular restyle, if the animation was
    1537             :         // the only reason the element had any transform applied, we will add
    1538             :         // nsChangeHint_AddOrRemoveTransform as part of the regular restyle.
    1539             :         //
    1540             :         // With the Gecko backend, these two change hints are processed
    1541             :         // after each restyle but when using the Servo backend they accumulate
    1542             :         // and are processed together after we have already removed the
    1543             :         // transform as part of the regular restyle. Since we don't actually
    1544             :         // need the nsChangeHint_UpdateTransformLayer hint if we already have
    1545             :         // a nsChangeHint_AddOrRemoveTransform hint, and since we
    1546             :         // will fail an assertion in ApplyRenderingChangeToTree if we try
    1547             :         // specify nsChangeHint_UpdateTransformLayer but don't have any
    1548             :         // transform style, we just drop the unneeded hint here.
    1549             :         hint &= ~nsChangeHint_UpdateTransformLayer;
    1550             :       }
    1551             : 
    1552          32 :       if (hint & nsChangeHint_UpdateEffects) {
    1553           0 :         for (nsIFrame* cont = frame; cont;
    1554             :              cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1555           0 :           SVGObserverUtils::UpdateEffects(cont);
    1556             :         }
    1557             :       }
    1558           0 :       if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
    1559           0 :           ((hint & nsChangeHint_UpdateOpacityLayer) &&
    1560           0 :            frame->IsFrameOfType(nsIFrame::eSVG) &&
    1561           0 :            !(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))) {
    1562           0 :         SVGObserverUtils::InvalidateRenderingObservers(frame);
    1563           0 :         frame->SchedulePaint();
    1564             :       }
    1565           0 :       if (hint & nsChangeHint_NeedReflow) {
    1566          12 :         StyleChangeReflow(frame, hint);
    1567          12 :         didReflowThisFrame = true;
    1568             :       }
    1569             : 
    1570             :       // Here we need to propagate repaint frame change hint instead of update
    1571             :       // opacity layer change hint when we do opacity optimization for SVG.
    1572             :       // We can't do it in nsStyleEffects::CalcDifference() just like we do
    1573             :       // for the optimization for 0.99 over opacity values since we have no way
    1574             :       // to call nsSVGUtils::CanOptimizeOpacity() there.
    1575           0 :       if ((hint & nsChangeHint_UpdateOpacityLayer) &&
    1576           0 :           nsSVGUtils::CanOptimizeOpacity(frame) &&
    1577           0 :           frame->IsFrameOfType(nsIFrame::eSVGGeometry)) {
    1578           0 :         hint &= ~nsChangeHint_UpdateOpacityLayer;
    1579             :         hint |= nsChangeHint_RepaintFrame;
    1580             :       }
    1581             : 
    1582           0 :       if ((hint & nsChangeHint_UpdateUsesOpacity) &&
    1583           4 :           frame->IsFrameOfType(nsIFrame::eTablePart)) {
    1584           0 :         NS_ASSERTION(hint & nsChangeHint_UpdateOpacityLayer,
    1585             :                      "should only return UpdateUsesOpacity hint "
    1586             :                      "when also returning UpdateOpacityLayer hint");
    1587             :         // When an internal table part (including cells) changes between
    1588             :         // having opacity 1 and non-1, it changes whether its
    1589             :         // backgrounds (and those of table parts inside of it) are
    1590             :         // painted as part of the table's nsDisplayTableBorderBackground
    1591             :         // display item, or part of its own display item.  That requires
    1592             :         // invalidation, so change UpdateOpacityLayer to RepaintFrame.
    1593           0 :         hint &= ~nsChangeHint_UpdateOpacityLayer;
    1594             :         hint |= nsChangeHint_RepaintFrame;
    1595             :       }
    1596             : 
    1597             :       // Opacity disables preserve-3d, so if we toggle it, then we also need
    1598             :       // to update the overflow areas of all potentially affected frames.
    1599          36 :       if ((hint & nsChangeHint_UpdateUsesOpacity) &&
    1600           4 :           frame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
    1601             :         hint |= nsChangeHint_UpdateSubtreeOverflow;
    1602             :       }
    1603             : 
    1604          32 :       if (hint & nsChangeHint_UpdateBackgroundPosition) {
    1605             :         // For most frame types, DLBI can detect background position changes,
    1606             :         // so we only need to schedule a paint.
    1607           0 :         hint |= nsChangeHint_SchedulePaint;
    1608           0 :         if (frame->IsFrameOfType(nsIFrame::eTablePart) ||
    1609           0 :             frame->IsFrameOfType(nsIFrame::eMathML)) {
    1610             :           // Table parts and MathML frames don't build display items for their
    1611             :           // backgrounds, so DLBI can't detect background-position changes for
    1612             :           // these frames. Repaint the whole frame.
    1613             :           hint |= nsChangeHint_RepaintFrame;
    1614             :         }
    1615             :       }
    1616             : 
    1617          32 :       if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
    1618             :                   nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
    1619             :                   nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
    1620           0 :         ApplyRenderingChangeToTree(presContext->PresShell(), frame, hint);
    1621             :       }
    1622          32 :       if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
    1623           0 :         ActiveLayerTracker::NotifyOffsetRestyle(frame);
    1624             :         // It is possible for this to fall back to a reflow
    1625           0 :         if (!RecomputePosition(frame)) {
    1626           0 :           didReflowThisFrame = true;
    1627             :         }
    1628             :       }
    1629          32 :       NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
    1630             :                    (hint & nsChangeHint_UpdateOverflow),
    1631             :                    "nsChangeHint_UpdateOverflow should be passed too");
    1632          20 :       if (!didReflowThisFrame &&
    1633           8 :           (hint & (nsChangeHint_UpdateOverflow |
    1634             :                    nsChangeHint_UpdatePostTransformOverflow |
    1635             :                    nsChangeHint_UpdateParentOverflow |
    1636             :                    nsChangeHint_UpdateSubtreeOverflow))) {
    1637           0 :         if (hint & nsChangeHint_UpdateSubtreeOverflow) {
    1638           0 :           for (nsIFrame* cont = frame; cont; cont =
    1639             :                  nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1640           0 :             AddSubtreeToOverflowTracker(cont, mOverflowChangedTracker);
    1641             :           }
    1642             :           // The work we just did in AddSubtreeToOverflowTracker
    1643             :           // subsumes some of the other hints:
    1644             :           hint &= ~(nsChangeHint_UpdateOverflow |
    1645             :                     nsChangeHint_UpdatePostTransformOverflow);
    1646             :         }
    1647           0 :         if (hint & nsChangeHint_ChildrenOnlyTransform) {
    1648             :           // The overflow areas of the child frames need to be updated:
    1649           0 :           nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame);
    1650           0 :           nsIFrame* childFrame = hintFrame->PrincipalChildList().FirstChild();
    1651           0 :           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame),
    1652             :                        "SVG frames should not have continuations "
    1653             :                        "or ib-split siblings");
    1654           0 :           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame),
    1655             :                        "SVG frames should not have continuations "
    1656             :                        "or ib-split siblings");
    1657           0 :           for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
    1658           0 :             MOZ_ASSERT(childFrame->IsFrameOfType(nsIFrame::eSVG),
    1659             :                        "Not expecting non-SVG children");
    1660             :             // If |childFrame| is dirty or has dirty children, we don't bother
    1661             :             // updating overflows since that will happen when it's reflowed.
    1662           0 :             if (!(childFrame->GetStateBits() &
    1663             :                   (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
    1664           0 :               mOverflowChangedTracker.AddFrame(childFrame,
    1665           0 :                                         OverflowChangedTracker::CHILDREN_CHANGED);
    1666             :             }
    1667           0 :             NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame),
    1668             :                          "SVG frames should not have continuations "
    1669             :                          "or ib-split siblings");
    1670           0 :             NS_ASSERTION(childFrame->GetParent() == hintFrame,
    1671             :                          "SVG child frame not expected to have different parent");
    1672             :           }
    1673             :         }
    1674             :         // If |frame| is dirty or has dirty children, we don't bother updating
    1675             :         // overflows since that will happen when it's reflowed.
    1676           0 :         if (!(frame->GetStateBits() &
    1677             :               (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
    1678           0 :           if (hint & (nsChangeHint_UpdateOverflow |
    1679             :                       nsChangeHint_UpdatePostTransformOverflow)) {
    1680             :             OverflowChangedTracker::ChangeKind changeKind;
    1681             :             // If we have both nsChangeHint_UpdateOverflow and
    1682             :             // nsChangeHint_UpdatePostTransformOverflow,
    1683             :             // CHILDREN_CHANGED is selected as it is
    1684             :             // strictly stronger.
    1685           0 :             if (hint & nsChangeHint_UpdateOverflow) {
    1686             :               changeKind = OverflowChangedTracker::CHILDREN_CHANGED;
    1687             :             } else {
    1688           0 :               changeKind = OverflowChangedTracker::TRANSFORM_CHANGED;
    1689             :             }
    1690           0 :             for (nsIFrame* cont = frame; cont; cont =
    1691             :                    nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1692           0 :               mOverflowChangedTracker.AddFrame(cont, changeKind);
    1693             :             }
    1694             :           }
    1695             :           // UpdateParentOverflow hints need to be processed in addition
    1696             :           // to the above, since if the processing of the above hints
    1697             :           // yields no change, the update will not propagate to the
    1698             :           // parent.
    1699           0 :           if (hint & nsChangeHint_UpdateParentOverflow) {
    1700           0 :             MOZ_ASSERT(frame->GetParent(),
    1701             :                        "shouldn't get style hints for the root frame");
    1702           0 :             for (nsIFrame* cont = frame; cont; cont =
    1703             :                    nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1704           0 :               mOverflowChangedTracker.AddFrame(cont->GetParent(),
    1705           0 :                                    OverflowChangedTracker::CHILDREN_CHANGED);
    1706             :             }
    1707             :           }
    1708             :         }
    1709             :       }
    1710           0 :       if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
    1711           0 :         presContext->PresShell()->SynthesizeMouseMove(false);
    1712           0 :         didUpdateCursor = true;
    1713             :       }
    1714          32 :       if (hint & nsChangeHint_UpdateWidgetProperties) {
    1715           0 :         frame->UpdateWidgetProperties();
    1716             :       }
    1717          32 :       if (hint & nsChangeHint_UpdateTableCellSpans) {
    1718           0 :         frameConstructor->UpdateTableCellSpans(content);
    1719             :       }
    1720          16 :       if (hint & nsChangeHint_VisibilityChange) {
    1721          12 :         frame->UpdateVisibleDescendantsState();
    1722             :       }
    1723             :     }
    1724             :   }
    1725             : 
    1726          26 :   aChangeList.Clear();
    1727             : }
    1728             : 
    1729             : /* static */ uint64_t
    1730           0 : RestyleManager::GetAnimationGenerationForFrame(nsIFrame* aFrame)
    1731             : {
    1732          23 :   EffectSet* effectSet = EffectSet::GetEffectSet(aFrame);
    1733          23 :   return effectSet ? effectSet->GetAnimationGeneration() : 0;
    1734             : }
    1735             : 
    1736             : void
    1737           2 : RestyleManager::IncrementAnimationGeneration()
    1738             : {
    1739             :   // We update the animation generation at start of each call to
    1740             :   // ProcessPendingRestyles so we should ignore any subsequent (redundant)
    1741             :   // calls that occur while we are still processing restyles.
    1742           2 :   if (!mInStyleRefresh) {
    1743           0 :     ++mAnimationGeneration;
    1744             :   }
    1745           2 : }
    1746             : 
    1747             : /* static */ void
    1748          23 : RestyleManager::AddLayerChangesForAnimation(nsIFrame* aFrame,
    1749             :                                             nsIContent* aContent,
    1750             :                                             nsStyleChangeList&
    1751             :                                               aChangeListToProcess)
    1752             : {
    1753          23 :   if (!aFrame || !aContent) {
    1754             :     return;
    1755             :   }
    1756             : 
    1757             :   uint64_t frameGeneration =
    1758           0 :     RestyleManager::GetAnimationGenerationForFrame(aFrame);
    1759             : 
    1760           0 :   nsChangeHint hint = nsChangeHint(0);
    1761          46 :   for (const LayerAnimationInfo::Record& layerInfo :
    1762           0 :          LayerAnimationInfo::sRecords) {
    1763             :     layers::Layer* layer =
    1764          46 :       FrameLayerBuilder::GetDedicatedLayer(aFrame, layerInfo.mLayerType);
    1765          46 :     if (layer && frameGeneration != layer->GetAnimationGeneration()) {
    1766             :       // If we have a transform layer but don't have any transform style, we
    1767             :       // probably just removed the transform but haven't destroyed the layer
    1768             :       // yet. In this case we will add the appropriate change hint
    1769             :       // (nsChangeHint_UpdateContainingBlock) when we compare styles so we can
    1770             :       // skip adding any change hint here. (If we *were* to add
    1771             :       // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
    1772             :       // complain that we're updating a transform layer without a transform).
    1773           0 :       if (layerInfo.mLayerType == DisplayItemType::TYPE_TRANSFORM &&
    1774           0 :           !aFrame->StyleDisplay()->HasTransformStyle()) {
    1775             :         continue;
    1776             :       }
    1777           0 :       hint |= layerInfo.mChangeHint;
    1778             :     }
    1779             : 
    1780             :     // We consider it's the first paint for the frame if we have an animation
    1781             :     // for the property but have no layer.
    1782             :     // Note that in case of animations which has properties preventing running
    1783             :     // on the compositor, e.g., width or height, corresponding layer is not
    1784             :     // created at all, but even in such cases, we normally set valid change
    1785             :     // hint for such animations in each tick, i.e. restyles in each tick. As
    1786             :     // a result, we usually do restyles for such animations in every tick on
    1787             :     // the main-thread.  The only animations which will be affected by this
    1788             :     // explicit change hint are animations that have opacity/transform but did
    1789             :     // not have those properies just before. e.g, setting transform by
    1790             :     // setKeyframes or changing target element from other target which prevents
    1791             :     // running on the compositor, etc.
    1792           0 :     if (!layer &&
    1793          46 :         nsLayoutUtils::HasEffectiveAnimation(aFrame, layerInfo.mProperty)) {
    1794           2 :       hint |= layerInfo.mChangeHint;
    1795             :     }
    1796             :   }
    1797             : 
    1798          23 :   if (hint) {
    1799           2 :     aChangeListToProcess.AppendChange(aFrame, aContent, hint);
    1800             :   }
    1801             : }
    1802             : 
    1803         160 : RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
    1804           0 :                                                 RestyleManager* aRestyleManager)
    1805             :   : mRestyleManager(aRestyleManager)
    1806           0 :   , mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
    1807             : {
    1808           0 :   MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
    1809             :              "shouldn't construct recursively");
    1810         160 :   mRestyleManager->mAnimationsWithDestroyedFrame = this;
    1811         160 : }
    1812             : 
    1813             : void
    1814         160 : RestyleManager::AnimationsWithDestroyedFrame
    1815             :               ::StopAnimationsForElementsWithoutFrames()
    1816             : {
    1817           0 :   StopAnimationsWithoutFrame(mContents, CSSPseudoElementType::NotPseudo);
    1818           0 :   StopAnimationsWithoutFrame(mBeforeContents, CSSPseudoElementType::before);
    1819         160 :   StopAnimationsWithoutFrame(mAfterContents, CSSPseudoElementType::after);
    1820         160 : }
    1821             : 
    1822             : void
    1823         480 : RestyleManager::AnimationsWithDestroyedFrame
    1824             :               ::StopAnimationsWithoutFrame(
    1825             :                   nsTArray<RefPtr<nsIContent>>& aArray,
    1826             :                   CSSPseudoElementType aPseudoType)
    1827             : {
    1828             :   nsAnimationManager* animationManager =
    1829           0 :     mRestyleManager->PresContext()->AnimationManager();
    1830             :   nsTransitionManager* transitionManager =
    1831           0 :     mRestyleManager->PresContext()->TransitionManager();
    1832           0 :   for (nsIContent* content : aArray) {
    1833           2 :     if (aPseudoType == CSSPseudoElementType::NotPseudo) {
    1834           2 :       if (content->GetPrimaryFrame()) {
    1835             :         continue;
    1836             :       }
    1837           0 :     } else if (aPseudoType == CSSPseudoElementType::before) {
    1838           0 :       if (nsLayoutUtils::GetBeforeFrame(content)) {
    1839             :         continue;
    1840             :       }
    1841           0 :     } else if (aPseudoType == CSSPseudoElementType::after) {
    1842           0 :       if (nsLayoutUtils::GetAfterFrame(content)) {
    1843             :         continue;
    1844             :       }
    1845             :     }
    1846           0 :     dom::Element* element = content->AsElement();
    1847             : 
    1848           0 :     animationManager->StopAnimationsForElement(element, aPseudoType);
    1849           0 :     transitionManager->StopAnimationsForElement(element, aPseudoType);
    1850             : 
    1851             :     // All other animations should keep running but not running on the
    1852             :     // *compositor* at this point.
    1853           0 :     EffectSet* effectSet = EffectSet::GetEffectSet(element, aPseudoType);
    1854           0 :     if (effectSet) {
    1855           0 :       for (KeyframeEffect* effect : *effectSet) {
    1856           0 :         effect->ResetIsRunningOnCompositor();
    1857             :       }
    1858             :     }
    1859             :   }
    1860         480 : }
    1861             : 
    1862             : #ifdef DEBUG
    1863             : static bool
    1864           0 : IsAnonBox(const nsIFrame& aFrame)
    1865             : {
    1866         790 :   return aFrame.Style()->IsAnonBox();
    1867             : }
    1868             : 
    1869             : static const nsIFrame*
    1870           0 : FirstContinuationOrPartOfIBSplit(const nsIFrame* aFrame)
    1871             : {
    1872         437 :   if (!aFrame) {
    1873             :     return nullptr;
    1874             :   }
    1875             : 
    1876         437 :   return nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
    1877             : }
    1878             : 
    1879             : static const nsIFrame*
    1880           0 : ExpectedOwnerForChild(const nsIFrame& aFrame)
    1881             : {
    1882           0 :   const nsIFrame* parent = aFrame.GetParent();
    1883           0 :   if (aFrame.IsTableFrame()) {
    1884           0 :     MOZ_ASSERT(parent->IsTableWrapperFrame());
    1885           0 :     parent = parent->GetParent();
    1886             :   }
    1887             : 
    1888           1 :   if (IsAnonBox(aFrame) && !aFrame.IsTextFrame()) {
    1889           2 :     if (parent->IsLineFrame()) {
    1890           0 :       parent = parent->GetParent();
    1891             :     }
    1892           2 :     return parent->IsViewportFrame() ?
    1893             :       nullptr : FirstContinuationOrPartOfIBSplit(parent);
    1894             :   }
    1895             : 
    1896         353 :   if (aFrame.IsBulletFrame()) {
    1897           0 :     return FirstContinuationOrPartOfIBSplit(parent);
    1898             :   }
    1899             : 
    1900         353 :   if (aFrame.IsLineFrame()) {
    1901             :     // A ::first-line always ends up here via its block, which is therefore the
    1902             :     // right expected owner.  That block can be an
    1903             :     // anonymous box.  For example, we could have a ::first-line on a columnated
    1904             :     // block; the blockframe is the column-content anonymous box in that case.
    1905             :     // So we don't want to end up in the code below, which steps out of anon
    1906             :     // boxes.  Just return the parent of the line frame, which is the block.
    1907             :     return parent;
    1908             :   }
    1909             : 
    1910         353 :   if (aFrame.IsLetterFrame()) {
    1911             :     // Ditto for ::first-letter. A first-letter always arrives here via its
    1912             :     // direct parent, except when it's parented to a ::first-line.
    1913           0 :     if (parent->IsLineFrame()) {
    1914           0 :       parent = parent->GetParent();
    1915             :     }
    1916           0 :     return FirstContinuationOrPartOfIBSplit(parent);
    1917             :   }
    1918             : 
    1919         353 :   if (parent->IsLetterFrame()) {
    1920             :     // Things never have ::first-letter as their expected parent.  Go
    1921             :     // on up to the ::first-letter's parent.
    1922           0 :     parent = parent->GetParent();
    1923             :   }
    1924             : 
    1925         353 :   parent = FirstContinuationOrPartOfIBSplit(parent);
    1926             : 
    1927             :   // We've handled already anon boxes and bullet frames, so now we're looking at
    1928             :   // a frame of a DOM element or pseudo. Hop through anon and line-boxes
    1929             :   // generated by our DOM parent, and go find the owner frame for it.
    1930           0 :   while (parent && (IsAnonBox(*parent) || parent->IsLineFrame())) {
    1931           0 :     auto* pseudo = parent->Style()->GetPseudo();
    1932           0 :     if (pseudo == nsCSSAnonBoxes::tableWrapper) {
    1933           0 :       const nsIFrame* tableFrame = parent->PrincipalChildList().FirstChild();
    1934           0 :       MOZ_ASSERT(tableFrame->IsTableFrame());
    1935             :       // Handle :-moz-table and :-moz-inline-table.
    1936           0 :       parent = IsAnonBox(*tableFrame) ? parent->GetParent() : tableFrame;
    1937             :     } else {
    1938             :       // We get the in-flow parent here so that we can handle the OOF anonymous
    1939             :       // boxed to get the correct parent.
    1940           0 :       parent = parent->GetInFlowParent();
    1941             :     }
    1942          82 :     parent = FirstContinuationOrPartOfIBSplit(parent);
    1943             :   }
    1944             : 
    1945             :   return parent;
    1946             : }
    1947             : 
    1948             : void
    1949           0 : ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const
    1950             : {
    1951         216 :   MOZ_ASSERT(mOwner);
    1952         432 :   MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
    1953             :   // We allow aParent.mOwner to be null, for cases when we're not starting at
    1954             :   // the root of the tree.  We also allow aParent.mOwner to be somewhere up our
    1955             :   // expected owner chain not our immediate owner, which allows us creating long
    1956             :   // chains of ServoRestyleStates in some cases where it's just not worth it.
    1957             : #ifdef DEBUG
    1958           0 :   if (aParent.mOwner) {
    1959           0 :     const nsIFrame* owner = ExpectedOwnerForChild(*mOwner);
    1960         174 :     if (owner != aParent.mOwner) {
    1961           0 :       MOZ_ASSERT(IsAnonBox(*owner),
    1962             :                  "Should only have expected owner weirdness when anon boxes are involved");
    1963             :       bool found = false;
    1964           0 :       for (; owner; owner = ExpectedOwnerForChild(*owner)) {
    1965           0 :         if (owner == aParent.mOwner) {
    1966             :           found = true;
    1967             :           break;
    1968             :         }
    1969             :       }
    1970           0 :       MOZ_ASSERT(found, "Must have aParent.mOwner on our expected owner chain");
    1971             :     }
    1972             :   }
    1973             : #endif
    1974         216 : }
    1975             : 
    1976             : nsChangeHint
    1977           0 : ServoRestyleState::ChangesHandledFor(const nsIFrame& aFrame) const
    1978             : {
    1979         223 :   if (!mOwner) {
    1980          42 :     MOZ_ASSERT(!mChangesHandled);
    1981             :     return mChangesHandled;
    1982             :   }
    1983             : 
    1984           0 :   MOZ_ASSERT(mOwner == ExpectedOwnerForChild(aFrame),
    1985             :              "Missed some frame in the hierarchy?");
    1986         181 :   return mChangesHandled;
    1987             : }
    1988             : #endif
    1989             : 
    1990             : void
    1991           0 : ServoRestyleState::AddPendingWrapperRestyle(nsIFrame* aWrapperFrame)
    1992             : {
    1993           0 :   MOZ_ASSERT(aWrapperFrame->Style()->IsWrapperAnonBox(),
    1994             :              "All our wrappers are anon boxes, and why would we restyle "
    1995             :              "non-inheriting ones?");
    1996           0 :   MOZ_ASSERT(aWrapperFrame->Style()->IsInheritingAnonBox(),
    1997             :              "All our wrappers are anon boxes, and why would we restyle "
    1998             :              "non-inheriting ones?");
    1999           0 :   MOZ_ASSERT(aWrapperFrame->Style()->GetPseudo() !=
    2000             :              nsCSSAnonBoxes::cellContent,
    2001             :              "Someone should be using TableAwareParentFor");
    2002           0 :   MOZ_ASSERT(aWrapperFrame->Style()->GetPseudo() !=
    2003             :              nsCSSAnonBoxes::tableWrapper,
    2004             :              "Someone should be using TableAwareParentFor");
    2005             :   // Make sure we only add first continuations.
    2006           0 :   aWrapperFrame = aWrapperFrame->FirstContinuation();
    2007           0 :   nsIFrame* last = mPendingWrapperRestyles.SafeLastElement(nullptr);
    2008           0 :   if (last == aWrapperFrame) {
    2009             :     // Already queued up, nothing to do.
    2010             :     return;
    2011             :   }
    2012             : 
    2013             :   // Make sure to queue up parents before children.  But don't queue up
    2014             :   // ancestors of non-anonymous boxes here; those are handled when we traverse
    2015             :   // their non-anonymous kids.
    2016           0 :   if (aWrapperFrame->ParentIsWrapperAnonBox()) {
    2017           0 :     AddPendingWrapperRestyle(TableAwareParentFor(aWrapperFrame));
    2018             :   }
    2019             : 
    2020             :   // If the append fails, we'll fail to restyle properly, but that's probably
    2021             :   // better than crashing.
    2022           0 :   if (mPendingWrapperRestyles.AppendElement(aWrapperFrame, fallible)) {
    2023           0 :     aWrapperFrame->SetIsWrapperAnonBoxNeedingRestyle(true);
    2024             :   }
    2025             : }
    2026             : 
    2027             : void
    2028           0 : ServoRestyleState::ProcessWrapperRestyles(nsIFrame* aParentFrame)
    2029             : {
    2030           0 :   size_t i = mPendingWrapperRestyleOffset;
    2031         444 :   while (i < mPendingWrapperRestyles.Length()) {
    2032           0 :     i += ProcessMaybeNestedWrapperRestyle(aParentFrame, i);
    2033             :   }
    2034             : 
    2035         222 :   mPendingWrapperRestyles.TruncateLength(mPendingWrapperRestyleOffset);
    2036         222 : }
    2037             : 
    2038             : size_t
    2039           0 : ServoRestyleState::ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent,
    2040             :                                                     size_t aIndex)
    2041             : {
    2042             :   // The frame at index aIndex is something we should restyle ourselves, but
    2043             :   // following frames may need separate ServoRestyleStates to restyle.
    2044           0 :   MOZ_ASSERT(aIndex < mPendingWrapperRestyles.Length());
    2045             : 
    2046           0 :   nsIFrame* cur = mPendingWrapperRestyles[aIndex];
    2047           0 :   MOZ_ASSERT(cur->Style()->IsWrapperAnonBox());
    2048             : 
    2049             :   // Where is cur supposed to inherit from?  From its parent frame, except in
    2050             :   // the case when cur is a table, in which case it should be its grandparent.
    2051             :   // Also, not in the case when the resulting frame would be a first-line; in
    2052             :   // that case we should be inheriting from the block, and the first-line will
    2053             :   // do its fixup later if needed.
    2054             :   //
    2055             :   // Note that after we do all that fixup the parent we get might still not be
    2056             :   // aParent; for example aParent could be a scrollframe, in which case we
    2057             :   // should inherit from the scrollcontent frame.  Or the parent might be some
    2058             :   // continuation of aParent.
    2059             :   //
    2060             :   // Try to assert as much as we can about the parent we actually end up using
    2061             :   // without triggering bogus asserts in all those various edge cases.
    2062           0 :   nsIFrame* parent = cur->GetParent();
    2063           0 :   if (cur->IsTableFrame()) {
    2064           0 :     MOZ_ASSERT(parent->IsTableWrapperFrame());
    2065           0 :     parent = parent->GetParent();
    2066             :   }
    2067           0 :   if (parent->IsLineFrame()) {
    2068           0 :     parent = parent->GetParent();
    2069             :   }
    2070           0 :   MOZ_ASSERT(FirstContinuationOrPartOfIBSplit(parent) == aParent ||
    2071             :              (parent->Style()->IsInheritingAnonBox() &&
    2072             :               parent->GetContent() == aParent->GetContent()));
    2073             : 
    2074             :   // Now "this" is a ServoRestyleState for aParent, so if parent is not a next
    2075             :   // continuation (possibly across ib splits) of aParent we need a new
    2076             :   // ServoRestyleState for the kid.
    2077           0 :   Maybe<ServoRestyleState> parentRestyleState;
    2078             :   nsIFrame* parentForRestyle =
    2079           0 :     nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent);
    2080           0 :   if (parentForRestyle != aParent) {
    2081           0 :     parentRestyleState.emplace(*parentForRestyle, *this, nsChangeHint_Empty,
    2082           0 :                                Type::InFlow);
    2083             :   }
    2084             :   ServoRestyleState& curRestyleState =
    2085           0 :     parentRestyleState ? *parentRestyleState : *this;
    2086             : 
    2087             :   // This frame may already have been restyled.  Even if it has, we can't just
    2088             :   // return, because the next frame may be a kid of it that does need restyling.
    2089           0 :   if (cur->IsWrapperAnonBoxNeedingRestyle()) {
    2090           0 :     parentForRestyle->UpdateStyleOfChildAnonBox(cur, curRestyleState);
    2091             :     cur->SetIsWrapperAnonBoxNeedingRestyle(false);
    2092             :   }
    2093             : 
    2094           0 :   size_t numProcessed = 1;
    2095             : 
    2096             :   // Note: no overflow possible here, since aIndex < length.
    2097           0 :   if (aIndex + 1 < mPendingWrapperRestyles.Length()) {
    2098           0 :     nsIFrame* next = mPendingWrapperRestyles[aIndex + 1];
    2099           0 :     if (TableAwareParentFor(next) == cur &&
    2100           0 :         next->IsWrapperAnonBoxNeedingRestyle()) {
    2101             :       // It might be nice if we could do better than nsChangeHint_Empty.  On
    2102             :       // the other hand, presumably our mChangesHandled already has the bits
    2103             :       // we really want here so in practice it doesn't matter.
    2104             :       ServoRestyleState childState(*cur, curRestyleState, nsChangeHint_Empty,
    2105             :                                    Type::InFlow,
    2106           0 :                                    /* aAssertWrapperRestyleLength = */ false);
    2107           0 :       numProcessed += childState.ProcessMaybeNestedWrapperRestyle(cur,
    2108             :                                                                   aIndex + 1);
    2109             :     }
    2110             :   }
    2111             : 
    2112           0 :   return numProcessed;
    2113             : }
    2114             : 
    2115             : nsIFrame*
    2116           0 : ServoRestyleState::TableAwareParentFor(const nsIFrame* aChild)
    2117             : {
    2118             :   // We want to get the anon box parent for aChild. where aChild has
    2119             :   // ParentIsWrapperAnonBox().
    2120             :   //
    2121             :   // For the most part this is pretty straightforward, but there are two
    2122             :   // wrinkles.  First, if aChild is a table, then we really want the parent of
    2123             :   // its table wrapper.
    2124           0 :   if (aChild->IsTableFrame()) {
    2125           0 :     aChild = aChild->GetParent();
    2126           0 :     MOZ_ASSERT(aChild->IsTableWrapperFrame());
    2127             :   }
    2128             : 
    2129           0 :   nsIFrame* parent = aChild->GetParent();
    2130             :   // Now if parent is a cell-content frame, we actually want the cellframe.
    2131           0 :   if (parent->Style()->GetPseudo() == nsCSSAnonBoxes::cellContent) {
    2132           0 :     parent = parent->GetParent();
    2133           0 :   } else if (parent->IsTableWrapperFrame()) {
    2134             :     // Must be a caption.  In that case we want the table here.
    2135           0 :     MOZ_ASSERT(aChild->StyleDisplay()->mDisplay == StyleDisplay::TableCaption);
    2136           0 :     parent = parent->PrincipalChildList().FirstChild();
    2137             :   }
    2138           0 :   return parent;
    2139             : }
    2140             : 
    2141             : void
    2142           9 : RestyleManager::PostRestyleEvent(Element* aElement,
    2143             :                                       nsRestyleHint aRestyleHint,
    2144             :                                       nsChangeHint aMinChangeHint)
    2145             : {
    2146           0 :   MOZ_ASSERT(!(aMinChangeHint & nsChangeHint_NeutralChange),
    2147             :              "Didn't expect explicit change hints to be neutral!");
    2148          27 :   if (MOZ_UNLIKELY(IsDisconnected()) ||
    2149          18 :       MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
    2150             :     return;
    2151             :   }
    2152             : 
    2153             :   // We allow posting restyles from within change hint handling, but not from
    2154             :   // within the restyle algorithm itself.
    2155           0 :   MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
    2156             : 
    2157           9 :   if (aRestyleHint == 0 && !aMinChangeHint) {
    2158             :     return; // Nothing to do.
    2159             :   }
    2160             : 
    2161             :   // Assuming the restyle hints will invalidate cached style for
    2162             :   // getComputedStyle, since we don't know if any of the restyling that we do
    2163             :   // would affect undisplayed elements.
    2164           9 :   if (aRestyleHint) {
    2165           9 :     IncrementUndisplayedRestyleGeneration();
    2166             :   }
    2167             : 
    2168             :   // Processing change hints sometimes causes new change hints to be generated,
    2169             :   // and very occasionally, additional restyle hints. We collect the change
    2170             :   // hints manually to avoid re-traversing the DOM to find them.
    2171           0 :   if (mReentrantChanges && !aRestyleHint) {
    2172           0 :     mReentrantChanges->AppendElement(ReentrantChange { aElement, aMinChangeHint });
    2173           0 :     return;
    2174             :   }
    2175             : 
    2176          18 :   if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
    2177           5 :     mHaveNonAnimationRestyles = true;
    2178             :   }
    2179             : 
    2180          18 :   if (aRestyleHint & eRestyle_LaterSiblings) {
    2181           0 :     aRestyleHint &= ~eRestyle_LaterSiblings;
    2182             : 
    2183           0 :     nsRestyleHint siblingHint = eRestyle_Subtree;
    2184           0 :     Element* current = aElement->GetNextElementSibling();
    2185           0 :     while (current) {
    2186           0 :       Servo_NoteExplicitHints(current, siblingHint, nsChangeHint(0));
    2187           0 :       current = current->GetNextElementSibling();
    2188             :     }
    2189             :   }
    2190             : 
    2191           9 :   if (aRestyleHint || aMinChangeHint) {
    2192           9 :     Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
    2193             :   }
    2194             : }
    2195             : 
    2196             : void
    2197           6 : RestyleManager::PostRestyleEventForAnimations(
    2198             :   Element* aElement,
    2199             :   CSSPseudoElementType aPseudoType,
    2200             :   nsRestyleHint aRestyleHint)
    2201             : {
    2202             :   Element* elementToRestyle =
    2203           0 :     EffectCompositor::GetElementToRestyle(aElement, aPseudoType);
    2204             : 
    2205           6 :   if (!elementToRestyle) {
    2206             :     // FIXME: Bug 1371107: When reframing happens,
    2207             :     // EffectCompositor::mElementsToRestyle still has unbound old pseudo
    2208             :     // element. We should drop it.
    2209           0 :     return;
    2210             :   }
    2211             : 
    2212           0 :   AutoRestyleTimelineMarker marker(mPresContext->GetDocShell(),
    2213          18 :                                    true /* animation-only */);
    2214           6 :   Servo_NoteExplicitHints(elementToRestyle, aRestyleHint, nsChangeHint(0));
    2215             : }
    2216             : 
    2217             : void
    2218           8 : RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
    2219             :                                          nsRestyleHint aRestyleHint)
    2220             : {
    2221             :   // NOTE(emilio): GeckoRestlyeManager does a sync style flush, which seems not
    2222             :   // to be needed in my testing.
    2223           8 :   PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
    2224           8 : }
    2225             : 
    2226             : void
    2227           8 : RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
    2228             :                                                   nsRestyleHint aRestyleHint)
    2229             : {
    2230             :   // NOTE(emilio): The semantics of these methods are quite funny, in the sense
    2231             :   // that we're not supposed to need to rebuild the actual stylist data.
    2232             :   //
    2233             :   // That's handled as part of the MediumFeaturesChanged stuff, if needed.
    2234           0 :   StyleSet()->ClearCachedStyleData();
    2235             : 
    2236           0 :   DocumentStyleRootIterator iter(mPresContext->Document());
    2237           0 :   while (Element* root = iter.GetNextStyleRoot()) {
    2238           3 :     PostRestyleEvent(root, aRestyleHint, aExtraHint);
    2239           3 :   }
    2240             : 
    2241             :   // TODO(emilio, bz): Extensions can add/remove stylesheets that can affect
    2242             :   // non-inheriting anon boxes. It's not clear if we want to support that, but
    2243             :   // if we do, we need to re-selector-match them here.
    2244           8 : }
    2245             : 
    2246             : /* static */ void
    2247           0 : RestyleManager::ClearServoDataFromSubtree(Element* aElement, IncludeRoot aIncludeRoot)
    2248             : {
    2249           0 :   if (aElement->HasServoData()) {
    2250           0 :     StyleChildrenIterator it(aElement);
    2251           0 :     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
    2252         754 :       if (n->IsElement()) {
    2253         372 :         ClearServoDataFromSubtree(n->AsElement(), IncludeRoot::Yes);
    2254             :       }
    2255             :     }
    2256             :   }
    2257             : 
    2258           0 :   if (MOZ_LIKELY(aIncludeRoot == IncludeRoot::Yes)) {
    2259           0 :     aElement->ClearServoData();
    2260         384 :     MOZ_ASSERT(!aElement->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME));
    2261           0 :     MOZ_ASSERT(aElement != aElement->OwnerDoc()->GetServoRestyleRoot());
    2262             :   }
    2263         503 : }
    2264             : 
    2265             : /* static */ void
    2266           0 : RestyleManager::ClearRestyleStateFromSubtree(Element* aElement)
    2267             : {
    2268           0 :   if (aElement->HasAnyOfFlags(Element::kAllServoDescendantBits)) {
    2269           0 :     StyleChildrenIterator it(aElement);
    2270           0 :     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
    2271          24 :       if (n->IsElement()) {
    2272          12 :         ClearRestyleStateFromSubtree(n->AsElement());
    2273             :       }
    2274             :     }
    2275             :   }
    2276             : 
    2277             :   bool wasRestyled;
    2278           0 :   Unused << Servo_TakeChangeHint(aElement, &wasRestyled);
    2279          25 :   aElement->UnsetFlags(Element::kAllServoDescendantBits);
    2280          25 : }
    2281             : 
    2282             : /**
    2283             :  * This struct takes care of encapsulating some common state that text nodes may
    2284             :  * need to track during the post-traversal.
    2285             :  *
    2286             :  * This is currently used to properly compute change hints when the parent
    2287             :  * element of this node is a display: contents node, and also to avoid computing
    2288             :  * the style for text children more than once per element.
    2289             :  */
    2290         116 : struct RestyleManager::TextPostTraversalState
    2291             : {
    2292             : public:
    2293             :   TextPostTraversalState(Element& aParentElement,
    2294             :                          ComputedStyle* aParentContext,
    2295             :                          bool aDisplayContentsParentStyleChanged,
    2296             :                          ServoRestyleState& aParentRestyleState)
    2297         116 :     : mParentElement(aParentElement)
    2298             :     , mParentContext(aParentContext)
    2299             :     , mParentRestyleState(aParentRestyleState)
    2300             :     , mStyle(nullptr)
    2301             :     , mShouldPostHints(aDisplayContentsParentStyleChanged)
    2302             :     , mShouldComputeHints(aDisplayContentsParentStyleChanged)
    2303         348 :     , mComputedHint(nsChangeHint_Empty)
    2304             :   {}
    2305             : 
    2306           0 :   nsStyleChangeList& ChangeList() { return mParentRestyleState.ChangeList(); }
    2307             : 
    2308           0 :   ComputedStyle& ComputeStyle(nsIContent* aTextNode)
    2309             :   {
    2310           0 :     if (!mStyle) {
    2311           0 :       mStyle = mParentRestyleState.StyleSet().ResolveStyleForText(
    2312           0 :         aTextNode, &ParentStyle());
    2313             :     }
    2314           0 :     MOZ_ASSERT(mStyle);
    2315           0 :     return *mStyle;
    2316             :   }
    2317             : 
    2318           0 :   void ComputeHintIfNeeded(nsIContent* aContent,
    2319             :                            nsIFrame* aTextFrame,
    2320             :                            ComputedStyle& aNewStyle)
    2321             :   {
    2322           0 :     MOZ_ASSERT(aTextFrame);
    2323           0 :     MOZ_ASSERT(aNewStyle.GetPseudo() == nsCSSAnonBoxes::mozText);
    2324             : 
    2325           0 :     if (MOZ_LIKELY(!mShouldPostHints)) {
    2326             :       return;
    2327             :     }
    2328             : 
    2329           0 :     ComputedStyle* oldStyle = aTextFrame->Style();
    2330           0 :     MOZ_ASSERT(oldStyle->GetPseudo() == nsCSSAnonBoxes::mozText);
    2331             : 
    2332             :     // We rely on the fact that all the text children for the same element share
    2333             :     // style to avoid recomputing style differences for all of them.
    2334             :     //
    2335             :     // TODO(emilio): The above may not be true for ::first-{line,letter}, but
    2336             :     // we'll cross that bridge when we support those in stylo.
    2337           0 :     if (mShouldComputeHints) {
    2338           0 :       mShouldComputeHints = false;
    2339             :       uint32_t equalStructs;
    2340           0 :       mComputedHint = oldStyle->CalcStyleDifference(&aNewStyle, &equalStructs);
    2341           0 :       mComputedHint = NS_RemoveSubsumedHints(
    2342           0 :         mComputedHint, mParentRestyleState.ChangesHandledFor(*aTextFrame));
    2343             :     }
    2344             : 
    2345           0 :     if (mComputedHint) {
    2346           0 :       mParentRestyleState.ChangeList().AppendChange(
    2347           0 :         aTextFrame, aContent, mComputedHint);
    2348             :     }
    2349             :   }
    2350             : 
    2351             : private:
    2352           0 :   ComputedStyle& ParentStyle() {
    2353           0 :     if (!mParentContext) {
    2354             :       mLazilyResolvedParentContext =
    2355           0 :         mParentRestyleState.StyleSet().ResolveServoStyle(&mParentElement);
    2356           0 :       mParentContext = mLazilyResolvedParentContext;
    2357             :     }
    2358           0 :     return *mParentContext;
    2359             :   }
    2360             : 
    2361             :   Element& mParentElement;
    2362             :   ComputedStyle* mParentContext;
    2363             :   RefPtr<ComputedStyle> mLazilyResolvedParentContext;
    2364             :   ServoRestyleState& mParentRestyleState;
    2365             :   RefPtr<ComputedStyle> mStyle;
    2366             :   bool mShouldPostHints;
    2367             :   bool mShouldComputeHints;
    2368             :   nsChangeHint mComputedHint;
    2369             : };
    2370             : 
    2371             : static void
    2372          23 : UpdateBackdropIfNeeded(nsIFrame* aFrame,
    2373             :                        ServoStyleSet& aStyleSet,
    2374             :                        nsStyleChangeList& aChangeList)
    2375             : {
    2376           0 :   const nsStyleDisplay* display = aFrame->Style()->StyleDisplay();
    2377          23 :   if (display->mTopLayer != NS_STYLE_TOP_LAYER_TOP) {
    2378          23 :     return;
    2379             :   }
    2380             : 
    2381             :   // Elements in the top layer are guaranteed to have absolute or fixed
    2382             :   // position per https://fullscreen.spec.whatwg.org/#new-stacking-layer.
    2383           0 :   MOZ_ASSERT(display->IsAbsolutelyPositionedStyle());
    2384             : 
    2385             :   nsIFrame* backdropPlaceholder =
    2386           0 :     aFrame->GetChildList(nsIFrame::kBackdropList).FirstChild();
    2387           0 :   if (!backdropPlaceholder) {
    2388             :     return;
    2389             :   }
    2390             : 
    2391           0 :   MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame());
    2392             :   nsIFrame* backdropFrame =
    2393           0 :     nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder);
    2394           0 :   MOZ_ASSERT(backdropFrame->IsBackdropFrame());
    2395           0 :   MOZ_ASSERT(backdropFrame->Style()->GetPseudoType() ==
    2396             :              CSSPseudoElementType::backdrop);
    2397             : 
    2398             :   RefPtr<ComputedStyle> newStyle =
    2399           0 :     aStyleSet.ResolvePseudoElementStyle(aFrame->GetContent()->AsElement(),
    2400             :                                         CSSPseudoElementType::backdrop,
    2401             :                                         aFrame->Style(),
    2402           0 :                                         /* aPseudoElement = */ nullptr);
    2403             : 
    2404             :   // NOTE(emilio): We can't use the changes handled for the owner of the
    2405             :   // backdrop frame, since it's out of flow, and parented to the viewport or
    2406             :   // canvas frame (depending on the `position` value).
    2407           0 :   MOZ_ASSERT(backdropFrame->GetParent()->IsViewportFrame() ||
    2408             :              backdropFrame->GetParent()->IsCanvasFrame());
    2409           0 :   nsTArray<nsIFrame*> wrappersToRestyle;
    2410           0 :   ServoRestyleState state(aStyleSet, aChangeList, wrappersToRestyle);
    2411           0 :   nsIFrame::UpdateStyleOfOwnedChildFrame(backdropFrame, newStyle, state);
    2412             : }
    2413             : 
    2414             : static void
    2415           0 : UpdateFirstLetterIfNeeded(nsIFrame* aFrame, ServoRestyleState& aRestyleState)
    2416             : {
    2417           0 :   MOZ_ASSERT(!aFrame->IsFrameOfType(nsIFrame::eBlockFrame),
    2418             :              "You're probably duplicating work with UpdatePseudoElementStyles!");
    2419          23 :   if (!aFrame->HasFirstLetterChild()) {
    2420             :     return;
    2421             :   }
    2422             : 
    2423             :   // We need to find the block the first-letter is associated with so we can
    2424             :   // find the right element for the first-letter's style resolution.  Might as
    2425             :   // well just delegate the whole thing to that block.
    2426           0 :   nsIFrame* block = aFrame->GetParent();
    2427           0 :   while (!block->IsFrameOfType(nsIFrame::eBlockFrame)) {
    2428           0 :     block = block->GetParent();
    2429             :   }
    2430             : 
    2431           0 :   static_cast<nsBlockFrame*>(block->FirstContinuation())->
    2432           0 :     UpdateFirstLetterStyle(aRestyleState);
    2433             : }
    2434             : 
    2435             : static void
    2436           0 : UpdateOneAdditionalComputedStyle(nsIFrame* aFrame,
    2437             :                                 uint32_t aIndex,
    2438             :                                 ComputedStyle& aOldContext,
    2439             :                                 ServoRestyleState& aRestyleState)
    2440             : {
    2441           0 :   auto pseudoType = aOldContext.GetPseudoType();
    2442           0 :   MOZ_ASSERT(pseudoType != CSSPseudoElementType::NotPseudo);
    2443           0 :   MOZ_ASSERT(
    2444             :       !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoType));
    2445             : 
    2446             :   RefPtr<ComputedStyle> newStyle =
    2447           0 :     aRestyleState.StyleSet().ResolvePseudoElementStyle(
    2448           0 :         aFrame->GetContent()->AsElement(),
    2449             :         pseudoType,
    2450             :         aFrame->Style(),
    2451           0 :         /* aPseudoElement = */ nullptr);
    2452             : 
    2453             :   uint32_t equalStructs; // Not used, actually.
    2454             :   nsChangeHint childHint =
    2455           0 :     aOldContext.CalcStyleDifference(newStyle, &equalStructs);
    2456           0 :   if (!aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
    2457           0 :     childHint = NS_RemoveSubsumedHints(
    2458           0 :         childHint, aRestyleState.ChangesHandledFor(*aFrame));
    2459             :   }
    2460             : 
    2461           0 :   if (childHint) {
    2462           0 :     if (childHint & nsChangeHint_ReconstructFrame) {
    2463             :       // If we generate a reconstruct here, remove any non-reconstruct hints we
    2464             :       // may have already generated for this content.
    2465           0 :       aRestyleState.ChangeList().PopChangesForContent(aFrame->GetContent());
    2466             :     }
    2467           0 :     aRestyleState.ChangeList().AppendChange(
    2468           0 :         aFrame, aFrame->GetContent(), childHint);
    2469             :   }
    2470             : 
    2471           0 :   aFrame->SetAdditionalComputedStyle(aIndex, newStyle);
    2472           0 : }
    2473             : 
    2474             : static void
    2475          23 : UpdateAdditionalComputedStyles(nsIFrame* aFrame,
    2476             :                               ServoRestyleState& aRestyleState)
    2477             : {
    2478          23 :   MOZ_ASSERT(aFrame);
    2479          92 :   MOZ_ASSERT(aFrame->GetContent() && aFrame->GetContent()->IsElement());
    2480             : 
    2481             :   // FIXME(emilio): Consider adding a bit or something to avoid the initial
    2482             :   // virtual call?
    2483             :   uint32_t index = 0;
    2484           0 :   while (auto* oldStyle = aFrame->GetAdditionalComputedStyle(index)) {
    2485           0 :     UpdateOneAdditionalComputedStyle(
    2486           0 :         aFrame, index++, *oldStyle, aRestyleState);
    2487           0 :   }
    2488          23 : }
    2489             : 
    2490             : static void
    2491          23 : UpdateFramePseudoElementStyles(nsIFrame* aFrame,
    2492             :                                ServoRestyleState& aRestyleState)
    2493             : {
    2494          23 :   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
    2495           0 :     static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(aRestyleState);
    2496             :   } else {
    2497          23 :     UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
    2498             :   }
    2499             : 
    2500           0 :   UpdateBackdropIfNeeded(
    2501          23 :     aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
    2502          23 : }
    2503             : 
    2504             : enum class ServoPostTraversalFlags : uint32_t
    2505             : {
    2506             :   Empty = 0,
    2507             :   // Whether parent was restyled.
    2508             :   ParentWasRestyled = 1 << 0,
    2509             :   // Skip sending accessibility notifications for all descendants.
    2510             :   SkipA11yNotifications = 1 << 1,
    2511             :   // Always send accessibility notifications if the element is shown.
    2512             :   // The SkipA11yNotifications flag above overrides this flag.
    2513             :   SendA11yNotificationsIfShown = 1 << 2,
    2514             : };
    2515             : 
    2516         550 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoPostTraversalFlags)
    2517             : 
    2518             : // Send proper accessibility notifications and return post traversal
    2519             : // flags for kids.
    2520             : static ServoPostTraversalFlags
    2521          23 : SendA11yNotifications(nsPresContext* aPresContext,
    2522             :                       Element* aElement,
    2523             :                       ComputedStyle* aOldComputedStyle,
    2524             :                       ComputedStyle* aNewComputedStyle,
    2525             :                       ServoPostTraversalFlags aFlags)
    2526             : {
    2527             :   using Flags = ServoPostTraversalFlags;
    2528          46 :   MOZ_ASSERT(!(aFlags & Flags::SkipA11yNotifications) ||
    2529             :              !(aFlags & Flags::SendA11yNotificationsIfShown),
    2530             :              "The two a11y flags should never be set together");
    2531             : 
    2532             : #ifdef ACCESSIBILITY
    2533          23 :   nsAccessibilityService* accService = GetAccService();
    2534          23 :   if (!accService) {
    2535             :     // If we don't have accessibility service, accessibility is not
    2536             :     // enabled. Just skip everything.
    2537             :     return Flags::Empty;
    2538             :   }
    2539           0 :   if (aFlags & Flags::SkipA11yNotifications) {
    2540             :     // Propogate the skipping flag to descendants.
    2541             :     return Flags::SkipA11yNotifications;
    2542             :   }
    2543             : 
    2544           0 :   bool needsNotify = false;
    2545           0 :   bool isVisible = aNewComputedStyle->StyleVisibility()->IsVisible();
    2546           0 :   if (aFlags & Flags::SendA11yNotificationsIfShown) {
    2547           0 :     if (!isVisible) {
    2548             :       // Propagate the sending-if-shown flag to descendants.
    2549             :       return Flags::SendA11yNotificationsIfShown;
    2550             :     }
    2551             :     // We have asked accessibility service to remove the whole subtree
    2552             :     // of element which becomes invisible from the accessible tree, but
    2553             :     // this element is visible, so we need to add it back.
    2554             :     needsNotify = true;
    2555             :   } else {
    2556             :     // If we shouldn't skip in any case, we need to check whether our
    2557             :     // own visibility has changed.
    2558           0 :     bool wasVisible = aOldComputedStyle->StyleVisibility()->IsVisible();
    2559           0 :     needsNotify = wasVisible != isVisible;
    2560             :   }
    2561             : 
    2562           0 :   if (needsNotify) {
    2563           0 :     nsIPresShell* presShell = aPresContext->PresShell();
    2564           0 :     if (isVisible) {
    2565           0 :       accService->ContentRangeInserted(
    2566           0 :         presShell, aElement, aElement->GetNextSibling());
    2567             :       // We are adding the subtree. Accessibility service would handle
    2568             :       // descendants, so we should just skip them from notifying.
    2569           0 :       return Flags::SkipA11yNotifications;
    2570             :     }
    2571             :     // Remove the subtree of this invisible element, and ask any shown
    2572             :     // descendant to add themselves back.
    2573           0 :     accService->ContentRemoved(presShell, aElement);
    2574           0 :     return Flags::SendA11yNotificationsIfShown;
    2575             :   }
    2576             : #endif
    2577             : 
    2578             :   return Flags::Empty;
    2579             : }
    2580             : 
    2581             : bool
    2582         400 : RestyleManager::ProcessPostTraversal(
    2583             :   Element* aElement,
    2584             :   ComputedStyle* aParentContext,
    2585             :   ServoRestyleState& aRestyleState,
    2586             :   ServoPostTraversalFlags aFlags)
    2587             : {
    2588         400 :   nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
    2589           0 :   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
    2590             : 
    2591         400 :   MOZ_DIAGNOSTIC_ASSERT(aElement->HasServoData(),
    2592             :                         "Element without Servo data on a post-traversal? How?");
    2593             : 
    2594             :   // NOTE(emilio): This is needed because for table frames the bit is set on the
    2595             :   // table wrapper (which is the primary frame), not on the table itself.
    2596             :   const bool isOutOfFlow =
    2597         629 :     primaryFrame &&
    2598         858 :     primaryFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
    2599             : 
    2600             :   // Grab the change hint from Servo.
    2601             :   bool wasRestyled;
    2602             :   nsChangeHint changeHint =
    2603         400 :     static_cast<nsChangeHint>(Servo_TakeChangeHint(aElement, &wasRestyled));
    2604             : 
    2605             :   // We should really fix the weird primary frame mapping for image maps
    2606             :   // (bug 135040)...
    2607         629 :   if (styleFrame && styleFrame->GetContent() != aElement) {
    2608           0 :     MOZ_ASSERT(static_cast<nsImageFrame*>(do_QueryFrame(styleFrame)));
    2609             :     styleFrame = nullptr;
    2610             :   }
    2611             : 
    2612             :   // Handle lazy frame construction by posting a reconstruct for any lazily-
    2613             :   // constructed roots.
    2614           0 :   if (aElement->HasFlag(NODE_NEEDS_FRAME)) {
    2615           6 :     changeHint |= nsChangeHint_ReconstructFrame;
    2616           6 :     MOZ_ASSERT(!styleFrame);
    2617             :   }
    2618             : 
    2619         400 :   if (styleFrame) {
    2620         229 :     MOZ_ASSERT(primaryFrame);
    2621             : 
    2622             :     nsIFrame* maybeAnonBoxChild;
    2623         229 :     if (isOutOfFlow) {
    2624           0 :       maybeAnonBoxChild = primaryFrame->GetPlaceholderFrame();
    2625             :     } else {
    2626         222 :       maybeAnonBoxChild = primaryFrame;
    2627         222 :       changeHint = NS_RemoveSubsumedHints(
    2628             :         changeHint, aRestyleState.ChangesHandledFor(*styleFrame));
    2629             :     }
    2630             : 
    2631             :     // If the parent wasn't restyled, the styles of our anon box parents won't
    2632             :     // change either.
    2633           0 :     if ((aFlags & ServoPostTraversalFlags::ParentWasRestyled) &&
    2634           0 :         maybeAnonBoxChild->ParentIsWrapperAnonBox()) {
    2635           0 :       aRestyleState.AddPendingWrapperRestyle(
    2636           0 :         ServoRestyleState::TableAwareParentFor(maybeAnonBoxChild));
    2637             :     }
    2638             :   }
    2639             : 
    2640             :   // Although we shouldn't generate non-ReconstructFrame hints for elements with
    2641             :   // no frames, we can still get them here if they were explicitly posted by
    2642             :   // PostRestyleEvent, such as a RepaintFrame hint when a :link changes to be
    2643             :   // :visited.  Skip processing these hints if there is no frame.
    2644         571 :   if ((styleFrame || (changeHint & nsChangeHint_ReconstructFrame)) && changeHint) {
    2645          29 :     aRestyleState.ChangeList().AppendChange(styleFrame, aElement, changeHint);
    2646             :   }
    2647             : 
    2648             :   // If our change hint is reconstruct, we delegate to the frame constructor,
    2649             :   // which consumes the new style and expects the old style to be on the frame.
    2650             :   //
    2651             :   // XXXbholley: We should teach the frame constructor how to clear the dirty
    2652             :   // descendants bit to avoid the traversal here.
    2653           0 :   if (changeHint & nsChangeHint_ReconstructFrame) {
    2654          13 :     ClearRestyleStateFromSubtree(aElement);
    2655          13 :     return true;
    2656             :   }
    2657             : 
    2658             :   // TODO(emilio): We could avoid some refcount traffic here, specially in the
    2659             :   // ComputedStyle case, which uses atomic refcounting.
    2660             :   //
    2661             :   // Hold the ComputedStyle alive, because it could become a dangling pointer
    2662             :   // during the replacement. In practice it's not a huge deal, but better not
    2663             :   // playing with dangling pointers if not needed.
    2664             :   //
    2665             :   // NOTE(emilio): We could keep around the old computed style for display:
    2666             :   // contents elements too, but we don't really need it right now.
    2667             :   RefPtr<ComputedStyle> oldOrDisplayContentsStyle =
    2668           0 :     styleFrame ? styleFrame->Style() : nullptr;
    2669             : 
    2670         387 :   MOZ_ASSERT(!(styleFrame && Servo_Element_IsDisplayContents(aElement)),
    2671             :              "display: contents node has a frame, yet we didn't reframe it"
    2672             :              " above?");
    2673             :   const bool isDisplayContents =
    2674         387 :     !styleFrame && aElement->HasServoData() &&
    2675           0 :     Servo_Element_IsDisplayContents(aElement);
    2676             :   if (isDisplayContents) {
    2677           0 :     oldOrDisplayContentsStyle =
    2678             :       aRestyleState.StyleSet().ResolveServoStyle(aElement);
    2679             :   }
    2680         774 : 
    2681           0 :   Maybe<ServoRestyleState> thisFrameRestyleState;
    2682             :   if (styleFrame) {
    2683         222 :     auto type = isOutOfFlow
    2684           0 :       ? ServoRestyleState::Type::OutOfFlow
    2685             :       : ServoRestyleState::Type::InFlow;
    2686         222 : 
    2687             :     thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
    2688             :   }
    2689             : 
    2690             :   // We can't really assume as used changes from display: contents elements (or
    2691             :   // other elements without frames).
    2692         387 :   ServoRestyleState& childrenRestyleState =
    2693             :     thisFrameRestyleState ? *thisFrameRestyleState : aRestyleState;
    2694             : 
    2695             :   RefPtr<ComputedStyle> upToDateContext =
    2696         449 :     wasRestyled
    2697        1517 :       ? aRestyleState.StyleSet().ResolveServoStyle(aElement)
    2698             :       : oldOrDisplayContentsStyle;
    2699             : 
    2700         387 :   ServoPostTraversalFlags childrenFlags =
    2701           0 :     wasRestyled ? ServoPostTraversalFlags::ParentWasRestyled
    2702             :                 : ServoPostTraversalFlags::Empty;
    2703         418 : 
    2704          23 :   if (wasRestyled && oldOrDisplayContentsStyle) {
    2705             :     MOZ_ASSERT(styleFrame || isDisplayContents);
    2706             : 
    2707             :     // Note that upToDateContext could be the same as oldOrDisplayContentsStyle,
    2708             :     // but it doesn't matter, since the only point of it is calling FinishStyle
    2709          23 :     // on the relevant structs, and those don't matter for display: contents.
    2710             :     upToDateContext->ResolveSameStructsAs(oldOrDisplayContentsStyle);
    2711             : 
    2712             :     // We want to walk all the continuations here, even the ones with different
    2713             :     // styles.  In practice, the only reason we get continuations with different
    2714             :     // styles here is ::first-line (::first-letter never affects element
    2715             :     // styles).  But in that case, newStyle is the right context for the
    2716             :     // _later_ continuations anyway (the ones not affected by ::first-line), not
    2717             :     // the earlier ones, so there is no point stopping right at the point when
    2718             :     // we'd actually be setting the right ComputedStyle.
    2719             :     //
    2720             :     // This does mean that we may be setting the wrong ComputedStyle on our
    2721           0 :     // initial continuations; ::first-line fixes that up after the fact.
    2722          23 :     for (nsIFrame* f = styleFrame; f; f = f->GetNextContinuation()) {
    2723          23 :       MOZ_ASSERT_IF(f != styleFrame, !f->GetAdditionalComputedStyle(0));
    2724             :       f->SetComputedStyle(upToDateContext);
    2725             :     }
    2726          23 : 
    2727          23 :     if (styleFrame) {
    2728             :       UpdateAdditionalComputedStyles(styleFrame, aRestyleState);
    2729             :     }
    2730          23 : 
    2731             :     if (!aElement->GetParent()) {
    2732             :       // This is the root.  Update styles on the viewport as needed.
    2733           0 :       ViewportFrame* viewport =
    2734           0 :         do_QueryFrame(mPresContext->PresShell()->GetRootFrame());
    2735             :       if (viewport) {
    2736           0 :         // NB: The root restyle state, not the one for our children!
    2737             :         viewport->UpdateStyle(aRestyleState);
    2738             :       }
    2739             :     }
    2740             : 
    2741             :     // Some changes to animations don't affect the computed style and yet still
    2742             :     // require the layer to be updated. For example, pausing an animation via
    2743             :     // the Web Animations API won't affect an element's style but still
    2744             :     // requires to update the animation on the layer.
    2745             :     //
    2746             :     // We can sometimes reach this when the animated style is being removed.
    2747             :     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
    2748             :     // style or not, we need to call it *after* setting |newStyle| to
    2749          23 :     // |styleFrame| to ensure the animated transform has been removed first.
    2750          23 :     AddLayerChangesForAnimation(
    2751             :       styleFrame, aElement, aRestyleState.ChangeList());
    2752             : 
    2753             :     childrenFlags |= SendA11yNotifications(mPresContext,
    2754             :                                            aElement,
    2755             :                                            oldOrDisplayContentsStyle,
    2756          46 :                                            upToDateContext,
    2757             :                                            aFlags);
    2758             :   }
    2759             : 
    2760           0 :   const bool traverseElementChildren =
    2761             :     aElement->HasAnyOfFlags(Element::kAllServoDescendantBits);
    2762           0 :   const bool traverseTextChildren =
    2763           0 :     wasRestyled || aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
    2764         387 :   bool recreatedAnyContext = wasRestyled;
    2765         232 :   if (traverseElementChildren || traverseTextChildren) {
    2766             :     StyleChildrenIterator it(aElement);
    2767             :     TextPostTraversalState textState(*aElement,
    2768           0 :                                      upToDateContext,
    2769           0 :                                      isDisplayContents && wasRestyled,
    2770           0 :                                      childrenRestyleState);
    2771         788 :     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
    2772         706 :       if (traverseElementChildren && n->IsElement()) {
    2773             :         recreatedAnyContext |= ProcessPostTraversal(n->AsElement(),
    2774             :                                                     upToDateContext,
    2775             :                                                     childrenRestyleState,
    2776          45 :                                                     childrenFlags);
    2777          35 :       } else if (traverseTextChildren && n->IsText()) {
    2778             :         recreatedAnyContext |= ProcessPostTraversalForText(n, textState,
    2779             :                                                            childrenRestyleState,
    2780             :                                                            childrenFlags);
    2781             :       }
    2782             :     }
    2783             :   }
    2784             : 
    2785             :   // We want to update frame pseudo-element styles after we've traversed our
    2786             :   // kids, because some of those updates (::first-line/::first-letter) need to
    2787             :   // modify the styles of the kids, and the child traversal above would just
    2788         387 :   // clobber those modifications.
    2789         222 :   if (styleFrame) {
    2790             :     if (wasRestyled) {
    2791             :       // Make sure to update anon boxes and pseudo bits after updating text,
    2792             :       // otherwise ProcessPostTraversalForText could clobber first-letter
    2793          23 :       // styles, for example.
    2794             :       styleFrame->UpdateStyleOfOwnedAnonBoxes(childrenRestyleState);
    2795             :     }
    2796             :     // Process anon box wrapper frames before ::first-line bits, but _after_
    2797             :     // owned anon boxes, since the children wrapper anon boxes could be
    2798           0 :     // inheriting from our own owned anon boxes.
    2799           0 :     childrenRestyleState.ProcessWrapperRestyles(styleFrame);
    2800           0 :     if (wasRestyled) {
    2801         283 :       UpdateFramePseudoElementStyles(styleFrame, childrenRestyleState);
    2802          84 :     } else if (traverseElementChildren &&
    2803             :                styleFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
    2804             :       // Even if we were not restyled, if we're a block with a first-line and
    2805             :       // one of our descendant elements which is on the first line was restyled,
    2806             :       // we need to update the styles of things on the first line, because
    2807             :       // they're wrong now.
    2808             :       //
    2809             :       // FIXME(bz) Could we do better here?  For example, could we keep track of
    2810             :       // frames that are "block with a ::first-line so we could avoid
    2811             :       // IsFrameOfType() and digging about for the first-line frame if not?
    2812             :       // Could we keep track of whether the element children we actually restyle
    2813             :       // are affected by first-line?  Something else?  Bug 1385443 tracks making
    2814             :       // this better.
    2815           0 :       nsIFrame* firstLineFrame =
    2816           0 :         static_cast<nsBlockFrame*>(styleFrame)->GetFirstLineFrame();
    2817           0 :       if (firstLineFrame) {
    2818           0 :         for (nsIFrame* kid : firstLineFrame->PrincipalChildList()) {
    2819             :           ReparentComputedStyleForFirstLine(kid);
    2820             :         }
    2821             :       }
    2822             :     }
    2823             :   }
    2824         387 : 
    2825             :   aElement->UnsetFlags(Element::kAllServoDescendantBits);
    2826             :   return recreatedAnyContext;
    2827             : }
    2828             : 
    2829          35 : bool
    2830             : RestyleManager::ProcessPostTraversalForText(
    2831             :     nsIContent* aTextNode,
    2832             :     TextPostTraversalState& aPostTraversalState,
    2833             :     ServoRestyleState& aRestyleState,
    2834             :     ServoPostTraversalFlags aFlags)
    2835             : {
    2836           0 :   // Handle lazy frame construction.
    2837           0 :   if (aTextNode->HasFlag(NODE_NEEDS_FRAME)) {
    2838          20 :     aPostTraversalState.ChangeList().AppendChange(
    2839          20 :       nullptr, aTextNode, nsChangeHint_ReconstructFrame);
    2840             :     return true;
    2841             :   }
    2842             : 
    2843          15 :   // Handle restyle.
    2844          15 :   nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
    2845             :   if (!primaryFrame) {
    2846             :     return false;
    2847             :   }
    2848             : 
    2849             :   // If the parent wasn't restyled, the styles of our anon box parents won't
    2850           0 :   // change either.
    2851           0 :   if ((aFlags & ServoPostTraversalFlags::ParentWasRestyled) &&
    2852           0 :       primaryFrame->ParentIsWrapperAnonBox()) {
    2853           0 :     aRestyleState.AddPendingWrapperRestyle(
    2854             :       ServoRestyleState::TableAwareParentFor(primaryFrame));
    2855             :   }
    2856           0 : 
    2857           0 :   ComputedStyle& newStyle = aPostTraversalState.ComputeStyle(aTextNode);
    2858             :   aPostTraversalState.ComputeHintIfNeeded(aTextNode, primaryFrame, newStyle);
    2859             : 
    2860             :   // We want to walk all the continuations here, even the ones with different
    2861             :   // styles.  In practice, the only reasons we get continuations with different
    2862             :   // styles are ::first-line and ::first-letter.  But in those cases,
    2863             :   // newStyle is the right context for the _later_ continuations anyway (the
    2864             :   // ones not affected by ::first-line/::first-letter), not the earlier ones,
    2865             :   // so there is no point stopping right at the point when we'd actually be
    2866             :   // setting the right ComputedStyle.
    2867             :   //
    2868             :   // This does mean that we may be setting the wrong ComputedStyle on our
    2869             :   // initial continuations; ::first-line/::first-letter fix that up after the
    2870           0 :   // fact.
    2871           0 :   for (nsIFrame* f = primaryFrame; f; f = f->GetNextContinuation()) {
    2872             :     f->SetComputedStyle(&newStyle);
    2873             :   }
    2874             : 
    2875             :   return true;
    2876             : }
    2877             : 
    2878           0 : void
    2879             : RestyleManager::ClearSnapshots()
    2880           0 : {
    2881          52 :   for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
    2882           0 :     iter.Key()->UnsetFlags(ELEMENT_HAS_SNAPSHOT | ELEMENT_HANDLED_SNAPSHOT);
    2883             :     iter.Remove();
    2884         187 :   }
    2885             : }
    2886             : 
    2887           0 : ServoElementSnapshot&
    2888             : RestyleManager::SnapshotFor(Element* aElement)
    2889          57 : {
    2890             :   MOZ_ASSERT(!mInStyleRefresh);
    2891             : 
    2892             :   // NOTE(emilio): We can handle snapshots from a one-off restyle of those that
    2893             :   // we do to restyle stuff for reconstruction, for example.
    2894             :   //
    2895             :   // It seems to be the case that we always flush in between that happens and
    2896             :   // the next attribute change, so we can assert that we haven't handled the
    2897             :   // snapshot here yet. If this assertion didn't hold, we'd need to unset that
    2898             :   // flag from here too.
    2899             :   //
    2900             :   // Can't wait to make ProcessPendingRestyles the only entry-point for styling,
    2901         114 :   // so this becomes much easier to reason about. Today is not that day though.
    2902           0 :   MOZ_ASSERT(aElement->HasServoData());
    2903             :   MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
    2904          57 : 
    2905          57 :   ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
    2906             :   aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
    2907             : 
    2908          57 :   // Now that we have a snapshot, make sure a restyle is triggered.
    2909          57 :   aElement->NoteDirtyForServo();
    2910             :   return *snapshot;
    2911             : }
    2912             : 
    2913           0 : void
    2914             : RestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags)
    2915           0 : {
    2916             :   nsPresContext* presContext = PresContext();
    2917         192 : 
    2918             :   MOZ_ASSERT(presContext->Document(), "No document?  Pshaw!");
    2919             :   // FIXME(emilio): In the "flush animations" case, ideally, we should only
    2920             :   // recascade animation styles running on the compositor, so we shouldn't care
    2921             :   // about other styles, or new rules that apply to the page...
    2922             :   //
    2923         576 :   // However, that's not true as of right now, see bug 1388031 and bug 1388692.
    2924             :   MOZ_ASSERT((aFlags & ServoTraversalFlags::FlushThrottledAnimations) ||
    2925             :              !presContext->HasPendingMediaQueryUpdates(),
    2926         192 :              "Someone forgot to update media queries?");
    2927         192 :   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
    2928             :   MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?");
    2929             : 
    2930         384 : 
    2931             :   if (MOZ_UNLIKELY(!presContext->PresShell()->DidInitialize())) {
    2932             :     // PresShell::FlushPendingNotifications doesn't early-return in the case
    2933             :     // where the PresShell hasn't yet been initialized (and therefore we haven't
    2934             :     // yet done the initial style traversal of the DOM tree). We should arguably
    2935             :     // fix up the callers and assert against this case, but we just detect and
    2936          32 :     // handle it for now.
    2937             :     return;
    2938             :   }
    2939             : 
    2940             :   // Create a AnimationsWithDestroyedFrame during restyling process to
    2941             :   // stop animations and transitions on elements that have no frame at the end
    2942           0 :   // of the restyling process.
    2943             :   AnimationsWithDestroyedFrame animationsWithDestroyedFrame(this);
    2944         160 : 
    2945         160 :   ServoStyleSet* styleSet = StyleSet();
    2946             :   nsIDocument* doc = presContext->Document();
    2947             : 
    2948             :   // Ensure the refresh driver is active during traversal to avoid mutating
    2949         160 :   // mActiveTimer and mMostRecentRefresh time.
    2950             :   presContext->RefreshDriver()->MostRecentRefresh();
    2951             : 
    2952             : 
    2953             :   // Perform the Servo traversal, and the post-traversal if required. We do this
    2954             :   // in a loop because certain rare paths in the frame constructor (like
    2955           0 :   // uninstalling XBL bindings) can trigger additional style validations.
    2956         160 :   mInStyleRefresh = true;
    2957           8 :   if (mHaveNonAnimationRestyles) {
    2958             :     ++mAnimationGeneration;
    2959             :   }
    2960         160 : 
    2961             :   if (mRestyleForCSSRuleChanges) {
    2962             :     aFlags |= ServoTraversalFlags::ForCSSRuleChanges;
    2963             :   }
    2964         214 : 
    2965           0 :   while (styleSet->StyleDocument(aFlags)) {
    2966             :     ClearSnapshots();
    2967          54 : 
    2968          27 :     nsStyleChangeList currentChanges;
    2969             :     bool anyStyleChanged = false;
    2970             : 
    2971             :     // Recreate styles , and queue up change hints (which also handle lazy frame
    2972             :     // construction).
    2973           0 :     {
    2974           0 :       AutoRestyleTimelineMarker marker(presContext->GetDocShell(), false);
    2975           0 :       DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
    2976           0 :       while (Element* root = iter.GetNextStyleRoot()) {
    2977           0 :         nsTArray<nsIFrame*> wrappersToRestyle;
    2978           0 :         ServoRestyleState state(*styleSet, currentChanges, wrappersToRestyle);
    2979          47 :         ServoPostTraversalFlags flags = ServoPostTraversalFlags::Empty;
    2980          47 :         anyStyleChanged |= ProcessPostTraversal(root, nullptr, state, flags);
    2981             :       }
    2982             :     }
    2983          27 : 
    2984             :     doc->ClearServoRestyleRoot();
    2985             : 
    2986             :     // Process the change hints.
    2987             :     //
    2988             :     // Unfortunately, the frame constructor can generate new change hints while
    2989             :     // processing existing ones. We redirect those into a secondary queue and
    2990             :     // iterate until there's nothing left.
    2991             :     {
    2992           0 :       AutoTimelineMarker marker(
    2993           0 :         presContext->GetDocShell(), "StylesApplyChanges");
    2994           0 :       ReentrantChangeList newChanges;
    2995           0 :       mReentrantChanges = &newChanges;
    2996           0 :       while (!currentChanges.IsEmpty()) {
    2997           0 :         ProcessRestyledFrames(currentChanges);
    2998           0 :         MOZ_ASSERT(currentChanges.IsEmpty());
    2999           0 :         for (ReentrantChange& change: newChanges)  {
    3000           0 :           if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
    3001             :               !change.mContent->GetPrimaryFrame()) {
    3002             :             // SVG Elements post change hints without ensuring that the primary
    3003             :             // frame will be there after that (see bug 1366142).
    3004             :             //
    3005             :             // Just ignore those, since we can't really process them.
    3006             :             continue;
    3007           0 :           }
    3008           0 :           currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
    3009             :                                       change.mContent, change.mHint);
    3010           0 :         }
    3011             :         newChanges.Clear();
    3012          27 :       }
    3013             :       mReentrantChanges = nullptr;
    3014             :     }
    3015          27 : 
    3016             :     if (anyStyleChanged) {
    3017             :       // Maybe no styles changed when:
    3018             :       //
    3019             :       //  * Only explicit change hints were posted in the first place.
    3020             :       //  * When an attribute or state change in the content happens not to need
    3021             :       //    a restyle after all.
    3022             :       //
    3023             :       // In any case, we don't need to increment the restyle generation in that
    3024          27 :       // case.
    3025             :       IncrementRestyleGeneration();
    3026             :     }
    3027             :   }
    3028           0 : 
    3029             :   doc->ClearServoRestyleRoot();
    3030           0 : 
    3031             :   FlushOverflowChangedTracker();
    3032           0 : 
    3033           0 :   ClearSnapshots();
    3034           0 :   styleSet->AssertTreeIsClean();
    3035         160 :   mHaveNonAnimationRestyles = false;
    3036         160 :   mRestyleForCSSRuleChanges = false;
    3037             :   mInStyleRefresh = false;
    3038             : 
    3039             :   // Now that everything has settled, see if we have enough free rule nodes in
    3040         160 :   // the tree to warrant sweeping them.
    3041             :   styleSet->MaybeGCRuleTree();
    3042             : 
    3043             :   // Note: We are in the scope of |animationsWithDestroyedFrame|, so
    3044         160 :   //       |mAnimationsWithDestroyedFrame| is still valid.
    3045         160 :   MOZ_ASSERT(mAnimationsWithDestroyedFrame);
    3046             :   mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
    3047             : }
    3048             : 
    3049             : #ifdef DEBUG
    3050           0 : static void
    3051             : VerifyFlatTree(const nsIContent& aContent)
    3052           0 : {
    3053             :   StyleChildrenIterator iter(&aContent);
    3054      222376 : 
    3055           0 :   for (auto* content = iter.GetNextChild();
    3056             :        content;
    3057           0 :        content = iter.GetNextChild()) {
    3058      111096 :     MOZ_ASSERT(content->GetFlattenedTreeParentNodeForStyle() == &aContent);
    3059           0 :     MOZ_ASSERT(!content->IsActiveChildrenElement());
    3060             :     VerifyFlatTree(*content);
    3061      111280 :   }
    3062             : }
    3063             : #endif
    3064             : 
    3065         192 : void
    3066             : RestyleManager::ProcessPendingRestyles()
    3067             : {
    3068         192 : #ifdef DEBUG
    3069         184 :   if (auto* root = mPresContext->Document()->GetRootElement()) {
    3070             :     VerifyFlatTree(*root);
    3071             :   }
    3072             : #endif
    3073         192 : 
    3074         192 :   DoProcessPendingRestyles(ServoTraversalFlags::Empty);
    3075             : }
    3076             : 
    3077           0 : void
    3078             : RestyleManager::ProcessAllPendingAttributeAndStateInvalidations()
    3079          12 : {
    3080             :   if (mSnapshots.IsEmpty()) {
    3081             :     return;
    3082           0 :   }
    3083             :   for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
    3084             :     // Servo data for the element might have been dropped. (e.g. by removing
    3085           0 :     // from its document)
    3086           0 :     if (iter.Key()->HasFlag(ELEMENT_HAS_SNAPSHOT)) {
    3087             :       Servo_ProcessInvalidations(StyleSet()->RawSet(), iter.Key(), &mSnapshots);
    3088             :     }
    3089           0 :   }
    3090             :   ClearSnapshots();
    3091             : }
    3092             : 
    3093           0 : bool
    3094             : RestyleManager::HasPendingRestyleAncestor(Element* aElement) const
    3095           3 : {
    3096             :   return Servo_HasPendingRestyleAncestor(aElement);
    3097             : }
    3098             : 
    3099           0 : void
    3100             : RestyleManager::UpdateOnlyAnimationStyles()
    3101           0 : {
    3102           0 :   bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
    3103             :   if (!doCSS) {
    3104             :     return;
    3105             :   }
    3106           0 : 
    3107             :   DoProcessPendingRestyles(ServoTraversalFlags::FlushThrottledAnimations);
    3108             : }
    3109             : 
    3110          10 : void
    3111             : RestyleManager::ContentStateChanged(nsIContent* aContent,
    3112             :                                     EventStates aChangedBits)
    3113           0 : {
    3114             :   MOZ_ASSERT(!mInStyleRefresh);
    3115          20 : 
    3116           9 :   if (!aContent->IsElement()) {
    3117             :     return;
    3118             :   }
    3119          10 : 
    3120          10 :   Element* aElement = aContent->AsElement();
    3121             :   if (!aElement->HasServoData()) {
    3122             :     return;
    3123             :   }
    3124             : 
    3125          10 :   nsChangeHint changeHint;
    3126             :   ContentStateChangedInternal(aElement, aChangedBits, &changeHint);
    3127             : 
    3128             :   // Don't bother taking a snapshot if no rules depend on these state bits.
    3129             :   //
    3130             :   // We always take a snapshot for the LTR/RTL event states, since Servo doesn't
    3131             :   // track those bits in the same way, and we know that :dir() rules are always
    3132          30 :   // present in UA style sheets.
    3133          10 :   if (!aChangedBits.HasAtLeastOneOfStates(DIRECTION_STATES) &&
    3134             :       !StyleSet()->HasStateDependency(*aElement, aChangedBits)) {
    3135             :     return;
    3136             :   }
    3137           0 : 
    3138           2 :   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
    3139           0 :   EventStates previousState = aElement->StyleState() ^ aChangedBits;
    3140             :   snapshot.AddState(previousState);
    3141           1 : 
    3142           0 :   if (changeHint) {
    3143             :     Servo_NoteExplicitHints(aElement, nsRestyleHint(0), changeHint);
    3144             :   }
    3145             : 
    3146             :   // Assuming we need to invalidate cached style in getComputedStyle for
    3147           1 :   // undisplayed elements, since we don't know if it is needed.
    3148             :   IncrementUndisplayedRestyleGeneration();
    3149             : }
    3150             : 
    3151         262 : static inline bool
    3152             : AttributeInfluencesOtherPseudoClassState(const Element& aElement,
    3153             :                                          const nsAtom* aAttribute)
    3154             : {
    3155             :   // We must record some state for :-moz-browser-frame and
    3156         262 :   // :-moz-table-border-nonzero.
    3157           0 :   if (aAttribute == nsGkAtoms::mozbrowser) {
    3158             :     return aElement.IsAnyOfHTMLElements(nsGkAtoms::iframe, nsGkAtoms::frame);
    3159             :   }
    3160         262 : 
    3161           0 :   if (aAttribute == nsGkAtoms::border) {
    3162             :     return aElement.IsHTMLElement(nsGkAtoms::table);
    3163             :   }
    3164             : 
    3165             :   return false;
    3166             : }
    3167             : 
    3168         262 : static inline bool
    3169             : NeedToRecordAttrChange(const ServoStyleSet& aStyleSet,
    3170             :                        const Element& aElement,
    3171             :                        int32_t aNameSpaceID,
    3172             :                        nsAtom* aAttribute,
    3173             :                        bool* aInfluencesOtherPseudoClassState)
    3174         262 : {
    3175         262 :   *aInfluencesOtherPseudoClassState =
    3176             :     AttributeInfluencesOtherPseudoClassState(aElement, aAttribute);
    3177             : 
    3178             :   // If the attribute influences one of the pseudo-classes that are backed by
    3179         262 :   // attributes, we just record it.
    3180             :   if (*aInfluencesOtherPseudoClassState) {
    3181             :     return true;
    3182             :   }
    3183             : 
    3184             :   // We assume that id and class attributes are used in class/id selectors, and
    3185             :   // thus record them.
    3186             :   //
    3187             :   // TODO(emilio): We keep a filter of the ids in use somewhere in the StyleSet,
    3188             :   // presumably we could try to filter the old and new id, but it's not clear
    3189         524 :   // it's worth it.
    3190         523 :   if (aNameSpaceID == kNameSpaceID_None &&
    3191             :       (aAttribute == nsGkAtoms::id || aAttribute == nsGkAtoms::_class)) {
    3192             :     return true;
    3193             :   }
    3194             : 
    3195             :   // We always record lang="", even though we force a subtree restyle when it
    3196             :   // changes, since it can change how its siblings match :lang(..) due to
    3197         260 :   // selectors like :lang(..) + div.
    3198             :   if (aAttribute == nsGkAtoms::lang) {
    3199             :     return true;
    3200             :   }
    3201             : 
    3202             :   // Otherwise, just record the attribute change if a selector in the page may
    3203         260 :   // reference it from an attribute selector.
    3204             :   return aStyleSet.MightHaveAttributeDependency(aElement, aAttribute);
    3205             : }
    3206             : 
    3207           0 : void
    3208             : RestyleManager::AttributeWillChange(Element* aElement,
    3209             :                                     int32_t aNameSpaceID,
    3210             :                                     nsAtom* aAttribute,
    3211             :                                     int32_t aModType,
    3212             :                                     const nsAttrValue* aNewValue)
    3213         309 : {
    3214           0 :   TakeSnapshotForAttributeChange(aElement, aNameSpaceID, aAttribute);
    3215             : }
    3216             : 
    3217           0 : void
    3218             : RestyleManager::ClassAttributeWillBeChangedBySMIL(Element* aElement)
    3219           0 : {
    3220           0 :   TakeSnapshotForAttributeChange(aElement, kNameSpaceID_None,
    3221           0 :                                  nsGkAtoms::_class);
    3222             : }
    3223             : 
    3224         309 : void
    3225             : RestyleManager::TakeSnapshotForAttributeChange(Element* aElement,
    3226             :                                                int32_t aNameSpaceID,
    3227             :                                                nsAtom* aAttribute)
    3228           0 : {
    3229             :   MOZ_ASSERT(!mInStyleRefresh);
    3230         309 : 
    3231         253 :   if (!aElement->HasServoData()) {
    3232             :     return;
    3233             :   }
    3234             : 
    3235         262 :   bool influencesOtherPseudoClassState;
    3236             :   if (!NeedToRecordAttrChange(*StyleSet(),
    3237             :                               *aElement,
    3238             :                               aNameSpaceID,
    3239             :                               aAttribute,
    3240             :                               &influencesOtherPseudoClassState)) {
    3241             :     return;
    3242             :   }
    3243             : 
    3244             :   // We cannot tell if the attribute change will affect the styles of
    3245             :   // undisplayed elements, because we don't actually restyle those elements
    3246             :   // during the restyle traversal. So just assume that the attribute change can
    3247          56 :   // cause the style to change.
    3248             :   IncrementUndisplayedRestyleGeneration();
    3249             : 
    3250             :   // Some other random attribute changes may also affect the transitions,
    3251           0 :   // so we also set this true here.
    3252             :   mHaveNonAnimationRestyles = true;
    3253          56 : 
    3254           0 :   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
    3255             :   snapshot.AddAttrs(aElement, aNameSpaceID, aAttribute);
    3256          56 : 
    3257           0 :   if (influencesOtherPseudoClassState) {
    3258             :     snapshot.AddOtherPseudoClassState(aElement);
    3259             :   }
    3260             : }
    3261             : 
    3262             : // For some attribute changes we must restyle the whole subtree:
    3263             : //
    3264             : // * <td> is affected by the cellpadding on its ancestor table
    3265             : // * lwtheme and lwthemetextcolor on root element of XUL document
    3266             : //   affects all descendants due to :-moz-lwtheme* pseudo-classes
    3267             : // * lang="" and xml:lang="" can affect all descendants due to :lang()
    3268             : //
    3269           0 : static inline bool
    3270             : AttributeChangeRequiresSubtreeRestyle(const Element& aElement, nsAtom* aAttr)
    3271         308 : {
    3272           0 :   if (aAttr == nsGkAtoms::cellpadding) {
    3273             :     return aElement.IsHTMLElement(nsGkAtoms::table);
    3274           0 :   }
    3275           0 :   if (aAttr == nsGkAtoms::lwtheme ||
    3276           0 :       aAttr == nsGkAtoms::lwthemetextcolor) {
    3277           0 :     return aElement.GetNameSpaceID() == kNameSpaceID_XUL &&
    3278             :       &aElement == aElement.OwnerDoc()->GetRootElement();
    3279             :   }
    3280         308 : 
    3281             :   return aAttr == nsGkAtoms::lang;
    3282             : }
    3283             : 
    3284         308 : void
    3285             : RestyleManager::AttributeChanged(Element* aElement,
    3286             :                                  int32_t aNameSpaceID,
    3287             :                                  nsAtom* aAttribute,
    3288             :                                  int32_t aModType,
    3289             :                                  const nsAttrValue* aOldValue)
    3290           0 : {
    3291             :   MOZ_ASSERT(!mInStyleRefresh);
    3292         308 : 
    3293           0 :   auto changeHint = nsChangeHint(0);
    3294             :   auto restyleHint = nsRestyleHint(0);
    3295           0 : 
    3296             :   changeHint |= aElement->GetAttributeChangeHint(aAttribute, aModType);
    3297           0 : 
    3298             :   if (aAttribute == nsGkAtoms::style) {
    3299           0 :     restyleHint |= eRestyle_StyleAttribute;
    3300             :   } else if (AttributeChangeRequiresSubtreeRestyle(*aElement, aAttribute)) {
    3301         308 :     restyleHint |= eRestyle_Subtree;
    3302             :   } else if (aElement->IsAttributeMapped(aAttribute)) {
    3303             :     restyleHint |= eRestyle_Self;
    3304             :   }
    3305           0 : 
    3306             :   if (nsIFrame* primaryFrame = aElement->GetPrimaryFrame()) {
    3307           0 :     // See if we have appearance information for a theme.
    3308           0 :     const nsStyleDisplay* disp = primaryFrame->StyleDisplay();
    3309           0 :     if (disp->mAppearance) {
    3310           0 :       nsITheme* theme = PresContext()->GetTheme();
    3311           0 :       if (theme && theme->ThemeSupportsWidget(PresContext(), primaryFrame,
    3312           0 :                                               disp->mAppearance)) {
    3313           0 :         bool repaint = false;
    3314         222 :         theme->WidgetStateChanged(primaryFrame, disp->mAppearance,
    3315         111 :                                   aAttribute, &repaint, aOldValue);
    3316             :         if (repaint) {
    3317             :           changeHint |= nsChangeHint_RepaintFrame;
    3318             :         }
    3319             :       }
    3320             :     }
    3321         133 : 
    3322             :     primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
    3323             :   }
    3324         308 : 
    3325           0 :   if (restyleHint || changeHint) {
    3326             :     Servo_NoteExplicitHints(aElement, restyleHint, changeHint);
    3327             :   }
    3328         308 : 
    3329             :   if (restyleHint) {
    3330             :     // Assuming we need to invalidate cached style in getComputedStyle for
    3331           0 :     // undisplayed elements, since we don't know if it is needed.
    3332             :     IncrementUndisplayedRestyleGeneration();
    3333             : 
    3334             :     // If we change attributes, we have to mark this to be true, so we will
    3335           0 :     // increase the animation generation for the new created transition if any.
    3336             :     mHaveNonAnimationRestyles = true;
    3337         308 :   }
    3338             : }
    3339             : 
    3340           0 : void
    3341             : RestyleManager::ReparentComputedStyleForFirstLine(nsIFrame* aFrame)
    3342             : {
    3343             :   // This is only called when moving frames in or out of the first-line
    3344             :   // pseudo-element (or one of its descendants).  We can't say much about
    3345             :   // aFrame's ancestors, unfortunately (e.g. during a dynamic insert into
    3346             :   // something inside an inline-block on the first line the ancestors could be
    3347             :   // totally arbitrary), but we will definitely find a line frame on the
    3348             :   // ancestor chain.  Note that the lineframe may not actually be the one that
    3349             :   // corresponds to ::first-line; when we're moving _out_ of the ::first-line it
    3350             :   // will be one of the continuations instead.
    3351             : #ifdef DEBUG
    3352           0 :   {
    3353           0 :     nsIFrame* f = aFrame->GetParent();
    3354           0 :     while (f && !f->IsLineFrame()) {
    3355             :       f = f->GetParent();
    3356           0 :     }
    3357             :     MOZ_ASSERT(f, "Must have found a first-line frame");
    3358             :   }
    3359             : #endif
    3360           0 : 
    3361           0 :   DoReparentComputedStyleForFirstLine(aFrame, *StyleSet());
    3362             : }
    3363             : 
    3364           0 : void
    3365             : RestyleManager::DoReparentComputedStyleForFirstLine(nsIFrame* aFrame,
    3366             :                                                     ServoStyleSet& aStyleSet)
    3367           0 : {
    3368             :   if (aFrame->IsBackdropFrame()) {
    3369             :     // Style context of backdrop frame has no parent style, and thus we do not
    3370           0 :     // need to reparent it.
    3371             :     return;
    3372             :   }
    3373           0 : 
    3374             :   if (aFrame->IsPlaceholderFrame()) {
    3375             :     // Also reparent the out-of-flow and all its continuations.  We're doing
    3376             :     // this to match Gecko for now, but it's not clear that this behavior is
    3377             :     // correct per spec.  It's certainly pretty odd for out-of-flows whose
    3378             :     // containing block is not within the first line.
    3379             :     //
    3380             :     // Right now we're somewhat inconsistent in this testcase:
    3381             :     //
    3382             :     //  <style>
    3383             :     //    div { color: orange; clear: left; }
    3384             :     //    div::first-line { color: blue; }
    3385             :     //  </style>
    3386             :     //  <div>
    3387             :     //    <span style="float: left">What color is this text?</span>
    3388             :     //  </div>
    3389             :     //  <div>
    3390             :     //    <span><span style="float: left">What color is this text?</span></span>
    3391             :     //  </div>
    3392             :     //
    3393             :     // We make the first float orange and the second float blue.  On the other
    3394             :     // hand, if the float were within an inline-block that was on the first
    3395             :     // line, arguably it _should_ inherit from the ::first-line...
    3396           0 :     nsIFrame* outOfFlow =
    3397           0 :       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
    3398           0 :     MOZ_ASSERT(outOfFlow, "no out-of-flow frame");
    3399           0 :     for (; outOfFlow; outOfFlow = outOfFlow->GetNextContinuation()) {
    3400             :       DoReparentComputedStyleForFirstLine(outOfFlow, aStyleSet);
    3401             :     }
    3402             :   }
    3403             : 
    3404             :   // FIXME(emilio): This is the only caller of GetParentComputedStyle, let's try
    3405             :   // to remove it?
    3406             :   nsIFrame* providerFrame;
    3407           0 :   ComputedStyle* newParentStyle =
    3408             :     aFrame->GetParentComputedStyle(&providerFrame);
    3409             :   // If our provider is our child, we want to reparent it first, because we
    3410           0 :   // inherit style from it.
    3411           0 :   bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
    3412           0 :   nsIFrame* providerChild = nullptr;
    3413           0 :   if (isChild) {
    3414             :     DoReparentComputedStyleForFirstLine(providerFrame, aStyleSet);
    3415             :     // Get the style again after ReparentComputedStyle() which might have
    3416           0 :     // changed it.
    3417           0 :     newParentStyle = providerFrame->Style();
    3418           0 :     providerChild = providerFrame;
    3419             :     MOZ_ASSERT(!providerFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
    3420             :                "Out of flow provider?");
    3421             :   }
    3422           0 : 
    3423             :   if (!newParentStyle) {
    3424             :     // No need to do anything here for this frame, but we should still reparent
    3425             :     // its descendants, because those may have styles that inherit from the
    3426             :     // parent of this frame (e.g. non-anonymous columns in an anonymous
    3427           0 :     // colgroup).
    3428             :     MOZ_ASSERT(aFrame->Style()->IsNonInheritingAnonBox(),
    3429           0 :                "Why did this frame not end up with a parent context?");
    3430           0 :     ReparentFrameDescendants(aFrame, providerChild, aStyleSet);
    3431             :     return;
    3432             :   }
    3433           0 : 
    3434             :   bool isElement = aFrame->GetContent()->IsElement();
    3435             : 
    3436             :   // We probably don't want to initiate transitions from ReparentComputedStyle,
    3437             :   // since we call it during frame construction rather than in response to
    3438             :   // dynamic changes.
    3439             :   // Also see the comment at the start of
    3440             :   // nsTransitionManager::ConsiderInitiatingTransition.
    3441             :   //
    3442             :   // We don't try to do the fancy copying from previous continuations that
    3443             :   // GeckoRestyleManager does here, because that relies on knowing the parents
    3444           0 :   // of ComputedStyles, and we don't know those.
    3445             :   ComputedStyle* oldStyle = aFrame->Style();
    3446           0 :   Element* ourElement =
    3447           0 :     oldStyle->GetPseudoType() == CSSPseudoElementType::NotPseudo &&
    3448           0 :     isElement ?
    3449           0 :       aFrame->GetContent()->AsElement() :
    3450           0 :       nullptr;
    3451             :   ComputedStyle* newParent = newParentStyle;
    3452             : 
    3453           0 :   ComputedStyle* newParentIgnoringFirstLine;
    3454           0 :   if (newParent->GetPseudoType() == CSSPseudoElementType::firstLine) {
    3455             :     MOZ_ASSERT(providerFrame && providerFrame->GetParent()->
    3456             :                IsFrameOfType(nsIFrame::eBlockFrame),
    3457             :                "How could we get a ::first-line parent style without having "
    3458             :                "a ::first-line provider frame?");
    3459             :     // If newParent is a ::first-line style, get the parent blockframe, and then
    3460             :     // correct it for our pseudo as needed (e.g. stepping out of anon boxes).
    3461           0 :     // Use the resulting style for the "parent style ignoring ::first-line".
    3462             :     nsIFrame* blockFrame = providerFrame->GetParent();
    3463           0 :     nsIFrame* correctedFrame =
    3464           0 :       nsFrame::CorrectStyleParentFrame(blockFrame, oldStyle->GetPseudo());
    3465             :     newParentIgnoringFirstLine = correctedFrame->Style();
    3466             :   } else {
    3467             :     newParentIgnoringFirstLine = newParent;
    3468             :   }
    3469           0 : 
    3470             :   if (!providerFrame) {
    3471             :     // No providerFrame means we inherited from a display:contents thing.  Our
    3472             :     // layout parent style is the style of our nearest ancestor frame.  But we have
    3473             :     // to be careful to do that with our placeholder, not with us, if we're out of
    3474           0 :     // flow.
    3475           0 :     if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
    3476             :       aFrame->GetPlaceholderFrame()->GetLayoutParentStyleForOutOfFlow(&providerFrame);
    3477           0 :     } else {
    3478             :       providerFrame = nsFrame::CorrectStyleParentFrame(aFrame->GetParent(),
    3479             :                                                        oldStyle->GetPseudo());
    3480             :     }
    3481           0 :   }
    3482             :   ComputedStyle* layoutParent = providerFrame->Style();
    3483             : 
    3484           0 :   RefPtr<ComputedStyle> newStyle =
    3485             :     aStyleSet.ReparentComputedStyle(oldStyle,
    3486             :                                     newParent,
    3487             :                                     newParentIgnoringFirstLine,
    3488           0 :                                     layoutParent,
    3489           0 :                                     ourElement);
    3490             :   aFrame->SetComputedStyle(newStyle);
    3491             : 
    3492             :   // This logic somewhat mirrors the logic in
    3493           0 :   // RestyleManager::ProcessPostTraversal.
    3494             :   if (isElement) {
    3495             :     // We can't use UpdateAdditionalComputedStyles as-is because it needs a
    3496             :     // ServoRestyleState and maintaining one of those during a _frametree_
    3497             :     // traversal is basically impossible.
    3498           0 :     uint32_t index = 0;
    3499             :     while (auto* oldAdditionalStyle = aFrame->GetAdditionalComputedStyle(index)) {
    3500           0 :       RefPtr<ComputedStyle> newAdditionalContext =
    3501             :         aStyleSet.ReparentComputedStyle(oldAdditionalStyle,
    3502             :                                         newStyle,
    3503             :                                         newStyle,
    3504           0 :                                         newStyle,
    3505           0 :                                         nullptr);
    3506           0 :       aFrame->SetAdditionalComputedStyle(index, newAdditionalContext);
    3507           0 :       ++index;
    3508             :     }
    3509             :   }
    3510             : 
    3511             :   // Generally, owned anon boxes are our descendants.  The only exceptions are
    3512             :   // tables (for the table wrapper) and inline frames (for the block part of the
    3513             :   // block-in-inline split).  We're going to update our descendants when looping
    3514             :   // over kids, and we don't want to update the block part of a block-in-inline
    3515             :   // split if the inline is on the first line but the block is not (and if the
    3516             :   // block is, it's the child of something else on the first line and will get
    3517             :   // updated as a child).  And given how this method ends up getting called, if
    3518             :   // we reach here for a table frame, we are already in the middle of
    3519             :   // reparenting the table wrapper frame.  So no need to
    3520             :   // UpdateStyleOfOwnedAnonBoxes() here.
    3521           0 : 
    3522             :   ReparentFrameDescendants(aFrame, providerChild, aStyleSet);
    3523             : 
    3524             :   // We do not need to do the equivalent of UpdateFramePseudoElementStyles,
    3525             :   // because those are handled by our descendant walk.
    3526             : }
    3527             : 
    3528           0 : void
    3529             : RestyleManager::ReparentFrameDescendants(nsIFrame* aFrame,
    3530             :                                          nsIFrame* aProviderChild,
    3531             :                                          ServoStyleSet& aStyleSet)
    3532           0 : {
    3533           0 :   if (aFrame->GetContent()->IsElement() &&
    3534             :       !aFrame->GetContent()->AsElement()->HasServoData()) {
    3535             :     // We're getting into a display: none subtree, avoid reparenting into stuff
    3536           0 :     // that is going to go away anyway in seconds.
    3537             :     return;
    3538           0 :   }
    3539           0 :   nsIFrame::ChildListIterator lists(aFrame);
    3540           0 :   for (; !lists.IsDone(); lists.Next()) {
    3541             :     for (nsIFrame* child : lists.CurrentList()) {
    3542           0 :       // only do frames that are in flow
    3543             :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    3544             :           child != aProviderChild) {
    3545             :         DoReparentComputedStyleForFirstLine(child, aStyleSet);
    3546             :       }
    3547             :     }
    3548             :   }
    3549             : }
    3550             : 
    3551             : } // namespace mozilla

Generated by: LCOV version 1.13-14-ga5dd952