Bug 922669 - Part 9: Restyle pseudo-elements when their content state changes. r=bz
authorCameron McCormack <cam@mcc.id.au>
Thu, 28 Nov 2013 17:46:40 +1100
changeset 157874 2c0cdf0d2c845a5bb930fbcda4fcb1af26bdf3ee
parent 157873 78c9cc1869676256f91d47ad722864bd81adc705
child 157875 00c87bd8f8aadd2500a66031f844074ebfe5b607
push id36877
push usercmccormack@mozilla.com
push dateThu, 28 Nov 2013 06:47:44 +0000
treeherdermozilla-inbound@3f7925e3933b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs922669
milestone28.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 922669 - Part 9: Restyle pseudo-elements when their content state changes. r=bz
layout/base/RestyleManager.cpp
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -819,16 +819,21 @@ RestyleManager::RestyleElement(Element* 
                           aRestyleTracker, aRestyleDescendants);
     ProcessRestyledFrames(changeList);
   } else {
     // no frames, reconstruct for content
     FrameConstructor()->MaybeRecreateFramesForElement(aElement);
   }
 }
 
+static inline dom::Element*
+ElementForStyleContext(nsIContent* aParentContent,
+                       nsIFrame* aFrame,
+                       nsCSSPseudoElements::Type aPseudoType);
+
 // Forwarded nsIDocumentObserver method, to handle restyling (and
 // passing the notification to the frame).
 nsresult
 RestyleManager::ContentStateChanged(nsIContent* aContent,
                                     nsEventStates aStateMask)
 {
   // XXXbz it would be good if this function only took Elements, but
   // we'd have to make ESM guarantee that usefully.
@@ -844,16 +849,18 @@ RestyleManager::ContentStateChanged(nsIC
   nsChangeHint hint = NS_STYLE_HINT_NONE;
   // Any change to a content state that affects which frames we construct
   // must lead to a frame reconstruct here if we already have a frame.
   // Note that we never decide through non-CSS means to not create frames
   // based on content states, so if we already don't have a frame we don't
   // need to force a reframe -- if it's needed, the HasStateDependentStyle
   // call will handle things.
   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
+  nsCSSPseudoElements::Type pseudoType =
+    nsCSSPseudoElements::ePseudo_NotPseudoElement;
   if (primaryFrame) {
     // If it's generated content, ignore LOADING/etc state changes on it.
     if (!primaryFrame->IsGeneratedContentFrame() &&
         aStateMask.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
                                          NS_EVENT_STATE_USERDISABLED |
                                          NS_EVENT_STATE_SUPPRESSED |
                                          NS_EVENT_STATE_LOADING)) {
       hint = nsChangeHint_ReconstructFrame;
@@ -867,22 +874,39 @@ RestyleManager::ContentStateChanged(nsIC
           theme->WidgetStateChanged(primaryFrame, app, nullptr, &repaint);
           if (repaint) {
             NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
           }
         }
       }
     }
 
+    pseudoType = primaryFrame->StyleContext()->GetPseudoType();
+
     primaryFrame->ContentStatesChanged(aStateMask);
   }
 
 
-  nsRestyleHint rshint =
-    styleSet->HasStateDependentStyle(mPresContext, aElement, aStateMask);
+  nsRestyleHint rshint;
+
+  if (pseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
+    rshint = styleSet->HasStateDependentStyle(mPresContext, aElement,
+                                              aStateMask);
+  } else if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(
+                                                                  pseudoType)) {
+    // If aElement is a pseudo-element, we want to check to see whether there
+    // are any state-dependent rules applying to that pseudo.
+    Element* ancestor = ElementForStyleContext(nullptr, primaryFrame,
+                                               pseudoType);
+    rshint = styleSet->HasStateDependentStyle(mPresContext, ancestor,
+                                              pseudoType, aElement,
+                                              aStateMask);
+  } else {
+    rshint = nsRestyleHint(0);
+  }
 
   if (aStateMask.HasState(NS_EVENT_STATE_HOVER) && rshint != 0) {
     ++mHoverGeneration;
   }
 
   if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
     // Exposing information to the page about whether the link is
     // visited or not isn't really something we can worry about here.
@@ -2360,16 +2384,17 @@ ElementRestyler::RestyleSelf(nsIFrame* a
         // all.
         NS_ASSERTION(pseudoType <
                        nsCSSPseudoElements::ePseudo_PseudoElementCount,
                      "Unexpected pseudo type");
         Element* pseudoElement =
           nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(pseudoTag) ||
           nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoTag) ?
             aSelf->GetContent()->AsElement() : nullptr;
+        MOZ_ASSERT(element != pseudoElement);
         newContext = styleSet->ResolvePseudoElementStyle(element,
                                                          pseudoType,
                                                          parentContext,
                                                          pseudoElement);
       }
     }
     else {
       NS_ASSERTION(aSelf->GetContent(),