<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[176152] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/176152">176152</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-11-14 18:32:37 -0800 (Fri, 14 Nov 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Compute the selector specificity as we match simple selectors
https://bugs.webkit.org/show_bug.cgi?id=138718

Reviewed by Andreas Kling.

This is an other tiny step toward dynamic specificity. Instead of computing
the entire specificity at the end, compute it dynamically as we are matching
each individual simple selector.

* css/CSSSelector.cpp:
(WebCore::CSSSelector::specificity):
(WebCore::CSSSelector::simpleSelectorSpecificity):
(WebCore::CSSSelector::addSpecificities):
(WebCore::CSSSelector::specificityForPage):
(WebCore::CSSSelector::specificityForOneSelector): Deleted.
* css/CSSSelector.h:
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::match):
(WebCore::SelectorChecker::matchRecursively):
(WebCore::SelectorChecker::checkOne):
(WebCore::SelectorChecker::matchSelectorList):
* css/SelectorChecker.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssCSSSelectorcpp">trunk/Source/WebCore/css/CSSSelector.cpp</a></li>
<li><a href="#trunkSourceWebCorecssCSSSelectorh">trunk/Source/WebCore/css/CSSSelector.h</a></li>
<li><a href="#trunkSourceWebCorecssSelectorCheckercpp">trunk/Source/WebCore/css/SelectorChecker.cpp</a></li>
<li><a href="#trunkSourceWebCorecssSelectorCheckerh">trunk/Source/WebCore/css/SelectorChecker.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (176151 => 176152)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-11-15 02:31:28 UTC (rev 176151)
+++ trunk/Source/WebCore/ChangeLog        2014-11-15 02:32:37 UTC (rev 176152)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2014-11-14  Benjamin Poulain  &lt;benjamin@webkit.org&gt;
+
+        Compute the selector specificity as we match simple selectors
+        https://bugs.webkit.org/show_bug.cgi?id=138718
+
+        Reviewed by Andreas Kling.
+
+        This is an other tiny step toward dynamic specificity. Instead of computing
+        the entire specificity at the end, compute it dynamically as we are matching
+        each individual simple selector.
+
+        * css/CSSSelector.cpp:
+        (WebCore::CSSSelector::specificity):
+        (WebCore::CSSSelector::simpleSelectorSpecificity):
+        (WebCore::CSSSelector::addSpecificities):
+        (WebCore::CSSSelector::specificityForPage):
+        (WebCore::CSSSelector::specificityForOneSelector): Deleted.
+        * css/CSSSelector.h:
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::match):
+        (WebCore::SelectorChecker::matchRecursively):
+        (WebCore::SelectorChecker::checkOne):
+        (WebCore::SelectorChecker::matchSelectorList):
+        * css/SelectorChecker.h:
+
</ins><span class="cx"> 2014-11-14  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [mac] Only images that are actually purgeable should be advertised as such.
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelector.cpp (176151 => 176152)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelector.cpp        2014-11-15 02:31:28 UTC (rev 176151)
+++ trunk/Source/WebCore/css/CSSSelector.cpp        2014-11-15 02:32:37 UTC (rev 176152)
</span><span class="lines">@@ -64,34 +64,17 @@
</span><span class="cx">     if (isForPage())
</span><span class="cx">         return specificityForPage() &amp; maxValueMask;
</span><span class="cx"> 
</span><del>-    unsigned total = specificityForOneSelector();
</del><ins>+    unsigned total = simpleSelectorSpecificity();
</ins><span class="cx"> 
</span><del>-    for (const CSSSelector* selector = this-&gt;tagHistory(); selector; selector = selector-&gt;tagHistory()) {
-        unsigned selectorSpecificity = selector-&gt;specificityForOneSelector();
-
-        unsigned newIdValue = (selectorSpecificity &amp; idMask);
-        if (((total &amp; idMask) + newIdValue) &amp; ~idMask)
-            total |= idMask;
-        else
-            total += newIdValue;
-
-        unsigned newClassValue = (selectorSpecificity &amp; classMask);
-        if (((total &amp; classMask) + newClassValue) &amp; ~classMask)
-            total |= classMask;
-        else
-            total += newClassValue;
-
-        unsigned newElementValue = (selectorSpecificity &amp; elementMask);
-        if (((total &amp; elementMask) + newElementValue) &amp; ~elementMask)
-            total |= elementMask;
-        else
-            total += newElementValue;
-    }
</del><ins>+    for (const CSSSelector* selector = this-&gt;tagHistory(); selector; selector = selector-&gt;tagHistory())
+        total = addSpecificities(total, selector-&gt;simpleSelectorSpecificity());
</ins><span class="cx">     return total;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline unsigned CSSSelector::specificityForOneSelector() const
</del><ins>+unsigned CSSSelector::simpleSelectorSpecificity() const
</ins><span class="cx"> {
</span><ins>+    ASSERT_WITH_MESSAGE(!isForPage(), &quot;At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors.&quot;);
+
</ins><span class="cx">     switch (match()) {
</span><span class="cx">     case Id:
</span><span class="cx">         return static_cast&lt;unsigned&gt;(SelectorSpecificityIncrement::ClassA);
</span><span class="lines">@@ -99,9 +82,6 @@
</span><span class="cx">     case PagePseudoClass:
</span><span class="cx">         break;
</span><span class="cx">     case PseudoClass:
</span><del>-        // FIXME: PseudoAny should base the specificity on the sub-selectors.
-        // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
-
</del><span class="cx"> #if ENABLE(CSS_SELECTORS_LEVEL4)
</span><span class="cx">         if (pseudoClassType() == PseudoClassNot) {
</span><span class="cx">             ASSERT_WITH_MESSAGE(selectorList() &amp;&amp; selectorList()-&gt;first(), &quot;The parser should never generate a valid selector for an empty :not().&quot;);
</span><span class="lines">@@ -114,7 +94,7 @@
</span><span class="cx">         FALLTHROUGH;
</span><span class="cx"> #else
</span><span class="cx">         if (pseudoClassType() == PseudoClassNot &amp;&amp; selectorList())
</span><del>-            return selectorList()-&gt;first()-&gt;specificityForOneSelector();
</del><ins>+            return selectorList()-&gt;first()-&gt;simpleSelectorSpecificity();
</ins><span class="cx">         FALLTHROUGH;
</span><span class="cx"> #endif
</span><span class="cx">     case Exact:
</span><span class="lines">@@ -137,8 +117,35 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+unsigned CSSSelector::addSpecificities(unsigned a, unsigned b)
+{
+    unsigned total = a;
+
+    unsigned newIdValue = (b &amp; idMask);
+    if (((total &amp; idMask) + newIdValue) &amp; ~idMask)
+        total |= idMask;
+    else
+        total += newIdValue;
+
+    unsigned newClassValue = (b &amp; classMask);
+    if (((total &amp; classMask) + newClassValue) &amp; ~classMask)
+        total |= classMask;
+    else
+        total += newClassValue;
+
+    unsigned newElementValue = (b &amp; elementMask);
+    if (((total &amp; elementMask) + newElementValue) &amp; ~elementMask)
+        total |= elementMask;
+    else
+        total += newElementValue;
+
+    return total;
+}
+
</ins><span class="cx"> unsigned CSSSelector::specificityForPage() const
</span><span class="cx"> {
</span><ins>+    ASSERT(isForPage());
+
</ins><span class="cx">     // See http://dev.w3.org/csswg/css3-page/#cascading-and-page-context
</span><span class="cx">     unsigned s = 0;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelector.h (176151 => 176152)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelector.h        2014-11-15 02:31:28 UTC (rev 176151)
+++ trunk/Source/WebCore/css/CSSSelector.h        2014-11-15 02:32:37 UTC (rev 176152)
</span><span class="lines">@@ -59,6 +59,8 @@
</span><span class="cx">         static const unsigned elementMask = 0xff;
</span><span class="cx"> 
</span><span class="cx">         unsigned specificity() const;
</span><ins>+        unsigned simpleSelectorSpecificity() const;
+        static unsigned addSpecificities(unsigned, unsigned);
</ins><span class="cx"> 
</span><span class="cx">         /* how the attribute value has to match.... Default is Exact */
</span><span class="cx">         enum Match {
</span><span class="lines">@@ -306,7 +308,7 @@
</span><span class="cx">         unsigned m_isForPage             : 1;
</span><span class="cx">         unsigned m_tagIsForNamespaceRule : 1;
</span><span class="cx"> 
</span><del>-        unsigned specificityForOneSelector() const;
</del><ins>+        unsigned simpleSelectorSpecificityForPage() const;
</ins><span class="cx">         unsigned specificityForPage() const;
</span><span class="cx"> 
</span><span class="cx">         // Hide.
</span></span></pre></div>
<a id="trunkSourceWebCorecssSelectorCheckercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (176151 => 176152)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -173,15 +173,16 @@
</span><span class="cx"> 
</span><span class="cx"> bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext&amp; providedContext, unsigned&amp; specificity) const
</span><span class="cx"> {
</span><ins>+    specificity = 0;
+
</ins><span class="cx">     CheckingContextWithStatus context(providedContext, selector, element);
</span><span class="cx">     PseudoIdSet pseudoIdSet;
</span><del>-    MatchResult result = matchRecursively(context, pseudoIdSet);
</del><ins>+    MatchResult result = matchRecursively(context, pseudoIdSet, specificity);
</ins><span class="cx">     if (result.match != Match::SelectorMatches)
</span><span class="cx">         return false;
</span><span class="cx">     if (context.pseudoId != NOPSEUDO &amp;&amp; !pseudoIdSet.has(context.pseudoId))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    specificity = selector-&gt;specificity();
</del><span class="cx">     if (context.pseudoId == NOPSEUDO &amp;&amp; pseudoIdSet) {
</span><span class="cx">         PseudoIdSet publicPseudoIdSet = pseudoIdSet &amp; PseudoIdSet::fromMask(PUBLIC_PSEUDOID_MASK);
</span><span class="cx">         if (context.resolvingMode == Mode::ResolvingStyle &amp;&amp; publicPseudoIdSet)
</span><span class="lines">@@ -221,12 +222,12 @@
</span><span class="cx"> // * SelectorFailsLocally     - the selector fails for the element e
</span><span class="cx"> // * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
</span><span class="cx"> // * SelectorFailsCompletely  - the selector fails for e and any sibling or ancestor of e
</span><del>-SelectorChecker::MatchResult SelectorChecker::matchRecursively(const CheckingContextWithStatus&amp; context, PseudoIdSet&amp; dynamicPseudoIdSet) const
</del><ins>+SelectorChecker::MatchResult SelectorChecker::matchRecursively(const CheckingContextWithStatus&amp; context, PseudoIdSet&amp; dynamicPseudoIdSet, unsigned&amp; specificity) const
</ins><span class="cx"> {
</span><span class="cx">     MatchType matchType = MatchType::Element;
</span><span class="cx"> 
</span><span class="cx">     // The first selector has to match.
</span><del>-    if (!checkOne(context, dynamicPseudoIdSet, matchType))
</del><ins>+    if (!checkOne(context, dynamicPseudoIdSet, matchType, specificity))
</ins><span class="cx">         return MatchResult::fails(Match::SelectorFailsLocally);
</span><span class="cx"> 
</span><span class="cx">     if (context.selector-&gt;match() == CSSSelector::PseudoElement) {
</span><span class="lines">@@ -289,8 +290,13 @@
</span><span class="cx">         nextContext.elementStyle = nullptr;
</span><span class="cx">         for (; nextContext.element; nextContext = checkingContextForParent(nextContext)) {
</span><span class="cx">             PseudoIdSet ignoreDynamicPseudo;
</span><del>-            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
</del><ins>+            unsigned descendantsSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, descendantsSpecificity);
</ins><span class="cx">             ASSERT(!nextContext.pseudoElementEffective &amp;&amp; !ignoreDynamicPseudo);
</span><ins>+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, descendantsSpecificity);
+
</ins><span class="cx">             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
</span><span class="cx">                 return MatchResult::updateWithMatchType(result, matchType);
</span><span class="cx">         }
</span><span class="lines">@@ -304,8 +310,13 @@
</span><span class="cx">             nextContext.firstSelectorOfTheFragment = nextContext.selector;
</span><span class="cx">             nextContext.elementStyle = nullptr;
</span><span class="cx">             PseudoIdSet ignoreDynamicPseudo;
</span><del>-            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
</del><ins>+            unsigned childSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, childSpecificity);
</ins><span class="cx">             ASSERT(!nextContext.pseudoElementEffective &amp;&amp; !ignoreDynamicPseudo);
</span><ins>+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, childSpecificity);
+
</ins><span class="cx">             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
</span><span class="cx">                 return MatchResult::updateWithMatchType(result, matchType);
</span><span class="cx">             return MatchResult::fails(Match::SelectorFailsAllSiblings);
</span><span class="lines">@@ -325,7 +336,14 @@
</span><span class="cx">             nextContext.firstSelectorOfTheFragment = nextContext.selector;
</span><span class="cx">             nextContext.elementStyle = nullptr;
</span><span class="cx">             PseudoIdSet ignoreDynamicPseudo;
</span><del>-            return MatchResult::updateWithMatchType(matchRecursively(nextContext, ignoreDynamicPseudo), matchType);
</del><ins>+            unsigned adjacentSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, adjacentSpecificity);
+            ASSERT(!nextContext.pseudoElementEffective &amp;&amp; !ignoreDynamicPseudo);
+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, adjacentSpecificity);
+
+            return MatchResult::updateWithMatchType(result, matchType);
</ins><span class="cx">         }
</span><span class="cx">     case CSSSelector::IndirectAdjacent:
</span><span class="cx">         if (context.resolvingMode == Mode::ResolvingStyle)
</span><span class="lines">@@ -338,25 +356,38 @@
</span><span class="cx">                 context.element-&gt;setAffectsNextSiblingElementStyle();
</span><span class="cx"> 
</span><span class="cx">             PseudoIdSet ignoreDynamicPseudo;
</span><del>-            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo);
</del><ins>+            unsigned indirectAdjacentSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, indirectAdjacentSpecificity);
</ins><span class="cx">             ASSERT(!nextContext.pseudoElementEffective &amp;&amp; !ignoreDynamicPseudo);
</span><ins>+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, indirectAdjacentSpecificity);
+
</ins><span class="cx">             if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsAllSiblings || result.match == Match::SelectorFailsCompletely)
</span><span class="cx">                 return MatchResult::updateWithMatchType(result, matchType);
</span><span class="cx">         };
</span><span class="cx">         return MatchResult::fails(Match::SelectorFailsAllSiblings);
</span><span class="cx"> 
</span><span class="cx">     case CSSSelector::SubSelector:
</span><del>-        // 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) &amp;&amp; dynamicPseudoIdSet
-            &amp;&amp; !nextContext.hasSelectionPseudo
-            &amp;&amp; !(nextContext.hasScrollbarPseudo &amp;&amp; nextContext.selector-&gt;match() == CSSSelector::PseudoClass))
-            return MatchResult::fails(Match::SelectorFailsCompletely);
-        return MatchResult::updateWithMatchType(matchRecursively(nextContext, dynamicPseudoIdSet), matchType);
</del><ins>+        {
+            // 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) &amp;&amp; dynamicPseudoIdSet
+                &amp;&amp; !nextContext.hasSelectionPseudo
+                &amp;&amp; !(nextContext.hasScrollbarPseudo &amp;&amp; nextContext.selector-&gt;match() == CSSSelector::PseudoClass))
+                return MatchResult::fails(Match::SelectorFailsCompletely);
</ins><span class="cx"> 
</span><ins>+            unsigned subselectorSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, dynamicPseudoIdSet, subselectorSpecificity);
+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
+
+            return MatchResult::updateWithMatchType(result, matchType);
+        }
</ins><span class="cx">     case CSSSelector::ShadowDescendant:
</span><span class="cx">         {
</span><span class="cx">             Element* shadowHostNode = context.element-&gt;shadowHost();
</span><span class="lines">@@ -366,7 +397,13 @@
</span><span class="cx">             nextContext.firstSelectorOfTheFragment = nextContext.selector;
</span><span class="cx">             nextContext.elementStyle = nullptr;
</span><span class="cx">             PseudoIdSet ignoreDynamicPseudo;
</span><del>-            return MatchResult::updateWithMatchType(matchRecursively(nextContext, ignoreDynamicPseudo), matchType);
</del><ins>+            unsigned shadowDescendantSpecificity = 0;
+            MatchResult result = matchRecursively(nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity);
+
+            if (result.match == Match::SelectorMatches)
+                specificity = CSSSelector::addSpecificities(specificity, shadowDescendantSpecificity);
+
+            return MatchResult::updateWithMatchType(result, matchType);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -506,13 +543,15 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SelectorChecker::checkOne(const CheckingContextWithStatus&amp; context, PseudoIdSet&amp; dynamicPseudoIdSet, MatchType&amp; matchType) const
</del><ins>+bool SelectorChecker::checkOne(const CheckingContextWithStatus&amp; context, PseudoIdSet&amp; dynamicPseudoIdSet, MatchType&amp; matchType, unsigned&amp; specificity) const
</ins><span class="cx"> {
</span><span class="cx">     Element* const &amp; element = context.element;
</span><span class="cx">     const CSSSelector* const &amp; selector = context.selector;
</span><span class="cx">     ASSERT(element);
</span><span class="cx">     ASSERT(selector);
</span><span class="cx"> 
</span><ins>+    specificity = CSSSelector::addSpecificities(specificity, selector-&gt;simpleSelectorSpecificity());
+
</ins><span class="cx">     if (selector-&gt;match() == CSSSelector::Tag)
</span><span class="cx">         return SelectorChecker::tagMatches(element, selector-&gt;tagQName());
</span><span class="cx"> 
</span><span class="lines">@@ -551,8 +590,9 @@
</span><span class="cx">                 subcontext.firstSelectorOfTheFragment = selectorList-&gt;first();
</span><span class="cx">                 PseudoIdSet ignoreDynamicPseudo;
</span><span class="cx"> 
</span><ins>+                unsigned ignoredSpecificity;
</ins><span class="cx"> #if ENABLE(CSS_SELECTORS_LEVEL4)
</span><del>-                if (matchRecursively(subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
</del><ins>+                if (matchRecursively(subcontext, ignoreDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches) {
</ins><span class="cx">                     ASSERT(!ignoreDynamicPseudo);
</span><span class="cx">                     return false;
</span><span class="cx">                 }
</span><span class="lines">@@ -568,7 +608,7 @@
</span><span class="cx">                 }
</span><span class="cx">                 // Since :not cannot contain pseudo elements, there's no effect on matchType.
</span><span class="cx">                 MatchType ignoreMatchType = MatchType::Element;
</span><del>-                if (!checkOne(subcontext, ignoreDynamicPseudo, ignoreMatchType))
</del><ins>+                if (!checkOne(subcontext, ignoreDynamicPseudo, ignoreMatchType, ignoredSpecificity))
</ins><span class="cx">                     return true;
</span><span class="cx"> #endif
</span><span class="cx">             }
</span><span class="lines">@@ -694,7 +734,8 @@
</span><span class="cx">                     subcontext.selector = subselector;
</span><span class="cx">                     subcontext.firstSelectorOfTheFragment = subselector;
</span><span class="cx">                     PseudoIdSet localDynamicPseudoIdSet;
</span><del>-                    MatchResult result = matchRecursively(subcontext, localDynamicPseudoIdSet);
</del><ins>+                    unsigned localSpecificity = 0;
+                    MatchResult result = matchRecursively(subcontext, localDynamicPseudoIdSet, localSpecificity);
</ins><span class="cx">                     if (result.match == Match::SelectorMatches) {
</span><span class="cx">                         if (!context.pseudoElementEffective) {
</span><span class="cx">                             // When pseudo elements are not effective in this fragment (e.g. it's not righmost fragment),
</span><span class="lines">@@ -838,7 +879,8 @@
</span><span class="cx">                 for (subContext.selector = selector-&gt;selectorList()-&gt;first(); subContext.selector; subContext.selector = CSSSelectorList::next(subContext.selector)) {
</span><span class="cx">                     subContext.firstSelectorOfTheFragment = subContext.selector;
</span><span class="cx">                     PseudoIdSet ignoreDynamicPseudo;
</span><del>-                    if (matchRecursively(subContext, ignoreDynamicPseudo).match == Match::SelectorMatches)
</del><ins>+                    unsigned ingoredSpecificity = 0;
+                    if (matchRecursively(subContext, ignoreDynamicPseudo, ingoredSpecificity).match == Match::SelectorMatches)
</ins><span class="cx">                         return true;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="lines">@@ -993,8 +1035,9 @@
</span><span class="cx">             subContext.firstSelectorOfTheFragment = subContext.selector;
</span><span class="cx">             subContext.inFunctionalPseudoClass = true;
</span><span class="cx">             subContext.pseudoElementEffective = false;
</span><del>-            PseudoIdSet ignoreDynamicPseudo;
-            if (matchRecursively(subContext, ignoreDynamicPseudo).match == Match::SelectorMatches)
</del><ins>+            PseudoIdSet ignoredDynamicPseudo;
+            unsigned ignoredSpecificity = 0;
+            if (matchRecursively(subContext, ignoredDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches)
</ins><span class="cx">                 return true;
</span><span class="cx">         }
</span><span class="cx">         return false;
</span><span class="lines">@@ -1014,7 +1057,8 @@
</span><span class="cx">         subcontext.pseudoElementEffective = false;
</span><span class="cx">         subcontext.firstSelectorOfTheFragment = subselector;
</span><span class="cx">         PseudoIdSet ignoreDynamicPseudo;
</span><del>-        if (matchRecursively(subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
</del><ins>+        unsigned localSpecificity = 0;
+        if (matchRecursively(subcontext, ignoreDynamicPseudo, localSpecificity).match == Match::SelectorMatches) {
</ins><span class="cx">             ASSERT(!ignoreDynamicPseudo);
</span><span class="cx">             return true;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceWebCorecssSelectorCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/SelectorChecker.h (176151 => 176152)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/SelectorChecker.h        2014-11-15 02:31:28 UTC (rev 176151)
+++ trunk/Source/WebCore/css/SelectorChecker.h        2014-11-15 02:32:37 UTC (rev 176152)
</span><span class="lines">@@ -107,8 +107,8 @@
</span><span class="cx">     static unsigned determineLinkMatchType(const CSSSelector*);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    MatchResult matchRecursively(const CheckingContextWithStatus&amp;, PseudoIdSet&amp;) const;
-    bool checkOne(const CheckingContextWithStatus&amp;, PseudoIdSet&amp;, MatchType&amp;) const;
</del><ins>+    MatchResult matchRecursively(const CheckingContextWithStatus&amp;, PseudoIdSet&amp;, unsigned&amp; specificity) const;
+    bool checkOne(const CheckingContextWithStatus&amp;, PseudoIdSet&amp;, MatchType&amp;, unsigned&amp; specificity) const;
</ins><span class="cx">     bool matchSelectorList(const CheckingContextWithStatus&amp;, Element&amp;, const CSSSelectorList&amp;) const;
</span><span class="cx"> 
</span><span class="cx">     bool checkScrollbarPseudoClass(const CheckingContextWithStatus&amp;, const CSSSelector*) const;
</span></span></pre>
</div>
</div>

</body>
</html>