Bug 704911. Don't restyle based on state selectors that match our node but don't depend on the state that's changing. r=dbaron

This commit is contained in:
Boris Zbarsky 2011-12-05 23:58:15 -05:00
parent 3687e2d7b5
commit fd8c7db48c
6 changed files with 65 additions and 14 deletions

View File

@ -0,0 +1 @@
== state-dependent-in-any.html state-dependent-in-any-ref.html

View File

@ -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>

View File

@ -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>

View File

@ -92,6 +92,9 @@ 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

View File

@ -899,7 +899,7 @@ struct RuleCascadeData {
RuleHash mRuleHash;
RuleHash*
mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount];
nsTArray<nsCSSSelector*> mStateSelectors;
nsTArray<nsCSSRuleProcessor::StateSelector> mStateSelectors;
nsEventStates mSelectorDocumentStates;
PLDHashTable mClassSelectors;
PLDHashTable mIdSelectors;
@ -2367,22 +2367,26 @@ nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
// 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,
@ -2620,11 +2624,13 @@ nsCSSRuleProcessor::ClearRuleCascades()
}
// 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
@ -2632,11 +2638,9 @@ bool IsStateSelector(nsCSSSelector& aSelector)
if (pseudoClass->mType >= nsCSSPseudoClasses::ePseudoClass_Count) {
continue;
}
if (!sPseudoClassStates[pseudoClass->mType].IsEmpty()) {
return true;
}
states |= sPseudoClassStates[pseudoClass->mType];
}
return false;
return states;
}
static bool
@ -2684,8 +2688,12 @@ AddSelector(RuleCascadeData* aCascade,
}
// 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) {

View File

@ -51,12 +51,14 @@
#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
@ -161,6 +163,16 @@ public:
}
#endif
struct StateSelector {
StateSelector(nsEventStates aStates, nsCSSSelector* aSelector)
: mStates(aStates),
mSelector(aSelector)
{}
nsEventStates mStates;
nsCSSSelector* mSelector;
};
private:
static bool CascadeSheet(nsCSSStyleSheet* aSheet, CascadeEnumData* aData);