Bug 1180118 - Part 2: Add eRestyle_SomeDescendants restyle hint and pass associated restyle hint data into restyle methods. r=bzbarsky
authorCameron McCormack <cam@mcc.id.au>
Wed, 05 Aug 2015 22:42:20 +1000
changeset 287957 fc5ff8a35475b7fcf9010b08673b24d335122b79
parent 287956 7b8dc7443e3a970fed752690b5e972ce79129a31
child 287958 d69928567288428833ed8e1322ff9952adc52995
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1180118
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1180118 - Part 2: Add eRestyle_SomeDescendants restyle hint and pass associated restyle hint data into restyle methods. r=bzbarsky
layout/base/RestyleManager.cpp
layout/base/RestyleManager.h
layout/base/RestyleTracker.cpp
layout/base/RestyleTracker.h
layout/base/nsChangeHint.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -976,21 +976,22 @@ RestyleManager::ProcessRestyledFrames(ns
 #endif
   }
 
   aChangeList.Clear();
   return NS_OK;
 }
 
 void
-RestyleManager::RestyleElement(Element*        aElement,
-                               nsIFrame*       aPrimaryFrame,
-                               nsChangeHint    aMinHint,
-                               RestyleTracker& aRestyleTracker,
-                               nsRestyleHint   aRestyleHint)
+RestyleManager::RestyleElement(Element*               aElement,
+                               nsIFrame*              aPrimaryFrame,
+                               nsChangeHint           aMinHint,
+                               RestyleTracker&        aRestyleTracker,
+                               nsRestyleHint          aRestyleHint,
+                               const RestyleHintData& aRestyleHintData)
 {
   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
   NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
                "frame/content mismatch");
   if (aPrimaryFrame && aPrimaryFrame->GetContent() != aElement) {
     // XXXbz this is due to image maps messing with the primary frame pointer
     // of <area>s.  See bug 135040.  We can remove this block once that's fixed.
     aPrimaryFrame = nullptr;
@@ -1017,33 +1018,34 @@ RestyleManager::RestyleElement(Element* 
     }
   }
 
   if (aMinHint & nsChangeHint_ReconstructFrame) {
     FrameConstructor()->RecreateFramesForContent(aElement, false,
       nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
   } else if (aPrimaryFrame) {
     ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
-                                 aRestyleHint);
+                                 aRestyleHint, aRestyleHintData);
   } else if (aRestyleHint & ~eRestyle_LaterSiblings) {
     // We're restyling an element with no frame, so we should try to
     // make one if its new style says it should have one.  But in order
     // to try to honor the restyle hint (which we'd like to do so that,
     // for example, an animation-only style flush doesn't flush other
     // buffered style changes), we only do this if the restyle hint says
     // we have *some* restyling for this frame.  This means we'll
     // potentially get ahead of ourselves in that case, but not as much
     // as we would if we didn't check the restyle hint.
     nsStyleContext* newContext =
       FrameConstructor()->MaybeRecreateFramesForElement(aElement);
     if (newContext &&
         newContext->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_CONTENTS) {
       // Style change for a display:contents node that did not recreate frames.
       ComputeAndProcessStyleChange(newContext, aElement, aMinHint,
-                                   aRestyleTracker, aRestyleHint);
+                                   aRestyleTracker, aRestyleHint,
+                                   aRestyleHintData);
     }
   }
 }
 
 RestyleManager::ReframingStyleContexts::ReframingStyleContexts(
                                           RestyleManager* aRestyleManager)
   : mRestyleManager(aRestyleManager)
   , mRestorePointer(mRestyleManager->mReframingStyleContexts)
@@ -1632,17 +1634,18 @@ RestyleManager::StartRebuildAllStyleData
   // root frame.  We can't do this with a change hint, since we can't
   // post a change hint for the root frame.
   // Note that we can ignore the return value of ComputeStyleChangeFor
   // because we never need to reframe the root frame.
   // XXX Does it matter that we're passing aExtraHint to the real root
   // frame and not the root node's primary frame?  (We could do
   // roughly what we do for aRestyleHint above.)
   ComputeAndProcessStyleChange(rootFrame,
-                               changeHint, aRestyleTracker, restyleHint);
+                               changeHint, aRestyleTracker, restyleHint,
+                               RestyleHintData());
 }
 
 void
 RestyleManager::FinishRebuildAllStyleData()
 {
   MOZ_ASSERT(mInRebuildAllStyleData, "bad caller");
 
   // Tell the style set it's safe to destroy the old rule tree.  We
@@ -1814,29 +1817,31 @@ RestyleManager::UpdateOnlyAnimationStyle
   ProcessRestyles(tracker);
 
   transitionManager->SetInAnimationOnlyStyleUpdate(false);
 }
 
 void
 RestyleManager::PostRestyleEvent(Element* aElement,
                                  nsRestyleHint aRestyleHint,
-                                 nsChangeHint aMinChangeHint)
+                                 nsChangeHint aMinChangeHint,
+                                 const RestyleHintData* aRestyleHintData)
 {
   if (MOZ_UNLIKELY(!mPresContext) ||
       MOZ_UNLIKELY(mPresContext->PresShell()->IsDestroying())) {
     return;
   }
 
   if (aRestyleHint == 0 && !aMinChangeHint) {
     // Nothing to do here
     return;
   }
 
-  mPendingRestyles.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint);
+  mPendingRestyles.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint,
+                                     aRestyleHintData);
 
   // Set mHavePendingNonAnimationRestyles for any restyle that could
   // possibly contain non-animation styles (i.e., those that require us
   // to do an animation-only style flush before processing style changes
   // to ensure correct initialization of CSS transitions).
   if (aRestyleHint & ~eRestyle_AllHintsWithAnimations) {
     mHavePendingNonAnimationRestyles = true;
   }
@@ -2737,16 +2742,17 @@ ElementRestyler::Restyle(nsRestyleHint a
 
   // List of descendant elements of mContent we know we will eventually need to
   // restyle.  Before we return from this function, we call
   // RestyleTracker::AddRestyleRootsIfAwaitingRestyle to ensure they get
   // restyled in RestyleTracker::DoProcessRestyles.
   nsTArray<nsRefPtr<Element>> descendants;
 
   nsRestyleHint hintToRestore = nsRestyleHint(0);
+  RestyleHintData hintDataToRestore;
   if (mContent && mContent->IsElement() &&
       // If we're resolving from the root of the frame tree (which
       // we do when mDoRebuildAllStyleData), we need to avoid getting the
       // root's restyle data until we get to its primary frame, since
       // it's the primary frame that has the styles for the root element
       // (rather than the ancestors of the primary frame whose mContent
       // is the root node but which have different styles).  If we use
       // up the hint for one of the ancestors that we hit first, then
@@ -2759,16 +2765,17 @@ ElementRestyler::Restyle(nsRestyleHint a
       mContent->GetPrimaryFrame() == mFrame) {
     mContent->OwnerDoc()->FlushPendingLinkUpdates();
     nsAutoPtr<RestyleTracker::RestyleData> restyleData;
     if (mRestyleTracker.GetRestyleData(mContent->AsElement(), restyleData)) {
       if (NS_UpdateHint(mHintsHandled, restyleData->mChangeHint)) {
         mChangeList->AppendChange(mFrame, mContent, restyleData->mChangeHint);
       }
       hintToRestore = restyleData->mRestyleHint;
+      hintDataToRestore = Move(restyleData->mRestyleHintData);
       aRestyleHint = nsRestyleHint(aRestyleHint | restyleData->mRestyleHint);
       descendants.SwapElements(restyleData->mDescendants);
     }
   }
 
   // If we are restyling this frame with eRestyle_Self or weaker hints,
   // we restyle children with nsRestyleHint(0).  But we pass the
   // eRestyle_ForceDescendants flag down too.
@@ -3581,21 +3588,22 @@ ElementRestyler::RestyleChildren(nsResty
   if (!(mHintsHandled & nsChangeHint_ReconstructFrame) &&
       mightReframePseudos) {
     MaybeReframeForAfterPseudo(lastContinuation);
   }
 }
 
 void
 ElementRestyler::RestyleChildrenOfDisplayContentsElement(
-  nsIFrame*       aParentFrame,
-  nsStyleContext* aNewContext,
-  nsChangeHint    aMinHint,
-  RestyleTracker& aRestyleTracker,
-  nsRestyleHint   aRestyleHint)
+  nsIFrame*              aParentFrame,
+  nsStyleContext*        aNewContext,
+  nsChangeHint           aMinHint,
+  RestyleTracker&        aRestyleTracker,
+  nsRestyleHint          aRestyleHint,
+  const RestyleHintData& aRestyleHintData)
 {
   MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame), "why call me?");
 
   const bool mightReframePseudos = aRestyleHint & eRestyle_Subtree;
   DoRestyleUndisplayedDescendants(nsRestyleHint(0), mContent, aNewContext);
   if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) {
     MaybeReframeForBeforePseudo(aParentFrame, nullptr, mContent, aNewContext);
   }
@@ -3614,34 +3622,35 @@ ElementRestyler::RestyleChildrenOfDispla
     for ( ; !lists.IsDone(); lists.Next()) {
       nsFrameList::Enumerator childFrames(lists.CurrentList());
       for (; !childFrames.AtEnd(); childFrames.Next()) {
         nsIFrame* f = childFrames.get();
         if (nsContentUtils::ContentIsDescendantOf(f->GetContent(), mContent) &&
             !f->GetPrevContinuation()) {
           if (!(f->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
             ComputeStyleChangeFor(f, mChangeList, aMinHint, aRestyleTracker,
-                                  aRestyleHint, mContextsToClear,
-                                  mSwappedStructOwners);
+                                  aRestyleHint, aRestyleHintData,
+                                  mContextsToClear, mSwappedStructOwners);
           }
         }
       }
     }
   }
   if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
     SendAccessibilityNotifications();
   }
 }
 
 void
 ElementRestyler::ComputeStyleChangeFor(nsIFrame*          aFrame,
                                        nsStyleChangeList* aChangeList,
                                        nsChangeHint       aMinChange,
                                        RestyleTracker&    aRestyleTracker,
                                        nsRestyleHint      aRestyleHint,
+                                       const RestyleHintData& aRestyleHintData,
                                        nsTArray<ContextToClear>&
                                          aContextsToClear,
                                        nsTArray<nsRefPtr<nsStyleContext>>&
                                          aSwappedStructOwners)
 {
   nsIContent* content = aFrame->GetContent();
   nsAutoCString idStr;
   if (profiler_is_active() && content) {
@@ -4085,42 +4094,45 @@ ClearCachedInheritedStyleDataOnDescendan
       entry.mStyleContext->ClearCachedInheritedStyleDataOnDescendants(
           entry.mStructs);
     }
     entry.mStyleContext = nullptr;
   }
 }
 
 void
-RestyleManager::ComputeAndProcessStyleChange(nsIFrame*          aFrame,
-                                             nsChangeHint       aMinChange,
-                                             RestyleTracker&    aRestyleTracker,
-                                             nsRestyleHint      aRestyleHint)
+RestyleManager::ComputeAndProcessStyleChange(nsIFrame*              aFrame,
+                                             nsChangeHint           aMinChange,
+                                             RestyleTracker&        aRestyleTracker,
+                                             nsRestyleHint          aRestyleHint,
+                                             const RestyleHintData& aRestyleHintData)
 {
   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
   nsStyleChangeList changeList;
   nsTArray<ElementRestyler::ContextToClear> contextsToClear;
 
   // swappedStructOwners needs to be kept alive until after
   // ProcessRestyledFrames and ClearCachedInheritedStyleDataOnDescendants
   // calls; see comment in ElementRestyler::Restyle.
   nsTArray<nsRefPtr<nsStyleContext>> swappedStructOwners;
   ElementRestyler::ComputeStyleChangeFor(aFrame, &changeList, aMinChange,
                                          aRestyleTracker, aRestyleHint,
+                                         aRestyleHintData,
                                          contextsToClear, swappedStructOwners);
   ProcessRestyledFrames(changeList);
   ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
 }
 
 void
-RestyleManager::ComputeAndProcessStyleChange(nsStyleContext*    aNewContext,
-                                             Element*           aElement,
-                                             nsChangeHint       aMinChange,
-                                             RestyleTracker&    aRestyleTracker,
-                                             nsRestyleHint      aRestyleHint)
+RestyleManager::ComputeAndProcessStyleChange(nsStyleContext*        aNewContext,
+                                             Element*               aElement,
+                                             nsChangeHint           aMinChange,
+                                             RestyleTracker&        aRestyleTracker,
+                                             nsRestyleHint          aRestyleHint,
+                                             const RestyleHintData& aRestyleHintData)
 {
   MOZ_ASSERT(mReframingStyleContexts, "should have rsc");
   MOZ_ASSERT(aNewContext->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_CONTENTS);
   nsIFrame* frame = GetNearestAncestorFrame(aElement);
   MOZ_ASSERT(frame, "display:contents node in map although it's a "
                     "display:none descendant?");
   TreeMatchContext treeMatchContext(true,
                                     nsRuleWalker::eRelevantLinkUnvisited,
@@ -4137,17 +4149,18 @@ RestyleManager::ComputeAndProcessStyleCh
   // calls; see comment in ElementRestyler::Restyle.
   nsTArray<nsRefPtr<nsStyleContext>> swappedStructOwners;
   nsStyleChangeList changeList;
   ElementRestyler r(frame->PresContext(), aElement, &changeList, aMinChange,
                     aRestyleTracker, treeMatchContext,
                     visibleKidsOfHiddenElement, contextsToClear,
                     swappedStructOwners);
   r.RestyleChildrenOfDisplayContentsElement(frame, aNewContext, aMinChange,
-                                            aRestyleTracker, aRestyleHint);
+                                            aRestyleTracker,
+                                            aRestyleHint, aRestyleHintData);
   ProcessRestyledFrames(changeList);
   ClearCachedInheritedStyleDataOnDescendants(contextsToClear);
 }
 
 AutoDisplayContentsAncestorPusher::AutoDisplayContentsAncestorPusher(
   TreeMatchContext& aTreeMatchContext, nsPresContext* aPresContext,
   nsIContent* aParent)
   : mTreeMatchContext(aTreeMatchContext)
@@ -4218,19 +4231,21 @@ RestyleManager::StructsToLog()
 }
 #endif
 
 /* static */ nsCString
 RestyleManager::RestyleHintToString(nsRestyleHint aHint)
 {
   nsCString result;
   bool any = false;
-  const char* names[] = { "Self", "Subtree", "LaterSiblings", "CSSTransitions",
-                          "CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
-                          "StyleAttribute_Animations", "Force", "ForceDescendants" };
+  const char* names[] = {
+    "Self", "SomeDescendants", "Subtree", "LaterSiblings", "CSSTransitions",
+    "CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
+    "StyleAttribute_Animations", "Force", "ForceDescendants"
+  };
   uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
   uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
   for (uint32_t i = 0; i < ArrayLength(names); i++) {
     if (hint & (1 << i)) {
       if (any) {
         result.AppendLiteral(" | ");
       }
       result.AppendPrintf("eRestyle_%s", names[i]);
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -124,26 +124,28 @@ public:
    * new position in the frame tree.
    *
    * @param aFrame the root of the subtree to reparent.  Must not be null.
    */
   nsresult ReparentStyleContext(nsIFrame* aFrame);
 
 private:
   // Used when restyling an element with a frame.
-  void ComputeAndProcessStyleChange(nsIFrame*       aFrame,
-                                    nsChangeHint    aMinChange,
-                                    RestyleTracker& aRestyleTracker,
-                                    nsRestyleHint   aRestyleHint);
+  void ComputeAndProcessStyleChange(nsIFrame*              aFrame,
+                                    nsChangeHint           aMinChange,
+                                    RestyleTracker&        aRestyleTracker,
+                                    nsRestyleHint          aRestyleHint,
+                                    const RestyleHintData& aRestyleHintData);
   // Used when restyling a display:contents element.
-  void ComputeAndProcessStyleChange(nsStyleContext* aNewContext,
-                                    Element*        aElement,
-                                    nsChangeHint    aMinChange,
-                                    RestyleTracker& aRestyleTracker,
-                                    nsRestyleHint   aRestyleHint);
+  void ComputeAndProcessStyleChange(nsStyleContext*        aNewContext,
+                                    Element*               aElement,
+                                    nsChangeHint           aMinChange,
+                                    RestyleTracker&        aRestyleTracker,
+                                    nsRestyleHint          aRestyleHint,
+                                    const RestyleHintData& aRestyleHintData);
 
 public:
 
 #ifdef DEBUG
   /**
    * DEBUG ONLY method to verify integrity of style tree versus frame tree
    */
   void DebugVerifyStyleTree(nsIFrame* aFrame);
@@ -330,20 +332,22 @@ public:
   /**
    * Notify the frame constructor that an element needs to have its
    * style recomputed.
    * @param aElement: The element to be restyled.
    * @param aRestyleHint: Which nodes need to have selector matching run
    *                      on them.
    * @param aMinChangeHint: A minimum change hint for aContent and its
    *                        descendants.
+   * @param aRestyleHintData: Additional data to go with aRestyleHint.
    */
   void PostRestyleEvent(Element* aElement,
                         nsRestyleHint aRestyleHint,
-                        nsChangeHint aMinChangeHint);
+                        nsChangeHint aMinChangeHint,
+                        const RestyleHintData* aRestyleHintData = nullptr);
 
   void PostRestyleEventForLazyConstruction()
   {
     PostRestyleEventInternal(true);
   }
 
   void FlushOverflowChangedTracker()
   {
@@ -418,17 +422,18 @@ public:
 
 private:
   /* aMinHint is the minimal change that should be made to the element */
   // XXXbz do we really need the aPrimaryFrame argument here?
   void RestyleElement(Element*        aElement,
                       nsIFrame*       aPrimaryFrame,
                       nsChangeHint    aMinHint,
                       RestyleTracker& aRestyleTracker,
-                      nsRestyleHint   aRestyleHint);
+                      nsRestyleHint   aRestyleHint,
+                      const RestyleHintData& aRestyleHintData);
 
   void StartRebuildAllStyleData(RestyleTracker& aRestyleTracker);
   void FinishRebuildAllStyleData();
 
   void StyleChangeReflow(nsIFrame* aFrame, nsChangeHint aHint);
 
   // Recursively add all the given frame and all children to the tracker.
   void AddSubtreeToOverflowTracker(nsIFrame* aFrame);
@@ -572,27 +577,30 @@ public:
   /**
    * Called from RestyleManager::ComputeAndProcessStyleChange to restyle
    * children of a display:contents element.
    */
   void RestyleChildrenOfDisplayContentsElement(nsIFrame*       aParentFrame,
                                                nsStyleContext* aNewContext,
                                                nsChangeHint    aMinHint,
                                                RestyleTracker& aRestyleTracker,
-                                               nsRestyleHint   aRestyleHint);
+                                               nsRestyleHint   aRestyleHint,
+                                               const RestyleHintData&
+                                                 aRestyleHintData);
 
   /**
    * Re-resolve the style contexts for a frame tree, building aChangeList
    * based on the resulting style changes, plus aMinChange applied to aFrame.
    */
   static void ComputeStyleChangeFor(nsIFrame*          aFrame,
                                     nsStyleChangeList* aChangeList,
                                     nsChangeHint       aMinChange,
                                     RestyleTracker&    aRestyleTracker,
                                     nsRestyleHint      aRestyleHint,
+                                    const RestyleHintData& aRestyleHintData,
                                     nsTArray<ContextToClear>& aContextsToClear,
                                     nsTArray<nsRefPtr<nsStyleContext>>&
                                       aSwappedStructOwners);
 
 #ifdef RESTYLE_LOGGING
   bool ShouldLogRestyle() {
     return RestyleManager::ShouldLogRestyle(mPresContext);
   }
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -164,16 +164,19 @@ CollectRestyles(nsISupports* aElement,
   element->UnsetFlags(collector->tracker->RestyleBit() |
                       collector->tracker->RootBit());
 
   RestyleEnumerateData** restyleArrayPtr = collector->restyleArrayPtr;
   RestyleEnumerateData* currentRestyle = *restyleArrayPtr;
   currentRestyle->mElement = element;
   currentRestyle->mRestyleHint = aData->mRestyleHint;
   currentRestyle->mChangeHint = aData->mChangeHint;
+  // We can move aData since we'll be clearing mPendingRestyles after
+  // we finish enumerating it.
+  currentRestyle->mRestyleHintData = Move(aData->mRestyleHintData);
 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
   currentRestyle->mBacktrace = Move(aData->mBacktrace);
 #endif
 
 #ifdef RESTYLE_LOGGING
   collector->count++;
 #endif
 
@@ -181,17 +184,18 @@ CollectRestyles(nsISupports* aElement,
   *restyleArrayPtr = currentRestyle + 1;
 
   return PL_DHASH_NEXT;
 }
 
 inline void
 RestyleTracker::ProcessOneRestyle(Element* aElement,
                                   nsRestyleHint aRestyleHint,
-                                  nsChangeHint aChangeHint)
+                                  nsChangeHint aChangeHint,
+                                  const RestyleHintData& aRestyleHintData)
 {
   NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
                   "Someone should have handled this before calling us");
   NS_PRECONDITION(Document(), "Must have a document");
   NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
                   "Element has unexpected document");
 
   LOG_RESTYLE("aRestyleHint = %s, aChangeHint = %s",
@@ -206,17 +210,17 @@ RestyleTracker::ProcessOneRestyle(Elemen
         RestyleManager::StructsToLog() != 0) {
       LOG_RESTYLE("style context tree before restyle:");
       LOG_RESTYLE_INDENT();
       primaryFrame->StyleContext()->LogStyleContextTree(
           LoggingDepth(), RestyleManager::StructsToLog());
     }
 #endif
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
-                                    *this, aRestyleHint);
+                                    *this, aRestyleHint, aRestyleHintData);
   } else if (aChangeHint &&
              (primaryFrame ||
               (aChangeHint & nsChangeHint_ReconstructFrame))) {
     // Don't need to recompute style; just apply the hint
     nsStyleChangeList changeList;
     changeList.AppendChange(primaryFrame, aElement, aChangeHint);
     mRestyleManager->ProcessRestyledFrames(changeList);
   }
@@ -362,17 +366,18 @@ RestyleTracker::DoProcessRestyles()
         }
 
 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
         Maybe<GeckoProfilerTracingRAII> profilerRAII;
         if (profiler_feature_active("restyle")) {
           profilerRAII.emplace("Paint", "Styles", Move(data->mBacktrace));
         }
 #endif
-        ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint);
+        ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint,
+                          data->mRestyleHintData);
         AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
 
         if (isTimelineRecording) {
           mozilla::UniquePtr<TimelineMarker> marker =
             MakeUnique<RestyleTimelineMarker>(docShell,
                                               TRACING_INTERVAL_END,
                                               data->mRestyleHint);
           TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
@@ -422,17 +427,18 @@ RestyleTracker::DoProcessRestyles()
               MakeUnique<RestyleTimelineMarker>(docShell,
                                                 TRACING_INTERVAL_START,
                                                 currentRestyle->mRestyleHint);
             TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
           }
 
           ProcessOneRestyle(currentRestyle->mElement,
                             currentRestyle->mRestyleHint,
-                            currentRestyle->mChangeHint);
+                            currentRestyle->mChangeHint,
+                            currentRestyle->mRestyleHintData);
 
           if (isTimelineRecording) {
             mozilla::UniquePtr<TimelineMarker> marker =
               MakeUnique<RestyleTimelineMarker>(docShell,
                                                 TRACING_INTERVAL_END,
                                                 currentRestyle->mRestyleHint);
             TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
           }
--- a/layout/base/RestyleTracker.h
+++ b/layout/base/RestyleTracker.h
@@ -253,17 +253,18 @@ public:
     return mPendingRestyles.Count();
   }
 
   /**
    * Add a restyle for the given element to the tracker.  Returns true
    * if the element already had eRestyle_LaterSiblings set on it.
    */
   bool AddPendingRestyle(Element* aElement, nsRestyleHint aRestyleHint,
-                         nsChangeHint aMinChangeHint);
+                         nsChangeHint aMinChangeHint,
+                         const RestyleHintData* aRestyleHintData = nullptr);
 
   /**
    * Process the restyles we've been tracking.
    */
   void DoProcessRestyles();
 
   // Return our ELEMENT_HAS_PENDING_(ANIMATION_)RESTYLE bit
   uint32_t RestyleBit() const {
@@ -271,29 +272,34 @@ public:
   }
 
   // Return our ELEMENT_IS_POTENTIAL_(ANIMATION_)RESTYLE_ROOT bit
   Element::FlagsType RootBit() const {
     return mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS;
   }
 
   struct Hints {
-    nsRestyleHint mRestyleHint;       // What we want to restyle
-    nsChangeHint mChangeHint;         // The minimal change hint for "self"
+    nsRestyleHint mRestyleHint;        // What we want to restyle
+    nsChangeHint mChangeHint;          // The minimal change hint for "self"
+    RestyleHintData mRestyleHintData;  // Data associated with mRestyleHint
   };
 
   struct RestyleData : Hints {
     RestyleData() {
       mRestyleHint = nsRestyleHint(0);
       mChangeHint = NS_STYLE_HINT_NONE;
     }
 
-    RestyleData(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint) {
+    RestyleData(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint,
+                const RestyleHintData* aRestyleHintData) {
       mRestyleHint = aRestyleHint;
       mChangeHint = aChangeHint;
+      if (aRestyleHintData) {
+        mRestyleHintData = *aRestyleHintData;
+      }
     }
 
     // Descendant elements we must check that we ended up restyling, ordered
     // with the same invariant as mRestyleRoots.  The elements here are those
     // that we called AddPendingRestyle for and found the element this is
     // the RestyleData for as its nearest restyle root.
     nsTArray<nsRefPtr<Element>> mDescendants;
 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
@@ -336,26 +342,28 @@ public:
 #ifdef RESTYLE_LOGGING
   // Defined in RestyleTrackerInlines.h.
   inline bool ShouldLogRestyle();
   inline int32_t& LoggingDepth();
 #endif
 
 private:
   bool AddPendingRestyleToTable(Element* aElement, nsRestyleHint aRestyleHint,
-                                nsChangeHint aMinChangeHint);
+                                nsChangeHint aMinChangeHint,
+                                const RestyleHintData* aRestyleHintData = nullptr);
 
   /**
    * Handle a single mPendingRestyles entry.  aRestyleHint must not
    * include eRestyle_LaterSiblings; that needs to be dealt with
    * before calling this function.
    */
   inline void ProcessOneRestyle(Element* aElement,
                                 nsRestyleHint aRestyleHint,
-                                nsChangeHint aChangeHint);
+                                nsChangeHint aChangeHint,
+                                const RestyleHintData& aRestyleHintData);
 
   typedef nsClassHashtable<nsISupportsHashKey, RestyleData> PendingRestyleTable;
   typedef nsAutoTArray< nsRefPtr<Element>, 32> RestyleRootArray;
   // Our restyle bits.  These will be a subset of ELEMENT_ALL_RESTYLE_FLAGS, and
   // will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS and one flag
   // that's not in ELEMENT_PENDING_RESTYLE_FLAGS.
   Element::FlagsType mRestyleBits;
   RestyleManager* mRestyleManager; // Owns us
@@ -376,57 +384,65 @@ private:
   // flag.  We need this to avoid enumerating the hashtable looking
   // for such entries when we can't possibly have any.
   bool mHaveLaterSiblingRestyles;
 };
 
 inline bool
 RestyleTracker::AddPendingRestyleToTable(Element* aElement,
                                          nsRestyleHint aRestyleHint,
-                                         nsChangeHint aMinChangeHint)
+                                         nsChangeHint aMinChangeHint,
+                                         const RestyleHintData* aRestyleHintData)
 {
   RestyleData* existingData;
 
   // Check the RestyleBit() flag before doing the hashtable Get, since
   // it's possible that the data in the hashtable isn't actually
   // relevant anymore (if the flag is not set).
   if (aElement->HasFlag(RestyleBit())) {
     mPendingRestyles.Get(aElement, &existingData);
   } else {
     aElement->SetFlags(RestyleBit());
     existingData = nullptr;
   }
 
   if (!existingData) {
-    RestyleData* rd = new RestyleData(aRestyleHint, aMinChangeHint);
+    RestyleData* rd =
+      new RestyleData(aRestyleHint, aMinChangeHint, aRestyleHintData);
 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
     if (profiler_feature_active("restyle")) {
       rd->mBacktrace.reset(profiler_get_backtrace());
     }
 #endif
     mPendingRestyles.Put(aElement, rd);
     return false;
   }
 
   bool hadRestyleLaterSiblings =
     (existingData->mRestyleHint & eRestyle_LaterSiblings) != 0;
   existingData->mRestyleHint =
     nsRestyleHint(existingData->mRestyleHint | aRestyleHint);
   NS_UpdateHint(existingData->mChangeHint, aMinChangeHint);
+  if (aRestyleHintData) {
+    existingData->mRestyleHintData.mSelectorsForDescendants
+      .AppendElements(aRestyleHintData->mSelectorsForDescendants);
+  }
 
   return hadRestyleLaterSiblings;
 }
 
 inline bool
 RestyleTracker::AddPendingRestyle(Element* aElement,
                                   nsRestyleHint aRestyleHint,
-                                  nsChangeHint aMinChangeHint)
+                                  nsChangeHint aMinChangeHint,
+                                  const RestyleHintData* aRestyleHintData)
 {
   bool hadRestyleLaterSiblings =
-    AddPendingRestyleToTable(aElement, aRestyleHint, aMinChangeHint);
+    AddPendingRestyleToTable(aElement, aRestyleHint, aMinChangeHint,
+                             aRestyleHintData);
 
   // We can only treat this element as a restyle root if we would
   // actually restyle its descendants (so either call
   // ReResolveStyleContext on it or just reframe it).
   if ((aRestyleHint & ~eRestyle_LaterSiblings) ||
       (aMinChangeHint & nsChangeHint_ReconstructFrame)) {
     Element* cur = aElement;
     while (!cur->HasFlag(RootBit())) {
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -3,18 +3,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* constants for what needs to be recomputed in response to style changes */
 
 #ifndef nsChangeHint_h___
 #define nsChangeHint_h___
 
+#include "mozilla/Types.h"
 #include "nsDebug.h"
-#include "mozilla/Types.h"
+#include "nsTArray.h"
+
+struct nsCSSSelector;
 
 // Defines for various style related constants
 
 enum nsChangeHint {
   // change was visual only (e.g., COLOR=)
   // Invalidates all descendant frames (including following
   // placeholders to out-of-flow frames).
   nsChangeHint_RepaintFrame = 0x01,
@@ -372,72 +375,76 @@ inline nsChangeHint NS_HintsNotHandledFo
  */
 enum nsRestyleHint {
   // Rerun selector matching on the element.  If a new style context
   // results, update the style contexts of descendants.  (Irrelevant if
   // eRestyle_Subtree is also set, since that implies a superset of the
   // work.)
   eRestyle_Self = (1<<0),
 
+  // Rerun selector matching on descendants of the element that match
+  // a given selector.
+  eRestyle_SomeDescendants = (1<<1),
+
   // Rerun selector matching on the element and all of its descendants.
   // (Implies eRestyle_ForceDescendants, which ensures that we continue
   // the restyling process for all descendants, but doesn't cause
   // selector matching.)
-  eRestyle_Subtree = (1<<1),
+  eRestyle_Subtree = (1<<2),
 
   // Rerun selector matching on all later siblings of the element and
   // all of their descendants.
-  eRestyle_LaterSiblings = (1<<2),
+  eRestyle_LaterSiblings = (1<<3),
 
   // Replace the style data coming from CSS transitions without updating
   // any other style data.  If a new style context results, update style
   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
   // eRestyle_Subtree is also set, since those imply a superset of the
   // work.)
-  eRestyle_CSSTransitions = (1<<3),
+  eRestyle_CSSTransitions = (1<<4),
 
   // Replace the style data coming from CSS animations without updating
   // any other style data.  If a new style context results, update style
   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
   // eRestyle_Subtree is also set, since those imply a superset of the
   // work.)
-  eRestyle_CSSAnimations = (1<<4),
+  eRestyle_CSSAnimations = (1<<5),
 
   // Replace the style data coming from SVG animations (SMIL Animations)
   // without updating any other style data.  If a new style context
   // results, update style contexts on the descendants.  (Irrelevant if
   // eRestyle_Self or eRestyle_Subtree is also set, since those imply a
   // superset of the work.)
-  eRestyle_SVGAttrAnimations = (1<<5),
+  eRestyle_SVGAttrAnimations = (1<<6),
 
   // Replace the style data coming from inline style without updating
   // any other style data.  If a new style context results, update style
   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
   // eRestyle_Subtree is also set, since those imply a superset of the
   // work.)  Supported only for element style contexts and not for
   // pseudo-elements or anonymous boxes, on which it converts to
   // eRestyle_Self.
   // If the change is for the advance of a declarative animation, use
   // the value below instead.
-  eRestyle_StyleAttribute = (1<<6),
+  eRestyle_StyleAttribute = (1<<7),
 
   // Same as eRestyle_StyleAttribute, but for when the change results
   // from the advance of a declarative animation.
-  eRestyle_StyleAttribute_Animations = (1<<7),
+  eRestyle_StyleAttribute_Animations = (1<<8),
 
   // Continue the restyling process to the current frame's children even
   // if this frame's restyling resulted in no style changes.
-  eRestyle_Force = (1<<8),
+  eRestyle_Force = (1<<9),
 
   // Continue the restyling process to all of the current frame's
   // descendants, even if any frame's restyling resulted in no style
   // changes.  (Implies eRestyle_Force.)  Note that this is weaker than
   // eRestyle_Subtree, which makes us rerun selector matching on all
   // descendants rather than just continuing the restyling process.
-  eRestyle_ForceDescendants = (1<<9),
+  eRestyle_ForceDescendants = (1<<10),
 
   // Useful unions:
   eRestyle_AllHintsWithAnimations = eRestyle_CSSTransitions |
                                     eRestyle_CSSAnimations |
                                     eRestyle_SVGAttrAnimations |
                                     eRestyle_StyleAttribute_Animations,
 };
 
@@ -478,9 +485,24 @@ inline nsRestyleHint operator^(nsRestyle
                        nsRestyleHint_size_t(aRight));
 }
 
 inline nsRestyleHint operator^=(nsRestyleHint& aLeft, nsRestyleHint aRight)
 {
   return aLeft = aLeft ^ aRight;
 }
 
+namespace mozilla {
+
+/**
+ * Additional data used in conjunction with an nsRestyleHint to control the
+ * restyle process.
+ */
+struct RestyleHintData
+{
+  // When eRestyle_SomeDescendants is used, this array contains the selectors
+  // that identify which descendants will be restyled.
+  nsTArray<nsCSSSelector*> mSelectorsForDescendants;
+};
+
+} // namespace mozilla
+
 #endif /* nsChangeHint_h___ */