Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (176151 => 176152)
--- trunk/Source/WebCore/css/SelectorChecker.cpp 2014-11-15 02:31:28 UTC (rev 176151)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp 2014-11-15 02:32:37 UTC (rev 176152)
@@ -173,15 +173,16 @@
bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext, unsigned& specificity) const
{
+ specificity = 0;
+
CheckingContextWithStatus context(providedContext, selector, element);
PseudoIdSet pseudoIdSet;
- MatchResult result = matchRecursively(context, pseudoIdSet);
+ MatchResult result = matchRecursively(context, pseudoIdSet, specificity);
if (result.match != Match::SelectorMatches)
return false;
if (context.pseudoId != NOPSEUDO && !pseudoIdSet.has(context.pseudoId))
return false;
- specificity = selector->specificity();
if (context.pseudoId == NOPSEUDO && pseudoIdSet) {
PseudoIdSet publicPseudoIdSet = pseudoIdSet & PseudoIdSet::fromMask(PUBLIC_PSEUDOID_MASK);
if (context.resolvingMode == Mode::ResolvingStyle && publicPseudoIdSet)
@@ -221,12 +222,12 @@
// * SelectorFailsLocally - the selector fails for the element e
// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
-SelectorChecker::MatchResult SelectorChecker::matchRecursively(const CheckingContextWithStatus& context, PseudoIdSet& dynamicPseudoIdSet) const
+SelectorChecker::MatchResult SelectorChecker::matchRecursively(const CheckingContextWithStatus& context, PseudoIdSet& dynamicPseudoIdSet, unsigned& specificity) const
{
MatchType matchType = MatchType::Element;
// The first selector has to match.
- if (!checkOne(context, dynamicPseudoIdSet, matchType))
+ if (!checkOne(context, dynamicPseudoIdSet, matchType, specificity))
return MatchResult::fails(Match::SelectorFailsLocally);
if (context.selector->match() == CSSSelector::PseudoElement) {
@@ -289,8 +290,13 @@
nextContext.elementStyle = nullptr;
for (; nextContext.element; nextContext = checkingContextForParent(nextContext)) {
PseudoIdSet ignoreDynamicPseudo;
- MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
+ unsigned descendantsSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, descendantsSpecificity);
ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, descendantsSpecificity);
+
if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
return MatchResult::updateWithMatchType(result, matchType);
}
@@ -304,8 +310,13 @@
nextContext.firstSelectorOfTheFragment = nextContext.selector;
nextContext.elementStyle = nullptr;
PseudoIdSet ignoreDynamicPseudo;
- MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
+ unsigned childSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, childSpecificity);
ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, childSpecificity);
+
if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
return MatchResult::updateWithMatchType(result, matchType);
return MatchResult::fails(Match::SelectorFailsAllSiblings);
@@ -325,7 +336,14 @@
nextContext.firstSelectorOfTheFragment = nextContext.selector;
nextContext.elementStyle = nullptr;
PseudoIdSet ignoreDynamicPseudo;
- return MatchResult::updateWithMatchType(matchRecursively(nextContext, ignoreDynamicPseudo), matchType);
+ unsigned adjacentSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, adjacentSpecificity);
+ ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, adjacentSpecificity);
+
+ return MatchResult::updateWithMatchType(result, matchType);
}
case CSSSelector::IndirectAdjacent:
if (context.resolvingMode == Mode::ResolvingStyle)
@@ -338,25 +356,38 @@
context.element->setAffectsNextSiblingElementStyle();
PseudoIdSet ignoreDynamicPseudo;
- MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
+ unsigned indirectAdjacentSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, indirectAdjacentSpecificity);
ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, indirectAdjacentSpecificity);
+
if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsAllSiblings || result.match == Match::SelectorFailsCompletely)
return MatchResult::updateWithMatchType(result, matchType);
};
return MatchResult::fails(Match::SelectorFailsAllSiblings);
case CSSSelector::SubSelector:
- // a selector is invalid if something follows a pseudo-element
- // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
- // to follow the pseudo elements.
- nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudoIdSet);
- nextContext.hasSelectionPseudo = dynamicPseudoIdSet.has(SELECTION);
- if ((context.elementStyle || context.resolvingMode == Mode::CollectingRules) && dynamicPseudoIdSet
- && !nextContext.hasSelectionPseudo
- && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
- return MatchResult::fails(Match::SelectorFailsCompletely);
- return MatchResult::updateWithMatchType(matchRecursively(nextContext, dynamicPseudoIdSet), matchType);
+ {
+ // a selector is invalid if something follows a pseudo-element
+ // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
+ // to follow the pseudo elements.
+ nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudoIdSet);
+ nextContext.hasSelectionPseudo = dynamicPseudoIdSet.has(SELECTION);
+ if ((context.elementStyle || context.resolvingMode == Mode::CollectingRules) && dynamicPseudoIdSet
+ && !nextContext.hasSelectionPseudo
+ && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
+ return MatchResult::fails(Match::SelectorFailsCompletely);
+ unsigned subselectorSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, dynamicPseudoIdSet, subselectorSpecificity);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
+
+ return MatchResult::updateWithMatchType(result, matchType);
+ }
case CSSSelector::ShadowDescendant:
{
Element* shadowHostNode = context.element->shadowHost();
@@ -366,7 +397,13 @@
nextContext.firstSelectorOfTheFragment = nextContext.selector;
nextContext.elementStyle = nullptr;
PseudoIdSet ignoreDynamicPseudo;
- return MatchResult::updateWithMatchType(matchRecursively(nextContext, ignoreDynamicPseudo), matchType);
+ unsigned shadowDescendantSpecificity = 0;
+ MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity);
+
+ if (result.match == Match::SelectorMatches)
+ specificity = CSSSelector::addSpecificities(specificity, shadowDescendantSpecificity);
+
+ return MatchResult::updateWithMatchType(result, matchType);
}
}
@@ -506,13 +543,15 @@
return false;
}
-bool SelectorChecker::checkOne(const CheckingContextWithStatus& context, PseudoIdSet& dynamicPseudoIdSet, MatchType& matchType) const
+bool SelectorChecker::checkOne(const CheckingContextWithStatus& context, PseudoIdSet& dynamicPseudoIdSet, MatchType& matchType, unsigned& specificity) const
{
Element* const & element = context.element;
const CSSSelector* const & selector = context.selector;
ASSERT(element);
ASSERT(selector);
+ specificity = CSSSelector::addSpecificities(specificity, selector->simpleSelectorSpecificity());
+
if (selector->match() == CSSSelector::Tag)
return SelectorChecker::tagMatches(element, selector->tagQName());
@@ -551,8 +590,9 @@
subcontext.firstSelectorOfTheFragment = selectorList->first();
PseudoIdSet ignoreDynamicPseudo;
+ unsigned ignoredSpecificity;
#if ENABLE(CSS_SELECTORS_LEVEL4)
- if (matchRecursively(subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
+ if (matchRecursively(subcontext, ignoreDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches) {
ASSERT(!ignoreDynamicPseudo);
return false;
}
@@ -568,7 +608,7 @@
}
// Since :not cannot contain pseudo elements, there's no effect on matchType.
MatchType ignoreMatchType = MatchType::Element;
- if (!checkOne(subcontext, ignoreDynamicPseudo, ignoreMatchType))
+ if (!checkOne(subcontext, ignoreDynamicPseudo, ignoreMatchType, ignoredSpecificity))
return true;
#endif
}
@@ -694,7 +734,8 @@
subcontext.selector = subselector;
subcontext.firstSelectorOfTheFragment = subselector;
PseudoIdSet localDynamicPseudoIdSet;
- MatchResult result = matchRecursively(subcontext, localDynamicPseudoIdSet);
+ unsigned localSpecificity = 0;
+ MatchResult result = matchRecursively(subcontext, localDynamicPseudoIdSet, localSpecificity);
if (result.match == Match::SelectorMatches) {
if (!context.pseudoElementEffective) {
// When pseudo elements are not effective in this fragment (e.g. it's not righmost fragment),
@@ -838,7 +879,8 @@
for (subContext.selector = selector->selectorList()->first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
subContext.firstSelectorOfTheFragment = subContext.selector;
PseudoIdSet ignoreDynamicPseudo;
- if (matchRecursively(subContext, ignoreDynamicPseudo).match == Match::SelectorMatches)
+ unsigned ingoredSpecificity = 0;
+ if (matchRecursively(subContext, ignoreDynamicPseudo, ingoredSpecificity).match == Match::SelectorMatches)
return true;
}
}
@@ -993,8 +1035,9 @@
subContext.firstSelectorOfTheFragment = subContext.selector;
subContext.inFunctionalPseudoClass = true;
subContext.pseudoElementEffective = false;
- PseudoIdSet ignoreDynamicPseudo;
- if (matchRecursively(subContext, ignoreDynamicPseudo).match == Match::SelectorMatches)
+ PseudoIdSet ignoredDynamicPseudo;
+ unsigned ignoredSpecificity = 0;
+ if (matchRecursively(subContext, ignoredDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches)
return true;
}
return false;
@@ -1014,7 +1057,8 @@
subcontext.pseudoElementEffective = false;
subcontext.firstSelectorOfTheFragment = subselector;
PseudoIdSet ignoreDynamicPseudo;
- if (matchRecursively(subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
+ unsigned localSpecificity = 0;
+ if (matchRecursively(subcontext, ignoreDynamicPseudo, localSpecificity).match == Match::SelectorMatches) {
ASSERT(!ignoreDynamicPseudo);
return true;
}