author | Boris Zbarsky <bzbarsky@mit.edu> |
Mon, 05 Dec 2011 23:58:15 -0500 | |
changeset 81476 | 5c0c7af66ec01e965d68cb42c670160bdfa64462 |
parent 81475 | 85358854403fbd5c6b1731e2eda2722deea51d98 |
child 81477 | b30a2262608de91f296adfefd12cbfffb33cb785 |
push id | 3836 |
push user | bzbarsky@mozilla.com |
push date | Tue, 06 Dec 2011 04:59:05 +0000 |
treeherder | mozilla-inbound@5c0c7af66ec0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dbaron |
bugs | 704911 |
milestone | 11.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
|
new file mode 100644 --- /dev/null +++ b/layout/reftests/css-selectors/reftest.list @@ -0,0 +1,1 @@ +== state-dependent-in-any.html state-dependent-in-any-ref.html
new file mode 100644 --- /dev/null +++ b/layout/reftests/css-selectors/state-dependent-in-any-ref.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> + <head> + <style> + span { color: green; } + </style> + </head> + <body> + <input value="Test"><span>This should be green</span> + </body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/css-selectors/state-dependent-in-any.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <head> + <style> + span { color: red; } + :-moz-any(:valid) + span { color: green; } + </style> + </head> + <body> + <input required><span>This should be green</span> + <script> + document.body.offsetWidth; + document.getElementsByTagName("input")[0].value = "Test" + </script> + </body> +</html>
--- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -87,16 +87,19 @@ skip-if(Android) include css-valid/refte skip-if(Android) include css-invalid/reftest.list # css-submit-invalid include css-submit-invalid/reftest.list # css text-overflow include text-overflow/reftest.list +# css selectors +include css-selectors/reftest.list + # css transitions include css-transitions/reftest.list # css :-moz-ui-invalid skip-if(Android) include css-ui-invalid/reftest.list # css :-moz-ui-valid skip-if(Android) include css-ui-valid/reftest.list
--- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -894,17 +894,17 @@ struct RuleCascadeData { } } PRInt64 SizeOf() const; RuleHash mRuleHash; RuleHash* mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount]; - nsTArray<nsCSSSelector*> mStateSelectors; + nsTArray<nsCSSRuleProcessor::StateSelector> mStateSelectors; nsEventStates mSelectorDocumentStates; PLDHashTable mClassSelectors; PLDHashTable mIdSelectors; nsTArray<nsCSSSelector*> mPossiblyNegatedClassSelectors; nsTArray<nsCSSSelector*> mPossiblyNegatedIDSelectors; PLDHashTable mAttributeSelectors; PLDHashTable mAnonBoxRules; #ifdef MOZ_XUL @@ -2362,32 +2362,36 @@ nsCSSRuleProcessor::HasStateDependentSty RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext); // Look up the content node in the state rule list, which points to // any (CSS2 definition) simple selector (whether or not it is the // subject) that has a state pseudo-class on it. This means that this // code will be matching selectors that aren't real selectors in any // stylesheet (e.g., if there is a selector "body > p:hover > a", then // "body > p:hover" will be in |cascade->mStateSelectors|). Note that - // |IsStateSelector| below determines which selectors are in + // |ComputeSelectorStateDependence| below determines which selectors are in // |cascade->mStateSelectors|. nsRestyleHint hint = nsRestyleHint(0); if (cascade) { - nsCSSSelector **iter = cascade->mStateSelectors.Elements(), - **end = iter + cascade->mStateSelectors.Length(); + StateSelector *iter = cascade->mStateSelectors.Elements(), + *end = iter + cascade->mStateSelectors.Length(); NodeMatchContext nodeContext(aData->mStateMask, false); for(; iter != end; ++iter) { - nsCSSSelector* selector = *iter; + nsCSSSelector* selector = iter->mSelector; + nsEventStates states = iter->mStates; nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator); // 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) && SelectorMatches(aData->mElement, selector, nodeContext, aData->mTreeMatchContext) && SelectorMatchesTree(aData->mElement, selector->mNext, aData->mTreeMatchContext, false)) { hint = nsRestyleHint(hint | possibleChange); } @@ -2615,33 +2619,33 @@ nsCSSRuleProcessor::ClearRuleCascades() RuleCascadeData *next = data->mNext; delete data; data = next; } return NS_OK; } -// This function should return true only for selectors that need to be -// checked by |HasStateDependentStyle|. +// This function should return the set of states that this selector +// depends on; this is used to implement HasStateDependentStyle. It +// does NOT recur down into things like :not and :-moz-any. inline -bool IsStateSelector(nsCSSSelector& aSelector) +nsEventStates ComputeSelectorStateDependence(nsCSSSelector& aSelector) { + nsEventStates states; for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList; pseudoClass; pseudoClass = pseudoClass->mNext) { // Tree pseudo-elements overload mPseudoClassList for things that // aren't pseudo-classes. if (pseudoClass->mType >= nsCSSPseudoClasses::ePseudoClass_Count) { continue; } - if (!sPseudoClassStates[pseudoClass->mType].IsEmpty()) { - return true; - } + states |= sPseudoClassStates[pseudoClass->mType]; } - return false; + return states; } static bool AddSelector(RuleCascadeData* aCascade, // The part between combinators at the top level of the selector nsCSSSelector* aSelectorInTopLevel, // The part we should look through (might be in :not or :-moz-any()) nsCSSSelector* aSelectorPart) @@ -2679,18 +2683,22 @@ AddSelector(RuleCascadeData* aCascade, } default: { break; } } } // Build mStateSelectors. - if (IsStateSelector(*negation)) - aCascade->mStateSelectors.AppendElement(aSelectorInTopLevel); + nsEventStates dependentStates = ComputeSelectorStateDependence(*negation); + if (!dependentStates.IsEmpty()) { + aCascade->mStateSelectors.AppendElement( + nsCSSRuleProcessor::StateSelector(dependentStates, + aSelectorInTopLevel)); + } // Build mIDSelectors if (negation == aSelectorInTopLevel) { for (nsAtomList* curID = negation->mIDList; curID; curID = curID->mNext) { AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>(PL_DHashTableOperate(&aCascade->mIdSelectors, curID->mAtom,
--- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -46,22 +46,24 @@ #define nsCSSRuleProcessor_h_ #include "nsIStyleRuleProcessor.h" #include "nsCSSStyleSheet.h" #include "nsTArray.h" #include "nsAutoPtr.h" #include "nsCSSRules.h" #include "nsRuleWalker.h" +#include "nsEventStates.h" struct RuleCascadeData; struct nsCSSSelectorList; struct CascadeEnumData; struct TreeMatchContext; class nsCSSKeyframesRule; +class nsCSSSelector; /** * The CSS style rule processor provides a mechanism for sibling style * sheets to combine their rule processing in order to allow proper * cascading to happen. * * CSS style rule processors keep a live reference on all style sheets * bound to them. The CSS style sheets keep a weak reference to all the @@ -156,16 +158,26 @@ public: #ifdef XP_WIN // Cached theme identifier for the moz-windows-theme media query. static PRUint8 GetWindowsThemeIdentifier(); static void SetWindowsThemeIdentifier(PRUint8 aId) { sWinThemeId = aId; } #endif + struct StateSelector { + StateSelector(nsEventStates aStates, nsCSSSelector* aSelector) + : mStates(aStates), + mSelector(aSelector) + {} + + nsEventStates mStates; + nsCSSSelector* mSelector; + }; + private: static bool CascadeSheet(nsCSSStyleSheet* aSheet, CascadeEnumData* aData); RuleCascadeData* GetRuleCascade(nsPresContext* aPresContext); void RefreshRuleCascade(nsPresContext* aPresContext); // The sheet order here is the same as in nsStyleSet::mSheets sheet_array_type mSheets;