LCOV - code coverage report
Current view: top level - layout/base - RestyleManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 327 827 39.5 %
Date: 2017-07-14 16:53:18 Functions: 26 36 72.2 %
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             : #include "mozilla/RestyleManagerInlines.h"
       9             : 
      10             : #include "Layers.h"
      11             : #include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
      12             : #include "mozilla/StyleSetHandleInlines.h"
      13             : #include "nsIFrame.h"
      14             : #include "nsIPresShellInlines.h"
      15             : 
      16             : 
      17             : namespace mozilla {
      18             : 
      19          28 : RestyleManager::RestyleManager(StyleBackendType aType,
      20          28 :                                nsPresContext* aPresContext)
      21             :   : mPresContext(aPresContext)
      22             :   , mRestyleGeneration(1)
      23             :   , mUndisplayedRestyleGeneration(1)
      24             :   , mHoverGeneration(0)
      25             :   , mType(aType)
      26             :   , mInStyleRefresh(false)
      27          28 :   , mAnimationGeneration(0)
      28             : {
      29          28 :   MOZ_ASSERT(mPresContext);
      30          28 : }
      31             : 
      32             : void
      33          19 : RestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild)
      34             : {
      35          19 :   RestyleForInsertOrChange(aContainer, aChild);
      36          19 : }
      37             : 
      38             : void
      39          56 : RestyleManager::ContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent)
      40             : {
      41          56 :   RestyleForAppend(aContainer, aFirstNewContent);
      42          56 : }
      43             : 
      44             : void
      45           0 : RestyleManager::RestyleForEmptyChange(Element* aContainer)
      46             : {
      47             :   // In some cases (:empty + E, :empty ~ E), a change in the content of
      48             :   // an element requires restyling its parent's siblings.
      49           0 :   nsRestyleHint hint = eRestyle_Subtree;
      50           0 :   nsIContent* grandparent = aContainer->GetParent();
      51           0 :   if (grandparent &&
      52           0 :       (grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
      53           0 :     hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
      54             :   }
      55           0 :   PostRestyleEvent(aContainer, hint, nsChangeHint(0));
      56           0 : }
      57             : 
      58             : void
      59          56 : RestyleManager::RestyleForAppend(nsIContent* aContainer,
      60             :                                  nsIContent* aFirstNewContent)
      61             : {
      62             :   // The container cannot be a document, but might be a ShadowRoot.
      63          56 :   if (!aContainer->IsElement()) {
      64           0 :     return;
      65             :   }
      66          56 :   Element* container = aContainer->AsElement();
      67             : 
      68             : #ifdef DEBUG
      69             :   {
      70         213 :     for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
      71         157 :       NS_ASSERTION(!cur->IsRootOfAnonymousSubtree(),
      72             :                    "anonymous nodes should not be in child lists");
      73             :     }
      74             :   }
      75             : #endif
      76             :   uint32_t selectorFlags =
      77          56 :     container->GetFlags() & (NODE_ALL_SELECTOR_FLAGS &
      78          56 :                              ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
      79          56 :   if (selectorFlags == 0)
      80          56 :     return;
      81             : 
      82           0 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
      83             :     // see whether we need to restyle the container
      84           0 :     bool wasEmpty = true; // :empty or :-moz-only-whitespace
      85           0 :     for (nsIContent* cur = container->GetFirstChild();
      86           0 :          cur != aFirstNewContent;
      87           0 :          cur = cur->GetNextSibling()) {
      88             :       // We don't know whether we're testing :empty or :-moz-only-whitespace,
      89             :       // so be conservative and assume :-moz-only-whitespace (i.e., make
      90             :       // IsSignificantChild less likely to be true, and thus make us more
      91             :       // likely to restyle).
      92           0 :       if (nsStyleUtil::IsSignificantChild(cur, true, false)) {
      93           0 :         wasEmpty = false;
      94           0 :         break;
      95             :       }
      96             :     }
      97           0 :     if (wasEmpty) {
      98           0 :       RestyleForEmptyChange(container);
      99           0 :       return;
     100             :     }
     101             :   }
     102             : 
     103           0 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     104           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     105             :     // Restyling the container is the most we can do here, so we're done.
     106           0 :     return;
     107             :   }
     108             : 
     109           0 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     110             :     // restyle the last element child before this node
     111           0 :     for (nsIContent* cur = aFirstNewContent->GetPreviousSibling();
     112           0 :          cur;
     113           0 :          cur = cur->GetPreviousSibling()) {
     114           0 :       if (cur->IsElement()) {
     115           0 :         PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, nsChangeHint(0));
     116           0 :         break;
     117             :       }
     118             :     }
     119             :   }
     120             : }
     121             : 
     122             : // Needed since we can't use PostRestyleEvent on non-elements (with
     123             : // eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
     124             : // eRestyle_LaterSiblings) as appropriate).
     125             : static void
     126           6 : RestyleSiblingsStartingWith(RestyleManager* aRestyleManager,
     127             :                             nsIContent* aStartingSibling /* may be null */)
     128             : {
     129           6 :   for (nsIContent* sibling = aStartingSibling; sibling;
     130           0 :        sibling = sibling->GetNextSibling()) {
     131           5 :     if (sibling->IsElement()) {
     132             :       aRestyleManager->
     133           5 :         PostRestyleEvent(sibling->AsElement(),
     134             :                          nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
     135           5 :                          nsChangeHint(0));
     136           5 :       break;
     137             :     }
     138             :   }
     139           6 : }
     140             : 
     141             : // Restyling for a ContentInserted or CharacterDataChanged notification.
     142             : // This could be used for ContentRemoved as well if we got the
     143             : // notification before the removal happened (and sometimes
     144             : // CharacterDataChanged is more like a removal than an addition).
     145             : // The comments are written and variables are named in terms of it being
     146             : // a ContentInserted notification.
     147             : void
     148          19 : RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
     149             :                                          nsIContent* aChild)
     150             : {
     151             :   // The container might be a document or a ShadowRoot.
     152          19 :   if (!aContainer->IsElement()) {
     153           0 :     return;
     154             :   }
     155          19 :   Element* container = aContainer->AsElement();
     156             : 
     157          19 :   NS_ASSERTION(!aChild->IsRootOfAnonymousSubtree(),
     158             :                "anonymous nodes should not be in child lists");
     159          19 :   uint32_t selectorFlags = container->GetFlags() & NODE_ALL_SELECTOR_FLAGS;
     160          19 :   if (selectorFlags == 0)
     161          14 :     return;
     162             : 
     163           5 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     164             :     // see whether we need to restyle the container
     165           0 :     bool wasEmpty = true; // :empty or :-moz-only-whitespace
     166           0 :     for (nsIContent* child = container->GetFirstChild();
     167           0 :          child;
     168           0 :          child = child->GetNextSibling()) {
     169           0 :       if (child == aChild)
     170           0 :         continue;
     171             :       // We don't know whether we're testing :empty or :-moz-only-whitespace,
     172             :       // so be conservative and assume :-moz-only-whitespace (i.e., make
     173             :       // IsSignificantChild less likely to be true, and thus make us more
     174             :       // likely to restyle).
     175           0 :       if (nsStyleUtil::IsSignificantChild(child, true, false)) {
     176           0 :         wasEmpty = false;
     177           0 :         break;
     178             :       }
     179             :     }
     180           0 :     if (wasEmpty) {
     181           0 :       RestyleForEmptyChange(container);
     182           0 :       return;
     183             :     }
     184             :   }
     185             : 
     186           5 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     187           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     188             :     // Restyling the container is the most we can do here, so we're done.
     189           0 :     return;
     190             :   }
     191             : 
     192           5 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     193             :     // Restyle all later siblings.
     194           5 :     RestyleSiblingsStartingWith(this, aChild->GetNextSibling());
     195             :   }
     196             : 
     197           5 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     198             :     // restyle the previously-first element child if it is after this node
     199           0 :     bool passedChild = false;
     200           0 :     for (nsIContent* content = container->GetFirstChild();
     201           0 :          content;
     202           0 :          content = content->GetNextSibling()) {
     203           0 :       if (content == aChild) {
     204           0 :         passedChild = true;
     205           0 :         continue;
     206             :       }
     207           0 :       if (content->IsElement()) {
     208           0 :         if (passedChild) {
     209           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     210           0 :                            nsChangeHint(0));
     211             :         }
     212           0 :         break;
     213             :       }
     214             :     }
     215             :     // restyle the previously-last element child if it is before this node
     216           0 :     passedChild = false;
     217           0 :     for (nsIContent* content = container->GetLastChild();
     218           0 :          content;
     219           0 :          content = content->GetPreviousSibling()) {
     220           0 :       if (content == aChild) {
     221           0 :         passedChild = true;
     222           0 :         continue;
     223             :       }
     224           0 :       if (content->IsElement()) {
     225           0 :         if (passedChild) {
     226           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     227           0 :                            nsChangeHint(0));
     228             :         }
     229           0 :         break;
     230             :       }
     231             :     }
     232             :   }
     233             : }
     234             : 
     235             : void
     236          11 : RestyleManager::ContentRemoved(nsINode* aContainer,
     237             :                                nsIContent* aOldChild,
     238             :                                nsIContent* aFollowingSibling)
     239             : {
     240             :   // The container might be a document or a ShadowRoot.
     241          11 :   if (!aContainer->IsElement()) {
     242           0 :     return;
     243             :   }
     244          11 :   Element* container = aContainer->AsElement();
     245             : 
     246          11 :   if (aOldChild->IsRootOfAnonymousSubtree()) {
     247             :     // This should be an assert, but this is called incorrectly in
     248             :     // HTMLEditor::DeleteRefToAnonymousNode and the assertions were clogging
     249             :     // up the logs.  Make it an assert again when that's fixed.
     250           0 :     MOZ_ASSERT(aOldChild->GetProperty(nsGkAtoms::restylableAnonymousNode),
     251             :                "anonymous nodes should not be in child lists (bug 439258)");
     252             :   }
     253          11 :   uint32_t selectorFlags = container->GetFlags() & NODE_ALL_SELECTOR_FLAGS;
     254          11 :   if (selectorFlags == 0)
     255          10 :     return;
     256             : 
     257           1 :   if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
     258             :     // see whether we need to restyle the container
     259           0 :     bool isEmpty = true; // :empty or :-moz-only-whitespace
     260           0 :     for (nsIContent* child = container->GetFirstChild();
     261           0 :          child;
     262           0 :          child = child->GetNextSibling()) {
     263             :       // We don't know whether we're testing :empty or :-moz-only-whitespace,
     264             :       // so be conservative and assume :-moz-only-whitespace (i.e., make
     265             :       // IsSignificantChild less likely to be true, and thus make us more
     266             :       // likely to restyle).
     267           0 :       if (nsStyleUtil::IsSignificantChild(child, true, false)) {
     268           0 :         isEmpty = false;
     269           0 :         break;
     270             :       }
     271             :     }
     272           0 :     if (isEmpty) {
     273           0 :       RestyleForEmptyChange(container);
     274           0 :       return;
     275             :     }
     276             :   }
     277             : 
     278           1 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
     279           0 :     PostRestyleEvent(container, eRestyle_Subtree, nsChangeHint(0));
     280             :     // Restyling the container is the most we can do here, so we're done.
     281           0 :     return;
     282             :   }
     283             : 
     284           1 :   if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
     285             :     // Restyle all later siblings.
     286           1 :     RestyleSiblingsStartingWith(this, aFollowingSibling);
     287             :   }
     288             : 
     289           1 :   if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
     290             :     // restyle the now-first element child if it was after aOldChild
     291           0 :     bool reachedFollowingSibling = false;
     292           0 :     for (nsIContent* content = container->GetFirstChild();
     293           0 :          content;
     294           0 :          content = content->GetNextSibling()) {
     295           0 :       if (content == aFollowingSibling) {
     296           0 :         reachedFollowingSibling = true;
     297             :         // do NOT continue here; we might want to restyle this node
     298             :       }
     299           0 :       if (content->IsElement()) {
     300           0 :         if (reachedFollowingSibling) {
     301           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
     302           0 :                            nsChangeHint(0));
     303             :         }
     304           0 :         break;
     305             :       }
     306             :     }
     307             :     // restyle the now-last element child if it was before aOldChild
     308           0 :     reachedFollowingSibling = (aFollowingSibling == nullptr);
     309           0 :     for (nsIContent* content = container->GetLastChild();
     310           0 :          content;
     311           0 :          content = content->GetPreviousSibling()) {
     312           0 :       if (content->IsElement()) {
     313           0 :         if (reachedFollowingSibling) {
     314           0 :           PostRestyleEvent(content->AsElement(), eRestyle_Subtree, nsChangeHint(0));
     315             :         }
     316           0 :         break;
     317             :       }
     318           0 :       if (content == aFollowingSibling) {
     319           0 :         reachedFollowingSibling = true;
     320             :       }
     321             :     }
     322             :   }
     323             : }
     324             : 
     325             : /**
     326             :  * Calculates the change hint and the restyle hint for a given content state
     327             :  * change.
     328             :  *
     329             :  * This is called from both Restyle managers.
     330             :  */
     331             : void
     332          51 : RestyleManager::ContentStateChangedInternal(Element* aElement,
     333             :                                             EventStates aStateMask,
     334             :                                             nsChangeHint* aOutChangeHint,
     335             :                                             nsRestyleHint* aOutRestyleHint)
     336             : {
     337          51 :   MOZ_ASSERT(!mInStyleRefresh);
     338          51 :   MOZ_ASSERT(aOutChangeHint);
     339          51 :   MOZ_ASSERT(aOutRestyleHint);
     340             : 
     341          51 :   StyleSetHandle styleSet = PresContext()->StyleSet();
     342          51 :   NS_ASSERTION(styleSet, "couldn't get style set");
     343             : 
     344          51 :   *aOutChangeHint = nsChangeHint(0);
     345             :   // Any change to a content state that affects which frames we construct
     346             :   // must lead to a frame reconstruct here if we already have a frame.
     347             :   // Note that we never decide through non-CSS means to not create frames
     348             :   // based on content states, so if we already don't have a frame we don't
     349             :   // need to force a reframe -- if it's needed, the HasStateDependentStyle
     350             :   // call will handle things.
     351          51 :   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
     352          51 :   CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
     353          51 :   if (primaryFrame) {
     354             :     // If it's generated content, ignore LOADING/etc state changes on it.
     355         225 :     if (!primaryFrame->IsGeneratedContentFrame() &&
     356         180 :         aStateMask.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
     357         225 :                                          NS_EVENT_STATE_USERDISABLED |
     358          90 :                                          NS_EVENT_STATE_SUPPRESSED |
     359         135 :                                          NS_EVENT_STATE_LOADING)) {
     360           0 :       *aOutChangeHint = nsChangeHint_ReconstructFrame;
     361             :     } else {
     362          45 :       uint8_t app = primaryFrame->StyleDisplay()->mAppearance;
     363          45 :       if (app) {
     364           3 :         nsITheme* theme = PresContext()->GetTheme();
     365           6 :         if (theme &&
     366           3 :             theme->ThemeSupportsWidget(PresContext(), primaryFrame, app)) {
     367           3 :           bool repaint = false;
     368           3 :           theme->WidgetStateChanged(primaryFrame, app, nullptr, &repaint,
     369           6 :                                     nullptr);
     370           3 :           if (repaint) {
     371           0 :             *aOutChangeHint |= nsChangeHint_RepaintFrame;
     372             :           }
     373             :         }
     374             :       }
     375             :     }
     376             : 
     377          45 :     pseudoType = primaryFrame->StyleContext()->GetPseudoType();
     378             : 
     379          45 :     primaryFrame->ContentStatesChanged(aStateMask);
     380             :   }
     381             : 
     382          51 :   if (pseudoType >= CSSPseudoElementType::Count) {
     383          51 :     *aOutRestyleHint = styleSet->HasStateDependentStyle(aElement, aStateMask);
     384           0 :   } else if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(
     385             :                pseudoType)) {
     386             :     // If aElement is a pseudo-element, we want to check to see whether there
     387             :     // are any state-dependent rules applying to that pseudo.
     388             :     Element* ancestor =
     389           0 :       ElementForStyleContext(nullptr, primaryFrame, pseudoType);
     390           0 :     *aOutRestyleHint = styleSet->HasStateDependentStyle(ancestor, pseudoType,
     391             :                                                         aElement, aStateMask);
     392             :   } else {
     393           0 :     *aOutRestyleHint = nsRestyleHint(0);
     394             :   }
     395             : 
     396          51 :   if (aStateMask.HasState(NS_EVENT_STATE_HOVER) && *aOutRestyleHint != 0) {
     397           0 :     IncrementHoverGeneration();
     398             :   }
     399             : 
     400          51 :   if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
     401             :     // Exposing information to the page about whether the link is
     402             :     // visited or not isn't really something we can worry about here.
     403             :     // FIXME: We could probably do this a bit better.
     404           0 :     *aOutChangeHint |= nsChangeHint_RepaintFrame;
     405             :   }
     406          51 : }
     407             : 
     408             : /* static */ nsCString
     409           0 : RestyleManager::RestyleHintToString(nsRestyleHint aHint)
     410             : {
     411           0 :   nsCString result;
     412           0 :   bool any = false;
     413             :   const char* names[] = {
     414             :     "Self", "SomeDescendants", "Subtree", "LaterSiblings", "CSSTransitions",
     415             :     "CSSAnimations", "StyleAttribute", "StyleAttribute_Animations",
     416             :     "Force", "ForceDescendants"
     417           0 :   };
     418           0 :   uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
     419           0 :   uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
     420           0 :   for (uint32_t i = 0; i < ArrayLength(names); i++) {
     421           0 :     if (hint & (1 << i)) {
     422           0 :       if (any) {
     423           0 :         result.AppendLiteral(" | ");
     424             :       }
     425           0 :       result.AppendPrintf("eRestyle_%s", names[i]);
     426           0 :       any = true;
     427             :     }
     428             :   }
     429           0 :   if (rest) {
     430           0 :     if (any) {
     431           0 :       result.AppendLiteral(" | ");
     432             :     }
     433           0 :     result.AppendPrintf("0x%0x", rest);
     434             :   } else {
     435           0 :     if (!any) {
     436           0 :       result.AppendLiteral("0");
     437             :     }
     438             :   }
     439           0 :   return result;
     440             : }
     441             : 
     442             : #ifdef DEBUG
     443             : /* static */ nsCString
     444           0 : RestyleManager::ChangeHintToString(nsChangeHint aHint)
     445             : {
     446           0 :   nsCString result;
     447           0 :   bool any = false;
     448             :   const char* names[] = {
     449             :     "RepaintFrame", "NeedReflow", "ClearAncestorIntrinsics",
     450             :     "ClearDescendantIntrinsics", "NeedDirtyReflow", "SyncFrameView",
     451             :     "UpdateCursor", "UpdateEffects", "UpdateOpacityLayer",
     452             :     "UpdateTransformLayer", "ReconstructFrame", "UpdateOverflow",
     453             :     "UpdateSubtreeOverflow", "UpdatePostTransformOverflow",
     454             :     "UpdateParentOverflow",
     455             :     "ChildrenOnlyTransform", "RecomputePosition", "UpdateContainingBlock",
     456             :     "BorderStyleNoneChange", "UpdateTextPath", "SchedulePaint",
     457             :     "NeutralChange", "InvalidateRenderingObservers",
     458             :     "ReflowChangesSizeOrPosition", "UpdateComputedBSize",
     459             :     "UpdateUsesOpacity", "UpdateBackgroundPosition",
     460             :     "AddOrRemoveTransform", "CSSOverflowChange",
     461             :     "UpdateWidgetProperties"
     462           0 :   };
     463             :   static_assert(nsChangeHint_AllHints == (1 << ArrayLength(names)) - 1,
     464             :                 "Name list doesn't match change hints.");
     465           0 :   uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
     466           0 :   uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
     467           0 :   if ((hint & NS_STYLE_HINT_REFLOW) == NS_STYLE_HINT_REFLOW) {
     468           0 :     result.AppendLiteral("NS_STYLE_HINT_REFLOW");
     469           0 :     hint = hint & ~NS_STYLE_HINT_REFLOW;
     470           0 :     any = true;
     471           0 :   } else if ((hint & nsChangeHint_AllReflowHints) == nsChangeHint_AllReflowHints) {
     472           0 :     result.AppendLiteral("nsChangeHint_AllReflowHints");
     473           0 :     hint = hint & ~nsChangeHint_AllReflowHints;
     474           0 :     any = true;
     475           0 :   } else if ((hint & NS_STYLE_HINT_VISUAL) == NS_STYLE_HINT_VISUAL) {
     476           0 :     result.AppendLiteral("NS_STYLE_HINT_VISUAL");
     477           0 :     hint = hint & ~NS_STYLE_HINT_VISUAL;
     478           0 :     any = true;
     479             :   }
     480           0 :   for (uint32_t i = 0; i < ArrayLength(names); i++) {
     481           0 :     if (hint & (1 << i)) {
     482           0 :       if (any) {
     483           0 :         result.AppendLiteral(" | ");
     484             :       }
     485           0 :       result.AppendPrintf("nsChangeHint_%s", names[i]);
     486           0 :       any = true;
     487             :     }
     488             :   }
     489           0 :   if (rest) {
     490           0 :     if (any) {
     491           0 :       result.AppendLiteral(" | ");
     492             :     }
     493           0 :     result.AppendPrintf("0x%0x", rest);
     494             :   } else {
     495           0 :     if (!any) {
     496           0 :       result.AppendLiteral("nsChangeHint(0)");
     497             :     }
     498             :   }
     499           0 :   return result;
     500             : }
     501             : #endif
     502             : 
     503             : /**
     504             :  * Frame construction helpers follow.
     505             :  */
     506             : #ifdef DEBUG
     507             : static bool gInApplyRenderingChangeToTree = false;
     508             : #endif
     509             : 
     510             : #ifdef DEBUG
     511             : static void
     512           0 : DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
     513             : {
     514           0 :   if (aFrame) {
     515           0 :     fputs("frame: ", stdout);
     516           0 :     nsAutoString name;
     517           0 :     aFrame->GetFrameName(name);
     518           0 :     fputs(NS_LossyConvertUTF16toASCII(name).get(), stdout);
     519           0 :     fprintf(stdout, " (%p)", static_cast<void*>(aFrame));
     520             :   }
     521           0 :   if (aContext) {
     522           0 :     fprintf(stdout, " style: %p ", static_cast<void*>(aContext));
     523             : 
     524           0 :     nsIAtom* pseudoTag = aContext->GetPseudo();
     525           0 :     if (pseudoTag) {
     526           0 :       nsAutoString buffer;
     527           0 :       pseudoTag->ToString(buffer);
     528           0 :       fputs(NS_LossyConvertUTF16toASCII(buffer).get(), stdout);
     529           0 :       fputs(" ", stdout);
     530             :     }
     531           0 :     fputs("{}\n", stdout);
     532             :   }
     533           0 : }
     534             : 
     535             : static void
     536           0 : VerifySameTree(nsStyleContext* aContext1, nsStyleContext* aContext2)
     537             : {
     538           0 :   nsStyleContext* top1 = aContext1;
     539           0 :   nsStyleContext* top2 = aContext2;
     540             :   nsStyleContext* parent;
     541             :   for (;;) {
     542           0 :     parent = top1->GetParent();
     543           0 :     if (!parent)
     544           0 :       break;
     545           0 :     top1 = parent;
     546             :   }
     547             :   for (;;) {
     548           0 :     parent = top2->GetParent();
     549           0 :     if (!parent)
     550           0 :       break;
     551           0 :     top2 = parent;
     552             :   }
     553           0 :   NS_ASSERTION(top1 == top2,
     554             :                "Style contexts are not in the same style context tree");
     555           0 : }
     556             : 
     557             : static void
     558         427 : VerifyContextParent(nsIFrame* aFrame, nsStyleContext* aContext,
     559             :                     nsStyleContext* aParentContext)
     560             : {
     561             :   // get the contexts not provided
     562         427 :   if (!aContext) {
     563          13 :     aContext = aFrame->StyleContext();
     564             :   }
     565             : 
     566         427 :   if (!aParentContext) {
     567             :     nsIFrame* providerFrame;
     568         427 :     aParentContext = aFrame->GetParentStyleContext(&providerFrame);
     569             :     // aParentContext could still be null
     570             :   }
     571             : 
     572         427 :   NS_ASSERTION(aContext, "Failure to get required contexts");
     573         427 :   nsStyleContext* actualParentContext = aContext->GetParent();
     574             : 
     575         427 :   if (aParentContext) {
     576         414 :     if (aParentContext != actualParentContext) {
     577           0 :       DumpContext(aFrame, aContext);
     578           0 :       if (aContext == aParentContext) {
     579           0 :         NS_ERROR("Using parent's style context");
     580             :       } else {
     581           0 :         NS_ERROR("Wrong parent style context");
     582           0 :         fputs("Wrong parent style context: ", stdout);
     583           0 :         DumpContext(nullptr, actualParentContext);
     584           0 :         fputs("should be using: ", stdout);
     585           0 :         DumpContext(nullptr, aParentContext);
     586           0 :         VerifySameTree(actualParentContext, aParentContext);
     587           0 :         fputs("\n", stdout);
     588             :       }
     589             :     }
     590             : 
     591             :   } else {
     592          13 :     if (actualParentContext) {
     593           0 :       NS_ERROR("Have parent context and shouldn't");
     594           0 :       DumpContext(aFrame, aContext);
     595           0 :       fputs("Has parent context: ", stdout);
     596           0 :       DumpContext(nullptr, actualParentContext);
     597           0 :       fputs("Should be null\n\n", stdout);
     598             :     }
     599             :   }
     600             : 
     601         427 :   nsStyleContext* childStyleIfVisited = aContext->GetStyleIfVisited();
     602             :   // Either childStyleIfVisited has aContext->GetParent()->GetStyleIfVisited()
     603             :   // as the parent or it has a different rulenode from aContext _and_ has
     604             :   // aContext->GetParent() as the parent.
     605         427 :   if (childStyleIfVisited &&
     606           0 :       !((childStyleIfVisited->RuleNode() != aContext->RuleNode() &&
     607           0 :          childStyleIfVisited->GetParent() == aContext->GetParent()) ||
     608           0 :         childStyleIfVisited->GetParent() ==
     609           0 :           aContext->GetParent()->GetStyleIfVisited())) {
     610           0 :     NS_ERROR("Visited style has wrong parent");
     611           0 :     DumpContext(aFrame, aContext);
     612           0 :     fputs("\n", stdout);
     613             :   }
     614         427 : }
     615             : 
     616             : static void
     617         414 : VerifyStyleTree(nsIFrame* aFrame)
     618             : {
     619         414 :   nsStyleContext* context = aFrame->StyleContext();
     620         414 :   VerifyContextParent(aFrame, context, nullptr);
     621             : 
     622         828 :   nsIFrame::ChildListIterator lists(aFrame);
     623         864 :   for (; !lists.IsDone(); lists.Next()) {
     624         547 :     for (nsIFrame* child : lists.CurrentList()) {
     625         322 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
     626             :         // only do frames that are in flow
     627         322 :         if (child->IsPlaceholderFrame()) {
     628             :           // placeholder: first recurse and verify the out of flow frame,
     629             :           // then verify the placeholder's context
     630             :           nsIFrame* outOfFlowFrame =
     631          13 :             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
     632             : 
     633             :           // recurse to out of flow frame, letting the parent context get resolved
     634          13 :           do {
     635          13 :             VerifyStyleTree(outOfFlowFrame);
     636          13 :           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
     637             : 
     638             :           // verify placeholder using the parent frame's context as
     639             :           // parent context
     640          13 :           VerifyContextParent(child, nullptr, nullptr);
     641             :         } else { // regular frame
     642         309 :           VerifyStyleTree(child);
     643             :         }
     644             :       }
     645             :     }
     646             :   }
     647             : 
     648             :   // do additional contexts
     649         414 :   int32_t contextIndex = 0;
     650         414 :   for (nsStyleContext* extraContext;
     651         414 :        (extraContext = aFrame->GetAdditionalStyleContext(contextIndex));
     652             :        ++contextIndex) {
     653           0 :     VerifyContextParent(aFrame, extraContext, context);
     654             :   }
     655         414 : }
     656             : 
     657             : void
     658          92 : RestyleManager::DebugVerifyStyleTree(nsIFrame* aFrame)
     659             : {
     660          92 :   if (IsServo()) {
     661             :     // XXXheycam For now, we know that we don't use the same inheritance
     662             :     // hierarchy for certain cases, so just skip these assertions until
     663             :     // we work out what we want to assert (bug 1322570).
     664           0 :     return;
     665             :   }
     666          92 :   if (aFrame) {
     667          92 :     VerifyStyleTree(aFrame);
     668             :   }
     669             : }
     670             : 
     671             : #endif // DEBUG
     672             : 
     673             : /**
     674             :  * Sync views on aFrame and all of aFrame's descendants (following placeholders),
     675             :  * if aChange has nsChangeHint_SyncFrameView.
     676             :  * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants
     677             :  * (following placeholders), if aChange has nsChangeHint_RepaintFrame.
     678             :  * aFrame should be some combination of nsChangeHint_SyncFrameView,
     679             :  * nsChangeHint_RepaintFrame, nsChangeHint_UpdateOpacityLayer and
     680             :  * nsChangeHint_SchedulePaint, nothing else.
     681             : */
     682             : static void SyncViewsAndInvalidateDescendants(nsIFrame* aFrame,
     683             :                                               nsChangeHint aChange);
     684             : 
     685             : static void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
     686             : 
     687             : /**
     688             :  * To handle nsChangeHint_ChildrenOnlyTransform we must iterate over the child
     689             :  * frames of the SVG frame concerned. This helper function is used to find that
     690             :  * SVG frame when we encounter nsChangeHint_ChildrenOnlyTransform to ensure
     691             :  * that we iterate over the intended children, since sometimes we end up
     692             :  * handling that hint while processing hints for one of the SVG frame's
     693             :  * ancestor frames.
     694             :  *
     695             :  * The reason that we sometimes end up trying to process the hint for an
     696             :  * ancestor of the SVG frame that the hint is intended for is due to the way we
     697             :  * process restyle events. ApplyRenderingChangeToTree adjusts the frame from
     698             :  * the restyled element's principle frame to one of its ancestor frames based
     699             :  * on what nsCSSRendering::FindBackground returns, since the background style
     700             :  * may have been propagated up to an ancestor frame. Processing hints using an
     701             :  * ancestor frame is fine in general, but nsChangeHint_ChildrenOnlyTransform is
     702             :  * a special case since it is intended to update the children of a specific
     703             :  * frame.
     704             :  */
     705             : static nsIFrame*
     706           0 : GetFrameForChildrenOnlyTransformHint(nsIFrame* aFrame)
     707             : {
     708           0 :   if (aFrame->IsViewportFrame()) {
     709             :     // This happens if the root-<svg> is fixed positioned, in which case we
     710             :     // can't use aFrame->GetContent() to find the primary frame, since
     711             :     // GetContent() returns nullptr for ViewportFrame.
     712           0 :     aFrame = aFrame->PrincipalChildList().FirstChild();
     713             :   }
     714             :   // For an nsHTMLScrollFrame, this will get the SVG frame that has the
     715             :   // children-only transforms:
     716           0 :   aFrame = aFrame->GetContent()->GetPrimaryFrame();
     717           0 :   if (aFrame->IsSVGOuterSVGFrame()) {
     718           0 :     aFrame = aFrame->PrincipalChildList().FirstChild();
     719           0 :     MOZ_ASSERT(aFrame->IsSVGOuterSVGAnonChildFrame(),
     720             :                "Where is the nsSVGOuterSVGFrame's anon child??");
     721             :   }
     722           0 :   MOZ_ASSERT(aFrame->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer),
     723             :              "Children-only transforms only expected on SVG frames");
     724           0 :   return aFrame;
     725             : }
     726             : 
     727             : // Returns true if this function managed to successfully move a frame, and
     728             : // false if it could not process the position change, and a reflow should
     729             : // be performed instead.
     730             : bool
     731           0 : RecomputePosition(nsIFrame* aFrame)
     732             : {
     733             :   // Don't process position changes on table frames, since we already handle
     734             :   // the dynamic position change on the table wrapper frame, and the
     735             :   // reflow-based fallback code path also ignores positions on inner table
     736             :   // frames.
     737           0 :   if (aFrame->IsTableFrame()) {
     738           0 :     return true;
     739             :   }
     740             : 
     741           0 :   const nsStyleDisplay* display = aFrame->StyleDisplay();
     742             :   // Changes to the offsets of a non-positioned element can safely be ignored.
     743           0 :   if (display->mPosition == NS_STYLE_POSITION_STATIC) {
     744           0 :     return true;
     745             :   }
     746             : 
     747             :   // Don't process position changes on frames which have views or the ones which
     748             :   // have a view somewhere in their descendants, because the corresponding view
     749             :   // needs to be repositioned properly as well.
     750           0 :   if (aFrame->HasView() ||
     751           0 :       (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
     752           0 :     StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     753           0 :     return false;
     754             :   }
     755             : 
     756           0 :   aFrame->SchedulePaint();
     757             : 
     758             :   // For relative positioning, we can simply update the frame rect
     759           0 :   if (display->IsRelativelyPositionedStyle()) {
     760             :     // Move the frame
     761           0 :     if (display->mPosition == NS_STYLE_POSITION_STICKY) {
     762           0 :       if (display->IsInnerTableStyle()) {
     763             :         // We don't currently support sticky positioning of inner table
     764             :         // elements (bug 975644). Bail.
     765             :         //
     766             :         // When this is fixed, remove the null-check for the computed
     767             :         // offsets in nsTableRowFrame::ReflowChildren.
     768           0 :         return true;
     769             :       }
     770             : 
     771             :       // Update sticky positioning for an entire element at once, starting with
     772             :       // the first continuation or ib-split sibling.
     773             :       // It's rare that the frame we already have isn't already the first
     774             :       // continuation or ib-split sibling, but it can happen when styles differ
     775             :       // across continuations such as ::first-line or ::first-letter, and in
     776             :       // those cases we will generally (but maybe not always) do the work twice.
     777             :       nsIFrame* firstContinuation =
     778           0 :         nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
     779             : 
     780           0 :       StickyScrollContainer::ComputeStickyOffsets(firstContinuation);
     781             :       StickyScrollContainer* ssc =
     782             :         StickyScrollContainer::GetStickyScrollContainerForFrame(
     783           0 :           firstContinuation);
     784           0 :       if (ssc) {
     785           0 :         ssc->PositionContinuations(firstContinuation);
     786             :       }
     787             :     } else {
     788           0 :       MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition,
     789             :                  "Unexpected type of positioning");
     790           0 :       for (nsIFrame* cont = aFrame; cont;
     791             :            cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
     792           0 :         nsIFrame* cb = cont->GetContainingBlock();
     793           0 :         nsMargin newOffsets;
     794           0 :         WritingMode wm = cb->GetWritingMode();
     795           0 :         const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size());
     796             : 
     797           0 :         ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets);
     798           0 :         NS_ASSERTION(newOffsets.left == -newOffsets.right &&
     799             :                      newOffsets.top == -newOffsets.bottom,
     800             :                      "ComputeRelativeOffsets should return valid results");
     801             : 
     802             :         // ReflowInput::ApplyRelativePositioning would work here, but
     803             :         // since we've already checked mPosition and aren't changing the frame's
     804             :         // normal position, go ahead and add the offsets directly.
     805             :         // First, we need to ensure that the normal position is stored though.
     806             :         bool hasProperty;
     807           0 :         nsPoint normalPosition = cont->GetNormalPosition(&hasProperty);
     808           0 :         if (!hasProperty) {
     809           0 :           cont->AddProperty(nsIFrame::NormalPositionProperty(),
     810           0 :                             new nsPoint(normalPosition));
     811             :         }
     812           0 :         cont->SetPosition(normalPosition +
     813           0 :                           nsPoint(newOffsets.left, newOffsets.top));
     814             :       }
     815             :     }
     816             : 
     817           0 :     return true;
     818             :   }
     819             : 
     820             :   // For the absolute positioning case, set up a fake HTML reflow state for
     821             :   // the frame, and then get the offsets and size from it. If the frame's size
     822             :   // doesn't need to change, we can simply update the frame position. Otherwise
     823             :   // we fall back to a reflow.
     824             :   RefPtr<gfxContext> rc =
     825           0 :     aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext();
     826             : 
     827             :   // Construct a bogus parent reflow state so that there's a usable
     828             :   // containing block reflow state.
     829           0 :   nsIFrame* parentFrame = aFrame->GetParent();
     830           0 :   WritingMode parentWM = parentFrame->GetWritingMode();
     831           0 :   WritingMode frameWM = aFrame->GetWritingMode();
     832           0 :   LogicalSize parentSize = parentFrame->GetLogicalSize();
     833             : 
     834           0 :   nsFrameState savedState = parentFrame->GetStateBits();
     835             :   ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame, rc,
     836           0 :                                 parentSize);
     837           0 :   parentFrame->RemoveStateBits(~nsFrameState(0));
     838           0 :   parentFrame->AddStateBits(savedState);
     839             : 
     840             :   // The bogus parent state here was created with no parent state of its own,
     841             :   // and therefore it won't have an mCBReflowInput set up.
     842             :   // But we may need one (for InitCBReflowInput in a child state), so let's
     843             :   // try to create one here for the cases where it will be needed.
     844           0 :   Maybe<ReflowInput> cbReflowInput;
     845           0 :   nsIFrame* cbFrame = parentFrame->GetContainingBlock();
     846           0 :   if (cbFrame && (aFrame->GetContainingBlock() != parentFrame ||
     847           0 :                   parentFrame->IsTableFrame())) {
     848           0 :     LogicalSize cbSize = cbFrame->GetLogicalSize();
     849           0 :     cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, rc, cbSize);
     850           0 :     cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin();
     851           0 :     cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding();
     852           0 :     cbReflowInput->ComputedPhysicalBorderPadding() =
     853           0 :       cbFrame->GetUsedBorderAndPadding();
     854           0 :     parentReflowInput.mCBReflowInput = cbReflowInput.ptr();
     855             :   }
     856             : 
     857           0 :   NS_WARNING_ASSERTION(parentSize.ISize(parentWM) != NS_INTRINSICSIZE &&
     858             :                        parentSize.BSize(parentWM) != NS_INTRINSICSIZE,
     859             :                        "parentSize should be valid");
     860           0 :   parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0));
     861           0 :   parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0));
     862           0 :   parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
     863             : 
     864           0 :   parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding();
     865           0 :   parentReflowInput.ComputedPhysicalBorderPadding() =
     866           0 :     parentFrame->GetUsedBorderAndPadding();
     867           0 :   LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM);
     868           0 :   availSize.BSize(frameWM) = NS_INTRINSICSIZE;
     869             : 
     870           0 :   ViewportFrame* viewport = do_QueryFrame(parentFrame);
     871             :   nsSize cbSize = viewport ?
     872           0 :     viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size()
     873           0 :     : aFrame->GetContainingBlock()->GetSize();
     874             :   const nsMargin& parentBorder =
     875           0 :     parentReflowInput.mStyleBorder->GetComputedBorder();
     876           0 :   cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
     877           0 :   LogicalSize lcbSize(frameWM, cbSize);
     878             :   ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput, aFrame,
     879           0 :                           availSize, &lcbSize);
     880           0 :   nsSize computedSize(reflowInput.ComputedWidth(),
     881           0 :                       reflowInput.ComputedHeight());
     882           0 :   computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight();
     883           0 :   if (computedSize.height != NS_INTRINSICSIZE) {
     884           0 :     computedSize.height +=
     885           0 :       reflowInput.ComputedPhysicalBorderPadding().TopBottom();
     886             :   }
     887           0 :   nsSize size = aFrame->GetSize();
     888             :   // The RecomputePosition hint is not used if any offset changed between auto
     889             :   // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
     890             :   // element height will be its intrinsic height, and since 'top' and 'bottom''s
     891             :   // auto-ness hasn't changed, the old height must also be its intrinsic
     892             :   // height, which we can assume hasn't changed (or reflow would have
     893             :   // been triggered).
     894           0 :   if (computedSize.width == size.width &&
     895           0 :       (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
     896             :     // If we're solving for 'left' or 'top', then compute it here, in order to
     897             :     // match the reflow code path.
     898           0 :     if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) {
     899           0 :       reflowInput.ComputedPhysicalOffsets().left = cbSize.width -
     900           0 :                                           reflowInput.ComputedPhysicalOffsets().right -
     901           0 :                                           reflowInput.ComputedPhysicalMargin().right -
     902           0 :                                           size.width -
     903           0 :                                           reflowInput.ComputedPhysicalMargin().left;
     904             :     }
     905             : 
     906           0 :     if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) {
     907           0 :       reflowInput.ComputedPhysicalOffsets().top = cbSize.height -
     908           0 :                                          reflowInput.ComputedPhysicalOffsets().bottom -
     909           0 :                                          reflowInput.ComputedPhysicalMargin().bottom -
     910           0 :                                          size.height -
     911           0 :                                          reflowInput.ComputedPhysicalMargin().top;
     912             :     }
     913             : 
     914             :     // Move the frame
     915           0 :     nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left +
     916           0 :                 reflowInput.ComputedPhysicalMargin().left,
     917           0 :                 parentBorder.top + reflowInput.ComputedPhysicalOffsets().top +
     918           0 :                 reflowInput.ComputedPhysicalMargin().top);
     919           0 :     aFrame->SetPosition(pos);
     920             : 
     921           0 :     return true;
     922             :   }
     923             : 
     924             :   // Fall back to a reflow
     925           0 :   StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
     926           0 :   return false;
     927             : }
     928             : 
     929             : static bool
     930           0 : HasBoxAncestor(nsIFrame* aFrame)
     931             : {
     932           0 :   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
     933           0 :     if (f->IsXULBoxFrame()) {
     934           0 :       return true;
     935             :     }
     936             :   }
     937           0 :   return false;
     938             : }
     939             : 
     940             : /**
     941             :  * Return true if aFrame's subtree has placeholders for out-of-flow content
     942             :  * whose 'position' style's bit in aPositionMask is set.
     943             :  */
     944             : static bool
     945           2 : FrameHasPositionedPlaceholderDescendants(nsIFrame* aFrame,
     946             :                                          uint32_t aPositionMask)
     947             : {
     948           2 :   MOZ_ASSERT(aPositionMask & (1 << NS_STYLE_POSITION_FIXED));
     949             : 
     950           4 :   for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
     951           0 :     for (nsIFrame* f : lists.CurrentList()) {
     952           0 :       if (f->IsPlaceholderFrame()) {
     953             :         nsIFrame* outOfFlow =
     954           0 :           nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
     955             :         // If SVG text frames could appear here, they could confuse us since
     956             :         // they ignore their position style ... but they can't.
     957           0 :         NS_ASSERTION(!nsSVGUtils::IsInSVGTextSubtree(outOfFlow),
     958             :                      "SVG text frames can't be out of flow");
     959           0 :         if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
     960           0 :           return true;
     961             :         }
     962             :       }
     963           0 :       uint32_t positionMask = aPositionMask;
     964             :       // NOTE:  It's tempting to check f->IsAbsPosContainingBlock() or
     965             :       // f->IsFixedPosContainingBlock() here.  However, that would only
     966             :       // be testing the *new* style of the frame, which might exclude
     967             :       // descendants that currently have this frame as an abs-pos
     968             :       // containing block.  Taking the codepath where we don't reframe
     969             :       // could lead to an unsafe call to
     970             :       // cont->MarkAsNotAbsoluteContainingBlock() before we've reframed
     971             :       // the descendant and taken it off the absolute list.
     972           0 :       if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
     973           0 :         return true;
     974             :       }
     975             :     }
     976             :   }
     977           2 :   return false;
     978             : }
     979             : 
     980             : static bool
     981           2 : NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame)
     982             : {
     983             :   static_assert(0 <= NS_STYLE_POSITION_ABSOLUTE &&
     984             :                 NS_STYLE_POSITION_ABSOLUTE < 32, "Style constant out of range");
     985             :   static_assert(0 <= NS_STYLE_POSITION_FIXED &&
     986             :                 NS_STYLE_POSITION_FIXED < 32, "Style constant out of range");
     987             : 
     988             :   uint32_t positionMask;
     989             :   // Don't call aFrame->IsPositioned here, since that returns true if
     990             :   // the frame already has a transform, and we want to ignore that here
     991           2 :   if (aFrame->IsAbsolutelyPositioned() || aFrame->IsRelativelyPositioned()) {
     992             :     // This frame is a container for abs-pos descendants whether or not it
     993             :     // has a transform.
     994             :     // So abs-pos descendants are no problem; we only need to reframe if
     995             :     // we have fixed-pos descendants.
     996           0 :     positionMask = 1 << NS_STYLE_POSITION_FIXED;
     997             :   } else {
     998             :     // This frame may not be a container for abs-pos descendants already.
     999             :     // So reframe if we have abs-pos or fixed-pos descendants.
    1000           2 :     positionMask =
    1001             :       (1 << NS_STYLE_POSITION_FIXED) | (1 << NS_STYLE_POSITION_ABSOLUTE);
    1002             :   }
    1003           4 :   for (nsIFrame* f = aFrame; f;
    1004             :        f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
    1005           2 :     if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
    1006           0 :       return true;
    1007             :     }
    1008             :   }
    1009           2 :   return false;
    1010             : }
    1011             : 
    1012             : /* static */ nsIFrame*
    1013           0 : RestyleManager::GetNearestAncestorFrame(nsIContent* aContent)
    1014             : {
    1015           0 :   nsIFrame* ancestorFrame = nullptr;
    1016           0 :   for (nsIContent* ancestor = aContent->GetParent();
    1017           0 :        ancestor && !ancestorFrame;
    1018           0 :        ancestor = ancestor->GetParent()) {
    1019           0 :     ancestorFrame = ancestor->GetPrimaryFrame();
    1020             :   }
    1021           0 :   return ancestorFrame;
    1022             : }
    1023             : 
    1024             : /* static */ nsIFrame*
    1025          61 : RestyleManager::GetNextBlockInInlineSibling(nsIFrame* aFrame)
    1026             : {
    1027          61 :   NS_ASSERTION(!aFrame->GetPrevContinuation(),
    1028             :                "must start with the first continuation");
    1029             :   // Might we have ib-split siblings?
    1030          61 :   if (!(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
    1031             :     // nothing more to do here
    1032          61 :     return nullptr;
    1033             :   }
    1034             : 
    1035           0 :   return aFrame->GetProperty(nsIFrame::IBSplitSibling());
    1036             : }
    1037             : 
    1038             : static void
    1039          60 : DoApplyRenderingChangeToTree(nsIFrame* aFrame,
    1040             :                              nsChangeHint aChange)
    1041             : {
    1042          60 :   NS_PRECONDITION(gInApplyRenderingChangeToTree,
    1043             :                   "should only be called within ApplyRenderingChangeToTree");
    1044             : 
    1045         180 :   for ( ; aFrame; aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) {
    1046             :     // Invalidate and sync views on all descendant frames, following placeholders.
    1047             :     // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because
    1048             :     // there can't be any out-of-flows or popups that need to be transformed;
    1049             :     // all out-of-flow descendants of the transformed element must also be
    1050             :     // descendants of the transformed frame.
    1051          60 :     SyncViewsAndInvalidateDescendants(aFrame,
    1052             :       nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
    1053             :                               nsChangeHint_SyncFrameView |
    1054             :                               nsChangeHint_UpdateOpacityLayer |
    1055          60 :                               nsChangeHint_SchedulePaint)));
    1056             :     // This must be set to true if the rendering change needs to
    1057             :     // invalidate content.  If it's false, a composite-only paint
    1058             :     // (empty transaction) will be scheduled.
    1059          60 :     bool needInvalidatingPaint = false;
    1060             : 
    1061             :     // if frame has view, will already be invalidated
    1062          60 :     if (aChange & nsChangeHint_RepaintFrame) {
    1063             :       // Note that this whole block will be skipped when painting is suppressed
    1064             :       // (due to our caller ApplyRendingChangeToTree() discarding the
    1065             :       // nsChangeHint_RepaintFrame hint).  If you add handling for any other
    1066             :       // hints within this block, be sure that they too should be ignored when
    1067             :       // painting is suppressed.
    1068          27 :       needInvalidatingPaint = true;
    1069          27 :       aFrame->InvalidateFrameSubtree();
    1070          54 :       if ((aChange & nsChangeHint_UpdateEffects) &&
    1071          27 :           aFrame->IsFrameOfType(nsIFrame::eSVG) &&
    1072           0 :           !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
    1073             :         // Need to update our overflow rects:
    1074           0 :         nsSVGUtils::ScheduleReflowSVG(aFrame);
    1075             :       }
    1076             :     }
    1077          60 :     if (aChange & nsChangeHint_UpdateTextPath) {
    1078           0 :       if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
    1079             :         // Invalidate and reflow the entire SVGTextFrame:
    1080           0 :         NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
    1081             :                      "expected frame for a <textPath> element");
    1082             :         nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType(
    1083           0 :           aFrame, LayoutFrameType::SVGText);
    1084           0 :         NS_ASSERTION(text, "expected to find an ancestor SVGTextFrame");
    1085           0 :         static_cast<SVGTextFrame*>(text)->NotifyGlyphMetricsChange();
    1086             :       } else {
    1087           0 :         MOZ_ASSERT(false, "unexpected frame got nsChangeHint_UpdateTextPath");
    1088             :       }
    1089             :     }
    1090          60 :     if (aChange & nsChangeHint_UpdateOpacityLayer) {
    1091             :       // FIXME/bug 796697: we can get away with empty transactions for
    1092             :       // opacity updates in many cases.
    1093          21 :       needInvalidatingPaint = true;
    1094             : 
    1095          21 :       ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity);
    1096          21 :       if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
    1097             :         // SVG effects paints the opacity without using
    1098             :         // nsDisplayOpacity. We need to invalidate manually.
    1099           0 :         aFrame->InvalidateFrameSubtree();
    1100             :       }
    1101             :     }
    1102          60 :     if ((aChange & nsChangeHint_UpdateTransformLayer) &&
    1103           0 :         aFrame->IsTransformed()) {
    1104           0 :       ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform);
    1105             :       // If we're not already going to do an invalidating paint, see
    1106             :       // if we can get away with only updating the transform on a
    1107             :       // layer for this frame, and not scheduling an invalidating
    1108             :       // paint.
    1109           0 :       if (!needInvalidatingPaint) {
    1110             :         Layer* layer;
    1111           0 :         needInvalidatingPaint |= !aFrame->TryUpdateTransformOnly(&layer);
    1112             : 
    1113           0 :         if (!needInvalidatingPaint) {
    1114             :           // Since we're not going to paint, we need to resend animation
    1115             :           // data to the layer.
    1116           0 :           MOZ_ASSERT(layer, "this can't happen if there's no layer");
    1117             :           nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(
    1118           0 :             layer, nullptr, nullptr, aFrame, eCSSProperty_transform);
    1119             :         }
    1120             :       }
    1121             :     }
    1122          60 :     if (aChange & nsChangeHint_ChildrenOnlyTransform) {
    1123           0 :       needInvalidatingPaint = true;
    1124             :       nsIFrame* childFrame =
    1125           0 :         GetFrameForChildrenOnlyTransformHint(aFrame)->PrincipalChildList().FirstChild();
    1126           0 :       for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
    1127           0 :         ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
    1128             :       }
    1129             :     }
    1130          60 :     if (aChange & nsChangeHint_SchedulePaint) {
    1131          30 :       needInvalidatingPaint = true;
    1132             :     }
    1133          60 :     aFrame->SchedulePaint(needInvalidatingPaint
    1134             :                             ? nsIFrame::PAINT_DEFAULT
    1135          60 :                             : nsIFrame::PAINT_COMPOSITE_ONLY);
    1136             :   }
    1137          60 : }
    1138             : 
    1139             : static void
    1140         163 : SyncViewsAndInvalidateDescendants(nsIFrame* aFrame, nsChangeHint aChange)
    1141             : {
    1142         163 :   NS_PRECONDITION(gInApplyRenderingChangeToTree,
    1143             :                   "should only be called within ApplyRenderingChangeToTree");
    1144         163 :   NS_ASSERTION(nsChangeHint_size_t(aChange) ==
    1145             :                           (aChange & (nsChangeHint_RepaintFrame |
    1146             :                                       nsChangeHint_SyncFrameView |
    1147             :                                       nsChangeHint_UpdateOpacityLayer |
    1148             :                                       nsChangeHint_SchedulePaint)),
    1149             :                "Invalid change flag");
    1150             : 
    1151         163 :   if (aChange & nsChangeHint_SyncFrameView) {
    1152         108 :     aFrame->SyncFrameViewProperties();
    1153             :   }
    1154             : 
    1155         326 :   nsIFrame::ChildListIterator lists(aFrame);
    1156         343 :   for (; !lists.IsDone(); lists.Next()) {
    1157         211 :     for (nsIFrame* child : lists.CurrentList()) {
    1158         121 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    1159             :         // only do frames that don't have placeholders
    1160         121 :         if (child->IsPlaceholderFrame()) {
    1161             :           // do the out-of-flow frame and its continuations
    1162             :           nsIFrame* outOfFlowFrame =
    1163           5 :             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
    1164           5 :           DoApplyRenderingChangeToTree(outOfFlowFrame, aChange);
    1165         116 :         } else if (lists.CurrentID() == nsIFrame::kPopupList) {
    1166          13 :           DoApplyRenderingChangeToTree(child, aChange);
    1167             :         } else { // regular frame
    1168         103 :           SyncViewsAndInvalidateDescendants(child, aChange);
    1169             :         }
    1170             :       }
    1171             :     }
    1172             :   }
    1173         163 : }
    1174             : 
    1175             : static void
    1176          51 : ApplyRenderingChangeToTree(nsIPresShell* aPresShell,
    1177             :                            nsIFrame* aFrame,
    1178             :                            nsChangeHint aChange)
    1179             : {
    1180             :   // We check StyleDisplay()->HasTransformStyle() in addition to checking
    1181             :   // IsTransformed() since we can get here for some frames that don't support
    1182             :   // CSS transforms.
    1183          51 :   NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) ||
    1184             :                aFrame->IsTransformed() ||
    1185             :                aFrame->StyleDisplay()->HasTransformStyle(),
    1186             :                "Unexpected UpdateTransformLayer hint");
    1187             : 
    1188          51 :   if (aPresShell->IsPaintingSuppressed()) {
    1189             :     // Don't allow synchronous rendering changes when painting is turned off.
    1190          17 :     aChange &= ~nsChangeHint_RepaintFrame;
    1191          17 :     if (!aChange) {
    1192           9 :       return;
    1193             :     }
    1194             :   }
    1195             : 
    1196             : // Trigger rendering updates by damaging this frame and any
    1197             : // continuations of this frame.
    1198             : #ifdef DEBUG
    1199          42 :   gInApplyRenderingChangeToTree = true;
    1200             : #endif
    1201          42 :   if (aChange & nsChangeHint_RepaintFrame) {
    1202             :     // If the frame's background is propagated to an ancestor, walk up to
    1203             :     // that ancestor and apply the RepaintFrame change hint to it.
    1204             :     nsStyleContext* bgSC;
    1205          16 :     nsIFrame* propagatedFrame = aFrame;
    1206          16 :     while (!nsCSSRendering::FindBackground(propagatedFrame, &bgSC)) {
    1207           0 :       propagatedFrame = propagatedFrame->GetParent();
    1208           0 :       NS_ASSERTION(aFrame, "root frame must paint");
    1209             :     }
    1210             : 
    1211          16 :     if (propagatedFrame != aFrame) {
    1212           0 :       DoApplyRenderingChangeToTree(propagatedFrame, nsChangeHint_RepaintFrame);
    1213           0 :       aChange &= ~nsChangeHint_RepaintFrame;
    1214           0 :       if (!aChange) {
    1215           0 :         return;
    1216             :       }
    1217             :     }
    1218             :   }
    1219          42 :   DoApplyRenderingChangeToTree(aFrame, aChange);
    1220             : #ifdef DEBUG
    1221          42 :   gInApplyRenderingChangeToTree = false;
    1222             : #endif
    1223             : }
    1224             : 
    1225             : static void
    1226           0 : AddSubtreeToOverflowTracker(nsIFrame* aFrame,
    1227             :                             OverflowChangedTracker& aOverflowChangedTracker)
    1228             : {
    1229           0 :   if (aFrame->FrameMaintainsOverflow()) {
    1230             :     aOverflowChangedTracker.AddFrame(aFrame,
    1231           0 :                                      OverflowChangedTracker::CHILDREN_CHANGED);
    1232             :   }
    1233           0 :   nsIFrame::ChildListIterator lists(aFrame);
    1234           0 :   for (; !lists.IsDone(); lists.Next()) {
    1235           0 :     for (nsIFrame* child : lists.CurrentList()) {
    1236           0 :       AddSubtreeToOverflowTracker(child, aOverflowChangedTracker);
    1237             :     }
    1238             :   }
    1239           0 : }
    1240             : 
    1241             : static void
    1242          28 : StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint)
    1243             : {
    1244             :   nsIPresShell::IntrinsicDirty dirtyType;
    1245          28 :   if (aHint & nsChangeHint_ClearDescendantIntrinsics) {
    1246          24 :     NS_ASSERTION(aHint & nsChangeHint_ClearAncestorIntrinsics,
    1247             :                  "Please read the comments in nsChangeHint.h");
    1248          24 :     NS_ASSERTION(aHint & nsChangeHint_NeedDirtyReflow,
    1249             :                  "ClearDescendantIntrinsics requires NeedDirtyReflow");
    1250          24 :     dirtyType = nsIPresShell::eStyleChange;
    1251           4 :   } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
    1252           0 :              aFrame->HasAnyStateBits(
    1253             :                NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
    1254           0 :     dirtyType = nsIPresShell::eStyleChange;
    1255           4 :   } else if (aHint & nsChangeHint_ClearAncestorIntrinsics) {
    1256           2 :     dirtyType = nsIPresShell::eTreeChange;
    1257           2 :   } else if ((aHint & nsChangeHint_UpdateComputedBSize) &&
    1258           0 :              HasBoxAncestor(aFrame)) {
    1259             :     // The frame's computed BSize is changing, and we have a box ancestor
    1260             :     // whose cached intrinsic height may need to be updated.
    1261           0 :     dirtyType = nsIPresShell::eTreeChange;
    1262             :   } else {
    1263           2 :     dirtyType = nsIPresShell::eResize;
    1264             :   }
    1265             : 
    1266             :   nsFrameState dirtyBits;
    1267          28 :   if (aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
    1268           2 :     dirtyBits = nsFrameState(0);
    1269          26 :   } else if ((aHint & nsChangeHint_NeedDirtyReflow) ||
    1270             :              dirtyType == nsIPresShell::eStyleChange) {
    1271          24 :     dirtyBits = NS_FRAME_IS_DIRTY;
    1272             :   } else {
    1273           2 :     dirtyBits = NS_FRAME_HAS_DIRTY_CHILDREN;
    1274             :   }
    1275             : 
    1276             :   // If we're not going to clear any intrinsic sizes on the frames, and
    1277             :   // there are no dirty bits to set, then there's nothing to do.
    1278          28 :   if (dirtyType == nsIPresShell::eResize && !dirtyBits)
    1279           1 :     return;
    1280             : 
    1281             :   nsIPresShell::ReflowRootHandling rootHandling;
    1282          27 :   if (aHint & nsChangeHint_ReflowChangesSizeOrPosition) {
    1283          26 :     rootHandling = nsIPresShell::ePositionOrSizeChange;
    1284             :   } else {
    1285           1 :     rootHandling = nsIPresShell::eNoPositionOrSizeChange;
    1286             :   }
    1287             : 
    1288           0 :   do {
    1289          27 :     aFrame->PresContext()->PresShell()->FrameNeedsReflow(
    1290          27 :       aFrame, dirtyType, dirtyBits, rootHandling);
    1291          27 :     aFrame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame);
    1292          27 :   } while (aFrame);
    1293             : }
    1294             : 
    1295             : /* static */ nsIFrame*
    1296        2550 : RestyleManager::GetNextContinuationWithSameStyle(
    1297             :   nsIFrame* aFrame, nsStyleContext* aOldStyleContext,
    1298             :   bool* aHaveMoreContinuations)
    1299             : {
    1300             :   // See GetPrevContinuationWithSameStyle about {ib} splits.
    1301             : 
    1302        2550 :   nsIFrame* nextContinuation = aFrame->GetNextContinuation();
    1303        5100 :   if (!nextContinuation &&
    1304        2550 :       (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
    1305             :     // We're the last continuation, so we have to hop back to the first
    1306             :     // before getting the frame property
    1307             :     nextContinuation =
    1308           0 :       aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling());
    1309           0 :     if (nextContinuation) {
    1310             :       nextContinuation =
    1311           0 :         nextContinuation->GetProperty(nsIFrame::IBSplitSibling());
    1312             :     }
    1313             :   }
    1314             : 
    1315        2550 :   if (!nextContinuation) {
    1316        2550 :     return nullptr;
    1317             :   }
    1318             : 
    1319           0 :   NS_ASSERTION(nextContinuation->GetContent() == aFrame->GetContent(),
    1320             :                "unexpected content mismatch");
    1321             : 
    1322           0 :   nsStyleContext* nextStyle = nextContinuation->StyleContext();
    1323           0 :   if (nextStyle != aOldStyleContext) {
    1324           0 :     NS_ASSERTION(aOldStyleContext->GetPseudo() != nextStyle->GetPseudo() ||
    1325             :                  aOldStyleContext->GetParentAllowServo() !=
    1326             :                    nextStyle->GetParentAllowServo(),
    1327             :                  "continuations should have the same style context");
    1328           0 :     nextContinuation = nullptr;
    1329           0 :     if (aHaveMoreContinuations) {
    1330           0 :       *aHaveMoreContinuations = true;
    1331             :     }
    1332             :   }
    1333           0 :   return nextContinuation;
    1334             : }
    1335             : 
    1336             : void
    1337          72 : RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
    1338             : {
    1339          72 :   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    1340             :                "Someone forgot a script blocker");
    1341          72 :   MOZ_ASSERT(!mDestroyedFrames);
    1342             : 
    1343          72 :   if (aChangeList.IsEmpty()) {
    1344          19 :     return;
    1345             :   }
    1346             : 
    1347          53 :   mDestroyedFrames = MakeUnique<nsTHashtable<nsPtrHashKey<const nsIFrame>>>();
    1348             : 
    1349         106 :   AUTO_PROFILER_LABEL("RestyleManager::ProcessRestyledFrames", CSS);
    1350             : 
    1351          53 :   nsPresContext* presContext = PresContext();
    1352          53 :   nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor();
    1353             : 
    1354             :   // Handle nsChangeHint_CSSOverflowChange, by either updating the
    1355             :   // scrollbars on the viewport, or upgrading the change hint to frame-reconstruct.
    1356         149 :   for (nsStyleChangeData& data : aChangeList) {
    1357          96 :     if (data.mHint & nsChangeHint_CSSOverflowChange) {
    1358           0 :       data.mHint &= ~nsChangeHint_CSSOverflowChange;
    1359           0 :       bool doReconstruct = true; // assume the worst
    1360             : 
    1361             :       // Only bother with this if we're html/body, since:
    1362             :       //  (a) It'd be *expensive* to reframe these particular nodes.  They're
    1363             :       //      at the root, so reframing would mean rebuilding the world.
    1364             :       //  (b) It's often *unnecessary* to reframe for "overflow" changes on
    1365             :       //      these particular nodes.  In general, the only reason we reframe
    1366             :       //      for "overflow" changes is so we can construct (or destroy) a
    1367             :       //      scrollframe & scrollbars -- and the html/body nodes often don't
    1368             :       //      need their own scrollframe/scrollbars because they coopt the ones
    1369             :       //      on the viewport (which always exist). So depending on whether
    1370             :       //      that's happening, we can skip the reframe for these nodes.
    1371           0 :       if (data.mContent->IsAnyOfHTMLElements(nsGkAtoms::body,
    1372             :                                              nsGkAtoms::html)) {
    1373             :         // If the restyled element provided/provides the scrollbar styles for
    1374             :         // the viewport before and/or after this restyle, AND it's not coopting
    1375             :         // that responsibility from some other element (which would need
    1376             :         // reconstruction to make its own scrollframe now), THEN: we don't need
    1377             :         // to reconstruct - we can just reflow, because no scrollframe is being
    1378             :         // added/removed.
    1379             :         nsIContent* prevOverrideNode =
    1380           0 :           presContext->GetViewportScrollbarStylesOverrideNode();
    1381             :         nsIContent* newOverrideNode =
    1382           0 :           presContext->UpdateViewportScrollbarStylesOverride();
    1383             : 
    1384           0 :         if (data.mContent == prevOverrideNode ||
    1385           0 :             data.mContent == newOverrideNode) {
    1386             :           // If we get here, the restyled element provided the scrollbar styles
    1387             :           // for viewport before this restyle, OR it will provide them after.
    1388           0 :           if (!prevOverrideNode || !newOverrideNode ||
    1389             :               prevOverrideNode == newOverrideNode) {
    1390             :             // If we get here, the restyled element is NOT replacing (or being
    1391             :             // replaced by) some other element as the viewport's
    1392             :             // scrollbar-styles provider. (If it were, we'd potentially need to
    1393             :             // reframe to create a dedicated scrollframe for whichever element
    1394             :             // is being booted from providing viewport scrollbar styles.)
    1395             :             //
    1396             :             // Under these conditions, we're OK to assume that this "overflow"
    1397             :             // change only impacts the root viewport's scrollframe, which
    1398             :             // already exists, so we can simply reflow instead of reframing.
    1399             :             // When requesting this reflow, we send the exact same change hints
    1400             :             // that "width" and "height" would send (since conceptually,
    1401             :             // adding/removing scrollbars is like changing the available
    1402             :             // space).
    1403             :             data.mHint |= (nsChangeHint_ReflowHintsForISizeChange |
    1404           0 :                            nsChangeHint_ReflowHintsForBSizeChange);
    1405           0 :             doReconstruct = false;
    1406             :           }
    1407             :         }
    1408             :       }
    1409           0 :       if (doReconstruct) {
    1410           0 :         data.mHint |= nsChangeHint_ReconstructFrame;
    1411             :       }
    1412             :     }
    1413             :   }
    1414             : 
    1415             :   // Make sure to not rebuild quote or counter lists while we're
    1416             :   // processing restyles
    1417          53 :   frameConstructor->BeginUpdate();
    1418             : 
    1419          53 :   bool didUpdateCursor = false;
    1420             : 
    1421         149 :   for (size_t i = 0; i < aChangeList.Length(); ++i) {
    1422             : 
    1423             :     // Collect and coalesce adjacent siblings for lazy frame construction.
    1424             :     // Eventually it would be even better to make RecreateFramesForContent
    1425             :     // accept a range and coalesce all adjacent reconstructs (bug 1344139).
    1426          96 :     size_t lazyRangeStart = i;
    1427         288 :     while (i < aChangeList.Length() &&
    1428         191 :            aChangeList[i].mContent &&
    1429         191 :            aChangeList[i].mContent->HasFlag(NODE_NEEDS_FRAME) &&
    1430           0 :            (i == lazyRangeStart ||
    1431           0 :             aChangeList[i - 1].mContent->GetNextSibling() == aChangeList[i].mContent))
    1432             :     {
    1433           0 :       MOZ_ASSERT(aChangeList[i].mHint & nsChangeHint_ReconstructFrame);
    1434           0 :       MOZ_ASSERT(!aChangeList[i].mFrame);
    1435           0 :       ++i;
    1436             :     }
    1437          96 :     if (i != lazyRangeStart) {
    1438           0 :       nsIContent* start = aChangeList[lazyRangeStart].mContent;
    1439           0 :       nsIContent* end = aChangeList[i-1].mContent->GetNextSibling();
    1440           0 :       nsIContent* container = start->GetParent();
    1441           0 :       MOZ_ASSERT(container);
    1442           0 :       if (!end) {
    1443           0 :         frameConstructor->ContentAppended(container, start, false);
    1444             :       } else {
    1445           0 :         frameConstructor->ContentRangeInserted(container, start, end, nullptr, false);
    1446             :       }
    1447             :     }
    1448          96 :     for (size_t j = lazyRangeStart; j < i; ++j) {
    1449           0 :       MOZ_ASSERT(!aChangeList[j].mContent->GetPrimaryFrame() ||
    1450             :                  !aChangeList[j].mContent->HasFlag(NODE_NEEDS_FRAME));
    1451             :     }
    1452          96 :     if (i == aChangeList.Length()) {
    1453           0 :       break;
    1454             :     }
    1455             : 
    1456          96 :     nsStyleChangeData& mutable_data = aChangeList[i];
    1457          96 :     const nsStyleChangeData& data = mutable_data;
    1458          96 :     nsIFrame* frame = data.mFrame;
    1459          96 :     nsIContent* content = data.mContent;
    1460          96 :     nsChangeHint hint = data.mHint;
    1461          96 :     bool didReflowThisFrame = false;
    1462             : 
    1463          96 :     NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) ||
    1464             :                  (hint & nsChangeHint_NeedReflow),
    1465             :                  "Reflow hint bits set without actually asking for a reflow");
    1466             : 
    1467             :     // skip any frame that has been destroyed due to a ripple effect
    1468          96 :     if (frame && mDestroyedFrames->Contains(frame)) {
    1469           0 :       continue;
    1470             :     }
    1471             : 
    1472          96 :     if (frame && frame->GetContent() != content) {
    1473             :       // XXXbz this is due to image maps messing with the primary frame of
    1474             :       // <area>s.  See bug 135040.  Remove this block once that's fixed.
    1475           0 :       frame = nullptr;
    1476           0 :       if (!(hint & nsChangeHint_ReconstructFrame)) {
    1477           0 :         continue;
    1478             :       }
    1479             :     }
    1480             : 
    1481          98 :     if ((hint & nsChangeHint_UpdateContainingBlock) && frame &&
    1482           2 :         !(hint & nsChangeHint_ReconstructFrame)) {
    1483           6 :       if (NeedToReframeForAddingOrRemovingTransform(frame) ||
    1484           4 :           frame->IsFieldSetFrame() ||
    1485           2 :           frame->GetContentInsertionFrame() != frame) {
    1486             :         // The frame has positioned children that need to be reparented, or
    1487             :         // it can't easily be converted to/from being an abs-pos container correctly.
    1488           2 :         hint |= nsChangeHint_ReconstructFrame;
    1489             :       } else {
    1490           0 :         for (nsIFrame* cont = frame; cont;
    1491             :              cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1492             :           // Normally frame construction would set state bits as needed,
    1493             :           // but we're not going to reconstruct the frame so we need to set them.
    1494             :           // It's because we need to set this state on each affected frame
    1495             :           // that we can't coalesce nsChangeHint_UpdateContainingBlock hints up
    1496             :           // to ancestors (i.e. it can't be an change hint that is handled for
    1497             :           // descendants).
    1498           0 :           if (cont->IsAbsPosContainingBlock()) {
    1499           0 :             if (!cont->IsAbsoluteContainer() &&
    1500           0 :                 (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
    1501           0 :               cont->MarkAsAbsoluteContainingBlock();
    1502             :             }
    1503             :           } else {
    1504           0 :             if (cont->IsAbsoluteContainer()) {
    1505           0 :               if (cont->HasAbsolutelyPositionedChildren()) {
    1506             :                 // If |cont| still has absolutely positioned children,
    1507             :                 // we can't call MarkAsNotAbsoluteContainingBlock.  This
    1508             :                 // will remove a frame list that still has children in
    1509             :                 // it that we need to keep track of.
    1510             :                 // The optimization of removing it isn't particularly
    1511             :                 // important, although it does mean we skip some tests.
    1512           0 :                 NS_WARNING("skipping removal of absolute containing block");
    1513             :               } else {
    1514           0 :                 cont->MarkAsNotAbsoluteContainingBlock();
    1515             :               }
    1516             :             }
    1517             :           }
    1518             :         }
    1519             :       }
    1520             :     }
    1521             : 
    1522          98 :     if ((hint & nsChangeHint_AddOrRemoveTransform) && frame &&
    1523           2 :         !(hint & nsChangeHint_ReconstructFrame)) {
    1524           0 :       for (nsIFrame* cont = frame; cont;
    1525             :            cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1526           0 :         if (cont->StyleDisplay()->HasTransform(cont)) {
    1527           0 :           cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
    1528             :         }
    1529             :         // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still be
    1530             :         // transformed by other means. It's OK to have the bit even if it's
    1531             :         // not needed.
    1532             :       }
    1533             :     }
    1534             : 
    1535          96 :     if (hint & nsChangeHint_ReconstructFrame) {
    1536             :       // If we ever start passing true here, be careful of restyles
    1537             :       // that involve a reframe and animations.  In particular, if the
    1538             :       // restyle we're processing here is an animation restyle, but
    1539             :       // the style resolution we will do for the frame construction
    1540             :       // happens async when we're not in an animation restyle already,
    1541             :       // problems could arise.
    1542             :       // We could also have problems with triggering of CSS transitions
    1543             :       // on elements whose frames are reconstructed, since we depend on
    1544             :       // the reconstruction happening synchronously.
    1545             :       frameConstructor->RecreateFramesForContent(content, false,
    1546          15 :         nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
    1547             :     } else {
    1548          81 :       NS_ASSERTION(frame, "This shouldn't happen");
    1549             : 
    1550          81 :       if (!frame->FrameMaintainsOverflow()) {
    1551             :         // frame does not maintain overflow rects, so avoid calling
    1552             :         // FinishAndStoreOverflow on it:
    1553             :         hint &= ~(nsChangeHint_UpdateOverflow |
    1554             :                   nsChangeHint_ChildrenOnlyTransform |
    1555             :                   nsChangeHint_UpdatePostTransformOverflow |
    1556           6 :                   nsChangeHint_UpdateParentOverflow);
    1557             :       }
    1558             : 
    1559          81 :       if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) {
    1560             :         // Frame can not be transformed, and thus a change in transform will
    1561             :         // have no effect and we should not use the
    1562             :         // nsChangeHint_UpdatePostTransformOverflow hint.
    1563          50 :         hint &= ~nsChangeHint_UpdatePostTransformOverflow;
    1564             :       }
    1565             : 
    1566          81 :       if (hint & nsChangeHint_UpdateEffects) {
    1567           0 :         for (nsIFrame* cont = frame; cont;
    1568             :              cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1569           0 :           nsSVGEffects::UpdateEffects(cont);
    1570             :         }
    1571             :       }
    1572         162 :       if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
    1573          79 :           ((hint & nsChangeHint_UpdateOpacityLayer) &&
    1574          21 :            frame->IsFrameOfType(nsIFrame::eSVG) &&
    1575           0 :            !(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))) {
    1576          23 :         nsSVGEffects::InvalidateRenderingObservers(frame);
    1577             :       }
    1578          81 :       if (hint & nsChangeHint_NeedReflow) {
    1579          28 :         StyleChangeReflow(frame, hint);
    1580          28 :         didReflowThisFrame = true;
    1581             :       }
    1582             : 
    1583          98 :       if ((hint & nsChangeHint_UpdateUsesOpacity) &&
    1584          17 :           frame->IsFrameOfType(nsIFrame::eTablePart)) {
    1585           0 :         NS_ASSERTION(hint & nsChangeHint_UpdateOpacityLayer,
    1586             :                      "should only return UpdateUsesOpacity hint "
    1587             :                      "when also returning UpdateOpacityLayer hint");
    1588             :         // When an internal table part (including cells) changes between
    1589             :         // having opacity 1 and non-1, it changes whether its
    1590             :         // backgrounds (and those of table parts inside of it) are
    1591             :         // painted as part of the table's nsDisplayTableBorderBackground
    1592             :         // display item, or part of its own display item.  That requires
    1593             :         // invalidation, so change UpdateOpacityLayer to RepaintFrame.
    1594           0 :         hint &= ~nsChangeHint_UpdateOpacityLayer;
    1595           0 :         hint |= nsChangeHint_RepaintFrame;
    1596             :       }
    1597             : 
    1598             :       // Opacity disables preserve-3d, so if we toggle it, then we also need
    1599             :       // to update the overflow areas of all potentially affected frames.
    1600          98 :       if ((hint & nsChangeHint_UpdateUsesOpacity) &&
    1601          17 :           frame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
    1602           0 :         hint |= nsChangeHint_UpdateSubtreeOverflow;
    1603             :       }
    1604             : 
    1605          81 :       if (hint & nsChangeHint_UpdateBackgroundPosition) {
    1606             :         // For most frame types, DLBI can detect background position changes,
    1607             :         // so we only need to schedule a paint.
    1608           0 :         hint |= nsChangeHint_SchedulePaint;
    1609           0 :         if (frame->IsFrameOfType(nsIFrame::eTablePart) ||
    1610           0 :             frame->IsFrameOfType(nsIFrame::eMathML)) {
    1611             :           // Table parts and MathML frames don't build display items for their
    1612             :           // backgrounds, so DLBI can't detect background-position changes for
    1613             :           // these frames. Repaint the whole frame.
    1614           0 :           hint |= nsChangeHint_RepaintFrame;
    1615             :         }
    1616             :       }
    1617             : 
    1618          81 :       if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
    1619             :                   nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
    1620             :                   nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
    1621          51 :         ApplyRenderingChangeToTree(presContext->PresShell(), frame, hint);
    1622             :       }
    1623          81 :       if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
    1624           0 :         ActiveLayerTracker::NotifyOffsetRestyle(frame);
    1625             :         // It is possible for this to fall back to a reflow
    1626           0 :         if (!RecomputePosition(frame)) {
    1627           0 :           didReflowThisFrame = true;
    1628             :         }
    1629             :       }
    1630          81 :       NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
    1631             :                    (hint & nsChangeHint_UpdateOverflow),
    1632             :                    "nsChangeHint_UpdateOverflow should be passed too");
    1633         134 :       if (!didReflowThisFrame &&
    1634          53 :           (hint & (nsChangeHint_UpdateOverflow |
    1635             :                    nsChangeHint_UpdatePostTransformOverflow |
    1636             :                    nsChangeHint_UpdateParentOverflow |
    1637             :                    nsChangeHint_UpdateSubtreeOverflow))) {
    1638           0 :         if (hint & nsChangeHint_UpdateSubtreeOverflow) {
    1639           0 :           for (nsIFrame* cont = frame; cont; cont =
    1640             :                  nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1641           0 :             AddSubtreeToOverflowTracker(cont, mOverflowChangedTracker);
    1642             :           }
    1643             :           // The work we just did in AddSubtreeToOverflowTracker
    1644             :           // subsumes some of the other hints:
    1645             :           hint &= ~(nsChangeHint_UpdateOverflow |
    1646           0 :                     nsChangeHint_UpdatePostTransformOverflow);
    1647             :         }
    1648           0 :         if (hint & nsChangeHint_ChildrenOnlyTransform) {
    1649             :           // The overflow areas of the child frames need to be updated:
    1650           0 :           nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame);
    1651           0 :           nsIFrame* childFrame = hintFrame->PrincipalChildList().FirstChild();
    1652           0 :           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame),
    1653             :                        "SVG frames should not have continuations "
    1654             :                        "or ib-split siblings");
    1655           0 :           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame),
    1656             :                        "SVG frames should not have continuations "
    1657             :                        "or ib-split siblings");
    1658           0 :           for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
    1659           0 :             MOZ_ASSERT(childFrame->IsFrameOfType(nsIFrame::eSVG),
    1660             :                        "Not expecting non-SVG children");
    1661             :             // If |childFrame| is dirty or has dirty children, we don't bother
    1662             :             // updating overflows since that will happen when it's reflowed.
    1663           0 :             if (!(childFrame->GetStateBits() &
    1664             :                   (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
    1665           0 :               mOverflowChangedTracker.AddFrame(childFrame,
    1666           0 :                                         OverflowChangedTracker::CHILDREN_CHANGED);
    1667             :             }
    1668           0 :             NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame),
    1669             :                          "SVG frames should not have continuations "
    1670             :                          "or ib-split siblings");
    1671           0 :             NS_ASSERTION(childFrame->GetParent() == hintFrame,
    1672             :                          "SVG child frame not expected to have different parent");
    1673             :           }
    1674             :         }
    1675             :         // If |frame| is dirty or has dirty children, we don't bother updating
    1676             :         // overflows since that will happen when it's reflowed.
    1677           0 :         if (!(frame->GetStateBits() &
    1678             :               (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
    1679           0 :           if (hint & (nsChangeHint_UpdateOverflow |
    1680             :                       nsChangeHint_UpdatePostTransformOverflow)) {
    1681             :             OverflowChangedTracker::ChangeKind changeKind;
    1682             :             // If we have both nsChangeHint_UpdateOverflow and
    1683             :             // nsChangeHint_UpdatePostTransformOverflow,
    1684             :             // CHILDREN_CHANGED is selected as it is
    1685             :             // strictly stronger.
    1686           0 :             if (hint & nsChangeHint_UpdateOverflow) {
    1687           0 :               changeKind = OverflowChangedTracker::CHILDREN_CHANGED;
    1688             :             } else {
    1689           0 :               changeKind = OverflowChangedTracker::TRANSFORM_CHANGED;
    1690             :             }
    1691           0 :             for (nsIFrame* cont = frame; cont; cont =
    1692             :                    nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1693           0 :               mOverflowChangedTracker.AddFrame(cont, changeKind);
    1694             :             }
    1695             :           }
    1696             :           // UpdateParentOverflow hints need to be processed in addition
    1697             :           // to the above, since if the processing of the above hints
    1698             :           // yields no change, the update will not propagate to the
    1699             :           // parent.
    1700           0 :           if (hint & nsChangeHint_UpdateParentOverflow) {
    1701           0 :             MOZ_ASSERT(frame->GetParent(),
    1702             :                        "shouldn't get style hints for the root frame");
    1703           0 :             for (nsIFrame* cont = frame; cont; cont =
    1704             :                    nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
    1705           0 :               mOverflowChangedTracker.AddFrame(cont->GetParent(),
    1706           0 :                                    OverflowChangedTracker::CHILDREN_CHANGED);
    1707             :             }
    1708             :           }
    1709             :         }
    1710             :       }
    1711          81 :       if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
    1712           0 :         presContext->PresShell()->SynthesizeMouseMove(false);
    1713           0 :         didUpdateCursor = true;
    1714             :       }
    1715          81 :       if (hint & nsChangeHint_UpdateWidgetProperties) {
    1716           0 :         frame->UpdateWidgetProperties();
    1717             :       }
    1718             :     }
    1719             :   }
    1720             : 
    1721          53 :   frameConstructor->EndUpdate();
    1722          53 :   mDestroyedFrames.reset(nullptr);
    1723             : 
    1724             : #ifdef DEBUG
    1725             :   // Verify the style tree.  Note that this needs to happen once we've
    1726             :   // processed the whole list, since until then the tree is not in fact in a
    1727             :   // consistent state.
    1728         149 :   for (const nsStyleChangeData& data : aChangeList) {
    1729             :     // reget frame from content since it may have been regenerated...
    1730          96 :     if (data.mContent) {
    1731          95 :       nsIFrame* frame = data.mContent->GetPrimaryFrame();
    1732          95 :       if (frame) {
    1733          92 :         DebugVerifyStyleTree(frame);
    1734             :       }
    1735           1 :     } else if (!data.mFrame || !data.mFrame->IsViewportFrame()) {
    1736             :       NS_WARNING("Unable to test style tree integrity -- no content node "
    1737           0 :                  "(and not a viewport frame)");
    1738             :     }
    1739             :   }
    1740             : #endif
    1741             : 
    1742          53 :   aChangeList.Clear();
    1743             : }
    1744             : 
    1745             : /* static */ uint64_t
    1746        1200 : RestyleManager::GetAnimationGenerationForFrame(nsIFrame* aFrame)
    1747             : {
    1748        1200 :   EffectSet* effectSet = EffectSet::GetEffectSet(aFrame);
    1749        1200 :   return effectSet ? effectSet->GetAnimationGeneration() : 0;
    1750             : }
    1751             : 
    1752             : void
    1753           2 : RestyleManager::IncrementAnimationGeneration()
    1754             : {
    1755             :   // We update the animation generation at start of each call to
    1756             :   // ProcessPendingRestyles so we should ignore any subsequent (redundant)
    1757             :   // calls that occur while we are still processing restyles.
    1758           4 :   if ((IsGecko() && !AsGecko()->IsProcessingRestyles()) ||
    1759           0 :       (IsServo() && !mInStyleRefresh)) {
    1760           2 :     ++mAnimationGeneration;
    1761             :   }
    1762           2 : }
    1763             : 
    1764             : /* static */ void
    1765        1202 : RestyleManager::AddLayerChangesForAnimation(nsIFrame* aFrame,
    1766             :                                             nsIContent* aContent,
    1767             :                                             nsStyleChangeList&
    1768             :                                               aChangeListToProcess)
    1769             : {
    1770        1202 :   if (!aFrame || !aContent) {
    1771           2 :     return;
    1772             :   }
    1773             : 
    1774             :   uint64_t frameGeneration =
    1775        1200 :     RestyleManager::GetAnimationGenerationForFrame(aFrame);
    1776             : 
    1777        1200 :   nsChangeHint hint = nsChangeHint(0);
    1778        2400 :   for (const LayerAnimationInfo::Record& layerInfo :
    1779        1200 :          LayerAnimationInfo::sRecords) {
    1780             :     layers::Layer* layer =
    1781        2400 :       FrameLayerBuilder::GetDedicatedLayer(aFrame, layerInfo.mLayerType);
    1782        2400 :     if (layer && frameGeneration != layer->GetAnimationGeneration()) {
    1783             :       // If we have a transform layer but don't have any transform style, we
    1784             :       // probably just removed the transform but haven't destroyed the layer
    1785             :       // yet. In this case we will add the appropriate change hint
    1786             :       // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
    1787             :       // so we can skip adding any change hint here. (If we *were* to add
    1788             :       // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
    1789             :       // complain that we're updating a transform layer without a transform).
    1790           0 :       if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
    1791           0 :           !aFrame->StyleDisplay()->HasTransformStyle()) {
    1792           0 :         continue;
    1793             :       }
    1794           0 :       hint |= layerInfo.mChangeHint;
    1795             :     }
    1796             : 
    1797             :     // We consider it's the first paint for the frame if we have an animation
    1798             :     // for the property but have no layer.
    1799             :     // Note that in case of animations which has properties preventing running
    1800             :     // on the compositor, e.g., width or height, corresponding layer is not
    1801             :     // created at all, but even in such cases, we normally set valid change
    1802             :     // hint for such animations in each tick, i.e. restyles in each tick. As
    1803             :     // a result, we usually do restyles for such animations in every tick on
    1804             :     // the main-thread.  The only animations which will be affected by this
    1805             :     // explicit change hint are animations that have opacity/transform but did
    1806             :     // not have those properies just before. e.g, setting transform by
    1807             :     // setKeyframes or changing target element from other target which prevents
    1808             :     // running on the compositor, etc.
    1809        4800 :     if (!layer &&
    1810        2400 :         nsLayoutUtils::HasEffectiveAnimation(aFrame, layerInfo.mProperty)) {
    1811          14 :       hint |= layerInfo.mChangeHint;
    1812             :     }
    1813             :   }
    1814             : 
    1815        1200 :   if (hint) {
    1816          14 :     aChangeListToProcess.AppendChange(aFrame, aContent, hint);
    1817             :   }
    1818             : }
    1819             : 
    1820          25 : RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
    1821          25 :                                                 RestyleManager* aRestyleManager)
    1822             :   : mRestyleManager(aRestyleManager)
    1823          25 :   , mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
    1824             : {
    1825          25 :   MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
    1826             :              "shouldn't construct recursively");
    1827          25 :   mRestyleManager->mAnimationsWithDestroyedFrame = this;
    1828          25 : }
    1829             : 
    1830             : void
    1831          25 : RestyleManager::AnimationsWithDestroyedFrame
    1832             :               ::StopAnimationsForElementsWithoutFrames()
    1833             : {
    1834          25 :   StopAnimationsWithoutFrame(mContents, CSSPseudoElementType::NotPseudo);
    1835          25 :   StopAnimationsWithoutFrame(mBeforeContents, CSSPseudoElementType::before);
    1836          25 :   StopAnimationsWithoutFrame(mAfterContents, CSSPseudoElementType::after);
    1837          25 : }
    1838             : 
    1839             : void
    1840          75 : RestyleManager::AnimationsWithDestroyedFrame
    1841             :               ::StopAnimationsWithoutFrame(
    1842             :                   nsTArray<RefPtr<nsIContent>>& aArray,
    1843             :                   CSSPseudoElementType aPseudoType)
    1844             : {
    1845             :   nsAnimationManager* animationManager =
    1846          75 :     mRestyleManager->PresContext()->AnimationManager();
    1847             :   nsTransitionManager* transitionManager =
    1848          75 :     mRestyleManager->PresContext()->TransitionManager();
    1849          77 :   for (nsIContent* content : aArray) {
    1850           2 :     if (content->GetPrimaryFrame()) {
    1851           2 :       continue;
    1852             :     }
    1853           0 :     dom::Element* element = content->AsElement();
    1854             : 
    1855           0 :     animationManager->StopAnimationsForElement(element, aPseudoType);
    1856           0 :     transitionManager->StopAnimationsForElement(element, aPseudoType);
    1857             : 
    1858             :     // All other animations should keep running but not running on the
    1859             :     // *compositor* at this point.
    1860           0 :     EffectSet* effectSet = EffectSet::GetEffectSet(element, aPseudoType);
    1861           0 :     if (effectSet) {
    1862           0 :       for (KeyframeEffectReadOnly* effect : *effectSet) {
    1863           0 :         effect->ResetIsRunningOnCompositor();
    1864             :       }
    1865             :     }
    1866             :   }
    1867          75 : }
    1868             : 
    1869             : } // namespace mozilla

Generated by: LCOV version 1.13