Bug 758885. Don't apply the dynamic :hover reresolution skipping optimization to selectors which can match on mutable state other than :hover. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 29 May 2012 00:17:45 -0400
changeset 99210 6aa5239fe656e06756662f53f589b377280f4a36
parent 99209 545eb36e72077660313a46aca1d4fe709ea60c52
child 99211 76791f5996ccd6ea78b183d675b35fb66d42da92
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs758885
milestone15.0a1
Bug 758885. Don't apply the dynamic :hover reresolution skipping optimization to selectors which can match on mutable state other than :hover. r=dbaron
layout/base/nsCSSFrameConstructor.cpp
layout/style/nsCSSRuleProcessor.cpp
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8087,24 +8087,19 @@ nsCSSFrameConstructor::ContentStateChang
           }
         }
       }
     }
 
     primaryFrame->ContentStatesChanged(aStateMask);
   }
 
-  if (aStateMask.HasState(NS_EVENT_STATE_HOVER) &&
-      !aElement->HasFlag(NODE_HAS_RELEVANT_HOVER_RULES)) {
-    aStateMask &= ~NS_EVENT_STATE_HOVER;
-  }
-
-  nsRestyleHint rshint = aStateMask.IsEmpty() ?
-      nsRestyleHint(0) :
-      styleSet->HasStateDependentStyle(presContext, aElement, aStateMask);
+
+  nsRestyleHint rshint = 
+    styleSet->HasStateDependentStyle(presContext, aElement, aStateMask);
       
   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.
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2386,16 +2386,34 @@ nsCSSRuleProcessor::HasStateDependentSty
 
       // If hint already includes all the bits of possibleChange,
       // don't bother calling SelectorMatches, since even if it returns false
       // hint won't change.
       // Also don't bother calling SelectorMatches if none of the
       // states passed in are relevant here.
       if ((possibleChange & ~hint) &&
           states.HasAtLeastOneOfStates(aData->mStateMask) &&
+          // We can optimize away testing selectors that only involve :hover, a
+          // namespace, and a tag name against nodes that don't have the
+          // NODE_HAS_RELEVANT_HOVER_RULES flag: such a selector didn't match
+          // the tag name or namespace the first time around (since the :hover
+          // didn't set the NODE_HAS_RELEVANT_HOVER_RULES flag), so it won't
+          // match it now.  Check for our selector only having :hover states, or
+          // the element having the hover rules flag, or the selector having
+          // some sort of non-namespace, non-tagname data in it.
+          (states != NS_EVENT_STATE_HOVER ||
+           aData->mElement->HasFlag(NODE_HAS_RELEVANT_HOVER_RULES) ||
+           selector->mIDList || selector->mClassList ||
+           // We generally expect an mPseudoClassList, since we have a :hover.
+           // The question is whether we have anything else in there.
+           (selector->mPseudoClassList &&
+            (selector->mPseudoClassList->mNext ||
+             selector->mPseudoClassList->mType !=
+               nsCSSPseudoClasses::ePseudoClass_hover)) ||
+           selector->mAttrList || selector->mNegations) &&
           SelectorMatches(aData->mElement, selector, nodeContext,
                           aData->mTreeMatchContext) &&
           SelectorMatchesTree(aData->mElement, selector->mNext,
                               aData->mTreeMatchContext,
                               false))
       {
         hint = nsRestyleHint(hint | possibleChange);
       }