<!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>[176436] 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/176436">176436</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-11-20 20:31:06 -0800 (Thu, 20 Nov 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: do not show invalid specificity for dynamic cases of :matches()
https://bugs.webkit.org/show_bug.cgi?id=138911

Reviewed by Joseph Pecoraro.

* css/CSSSelector.cpp:
(WebCore::simpleSelectorFunctionalPseudoClassStaticSpecificity):
(WebCore::functionalPseudoClassStaticSpecificity):
(WebCore::staticSpecificityInternal):
(WebCore::CSSSelector::staticSpecificity):
(WebCore::CSSSelector::specificity): Deleted.
* css/CSSSelector.h:
Add an additional computation path for the inspector.

The regular path ignores everything inside function pseudo classes.
This new path takes the static specificity of the regular path, then evaluate
recursively all the selector lists inside any level of :matches().

If two complex selector of selector list do not have the same specificity,
we bail out and refuse to compute a static specificity representing the selector.

* inspector/InspectorStyleSheet.cpp:
(WebCore::buildObjectForSelectorHelper):
(WebCore::selectorsFromSource):
(WebCore::InspectorStyleSheet::buildObjectForSelector):
Do not add the complexity to the inspector's CSSSelector structure whenever
it is dynamic.</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="#trunkSourceWebCoreinspectorInspectorStyleSheetcpp">trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (176435 => 176436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-11-21 04:30:38 UTC (rev 176435)
+++ trunk/Source/WebCore/ChangeLog        2014-11-21 04:31:06 UTC (rev 176436)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2014-11-20  Benjamin Poulain  &lt;benjamin@webkit.org&gt;
+
+        Web Inspector: do not show invalid specificity for dynamic cases of :matches()
+        https://bugs.webkit.org/show_bug.cgi?id=138911
+
+        Reviewed by Joseph Pecoraro.
+
+        * css/CSSSelector.cpp:
+        (WebCore::simpleSelectorFunctionalPseudoClassStaticSpecificity):
+        (WebCore::functionalPseudoClassStaticSpecificity):
+        (WebCore::staticSpecificityInternal):
+        (WebCore::CSSSelector::staticSpecificity):
+        (WebCore::CSSSelector::specificity): Deleted.
+        * css/CSSSelector.h:
+        Add an additional computation path for the inspector.
+
+        The regular path ignores everything inside function pseudo classes.
+        This new path takes the static specificity of the regular path, then evaluate
+        recursively all the selector lists inside any level of :matches().
+
+        If two complex selector of selector list do not have the same specificity,
+        we bail out and refuse to compute a static specificity representing the selector.
+
+        * inspector/InspectorStyleSheet.cpp:
+        (WebCore::buildObjectForSelectorHelper):
+        (WebCore::selectorsFromSource):
+        (WebCore::InspectorStyleSheet::buildObjectForSelector):
+        Do not add the complexity to the inspector's CSSSelector structure whenever
+        it is dynamic.
+
</ins><span class="cx"> 2014-11-20  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove InspectorCSSAgent::buildArrayForRuleList()
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelector.cpp (176435 => 176436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelector.cpp        2014-11-21 04:30:38 UTC (rev 176435)
+++ trunk/Source/WebCore/css/CSSSelector.cpp        2014-11-21 04:31:06 UTC (rev 176436)
</span><span class="lines">@@ -78,14 +78,6 @@
</span><span class="cx">     return maxSpecificity;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned CSSSelector::specificity() const
-{
-    if (isForPage())
-        return specificityForPage() &amp; maxValueMask;
-
-    return selectorSpecificity(*this, false);
-}
-
</del><span class="cx"> static unsigned simpleSelectorSpecificityInternal(const CSSSelector&amp; simpleSelector, bool isComputingMaximumSpecificity)
</span><span class="cx"> {
</span><span class="cx">     ASSERT_WITH_MESSAGE(!simpleSelector.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;);
</span><span class="lines">@@ -140,6 +132,58 @@
</span><span class="cx">     return simpleSelectorSpecificityInternal(*this, false);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static unsigned staticSpecificityInternal(const CSSSelector&amp; firstSimpleSelector, bool&amp; ok);
+
+static unsigned simpleSelectorFunctionalPseudoClassStaticSpecificity(const CSSSelector&amp; simpleSelector, bool&amp; ok)
+{
+#if ENABLE(CSS_SELECTORS_LEVEL4)
+    if (simpleSelector.match() == CSSSelector::PseudoClass) {
+        if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassMatches) {
+            const CSSSelectorList&amp; selectorList = *simpleSelector.selectorList();
+            const CSSSelector&amp; firstSubselector = *selectorList.first();
+
+            unsigned initialSpecificity = staticSpecificityInternal(firstSubselector, ok);
+            if (!ok)
+                return 0;
+
+            const CSSSelector* subselector = &amp;firstSubselector;
+            while ((subselector = CSSSelectorList::next(subselector))) {
+                unsigned subSelectorSpecificity = staticSpecificityInternal(*subselector, ok);
+                if (initialSpecificity != subSelectorSpecificity)
+                    ok = false;
+                if (!ok)
+                    return 0;
+            }
+            return initialSpecificity;
+        }
+    }
+#endif
+    return 0;
+}
+
+static unsigned functionalPseudoClassStaticSpecificity(const CSSSelector&amp; firstSimpleSelector, bool&amp; ok)
+{
+    unsigned total = 0;
+    for (const CSSSelector* selector = &amp;firstSimpleSelector; selector; selector = selector-&gt;tagHistory()) {
+        total = CSSSelector::addSpecificities(total, simpleSelectorFunctionalPseudoClassStaticSpecificity(*selector, ok));
+        if (!ok)
+            return 0;
+    }
+    return total;
+}
+
+static unsigned staticSpecificityInternal(const CSSSelector&amp; firstSimpleSelector, bool&amp; ok)
+{
+    unsigned staticSpecificity = selectorSpecificity(firstSimpleSelector, false);
+    return CSSSelector::addSpecificities(staticSpecificity, functionalPseudoClassStaticSpecificity(firstSimpleSelector, ok));
+}
+
+unsigned CSSSelector::staticSpecificity(bool &amp;ok) const
+{
+    ok = true;
+    return staticSpecificityInternal(*this, ok);
+}
+
</ins><span class="cx"> unsigned CSSSelector::addSpecificities(unsigned a, unsigned b)
</span><span class="cx"> {
</span><span class="cx">     unsigned total = a;
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSSelectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSSelector.h (176435 => 176436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSSelector.h        2014-11-21 04:30:38 UTC (rev 176435)
+++ trunk/Source/WebCore/css/CSSSelector.h        2014-11-21 04:31:06 UTC (rev 176436)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx">         static const unsigned classMask = 0xff00;
</span><span class="cx">         static const unsigned elementMask = 0xff;
</span><span class="cx"> 
</span><del>-        unsigned specificity() const;
</del><ins>+        unsigned staticSpecificity(bool&amp; ok) const;
</ins><span class="cx">         unsigned specificityForPage() const;
</span><span class="cx">         unsigned simpleSelectorSpecificity() const;
</span><span class="cx">         static unsigned addSpecificities(unsigned, unsigned);
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorStyleSheetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp (176435 => 176436)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp        2014-11-21 04:30:38 UTC (rev 176435)
+++ trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp        2014-11-21 04:31:06 UTC (rev 176436)
</span><span class="lines">@@ -991,18 +991,23 @@
</span><span class="cx">         .release();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static PassRefPtr&lt;Inspector::Protocol::CSS::CSSSelector&gt; buildObjectForSelectorHelper(const String&amp; selectorText, unsigned specificity)
</del><ins>+static PassRefPtr&lt;Inspector::Protocol::CSS::CSSSelector&gt; buildObjectForSelectorHelper(const String&amp; selectorText, const CSSSelector&amp; selector)
</ins><span class="cx"> {
</span><del>-    RefPtr&lt;Inspector::Protocol::CSS::CSSSelector&gt; selector = Inspector::Protocol::CSS::CSSSelector::create()
</del><ins>+    RefPtr&lt;Inspector::Protocol::CSS::CSSSelector&gt; inspectorSelector = Inspector::Protocol::CSS::CSSSelector::create()
</ins><span class="cx">         .setText(selectorText);
</span><span class="cx"> 
</span><del>-    RefPtr&lt;Inspector::Protocol::Array&lt;int&gt;&gt; tuple = Inspector::Protocol::Array&lt;int&gt;::create();
-    tuple-&gt;addItem(static_cast&lt;int&gt;((specificity &amp; CSSSelector::idMask) &gt;&gt; 16));
-    tuple-&gt;addItem(static_cast&lt;int&gt;((specificity &amp; CSSSelector::classMask) &gt;&gt; 8));
-    tuple-&gt;addItem(static_cast&lt;int&gt;(specificity &amp; CSSSelector::elementMask));
-    selector-&gt;setSpecificity(tuple.release());
</del><ins>+    bool ok;
+    unsigned specificity = selector.staticSpecificity(ok);
</ins><span class="cx"> 
</span><del>-    return selector.release();
</del><ins>+    if (ok) {
+        RefPtr&lt;Inspector::Protocol::Array&lt;int&gt;&gt; tuple = Inspector::Protocol::Array&lt;int&gt;::create();
+        tuple-&gt;addItem(static_cast&lt;int&gt;((specificity &amp; CSSSelector::idMask) &gt;&gt; 16));
+        tuple-&gt;addItem(static_cast&lt;int&gt;((specificity &amp; CSSSelector::classMask) &gt;&gt; 8));
+        tuple-&gt;addItem(static_cast&lt;int&gt;(specificity &amp; CSSSelector::elementMask));
+        inspectorSelector-&gt;setSpecificity(tuple.release());
+    }
+
+    return inspectorSelector.release();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static PassRefPtr&lt;Inspector::Protocol::Array&lt;Inspector::Protocol::CSS::CSSSelector&gt;&gt; selectorsFromSource(const CSSRuleSourceData* sourceData, const String&amp; sheetText, const CSSSelectorList&amp; selectorList)
</span><span class="lines">@@ -1018,7 +1023,7 @@
</span><span class="cx"> 
</span><span class="cx">         // We don't want to see any comments in the selector components, only the meaningful parts.
</span><span class="cx">         replace(selectorText, comment, String());
</span><del>-        result-&gt;addItem(buildObjectForSelectorHelper(selectorText.stripWhiteSpace(), selector-&gt;specificity()));
</del><ins>+        result-&gt;addItem(buildObjectForSelectorHelper(selectorText.stripWhiteSpace(), *selector));
</ins><span class="cx"> 
</span><span class="cx">         selector = CSSSelectorList::next(selector);
</span><span class="cx">     }
</span><span class="lines">@@ -1027,7 +1032,7 @@
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;Inspector::Protocol::CSS::CSSSelector&gt; InspectorStyleSheet::buildObjectForSelector(const CSSSelector* selector)
</span><span class="cx"> {
</span><del>-    return buildObjectForSelectorHelper(selector-&gt;selectorText(), selector-&gt;specificity());
</del><ins>+    return buildObjectForSelectorHelper(selector-&gt;selectorText(), *selector);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;Inspector::Protocol::CSS::SelectorList&gt; InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule)
</span></span></pre>
</div>
</div>

</body>
</html>