LCOV - code coverage report
Current view: top level - layout/base - GeckoRestyleManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 923 1409 65.5 %
Date: 2017-07-14 16:53:18 Functions: 63 76 82.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /**
       7             :  * Code responsible for managing style changes: tracking what style
       8             :  * changes need to happen, scheduling them, and doing them.
       9             :  */
      10             : 
      11             : #include "mozilla/GeckoRestyleManager.h"
      12             : 
      13             : #include <algorithm> // For std::max
      14             : #include "gfxContext.h"
      15             : #include "mozilla/EffectSet.h"
      16             : #include "mozilla/GeckoStyleContext.h"
      17             : #include "mozilla/EventStates.h"
      18             : #include "mozilla/ViewportFrame.h"
      19             : #include "mozilla/css/StyleRule.h" // For nsCSSSelector
      20             : #include "nsLayoutUtils.h"
      21             : #include "AnimationCommon.h" // For GetLayerAnimationInfo
      22             : #include "FrameLayerBuilder.h"
      23             : #include "GeckoProfiler.h"
      24             : #include "nsAutoPtr.h"
      25             : #include "nsStyleChangeList.h"
      26             : #include "nsRuleProcessorData.h"
      27             : #include "nsStyleContextInlines.h"
      28             : #include "nsStyleSet.h"
      29             : #include "nsStyleUtil.h"
      30             : #include "nsCSSFrameConstructor.h"
      31             : #include "nsSVGEffects.h"
      32             : #include "nsCSSPseudoElements.h"
      33             : #include "nsCSSRendering.h"
      34             : #include "nsAnimationManager.h"
      35             : #include "nsTransitionManager.h"
      36             : #include "nsViewManager.h"
      37             : #include "nsSVGIntegrationUtils.h"
      38             : #include "nsCSSAnonBoxes.h"
      39             : #include "nsContainerFrame.h"
      40             : #include "nsPlaceholderFrame.h"
      41             : #include "nsBlockFrame.h"
      42             : #include "SVGTextFrame.h"
      43             : #include "StickyScrollContainer.h"
      44             : #include "nsIRootBox.h"
      45             : #include "nsIDOMMutationEvent.h"
      46             : #include "nsContentUtils.h"
      47             : #include "nsIFrameInlines.h"
      48             : #include "ActiveLayerTracker.h"
      49             : #include "nsDisplayList.h"
      50             : #include "RestyleTrackerInlines.h"
      51             : #include "nsSMILAnimationController.h"
      52             : #include "nsCSSRuleProcessor.h"
      53             : #include "ChildIterator.h"
      54             : 
      55             : #ifdef ACCESSIBILITY
      56             : #include "nsAccessibilityService.h"
      57             : #endif
      58             : 
      59             : namespace mozilla {
      60             : 
      61             : using namespace layers;
      62             : using namespace dom;
      63             : 
      64             : #define LOG_RESTYLE_CONTINUE(reason_, ...) \
      65             :   LOG_RESTYLE("continuing restyle since " reason_, ##__VA_ARGS__)
      66             : 
      67             : #ifdef RESTYLE_LOGGING
      68             : static nsCString
      69           0 : FrameTagToString(const nsIFrame* aFrame)
      70             : {
      71           0 :   nsCString result;
      72           0 :   aFrame->ListTag(result);
      73           0 :   return result;
      74             : }
      75             : 
      76             : static nsCString
      77           0 : ElementTagToString(dom::Element* aElement)
      78             : {
      79           0 :   nsCString result;
      80           0 :   nsDependentAtomString buf(aElement->NodeInfo()->NameAtom());
      81           0 :   result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
      82           0 :   return result;
      83             : }
      84             : #endif
      85             : 
      86          28 : GeckoRestyleManager::GeckoRestyleManager(nsPresContext* aPresContext)
      87             :   : RestyleManager(StyleBackendType::Gecko, aPresContext)
      88             :   , mDoRebuildAllStyleData(false)
      89             :   , mInRebuildAllStyleData(false)
      90             :   , mSkipAnimationRules(false)
      91             :   , mHavePendingNonAnimationRestyles(false)
      92             :   , mRebuildAllExtraHint(nsChangeHint(0))
      93             :   , mRebuildAllRestyleHint(nsRestyleHint(0))
      94             :   , mReframingStyleContexts(nullptr)
      95             :   , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
      96             :                      ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
      97             :                      ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
      98             :   , mIsProcessingRestyles(false)
      99             : #ifdef RESTYLE_LOGGING
     100          28 :   , mLoggingDepth(0)
     101             : #endif
     102             : {
     103          28 :   mPendingRestyles.Init(this);
     104          28 : }
     105             : 
     106             : void
     107         109 : GeckoRestyleManager::RestyleElement(Element*               aElement,
     108             :                                     nsIFrame*              aPrimaryFrame,
     109             :                                     nsChangeHint           aMinHint,
     110             :                                     RestyleTracker&        aRestyleTracker,
     111             :                                     nsRestyleHint          aRestyleHint,
     112             :                                     const RestyleHintData& aRestyleHintData)
     113             : {
     114         109 :   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
     115         109 :   NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
     116             :                "frame/content mismatch");
     117         109 :   if (aPrimaryFrame && aPrimaryFrame->GetContent() != aElement) {
     118             :     // XXXbz this is due to image maps messing with the primary frame pointer
     119             :     // of <area>s.  See bug 135040.  We can remove this block once that's fixed.
     120           0 :     aPrimaryFrame = nullptr;
     121             :   }
     122         109 :   NS_ASSERTION(!aPrimaryFrame || aPrimaryFrame->GetContent() == aElement,
     123             :                "frame/content mismatch");
     124             : 
     125             :   // If we're restyling the root element and there are 'rem' units in
     126             :   // use, handle dynamic changes to the definition of a 'rem' here.
     127         109 :   if (PresContext()->UsesRootEMUnits() && aPrimaryFrame &&
     128           0 :       !mInRebuildAllStyleData) {
     129           0 :     nsStyleContext* oldContext = aPrimaryFrame->StyleContext();
     130           0 :     if (!oldContext->GetParent()) { // check that we're the root element
     131             :       RefPtr<nsStyleContext> newContext = StyleSet()->
     132           0 :         ResolveStyleFor(aElement, nullptr /* == oldContext->GetParent() */);
     133           0 :       if (oldContext->StyleFont()->mFont.size !=
     134           0 :           newContext->StyleFont()->mFont.size) {
     135             :         // The basis for 'rem' units has changed.
     136           0 :         mRebuildAllRestyleHint |= aRestyleHint;
     137           0 :         if (aRestyleHint & eRestyle_SomeDescendants) {
     138           0 :           mRebuildAllRestyleHint |= eRestyle_Subtree;
     139             :         }
     140           0 :         mRebuildAllExtraHint |= aMinHint;
     141           0 :         StartRebuildAllStyleData(aRestyleTracker);
     142           0 :         return;
     143             :       }
     144             :     }
     145             :   }
     146             : 
     147         109 :   if (aMinHint & nsChangeHint_ReconstructFrame) {
     148           0 :     FrameConstructor()->RecreateFramesForContent(aElement, false,
     149           0 :       nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
     150         109 :   } else if (aPrimaryFrame) {
     151             :     ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
     152          59 :                                  aRestyleHint, aRestyleHintData);
     153          50 :   } else if (aRestyleHint & ~eRestyle_LaterSiblings) {
     154             :     // We're restyling an element with no frame, so we should try to
     155             :     // make one if its new style says it should have one.  But in order
     156             :     // to try to honor the restyle hint (which we'd like to do so that,
     157             :     // for example, an animation-only style flush doesn't flush other
     158             :     // buffered style changes), we only do this if the restyle hint says
     159             :     // we have *some* restyling for this frame.  This means we'll
     160             :     // potentially get ahead of ourselves in that case, but not as much
     161             :     // as we would if we didn't check the restyle hint.
     162             :     nsStyleContext* newContext =
     163          50 :       FrameConstructor()->MaybeRecreateFramesForElement(aElement);
     164          56 :     if (newContext &&
     165           6 :         newContext->StyleDisplay()->mDisplay == StyleDisplay::Contents) {
     166             :       // Style change for a display:contents node that did not recreate frames.
     167             :       ComputeAndProcessStyleChange(newContext, aElement, aMinHint,
     168             :                                    aRestyleTracker, aRestyleHint,
     169           0 :                                    aRestyleHintData);
     170             :     }
     171             :   }
     172             : }
     173             : 
     174          25 : GeckoRestyleManager::ReframingStyleContexts
     175             :                    ::ReframingStyleContexts(
     176          25 :                        GeckoRestyleManager* aRestyleManager)
     177             :   : mRestyleManager(aRestyleManager)
     178          25 :   , mRestorePointer(mRestyleManager->mReframingStyleContexts)
     179             : {
     180          25 :   MOZ_ASSERT(!mRestyleManager->mReframingStyleContexts,
     181             :              "shouldn't construct recursively");
     182          25 :   mRestyleManager->mReframingStyleContexts = this;
     183          25 : }
     184             : 
     185          50 : GeckoRestyleManager::ReframingStyleContexts::~ReframingStyleContexts()
     186             : {
     187             :   // Before we go away, we need to flush out any frame construction that
     188             :   // was enqueued, so that we initiate transitions.
     189             :   // Note that this is a little bit evil in that we're calling into code
     190             :   // that calls our member functions from our destructor, but it's at
     191             :   // the beginning of our destructor, so it shouldn't be too bad.
     192          25 :   mRestyleManager->PresContext()->FrameConstructor()->CreateNeededFrames();
     193          25 : }
     194             : 
     195             : static inline dom::Element*
     196             : ElementForStyleContext(nsIContent* aParentContent,
     197             :                        nsIFrame* aFrame,
     198             :                        CSSPseudoElementType aPseudoType);
     199             : 
     200             : // Forwarded nsIDocumentObserver method, to handle restyling (and
     201             : // passing the notification to the frame).
     202             : void
     203          51 : GeckoRestyleManager::ContentStateChanged(nsIContent* aContent,
     204             :                                          EventStates aStateMask)
     205             : {
     206          51 :   MOZ_ASSERT(!mInStyleRefresh);
     207             : 
     208             :   // XXXbz it would be good if this function only took Elements, but
     209             :   // we'd have to make ESM guarantee that usefully.
     210          51 :   if (!aContent->IsElement()) {
     211           0 :     return;
     212             :   }
     213             : 
     214          51 :   Element* aElement = aContent->AsElement();
     215             : 
     216             :   nsChangeHint changeHint;
     217             :   nsRestyleHint restyleHint;
     218          51 :   ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
     219             : 
     220          51 :   PostRestyleEvent(aElement, restyleHint, changeHint);
     221             : }
     222             : 
     223             : // Forwarded nsIMutationObserver method, to handle restyling.
     224             : void
     225         326 : GeckoRestyleManager::AttributeWillChange(Element* aElement,
     226             :                                          int32_t aNameSpaceID,
     227             :                                          nsIAtom* aAttribute,
     228             :                                          int32_t aModType,
     229             :                                          const nsAttrValue* aNewValue)
     230             : {
     231         326 :   MOZ_ASSERT(!mInStyleRefresh);
     232             : 
     233         652 :   RestyleHintData rsdata;
     234             :   nsRestyleHint rshint =
     235         326 :     StyleSet()->HasAttributeDependentStyle(aElement,
     236             :                                            aNameSpaceID,
     237             :                                            aAttribute,
     238             :                                            aModType,
     239             :                                            false,
     240             :                                            aNewValue,
     241         326 :                                            rsdata);
     242         326 :   PostRestyleEvent(aElement, rshint, nsChangeHint(0), &rsdata);
     243         326 : }
     244             : 
     245             : // Forwarded nsIMutationObserver method, to handle restyling (and
     246             : // passing the notification to the frame).
     247             : void
     248         322 : GeckoRestyleManager::AttributeChanged(Element* aElement,
     249             :                                       int32_t aNameSpaceID,
     250             :                                       nsIAtom* aAttribute,
     251             :                                       int32_t aModType,
     252             :                                       const nsAttrValue* aOldValue)
     253             : {
     254         322 :   MOZ_ASSERT(!mInStyleRefresh);
     255             : 
     256             :   // Hold onto the PresShell to prevent ourselves from being destroyed.
     257             :   // XXXbz how, exactly, would this attribute change cause us to be
     258             :   // destroyed from inside this function?
     259         644 :   nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
     260             :   mozilla::Unused << shell; // Unused within this function
     261             : 
     262             :   // Get the frame associated with the content which is the highest in the frame tree
     263         322 :   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
     264             : 
     265             : #if 0
     266             :   NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
     267             :      ("RestyleManager::AttributeChanged: content=%p[%s] frame=%p",
     268             :       aContent, ContentTag(aElement, 0), frame));
     269             : #endif
     270             : 
     271             :   // the style tag has its own interpretation based on aHint
     272         322 :   nsChangeHint hint = aElement->GetAttributeChangeHint(aAttribute, aModType);
     273             : 
     274         322 :   bool reframe = (hint & nsChangeHint_ReconstructFrame) != 0;
     275             : 
     276             : #ifdef MOZ_XUL
     277             :   // The following listbox widget trap prevents offscreen listbox widget
     278             :   // content from being removed and re-inserted (which is what would
     279             :   // happen otherwise).
     280         322 :   if (!primaryFrame && !reframe) {
     281             :     int32_t namespaceID;
     282             :     nsIAtom* tag = PresContext()->Document()->BindingManager()->
     283         173 :                      ResolveTag(aElement, &namespaceID);
     284             : 
     285         346 :     if (namespaceID == kNameSpaceID_XUL &&
     286         346 :         (tag == nsGkAtoms::listitem ||
     287         173 :          tag == nsGkAtoms::listcell))
     288           0 :       return;
     289             :   }
     290             : 
     291         633 :   if (aAttribute == nsGkAtoms::tooltiptext ||
     292         311 :       aAttribute == nsGkAtoms::tooltip)
     293             :   {
     294          11 :     nsIRootBox* rootBox = nsIRootBox::GetRootBox(PresContext()->GetPresShell());
     295          11 :     if (rootBox) {
     296          11 :       if (aModType == nsIDOMMutationEvent::REMOVAL)
     297           0 :         rootBox->RemoveTooltipSupport(aElement);
     298          11 :       if (aModType == nsIDOMMutationEvent::ADDITION)
     299          11 :         rootBox->AddTooltipSupport(aElement);
     300             :     }
     301             :   }
     302             : 
     303             : #endif // MOZ_XUL
     304             : 
     305         322 :   if (primaryFrame) {
     306             :     // See if we have appearance information for a theme.
     307         148 :     const nsStyleDisplay* disp = primaryFrame->StyleDisplay();
     308         148 :     if (disp->mAppearance) {
     309          52 :       nsITheme* theme = PresContext()->GetTheme();
     310          52 :       if (theme && theme->ThemeSupportsWidget(PresContext(), primaryFrame, disp->mAppearance)) {
     311          52 :         bool repaint = false;
     312          52 :         theme->WidgetStateChanged(primaryFrame, disp->mAppearance, aAttribute,
     313         104 :             &repaint, aOldValue);
     314          52 :         if (repaint)
     315           8 :           hint |= nsChangeHint_RepaintFrame;
     316             :       }
     317             :     }
     318             : 
     319             :     // let the frame deal with it now, so we don't have to deal later
     320         148 :     primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
     321             :     // XXXwaterson should probably check for IB split siblings
     322             :     // here, and propagate the AttributeChanged notification to
     323             :     // them, as well. Currently, inline frames don't do anything on
     324             :     // this notification, so it's not that big a deal.
     325             :   }
     326             : 
     327             :   // See if we can optimize away the style re-resolution -- must be called after
     328             :   // the frame's AttributeChanged() in case it does something that affects the style
     329         644 :   RestyleHintData rsdata;
     330             :   nsRestyleHint rshint =
     331         322 :     StyleSet()->HasAttributeDependentStyle(aElement,
     332             :                                            aNameSpaceID,
     333             :                                            aAttribute,
     334             :                                            aModType,
     335             :                                            true,
     336             :                                            aOldValue,
     337         322 :                                            rsdata);
     338         322 :   PostRestyleEvent(aElement, rshint, hint, &rsdata);
     339             : }
     340             : 
     341             : void
     342           3 : GeckoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
     343             :                                          nsRestyleHint aRestyleHint)
     344             : {
     345           3 :   NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
     346             :                "Should not reconstruct the root of the frame tree.  "
     347             :                "Use ReconstructDocElementHierarchy instead.");
     348           3 :   MOZ_ASSERT(!(aRestyleHint & ~(eRestyle_Subtree | eRestyle_ForceDescendants)),
     349             :              "the only bits allowed in aRestyleHint are eRestyle_Subtree and "
     350             :              "eRestyle_ForceDescendants");
     351             : 
     352           3 :   mRebuildAllExtraHint |= aExtraHint;
     353           3 :   mRebuildAllRestyleHint |= aRestyleHint;
     354             : 
     355             :   // Processing the style changes could cause a flush that propagates to
     356             :   // the parent frame and thus destroys the pres shell, so we must hold
     357             :   // a reference.
     358           5 :   nsCOMPtr<nsIPresShell> presShell = PresContext()->GetPresShell();
     359           3 :   if (!presShell || !presShell->GetRootFrame()) {
     360           1 :     mDoRebuildAllStyleData = false;
     361           1 :     return;
     362             :   }
     363             : 
     364             :   // Make sure that the viewmanager will outlive the presshell
     365           4 :   RefPtr<nsViewManager> vm = presShell->GetViewManager();
     366             :   mozilla::Unused << vm; // Not used within this function
     367             : 
     368             :   // We may reconstruct frames below and hence process anything that is in the
     369             :   // tree. We don't want to get notified to process those items again after.
     370           2 :   presShell->GetDocument()->FlushPendingNotifications(FlushType::ContentAndNotify);
     371             : 
     372           4 :   nsAutoScriptBlocker scriptBlocker;
     373             : 
     374           2 :   mDoRebuildAllStyleData = true;
     375             : 
     376           2 :   ProcessPendingRestyles();
     377             : }
     378             : 
     379             : void
     380           2 : GeckoRestyleManager::StartRebuildAllStyleData(RestyleTracker& aRestyleTracker)
     381             : {
     382           2 :   MOZ_ASSERT(mIsProcessingRestyles);
     383             : 
     384           2 :   nsIFrame* rootFrame = PresContext()->PresShell()->GetRootFrame();
     385           2 :   if (!rootFrame) {
     386             :     // No need to do anything.
     387           0 :     return;
     388             :   }
     389             : 
     390           2 :   mInRebuildAllStyleData = true;
     391             : 
     392             :   // Tell the style set to get the old rule tree out of the way
     393             :   // so we can recalculate while maintaining rule tree immutability
     394           2 :   nsresult rv = StyleSet()->BeginReconstruct();
     395           2 :   if (NS_FAILED(rv)) {
     396           0 :     MOZ_CRASH("unable to rebuild style data");
     397             :   }
     398             : 
     399           2 :   nsRestyleHint restyleHint = mRebuildAllRestyleHint;
     400           2 :   nsChangeHint changeHint = mRebuildAllExtraHint;
     401           2 :   mRebuildAllExtraHint = nsChangeHint(0);
     402           2 :   mRebuildAllRestyleHint = nsRestyleHint(0);
     403             : 
     404           2 :   restyleHint |= eRestyle_ForceDescendants;
     405             : 
     406           3 :   if (!(restyleHint & eRestyle_Subtree) &&
     407           1 :       (restyleHint & ~(eRestyle_Force | eRestyle_ForceDescendants))) {
     408             :     // We want this hint to apply to the root node's primary frame
     409             :     // rather than the root frame, since it's the primary frame that has
     410             :     // the styles for the root element (rather than the ancestors of the
     411             :     // primary frame whose mContent is the root node but which have
     412             :     // different styles).  If we use up the hint for one of the
     413             :     // ancestors that we hit first, then we'll fail to do the restyling
     414             :     // we need to do.
     415           0 :     Element* root = PresContext()->Document()->GetRootElement();
     416           0 :     if (root) {
     417             :       // If the root element is gone, dropping the hint on the floor
     418             :       // should be fine.
     419           0 :       aRestyleTracker.AddPendingRestyle(root, restyleHint, nsChangeHint(0));
     420             :     }
     421           0 :     restyleHint = nsRestyleHint(0);
     422             :   }
     423             : 
     424             :   // Recalculate all of the style contexts for the document, from the
     425             :   // root frame.  We can't do this with a change hint, since we can't
     426             :   // post a change hint for the root frame.
     427             :   // Note that we can ignore the return value of ComputeStyleChangeFor
     428             :   // because we never need to reframe the root frame.
     429             :   // XXX Does it matter that we're passing aExtraHint to the real root
     430             :   // frame and not the root node's primary frame?  (We could do
     431             :   // roughly what we do for aRestyleHint above.)
     432             :   ComputeAndProcessStyleChange(rootFrame,
     433             :                                changeHint, aRestyleTracker, restyleHint,
     434           2 :                                RestyleHintData());
     435             : }
     436             : 
     437             : void
     438           2 : GeckoRestyleManager::FinishRebuildAllStyleData()
     439             : {
     440           2 :   MOZ_ASSERT(mInRebuildAllStyleData, "bad caller");
     441             : 
     442             :   // Tell the style set it's safe to destroy the old rule tree.  We
     443             :   // must do this after the ProcessRestyledFrames call in case the
     444             :   // change list has frame reconstructs in it (since frames to be
     445             :   // reconstructed will still have their old style context pointers
     446             :   // until they are destroyed).
     447           2 :   StyleSet()->EndReconstruct();
     448             : 
     449           2 :   mInRebuildAllStyleData = false;
     450           2 : }
     451             : 
     452             : void
     453         266 : GeckoRestyleManager::ProcessPendingRestyles()
     454             : {
     455         266 :   NS_PRECONDITION(PresContext()->Document(), "No document?  Pshaw!");
     456         266 :   NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
     457             :                   "Missing a script blocker!");
     458             : 
     459             :   // First do any queued-up frame creation.  (We should really
     460             :   // merge this into the rest of the process, though; see bug 827239.)
     461         266 :   PresContext()->FrameConstructor()->CreateNeededFrames();
     462             : 
     463             :   // Process non-animation restyles...
     464         266 :   MOZ_ASSERT(!mIsProcessingRestyles,
     465             :              "Nesting calls to ProcessPendingRestyles?");
     466         266 :   mIsProcessingRestyles = true;
     467             : 
     468             :   // Before we process any restyles, we need to ensure that style
     469             :   // resulting from any animations is up-to-date, so that if any style
     470             :   // changes we cause trigger transitions, we have the correct old style
     471             :   // for starting the transition.
     472             :   bool haveNonAnimation =
     473         266 :     mHavePendingNonAnimationRestyles || mDoRebuildAllStyleData;
     474         266 :   if (haveNonAnimation) {
     475          23 :     ++mAnimationGeneration;
     476          23 :     UpdateOnlyAnimationStyles();
     477             :   } else {
     478             :     // If we don't have non-animation style updates, then we have queued
     479             :     // up animation style updates from the refresh driver tick.  This
     480             :     // doesn't necessarily include *all* animation style updates, since
     481             :     // we might be suppressing main-thread updates for some animations,
     482             :     // so we don't want to call UpdateOnlyAnimationStyles, which updates
     483             :     // all animations.  In other words, the work that we're about to do
     484             :     // to process the pending restyles queue is a *subset* of the work
     485             :     // that UpdateOnlyAnimationStyles would do, since we're *not*
     486             :     // updating transitions that are running on the compositor thread
     487             :     // and suppressed on the main thread.
     488             :     //
     489             :     // But when we update those styles, we want to suppress updates to
     490             :     // transitions just like we do in UpdateOnlyAnimationStyles.  So we
     491             :     // want to tell the transition manager to act as though we're in
     492             :     // UpdateOnlyAnimationStyles.
     493             :     //
     494             :     // FIXME: In the future, we might want to refactor the way the
     495             :     // animation and transition manager do their refresh driver ticks so
     496             :     // that we can use UpdateOnlyAnimationStyles, with a different
     497             :     // boolean argument, for this update as well, instead of having them
     498             :     // post style updates in their WillRefresh methods.
     499         243 :     PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(true);
     500             :   }
     501             : 
     502         266 :   ProcessRestyles(mPendingRestyles);
     503             : 
     504         266 :   if (!haveNonAnimation) {
     505         243 :     PresContext()->TransitionManager()->SetInAnimationOnlyStyleUpdate(false);
     506             :   }
     507             : 
     508         266 :   mIsProcessingRestyles = false;
     509             : 
     510         266 :   NS_ASSERTION(haveNonAnimation || !mHavePendingNonAnimationRestyles,
     511             :                "should not have added restyles");
     512         266 :   mHavePendingNonAnimationRestyles = false;
     513             : 
     514         266 :   if (mDoRebuildAllStyleData) {
     515             :     // We probably wasted a lot of work up above, but this seems safest
     516             :     // and it should be rarely used.
     517             :     // This might add us as a refresh observer again; that's ok.
     518           0 :     ProcessPendingRestyles();
     519             : 
     520           0 :     NS_ASSERTION(!mDoRebuildAllStyleData,
     521             :                  "repeatedly setting mDoRebuildAllStyleData?");
     522             :   }
     523             : 
     524         266 :   MOZ_ASSERT(!mInRebuildAllStyleData,
     525             :              "should have called FinishRebuildAllStyleData");
     526         266 : }
     527             : 
     528             : void
     529          25 : GeckoRestyleManager::BeginProcessingRestyles(RestyleTracker& aRestyleTracker)
     530             : {
     531             :   // Make sure to not rebuild quote or counter lists while we're
     532             :   // processing restyles
     533          25 :   PresContext()->FrameConstructor()->BeginUpdate();
     534             : 
     535          25 :   mInStyleRefresh = true;
     536             : 
     537          25 :   if (ShouldStartRebuildAllFor(aRestyleTracker)) {
     538           2 :     mDoRebuildAllStyleData = false;
     539           2 :     StartRebuildAllStyleData(aRestyleTracker);
     540             :   }
     541          25 : }
     542             : 
     543             : void
     544          25 : GeckoRestyleManager::EndProcessingRestyles()
     545             : {
     546          25 :   FlushOverflowChangedTracker();
     547             : 
     548          25 :   MOZ_ASSERT(mAnimationsWithDestroyedFrame);
     549          25 :   mAnimationsWithDestroyedFrame->
     550          25 :     StopAnimationsForElementsWithoutFrames();
     551             : 
     552             :   // Set mInStyleRefresh to false now, since the EndUpdate call might
     553             :   // add more restyles.
     554          25 :   mInStyleRefresh = false;
     555             : 
     556          25 :   if (mInRebuildAllStyleData) {
     557           2 :     FinishRebuildAllStyleData();
     558             :   }
     559             : 
     560          25 :   PresContext()->FrameConstructor()->EndUpdate();
     561             : 
     562             : #ifdef DEBUG
     563          25 :   PresContext()->PresShell()->VerifyStyleTree();
     564             : #endif
     565          25 : }
     566             : 
     567             : void
     568          33 : GeckoRestyleManager::UpdateOnlyAnimationStyles()
     569             : {
     570          33 :   bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
     571             : 
     572          33 :   nsIDocument* document = PresContext()->Document();
     573             :   nsSMILAnimationController* animationController =
     574          63 :     document->HasAnimationController() ?
     575          30 :     document->GetAnimationController() :
     576          33 :     nullptr;
     577          63 :   bool doSMIL = animationController &&
     578          63 :                 animationController->MightHavePendingStyleUpdates();
     579             : 
     580          33 :   if (!doCSS && !doSMIL) {
     581          32 :     return;
     582             :   }
     583             : 
     584           1 :   nsTransitionManager* transitionManager = PresContext()->TransitionManager();
     585             : 
     586           1 :   transitionManager->SetInAnimationOnlyStyleUpdate(true);
     587             : 
     588             :   RestyleTracker tracker(ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
     589           2 :                          ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT);
     590           1 :   tracker.Init(this);
     591             : 
     592           1 :   if (doCSS) {
     593           1 :     PresContext()->EffectCompositor()->AddStyleUpdatesTo(tracker);
     594             :   }
     595             : 
     596           1 :   if (doSMIL) {
     597           0 :     animationController->AddStyleUpdatesTo(tracker);
     598             :   }
     599             : 
     600           1 :   ProcessRestyles(tracker);
     601             : 
     602           1 :   transitionManager->SetInAnimationOnlyStyleUpdate(false);
     603             : }
     604             : 
     605             : void
     606         227 : GeckoRestyleManager::PostRestyleEventInternal()
     607             : {
     608             :   // Make sure we're not in a style refresh; if we are, we still have
     609             :   // a call to ProcessPendingRestyles coming and there's no need to
     610             :   // add ourselves as a refresh observer until then.
     611         227 :   nsIPresShell* presShell = PresContext()->PresShell();
     612         227 :   if (!mInStyleRefresh) {
     613         215 :     presShell->ObserveStyleFlushes();
     614             :   }
     615             : 
     616             :   // Unconditionally flag our document as needing a flush.  The other
     617             :   // option here would be a dedicated boolean to track whether we need
     618             :   // to do so (set here and unset in ProcessPendingRestyles).
     619         227 :   presShell->SetNeedStyleFlush();
     620         227 : }
     621             : 
     622             : 
     623             : void
     624         767 : GeckoRestyleManager::PostRestyleEvent(Element* aElement,
     625             :                                       nsRestyleHint aRestyleHint,
     626             :                                       nsChangeHint aMinChangeHint,
     627             :                                       const RestyleHintData* aRestyleHintData)
     628             : {
     629        1534 :   if (MOZ_UNLIKELY(IsDisconnected()) ||
     630         767 :       MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
     631           0 :     return;
     632             :   }
     633             : 
     634         767 :   if (aRestyleHint == 0 && !aMinChangeHint) {
     635             :     // Nothing to do here
     636         574 :     return;
     637             :   }
     638             : 
     639         386 :   mPendingRestyles.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint,
     640         193 :                                      aRestyleHintData);
     641             : 
     642             :   // Set mHavePendingNonAnimationRestyles for any restyle that could
     643             :   // possibly contain non-animation styles (i.e., those that require us
     644             :   // to do an animation-only style flush before processing style changes
     645             :   // to ensure correct initialization of CSS transitions).
     646         193 :   if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
     647         141 :     mHavePendingNonAnimationRestyles = true;
     648             :   }
     649             : 
     650         193 :   PostRestyleEventInternal();
     651             : }
     652             : 
     653             : void
     654           0 : GeckoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
     655             :                                                   nsRestyleHint aRestyleHint)
     656             : {
     657           0 :   NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
     658             :                "Should not reconstruct the root of the frame tree.  "
     659             :                "Use ReconstructDocElementHierarchy instead.");
     660           0 :   MOZ_ASSERT(!(aRestyleHint & eRestyle_SomeDescendants),
     661             :              "PostRebuildAllStyleDataEvent does not handle "
     662             :              "eRestyle_SomeDescendants");
     663             : 
     664           0 :   mDoRebuildAllStyleData = true;
     665           0 :   mRebuildAllExtraHint |= aExtraHint;
     666           0 :   mRebuildAllRestyleHint |= aRestyleHint;
     667             : 
     668             :   // Get a restyle event posted if necessary
     669           0 :   PostRestyleEventInternal();
     670           0 : }
     671             : 
     672             : // aContent must be the content for the frame in question, which may be
     673             : // :before/:after content
     674             : /* static */ bool
     675         823 : GeckoRestyleManager::TryInitiatingTransition(nsPresContext* aPresContext,
     676             :                                              nsIContent* aContent,
     677             :                                              nsStyleContext* aOldStyleContext,
     678             :                                              RefPtr<nsStyleContext>*
     679             :                                                aNewStyleContext /* inout */)
     680             : {
     681         823 :   if (!aContent || !aContent->IsElement()) {
     682          31 :     return false;
     683             :   }
     684             : 
     685             :   // Notify the transition manager.  If it starts a transition,
     686             :   // it might modify the new style context.
     687        1584 :   RefPtr<nsStyleContext> sc = *aNewStyleContext;
     688         792 :   aPresContext->TransitionManager()->StyleContextChanged(
     689         792 :     aContent->AsElement(), aOldStyleContext, aNewStyleContext);
     690         792 :   return *aNewStyleContext != sc;
     691             : }
     692             : 
     693             : static dom::Element*
     694        1063 : ElementForStyleContext(nsIContent* aParentContent,
     695             :                        nsIFrame* aFrame,
     696             :                        CSSPseudoElementType aPseudoType)
     697             : {
     698             :   // We don't expect XUL tree stuff here.
     699        1063 :   NS_PRECONDITION(aPseudoType == CSSPseudoElementType::NotPseudo ||
     700             :                   aPseudoType == CSSPseudoElementType::InheritingAnonBox ||
     701             :                   aPseudoType == CSSPseudoElementType::NonInheritingAnonBox ||
     702             :                   aPseudoType < CSSPseudoElementType::Count,
     703             :                   "Unexpected pseudo");
     704             :   // XXX see the comments about the various element confusion in
     705             :   // ElementRestyler::Restyle.
     706        1063 :   if (aPseudoType == CSSPseudoElementType::NotPseudo) {
     707         940 :     return aFrame->GetContent()->AsElement();
     708             :   }
     709             : 
     710         123 :   if (aPseudoType == CSSPseudoElementType::InheritingAnonBox ||
     711             :       aPseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
     712          90 :     return nullptr;
     713             :   }
     714             : 
     715          33 :   if (aPseudoType == CSSPseudoElementType::firstLetter) {
     716           0 :     NS_ASSERTION(aFrame->IsLetterFrame(),
     717             :                  "firstLetter pseudoTag without a nsFirstLetterFrame");
     718           0 :     nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
     719           0 :     return block->GetContent()->AsElement();
     720             :   }
     721             : 
     722          33 :   if (aPseudoType == CSSPseudoElementType::mozColorSwatch) {
     723           0 :     MOZ_ASSERT(aFrame->GetParent() &&
     724             :                aFrame->GetParent()->GetParent(),
     725             :                "Color swatch frame should have a parent & grandparent");
     726             : 
     727           0 :     nsIFrame* grandparentFrame = aFrame->GetParent()->GetParent();
     728           0 :     MOZ_ASSERT(grandparentFrame->IsColorControlFrame(),
     729             :                "Color swatch's grandparent should be nsColorControlFrame");
     730             : 
     731           0 :     return grandparentFrame->GetContent()->AsElement();
     732             :   }
     733             : 
     734          33 :   if (aPseudoType == CSSPseudoElementType::mozNumberText ||
     735          33 :       aPseudoType == CSSPseudoElementType::mozNumberWrapper ||
     736          33 :       aPseudoType == CSSPseudoElementType::mozNumberSpinBox ||
     737          33 :       aPseudoType == CSSPseudoElementType::mozNumberSpinUp ||
     738             :       aPseudoType == CSSPseudoElementType::mozNumberSpinDown) {
     739             :     // Get content for nearest nsNumberControlFrame:
     740           0 :     nsIFrame* f = aFrame->GetParent();
     741           0 :     MOZ_ASSERT(f);
     742           0 :     while (!f->IsNumberControlFrame()) {
     743           0 :       f = f->GetParent();
     744           0 :       MOZ_ASSERT(f);
     745             :     }
     746           0 :     return f->GetContent()->AsElement();
     747             :   }
     748             : 
     749          33 :   Element* frameElement = aFrame->GetContent()->AsElement();
     750          33 :   if (frameElement->IsNativeAnonymous()) {
     751             :     // NAC-implemented pseudos use the closest non-NAC element as their
     752             :     // element to inherit from.
     753             :     Element* originatingElement =
     754          33 :       nsContentUtils::GetClosestNonNativeAnonymousAncestor(frameElement);
     755          33 :     if (originatingElement) {
     756          33 :       return originatingElement;
     757             :     }
     758             :   }
     759             : 
     760           0 :   if (aParentContent) {
     761           0 :     return aParentContent->AsElement();
     762             :   }
     763             : 
     764           0 :   MOZ_ASSERT(aFrame->GetContent()->GetParent(),
     765             :              "should not have got here for the root element");
     766           0 :   return aFrame->GetContent()->GetParent()->AsElement();
     767             : }
     768             : 
     769             : /**
     770             :  * Some pseudo-elements actually have a content node created for them,
     771             :  * whereas others have only a frame but not a content node.  In some
     772             :  * cases, we want to support style attributes or states on those
     773             :  * elements.  For those pseudo-elements, we need to pass the
     774             :  * anonymous pseudo-element content to selector matching processes in
     775             :  * addition to the element that the pseudo-element is for; in other
     776             :  * cases we should pass null instead.  This function returns the
     777             :  * pseudo-element content that we should pass.
     778             :  */
     779             : static dom::Element*
     780          35 : PseudoElementForStyleContext(nsIFrame* aFrame,
     781             :                              CSSPseudoElementType aPseudoType)
     782             : {
     783          35 :   if (aPseudoType >= CSSPseudoElementType::Count) {
     784          31 :     return nullptr;
     785             :   }
     786             : 
     787           8 :   if (nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
     788           4 :       nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType)) {
     789           4 :     return aFrame->GetContent()->AsElement();
     790             :   }
     791             : 
     792           0 :   return nullptr;
     793             : }
     794             : 
     795             : /**
     796             :  * FIXME: Temporary.  Should merge with following function.
     797             :  */
     798             : static nsIFrame*
     799        3802 : GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame)
     800             : {
     801             :   // Account for {ib} splits when looking for "prevContinuation".  In
     802             :   // particular, for the first-continuation of a part of an {ib} split
     803             :   // we want to use the previous ib-split sibling of the previous
     804             :   // ib-split sibling of aFrame, which should have the same style
     805             :   // context as aFrame itself.  In particular, if aFrame is the first
     806             :   // continuation of an inline part of a block-in-inline split then its
     807             :   // previous ib-split sibling is a block, and the previous ib-split
     808             :   // sibling of _that_ is an inline, just like aFrame.  Similarly, if
     809             :   // aFrame is the first continuation of a block part of an
     810             :   // block-in-inline split (a block-in-inline wrapper block), then its
     811             :   // previous ib-split sibling is an inline and the previous ib-split
     812             :   // sibling of that is either another block-in-inline wrapper block box
     813             :   // or null.
     814        3802 :   nsIFrame* prevContinuation = aFrame->GetPrevContinuation();
     815        7604 :   if (!prevContinuation &&
     816        3802 :       (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
     817             :     // We're the first continuation, so we can just get the frame
     818             :     // property directly
     819             :     prevContinuation =
     820           0 :       aFrame->GetProperty(nsIFrame::IBSplitPrevSibling());
     821           0 :     if (prevContinuation) {
     822             :       prevContinuation =
     823           0 :         prevContinuation->GetProperty(nsIFrame::IBSplitPrevSibling());
     824             :     }
     825             :   }
     826             : 
     827        3802 :   NS_ASSERTION(!prevContinuation ||
     828             :                prevContinuation->GetContent() == aFrame->GetContent(),
     829             :                "unexpected content mismatch");
     830             : 
     831        3802 :   return prevContinuation;
     832             : }
     833             : 
     834             : /**
     835             :  * Get the previous continuation or similar ib-split sibling (assuming
     836             :  * block/inline alternation), conditionally on it having the same style.
     837             :  * This assumes that we're not between resolving the two (i.e., that
     838             :  * they're both already resolved.
     839             :  */
     840             : static nsIFrame*
     841        2595 : GetPrevContinuationWithSameStyle(nsIFrame* aFrame)
     842             : {
     843        2595 :   nsIFrame* prevContinuation = GetPrevContinuationWithPossiblySameStyle(aFrame);
     844        2595 :   if (!prevContinuation) {
     845        2595 :     return nullptr;
     846             :   }
     847             : 
     848           0 :   nsStyleContext* prevStyle = prevContinuation->StyleContext();
     849           0 :   nsStyleContext* selfStyle = aFrame->StyleContext();
     850           0 :   if (prevStyle != selfStyle) {
     851           0 :     NS_ASSERTION(prevStyle->GetPseudo() != selfStyle->GetPseudo() ||
     852             :                  prevStyle->GetParent() != selfStyle->GetParent(),
     853             :                  "continuations should have the same style context");
     854           0 :     prevContinuation = nullptr;
     855             :   }
     856           0 :   return prevContinuation;
     857             : }
     858             : 
     859             : nsresult
     860           5 : GeckoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
     861             : {
     862           5 :   LayoutFrameType frameType = aFrame->Type();
     863           5 :   if (frameType == LayoutFrameType::Placeholder) {
     864             :     // Also reparent the out-of-flow and all its continuations.
     865             :     nsIFrame* outOfFlow =
     866           0 :       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     867           0 :     NS_ASSERTION(outOfFlow, "no out-of-flow frame");
     868           0 :     do {
     869           0 :       ReparentStyleContext(outOfFlow);
     870           0 :     } while ((outOfFlow = outOfFlow->GetNextContinuation()));
     871           5 :   } else if (frameType == LayoutFrameType::Backdrop) {
     872             :     // Style context of backdrop frame has no parent style context, and
     873             :     // thus we do not need to reparent it.
     874           0 :     return NS_OK;
     875             :   }
     876             : 
     877             :   // DO NOT verify the style tree before reparenting.  The frame
     878             :   // tree has already been changed, so this check would just fail.
     879           5 :   nsStyleContext* oldContext = aFrame->StyleContext();
     880             : 
     881          10 :   RefPtr<nsStyleContext> newContext;
     882             :   nsIFrame* providerFrame;
     883           5 :   nsStyleContext* newParentContext = aFrame->GetParentStyleContext(&providerFrame);
     884           5 :   bool isChild = providerFrame && providerFrame->GetParent() == aFrame;
     885           5 :   nsIFrame* providerChild = nullptr;
     886           5 :   if (isChild) {
     887           0 :     ReparentStyleContext(providerFrame);
     888             :     // Get the style context again after ReparentStyleContext() which might have
     889             :     // changed it.
     890           0 :     newParentContext = providerFrame->StyleContext();
     891           0 :     providerChild = providerFrame;
     892             :   }
     893             : 
     894             : #ifdef DEBUG
     895             :   {
     896             :     // Check that our assumption that continuations of the same
     897             :     // pseudo-type and with the same style context parent have the
     898             :     // same style context is valid before the reresolution.  (We need
     899             :     // to check the pseudo-type and style context parent because of
     900             :     // :first-letter and :first-line, where we create styled and
     901             :     // unstyled letter/line frames distinguished by pseudo-type, and
     902             :     // then need to distinguish their descendants based on having
     903             :     // different parents.)
     904           5 :     nsIFrame* nextContinuation = aFrame->GetNextContinuation();
     905           5 :     if (nextContinuation) {
     906             :       nsStyleContext* nextContinuationContext =
     907           0 :         nextContinuation->StyleContext();
     908           0 :       NS_ASSERTION(oldContext == nextContinuationContext ||
     909             :                    oldContext->GetPseudo() !=
     910             :                      nextContinuationContext->GetPseudo() ||
     911             :                    oldContext->GetParent() !=
     912             :                      nextContinuationContext->GetParent(),
     913             :                    "continuations should have the same style context");
     914             :     }
     915             :   }
     916             : #endif
     917             : 
     918           5 :   if (!newParentContext && !oldContext->GetParent()) {
     919             :     // No need to do anything here.
     920             : #ifdef DEBUG
     921             :     // Make sure we have no children, so we really know there is nothing to do.
     922           0 :     nsIFrame::ChildListIterator lists(aFrame);
     923           0 :     for (; !lists.IsDone(); lists.Next()) {
     924           0 :       MOZ_ASSERT(lists.CurrentList().IsEmpty(),
     925             :                  "Failing to reparent style context for child of "
     926             :                  "non-inheriting anon box");
     927             :     }
     928             : #endif // DEBUG
     929           0 :     return NS_OK;
     930             :   }
     931             : 
     932           5 :   NS_ASSERTION(newParentContext, "Reparenting something that has no usable"
     933             :                " parent? Shouldn't happen!");
     934             :   // XXX need to do something here to produce the correct style context for
     935             :   // an IB split whose first inline part is inside a first-line frame.
     936             :   // Currently the first IB anonymous block's style context takes the first
     937             :   // part's style context as parent, which is wrong since first-line style
     938             :   // should not apply to the anonymous block.
     939             : 
     940             :   nsIFrame* prevContinuation =
     941           5 :     GetPrevContinuationWithPossiblySameStyle(aFrame);
     942             :   nsStyleContext* prevContinuationContext;
     943             :   bool copyFromContinuation =
     944           0 :     prevContinuation &&
     945             :     (prevContinuationContext = prevContinuation->StyleContext())
     946           5 :       ->GetPseudo() == oldContext->GetPseudo() &&
     947           5 :      prevContinuationContext->GetParent() == newParentContext;
     948           5 :   if (copyFromContinuation) {
     949             :     // Just use the style context from the frame's previous
     950             :     // continuation (see assertion about aFrame->GetNextContinuation()
     951             :     // above, which we would have previously hit for aFrame's previous
     952             :     // continuation).
     953           0 :     newContext = prevContinuationContext;
     954             :   } else {
     955           5 :     nsIFrame* parentFrame = aFrame->GetParent();
     956             :     Element* element =
     957           5 :       ElementForStyleContext(parentFrame ? parentFrame->GetContent() : nullptr,
     958             :                              aFrame,
     959           5 :                              oldContext->GetPseudoType());
     960             :     newContext = StyleSet()->
     961           5 :                    ReparentStyleContext(oldContext, newParentContext, element);
     962             :   }
     963             : 
     964           5 :   if (newContext) {
     965           5 :     if (newContext != oldContext) {
     966             :       // We probably don't want to initiate transitions from
     967             :       // ReparentStyleContext, since we call it during frame
     968             :       // construction rather than in response to dynamic changes.
     969             :       // Also see the comment at the start of
     970             :       // nsTransitionManager::ConsiderInitiatingTransition.
     971             : #if 0
     972             :       if (!copyFromContinuation) {
     973             :         TryInitiatingTransition(mPresContext, aFrame->GetContent(),
     974             :                                 oldContext, &newContext);
     975             :       }
     976             : #endif
     977             : 
     978             :       // Ensure the new context ends up resolving all the structs the old
     979             :       // context resolved.
     980           0 :       if (!copyFromContinuation) {
     981           0 :         newContext->AsGecko()->EnsureSameStructsCached(oldContext);
     982             :       }
     983             : 
     984           0 :       aFrame->SetStyleContext(newContext);
     985             : 
     986           0 :       nsIFrame::ChildListIterator lists(aFrame);
     987           0 :       for (; !lists.IsDone(); lists.Next()) {
     988           0 :         for (nsIFrame* child : lists.CurrentList()) {
     989             :           // only do frames that are in flow
     990           0 :           if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
     991             :               child != providerChild) {
     992             : #ifdef DEBUG
     993           0 :             if (child->IsPlaceholderFrame()) {
     994             :               nsIFrame* outOfFlowFrame =
     995           0 :                 nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
     996           0 :               NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
     997             : 
     998           0 :               NS_ASSERTION(outOfFlowFrame != providerChild,
     999             :                            "Out of flow provider?");
    1000             :             }
    1001             : #endif
    1002           0 :             ReparentStyleContext(child);
    1003             :           }
    1004             :         }
    1005             :       }
    1006             : 
    1007             :       // If this frame is part of an IB split, then the style context of
    1008             :       // the next part of the split might be a child of our style context.
    1009             :       // Reparent its style context just in case one of our ancestors
    1010             :       // (split or not) hasn't done so already). It's not a problem to
    1011             :       // reparent the same frame twice because the "if (newContext !=
    1012             :       // oldContext)" check will prevent us from redoing work.
    1013           0 :       if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
    1014           0 :           !aFrame->GetPrevContinuation()) {
    1015           0 :         nsIFrame* sib = aFrame->GetProperty(nsIFrame::IBSplitSibling());
    1016           0 :         if (sib) {
    1017           0 :           ReparentStyleContext(sib);
    1018             :         }
    1019             :       }
    1020             : 
    1021             :       // do additional contexts
    1022           0 :       int32_t contextIndex = 0;
    1023           0 :       for (nsStyleContext* oldExtraContext;
    1024           0 :            (oldExtraContext = aFrame->GetAdditionalStyleContext(contextIndex));
    1025             :            ++contextIndex) {
    1026           0 :         RefPtr<nsStyleContext> newExtraContext;
    1027             :         newExtraContext = StyleSet()->
    1028           0 :                             ReparentStyleContext(oldExtraContext,
    1029           0 :                                                  newContext, nullptr);
    1030           0 :         if (newExtraContext) {
    1031           0 :           if (newExtraContext != oldExtraContext) {
    1032             :             // Ensure the new context ends up resolving all the structs the old
    1033             :             // context resolved.
    1034           0 :             newContext->AsGecko()->EnsureSameStructsCached(oldContext);
    1035             :           }
    1036             : 
    1037           0 :           aFrame->SetAdditionalStyleContext(contextIndex, newExtraContext);
    1038             :         }
    1039             :       }
    1040             : #ifdef DEBUG
    1041           0 :       DebugVerifyStyleTree(aFrame);
    1042             : #endif
    1043             :     }
    1044             :   }
    1045             : 
    1046           5 :   return NS_OK;
    1047             : }
    1048             : 
    1049          61 : ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
    1050             :                                  nsIFrame* aFrame,
    1051             :                                  nsStyleChangeList* aChangeList,
    1052             :                                  nsChangeHint aHintsHandledByAncestors,
    1053             :                                  RestyleTracker& aRestyleTracker,
    1054             :                                  nsTArray<nsCSSSelector*>&
    1055             :                                    aSelectorsForDescendants,
    1056             :                                  TreeMatchContext& aTreeMatchContext,
    1057             :                                  nsTArray<nsIContent*>&
    1058             :                                    aVisibleKidsOfHiddenElement,
    1059             :                                  nsTArray<ContextToClear>& aContextsToClear,
    1060             :                                  nsTArray<RefPtr<nsStyleContext>>&
    1061          61 :                                    aSwappedStructOwners)
    1062             :   : mPresContext(aPresContext)
    1063             :   , mFrame(aFrame)
    1064             :   , mParentContent(nullptr)
    1065             :     // XXXldb Why does it make sense to use aParentContent?  (See
    1066             :     // comment above assertion at start of ElementRestyler::Restyle.)
    1067          61 :   , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
    1068             :   , mChangeList(aChangeList)
    1069             :   , mHintsHandledByAncestors(aHintsHandledByAncestors)
    1070             :   , mHintsHandledBySelf(nsChangeHint(0))
    1071             :   , mRestyleTracker(aRestyleTracker)
    1072             :   , mSelectorsForDescendants(aSelectorsForDescendants)
    1073             :   , mTreeMatchContext(aTreeMatchContext)
    1074             :   , mResolvedChild(nullptr)
    1075             :   , mContextsToClear(aContextsToClear)
    1076             :   , mSwappedStructOwners(aSwappedStructOwners)
    1077             :   , mIsRootOfRestyle(true)
    1078             : #ifdef ACCESSIBILITY
    1079             :   , mDesiredA11yNotifications(eSendAllNotifications)
    1080          61 :   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
    1081             :   , mOurA11yNotification(eDontNotify)
    1082             :   , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
    1083             : #endif
    1084             : #ifdef RESTYLE_LOGGING
    1085         183 :   , mLoggingDepth(aRestyleTracker.LoggingDepth() + 1)
    1086             : #endif
    1087             : {
    1088          61 :   MOZ_ASSERT(!mContent || !mContent->IsStyledByServo());
    1089          61 :   MOZ_ASSERT(!(mHintsHandledByAncestors & nsChangeHint_ReconstructFrame),
    1090             :              "why restyle descendants if we are reconstructing the frame for "
    1091             :              "an ancestor?");
    1092          61 : }
    1093             : 
    1094        1141 : ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler,
    1095             :                                  nsIFrame* aFrame,
    1096        1141 :                                  uint32_t aConstructorFlags)
    1097        1141 :   : mPresContext(aParentRestyler.mPresContext)
    1098             :   , mFrame(aFrame)
    1099        1141 :   , mParentContent(aParentRestyler.mContent)
    1100             :     // XXXldb Why does it make sense to use aParentContent?  (See
    1101             :     // comment above assertion at start of ElementRestyler::Restyle.)
    1102        1141 :   , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
    1103        1141 :   , mChangeList(aParentRestyler.mChangeList)
    1104             :   , mHintsHandledByAncestors(
    1105             :       // Note that when FOR_OUT_OF_FLOW_CHILD, the out-of-flow may not be a
    1106             :       // geometric descendant of the frame where we started the reresolve.
    1107             :       // Therefore, even if mHintsHandledByAncestors already includes
    1108             :       // nsChangeHint_AllReflowHints/ we don't want to pass that on to the
    1109             :       // out-of-flow reresolve, since that can lead to the out-of-flow not
    1110             :       // getting reflowed when it should be (eg a reresolve starting at <body>
    1111             :       // that involves reflowing the <body> would miss reflowing fixed-pos
    1112             :       // nodes that also need reflow).  In the cases when the out-of-flow _is_
    1113             :       // a geometric descendant of a frame we already have a reflow hint
    1114             :       // for, reflow coalescing should keep us from doing the work twice.
    1115        1141 :       (aParentRestyler.mHintsHandledByAncestors |
    1116        2386 :        aParentRestyler.mHintsHandledBySelf) &
    1117        1141 :       ((aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) ?
    1118         104 :        ~nsChangeHint_AllReflowHints : ~nsChangeHint(0)))
    1119             :   , mHintsHandledBySelf(nsChangeHint(0))
    1120        1141 :   , mRestyleTracker(aParentRestyler.mRestyleTracker)
    1121        1141 :   , mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
    1122        1141 :   , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
    1123             :   , mResolvedChild(nullptr)
    1124        1141 :   , mContextsToClear(aParentRestyler.mContextsToClear)
    1125        1141 :   , mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
    1126             :   , mIsRootOfRestyle(false)
    1127             : #ifdef ACCESSIBILITY
    1128        1141 :   , mDesiredA11yNotifications(aParentRestyler.mKidsDesiredA11yNotifications)
    1129        1141 :   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
    1130             :   , mOurA11yNotification(eDontNotify)
    1131        1141 :   , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
    1132             : #endif
    1133             : #ifdef RESTYLE_LOGGING
    1134       14833 :   , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
    1135             : #endif
    1136             : {
    1137        1141 :   MOZ_ASSERT(!mContent || !mContent->IsStyledByServo());
    1138        1141 :   MOZ_ASSERT(!(mHintsHandledByAncestors & nsChangeHint_ReconstructFrame),
    1139             :              "why restyle descendants if we are reconstructing the frame for "
    1140             :              "an ancestor?");
    1141        1141 : }
    1142             : 
    1143           0 : ElementRestyler::ElementRestyler(ParentContextFromChildFrame,
    1144             :                                  const ElementRestyler& aParentRestyler,
    1145           0 :                                  nsIFrame* aFrame)
    1146           0 :   : mPresContext(aParentRestyler.mPresContext)
    1147             :   , mFrame(aFrame)
    1148           0 :   , mParentContent(aParentRestyler.mParentContent)
    1149             :     // XXXldb Why does it make sense to use aParentContent?  (See
    1150             :     // comment above assertion at start of ElementRestyler::Restyle.)
    1151           0 :   , mContent(mFrame->GetContent() ? mFrame->GetContent() : mParentContent)
    1152           0 :   , mChangeList(aParentRestyler.mChangeList)
    1153           0 :   , mHintsHandledByAncestors(aParentRestyler.mHintsHandledByAncestors |
    1154           0 :                              aParentRestyler.mHintsHandledBySelf)
    1155             :   , mHintsHandledBySelf(nsChangeHint(0))
    1156           0 :   , mRestyleTracker(aParentRestyler.mRestyleTracker)
    1157           0 :   , mSelectorsForDescendants(aParentRestyler.mSelectorsForDescendants)
    1158           0 :   , mTreeMatchContext(aParentRestyler.mTreeMatchContext)
    1159             :   , mResolvedChild(nullptr)
    1160           0 :   , mContextsToClear(aParentRestyler.mContextsToClear)
    1161           0 :   , mSwappedStructOwners(aParentRestyler.mSwappedStructOwners)
    1162             :   , mIsRootOfRestyle(false)
    1163             : #ifdef ACCESSIBILITY
    1164           0 :   , mDesiredA11yNotifications(aParentRestyler.mDesiredA11yNotifications)
    1165           0 :   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
    1166             :   , mOurA11yNotification(eDontNotify)
    1167           0 :   , mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
    1168             : #endif
    1169             : #ifdef RESTYLE_LOGGING
    1170           0 :   , mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
    1171             : #endif
    1172             : {
    1173           0 :   MOZ_ASSERT(!mContent || !mContent->IsStyledByServo());
    1174             : 
    1175             :   // We would assert here that we're not restyling a child provider frame if
    1176             :   // mHintsHandledByAncestors includes nsChangeHint_ReconstructFrame, but
    1177             :   // we do actually do this if the ReconstructFrame hint came from the
    1178             :   // RestyleTracker, rather than generated from CalcDifference.  (We could
    1179             :   // even try to avoid restyling the child provider frame, by returning
    1180             :   // early in ElementRestyler::Restyle if we grab out a ReconstructFrame
    1181             :   // hint from the RestyleTracker, but it's trickier to verify its correctness
    1182             :   // with all of the tree patching that happens currently, so for now we just
    1183             :   // skip the assertion.)
    1184           0 : }
    1185             : 
    1186           0 : ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
    1187             :                                  nsIContent* aContent,
    1188             :                                  nsStyleChangeList* aChangeList,
    1189             :                                  nsChangeHint aHintsHandledByAncestors,
    1190             :                                  RestyleTracker& aRestyleTracker,
    1191             :                                  nsTArray<nsCSSSelector*>& aSelectorsForDescendants,
    1192             :                                  TreeMatchContext& aTreeMatchContext,
    1193             :                                  nsTArray<nsIContent*>&
    1194             :                                    aVisibleKidsOfHiddenElement,
    1195             :                                  nsTArray<ContextToClear>& aContextsToClear,
    1196             :                                  nsTArray<RefPtr<nsStyleContext>>&
    1197           0 :                                    aSwappedStructOwners)
    1198             :   : mPresContext(aPresContext)
    1199             :   , mFrame(nullptr)
    1200             :   , mParentContent(nullptr)
    1201             :   , mContent(aContent)
    1202             :   , mChangeList(aChangeList)
    1203             :   , mHintsHandledByAncestors(aHintsHandledByAncestors)
    1204             :   , mHintsHandledBySelf(nsChangeHint(0))
    1205             :   , mRestyleTracker(aRestyleTracker)
    1206             :   , mSelectorsForDescendants(aSelectorsForDescendants)
    1207             :   , mTreeMatchContext(aTreeMatchContext)
    1208             :   , mResolvedChild(nullptr)
    1209             :   , mContextsToClear(aContextsToClear)
    1210             :   , mSwappedStructOwners(aSwappedStructOwners)
    1211             :   , mIsRootOfRestyle(true)
    1212             : #ifdef ACCESSIBILITY
    1213             :   , mDesiredA11yNotifications(eSendAllNotifications)
    1214           0 :   , mKidsDesiredA11yNotifications(mDesiredA11yNotifications)
    1215             :   , mOurA11yNotification(eDontNotify)
    1216           0 :   , mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
    1217             : #endif
    1218             : {
    1219           0 :   MOZ_ASSERT(!(mHintsHandledByAncestors & nsChangeHint_ReconstructFrame),
    1220             :              "why restyle descendants if we are reconstructing the frame for "
    1221             :              "an ancestor?");
    1222           0 : }
    1223             : 
    1224             : void
    1225         724 : ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
    1226             :                                nsStyleContext* aNewContext,
    1227             :                                nsChangeHint aChangeToAssume,
    1228             :                                uint32_t* aEqualStructs,
    1229             :                                uint32_t* aSamePointerStructs)
    1230             : {
    1231             :   static_assert(nsStyleStructID_Length <= 32,
    1232             :                 "aEqualStructs is not big enough");
    1233             : 
    1234             :   // Check some invariants about replacing one style context with another.
    1235         724 :   NS_ASSERTION(aOldContext->GetPseudo() == aNewContext->GetPseudo(),
    1236             :                "old and new style contexts should have the same pseudo");
    1237         724 :   NS_ASSERTION(aOldContext->GetPseudoType() == aNewContext->GetPseudoType(),
    1238             :                "old and new style contexts should have the same pseudo");
    1239             : 
    1240             :   nsChangeHint ourChange =
    1241         724 :     aOldContext->CalcStyleDifference(aNewContext,
    1242             :                                      aEqualStructs,
    1243         724 :                                      aSamePointerStructs);
    1244         724 :   NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
    1245             :                (ourChange & nsChangeHint_NeedReflow),
    1246             :                "Reflow hint bits set without actually asking for a reflow");
    1247             : 
    1248         724 :   LOG_RESTYLE("CaptureChange, ourChange = %s, aChangeToAssume = %s",
    1249             :               GeckoRestyleManager::ChangeHintToString(ourChange).get(),
    1250             :               GeckoRestyleManager::ChangeHintToString(aChangeToAssume).get());
    1251        1448 :   LOG_RESTYLE_INDENT();
    1252             : 
    1253             :   // nsChangeHint_UpdateEffects is not handled for descendants, but it can be
    1254             :   // set due to changes in inherited properties (fill and stroke).  Avoid
    1255             :   // propagating it into text nodes.
    1256        1450 :   if ((ourChange & nsChangeHint_UpdateEffects) &&
    1257         726 :       mContent && !mContent->IsElement()) {
    1258           0 :     ourChange &= ~nsChangeHint_UpdateEffects;
    1259             :   }
    1260             : 
    1261         724 :   ourChange |= aChangeToAssume;
    1262             : 
    1263             :   nsChangeHint changeToAppend =
    1264         724 :     NS_RemoveSubsumedHints(ourChange, mHintsHandledByAncestors);
    1265             : 
    1266             :   // mHintsHandledBySelf starts off as nsChangeHint(0), when restyling a given
    1267             :   // frame, and accumulates change hints for each same-style-continuation and
    1268             :   // {ib}-split sibling following it.  Most of the time, any subsequent frames
    1269             :   // we restyle with this ElementRestyler will generate exactly the same
    1270             :   // |changeToAppend| that we have already stored in mHintsHandledBySelf.  If
    1271             :   // we generate some hints that weren't handled by an earler same-style-
    1272             :   // continuation or {ib}-split sibling, then we record the entire
    1273             :   // |changeToAppend| value.  (We could use something like
    1274             :   // NS_RemoveSubsumedHints, but aimed at removing hints handled only for the
    1275             :   // current element instead.  However, we should probably just fix these rare
    1276             :   // cases as part of bug 918064.)
    1277         724 :   if (!NS_IsHintSubset(changeToAppend, mHintsHandledBySelf)) {
    1278          59 :     mHintsHandledBySelf |= changeToAppend;
    1279          59 :     if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) {
    1280          59 :       LOG_RESTYLE("appending change %s",
    1281             :                   RestyleManager::ChangeHintToString(changeToAppend).get());
    1282          59 :       mChangeList->AppendChange(mFrame, mContent, changeToAppend);
    1283             :     } else {
    1284           0 :       LOG_RESTYLE("ignoring ReconstructFrame change with no content");
    1285             :     }
    1286             :   } else {
    1287         665 :     LOG_RESTYLE("change has already been handled");
    1288             :   }
    1289         724 : }
    1290             : 
    1291             : class MOZ_RAII AutoSelectorArrayTruncater final
    1292             : {
    1293             : public:
    1294        1202 :   explicit AutoSelectorArrayTruncater(
    1295             :         nsTArray<nsCSSSelector*>& aSelectorsForDescendants)
    1296        1202 :     : mSelectorsForDescendants(aSelectorsForDescendants)
    1297        1202 :     , mOriginalLength(aSelectorsForDescendants.Length())
    1298             :   {
    1299        1202 :   }
    1300             : 
    1301        1202 :   ~AutoSelectorArrayTruncater()
    1302        1202 :   {
    1303        1202 :     mSelectorsForDescendants.TruncateLength(mOriginalLength);
    1304        1202 :   }
    1305             : 
    1306             : private:
    1307             :   nsTArray<nsCSSSelector*>& mSelectorsForDescendants;
    1308             :   size_t mOriginalLength;
    1309             : };
    1310             : 
    1311             : /**
    1312             :  * Called when we are stopping a restyle with eRestyle_SomeDescendants, to
    1313             :  * search for descendants that match any of the selectors in
    1314             :  * mSelectorsForDescendants.  If the element does match one of the selectors,
    1315             :  * we cause it to be restyled with eRestyle_Self.
    1316             :  *
    1317             :  * We traverse down the frame tree (and through the flattened content tree
    1318             :  * when we find undisplayed content) unless we find an element that (a) already
    1319             :  * has a pending restyle, or (b) does not have a pending restyle but does match
    1320             :  * one of the selectors in mSelectorsForDescendants.  For (a), we add the
    1321             :  * current mSelectorsForDescendants into the existing restyle data, and for (b)
    1322             :  * we add a new pending restyle with that array.  So in both cases, when we
    1323             :  * come to restyling this element back up in ProcessPendingRestyles, we will
    1324             :  * again find the eRestyle_SomeDescendants hint and its selectors array.
    1325             :  *
    1326             :  * This ensures that we don't visit descendant elements and check them
    1327             :  * against mSelectorsForDescendants more than once.
    1328             :  */
    1329             : void
    1330          38 : ElementRestyler::ConditionallyRestyleChildren()
    1331             : {
    1332          38 :   MOZ_ASSERT(mContent == mFrame->GetContent());
    1333             : 
    1334          38 :   if (!mContent->IsElement() || mSelectorsForDescendants.IsEmpty()) {
    1335           0 :     return;
    1336             :   }
    1337             : 
    1338          38 :   Element* element = mContent->AsElement();
    1339             : 
    1340          38 :   LOG_RESTYLE("traversing descendants of frame %s (with element %s) to "
    1341             :               "propagate eRestyle_SomeDescendants for these %d selectors:",
    1342             :               FrameTagToString(mFrame).get(),
    1343             :               ElementTagToString(element).get(),
    1344             :               int(mSelectorsForDescendants.Length()));
    1345          76 :   LOG_RESTYLE_INDENT();
    1346             : #ifdef RESTYLE_LOGGING
    1347         909 :   for (nsCSSSelector* sel : mSelectorsForDescendants) {
    1348         871 :     LOG_RESTYLE("%s", sel->RestrictedSelectorToString().get());
    1349             :   }
    1350             : #endif
    1351             : 
    1352          38 :   Element* restyleRoot = mRestyleTracker.FindClosestRestyleRoot(element);
    1353          38 :   ConditionallyRestyleChildren(mFrame, restyleRoot);
    1354             : }
    1355             : 
    1356             : void
    1357         200 : ElementRestyler::ConditionallyRestyleChildren(nsIFrame* aFrame,
    1358             :                                               Element* aRestyleRoot)
    1359             : {
    1360         200 :   MOZ_ASSERT(aFrame->GetContent());
    1361         200 :   MOZ_ASSERT(aFrame->GetContent()->IsElement());
    1362         200 :   MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
    1363             : 
    1364         200 :   ConditionallyRestyleUndisplayedDescendants(aFrame, aRestyleRoot);
    1365         200 :   ConditionallyRestyleContentChildren(aFrame, aRestyleRoot);
    1366         200 : }
    1367             : 
    1368             : // The structure of this method parallels RestyleContentChildren.
    1369             : // If you update this method, you probably want to update that one too.
    1370             : void
    1371         200 : ElementRestyler::ConditionallyRestyleContentChildren(nsIFrame* aFrame,
    1372             :                                                      Element* aRestyleRoot)
    1373             : {
    1374         200 :   MOZ_ASSERT(aFrame->GetContent());
    1375         200 :   MOZ_ASSERT(aFrame->GetContent()->IsElement());
    1376         200 :   MOZ_ASSERT(!aFrame->GetContent()->IsStyledByServo());
    1377             : 
    1378         200 :   if (aFrame->GetContent()->HasFlag(mRestyleTracker.RootBit())) {
    1379           0 :     aRestyleRoot = aFrame->GetContent()->AsElement();
    1380             :   }
    1381             : 
    1382         400 :   for (nsIFrame* f = aFrame; f;
    1383         200 :        f = GeckoRestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
    1384         400 :     nsIFrame::ChildListIterator lists(f);
    1385         454 :     for (; !lists.IsDone(); lists.Next()) {
    1386         314 :       for (nsIFrame* child : lists.CurrentList()) {
    1387             :         // Out-of-flows are reached through their placeholders.  Continuations
    1388             :         // and block-in-inline splits are reached through those chains.
    1389         374 :         if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    1390         187 :             !GetPrevContinuationWithSameStyle(child)) {
    1391             :           // only do frames that are in flow
    1392         187 :           if (child->IsPlaceholderFrame()) { // placeholder
    1393             :             // get out of flow frame and recur there
    1394             :             nsIFrame* outOfFlowFrame =
    1395           4 :               nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
    1396             : 
    1397             :             // |nsFrame::GetParentStyleContext| checks being out
    1398             :             // of flow so that this works correctly.
    1399           4 :             do {
    1400           4 :               if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) {
    1401           0 :                 continue;
    1402             :               }
    1403           4 :               if (!ConditionallyRestyle(outOfFlowFrame, aRestyleRoot)) {
    1404           4 :                 ConditionallyRestyleChildren(outOfFlowFrame, aRestyleRoot);
    1405             :               }
    1406           4 :             } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
    1407             :           } else {  // regular child frame
    1408         183 :             if (child != mResolvedChild) {
    1409         183 :               if (!ConditionallyRestyle(child, aRestyleRoot)) {
    1410         158 :                 ConditionallyRestyleChildren(child, aRestyleRoot);
    1411             :               }
    1412             :             }
    1413             :           }
    1414             :         }
    1415             :       }
    1416             :     }
    1417             :   }
    1418         200 : }
    1419             : 
    1420             : // The structure of this method parallels RestyleUndisplayedDescendants.
    1421             : // If you update this method, you probably want to update that one too.
    1422             : void
    1423         200 : ElementRestyler::ConditionallyRestyleUndisplayedDescendants(
    1424             :     nsIFrame* aFrame,
    1425             :     Element* aRestyleRoot)
    1426             : {
    1427             :   nsIContent* undisplayedParent;
    1428         200 :   if (MustCheckUndisplayedContent(aFrame, undisplayedParent)) {
    1429             :     DoConditionallyRestyleUndisplayedDescendants(undisplayedParent,
    1430         167 :                                                  aRestyleRoot);
    1431             :   }
    1432         200 : }
    1433             : 
    1434             : // The structure of this method parallels DoRestyleUndisplayedDescendants.
    1435             : // If you update this method, you probably want to update that one too.
    1436             : void
    1437         167 : ElementRestyler::DoConditionallyRestyleUndisplayedDescendants(
    1438             :     nsIContent* aParent,
    1439             :     Element* aRestyleRoot)
    1440             : {
    1441         167 :   nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
    1442         167 :   UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
    1443             :   ConditionallyRestyleUndisplayedNodes(nodes, aParent,
    1444         167 :                                        StyleDisplay::None, aRestyleRoot);
    1445         167 :   nodes = fc->GetAllDisplayContentsIn(aParent);
    1446             :   ConditionallyRestyleUndisplayedNodes(nodes, aParent,
    1447         167 :                                        StyleDisplay::Contents, aRestyleRoot);
    1448         167 : }
    1449             : 
    1450             : // The structure of this method parallels RestyleUndisplayedNodes.
    1451             : // If you update this method, you probably want to update that one too.
    1452             : void
    1453         334 : ElementRestyler::ConditionallyRestyleUndisplayedNodes(
    1454             :     UndisplayedNode* aUndisplayed,
    1455             :     nsIContent* aUndisplayedParent,
    1456             :     const StyleDisplay aDisplay,
    1457             :     Element* aRestyleRoot)
    1458             : {
    1459         334 :   MOZ_ASSERT(aDisplay == StyleDisplay::None ||
    1460             :              aDisplay == StyleDisplay::Contents);
    1461         334 :   if (!aUndisplayed) {
    1462         319 :     return;
    1463             :   }
    1464             : 
    1465          30 :   if (aUndisplayedParent &&
    1466          30 :       aUndisplayedParent->IsElement() &&
    1467          15 :       aUndisplayedParent->HasFlag(mRestyleTracker.RootBit())) {
    1468           0 :     MOZ_ASSERT(!aUndisplayedParent->IsStyledByServo());
    1469           0 :     aRestyleRoot = aUndisplayedParent->AsElement();
    1470             :   }
    1471             : 
    1472          71 :   for (UndisplayedNode* undisplayed = aUndisplayed; undisplayed;
    1473          56 :        undisplayed = undisplayed->getNext()) {
    1474             : 
    1475          56 :     if (!undisplayed->mContent->IsElement()) {
    1476           0 :       continue;
    1477             :     }
    1478             : 
    1479          56 :     Element* element = undisplayed->mContent->AsElement();
    1480             : 
    1481          56 :     if (!ConditionallyRestyle(element, aRestyleRoot)) {
    1482          51 :       if (aDisplay == StyleDisplay::None) {
    1483          51 :         ConditionallyRestyleContentDescendants(element, aRestyleRoot);
    1484             :       } else {  // StyleDisplay::Contents
    1485           0 :         DoConditionallyRestyleUndisplayedDescendants(element, aRestyleRoot);
    1486             :       }
    1487             :     }
    1488             :   }
    1489             : }
    1490             : 
    1491             : void
    1492          96 : ElementRestyler::ConditionallyRestyleContentDescendants(Element* aElement,
    1493             :                                                         Element* aRestyleRoot)
    1494             : {
    1495          96 :   MOZ_ASSERT(!aElement->IsStyledByServo());
    1496          96 :   if (aElement->HasFlag(mRestyleTracker.RootBit())) {
    1497           0 :     aRestyleRoot = aElement;
    1498             :   }
    1499             : 
    1500         192 :   FlattenedChildIterator it(aElement);
    1501         149 :   for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
    1502          53 :     if (n->IsElement()) {
    1503          49 :       Element* e = n->AsElement();
    1504          49 :       if (!ConditionallyRestyle(e, aRestyleRoot)) {
    1505          45 :         ConditionallyRestyleContentDescendants(e, aRestyleRoot);
    1506             :       }
    1507             :     }
    1508             :   }
    1509          96 : }
    1510             : 
    1511             : bool
    1512         187 : ElementRestyler::ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot)
    1513             : {
    1514         187 :   MOZ_ASSERT(aFrame->GetContent());
    1515             : 
    1516         187 :   if (!aFrame->GetContent()->IsElement()) {
    1517          16 :     return true;
    1518             :   }
    1519             : 
    1520         171 :   return ConditionallyRestyle(aFrame->GetContent()->AsElement(), aRestyleRoot);
    1521             : }
    1522             : 
    1523             : bool
    1524         276 : ElementRestyler::ConditionallyRestyle(Element* aElement, Element* aRestyleRoot)
    1525             : {
    1526         276 :   MOZ_ASSERT(!aElement->IsStyledByServo());
    1527         276 :   LOG_RESTYLE("considering element %s for eRestyle_SomeDescendants",
    1528             :               ElementTagToString(aElement).get());
    1529         552 :   LOG_RESTYLE_INDENT();
    1530             : 
    1531         276 :   if (aElement->HasFlag(mRestyleTracker.RootBit())) {
    1532           4 :     aRestyleRoot = aElement;
    1533             :   }
    1534             : 
    1535         276 :   if (mRestyleTracker.HasRestyleData(aElement)) {
    1536           4 :     nsRestyleHint rshint = eRestyle_SomeDescendants;
    1537           4 :     if (SelectorMatchesForRestyle(aElement)) {
    1538           0 :       LOG_RESTYLE("element has existing restyle data and matches a selector");
    1539           0 :       rshint |= eRestyle_Self;
    1540             :     } else {
    1541           4 :       LOG_RESTYLE("element has existing restyle data but doesn't match selectors");
    1542             :     }
    1543           8 :     RestyleHintData data;
    1544           4 :     data.mSelectorsForDescendants = mSelectorsForDescendants;
    1545           4 :     mRestyleTracker.AddPendingRestyle(aElement, rshint, nsChangeHint(0), &data,
    1546           8 :                                       Some(aRestyleRoot));
    1547           4 :     return true;
    1548             :   }
    1549             : 
    1550         272 :   if (SelectorMatchesForRestyle(aElement)) {
    1551          14 :     LOG_RESTYLE("element has no restyle data but matches a selector");
    1552          28 :     RestyleHintData data;
    1553          14 :     data.mSelectorsForDescendants = mSelectorsForDescendants;
    1554          14 :     mRestyleTracker.AddPendingRestyle(aElement,
    1555             :                                       eRestyle_Self | eRestyle_SomeDescendants,
    1556             :                                       nsChangeHint(0), &data,
    1557          28 :                                       Some(aRestyleRoot));
    1558          14 :     return true;
    1559             :   }
    1560             : 
    1561         258 :   return false;
    1562             : }
    1563             : 
    1564             : bool
    1565        1348 : ElementRestyler::MustCheckUndisplayedContent(nsIFrame* aFrame,
    1566             :                                              nsIContent*& aUndisplayedParent)
    1567             : {
    1568             :   // When the root element is display:none, we still construct *some*
    1569             :   // frames that have the root element as their mContent, down to the
    1570             :   // DocElementContainingBlock.
    1571        1348 :   if (aFrame->StyleContext()->GetPseudo()) {
    1572         295 :     aUndisplayedParent = nullptr;
    1573         295 :     return aFrame == mPresContext->FrameConstructor()->
    1574         295 :                        GetDocElementContainingBlock();
    1575             :   }
    1576             : 
    1577        1053 :   aUndisplayedParent = aFrame->GetContent();
    1578        1053 :   return !!aUndisplayedParent;
    1579             : }
    1580             : 
    1581             : /**
    1582             :  * Helper for MoveStyleContextsForChildren, below.  Appends the style
    1583             :  * contexts to be moved to mFrame's current (new) style context to
    1584             :  * aContextsToMove.
    1585             :  */
    1586             : bool
    1587           0 : ElementRestyler::MoveStyleContextsForContentChildren(
    1588             :     nsIFrame* aParent,
    1589             :     nsStyleContext* aOldContext,
    1590             :     nsTArray<nsStyleContext*>& aContextsToMove)
    1591             : {
    1592           0 :   nsIFrame::ChildListIterator lists(aParent);
    1593           0 :   for (; !lists.IsDone(); lists.Next()) {
    1594           0 :     for (nsIFrame* child : lists.CurrentList()) {
    1595             :       // Bail out if we have out-of-flow frames.
    1596             :       // FIXME: It might be safe to just continue here instead of bailing out.
    1597           0 :       if (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
    1598           0 :         return false;
    1599             :       }
    1600           0 :       if (GetPrevContinuationWithSameStyle(child)) {
    1601           0 :         continue;
    1602             :       }
    1603             :       // Bail out if we have placeholder frames.
    1604             :       // FIXME: It is probably safe to just continue here instead of bailing out.
    1605           0 :       if (child->IsPlaceholderFrame()) {
    1606           0 :         return false;
    1607             :       }
    1608           0 :       nsStyleContext* sc = child->StyleContext();
    1609           0 :       if (sc->GetParent() != aOldContext) {
    1610           0 :         return false;
    1611             :       }
    1612           0 :       LayoutFrameType type = child->Type();
    1613           0 :       if (type == LayoutFrameType::Letter || type == LayoutFrameType::Line) {
    1614           0 :         return false;
    1615             :       }
    1616           0 :       if (sc->HasChildThatUsesGrandancestorStyle()) {
    1617             :         // XXX Not sure if we need this?
    1618           0 :         return false;
    1619             :       }
    1620           0 :       nsIAtom* pseudoTag = sc->GetPseudo();
    1621           0 :       if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
    1622           0 :         return false;
    1623             :       }
    1624           0 :       aContextsToMove.AppendElement(sc);
    1625             :     }
    1626             :   }
    1627           0 :   return true;
    1628             : }
    1629             : 
    1630             : /**
    1631             :  * Traverses to child elements (through the current frame's same style
    1632             :  * continuations, just like RestyleChildren does) and moves any style context
    1633             :  * for those children to be parented under mFrame's current (new) style
    1634             :  * context.
    1635             :  *
    1636             :  * False is returned if it encounters any conditions on the child elements'
    1637             :  * frames and style contexts that means it is impossible to move a
    1638             :  * style context.  If false is returned, no style contexts will have been
    1639             :  * moved.
    1640             :  */
    1641             : bool
    1642           0 : ElementRestyler::MoveStyleContextsForChildren(nsStyleContext* aOldContext)
    1643             : {
    1644             :   // Bail out if there are undisplayed or display:contents children.
    1645             :   // FIXME: We could get this to work if we need to.
    1646             :   nsIContent* undisplayedParent;
    1647           0 :   if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
    1648           0 :     nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
    1649           0 :     if (fc->GetAllUndisplayedContentIn(undisplayedParent) ||
    1650           0 :         fc->GetAllDisplayContentsIn(undisplayedParent)) {
    1651           0 :       return false;
    1652             :     }
    1653             :   }
    1654             : 
    1655           0 :   nsTArray<nsStyleContext*> contextsToMove;
    1656             : 
    1657           0 :   MOZ_ASSERT(!MustReframeForBeforePseudo(),
    1658             :              "shouldn't need to reframe ::before as we would have had "
    1659             :              "eRestyle_Subtree and wouldn't get in here");
    1660             : 
    1661           0 :   DebugOnly<nsIFrame*> lastContinuation;
    1662           0 :   for (nsIFrame* f = mFrame; f;
    1663           0 :        f = GeckoRestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
    1664           0 :     lastContinuation = f;
    1665           0 :     if (!MoveStyleContextsForContentChildren(f, aOldContext, contextsToMove)) {
    1666           0 :       return false;
    1667             :     }
    1668             :   }
    1669             : 
    1670           0 :   MOZ_ASSERT(!MustReframeForAfterPseudo(lastContinuation),
    1671             :              "shouldn't need to reframe ::after as we would have had "
    1672             :              "eRestyle_Subtree and wouldn't get in here");
    1673             : 
    1674           0 :   nsStyleContext* newParent = mFrame->StyleContext();
    1675           0 :   for (nsStyleContext* child : contextsToMove) {
    1676             :     // We can have duplicate entries in contextsToMove, so only move
    1677             :     // each style context once.
    1678           0 :     if (child->GetParent() != newParent) {
    1679           0 :       child->MoveTo(newParent);
    1680             :     }
    1681             :   }
    1682             : 
    1683           0 :   return true;
    1684             : }
    1685             : 
    1686             : /**
    1687             :  * Recompute style for mFrame (which should not have a prev continuation
    1688             :  * with the same style), all of its next continuations with the same
    1689             :  * style, and all ib-split siblings of the same type (either block or
    1690             :  * inline, skipping the intermediates of the other type) and accumulate
    1691             :  * changes into mChangeList given that mHintsHandledByAncestors is already
    1692             :  * accumulated for an ancestor.
    1693             :  * mParentContent is the content node used to resolve the parent style
    1694             :  * context.  This means that, for pseudo-elements, it is the content
    1695             :  * that should be used for selector matching (rather than the fake
    1696             :  * content node attached to the frame).
    1697             :  */
    1698             : void
    1699        1202 : ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
    1700             : {
    1701             :   // It would be nice if we could make stronger assertions here; they
    1702             :   // would let us simplify the ?: expressions below setting |content|
    1703             :   // and |pseudoContent| in sensible ways as well as making what
    1704             :   // |content| and |pseudoContent| mean, and their relationship to
    1705             :   // |mFrame->GetContent()|, make more sense.  However, we can't,
    1706             :   // because of frame trees like the one in
    1707             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=472353#c14 .  Once we
    1708             :   // fix bug 242277 we should be able to make this make more sense.
    1709        1202 :   NS_ASSERTION(mFrame->GetContent() || !mParentContent ||
    1710             :                !mParentContent->GetParent(),
    1711             :                "frame must have content (unless at the top of the tree)");
    1712        1202 :   MOZ_ASSERT(mPresContext == mFrame->PresContext(), "pres contexts match");
    1713             : 
    1714        1202 :   NS_ASSERTION(!GetPrevContinuationWithSameStyle(mFrame),
    1715             :                "should not be trying to restyle this frame separately");
    1716             : 
    1717        1202 :   MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
    1718             :              "eRestyle_LaterSiblings must not be part of aRestyleHint");
    1719             : 
    1720        1202 :   AutoDisplayContentsAncestorPusher adcp(mTreeMatchContext, mPresContext,
    1721        3562 :       mFrame->GetContent() ? mFrame->GetContent()->GetParent() : nullptr);
    1722             : 
    1723        2360 :   AutoSelectorArrayTruncater asat(mSelectorsForDescendants);
    1724             : 
    1725             :   // List of descendant elements of mContent we know we will eventually need to
    1726             :   // restyle.  Before we return from this function, we call
    1727             :   // RestyleTracker::AddRestyleRootsIfAwaitingRestyle to ensure they get
    1728             :   // restyled in RestyleTracker::DoProcessRestyles.
    1729        2360 :   nsTArray<RefPtr<Element>> descendants;
    1730             : 
    1731        1202 :   nsRestyleHint hintToRestore = nsRestyleHint(0);
    1732        2360 :   RestyleHintData hintDataToRestore;
    1733        2362 :   if (mContent && mContent->IsElement() &&
    1734             :       // If we're resolving from the root of the frame tree (which
    1735             :       // we do when mDoRebuildAllStyleData), we need to avoid getting the
    1736             :       // root's restyle data until we get to its primary frame, since
    1737             :       // it's the primary frame that has the styles for the root element
    1738             :       // (rather than the ancestors of the primary frame whose mContent
    1739             :       // is the root node but which have different styles).  If we use
    1740             :       // up the hint for one of the ancestors that we hit first, then
    1741             :       // we'll fail to do the restyling we need to do.
    1742             :       // Likewise, if we're restyling something with two nested frames,
    1743             :       // and we post a restyle from the transition manager while
    1744             :       // computing style for the outer frame (to be computed after the
    1745             :       // descendants have been resolved), we don't want to consume it
    1746             :       // for the inner frame.
    1747        1160 :       mContent->GetPrimaryFrame() == mFrame) {
    1748         973 :     mContent->OwnerDoc()->FlushPendingLinkUpdates();
    1749        1946 :     nsAutoPtr<RestyleTracker::RestyleData> restyleData;
    1750         973 :     if (mRestyleTracker.GetRestyleData(mContent->AsElement(), restyleData)) {
    1751             :       nsChangeHint changeToAppend =
    1752          35 :         NS_RemoveSubsumedHints(restyleData->mChangeHint,
    1753          70 :                                mHintsHandledByAncestors);
    1754             :       // See the comment in CaptureChange about why we use NS_IsHintSubset here.
    1755          35 :       if (!NS_IsHintSubset(changeToAppend, mHintsHandledBySelf)) {
    1756          23 :         mHintsHandledBySelf |= changeToAppend;
    1757          23 :         mChangeList->AppendChange(mFrame, mContent, changeToAppend);
    1758             :       }
    1759          35 :       mSelectorsForDescendants.AppendElements(
    1760          70 :           restyleData->mRestyleHintData.mSelectorsForDescendants);
    1761          35 :       hintToRestore = restyleData->mRestyleHint;
    1762          35 :       hintDataToRestore = Move(restyleData->mRestyleHintData);
    1763          35 :       aRestyleHint = nsRestyleHint(aRestyleHint | restyleData->mRestyleHint);
    1764          35 :       descendants.SwapElements(restyleData->mDescendants);
    1765             :     }
    1766             :   }
    1767             : 
    1768             :   // If we are restyling this frame with eRestyle_Self or weaker hints,
    1769             :   // we restyle children with nsRestyleHint(0).  But we pass the
    1770             :   // eRestyle_ForceDescendants flag down too.
    1771             :   nsRestyleHint childRestyleHint =
    1772        1202 :     nsRestyleHint(aRestyleHint & (eRestyle_SomeDescendants |
    1773             :                                   eRestyle_Subtree |
    1774        1202 :                                   eRestyle_ForceDescendants));
    1775             : 
    1776        2360 :   RefPtr<GeckoStyleContext> oldContext = mFrame->StyleContext()->AsGecko();
    1777             : 
    1778        2360 :   nsTArray<SwapInstruction> swaps;
    1779             : 
    1780             :   // TEMPORARY (until bug 918064):  Call RestyleSelf for each
    1781             :   // continuation or block-in-inline sibling.
    1782             : 
    1783             :   // We must make a single decision on how to process this frame and
    1784             :   // its descendants, yet RestyleSelf might return different RestyleResult
    1785             :   // values for the different same-style continuations.  |result| is our
    1786             :   // overall decision.
    1787        1202 :   RestyleResult result = RestyleResult::eNone;
    1788        1202 :   uint32_t swappedStructs = 0;
    1789             : 
    1790        1202 :   nsRestyleHint thisRestyleHint = aRestyleHint;
    1791             : 
    1792        1202 :   bool haveMoreContinuations = false;
    1793        2404 :   for (nsIFrame* f = mFrame; f; ) {
    1794             :     RestyleResult thisResult =
    1795        1202 :       RestyleSelf(f, thisRestyleHint, &swappedStructs, swaps);
    1796             : 
    1797        1202 :     if (thisResult != RestyleResult::eStop) {
    1798             :       // Calls to RestyleSelf for later same-style continuations must not
    1799             :       // return RestyleResult::eStop, so pass eRestyle_Force in to them.
    1800        1158 :       thisRestyleHint = nsRestyleHint(thisRestyleHint | eRestyle_Force);
    1801             : 
    1802        1158 :       if (result == RestyleResult::eStop) {
    1803             :         // We received RestyleResult::eStop for earlier same-style
    1804             :         // continuations, and RestyleResult::eStopWithStyleChange or
    1805             :         // RestyleResult::eContinue(AndForceDescendants) for this one; go
    1806             :         // back and force-restyle the earlier continuations.
    1807           0 :         result = thisResult;
    1808           0 :         f = mFrame;
    1809           0 :         continue;
    1810             :       }
    1811             :     }
    1812             : 
    1813        1202 :     if (thisResult > result) {
    1814             :       // We take the highest RestyleResult value when working out what to do
    1815             :       // with this frame and its descendants.  Higher RestyleResult values
    1816             :       // represent a superset of the work done by lower values.
    1817        1202 :       result = thisResult;
    1818             :     }
    1819             : 
    1820             :     f = GeckoRestyleManager::GetNextContinuationWithSameStyle(
    1821        1202 :             f, oldContext, &haveMoreContinuations);
    1822             :   }
    1823             : 
    1824             :   // Some changes to animations don't affect the computed style and yet still
    1825             :   // require the layer to be updated. For example, pausing an animation via
    1826             :   // the Web Animations API won't affect an element's style but still
    1827             :   // requires to update the animation on the layer.
    1828             :   //
    1829             :   // Although we only expect this code path to be called when computed style
    1830             :   // is not changing, we can sometimes reach this at the end of a transition
    1831             :   // when the animated style is being removed. Since
    1832             :   // AddLayerChangesForAnimation checks if mFrame has a transform style or not,
    1833             :   // we need to call it *after* calling RestyleSelf to ensure the animated
    1834             :   // transform has been removed first.
    1835        1202 :   RestyleManager::AddLayerChangesForAnimation(mFrame, mContent, *mChangeList);
    1836             : 
    1837        1202 :   if (haveMoreContinuations && hintToRestore) {
    1838             :     // If we have more continuations with different style (e.g., because
    1839             :     // we're inside a ::first-letter or ::first-line), put the restyle
    1840             :     // hint back.
    1841           0 :     mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
    1842           0 :                                              hintToRestore, nsChangeHint(0));
    1843             :   }
    1844             : 
    1845        1202 :   if (result == RestyleResult::eStop) {
    1846          44 :     MOZ_ASSERT(mFrame->StyleContext() == oldContext,
    1847             :                "frame should have been left with its old style context");
    1848             : 
    1849             :     nsIFrame* unused;
    1850          44 :     nsStyleContext* newParent = mFrame->GetParentStyleContext(&unused);
    1851          44 :     if (oldContext->GetParent() != newParent) {
    1852             :       // If we received RestyleResult::eStop, then the old style context was
    1853             :       // left on mFrame.  Since we ended up restyling our parent, change
    1854             :       // this old style context to point to its new parent.
    1855          37 :       LOG_RESTYLE("moving style context %p from old parent %p to new parent %p",
    1856             :                   oldContext.get(), oldContext->GetParent(), newParent);
    1857             :       // We keep strong references to the new parent around until the end
    1858             :       // of the restyle, in case:
    1859             :       //   (a) we swapped structs between the old and new parent,
    1860             :       //   (b) some descendants of the old parent are not getting restyled
    1861             :       //       (which is the reason for the existence of
    1862             :       //       ClearCachedInheritedStyleDataOnDescendants),
    1863             :       //   (c) something under ProcessPendingRestyles (which notably is called
    1864             :       //       *before* ClearCachedInheritedStyleDataOnDescendants is called
    1865             :       //       on the old context) causes the new parent to be destroyed, thus
    1866             :       //       destroying its owned structs, and
    1867             :       //   (d) something under ProcessPendingRestyles then wants to use of those
    1868             :       //       now destroyed structs (through the old parent's descendants).
    1869          37 :       mSwappedStructOwners.AppendElement(newParent);
    1870          37 :       oldContext->MoveTo(newParent);
    1871             :     }
    1872             : 
    1873             :     // Send the accessibility notifications that RestyleChildren otherwise
    1874             :     // would have sent.
    1875          44 :     if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    1876          44 :       InitializeAccessibilityNotifications(mFrame->StyleContext());
    1877          44 :       SendAccessibilityNotifications();
    1878             :     }
    1879             : 
    1880          44 :     mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
    1881          44 :     if (aRestyleHint & eRestyle_SomeDescendants) {
    1882          38 :       ConditionallyRestyleChildren();
    1883             :     }
    1884          44 :     return;
    1885             :   }
    1886             : 
    1887        1158 :   if (result == RestyleResult::eStopWithStyleChange &&
    1888           0 :       !(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    1889           0 :     MOZ_ASSERT(mFrame->StyleContext() != oldContext,
    1890             :                "RestyleResult::eStopWithStyleChange should only be returned "
    1891             :                "if we got a new style context or we will reconstruct");
    1892           0 :     MOZ_ASSERT(swappedStructs == 0,
    1893             :                "should have ensured we didn't swap structs when "
    1894             :                "returning RestyleResult::eStopWithStyleChange");
    1895             : 
    1896             :     // We need to ensure that all of the frames that inherit their style
    1897             :     // from oldContext are able to be moved across to newContext.
    1898             :     // MoveStyleContextsForChildren will check for certain conditions
    1899             :     // to ensure it is safe to move all of the relevant child style
    1900             :     // contexts to newContext.  If these conditions fail, it will
    1901             :     // return false, and we'll have to continue restyling.
    1902           0 :     const bool canStop = MoveStyleContextsForChildren(oldContext);
    1903             : 
    1904           0 :     if (canStop) {
    1905             :       // Send the accessibility notifications that RestyleChildren otherwise
    1906             :       // would have sent.
    1907           0 :       if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    1908           0 :         InitializeAccessibilityNotifications(mFrame->StyleContext());
    1909           0 :         SendAccessibilityNotifications();
    1910             :       }
    1911             : 
    1912           0 :       mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
    1913           0 :       if (aRestyleHint & eRestyle_SomeDescendants) {
    1914           0 :         ConditionallyRestyleChildren();
    1915             :       }
    1916           0 :       return;
    1917             :     }
    1918             : 
    1919             :     // Turns out we couldn't stop restyling here.  Process the struct
    1920             :     // swaps that RestyleSelf would've done had we not returned
    1921             :     // RestyleResult::eStopWithStyleChange.
    1922           0 :     for (SwapInstruction& swap : swaps) {
    1923           0 :       LOG_RESTYLE("swapping style structs between %p and %p",
    1924             :                   swap.mOldContext.get(), swap.mNewContext.get());
    1925           0 :       swap.mOldContext->AsGecko()->SwapStyleData(swap.mNewContext->AsGecko(), swap.mStructsToSwap);
    1926           0 :       swappedStructs |= swap.mStructsToSwap;
    1927             :     }
    1928           0 :     swaps.Clear();
    1929             :   }
    1930             : 
    1931        1158 :   if (!swappedStructs) {
    1932             :     // If we swapped any structs from the old context, then we need to keep
    1933             :     // it alive until after the RestyleChildren call so that we can fix up
    1934             :     // its descendants' cached structs.
    1935         779 :     oldContext = nullptr;
    1936             :   }
    1937             : 
    1938        1158 :   if (result == RestyleResult::eContinueAndForceDescendants) {
    1939             :     childRestyleHint =
    1940         293 :       nsRestyleHint(childRestyleHint | eRestyle_ForceDescendants);
    1941             :   }
    1942             : 
    1943             :   // No need to do this if we're planning to reframe already.
    1944             :   // It's also important to check mHintsHandledBySelf since we use
    1945             :   // mFrame->StyleContext(), which is out of date if mHintsHandledBySelf
    1946             :   // has a ReconstructFrame hint.  Using an out of date style
    1947             :   // context could trigger assertions about mismatched rule trees.
    1948        1158 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    1949        1148 :     RestyleChildren(childRestyleHint);
    1950             :   }
    1951             : 
    1952        1158 :   if (oldContext && !oldContext->HasSingleReference()) {
    1953             :     // If we swapped some structs out of oldContext in the RestyleSelf call
    1954             :     // and after the RestyleChildren call we still have other strong references
    1955             :     // to it, we need to make ensure its descendants don't cache any of the
    1956             :     // structs that were swapped out.
    1957             :     //
    1958             :     // Much of the time we will not get in here; we do for example when the
    1959             :     // style context is shared with a later IB split sibling (which we won't
    1960             :     // restyle until a bit later) or if other code is holding a strong reference
    1961             :     // to the style context (as is done by nsTransformedTextRun objects, which
    1962             :     // can be referenced by a text frame's mTextRun longer than the frame's
    1963             :     // mStyleContext).
    1964             :     //
    1965             :     // Also, we don't want this style context to get any more uses by being
    1966             :     // returned from nsStyleContext::FindChildWithRules, so we add the
    1967             :     // NS_STYLE_INELIGIBLE_FOR_SHARING bit to it.
    1968          33 :     oldContext->SetIneligibleForSharing();
    1969             : 
    1970          33 :     ContextToClear* toClear = mContextsToClear.AppendElement();
    1971          33 :     toClear->mStyleContext = Move(oldContext);
    1972          33 :     toClear->mStructs = swappedStructs;
    1973             :   }
    1974             : 
    1975        1158 :   mRestyleTracker.AddRestyleRootsIfAwaitingRestyle(descendants);
    1976             : }
    1977             : 
    1978             : /**
    1979             :  * Depending on the details of the frame we are restyling or its old style
    1980             :  * context, we may or may not be able to stop restyling after this frame if
    1981             :  * we find we had no style changes.
    1982             :  *
    1983             :  * This function returns RestyleResult::eStop if it does not find any
    1984             :  * conditions that would preclude stopping restyling, and
    1985             :  * RestyleResult::eContinue if it does.
    1986             :  */
    1987             : void
    1988        1202 : ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf,
    1989             :                                                RestyleResult& aRestyleResult,
    1990             :                                                bool& aCanStopWithStyleChange)
    1991             : {
    1992             :   // We can't handle situations where the primary style context of a frame
    1993             :   // has not had any style data changes, but its additional style contexts
    1994             :   // have, so we don't considering stopping if this frame has any additional
    1995             :   // style contexts.
    1996        1202 :   if (aSelf->GetAdditionalStyleContext(0)) {
    1997           0 :     LOG_RESTYLE_CONTINUE("there are additional style contexts");
    1998           0 :     aRestyleResult = RestyleResult::eContinue;
    1999           0 :     aCanStopWithStyleChange = false;
    2000           0 :     return;
    2001             :   }
    2002             : 
    2003             :   // Each NAC element inherits from the first non-NAC ancestor, so child
    2004             :   // NAC may inherit from our parent instead of us. That means we can't
    2005             :   // cull traversal if our style context didn't change.
    2006        1202 :   if (aSelf->GetContent() && aSelf->GetContent()->IsNativeAnonymous()) {
    2007          90 :     LOG_RESTYLE_CONTINUE("native anonymous content");
    2008          90 :     aRestyleResult = RestyleResult::eContinue;
    2009          90 :     aCanStopWithStyleChange = false;
    2010          90 :     return;
    2011             :   }
    2012             : 
    2013             :   // Style changes might have moved children between the two nsLetterFrames
    2014             :   // (the one matching ::first-letter and the one containing the rest of the
    2015             :   // content).  Continue restyling to the children of the nsLetterFrame so
    2016             :   // that they get the correct style context parent.  Similarly for
    2017             :   // nsLineFrames.
    2018        1112 :   LayoutFrameType type = aSelf->Type();
    2019             : 
    2020        1112 :   if (type == LayoutFrameType::Letter) {
    2021           0 :     LOG_RESTYLE_CONTINUE("frame is a letter frame");
    2022           0 :     aRestyleResult = RestyleResult::eContinue;
    2023           0 :     aCanStopWithStyleChange = false;
    2024           0 :     return;
    2025             :   }
    2026             : 
    2027        1112 :   if (type == LayoutFrameType::Line) {
    2028           0 :     LOG_RESTYLE_CONTINUE("frame is a line frame");
    2029           0 :     aRestyleResult = RestyleResult::eContinue;
    2030           0 :     aCanStopWithStyleChange = false;
    2031           0 :     return;
    2032             :   }
    2033             : 
    2034             :   // Some style computations depend not on the parent's style, but a grandparent
    2035             :   // or one the grandparent's ancestors.  An example is an explicit 'inherit'
    2036             :   // value for align-self, where if the parent frame's value for the property is
    2037             :   // 'auto' we end up inheriting the computed value from the grandparent.  We
    2038             :   // can't stop the restyling process on this frame (the one with 'auto', in
    2039             :   // this example), as the grandparent's computed value might have changed
    2040             :   // and we need to recompute the child's 'inherit' to that new value.
    2041        1112 :   nsStyleContext* oldContext = aSelf->StyleContext();
    2042        1112 :   if (oldContext->HasChildThatUsesGrandancestorStyle()) {
    2043           0 :     LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
    2044           0 :     aRestyleResult = RestyleResult::eContinue;
    2045           0 :     aCanStopWithStyleChange = false;
    2046           0 :     return;
    2047             :   }
    2048             : 
    2049             :   // We ignore all situations that involve :visited style.
    2050        1112 :   if (oldContext->GetStyleIfVisited()) {
    2051           0 :     LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
    2052           0 :     aRestyleResult = RestyleResult::eContinue;
    2053           0 :     aCanStopWithStyleChange = false;
    2054           0 :     return;
    2055             :   }
    2056             : 
    2057        1112 :   nsStyleContext* parentContext = oldContext->GetParent();
    2058        1112 :   if (parentContext && parentContext->GetStyleIfVisited()) {
    2059           0 :     LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
    2060           0 :     aRestyleResult = RestyleResult::eContinue;
    2061           0 :     aCanStopWithStyleChange = false;
    2062           0 :     return;
    2063             :   }
    2064             : 
    2065             :   // We also ignore frames for pseudos, as their style contexts have
    2066             :   // inheritance structures that do not match the frame inheritance
    2067             :   // structure.  To avoid enumerating and checking all of the cases
    2068             :   // where we have this kind of inheritance, we keep restyling past
    2069             :   // pseudos.
    2070        1112 :   nsIAtom* pseudoTag = oldContext->GetPseudo();
    2071        1112 :   if (pseudoTag && !nsCSSAnonBoxes::IsNonElement(pseudoTag)) {
    2072          53 :     LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
    2073          53 :     aRestyleResult = RestyleResult::eContinue;
    2074          53 :     aCanStopWithStyleChange = false;
    2075          53 :     return;
    2076             :   }
    2077             : 
    2078        1059 :   nsIFrame* parent = mFrame->GetParent();
    2079             : 
    2080        1059 :   if (parent) {
    2081             :     // Also if the parent has a pseudo, as this frame's style context will
    2082             :     // be inheriting from a grandparent frame's style context (or a further
    2083             :     // ancestor).
    2084        1059 :     nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
    2085        1224 :     if (parentPseudoTag &&
    2086         165 :         parentPseudoTag != nsCSSAnonBoxes::firstLetterContinuation) {
    2087         165 :       MOZ_ASSERT(parentPseudoTag != nsCSSAnonBoxes::mozText,
    2088             :                  "Style of text node should not be parent of anything");
    2089         165 :       MOZ_ASSERT(parentPseudoTag != nsCSSAnonBoxes::oofPlaceholder,
    2090             :                  "Style of placeholder should not be parent of anything");
    2091         165 :       LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
    2092         165 :       aRestyleResult = RestyleResult::eContinue;
    2093             :       // Parent style context pseudo-ness doesn't affect whether we can
    2094             :       // return RestyleResult::eStopWithStyleChange.
    2095             :       //
    2096             :       // If we had later conditions to check in this function, we would
    2097             :       // continue to check them, in case we set aCanStopWithStyleChange to
    2098             :       // false.
    2099             :     }
    2100             :   }
    2101             : }
    2102             : 
    2103             : void
    2104         724 : ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
    2105             :                                                     nsStyleContext* aNewContext,
    2106             :                                                     RestyleResult& aRestyleResult,
    2107             :                                                     bool& aCanStopWithStyleChange)
    2108             : {
    2109             :   // If we've already determined that we must continue styling, we don't
    2110             :   // need to check anything.
    2111         724 :   if (aRestyleResult == RestyleResult::eContinue && !aCanStopWithStyleChange) {
    2112         616 :     return;
    2113             :   }
    2114             : 
    2115             :   // Keep restyling if the new style context has any style-if-visted style, so
    2116             :   // that we can avoid the style context tree surgery having to deal to deal
    2117             :   // with visited styles.
    2118         108 :   if (aNewContext->GetStyleIfVisited()) {
    2119           0 :     LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
    2120           0 :     aRestyleResult = RestyleResult::eContinue;
    2121           0 :     aCanStopWithStyleChange = false;
    2122           0 :     return;
    2123             :   }
    2124             : 
    2125             :   // If link-related information has changed, or the pseudo for the frame has
    2126             :   // changed, or the new style context points to a different rule node, we can't
    2127             :   // leave the old style context on the frame.
    2128         108 :   nsStyleContext* oldContext = aSelf->StyleContext();
    2129         324 :   if (oldContext->IsLinkContext() != aNewContext->IsLinkContext() ||
    2130         216 :       oldContext->RelevantLinkVisited() != aNewContext->RelevantLinkVisited() ||
    2131         324 :       oldContext->GetPseudo() != aNewContext->GetPseudo() ||
    2132         108 :       oldContext->GetPseudoType() != aNewContext->GetPseudoType()) {
    2133           0 :     LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
    2134             :                          "visited/pseudo");
    2135           0 :     aRestyleResult = RestyleResult::eContinue;
    2136           0 :     aCanStopWithStyleChange = false;
    2137           0 :     return;
    2138             :   }
    2139             : 
    2140         108 :   if (oldContext->RuleNode() != aNewContext->RuleNode()) {
    2141          30 :     LOG_RESTYLE_CONTINUE("the old and new style contexts have different "
    2142             :                          "rulenodes");
    2143          30 :     aRestyleResult = RestyleResult::eContinue;
    2144             :     // Continue to check other conditions if aCanStopWithStyleChange might
    2145             :     // still need to be set to false.
    2146          30 :     if (!aCanStopWithStyleChange) {
    2147           1 :       return;
    2148             :     }
    2149             :   }
    2150             : 
    2151             :   // If the old and new style contexts differ in their
    2152             :   // NS_STYLE_HAS_TEXT_DECORATION_LINES or NS_STYLE_HAS_PSEUDO_ELEMENT_DATA
    2153             :   // bits, then we must keep restyling so that those new bit values are
    2154             :   // propagated.
    2155         214 :   if (oldContext->HasTextDecorationLines() !=
    2156         107 :         aNewContext->HasTextDecorationLines()) {
    2157           0 :     LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
    2158             :                          " and new style contexts");
    2159           0 :     aRestyleResult = RestyleResult::eContinue;
    2160           0 :     aCanStopWithStyleChange = false;
    2161           0 :     return;
    2162             :   }
    2163             : 
    2164         214 :   if (oldContext->HasPseudoElementData() !=
    2165         107 :         aNewContext->HasPseudoElementData()) {
    2166           0 :     LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
    2167             :                          " and new style contexts");
    2168           0 :     aRestyleResult = RestyleResult::eContinue;
    2169           0 :     aCanStopWithStyleChange = false;
    2170           0 :     return;
    2171             :   }
    2172             : 
    2173         214 :   if (oldContext->ShouldSuppressLineBreak() !=
    2174         107 :         aNewContext->ShouldSuppressLineBreak()) {
    2175           0 :     LOG_RESTYLE_CONTINUE("NS_STYLE_SUPPRESS_LINEBREAK differs"
    2176             :                          "between old and new style contexts");
    2177           0 :     aRestyleResult = RestyleResult::eContinue;
    2178           0 :     aCanStopWithStyleChange = false;
    2179           0 :     return;
    2180             :   }
    2181             : 
    2182         214 :   if (oldContext->IsInDisplayNoneSubtree() !=
    2183         107 :         aNewContext->IsInDisplayNoneSubtree()) {
    2184           1 :     LOG_RESTYLE_CONTINUE("NS_STYLE_IN_DISPLAY_NONE_SUBTREE differs between old"
    2185             :                          " and new style contexts");
    2186           1 :     aRestyleResult = RestyleResult::eContinue;
    2187           1 :     aCanStopWithStyleChange = false;
    2188           1 :     return;
    2189             :   }
    2190             : 
    2191         106 :   if (oldContext->IsTextCombined() != aNewContext->IsTextCombined()) {
    2192           0 :     LOG_RESTYLE_CONTINUE("NS_STYLE_IS_TEXT_COMBINED differs between "
    2193             :                          "old and new style contexts");
    2194           0 :     aRestyleResult = RestyleResult::eContinue;
    2195           0 :     aCanStopWithStyleChange = false;
    2196           0 :     return;
    2197             :   }
    2198             : }
    2199             : 
    2200             : bool
    2201         603 : ElementRestyler::SelectorMatchesForRestyle(Element* aElement)
    2202             : {
    2203         603 :   if (!aElement) {
    2204          14 :     return false;
    2205             :   }
    2206       11863 :   for (nsCSSSelector* selector : mSelectorsForDescendants) {
    2207       11332 :     if (nsCSSRuleProcessor::RestrictedSelectorMatches(aElement, selector,
    2208             :                                                       mTreeMatchContext)) {
    2209          58 :       return true;
    2210             :     }
    2211             :   }
    2212         531 :   return false;
    2213             : }
    2214             : 
    2215             : bool
    2216        1706 : ElementRestyler::MustRestyleSelf(nsRestyleHint aRestyleHint,
    2217             :                                  Element* aElement)
    2218             : {
    2219        3456 :   return (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) ||
    2220         710 :          ((aRestyleHint & eRestyle_SomeDescendants) &&
    2221        2033 :           SelectorMatchesForRestyle(aElement));
    2222             : }
    2223             : 
    2224             : bool
    2225         339 : ElementRestyler::CanReparentStyleContext(nsRestyleHint aRestyleHint)
    2226             : {
    2227             :   // If we had any restyle hints other than the ones listed below,
    2228             :   // which don't control whether the current frame/element needs
    2229             :   // a new style context by looking up a new rule node, or if
    2230             :   // we are reconstructing the entire rule tree, then we can't
    2231             :   // use ReparentStyleContext.
    2232         339 :   return !(aRestyleHint & ~(eRestyle_Force |
    2233             :                             eRestyle_ForceDescendants |
    2234         659 :                             eRestyle_SomeDescendants)) &&
    2235         659 :          !StyleSet()->IsInRuleTreeReconstruct();
    2236             : }
    2237             : 
    2238             : // Returns true iff any rule node that is an ancestor-or-self of the
    2239             : // two specified rule nodes, but which is not an ancestor of both,
    2240             : // has any inherited style data.  If false is returned, then we know
    2241             : // that a change from one rule node to the other must not result in
    2242             : // any change in inherited style data.
    2243             : static bool
    2244         297 : CommonInheritedStyleData(nsRuleNode* aRuleNode1, nsRuleNode* aRuleNode2)
    2245             : {
    2246         297 :   if (aRuleNode1 == aRuleNode2) {
    2247         166 :     return true;
    2248             :   }
    2249             : 
    2250         131 :   nsRuleNode* n1 = aRuleNode1->GetParent();
    2251         131 :   nsRuleNode* n2 = aRuleNode2->GetParent();
    2252             : 
    2253         131 :   if (n1 == n2) {
    2254             :     // aRuleNode1 and aRuleNode2 sharing a parent is a common case, e.g.
    2255             :     // when modifying a style="" attribute.  (We must null check GetRule()'s
    2256             :     // result since although we know the two parents are the same, it might
    2257             :     // be null, as in the case of the two rule nodes being roots of two
    2258             :     // different rule trees.)
    2259           2 :     if (aRuleNode1->GetRule() &&
    2260           0 :         aRuleNode1->GetRule()->MightMapInheritedStyleData()) {
    2261           0 :       return false;
    2262             :     }
    2263           2 :     if (aRuleNode2->GetRule() &&
    2264           0 :         aRuleNode2->GetRule()->MightMapInheritedStyleData()) {
    2265           0 :       return false;
    2266             :     }
    2267           2 :     return true;
    2268             :   }
    2269             : 
    2270             :   // Compute the depths of aRuleNode1 and aRuleNode2.
    2271         129 :   int d1 = 0, d2 = 0;
    2272        1195 :   while (n1) {
    2273         533 :     ++d1;
    2274         533 :     n1 = n1->GetParent();
    2275             :   }
    2276         538 :   while (n2) {
    2277         538 :     ++d2;
    2278         538 :     n2 = n2->GetParent();
    2279             :   }
    2280             : 
    2281             :   // Make aRuleNode1 be the deeper node.
    2282         129 :   if (d2 > d1) {
    2283          14 :     std::swap(d1, d2);
    2284          14 :     std::swap(aRuleNode1, aRuleNode2);
    2285             :   }
    2286             : 
    2287             :   // Check all of the rule nodes in the deeper branch until we reach
    2288             :   // the same depth as the shallower branch.
    2289         129 :   n1 = aRuleNode1;
    2290         129 :   n2 = aRuleNode2;
    2291         153 :   while (d1 > d2) {
    2292          28 :     nsIStyleRule* rule = n1->GetRule();
    2293          28 :     MOZ_ASSERT(rule, "non-root rule node should have a rule");
    2294          28 :     if (rule->MightMapInheritedStyleData()) {
    2295          16 :       return false;
    2296             :     }
    2297          12 :     n1 = n1->GetParent();
    2298          12 :     --d1;
    2299             :   }
    2300             : 
    2301             :   // Check both branches simultaneously until we reach a common ancestor.
    2302         106 :   while (n1 != n2) {
    2303         203 :     MOZ_ASSERT(n1);
    2304         203 :     MOZ_ASSERT(n2);
    2305             :     // As above, we must null check GetRule()'s result since we won't find
    2306             :     // a common ancestor if the two rule nodes come from different rule trees,
    2307             :     // and thus we might reach the root (which has a null rule).
    2308         203 :     if (n1->GetRule() && n1->GetRule()->MightMapInheritedStyleData()) {
    2309          97 :       return false;
    2310             :     }
    2311         106 :     if (n2->GetRule() && n2->GetRule()->MightMapInheritedStyleData()) {
    2312           0 :       return false;
    2313             :     }
    2314         106 :     n1 = n1->GetParent();
    2315         106 :     n2 = n2->GetParent();
    2316             :   }
    2317             : 
    2318          16 :   return true;
    2319             : }
    2320             : 
    2321             : ElementRestyler::RestyleResult
    2322        1202 : ElementRestyler::RestyleSelf(nsIFrame* aSelf,
    2323             :                              nsRestyleHint aRestyleHint,
    2324             :                              uint32_t* aSwappedStructs,
    2325             :                              nsTArray<SwapInstruction>& aSwaps)
    2326             : {
    2327        1202 :   MOZ_ASSERT(!(aRestyleHint & eRestyle_LaterSiblings),
    2328             :              "eRestyle_LaterSiblings must not be part of aRestyleHint");
    2329             : 
    2330             :   // XXXldb get new context from prev-in-flow if possible, to avoid
    2331             :   // duplication.  (Or should we just let |GetContext| handle that?)
    2332             :   // Getting the hint would be nice too, but that's harder.
    2333             : 
    2334             :   // XXXbryner we may be able to avoid some of the refcounting goop here.
    2335             :   // We do need a reference to oldContext for the lifetime of this function, and it's possible
    2336             :   // that the frame has the last reference to it, so AddRef it here.
    2337             : 
    2338        1202 :   LOG_RESTYLE("RestyleSelf %s, aRestyleHint = %s",
    2339             :               FrameTagToString(aSelf).get(),
    2340             :               RestyleManager::RestyleHintToString(aRestyleHint).get());
    2341        2404 :   LOG_RESTYLE_INDENT();
    2342             : 
    2343             :   // Initially assume that it is safe to stop restyling.
    2344             :   //
    2345             :   // Throughout most of this function, we update the following two variables
    2346             :   // independently.  |result| is set to RestyleResult::eContinue when we
    2347             :   // detect a condition that would not allow us to return RestyleResult::eStop.
    2348             :   // |canStopWithStyleChange| is set to false when we detect a condition
    2349             :   // that would not allow us to return RestyleResult::eStopWithStyleChange.
    2350             :   //
    2351             :   // Towards the end of this function, we reconcile these two variables --
    2352             :   // if |canStopWithStyleChange| is true, we convert |result| into
    2353             :   // RestyleResult::eStopWithStyleChange.
    2354        1202 :   RestyleResult result = RestyleResult::eStop;
    2355        1202 :   bool canStopWithStyleChange = true;
    2356             : 
    2357        1202 :   if (aRestyleHint & ~eRestyle_SomeDescendants) {
    2358             :     // If we are doing any restyling of the current element, or if we're
    2359             :     // forced to continue, we must.
    2360         982 :     result = RestyleResult::eContinue;
    2361             : 
    2362             :     // If we have to restyle children, we can't return
    2363             :     // RestyleResult::eStopWithStyleChange.
    2364         982 :     if (aRestyleHint & (eRestyle_Subtree | eRestyle_Force |
    2365             :                         eRestyle_ForceDescendants)) {
    2366         931 :       canStopWithStyleChange = false;
    2367             :     }
    2368             :   }
    2369             : 
    2370             :   // We only consider returning RestyleResult::eStopWithStyleChange if this
    2371             :   // is the root of the restyle.  (Otherwise, we would need to track the
    2372             :   // style changes of the ancestors we just restyled.)
    2373        1202 :   if (!mIsRootOfRestyle) {
    2374        1141 :     canStopWithStyleChange = false;
    2375             :   }
    2376             : 
    2377             :   // Look at the frame and its current style context for conditions
    2378             :   // that would change our RestyleResult.
    2379        1202 :   ComputeRestyleResultFromFrame(aSelf, result, canStopWithStyleChange);
    2380             : 
    2381        1202 :   nsChangeHint assumeDifferenceHint = nsChangeHint(0);
    2382        2404 :   RefPtr<nsStyleContext> oldContext = aSelf->StyleContext();
    2383        1202 :   nsStyleSet* styleSet = StyleSet();
    2384             : 
    2385             : #ifdef ACCESSIBILITY
    2386        1202 :   mWasFrameVisible = nsIPresShell::IsAccessibilityActive() ?
    2387           0 :     oldContext->StyleVisibility()->IsVisible() : false;
    2388             : #endif
    2389             : 
    2390        1202 :   nsIAtom* const pseudoTag = oldContext->GetPseudo();
    2391        1202 :   const CSSPseudoElementType pseudoType = oldContext->GetPseudoType();
    2392             : 
    2393             :   // Get the frame providing the parent style context.  If it is a
    2394             :   // child, then resolve the provider first.
    2395             :   nsIFrame* providerFrame;
    2396        1202 :   nsStyleContext* parentContext = aSelf->GetParentStyleContext(&providerFrame);
    2397        1202 :   bool isChild = providerFrame && providerFrame->GetParent() == aSelf;
    2398        1202 :   if (isChild) {
    2399           0 :     MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(),
    2400             :                "Postcondition for GetParentStyleContext() violated. "
    2401             :                "That means we need to add the current element to the "
    2402             :                "ancestor filter.");
    2403             : 
    2404             :     // resolve the provider here (before aSelf below).
    2405           0 :     LOG_RESTYLE("resolving child provider frame");
    2406             : 
    2407             :     // assumeDifferenceHint forces the parent's change to be also
    2408             :     // applied to this frame, no matter what
    2409             :     // nsStyleContext::CalcStyleDifference says. CalcStyleDifference
    2410             :     // can't be trusted because it assumes any changes to the parent
    2411             :     // style context provider will be automatically propagated to
    2412             :     // the frame(s) with child style contexts.
    2413             : 
    2414             :     ElementRestyler providerRestyler(PARENT_CONTEXT_FROM_CHILD_FRAME,
    2415           0 :                                      *this, providerFrame);
    2416           0 :     providerRestyler.Restyle(aRestyleHint);
    2417           0 :     assumeDifferenceHint = providerRestyler.HintsHandledForFrame();
    2418             : 
    2419             :     // The provider's new context becomes the parent context of
    2420             :     // aSelf's context.
    2421           0 :     parentContext = providerFrame->StyleContext();
    2422             :     // Set |mResolvedChild| so we don't bother resolving the
    2423             :     // provider again.
    2424           0 :     mResolvedChild = providerFrame;
    2425           0 :     LOG_RESTYLE_CONTINUE("we had a provider frame");
    2426             :     // Continue restyling past the odd style context inheritance.
    2427           0 :     result = RestyleResult::eContinue;
    2428           0 :     canStopWithStyleChange = false;
    2429             :   }
    2430             : 
    2431        1202 :   LOG_RESTYLE("parentContext = %p", parentContext);
    2432             : 
    2433             :   // do primary context
    2434        2404 :   RefPtr<nsStyleContext> newContext;
    2435             :   nsIFrame* prevContinuation =
    2436        1202 :     GetPrevContinuationWithPossiblySameStyle(aSelf);
    2437             :   nsStyleContext* prevContinuationContext;
    2438             :   bool copyFromContinuation =
    2439           0 :     prevContinuation &&
    2440             :     (prevContinuationContext = prevContinuation->StyleContext())
    2441        1202 :       ->GetPseudo() == oldContext->GetPseudo() &&
    2442        1202 :      prevContinuationContext->GetParent() == parentContext;
    2443        1202 :   if (copyFromContinuation) {
    2444             :     // Just use the style context from the frame's previous
    2445             :     // continuation.
    2446           0 :     LOG_RESTYLE("using previous continuation's context");
    2447           0 :     newContext = prevContinuationContext;
    2448        1202 :   } else if (pseudoTag == nsCSSAnonBoxes::mozText) {
    2449          40 :     MOZ_ASSERT(aSelf->IsTextFrame());
    2450             :     newContext =
    2451          40 :       styleSet->ResolveStyleForText(aSelf->GetContent(), parentContext);
    2452        1162 :   } else if (pseudoTag == nsCSSAnonBoxes::firstLetterContinuation) {
    2453           0 :     newContext = styleSet->ResolveStyleForFirstLetterContinuation(parentContext);
    2454        1162 :   } else if (pseudoTag == nsCSSAnonBoxes::oofPlaceholder) {
    2455             :     // We still need to ResolveStyleForPlaceholder() here, because we may be
    2456             :     // doing a ruletree reconstruct and hence actually changing our style
    2457             :     // context.
    2458         104 :     newContext = styleSet->ResolveStyleForPlaceholder();
    2459        1058 :   } else if (pseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
    2460             :     // We still need to ResolveNonInheritingAnonymousBoxStyle() here, because we
    2461             :     // may be doing a ruletree reconstruct and hence actually changing our style
    2462             :     // context.
    2463           0 :     newContext = styleSet->ResolveNonInheritingAnonymousBoxStyle(pseudoTag);
    2464             :   }
    2465             :   else {
    2466        1058 :     Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType);
    2467        1058 :     if (!MustRestyleSelf(aRestyleHint, element)) {
    2468         175 :       if (CanReparentStyleContext(aRestyleHint)) {
    2469         144 :         LOG_RESTYLE("reparenting style context");
    2470             :         newContext =
    2471         144 :           styleSet->ReparentStyleContext(oldContext, parentContext, element);
    2472             :       } else {
    2473             :         // Use ResolveStyleWithReplacement either for actual replacements
    2474             :         // or, with no replacements, as a substitute for
    2475             :         // ReparentStyleContext that rebuilds the path in the rule tree
    2476             :         // rather than reusing the rule node, as we need to do during a
    2477             :         // rule tree reconstruct.
    2478          31 :         Element* pseudoElement = PseudoElementForStyleContext(aSelf, pseudoType);
    2479          31 :         MOZ_ASSERT(!element || element != pseudoElement,
    2480             :                    "pseudo-element for selector matching should be "
    2481             :                    "the anonymous content node that we create, "
    2482             :                    "not the real element");
    2483          31 :         LOG_RESTYLE("resolving style with replacement");
    2484          31 :         nsRestyleHint rshint = aRestyleHint & ~eRestyle_SomeDescendants;
    2485             :         newContext =
    2486          62 :           styleSet->ResolveStyleWithReplacement(element, pseudoElement,
    2487             :                                                 parentContext, oldContext,
    2488          31 :                                                 rshint);
    2489             :       }
    2490         883 :     } else if (pseudoType == CSSPseudoElementType::InheritingAnonBox) {
    2491         132 :       newContext = styleSet->ResolveInheritingAnonymousBoxStyle(pseudoTag,
    2492          66 :                                                                 parentContext);
    2493             :     }
    2494             :     else {
    2495         817 :       if (pseudoTag) {
    2496          42 :         if (pseudoTag == nsCSSPseudoElements::before ||
    2497          15 :             pseudoTag == nsCSSPseudoElements::after) {
    2498             :           // XXX what other pseudos do we need to treat like this?
    2499          46 :           newContext = styleSet->ProbePseudoElementStyle(element,
    2500             :                                                          pseudoType,
    2501             :                                                          parentContext,
    2502          23 :                                                          mTreeMatchContext);
    2503          46 :           if (!newContext) {
    2504             :             // This pseudo should no longer exist; gotta reframe
    2505           0 :             mHintsHandledBySelf |= nsChangeHint_ReconstructFrame;
    2506           0 :             mChangeList->AppendChange(aSelf, element,
    2507           0 :                                       nsChangeHint_ReconstructFrame);
    2508             :             // We're reframing anyway; just keep the same context
    2509           0 :             newContext = oldContext;
    2510             : #ifdef DEBUG
    2511             :             // oldContext's parent might have had its style structs swapped out
    2512             :             // with parentContext, so to avoid any assertions that might
    2513             :             // otherwise trigger in oldContext's parent's destructor, we set a
    2514             :             // flag on oldContext to skip it and its descendants in
    2515             :             // nsStyleContext::AssertStructsNotUsedElsewhere.
    2516           0 :             if (oldContext->GetParent() != parentContext) {
    2517           0 :               oldContext->AddStyleBit(NS_STYLE_IS_GOING_AWAY);
    2518             :             }
    2519             : #endif
    2520             :           }
    2521             :         } else {
    2522             :           // Don't expect XUL tree stuff here, since it needs a comparator and
    2523             :           // all.
    2524           4 :           NS_ASSERTION(pseudoType < CSSPseudoElementType::Count,
    2525             :                        "Unexpected pseudo type");
    2526             :           Element* pseudoElement =
    2527           4 :             PseudoElementForStyleContext(aSelf, pseudoType);
    2528           4 :           MOZ_ASSERT(element != pseudoElement,
    2529             :                      "pseudo-element for selector matching should be "
    2530             :                      "the anonymous content node that we create, "
    2531             :                      "not the real element");
    2532           8 :           newContext = styleSet->ResolvePseudoElementStyle(element,
    2533             :                                                            pseudoType,
    2534             :                                                            parentContext,
    2535           4 :                                                            pseudoElement);
    2536             :         }
    2537             :       }
    2538             :       else {
    2539         790 :         NS_ASSERTION(aSelf->GetContent(),
    2540             :                      "non pseudo-element frame without content node");
    2541             :         // Skip parent display based style fixup for anonymous subtrees:
    2542             :         TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
    2543             :           parentDisplayBasedFixupSkipper(mTreeMatchContext,
    2544        1580 :                                  element->IsRootOfNativeAnonymousSubtree());
    2545        1580 :         newContext = styleSet->ResolveStyleFor(element, parentContext,
    2546         790 :                                                mTreeMatchContext);
    2547             :       }
    2548             :     }
    2549             :   }
    2550             : 
    2551        1202 :   MOZ_ASSERT(newContext);
    2552             : 
    2553        1202 :   if (!parentContext) {
    2554         317 :     if (oldContext->RuleNode() == newContext->RuleNode() &&
    2555         201 :         oldContext->IsLinkContext() == newContext->IsLinkContext() &&
    2556          85 :         oldContext->RelevantLinkVisited() ==
    2557          85 :           newContext->RelevantLinkVisited()) {
    2558             :       // We're the root of the style context tree and the new style
    2559             :       // context returned has the same rule node.  This means that
    2560             :       // we can use FindChildWithRules to keep a lot of the old
    2561             :       // style contexts around.  However, we need to start from the
    2562             :       // same root.
    2563          85 :       LOG_RESTYLE("restyling root and keeping old context");
    2564          85 :       LOG_RESTYLE_IF(this, result != RestyleResult::eContinue,
    2565             :                      "continuing restyle since this is the root");
    2566          85 :       newContext = oldContext;
    2567             :       // Never consider stopping restyling at the root.
    2568          85 :       result = RestyleResult::eContinue;
    2569          85 :       canStopWithStyleChange = false;
    2570             :     }
    2571             :   }
    2572             : 
    2573        1202 :   LOG_RESTYLE("oldContext = %p, newContext = %p%s",
    2574             :               oldContext.get(), newContext.get(),
    2575             :               oldContext == newContext ? (const char*) " (same)" :
    2576             :                                          (const char*) "");
    2577             : 
    2578        1202 :   if (newContext != oldContext) {
    2579         724 :     if (oldContext->IsShared()) {
    2580             :       // If the old style context was shared, then we can't return
    2581             :       // RestyleResult::eStop and patch its parent to point to the
    2582             :       // new parent style context, as that change might not be valid
    2583             :       // for the other frames sharing the style context.
    2584         297 :       LOG_RESTYLE_CONTINUE("the old style context is shared");
    2585         297 :       result = RestyleResult::eContinue;
    2586             : 
    2587             :       // It is not safe to return RestyleResult::eStopWithStyleChange
    2588             :       // when oldContext is shared and newContext has different
    2589             :       // inherited style data, regardless of whether the oldContext has
    2590             :       // that inherited style data cached.  We can't simply rely on the
    2591             :       // samePointerStructs check later on, as the descendent style
    2592             :       // contexts just might not have had their inherited style data
    2593             :       // requested yet (which is possible for example if we flush style
    2594             :       // between resolving an initial style context for a frame and
    2595             :       // building its display list items).  Therefore we must compare
    2596             :       // the rule nodes of oldContext and newContext to see if the
    2597             :       // restyle results in new inherited style data.  If not, then
    2598             :       // we can continue assuming that RestyleResult::eStopWithStyleChange
    2599             :       // is safe.  Without this check, we could end up with style contexts
    2600             :       // shared between elements which should have different styles.
    2601         297 :       if (!CommonInheritedStyleData(oldContext->RuleNode(),
    2602             :                                     newContext->RuleNode())) {
    2603         113 :         canStopWithStyleChange = false;
    2604             :       }
    2605             :     }
    2606             : 
    2607             :     // Look at some details of the new style context to see if it would
    2608             :     // be safe to stop restyling, if we discover it has the same style
    2609             :     // data as the old style context.
    2610         724 :     ComputeRestyleResultFromNewContext(aSelf, newContext,
    2611         724 :                                        result, canStopWithStyleChange);
    2612             : 
    2613         724 :     uint32_t equalStructs = 0;
    2614         724 :     uint32_t samePointerStructs = 0;
    2615             : 
    2616         724 :     if (copyFromContinuation) {
    2617             :       // In theory we should know whether there was any style data difference,
    2618             :       // since we would have calculated that in the previous call to
    2619             :       // RestyleSelf, so until we perform only one restyling per chain-of-
    2620             :       // same-style continuations (bug 918064), we need to check again here to
    2621             :       // determine whether it is safe to stop restyling.
    2622           0 :       if (result == RestyleResult::eStop) {
    2623           0 :         oldContext->CalcStyleDifference(newContext,
    2624             :                                         &equalStructs,
    2625           0 :                                         &samePointerStructs);
    2626           0 :         if (equalStructs != NS_STYLE_INHERIT_MASK) {
    2627             :           // At least one struct had different data in it, so we must
    2628             :           // continue restyling children.
    2629           0 :           LOG_RESTYLE_CONTINUE("there is different style data: %s",
    2630             :                       GeckoRestyleManager::StructNamesToString(
    2631             :                         ~equalStructs & NS_STYLE_INHERIT_MASK).get());
    2632           0 :           result = RestyleResult::eContinue;
    2633             :         }
    2634             :       }
    2635             :     } else {
    2636             :       bool changedStyle =
    2637         724 :         GeckoRestyleManager::TryInitiatingTransition(mPresContext,
    2638             :                                                      aSelf->GetContent(),
    2639         724 :                                                      oldContext, &newContext);
    2640         724 :       if (changedStyle) {
    2641           4 :         LOG_RESTYLE_CONTINUE("TryInitiatingTransition changed the new style "
    2642             :                              "context");
    2643           4 :         result = RestyleResult::eContinue;
    2644           4 :         canStopWithStyleChange = false;
    2645             :       }
    2646         724 :       CaptureChange(oldContext, newContext, assumeDifferenceHint,
    2647         724 :                     &equalStructs, &samePointerStructs);
    2648         724 :       if (equalStructs != NS_STYLE_INHERIT_MASK) {
    2649             :         // At least one struct had different data in it, so we must
    2650             :         // continue restyling children.
    2651         172 :         LOG_RESTYLE_CONTINUE("there is different style data: %s",
    2652             :                     GeckoRestyleManager::StructNamesToString(
    2653             :                       ~equalStructs & NS_STYLE_INHERIT_MASK).get());
    2654         172 :         result = RestyleResult::eContinue;
    2655             :       }
    2656             :     }
    2657             : 
    2658         724 :     if (canStopWithStyleChange) {
    2659             :       // If any inherited struct pointers are different, or if any
    2660             :       // reset struct pointers are different and we have descendants
    2661             :       // that rely on those reset struct pointers, we can't return
    2662             :       // RestyleResult::eStopWithStyleChange.
    2663          28 :       if ((samePointerStructs & NS_STYLE_INHERITED_STRUCT_MASK) !=
    2664             :             NS_STYLE_INHERITED_STRUCT_MASK) {
    2665          28 :         LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
    2666             :                     "there is different inherited data");
    2667          28 :         canStopWithStyleChange = false;
    2668           0 :       } else if ((samePointerStructs & NS_STYLE_RESET_STRUCT_MASK) !=
    2669           0 :                    NS_STYLE_RESET_STRUCT_MASK &&
    2670           0 :                  oldContext->HasChildThatUsesResetStyle()) {
    2671           0 :         LOG_RESTYLE("can't return RestyleResult::eStopWithStyleChange since "
    2672             :                     "there is different reset data and descendants use it");
    2673           0 :         canStopWithStyleChange = false;
    2674             :       }
    2675             :     }
    2676             : 
    2677         724 :     if (result == RestyleResult::eStop) {
    2678             :       // Since we currently have RestyleResult::eStop, we know at this
    2679             :       // point that all of our style structs are equal in terms of styles.
    2680             :       // However, some of them might be different pointers.  Since our
    2681             :       // descendants might share those pointers, we have to continue to
    2682             :       // restyling our descendants.
    2683             :       //
    2684             :       // However, because of the swapping of equal structs we've done on
    2685             :       // ancestors (later in this function), we've ensured that for structs
    2686             :       // that cannot be stored in the rule tree, we keep the old equal structs
    2687             :       // around rather than replacing them with new ones.  This means that we
    2688             :       // only time we hit this deoptimization is either
    2689             :       //
    2690             :       // (a) when at least one of the (old or new) equal structs could be stored
    2691             :       //     in the rule tree, and those structs are then inherited (by pointer
    2692             :       //     sharing) to descendant style contexts; or
    2693             :       //
    2694             :       // (b) when we were unable to swap the structs on the parent because
    2695             :       //     either or both of the old parent and new parent are shared.
    2696             :       //
    2697             :       // FIXME This loop could be rewritten as bit operations on
    2698             :       //       oldContext->mBits and samePointerStructs.
    2699         940 :       for (nsStyleStructID sid = nsStyleStructID(0);
    2700         940 :            sid < nsStyleStructID_Length;
    2701         900 :            sid = nsStyleStructID(sid + 1)) {
    2702         995 :         if (oldContext->HasCachedDependentStyleData(sid) &&
    2703          92 :             !(samePointerStructs & nsCachedStyleData::GetBitForSID(sid))) {
    2704           3 :           LOG_RESTYLE_CONTINUE("there are different struct pointers");
    2705           3 :           result = RestyleResult::eContinue;
    2706           3 :           break;
    2707             :         }
    2708             :       }
    2709             :     }
    2710             : 
    2711             :     // From this point we no longer do any assignments of
    2712             :     // RestyleResult::eContinue to |result|.  If canStopWithStyleChange is true,
    2713             :     // it means that we can convert |result| (whether it is
    2714             :     // RestyleResult::eContinue or RestyleResult::eStop) into
    2715             :     // RestyleResult::eStopWithStyleChange.
    2716         724 :     if (canStopWithStyleChange) {
    2717           0 :       LOG_RESTYLE("converting %s into RestyleResult::eStopWithStyleChange",
    2718             :                   RestyleResultToString(result).get());
    2719           0 :       result = RestyleResult::eStopWithStyleChange;
    2720             :     }
    2721             : 
    2722         724 :     if (aRestyleHint & eRestyle_ForceDescendants) {
    2723         293 :       result = RestyleResult::eContinueAndForceDescendants;
    2724             :     }
    2725             : 
    2726         724 :     if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    2727             :       // If the frame gets regenerated, let it keep its old context,
    2728             :       // which is important to maintain various invariants about
    2729             :       // frame types matching their style contexts.
    2730             :       // Note that this check even makes sense if we didn't call
    2731             :       // CaptureChange because of copyFromContinuation being true,
    2732             :       // since we'll have copied the existing context from the
    2733             :       // previous continuation, so newContext == oldContext.
    2734             : 
    2735         714 :       if (result != RestyleResult::eStop) {
    2736         677 :         if (copyFromContinuation) {
    2737           0 :           LOG_RESTYLE("not swapping style structs, since we copied from a "
    2738             :                       "continuation");
    2739         677 :         } else if (oldContext->IsShared() && newContext->IsShared()) {
    2740         123 :           LOG_RESTYLE("not swapping style structs, since both old and contexts "
    2741             :                       "are shared");
    2742         554 :         } else if (oldContext->IsShared()) {
    2743         173 :           LOG_RESTYLE("not swapping style structs, since the old context is "
    2744             :                       "shared");
    2745         381 :         } else if (newContext->IsShared()) {
    2746           2 :           LOG_RESTYLE("not swapping style structs, since the new context is "
    2747             :                       "shared");
    2748             :         } else {
    2749         379 :           if (result == RestyleResult::eStopWithStyleChange) {
    2750           0 :             LOG_RESTYLE("recording a style struct swap between %p and %p to "
    2751             :                         "do if RestyleResult::eStopWithStyleChange fails",
    2752             :                         oldContext.get(), newContext.get());
    2753           0 :             SwapInstruction* swap = aSwaps.AppendElement();
    2754           0 :             swap->mOldContext = oldContext;
    2755           0 :             swap->mNewContext = newContext;
    2756           0 :             swap->mStructsToSwap = equalStructs;
    2757             :           } else {
    2758         379 :             LOG_RESTYLE("swapping style structs between %p and %p",
    2759             :                         oldContext.get(), newContext.get());
    2760         379 :             oldContext->AsGecko()->SwapStyleData(newContext->AsGecko(), equalStructs);
    2761         379 :             *aSwappedStructs |= equalStructs;
    2762             :           }
    2763             : #ifdef RESTYLE_LOGGING
    2764         379 :           uint32_t structs = GeckoRestyleManager::StructsToLog() & equalStructs;
    2765         379 :           if (structs) {
    2766           0 :             LOG_RESTYLE_INDENT();
    2767           0 :             LOG_RESTYLE("old style context now has: %s",
    2768             :                         oldContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
    2769           0 :             LOG_RESTYLE("new style context now has: %s",
    2770             :                         newContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
    2771             :           }
    2772             : #endif
    2773             :         }
    2774         677 :         LOG_RESTYLE("setting new style context");
    2775         677 :         aSelf->SetStyleContext(newContext);
    2776             :       }
    2777             :     } else {
    2778          10 :       LOG_RESTYLE("not setting new style context, since we'll reframe");
    2779             :       // We need to keep the new parent alive, in case it had structs
    2780             :       // swapped into it that our frame's style context still has cached.
    2781             :       // This is a similar scenario to the one described in the
    2782             :       // ElementRestyler::Restyle comment where we append to
    2783             :       // mSwappedStructOwners.
    2784             :       //
    2785             :       // We really only need to do this if we did swap structs on the
    2786             :       // parent, but we don't have that information here.
    2787          10 :       mSwappedStructOwners.AppendElement(newContext->GetParent());
    2788             :     }
    2789             :   } else {
    2790         478 :     if (aRestyleHint & eRestyle_ForceDescendants) {
    2791           0 :       result = RestyleResult::eContinueAndForceDescendants;
    2792             :     }
    2793             :   }
    2794        1202 :   oldContext = nullptr;
    2795             : 
    2796             :   // do additional contexts
    2797             :   // XXXbz might be able to avoid selector matching here in some
    2798             :   // cases; won't worry about it for now.
    2799        1202 :   int32_t contextIndex = 0;
    2800        1202 :   for (nsStyleContext* oldExtraContext;
    2801        1202 :        (oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex));
    2802             :        ++contextIndex) {
    2803           0 :     LOG_RESTYLE("extra context %d", contextIndex);
    2804           0 :     LOG_RESTYLE_INDENT();
    2805           0 :     RefPtr<nsStyleContext> newExtraContext;
    2806           0 :     nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
    2807             :     const CSSPseudoElementType extraPseudoType =
    2808           0 :       oldExtraContext->GetPseudoType();
    2809           0 :     NS_ASSERTION(extraPseudoTag &&
    2810             :                  !nsCSSAnonBoxes::IsNonElement(extraPseudoTag),
    2811             :                  "extra style context is not pseudo element");
    2812             :     Element* element =
    2813           0 :       (extraPseudoType != CSSPseudoElementType::InheritingAnonBox &&
    2814             :        extraPseudoType != CSSPseudoElementType::NonInheritingAnonBox)
    2815           0 :       ? mContent->AsElement() : nullptr;
    2816           0 :     if (extraPseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
    2817             :       newExtraContext =
    2818           0 :         styleSet->ResolveNonInheritingAnonymousBoxStyle(extraPseudoTag);
    2819           0 :     } else if (!MustRestyleSelf(aRestyleHint, element)) {
    2820           0 :       if (CanReparentStyleContext(aRestyleHint)) {
    2821             :         newExtraContext =
    2822           0 :           styleSet->ReparentStyleContext(oldExtraContext, newContext, element);
    2823             :       } else {
    2824             :         // Use ResolveStyleWithReplacement as a substitute for
    2825             :         // ReparentStyleContext that rebuilds the path in the rule tree
    2826             :         // rather than reusing the rule node, as we need to do during a
    2827             :         // rule tree reconstruct.
    2828             :         Element* pseudoElement =
    2829           0 :           PseudoElementForStyleContext(aSelf, extraPseudoType);
    2830           0 :         MOZ_ASSERT(!element || element != pseudoElement,
    2831             :                    "pseudo-element for selector matching should be "
    2832             :                    "the anonymous content node that we create, "
    2833             :                    "not the real element");
    2834             :         newExtraContext =
    2835           0 :           styleSet->ResolveStyleWithReplacement(element, pseudoElement,
    2836             :                                                 newContext, oldExtraContext,
    2837           0 :                                                 nsRestyleHint(0));
    2838             :       }
    2839           0 :     } else if (extraPseudoType == CSSPseudoElementType::InheritingAnonBox) {
    2840             :       newExtraContext = styleSet->
    2841           0 :         ResolveInheritingAnonymousBoxStyle(extraPseudoTag, newContext);
    2842             :     } else {
    2843             :       // Don't expect XUL tree stuff here, since it needs a comparator and
    2844             :       // all.
    2845           0 :       NS_ASSERTION(extraPseudoType < CSSPseudoElementType::Count,
    2846             :                    "Unexpected type");
    2847           0 :       newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(),
    2848             :                                                             extraPseudoType,
    2849             :                                                             newContext,
    2850           0 :                                                             nullptr);
    2851             :     }
    2852             : 
    2853           0 :     MOZ_ASSERT(newExtraContext);
    2854             : 
    2855           0 :     LOG_RESTYLE("newExtraContext = %p", newExtraContext.get());
    2856             : 
    2857           0 :     if (oldExtraContext != newExtraContext) {
    2858             :       uint32_t equalStructs;
    2859             :       uint32_t samePointerStructs;
    2860           0 :       CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint,
    2861           0 :                     &equalStructs, &samePointerStructs);
    2862           0 :       if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    2863           0 :         LOG_RESTYLE("setting new extra style context");
    2864           0 :         aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
    2865             :       } else {
    2866           0 :         LOG_RESTYLE("not setting new extra style context, since we'll reframe");
    2867             :       }
    2868             :     }
    2869             :   }
    2870             : 
    2871        1202 :   LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
    2872             : 
    2873        2404 :   return result;
    2874             : }
    2875             : 
    2876             : void
    2877        1148 : ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
    2878             : {
    2879        1148 :   MOZ_ASSERT(!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame),
    2880             :              "No need to do this if we're planning to reframe already.");
    2881             : 
    2882             :   // We'd like style resolution to be exact in the sense that an
    2883             :   // animation-only style flush flushes only the styles it requests
    2884             :   // flushing and doesn't update any other styles.  This means avoiding
    2885             :   // constructing new frames during such a flush.
    2886             :   //
    2887             :   // For a ::before or ::after, we'll do an eRestyle_Subtree due to
    2888             :   // RestyleHintForOp in nsCSSRuleProcessor.cpp (via its
    2889             :   // HasAttributeDependentStyle or HasStateDependentStyle), given that
    2890             :   // we store pseudo-elements in selectors like they were children.
    2891             :   //
    2892             :   // Also, it's faster to skip the work we do on undisplayed children
    2893             :   // and pseudo-elements when we can skip it.
    2894        1148 :   bool mightReframePseudos = aChildRestyleHint & eRestyle_Subtree;
    2895             : 
    2896        1148 :   RestyleUndisplayedDescendants(aChildRestyleHint);
    2897             : 
    2898             :   // Check whether we might need to create a new ::before frame.
    2899             :   // There's no need to do this if we're planning to reframe already
    2900             :   // or if we're not forcing restyles on kids.
    2901             :   // It's also important to check mHintsHandledBySelf since we use
    2902             :   // mFrame->StyleContext(), which is out of date if mHintsHandledBySelf
    2903             :   // has a ReconstructFrame hint.  Using an out of date style context could
    2904             :   // trigger assertions about mismatched rule trees.
    2905        1148 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame) &&
    2906             :       mightReframePseudos) {
    2907         918 :     MaybeReframeForBeforePseudo();
    2908             :   }
    2909             : 
    2910             :   // There is no need to waste time crawling into a frame's children
    2911             :   // on a frame change.  The act of reconstructing frames will force
    2912             :   // new style contexts to be resolved on all of this frame's
    2913             :   // descendants anyway, so we want to avoid wasting time processing
    2914             :   // style contexts that we're just going to throw away anyway. - dwh
    2915             :   // It's also important to check mHintsHandledBySelf since reresolving the
    2916             :   // kids would use mFrame->StyleContext(), which is out of date if
    2917             :   // mHintsHandledBySelf has a ReconstructFrame hint; doing this could
    2918             :   // trigger assertions about mismatched rule trees.
    2919             :   nsIFrame* lastContinuation;
    2920        1148 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    2921        1148 :     InitializeAccessibilityNotifications(mFrame->StyleContext());
    2922             : 
    2923        2296 :     for (nsIFrame* f = mFrame; f;
    2924        1148 :          f = GeckoRestyleManager::GetNextContinuationWithSameStyle(f, f->StyleContext())) {
    2925        1148 :       lastContinuation = f;
    2926        1148 :       RestyleContentChildren(f, aChildRestyleHint);
    2927             :     }
    2928             : 
    2929        1148 :     SendAccessibilityNotifications();
    2930             :   }
    2931             : 
    2932             :   // Check whether we might need to create a new ::after frame.
    2933             :   // See comments above regarding :before.
    2934        1148 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame) &&
    2935             :       mightReframePseudos) {
    2936         918 :     MaybeReframeForAfterPseudo(lastContinuation);
    2937             :   }
    2938        1148 : }
    2939             : 
    2940             : void
    2941           0 : ElementRestyler::RestyleChildrenOfDisplayContentsElement(
    2942             :   nsIFrame*              aParentFrame,
    2943             :   nsStyleContext*        aNewContext,
    2944             :   nsChangeHint           aMinHint,
    2945             :   RestyleTracker&        aRestyleTracker,
    2946             :   nsRestyleHint          aRestyleHint,
    2947             :   const RestyleHintData& aRestyleHintData)
    2948             : {
    2949           0 :   MOZ_ASSERT(!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame),
    2950             :              "why call me?");
    2951             : 
    2952           0 :   const bool mightReframePseudos = aRestyleHint & eRestyle_Subtree;
    2953           0 :   DoRestyleUndisplayedDescendants(nsRestyleHint(0), mContent, aNewContext);
    2954           0 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame) &&
    2955             :       mightReframePseudos) {
    2956             :     MaybeReframeForPseudo(CSSPseudoElementType::before,
    2957           0 :                           aParentFrame, nullptr, mContent, aNewContext);
    2958             :   }
    2959           0 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame) &&
    2960             :       mightReframePseudos) {
    2961             :     MaybeReframeForPseudo(CSSPseudoElementType::after,
    2962           0 :                           aParentFrame, nullptr, mContent, aNewContext);
    2963             :   }
    2964           0 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    2965           0 :     InitializeAccessibilityNotifications(aNewContext);
    2966             : 
    2967             :     // Then process child frames for content that is a descendant of mContent.
    2968             :     // XXX perhaps it's better to walk child frames (before reresolving
    2969             :     // XXX undisplayed contexts above) and mark those that has a stylecontext
    2970             :     // XXX leading up to mContent's old context? (instead of the
    2971             :     // XXX ContentIsDescendantOf check below)
    2972           0 :     nsIFrame::ChildListIterator lists(aParentFrame);
    2973           0 :     for ( ; !lists.IsDone(); lists.Next()) {
    2974           0 :       for (nsIFrame* f : lists.CurrentList()) {
    2975           0 :         if (nsContentUtils::ContentIsDescendantOf(f->GetContent(), mContent) &&
    2976           0 :             !f->GetPrevContinuation()) {
    2977           0 :           if (!(f->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
    2978           0 :             ComputeStyleChangeFor(f, mChangeList, aMinHint, aRestyleTracker,
    2979             :                                   aRestyleHint, aRestyleHintData,
    2980           0 :                                   mContextsToClear, mSwappedStructOwners);
    2981             :           }
    2982             :         }
    2983             :       }
    2984             :     }
    2985             :   }
    2986           0 :   if (!(mHintsHandledBySelf & nsChangeHint_ReconstructFrame)) {
    2987           0 :     SendAccessibilityNotifications();
    2988             :   }
    2989           0 : }
    2990             : 
    2991             : void
    2992          61 : ElementRestyler::ComputeStyleChangeFor(nsIFrame*          aFrame,
    2993             :                                        nsStyleChangeList* aChangeList,
    2994             :                                        nsChangeHint       aMinChange,
    2995             :                                        RestyleTracker&    aRestyleTracker,
    2996             :                                        nsRestyleHint      aRestyleHint,
    2997             :                                        const RestyleHintData& aRestyleHintData,
    2998             :                                        nsTArray<ContextToClear>&
    2999             :                                          aContextsToClear,
    3000             :                                        nsTArray<RefPtr<nsStyleContext>>&
    3001             :                                          aSwappedStructOwners)
    3002             : {
    3003         116 :   AUTO_PROFILER_LABEL("ElementRestyler::ComputeStyleChangeFor", CSS);
    3004             : 
    3005          61 :   nsIContent* content = aFrame->GetContent();
    3006          61 :   if (aMinChange) {
    3007           1 :     aChangeList->AppendChange(aFrame, content, aMinChange);
    3008             :   }
    3009             : 
    3010          61 :   NS_ASSERTION(!aFrame->GetPrevContinuation(),
    3011             :                "must start with the first continuation");
    3012             : 
    3013             :   // We want to start with this frame and walk all its next-in-flows,
    3014             :   // as well as all its ib-split siblings and their next-in-flows,
    3015             :   // reresolving style on all the frames we encounter in this walk that
    3016             :   // we didn't reach already.  In the normal case, this will mean only
    3017             :   // restyling the first two block-in-inline splits and no
    3018             :   // continuations, and skipping everything else.  However, when we have
    3019             :   // a style change targeted at an element inside a context where styles
    3020             :   // vary between continuations (e.g., a style change on an element that
    3021             :   // extends from inside a styled ::first-line to outside of that first
    3022             :   // line), we might restyle more than that.
    3023             : 
    3024          61 :   nsPresContext* presContext = aFrame->PresContext();
    3025             : 
    3026             :   TreeMatchContext treeMatchContext(true,
    3027             :                                     nsRuleWalker::eRelevantLinkUnvisited,
    3028         116 :                                     presContext->Document());
    3029             :   Element* parent =
    3030          61 :     content ? content->GetParentElementCrossingShadowRoot() : nullptr;
    3031          61 :   treeMatchContext.InitAncestors(parent);
    3032         116 :   nsTArray<nsCSSSelector*> selectorsForDescendants;
    3033          61 :   selectorsForDescendants.AppendElements(
    3034          61 :       aRestyleHintData.mSelectorsForDescendants);
    3035         116 :   nsTArray<nsIContent*> visibleKidsOfHiddenElement;
    3036             :   nsIFrame* nextIBSibling;
    3037         116 :   for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) {
    3038             :     nextIBSibling =
    3039          61 :       GeckoRestyleManager::GetNextBlockInInlineSibling(ibSibling);
    3040             : 
    3041          61 :     if (nextIBSibling) {
    3042             :       // Don't allow some ib-split siblings to be processed with
    3043             :       // RestyleResult::eStopWithStyleChange and others not.
    3044           0 :       aRestyleHint |= eRestyle_Force;
    3045             :     }
    3046             : 
    3047             :     // Outer loop over ib-split siblings
    3048         116 :     for (nsIFrame* cont = ibSibling; cont; cont = cont->GetNextContinuation()) {
    3049          61 :       if (GetPrevContinuationWithSameStyle(cont)) {
    3050             :         // We already handled this element when dealing with its earlier
    3051             :         // continuation.
    3052           0 :         continue;
    3053             :       }
    3054             : 
    3055             :       // Inner loop over next-in-flows of the current frame
    3056             :       ElementRestyler restyler(presContext, cont, aChangeList,
    3057             :                                aMinChange, aRestyleTracker,
    3058             :                                selectorsForDescendants,
    3059             :                                treeMatchContext,
    3060             :                                visibleKidsOfHiddenElement,
    3061          61 :                                aContextsToClear, aSwappedStructOwners);
    3062             : 
    3063          61 :       restyler.Restyle(aRestyleHint);
    3064             : 
    3065          61 :       if (restyler.HintsHandledForFrame() & nsChangeHint_ReconstructFrame) {
    3066             :         // If it's going to cause a framechange, then don't bother
    3067             :         // with the continuations or ib-split siblings since they'll be
    3068             :         // clobbered by the frame reconstruct anyway.
    3069           6 :         NS_ASSERTION(!cont->GetPrevContinuation(),
    3070             :                      "continuing frame had more severe impact than first-in-flow");
    3071           6 :         return;
    3072             :       }
    3073             :     }
    3074             :   }
    3075             : }
    3076             : 
    3077             : // The structure of this method parallels ConditionallyRestyleUndisplayedDescendants.
    3078             : // If you update this method, you probably want to update that one too.
    3079             : void
    3080        1148 : ElementRestyler::RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint)
    3081             : {
    3082             :   nsIContent* undisplayedParent;
    3083        1148 :   if (MustCheckUndisplayedContent(mFrame, undisplayedParent)) {
    3084         888 :     DoRestyleUndisplayedDescendants(aChildRestyleHint, undisplayedParent,
    3085        1776 :                                     mFrame->StyleContext());
    3086             :   }
    3087        1148 : }
    3088             : 
    3089             : // The structure of this method parallels DoConditionallyRestyleUndisplayedDescendants.
    3090             : // If you update this method, you probably want to update that one too.
    3091             : void
    3092         888 : ElementRestyler::DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
    3093             :                                                  nsIContent* aParent,
    3094             :                                                  nsStyleContext* aParentContext)
    3095             : {
    3096         888 :   nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
    3097         888 :   UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
    3098             :   RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
    3099         888 :                           aParentContext, StyleDisplay::None);
    3100         888 :   nodes = fc->GetAllDisplayContentsIn(aParent);
    3101             :   RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
    3102         888 :                           aParentContext, StyleDisplay::Contents);
    3103         888 : }
    3104             : 
    3105             : // The structure of this method parallels ConditionallyRestyleUndisplayedNodes.
    3106             : // If you update this method, you probably want to update that one too.
    3107             : void
    3108        1776 : ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint      aChildRestyleHint,
    3109             :                                          UndisplayedNode*   aUndisplayed,
    3110             :                                          nsIContent*        aUndisplayedParent,
    3111             :                                          nsStyleContext*    aParentContext,
    3112             :                                          const StyleDisplay aDisplay)
    3113             : {
    3114        1776 :   nsIContent* undisplayedParent = aUndisplayedParent;
    3115        1776 :   UndisplayedNode* undisplayed = aUndisplayed;
    3116        3552 :   TreeMatchContext::AutoAncestorPusher pusher(&mTreeMatchContext);
    3117        1776 :   if (undisplayed) {
    3118         139 :     pusher.PushAncestorAndStyleScope(undisplayedParent);
    3119             :   }
    3120        3072 :   for (; undisplayed; undisplayed = undisplayed->getNext()) {
    3121         648 :     NS_ASSERTION(undisplayedParent ||
    3122             :                  undisplayed->mContent ==
    3123             :                    mPresContext->Document()->GetRootElement(),
    3124             :                  "undisplayed node child of null must be root");
    3125         648 :     NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
    3126             :                  "Shouldn't have random pseudo style contexts in the "
    3127             :                  "undisplayed map");
    3128             : 
    3129         648 :     LOG_RESTYLE("RestyleUndisplayedChildren: undisplayed->mContent = %p",
    3130             :                 undisplayed->mContent.get());
    3131             : 
    3132             :     // Get the parent of the undisplayed content and check if it is a XBL
    3133             :     // children element. Push the children element as an ancestor here because it does
    3134             :     // not have a frame and would not otherwise be pushed as an ancestor.
    3135         648 :     nsIContent* parent = undisplayed->mContent->GetParent();
    3136        1296 :     TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
    3137         648 :     if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
    3138           0 :       insertionPointPusher.PushAncestorAndStyleScope(parent);
    3139             :     }
    3140             : 
    3141         648 :     nsRestyleHint thisChildHint = aChildRestyleHint;
    3142        1296 :     nsAutoPtr<RestyleTracker::RestyleData> undisplayedRestyleData;
    3143         648 :     Element* element = undisplayed->mContent->AsElement();
    3144         648 :     if (mRestyleTracker.GetRestyleData(element,
    3145             :                                        undisplayedRestyleData)) {
    3146             :       thisChildHint =
    3147           1 :         nsRestyleHint(thisChildHint | undisplayedRestyleData->mRestyleHint);
    3148             :     }
    3149        1296 :     RefPtr<nsStyleContext> undisplayedContext;
    3150         648 :     nsStyleSet* styleSet = StyleSet();
    3151         648 :     if (MustRestyleSelf(thisChildHint, element)) {
    3152             :       undisplayedContext =
    3153         484 :         styleSet->ResolveStyleFor(element, aParentContext, mTreeMatchContext);
    3154         164 :     } else if (CanReparentStyleContext(thisChildHint)) {
    3155             :       undisplayedContext =
    3156         308 :         styleSet->ReparentStyleContext(undisplayed->mStyle,
    3157             :                                        aParentContext,
    3158         154 :                                        element);
    3159             :     } else {
    3160             :       // Use ResolveStyleWithReplacement either for actual
    3161             :       // replacements, or as a substitute for ReparentStyleContext
    3162             :       // that rebuilds the path in the rule tree rather than reusing
    3163             :       // the rule node, as we need to do during a rule tree
    3164             :       // reconstruct.
    3165          10 :       nsRestyleHint rshint = thisChildHint & ~eRestyle_SomeDescendants;
    3166             :       undisplayedContext =
    3167          20 :         styleSet->ResolveStyleWithReplacement(element, nullptr,
    3168             :                                               aParentContext,
    3169             :                                               undisplayed->mStyle,
    3170          10 :                                               rshint);
    3171             :     }
    3172         648 :     const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
    3173         648 :     if (display->mDisplay != aDisplay) {
    3174           0 :       NS_ASSERTION(element, "Must have undisplayed content");
    3175           0 :       mChangeList->AppendChange(nullptr, element,
    3176           0 :                                 nsChangeHint_ReconstructFrame);
    3177             :       // The node should be removed from the undisplayed map when
    3178             :       // we reframe it.
    3179             :     } else {
    3180             :       // update the undisplayed node with the new context
    3181         648 :       undisplayed->mStyle = undisplayedContext;
    3182             : 
    3183         648 :       if (aDisplay == StyleDisplay::Contents) {
    3184           0 :         DoRestyleUndisplayedDescendants(aChildRestyleHint, element,
    3185           0 :                                         undisplayed->mStyle);
    3186             :       }
    3187             :     }
    3188             :   }
    3189        1776 : }
    3190             : 
    3191             : void
    3192         918 : ElementRestyler::MaybeReframeForBeforePseudo()
    3193             : {
    3194        1836 :   MaybeReframeForPseudo(CSSPseudoElementType::before,
    3195        1836 :                         mFrame, mFrame, mFrame->GetContent(),
    3196        1836 :                         mFrame->StyleContext());
    3197         918 : }
    3198             : 
    3199             : /**
    3200             :  * aFrame is the last continuation or block-in-inline sibling that this
    3201             :  * ElementRestyler is restyling.
    3202             :  */
    3203             : void
    3204         918 : ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame)
    3205             : {
    3206         918 :   MOZ_ASSERT(aFrame);
    3207         918 :   MaybeReframeForPseudo(CSSPseudoElementType::after,
    3208             :                         aFrame, aFrame, aFrame->GetContent(),
    3209         918 :                         aFrame->StyleContext());
    3210         918 : }
    3211             : 
    3212             : #ifdef DEBUG
    3213             : bool
    3214           0 : ElementRestyler::MustReframeForBeforePseudo()
    3215             : {
    3216           0 :   return MustReframeForPseudo(CSSPseudoElementType::before,
    3217           0 :                               mFrame, mFrame, mFrame->GetContent(),
    3218           0 :                               mFrame->StyleContext());
    3219             : }
    3220             : 
    3221             : bool
    3222           0 : ElementRestyler::MustReframeForAfterPseudo(nsIFrame* aFrame)
    3223             : {
    3224           0 :   MOZ_ASSERT(aFrame);
    3225           0 :   return MustReframeForPseudo(CSSPseudoElementType::after,
    3226             :                               aFrame, aFrame, aFrame->GetContent(),
    3227           0 :                               aFrame->StyleContext());
    3228             : }
    3229             : #endif
    3230             : 
    3231             : void
    3232        1836 : ElementRestyler::MaybeReframeForPseudo(CSSPseudoElementType aPseudoType,
    3233             :                                        nsIFrame* aGenConParentFrame,
    3234             :                                        nsIFrame* aFrame,
    3235             :                                        nsIContent* aContent,
    3236             :                                        nsStyleContext* aStyleContext)
    3237             : {
    3238        1836 :   if (MustReframeForPseudo(aPseudoType, aGenConParentFrame, aFrame, aContent,
    3239             :                            aStyleContext)) {
    3240             :     // Have to create the new ::before/::after frame.
    3241           0 :     LOG_RESTYLE("MaybeReframeForPseudo, appending "
    3242             :                 "nsChangeHint_ReconstructFrame");
    3243           0 :     mHintsHandledBySelf |= nsChangeHint_ReconstructFrame;
    3244           0 :     mChangeList->AppendChange(aFrame, aContent, nsChangeHint_ReconstructFrame);
    3245             :   }
    3246        1836 : }
    3247             : 
    3248             : bool
    3249        1836 : ElementRestyler::MustReframeForPseudo(CSSPseudoElementType aPseudoType,
    3250             :                                       nsIFrame* aGenConParentFrame,
    3251             :                                       nsIFrame* aFrame,
    3252             :                                       nsIContent* aContent,
    3253             :                                       nsStyleContext* aStyleContext)
    3254             : {
    3255        1836 :   MOZ_ASSERT(aPseudoType == CSSPseudoElementType::before ||
    3256             :              aPseudoType == CSSPseudoElementType::after);
    3257             : 
    3258             :   // Make sure not to do this for pseudo-frames...
    3259        1836 :   if (aStyleContext->GetPseudo()) {
    3260         406 :     return false;
    3261             :   }
    3262             : 
    3263             :   // ... or frames that can't have generated content.
    3264        1430 :   if (!(aGenConParentFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT)) {
    3265             :     // Our content insertion frame might have gotten flagged.
    3266         812 :     nsContainerFrame* cif = aGenConParentFrame->GetContentInsertionFrame();
    3267         812 :     if (!cif || !(cif->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT)) {
    3268         730 :       return false;
    3269             :     }
    3270             :   }
    3271             : 
    3272         700 :   if (aPseudoType == CSSPseudoElementType::before) {
    3273             :     // Check for a ::before pseudo style and the absence of a ::before content,
    3274             :     // but only if aFrame is null or is the first continuation/ib-split.
    3275         700 :     if ((aFrame && !nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) ||
    3276         350 :         nsLayoutUtils::GetBeforeFrame(aContent)) {
    3277          12 :       return false;
    3278             :     }
    3279             :   } else {
    3280             :     // Similarly for ::after, but check for being the last continuation/
    3281             :     // ib-split.
    3282         700 :     if ((aFrame && nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) ||
    3283         350 :         nsLayoutUtils::GetAfterFrame(aContent)) {
    3284          11 :       return false;
    3285             :     }
    3286             :   }
    3287             : 
    3288             :   // Checking for a ::before frame (which we do above) is cheaper than getting
    3289             :   // the ::before style context here.
    3290             :   return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, aPseudoType,
    3291         677 :                                        mPresContext);
    3292             : }
    3293             : 
    3294             : void
    3295        1192 : ElementRestyler::InitializeAccessibilityNotifications(nsStyleContext* aNewContext)
    3296             : {
    3297             : #ifdef ACCESSIBILITY
    3298             :   // Notify a11y for primary frame only if it's a root frame of visibility
    3299             :   // changes or its parent frame was hidden while it stays visible and
    3300             :   // it is not inside a {ib} split or is the first frame of {ib} split.
    3301        1192 :   if (nsIPresShell::IsAccessibilityActive() &&
    3302           0 :       (!mFrame ||
    3303           0 :        (!mFrame->GetPrevContinuation() &&
    3304           0 :         !mFrame->FrameIsNonFirstInIBSplit()))) {
    3305           0 :     if (mDesiredA11yNotifications == eSendAllNotifications) {
    3306           0 :       bool isFrameVisible = aNewContext->StyleVisibility()->IsVisible();
    3307           0 :       if (isFrameVisible != mWasFrameVisible) {
    3308           0 :         if (isFrameVisible) {
    3309             :           // Notify a11y the element (perhaps with its children) was shown.
    3310             :           // We don't fall into this case if this element gets or stays shown
    3311             :           // while its parent becomes hidden.
    3312           0 :           mKidsDesiredA11yNotifications = eSkipNotifications;
    3313           0 :           mOurA11yNotification = eNotifyShown;
    3314             :         } else {
    3315             :           // The element is being hidden; its children may stay visible, or
    3316             :           // become visible after being hidden previously. If we'll find
    3317             :           // visible children then we should notify a11y about that as if
    3318             :           // they were inserted into tree. Notify a11y this element was
    3319             :           // hidden.
    3320           0 :           mKidsDesiredA11yNotifications = eNotifyIfShown;
    3321           0 :           mOurA11yNotification = eNotifyHidden;
    3322             :         }
    3323             :       }
    3324           0 :     } else if (mDesiredA11yNotifications == eNotifyIfShown &&
    3325           0 :                aNewContext->StyleVisibility()->IsVisible()) {
    3326             :       // Notify a11y that element stayed visible while its parent was hidden.
    3327           0 :       nsIContent* c = mFrame ? mFrame->GetContent() : mContent;
    3328           0 :       mVisibleKidsOfHiddenElement.AppendElement(c);
    3329           0 :       mKidsDesiredA11yNotifications = eSkipNotifications;
    3330             :     }
    3331             :   }
    3332             : #endif
    3333        1192 : }
    3334             : 
    3335             : // The structure of this method parallels ConditionallyRestyleContentChildren.
    3336             : // If you update this method, you probably want to update that one too.
    3337             : void
    3338        1148 : ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
    3339             :                                         nsRestyleHint aChildRestyleHint)
    3340             : {
    3341        1148 :   LOG_RESTYLE("RestyleContentChildren");
    3342             : 
    3343        2296 :   nsIFrame::ChildListIterator lists(aParent);
    3344        2296 :   TreeMatchContext::AutoAncestorPusher ancestorPusher(&mTreeMatchContext);
    3345        1148 :   if (!lists.IsDone()) {
    3346         565 :     ancestorPusher.PushAncestorAndStyleScope(mContent);
    3347             :   }
    3348        2384 :   for (; !lists.IsDone(); lists.Next()) {
    3349        1752 :     for (nsIFrame* child : lists.CurrentList()) {
    3350             :       // Out-of-flows are reached through their placeholders.  Continuations
    3351             :       // and block-in-inline splits are reached through those chains.
    3352        2171 :       if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
    3353        1037 :           !GetPrevContinuationWithSameStyle(child)) {
    3354             :         // Get the parent of the child frame's content and check if it
    3355             :         // is a XBL children element. Push the children element as an
    3356             :         // ancestor here because it does not have a frame and would not
    3357             :         // otherwise be pushed as an ancestor.
    3358             : 
    3359             :         // Check if the frame has a content because |child| may be a
    3360             :         // nsPageFrame that does not have a content.
    3361        1037 :         nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
    3362        2074 :         TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
    3363        1037 :         if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
    3364           0 :           insertionPointPusher.PushAncestorAndStyleScope(parent);
    3365             :         }
    3366             : 
    3367             :         // only do frames that are in flow
    3368        1037 :         if (child->IsPlaceholderFrame()) { // placeholder
    3369             :           // get out of flow frame and recur there
    3370             :           nsIFrame* outOfFlowFrame =
    3371         104 :             nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
    3372         104 :           NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
    3373         104 :           NS_ASSERTION(outOfFlowFrame != mResolvedChild,
    3374             :                        "out-of-flow frame not a true descendant");
    3375             : 
    3376             :           // |nsFrame::GetParentStyleContext| checks being out
    3377             :           // of flow so that this works correctly.
    3378         104 :           do {
    3379         104 :             if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) {
    3380             :               // Later continuations are likely restyled as a result of
    3381             :               // the restyling of the previous continuation.
    3382             :               // (Currently that's always true, but it's likely to
    3383             :               // change if we implement overflow:fragments or similar.)
    3384           0 :               continue;
    3385             :             }
    3386             :             ElementRestyler oofRestyler(*this, outOfFlowFrame,
    3387         104 :                                         FOR_OUT_OF_FLOW_CHILD);
    3388         104 :             oofRestyler.Restyle(aChildRestyleHint);
    3389         104 :           } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
    3390             : 
    3391             :           // reresolve placeholder's context under the same parent
    3392             :           // as the out-of-flow frame
    3393         104 :           ElementRestyler phRestyler(*this, child, 0);
    3394         104 :           phRestyler.Restyle(aChildRestyleHint);
    3395             :         }
    3396             :         else {  // regular child frame
    3397         933 :           if (child != mResolvedChild) {
    3398         933 :             ElementRestyler childRestyler(*this, child, 0);
    3399         933 :             childRestyler.Restyle(aChildRestyleHint);
    3400             :           }
    3401             :         }
    3402             :       }
    3403             :     }
    3404             :   }
    3405             :   // XXX need to do overflow frames???
    3406        1148 : }
    3407             : 
    3408             : void
    3409        1192 : ElementRestyler::SendAccessibilityNotifications()
    3410             : {
    3411             : #ifdef ACCESSIBILITY
    3412             :   // Send notifications about visibility changes.
    3413        1192 :   if (mOurA11yNotification == eNotifyShown) {
    3414           0 :     nsAccessibilityService* accService = nsIPresShell::AccService();
    3415           0 :     if (accService) {
    3416           0 :       nsIPresShell* presShell = mPresContext->GetPresShell();
    3417           0 :       nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
    3418             : 
    3419           0 :       accService->ContentRangeInserted(presShell, content->GetParent(),
    3420             :                                        content,
    3421           0 :                                        content->GetNextSibling());
    3422             :     }
    3423        1192 :   } else if (mOurA11yNotification == eNotifyHidden) {
    3424           0 :     nsAccessibilityService* accService = nsIPresShell::AccService();
    3425           0 :     if (accService) {
    3426           0 :       nsIPresShell* presShell = mPresContext->GetPresShell();
    3427           0 :       nsIContent* content = mFrame ? mFrame->GetContent() : mContent;
    3428           0 :       accService->ContentRemoved(presShell, content);
    3429             : 
    3430             :       // Process children staying shown.
    3431           0 :       uint32_t visibleContentCount = mVisibleKidsOfHiddenElement.Length();
    3432           0 :       for (uint32_t idx = 0; idx < visibleContentCount; idx++) {
    3433           0 :         nsIContent* childContent = mVisibleKidsOfHiddenElement[idx];
    3434           0 :         accService->ContentRangeInserted(presShell, childContent->GetParent(),
    3435             :                                          childContent,
    3436           0 :                                          childContent->GetNextSibling());
    3437             :       }
    3438           0 :       mVisibleKidsOfHiddenElement.Clear();
    3439             :     }
    3440             :   }
    3441             : #endif
    3442        1192 : }
    3443             : 
    3444             : static void
    3445          61 : ClearCachedInheritedStyleDataOnDescendants(
    3446             :     nsTArray<ElementRestyler::ContextToClear>& aContextsToClear)
    3447             : {
    3448          94 :   for (size_t i = 0; i < aContextsToClear.Length(); i++) {
    3449          33 :     auto& entry = aContextsToClear[i];
    3450          33 :     if (!entry.mStyleContext->HasSingleReference()) {
    3451          32 :       entry.mStyleContext->AsGecko()->ClearCachedInheritedStyleDataOnDescendants(
    3452          32 :           entry.mStructs);
    3453             :     }
    3454          33 :     entry.mStyleContext = nullptr;
    3455             :   }
    3456          61 : }
    3457             : 
    3458             : void
    3459          61 : GeckoRestyleManager::ComputeAndProcessStyleChange(
    3460             :     nsIFrame*              aFrame,
    3461             :     nsChangeHint           aMinChange,
    3462             :     RestyleTracker&        aRestyleTracker,
    3463             :     nsRestyleHint          aRestyleHint,
    3464             :     const RestyleHintData& aRestyleHintData)
    3465             : {
    3466          61 :   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
    3467         122 :   nsStyleChangeList changeList(StyleBackendType::Gecko);
    3468         122 :   nsTArray<ElementRestyler::ContextToClear> contextsToClear;
    3469             : 
    3470             :   // swappedStructOwners needs to be kept alive until after
    3471             :   // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
    3472             :   // calls; see comment in ElementRestyler::Restyle.
    3473         122 :   nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
    3474             :   ElementRestyler::ComputeStyleChangeFor(aFrame, &changeList, aMinChange,
    3475             :                                          aRestyleTracker, aRestyleHint,
    3476             :                                          aRestyleHintData,
    3477          61 :                                          contextsToClear, swappedStructOwners);
    3478          61 :   ProcessRestyledFrames(changeList);
    3479          61 :   ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
    3480          61 : }
    3481             : 
    3482             : void
    3483           0 : GeckoRestyleManager::ComputeAndProcessStyleChange(
    3484             :     nsStyleContext*        aNewContext,
    3485             :     Element*               aElement,
    3486             :     nsChangeHint           aMinChange,
    3487             :     RestyleTracker&        aRestyleTracker,
    3488             :     nsRestyleHint          aRestyleHint,
    3489             :     const RestyleHintData& aRestyleHintData)
    3490             : {
    3491           0 :   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
    3492           0 :   MOZ_ASSERT(aNewContext->StyleDisplay()->mDisplay == StyleDisplay::Contents);
    3493           0 :   nsIFrame* frame = GetNearestAncestorFrame(aElement);
    3494           0 :   MOZ_ASSERT(frame, "display:contents node in map although it's a "
    3495             :                     "display:none descendant?");
    3496             :   TreeMatchContext treeMatchContext(true,
    3497             :                                     nsRuleWalker::eRelevantLinkUnvisited,
    3498           0 :                                     frame->PresContext()->Document());
    3499           0 :   nsIContent* parent = aElement->GetParent();
    3500             :   Element* parentElement =
    3501           0 :     parent && parent->IsElement() ? parent->AsElement() : nullptr;
    3502           0 :   treeMatchContext.InitAncestors(parentElement);
    3503             : 
    3504           0 :   nsTArray<nsCSSSelector*> selectorsForDescendants;
    3505           0 :   nsTArray<nsIContent*> visibleKidsOfHiddenElement;
    3506           0 :   nsTArray<ElementRestyler::ContextToClear> contextsToClear;
    3507             : 
    3508             :   // swappedStructOwners needs to be kept alive until after
    3509             :   // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
    3510             :   // calls; see comment in ElementRestyler::Restyle.
    3511           0 :   nsTArray<RefPtr<nsStyleContext>> swappedStructOwners;
    3512           0 :   nsStyleChangeList changeList(StyleBackendType::Gecko);
    3513             :   ElementRestyler r(frame->PresContext(), aElement, &changeList, aMinChange,
    3514             :                     aRestyleTracker, selectorsForDescendants, treeMatchContext,
    3515             :                     visibleKidsOfHiddenElement, contextsToClear,
    3516           0 :                     swappedStructOwners);
    3517             :   r.RestyleChildrenOfDisplayContentsElement(frame, aNewContext, aMinChange,
    3518             :                                             aRestyleTracker,
    3519           0 :                                             aRestyleHint, aRestyleHintData);
    3520           0 :   ProcessRestyledFrames(changeList);
    3521           0 :   ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
    3522           0 : }
    3523             : 
    3524             : nsStyleSet*
    3525        2170 : ElementRestyler::StyleSet() const
    3526             : {
    3527        2170 :   MOZ_ASSERT(mPresContext->StyleSet()->IsGecko(),
    3528             :              "ElementRestyler should only be used with a Gecko-flavored "
    3529             :              "style backend");
    3530        2170 :   return mPresContext->StyleSet()->AsGecko();
    3531             : }
    3532             : 
    3533        1671 : AutoDisplayContentsAncestorPusher::AutoDisplayContentsAncestorPusher(
    3534             :   TreeMatchContext& aTreeMatchContext, nsPresContext* aPresContext,
    3535        1671 :   nsIContent* aParent)
    3536             :   : mTreeMatchContext(aTreeMatchContext)
    3537        1671 :   , mPresContext(aPresContext)
    3538             : {
    3539        1671 :   if (aParent) {
    3540        1651 :     nsFrameManager* fm = mPresContext->FrameManager();
    3541             :     // Push display:contents mAncestors onto mTreeMatchContext.
    3542        1651 :     for (nsIContent* p = aParent; p && fm->GetDisplayContentsStyleFor(p);
    3543           0 :          p = p->GetParent()) {
    3544           0 :       mAncestors.AppendElement(p->AsElement());
    3545             :     }
    3546        1651 :     bool hasFilter = mTreeMatchContext.mAncestorFilter.HasFilter();
    3547        1651 :     nsTArray<mozilla::dom::Element*>::size_type i = mAncestors.Length();
    3548        1651 :     while (i--) {
    3549           0 :       if (hasFilter) {
    3550           0 :         mTreeMatchContext.mAncestorFilter.PushAncestor(mAncestors[i]);
    3551             :       }
    3552           0 :       mTreeMatchContext.PushStyleScope(mAncestors[i]);
    3553             :     }
    3554             :   }
    3555        1671 : }
    3556             : 
    3557        3342 : AutoDisplayContentsAncestorPusher::~AutoDisplayContentsAncestorPusher()
    3558             : {
    3559             :   // Pop the ancestors we pushed in the CTOR, if any.
    3560             :   typedef nsTArray<mozilla::dom::Element*>::size_type sz;
    3561        1671 :   sz len = mAncestors.Length();
    3562        1671 :   bool hasFilter = mTreeMatchContext.mAncestorFilter.HasFilter();
    3563        1671 :   for (sz i = 0; i < len; ++i) {
    3564           0 :     if (hasFilter) {
    3565           0 :       mTreeMatchContext.mAncestorFilter.PopAncestor();
    3566             :     }
    3567           0 :     mTreeMatchContext.PopStyleScope(mAncestors[i]);
    3568             :   }
    3569        1671 : }
    3570             : 
    3571             : #ifdef RESTYLE_LOGGING
    3572             : uint32_t
    3573         379 : GeckoRestyleManager::StructsToLog()
    3574             : {
    3575             :   static bool initialized = false;
    3576             :   static uint32_t structs;
    3577         379 :   if (!initialized) {
    3578           2 :     structs = 0;
    3579           2 :     const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
    3580           2 :     if (value) {
    3581           0 :       nsCString s(value);
    3582           0 :       while (!s.IsEmpty()) {
    3583           0 :         int32_t index = s.FindChar(',');
    3584             :         nsStyleStructID sid;
    3585             :         bool found;
    3586           0 :         if (index == -1) {
    3587           0 :           found = nsStyleContext::LookupStruct(s, sid);
    3588           0 :           s.Truncate();
    3589             :         } else {
    3590           0 :           found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
    3591           0 :           s = Substring(s, index + 1);
    3592             :         }
    3593           0 :         if (found) {
    3594           0 :           structs |= nsCachedStyleData::GetBitForSID(sid);
    3595             :         }
    3596             :       }
    3597             :     }
    3598           2 :     initialized = true;
    3599             :   }
    3600         379 :   return structs;
    3601             : }
    3602             : #endif
    3603             : 
    3604             : #ifdef DEBUG
    3605             : /* static */ nsCString
    3606           0 : GeckoRestyleManager::StructNamesToString(uint32_t aSIDs)
    3607             : {
    3608           0 :   nsCString result;
    3609           0 :   bool any = false;
    3610           0 :   for (nsStyleStructID sid = nsStyleStructID(0);
    3611           0 :        sid < nsStyleStructID_Length;
    3612           0 :        sid = nsStyleStructID(sid + 1)) {
    3613           0 :     if (aSIDs & nsCachedStyleData::GetBitForSID(sid)) {
    3614           0 :       if (any) {
    3615           0 :         result.AppendLiteral(",");
    3616             :       }
    3617           0 :       result.AppendPrintf("%s", nsStyleContext::StructName(sid));
    3618           0 :       any = true;
    3619             :     }
    3620             :   }
    3621           0 :   return result;
    3622             : }
    3623             : 
    3624             : /* static */ nsCString
    3625           0 : ElementRestyler::RestyleResultToString(RestyleResult aRestyleResult)
    3626             : {
    3627           0 :   nsCString result;
    3628           0 :   switch (aRestyleResult) {
    3629             :     case RestyleResult::eStop:
    3630           0 :       result.AssignLiteral("RestyleResult::eStop");
    3631           0 :       break;
    3632             :     case RestyleResult::eStopWithStyleChange:
    3633           0 :       result.AssignLiteral("RestyleResult::eStopWithStyleChange");
    3634           0 :       break;
    3635             :     case RestyleResult::eContinue:
    3636           0 :       result.AssignLiteral("RestyleResult::eContinue");
    3637           0 :       break;
    3638             :     case RestyleResult::eContinueAndForceDescendants:
    3639           0 :       result.AssignLiteral("RestyleResult::eContinueAndForceDescendants");
    3640           0 :       break;
    3641             :     default:
    3642           0 :       MOZ_ASSERT(aRestyleResult == RestyleResult::eNone,
    3643             :                  "Unexpected RestyleResult");
    3644             :   }
    3645           0 :   return result;
    3646             : }
    3647             : #endif
    3648             : 
    3649             : } // namespace mozilla

Generated by: LCOV version 1.13