<!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>[175018] trunk</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/175018">175018</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-10-21 20:28:29 -0700 (Tue, 21 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>CSS Rule features are ignored for nested CSS Selector lists
https://bugs.webkit.org/show_bug.cgi?id=137908

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2014-10-21
Reviewed by Andreas Kling.

Source/WebCore:

When Rule feature sets were collected, any selector list nested inside an other
selector list was ignored when collecting properties of the CSS Selector.

As a result, style was not invalidated properly when any property listed in
the nested selectors.

This patch fixes the issue by make RuleFeatureSet::collectFeaturesFromSelector()
recursive, evaluating every chain of every selector lists.

Tests: fast/css/class-style-invalidation-optimization.html
       fast/css/direct-adjacent-style-sharing-1.html
       fast/css/direct-adjacent-style-sharing-2.html
       fast/css/direct-adjacent-style-sharing-3.html
       fast/css/id-style-invalidation-optimization.html
       fast/selectors/class-style-update-with-not.html
       fast/selectors/class-style-update-with-nth-child-of.html
       fast/selectors/class-style-update.html

* css/RuleFeature.cpp:
(WebCore::recursivelyCollectFeaturesFromSelector):
(WebCore::RuleFeatureSet::collectFeaturesFromSelector):
* css/RuleFeature.h:
* css/RuleSet.cpp:
(WebCore::collectFeaturesFromRuleData):

LayoutTests:

* fast/selectors/class-style-update-with-not-expected.txt: Added.
* fast/selectors/class-style-update-with-not.html: Added.
Parts of this test fail due to a bug with specificity. This will be addressed
separately.

* fast/css/class-style-invalidation-optimization-expected.txt: Added.
* fast/css/class-style-invalidation-optimization.html: Added.
* fast/css/direct-adjacent-style-sharing-1-expected.html: Added.
* fast/css/direct-adjacent-style-sharing-1.html: Added.
* fast/css/direct-adjacent-style-sharing-2-expected.html: Added.
* fast/css/direct-adjacent-style-sharing-2.html: Added.
* fast/css/direct-adjacent-style-sharing-3-expected.html: Added.
* fast/css/direct-adjacent-style-sharing-3.html: Added.
* fast/css/id-style-invalidation-optimization-expected.txt: Added.
* fast/css/id-style-invalidation-optimization.html: Added.
* fast/selectors/class-style-update-expected.txt: Added.
* fast/selectors/class-style-update-with-nth-child-of-expected.txt: Added.
* fast/selectors/class-style-update-with-nth-child-of.html: Added.
* fast/selectors/class-style-update.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssRuleFeaturecpp">trunk/Source/WebCore/css/RuleFeature.cpp</a></li>
<li><a href="#trunkSourceWebCorecssRuleFeatureh">trunk/Source/WebCore/css/RuleFeature.h</a></li>
<li><a href="#trunkSourceWebCorecssRuleSetcpp">trunk/Source/WebCore/css/RuleSet.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastcssclassstyleinvalidationoptimizationexpectedtxt">trunk/LayoutTests/fast/css/class-style-invalidation-optimization-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastcssclassstyleinvalidationoptimizationhtml">trunk/LayoutTests/fast/css/class-style-invalidation-optimization.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing1expectedhtml">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing1html">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing2expectedhtml">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing2html">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing3expectedhtml">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastcssdirectadjacentstylesharing3html">trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3.html</a></li>
<li><a href="#trunkLayoutTestsfastcssidstyleinvalidationoptimizationexpectedtxt">trunk/LayoutTests/fast/css/id-style-invalidation-optimization-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastcssidstyleinvalidationoptimizationhtml">trunk/LayoutTests/fast/css/id-style-invalidation-optimization.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdateexpectedtxt">trunk/LayoutTests/fast/selectors/class-style-update-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdatewithnotexpectedtxt">trunk/LayoutTests/fast/selectors/class-style-update-with-not-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdatewithnothtml">trunk/LayoutTests/fast/selectors/class-style-update-with-not.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdatewithnthchildofexpectedtxt">trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdatewithnthchildofhtml">trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsclassstyleupdatehtml">trunk/LayoutTests/fast/selectors/class-style-update.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (175017 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/LayoutTests/ChangeLog        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2014-10-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        CSS Rule features are ignored for nested CSS Selector lists
+        https://bugs.webkit.org/show_bug.cgi?id=137908
+
+        Reviewed by Andreas Kling.
+
+        * fast/selectors/class-style-update-with-not-expected.txt: Added.
+        * fast/selectors/class-style-update-with-not.html: Added.
+        Parts of this test fail due to a bug with specificity. This will be addressed
+        separately.
+
+        * fast/css/class-style-invalidation-optimization-expected.txt: Added.
+        * fast/css/class-style-invalidation-optimization.html: Added.
+        * fast/css/direct-adjacent-style-sharing-1-expected.html: Added.
+        * fast/css/direct-adjacent-style-sharing-1.html: Added.
+        * fast/css/direct-adjacent-style-sharing-2-expected.html: Added.
+        * fast/css/direct-adjacent-style-sharing-2.html: Added.
+        * fast/css/direct-adjacent-style-sharing-3-expected.html: Added.
+        * fast/css/direct-adjacent-style-sharing-3.html: Added.
+        * fast/css/id-style-invalidation-optimization-expected.txt: Added.
+        * fast/css/id-style-invalidation-optimization.html: Added.
+        * fast/selectors/class-style-update-expected.txt: Added.
+        * fast/selectors/class-style-update-with-nth-child-of-expected.txt: Added.
+        * fast/selectors/class-style-update-with-nth-child-of.html: Added.
+        * fast/selectors/class-style-update.html: Added.
+
</ins><span class="cx"> 2014-10-21  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Win] Unreviewed test updates after switching to Windows theme for tests.
</span></span></pre></div>
<a id="trunkLayoutTestsfastcssclassstyleinvalidationoptimizationexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/class-style-invalidation-optimization-expected.txt (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/class-style-invalidation-optimization-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/css/class-style-invalidation-optimization-expected.txt        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+Test that we do not invalidate the style of an element if we are changing a class that is not used by the stylesheet.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssclassstyleinvalidationoptimizationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/class-style-invalidation-optimization.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/class-style-invalidation-optimization.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/class-style-invalidation-optimization.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style&gt;
+* {
+    color: black;
+}
+target.Case1 {
+    color: rgb(0, 1, 2);
+}
+target:matches(foo, .Case2, bar) {
+    color: rgb(3, 4, 5);
+}
+target:matches(foo1, :matches(foo2, .Case3, bar1), bar2) {
+    color: rgb(6, 7, 8);
+}
+target:matches(foo1, :matches(foo2, :matches(foo3, .Case4, bar1), bar2), bar3) {
+    color: rgb(9, 10, 11);
+}
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;
+        &lt;!-- With renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+    &lt;div style=&quot;display:none;&quot;&gt;
+        &lt;!-- Without renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+
+description('Test that we do not invalidate the style of an element if we are changing a class that is not used by the stylesheet.');
+
+function shouldNeedStyleRecalc(expected) {
+    var testFunction = expected ? shouldBeTrue : shouldBeFalse;
+    testFunction(&quot;window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\&quot;target\&quot;)[0])&quot;);
+    testFunction(&quot;window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\&quot;target\&quot;)[1])&quot;);
+}
+
+function addClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].classList.add(name);
+    allTargets[1].classList.add(name);
+}
+
+function checkStyle(expectedColor) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color', expectedColor);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color', expectedColor);
+}
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+shouldNeedStyleRecalc(false);
+
+addClass('NotThere');
+shouldNeedStyleRecalc(false);
+
+addClass('Case1');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(0, 1, 2)');
+shouldNeedStyleRecalc(false);
+
+addClass('case1');
+shouldNeedStyleRecalc(false);
+
+addClass('Case2');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(3, 4, 5)');
+shouldNeedStyleRecalc(false);
+
+addClass('case2');
+shouldNeedStyleRecalc(false);
+
+addClass('Case3');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(6, 7, 8)');
+shouldNeedStyleRecalc(false);
+
+addClass('case3');
+shouldNeedStyleRecalc(false);
+
+addClass('Case4');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(9, 10, 11)');
+shouldNeedStyleRecalc(false);
+
+addClass('case4');
+shouldNeedStyleRecalc(false);
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing1expectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1-expected.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1-expected.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            div + div {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div style=&quot;background-color: red; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing1html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            div + div {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing2expectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2-expected.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2-expected.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            div + div {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div style=&quot;background-color: red; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing2html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            :matches(div + div) {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing3expectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3-expected.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3-expected.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            div + div {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div style=&quot;background-color: red; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+        &lt;div style=&quot;background-color: green; border: 1px solid black; width: 100px; height: 100px;&quot;&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssdirectadjacentstylesharing3html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;html&gt;
+    &lt;head&gt;
+        &lt;style type=&quot;text/css&quot;&gt;
+            div {
+                background-color: red;
+                border: 1px solid black;
+                width: 100px;
+                height: 100px;
+            }
+
+            :matches(:matches(div + div)) {
+                background-color: green;
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;p&gt;If the test pass, there should be one red block followed by 3 green blocks.&lt;/p&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+        &lt;div&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssidstyleinvalidationoptimizationexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/id-style-invalidation-optimization-expected.txt (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/id-style-invalidation-optimization-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/css/id-style-invalidation-optimization-expected.txt        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+Test that we do not invalidate the style of an element if we are changing an #id that is not used by the stylesheet.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is true
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(&quot;target&quot;)[1]) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssidstyleinvalidationoptimizationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/id-style-invalidation-optimization.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/id-style-invalidation-optimization.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/id-style-invalidation-optimization.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style&gt;
+* {
+    color: black;
+}
+target#Case1 {
+    color: rgb(0, 1, 2);
+}
+target:matches(foo, #Case2, bar) {
+    color: rgb(3, 4, 5);
+}
+target:matches(foo1, :matches(foo2, #Case3, bar1), bar2) {
+    color: rgb(6, 7, 8);
+}
+target:matches(foo1, :matches(foo2, :matches(foo3, #Case4, bar1), bar2), bar3) {
+    color: rgb(9, 10, 11);
+}
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;
+        &lt;!-- With renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+    &lt;div style=&quot;display:none;&quot;&gt;
+        &lt;!-- Without renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+
+description('Test that we do not invalidate the style of an element if we are changing an #id that is not used by the stylesheet.');
+
+function shouldNeedStyleRecalc(expected) {
+    var testFunction = expected ? shouldBeTrue : shouldBeFalse;
+    testFunction(&quot;window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\&quot;target\&quot;)[0])&quot;);
+    testFunction(&quot;window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\&quot;target\&quot;)[1])&quot;);
+}
+
+function setId(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].id = name;
+    allTargets[1].id = name;
+}
+
+function checkStyle(expectedColor) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color', expectedColor);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color', expectedColor);
+}
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+shouldNeedStyleRecalc(false);
+
+setId('NotThere');
+shouldNeedStyleRecalc(false);
+
+setId('Case1');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(0, 1, 2)');
+shouldNeedStyleRecalc(false);
+
+setId('Case2');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(3, 4, 5)');
+shouldNeedStyleRecalc(false);
+
+setId('Case3');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(6, 7, 8)');
+shouldNeedStyleRecalc(false);
+
+setId('Case4');
+shouldNeedStyleRecalc(true);
+checkStyle('rgb(9, 10, 11)');
+shouldNeedStyleRecalc(false);
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdateexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update-expected.txt (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update-expected.txt        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+Test that the style of elements is invalidated correctly when class changes can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdatewithnotexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update-with-not-expected.txt (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update-with-not-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update-with-not-expected.txt        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+Test that the style of elements is invalidated correctly when a class changes inside :not() can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(12, 13, 14)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(12, 13, 14)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color should be rgb(3, 4, 5). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color should be rgb(3, 4, 5). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color should be rgb(6, 7, 8). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color should be rgb(6, 7, 8). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color should be rgb(9, 10, 11). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color should be rgb(9, 10, 11). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color should be rgb(12, 13, 14). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color should be rgb(12, 13, 14). Was rgb(0, 1, 2).
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdatewithnothtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update-with-not.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update-with-not.html                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update-with-not.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style&gt;
+* {
+    color: black;
+}
+target:not(.Case1) {
+    color: rgb(0, 1, 2);
+}
+target:not(foo, .Case2, bar) {
+    color: rgb(3, 4, 5);
+}
+target:not(foo1, :matches(foo2, .Case3, bar1), bar2) {
+    color: rgb(6, 7, 8);
+}
+target:not(foo1, :not(foo2, .Case4, bar1), bar2) {
+    color: rgb(9, 10, 11);
+}
+target:not(foo1, :matches(foo2, :matches(foo3, .Case5, bar1), bar2), bar3) {
+    color: rgb(12, 13, 14);
+}
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;
+        &lt;!-- With renderer --&gt;
+        &lt;target class=&quot;Case1 Case2 Case3 Case5&quot;&gt;&lt;/target&gt;
+    &lt;/div&gt;
+    &lt;div style=&quot;display:none;&quot;&gt;
+        &lt;!-- Without renderer --&gt;
+        &lt;target class=&quot;Case1 Case2 Case3 Case5&quot;&gt;&lt;/target&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+
+description('Test that the style of elements is invalidated correctly when a class changes inside :not() can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.');
+
+function addClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].classList.add(name);
+    allTargets[1].classList.add(name);
+}
+
+function removeClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].classList.remove(name);
+    allTargets[1].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color', expectedColor);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color', expectedColor);
+}
+
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+
+checkStyle('rgb(0, 0, 0)');
+
+// Change the classes one by one.
+removeClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+addClass('Case1');
+checkStyle('rgb(0, 0, 0)');
+
+removeClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+addClass('Case2');
+checkStyle('rgb(0, 0, 0)');
+
+removeClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+addClass('Case3');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+removeClass('Case4');
+checkStyle('rgb(0, 0, 0)');
+
+removeClass('Case5');
+checkStyle('rgb(12, 13, 14)');
+addClass('Case5');
+checkStyle('rgb(0, 0, 0)');
+
+
+// Remove the classes one after the other.
+removeClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+removeClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+removeClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+removeClass('Case5');
+checkStyle('rgb(12, 13, 14)');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdatewithnthchildofexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of-expected.txt (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of-expected.txt        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+Test that the style of elements is invalidated correctly when a class changes inside :nth-child(An+B of selectorList) can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 0, 0)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(0, 1, 2)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(3, 4, 5)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(6, 7, 8)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color is &quot;rgb(9, 10, 11)&quot;
+PASS getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color is &quot;rgb(9, 10, 11)&quot;
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdatewithnthchildofhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of.html                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,112 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style&gt;
+* {
+    color: black;
+}
+target:nth-child(2 of .Case1) {
+    color: rgb(0, 1, 2);
+}
+target:nth-child(2 of foo, .Case2, bar) {
+    color: rgb(3, 4, 5);
+}
+target:nth-child(2 of foo1, :matches(foo2, .Case3, bar1), bar2) {
+    color: rgb(6, 7, 8);
+}
+target:nth-child(2 of foo1, :nth-child(n of foo2, .Case4, bar1), bar2) {
+    color: rgb(9, 10, 11);
+}
+target:nth-child(2 of foo1, :matches(foo2, :nth-child(n of foo3, .Case5, bar1), bar2), bar3) {
+    color: rgb(12, 13, 14);
+}
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;
+        &lt;!-- With renderer --&gt;
+        &lt;padding&gt;&lt;/padding&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+    &lt;div style=&quot;display:none;&quot;&gt;
+        &lt;!-- Without renderer --&gt;
+        &lt;padding&gt;&lt;/padding&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+
+description('Test that the style of elements is invalidated correctly when a class changes inside :nth-child(An+B of selectorList) can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.');
+
+function addClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target, padding&quot;);
+    for (var i = 0; i &lt; allTargets.length; ++i)
+        allTargets[i].classList.add(name);
+}
+
+function removeClass(name) {
+    var allTargets = document.querySelectorAll(&quot;:matches(target, padding)&quot;);
+    for (var i = 0; i &lt; allTargets.length; ++i)
+        allTargets[i].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color', expectedColor);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color', expectedColor);
+}
+
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+
+checkStyle('rgb(0, 0, 0)');
+
+// Add the classes one by one.
+addClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+removeClass('Case1');
+checkStyle('rgb(0, 0, 0)');
+addClass('case1');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case1');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+removeClass('Case2');
+checkStyle('rgb(0, 0, 0)');
+addClass('case2');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case2');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+removeClass('Case3');
+checkStyle('rgb(0, 0, 0)');
+addClass('case3');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case3');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+removeClass('Case4');
+checkStyle('rgb(0, 0, 0)');
+addClass('case4');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case4');
+checkStyle('rgb(0, 0, 0)');
+
+// Add the classes one after the other.
+addClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+addClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+addClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsclassstyleupdatehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/class-style-update.html (0 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/class-style-update.html                                (rev 0)
+++ trunk/LayoutTests/fast/selectors/class-style-update.html        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -0,0 +1,107 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;style&gt;
+* {
+    color: black;
+}
+target.Case1 {
+    color: rgb(0, 1, 2);
+}
+target:matches(foo, .Case2, bar) {
+    color: rgb(3, 4, 5);
+}
+target:matches(foo1, :matches(foo2, .Case3, bar1), bar2) {
+    color: rgb(6, 7, 8);
+}
+target:matches(foo1, :matches(foo2, :matches(foo3, .Case4, bar1), bar2), bar3) {
+    color: rgb(9, 10, 11);
+}
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div&gt;
+        &lt;!-- With renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+    &lt;div style=&quot;display:none;&quot;&gt;
+        &lt;!-- Without renderer --&gt;
+        &lt;target&gt;&lt;/target&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+
+description('Test that the style of elements is invalidated correctly when class changes can affect its style. Elements are only invalidate if the class changed affects the style. It is important to account nested selector lists.');
+
+function addClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].classList.add(name);
+    allTargets[1].classList.add(name);
+}
+
+function removeClass(name) {
+    var allTargets = document.querySelectorAll(&quot;target&quot;);
+    allTargets[0].classList.remove(name);
+    allTargets[1].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[0]).color', expectedColor);
+    shouldBeEqualToString('getComputedStyle(document.querySelectorAll(&quot;target&quot;)[1]).color', expectedColor);
+}
+
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+
+checkStyle('rgb(0, 0, 0)');
+
+// Add the classes one by one.
+addClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+removeClass('Case1');
+checkStyle('rgb(0, 0, 0)');
+addClass('case1');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case1');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+removeClass('Case2');
+checkStyle('rgb(0, 0, 0)');
+addClass('case2');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case2');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+removeClass('Case3');
+checkStyle('rgb(0, 0, 0)');
+addClass('case3');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case3');
+checkStyle('rgb(0, 0, 0)');
+
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+removeClass('Case4');
+checkStyle('rgb(0, 0, 0)');
+addClass('case4');
+checkStyle('rgb(0, 0, 0)');
+removeClass('Case4');
+checkStyle('rgb(0, 0, 0)');
+
+// Add the classes one after the other.
+addClass('Case1');
+checkStyle('rgb(0, 1, 2)');
+addClass('Case2');
+checkStyle('rgb(3, 4, 5)');
+addClass('Case3');
+checkStyle('rgb(6, 7, 8)');
+addClass('Case4');
+checkStyle('rgb(9, 10, 11)');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (175017 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/Source/WebCore/ChangeLog        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2014-10-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        CSS Rule features are ignored for nested CSS Selector lists
+        https://bugs.webkit.org/show_bug.cgi?id=137908
+
+        Reviewed by Andreas Kling.
+
+        When Rule feature sets were collected, any selector list nested inside an other
+        selector list was ignored when collecting properties of the CSS Selector.
+
+        As a result, style was not invalidated properly when any property listed in
+        the nested selectors.
+
+        This patch fixes the issue by make RuleFeatureSet::collectFeaturesFromSelector()
+        recursive, evaluating every chain of every selector lists.
+
+        Tests: fast/css/class-style-invalidation-optimization.html
+               fast/css/direct-adjacent-style-sharing-1.html
+               fast/css/direct-adjacent-style-sharing-2.html
+               fast/css/direct-adjacent-style-sharing-3.html
+               fast/css/id-style-invalidation-optimization.html
+               fast/selectors/class-style-update-with-not.html
+               fast/selectors/class-style-update-with-nth-child-of.html
+               fast/selectors/class-style-update.html
+
+        * css/RuleFeature.cpp:
+        (WebCore::recursivelyCollectFeaturesFromSelector):
+        (WebCore::RuleFeatureSet::collectFeaturesFromSelector):
+        * css/RuleFeature.h:
+        * css/RuleSet.cpp:
+        (WebCore::collectFeaturesFromRuleData):
+
</ins><span class="cx"> 2014-10-21  Tim Horton  &lt;timothy_horton@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Try to fix the iOS build after r175013.
</span></span></pre></div>
<a id="trunkSourceWebCorecssRuleFeaturecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/RuleFeature.cpp (175017 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/RuleFeature.cpp        2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/Source/WebCore/css/RuleFeature.cpp        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -2,7 +2,7 @@
</span><span class="cx">  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
</span><span class="cx">  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
</span><span class="cx">  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
</span><del>- * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2005-2012, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Alexey Proskuryakov &lt;ap@webkit.org&gt;
</span><span class="cx">  * Copyright (C) 2007, 2008 Eric Seidel &lt;eric@webkit.org&gt;
</span><span class="cx">  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
</span><span class="lines">@@ -30,36 +30,59 @@
</span><span class="cx"> #include &quot;RuleFeature.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CSSSelector.h&quot;
</span><ins>+#include &quot;CSSSelectorList.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector* selector)
</del><ins>+static void recursivelyCollectFeaturesFromSelector(RuleFeatureSet&amp; features, const CSSSelector&amp; firstSelector, bool&amp; hasSiblingSelector)
</ins><span class="cx"> {
</span><del>-    if (selector-&gt;match() == CSSSelector::Id)
-        idsInRules.add(selector-&gt;value().impl());
-    else if (selector-&gt;match() == CSSSelector::Class)
-        classesInRules.add(selector-&gt;value().impl());
-    else if (selector-&gt;isAttributeSelector()) {
-        attributeCanonicalLocalNamesInRules.add(selector-&gt;attributeCanonicalLocalName().impl());
-        attributeLocalNamesInRules.add(selector-&gt;attribute().localName().impl());
-    } else if (selector-&gt;match() == CSSSelector::PseudoElement) {
-        switch (selector-&gt;pseudoElementType()) {
-        case CSSSelector::PseudoElementFirstLine:
-            usesFirstLineRules = true;
-            break;
-        case CSSSelector::PseudoElementFirstLetter:
-            usesFirstLetterRules = true;
-            break;
-        case CSSSelector::PseudoElementBefore:
-        case CSSSelector::PseudoElementAfter:
-            usesBeforeAfterRules = true;
-            break;
-        default:
-            break;
</del><ins>+    const CSSSelector* selector = &amp;firstSelector;
+    do {
+        if (selector-&gt;match() == CSSSelector::Id)
+            features.idsInRules.add(selector-&gt;value().impl());
+        else if (selector-&gt;match() == CSSSelector::Class)
+            features.classesInRules.add(selector-&gt;value().impl());
+        else if (selector-&gt;isAttributeSelector()) {
+            features.attributeCanonicalLocalNamesInRules.add(selector-&gt;attributeCanonicalLocalName().impl());
+            features.attributeLocalNamesInRules.add(selector-&gt;attribute().localName().impl());
+        } else if (selector-&gt;match() == CSSSelector::PseudoElement) {
+            switch (selector-&gt;pseudoElementType()) {
+            case CSSSelector::PseudoElementFirstLine:
+                features.usesFirstLineRules = true;
+                break;
+            case CSSSelector::PseudoElementFirstLetter:
+                features.usesFirstLetterRules = true;
+                break;
+            case CSSSelector::PseudoElementBefore:
+            case CSSSelector::PseudoElementAfter:
+                features.usesBeforeAfterRules = true;
+                break;
+            default:
+                break;
+            }
</ins><span class="cx">         }
</span><del>-    }
</del><ins>+
+        if (!hasSiblingSelector &amp;&amp; selector-&gt;isSiblingSelector())
+            hasSiblingSelector = true;
+
+        if (const CSSSelectorList* selectorList = selector-&gt;selectorList()) {
+            for (const CSSSelector* subSelector = selectorList-&gt;first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
+                if (!hasSiblingSelector &amp;&amp; selector-&gt;isSiblingSelector())
+                    hasSiblingSelector = true;
+                recursivelyCollectFeaturesFromSelector(features, *subSelector, hasSiblingSelector);
+            }
+        }
+
+        selector = selector-&gt;tagHistory();
+    } while (selector);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector&amp; firstSelector, bool&amp; hasSiblingSelector)
+{
+    hasSiblingSelector = false;
+    recursivelyCollectFeaturesFromSelector(*this, firstSelector, hasSiblingSelector);
+}
+
</ins><span class="cx"> void RuleFeatureSet::add(const RuleFeatureSet&amp; other)
</span><span class="cx"> {
</span><span class="cx">     idsInRules.add(other.idsInRules.begin(), other.idsInRules.end());
</span></span></pre></div>
<a id="trunkSourceWebCorecssRuleFeatureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/RuleFeature.h (175017 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/RuleFeature.h        2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/Source/WebCore/css/RuleFeature.h        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
</span><del>- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2003-2011, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * This library is free software; you can redistribute it and/or
</span><span class="cx">  * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx">     void add(const RuleFeatureSet&amp;);
</span><span class="cx">     void clear();
</span><span class="cx"> 
</span><del>-    void collectFeaturesFromSelector(const CSSSelector*);
</del><ins>+    void collectFeaturesFromSelector(const CSSSelector&amp;, bool&amp; hasSiblingSelector);
</ins><span class="cx"> 
</span><span class="cx">     HashSet&lt;AtomicStringImpl*&gt; idsInRules;
</span><span class="cx">     HashSet&lt;AtomicStringImpl*&gt; classesInRules;
</span></span></pre></div>
<a id="trunkSourceWebCorecssRuleSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/RuleSet.cpp (175017 => 175018)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/RuleSet.cpp        2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/Source/WebCore/css/RuleSet.cpp        2014-10-22 03:28:29 UTC (rev 175018)
</span><span class="lines">@@ -166,20 +166,10 @@
</span><span class="cx"> 
</span><span class="cx"> static void collectFeaturesFromRuleData(RuleFeatureSet&amp; features, const RuleData&amp; ruleData)
</span><span class="cx"> {
</span><del>-    bool foundSiblingSelector = false;
-    for (const CSSSelector* selector = ruleData.selector(); selector; selector = selector-&gt;tagHistory()) {
-        features.collectFeaturesFromSelector(selector);
-        
-        if (const CSSSelectorList* selectorList = selector-&gt;selectorList()) {
-            for (const CSSSelector* subSelector = selectorList-&gt;first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
-                if (!foundSiblingSelector &amp;&amp; selector-&gt;isSiblingSelector())
-                    foundSiblingSelector = true;
-                features.collectFeaturesFromSelector(subSelector);
-            }
-        } else if (!foundSiblingSelector &amp;&amp; selector-&gt;isSiblingSelector())
-            foundSiblingSelector = true;
-    }
-    if (foundSiblingSelector)
</del><ins>+    bool hasSiblingSelector;
+    features.collectFeaturesFromSelector(*ruleData.selector(), hasSiblingSelector);
+
+    if (hasSiblingSelector)
</ins><span class="cx">         features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
</span><span class="cx">     if (ruleData.containsUncommonAttributeSelector())
</span><span class="cx">         features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
</span></span></pre>
</div>
</div>

</body>
</html>