<!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>[172721] 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/172721">172721</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-08-18 13:52:04 -0700 (Mon, 18 Aug 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>The style is not updated correctly when the pseudo class :empty is applied on anything but the rightmost element
https://bugs.webkit.org/show_bug.cgi?id=135999
Reviewed by Antti Koivisto.
Source/WebCore:
In Element's checkForEmptyStyleChange(), the style invalidation was only considering the invalidation of the element
for which the subtree has changed. When the pseudo class :empty is used with a sibling combinator (e.g. foo:empty+bar),
we were never invalidating the style of the element on which the selector applies.
This patch fixes the issue by invalidating the whole subtree rooted at the parent if the :empty rules applies
to siblings. A new flag "styleOfSiblingsAffectedByEmpty" is introduced to cover this case.
SelectorChecker just sets the flag all the time if any sibling rule exists.
This is overkill but that code is just there for non-jit cases.
SelectorCompiler does a better job and only sets the flag if matching anything else than the rightmost element.
There is a case not optimized, :empty with descendant (e.g. foo:empty>bar). Those cases are useless in practice,
it is not worth optimizing them.
Tests: fast/css/pseudo-element-updates-on-empty.html
fast/selectors/not-empty-adjacent-style-update.html
fast/selectors/not-empty-style-update.html
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::checkOne):
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::fragmentMatchesTheRightmostElement):
shouldUseRenderStyleFromCheckingContext() is renamed fragmentMatchesTheRightmostElement() because
it is now also used by generateElementIsEmpty() in a context where the Context's style is irrelevant.
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsActive):
(WebCore::SelectorCompiler::setStyleOfSiblingsAffectedByEmpty):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsEmpty):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsFirstChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsHovered):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsLastChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsOnlyChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementHasPseudoElement):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateRequestedPseudoElementEqualsToSelectorPseudoElement):
(WebCore::SelectorCompiler::shouldUseRenderStyleFromCheckingContext): Deleted.
(WebCore::SelectorCompiler::setElementStyleIsAffectedByEmptyAndUpdateRenderStyleIfNecessary): Deleted.
* dom/Element.cpp:
(WebCore::checkForEmptyStyleChange):
(WebCore::Element::setStyleOfSiblingsAffectedByEmpty):
(WebCore::Element::rareDataStyleOfSiblingsAffectedByEmpty):
* dom/Element.h:
(WebCore::Element::styleOfSiblingsAffectedByEmpty):
* dom/ElementRareData.h:
(WebCore::ElementRareData::styleOfSiblingsAffectedByEmpty):
(WebCore::ElementRareData::setStyleOfSiblingsAffectedByEmpty):
(WebCore::ElementRareData::ElementRareData):
LayoutTests:
* fast/css/pseudo-element-updates-on-empty-expected.html: Added.
* fast/css/pseudo-element-updates-on-empty.html: Added.
* fast/selectors/empty-adjacent-style-update-expected.txt:
* fast/selectors/empty-adjacent-style-update.html:
* fast/selectors/empty-style-update-expected.txt:
* fast/selectors/empty-style-update.html:
* fast/selectors/not-empty-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt.
* fast/selectors/not-empty-adjacent-style-update.html: Copied from LayoutTests/fast/selectors/empty-adjacent-style-update.html.
* fast/selectors/not-empty-style-update-expected.txt: Copied from LayoutTests/fast/selectors/empty-style-update-expected.txt.
* fast/selectors/not-empty-style-update.html: Copied from LayoutTests/fast/selectors/empty-style-update.html.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastselectorsemptyadjacentstyleupdateexpectedtxt">trunk/LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsemptyadjacentstyleupdatehtml">trunk/LayoutTests/fast/selectors/empty-adjacent-style-update.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsemptystyleupdateexpectedtxt">trunk/LayoutTests/fast/selectors/empty-style-update-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsemptystyleupdatehtml">trunk/LayoutTests/fast/selectors/empty-style-update.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssSelectorCheckercpp">trunk/Source/WebCore/css/SelectorChecker.cpp</a></li>
<li><a href="#trunkSourceWebCorecssjitSelectorCompilercpp">trunk/Source/WebCore/cssjit/SelectorCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCoredomElementcpp">trunk/Source/WebCore/dom/Element.cpp</a></li>
<li><a href="#trunkSourceWebCoredomElementh">trunk/Source/WebCore/dom/Element.h</a></li>
<li><a href="#trunkSourceWebCoredomElementRareDatah">trunk/Source/WebCore/dom/ElementRareData.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastcsspseudoelementupdatesonemptyexpectedhtml">trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastcsspseudoelementupdatesonemptyhtml">trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsnotemptyadjacentstyleupdateexpectedtxt">trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsnotemptyadjacentstyleupdatehtml">trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsnotemptystyleupdateexpectedtxt">trunk/LayoutTests/fast/selectors/not-empty-style-update-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsnotemptystyleupdatehtml">trunk/LayoutTests/fast/selectors/not-empty-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 (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/LayoutTests/ChangeLog        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2014-08-18 Benjamin Poulain <benjamin@webkit.org>
+
+ The style is not updated correctly when the pseudo class :empty is applied on anything but the rightmost element
+ https://bugs.webkit.org/show_bug.cgi?id=135999
+
+ Reviewed by Antti Koivisto.
+
+ * fast/css/pseudo-element-updates-on-empty-expected.html: Added.
+ * fast/css/pseudo-element-updates-on-empty.html: Added.
+ * fast/selectors/empty-adjacent-style-update-expected.txt:
+ * fast/selectors/empty-adjacent-style-update.html:
+ * fast/selectors/empty-style-update-expected.txt:
+ * fast/selectors/empty-style-update.html:
+ * fast/selectors/not-empty-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt.
+ * fast/selectors/not-empty-adjacent-style-update.html: Copied from LayoutTests/fast/selectors/empty-adjacent-style-update.html.
+ * fast/selectors/not-empty-style-update-expected.txt: Copied from LayoutTests/fast/selectors/empty-style-update-expected.txt.
+ * fast/selectors/not-empty-style-update.html: Copied from LayoutTests/fast/selectors/empty-style-update.html.
+
</ins><span class="cx"> 2014-08-18 Andy Estes <aestes@apple.com>
</span><span class="cx">
</span><span class="cx"> Remove a test inadvertently landed in r172709.
</span></span></pre></div>
<a id="trunkLayoutTestsfastcsspseudoelementupdatesonemptyexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty-expected.html (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty-expected.html         (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty-expected.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ .target::before {
+ background-color: green;
+ content: "Pass!";
+ }
+ </style>
+</head>
+<body>
+ <p>This tests pseudo elements are styled properly. If the test succeed, you should see 6 lines with "Pass!" over a green background.</p>
+ <test1>
+ <div class="target"></div>
+ </test1>
+
+ <test2>
+ <div></div>
+ <div class="target"></div>
+ </test2>
+
+ <test3>
+ <div></div>
+ <div>
+ <div class="target"></div>
+ </div>
+ </test3>
+
+ <test4>
+ <div class="target"></div>
+ </test4>
+
+ <test5>
+ <notempty></notempty>
+ <div class="target"></div>
+ </test5>
+
+ <test6>
+ <notempty></notempty>
+ <div>
+ <div class="target"></div>
+ </div>
+ </test6>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcsspseudoelementupdatesonemptyhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty.html (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty.html         (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-element-updates-on-empty.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ test1 > :empty::before {
+ background-color: green;
+ content: "Pass!";
+ }
+
+ test2 > :empty + ::before {
+ background-color: green;
+ content: "Pass!";
+ }
+
+ test3 > :empty + * > ::before {
+ background-color: green;
+ content: "Pass!";
+ }
+
+ test4 > :not(:empty)::before {
+ background-color: green;
+ content: "Pass!";
+ }
+
+ test5 > :not(:empty) + ::before {
+ background-color: green;
+ content: "Pass!";
+ }
+
+ test6 > :not(:empty) + * > ::before {
+ background-color: green;
+ content: "Pass!";
+ }
+ </style>
+ <script>
+ window.addEventListener('load', function() {
+ scratch = document.documentElement.offsetTop;
+ var children = document.querySelectorAll('child');
+ for (var i = 0; i < children.length; ++i)
+ children[i].parentNode.removeChild(children[i]);
+
+ var children = document.querySelectorAll('notempty');
+ for (var i = 0; i < children.length; ++i)
+ children[i].appendChild(document.createTextNode(" "));
+ });
+ </script>
+</head>
+<body>
+ <p>This tests pseudo elements are styled properly. If the test succeed, you should see 6 lines with "Pass!" over a green background.</p>
+ <test1>
+ <div><child></child></div>
+ </test1>
+
+ <test2>
+ <div><child></child></div>
+ <div></div>
+ </test2>
+
+ <test3>
+ <div><child></child></div>
+ <div>
+ <div></div>
+ </div>
+ </test3>
+
+ <test4>
+ <notempty></notempty>
+ </test4>
+
+ <test5>
+ <notempty></notempty>
+ <div></div>
+ </test5>
+
+ <test6>
+ <notempty></notempty>
+ <div>
+ <div></div>
+ </div>
+ </test6>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsemptyadjacentstyleupdateexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/LayoutTests/fast/selectors/empty-adjacent-style-update-expected.txt        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -3,24 +3,24 @@
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span><span class="cx">
</span><span class="cx">
</span><del>-Initial state is emtpy.
</del><ins>+Initial state is empty.
</ins><span class="cx"> PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> Adding a comment does not change the :empty state.
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> Add an element as child make updates :empty.
</span><del>-FAIL getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
-FAIL getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
</del><ins>+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
</ins><span class="cx"> Adding an empty text node, this is still not empty because of the element.
</span><del>-FAIL getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
-FAIL getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
</del><ins>+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
</ins><span class="cx"> Removing the elements previously added should restore the :empty state.
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> Adding a non empty text node makes the state non empty.
</span><del>-FAIL getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
-FAIL getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
</del><ins>+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
</ins><span class="cx"> Removing the last text child, back to being empty.
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsemptyadjacentstyleupdatehtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/empty-adjacent-style-update.html (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/empty-adjacent-style-update.html        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/LayoutTests/fast/selectors/empty-adjacent-style-update.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -6,7 +6,7 @@
</span><span class="cx"> target {
</span><span class="cx"> background-color: white;
</span><span class="cx"> }
</span><del>-testcase:empty+target {
</del><ins>+testcase:empty + target {
</ins><span class="cx"> background-color: rgb(1, 2, 3);
</span><span class="cx"> }
</span><span class="cx"> </style>
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> var testCaseWithRender = document.getElementById("with-renderer");
</span><span class="cx"> var testCaseWithoutRenderer = document.getElementById("without-renderer");
</span><span class="cx">
</span><del>-debug("Initial state is emtpy.");
</del><ins>+debug("Initial state is empty.");
</ins><span class="cx"> shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
</span><span class="cx"> shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
</span><span class="cx">
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsemptystyleupdateexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/empty-style-update-expected.txt (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/empty-style-update-expected.txt        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/LayoutTests/fast/selectors/empty-style-update-expected.txt        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span><span class="cx">
</span><span class="cx">
</span><del>-Initial state is emtpy.
</del><ins>+Initial state is empty.
</ins><span class="cx"> PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(1, 2, 3)"
</span><span class="cx"> Adding a comment does not change the :empty state.
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsemptystyleupdatehtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/selectors/empty-style-update.html (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/empty-style-update.html        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/LayoutTests/fast/selectors/empty-style-update.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx"> var testCaseWithRender = document.getElementById("with-renderer");
</span><span class="cx"> var testCaseWithoutRenderer = document.getElementById("without-renderer");
</span><span class="cx">
</span><del>-debug("Initial state is emtpy.");
</del><ins>+debug("Initial state is empty.");
</ins><span class="cx"> shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
</span><span class="cx"> shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
</span><span class="cx">
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsnotemptyadjacentstyleupdateexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update-expected.txt (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update-expected.txt        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+Test the style with a :empty pseudo class used for a sibling of the styled element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Initial state is empty.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Adding a comment does not change the :empty state.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Add an element as child make updates :empty.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Adding an empty text node, this is still not empty because of the element.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Removing the elements previously added should restore the :empty state.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Adding a non empty text node makes the state non empty.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Removing the last text child, back to being empty.
+PASS getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsnotemptyadjacentstyleupdatehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update.html (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/not-empty-adjacent-style-update.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,73 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<style>
+target {
+ background-color: rgb(1, 2, 3);
+}
+testcase:not(:empty) + target {
+ background-color: white;
+}
+</style>
+</head>
+<body>
+ <div>
+ <testcase id="with-renderer"></testcase>
+ <target id="target-with-renderer"></target>
+ </div>
+ <div style="display:none;">
+ <testcase id="without-renderer"></testcase>
+ <target id="target-without-renderer"></target>
+ </div>
+</body>
+<script>
+description('Test the style with a :empty pseudo class used for a sibling of the styled element.');
+
+var testCaseWithRender = document.getElementById("with-renderer");
+var testCaseWithoutRenderer = document.getElementById("without-renderer");
+
+debug("Initial state is empty.");
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Adding a comment does not change the :empty state.");
+testCaseWithRender.appendChild(document.createComment("WebKit!"));
+testCaseWithoutRenderer.appendChild(document.createComment("WebKit!"));
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Add an element as child make updates :empty.");
+var elementForCaseWithRenderer = document.createElement('div');
+var elementForCaseWithoutRenderer = document.createElement('div');
+testCaseWithRender.appendChild(elementForCaseWithRenderer);
+testCaseWithoutRenderer.appendChild(elementForCaseWithoutRenderer);
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Adding an empty text node, this is still not empty because of the element.");
+testCaseWithRender.appendChild(document.createTextNode(''));
+testCaseWithoutRenderer.appendChild(document.createTextNode(''));
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Removing the elements previously added should restore the :empty state.");
+testCaseWithRender.removeChild(elementForCaseWithRenderer);
+testCaseWithoutRenderer.removeChild(elementForCaseWithoutRenderer);
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Adding a non empty text node makes the state non empty.");
+testCaseWithRender.appendChild(document.createTextNode('WebKit!'));
+testCaseWithoutRenderer.appendChild(document.createTextNode('WebKit!'));
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Removing the last text child, back to being empty.");
+testCaseWithRender.removeChild(testCaseWithRender.lastChild);
+testCaseWithoutRenderer.removeChild(testCaseWithoutRenderer.lastChild);
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("target-without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsnotemptystyleupdateexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/not-empty-style-update-expected.txt (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/not-empty-style-update-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/not-empty-style-update-expected.txt        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+Test the style update with the :empty pseudo class.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Initial state is empty.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Adding a comment does not change the :empty state.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Add an element as child make updates :empty.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Adding an empty text node, this is still not empty because of the element.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Removing the elements previously added should restore the :empty state.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+Adding a non empty text node makes the state non empty.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(255, 255, 255)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(255, 255, 255)"
+Removing the last text child, back to being empty.
+PASS getComputedStyle(document.getElementById("with-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById("without-renderer")).backgroundColor is "rgb(1, 2, 3)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsnotemptystyleupdatehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/not-empty-style-update.html (0 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/not-empty-style-update.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/not-empty-style-update.html        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -0,0 +1,71 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<style>
+testcase {
+ background-color: rgb(1, 2, 3);
+}
+testcase:not(:empty) {
+ background-color: white;
+}
+</style>
+</head>
+<body>
+ <div>
+ <testcase id="with-renderer"></testcase>
+ </div>
+ <div style="display:none;">
+ <testcase id="without-renderer"></testcase>
+ </div>
+</body>
+<script>
+description('Test the style update with the :empty pseudo class.');
+
+var testCaseWithRender = document.getElementById("with-renderer");
+var testCaseWithoutRenderer = document.getElementById("without-renderer");
+
+debug("Initial state is empty.");
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Adding a comment does not change the :empty state.");
+testCaseWithRender.appendChild(document.createComment("WebKit!"));
+testCaseWithoutRenderer.appendChild(document.createComment("WebKit!"));
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Add an element as child make updates :empty.");
+var elementForCaseWithRenderer = document.createElement('div');
+var elementForCaseWithoutRenderer = document.createElement('div');
+testCaseWithRender.appendChild(elementForCaseWithRenderer);
+testCaseWithoutRenderer.appendChild(elementForCaseWithoutRenderer);
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Adding an empty text node, this is still not empty because of the element.");
+testCaseWithRender.appendChild(document.createTextNode(''));
+testCaseWithoutRenderer.appendChild(document.createTextNode(''));
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Removing the elements previously added should restore the :empty state.");
+testCaseWithRender.removeChild(elementForCaseWithRenderer);
+testCaseWithoutRenderer.removeChild(elementForCaseWithoutRenderer);
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+
+debug("Adding a non empty text node makes the state non empty.");
+testCaseWithRender.appendChild(document.createTextNode('WebKit!'));
+testCaseWithoutRenderer.appendChild(document.createTextNode('WebKit!'));
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(255, 255, 255)');
+
+debug("Removing the last text child, back to being empty.");
+testCaseWithRender.removeChild(testCaseWithRender.lastChild);
+testCaseWithoutRenderer.removeChild(testCaseWithoutRenderer.lastChild);
+shouldBeEqualToString('getComputedStyle(document.getElementById("with-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+shouldBeEqualToString('getComputedStyle(document.getElementById("without-renderer")).backgroundColor', 'rgb(1, 2, 3)');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/ChangeLog        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -1,3 +1,59 @@
</span><ins>+2014-08-18 Benjamin Poulain <benjamin@webkit.org>
+
+ The style is not updated correctly when the pseudo class :empty is applied on anything but the rightmost element
+ https://bugs.webkit.org/show_bug.cgi?id=135999
+
+ Reviewed by Antti Koivisto.
+
+ In Element's checkForEmptyStyleChange(), the style invalidation was only considering the invalidation of the element
+ for which the subtree has changed. When the pseudo class :empty is used with a sibling combinator (e.g. foo:empty+bar),
+ we were never invalidating the style of the element on which the selector applies.
+
+ This patch fixes the issue by invalidating the whole subtree rooted at the parent if the :empty rules applies
+ to siblings. A new flag "styleOfSiblingsAffectedByEmpty" is introduced to cover this case.
+
+ SelectorChecker just sets the flag all the time if any sibling rule exists.
+ This is overkill but that code is just there for non-jit cases.
+
+ SelectorCompiler does a better job and only sets the flag if matching anything else than the rightmost element.
+ There is a case not optimized, :empty with descendant (e.g. foo:empty>bar). Those cases are useless in practice,
+ it is not worth optimizing them.
+
+ Tests: fast/css/pseudo-element-updates-on-empty.html
+ fast/selectors/not-empty-adjacent-style-update.html
+ fast/selectors/not-empty-style-update.html
+
+ * css/SelectorChecker.cpp:
+ (WebCore::SelectorChecker::checkOne):
+ * cssjit/SelectorCompiler.cpp:
+ (WebCore::SelectorCompiler::fragmentMatchesTheRightmostElement):
+ shouldUseRenderStyleFromCheckingContext() is renamed fragmentMatchesTheRightmostElement() because
+ it is now also used by generateElementIsEmpty() in a context where the Context's style is irrelevant.
+
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsActive):
+ (WebCore::SelectorCompiler::setStyleOfSiblingsAffectedByEmpty):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsEmpty):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsFirstChild):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsHovered):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsLastChild):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsOnlyChild):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementHasPseudoElement):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateRequestedPseudoElementEqualsToSelectorPseudoElement):
+ (WebCore::SelectorCompiler::shouldUseRenderStyleFromCheckingContext): Deleted.
+ (WebCore::SelectorCompiler::setElementStyleIsAffectedByEmptyAndUpdateRenderStyleIfNecessary): Deleted.
+ * dom/Element.cpp:
+ (WebCore::checkForEmptyStyleChange):
+ (WebCore::Element::setStyleOfSiblingsAffectedByEmpty):
+ (WebCore::Element::rareDataStyleOfSiblingsAffectedByEmpty):
+ * dom/Element.h:
+ (WebCore::Element::styleOfSiblingsAffectedByEmpty):
+ * dom/ElementRareData.h:
+ (WebCore::ElementRareData::styleOfSiblingsAffectedByEmpty):
+ (WebCore::ElementRareData::setStyleOfSiblingsAffectedByEmpty):
+ (WebCore::ElementRareData::ElementRareData):
+
</ins><span class="cx"> 2014-08-18 Brent Fulgham <bfulgham@apple.com>
</span><span class="cx">
</span><span class="cx"> [Mac] Unreviewed merge correction.
</span></span></pre></div>
<a id="trunkSourceWebCorecssSelectorCheckercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/SelectorChecker.cpp        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -524,10 +524,10 @@
</span><span class="cx"> }
</span><span class="cx"> if (m_mode == Mode::ResolvingStyle) {
</span><span class="cx"> element->setStyleAffectedByEmpty();
</span><ins>+ if (element->document().styleSheetCollection().usesSiblingRules())
+ element->setStyleOfSiblingsAffectedByEmpty();
</ins><span class="cx"> if (context.elementStyle)
</span><span class="cx"> context.elementStyle->setEmptyState(result);
</span><del>- else if (element->renderStyle() && (element->document().styleSheetCollection().usesSiblingRules() || element->renderStyle()->unique()))
- element->renderStyle()->setEmptyState(result);
</del><span class="cx"> }
</span><span class="cx"> return result;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitSelectorCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -353,7 +353,7 @@
</span><span class="cx"> return std::max(a, b);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static inline bool shouldUseRenderStyleFromCheckingContext(SelectorContext selectorContext, const SelectorFragment& fragment)
</del><ins>+static inline bool fragmentMatchesTheRightmostElement(SelectorContext selectorContext, const SelectorFragment& fragment)
</ins><span class="cx"> {
</span><span class="cx"> // Return true if the position of this fragment is Rightmost in the root fragments.
</span><span class="cx"> // In this case, we should use the RenderStyle stored in the CheckingContext.
</span><span class="lines">@@ -1346,7 +1346,7 @@
</span><span class="cx"> Assembler::JumpList failureOnFunctionEntry;
</span><span class="cx"> // Test selector's pseudo element equals to requested PseudoId.
</span><span class="cx"> if (m_selectorContext != SelectorContext::QuerySelector && m_functionType == FunctionType::SelectorCheckerWithCheckingContext) {
</span><del>- ASSERT_WITH_MESSAGE(shouldUseRenderStyleFromCheckingContext(m_selectorContext, m_selectorFragments.first()), "Matching pseudo elements only make sense for the rightmost fragment.");
</del><ins>+ ASSERT_WITH_MESSAGE(fragmentMatchesTheRightmostElement(m_selectorContext, m_selectorFragments.first()), "Matching pseudo elements only make sense for the rightmost fragment.");
</ins><span class="cx"> generateRequestedPseudoElementEqualsToSelectorPseudoElement(failureOnFunctionEntry, m_selectorFragments.first(), checkingContextRegister);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -2442,7 +2442,7 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> LocalRegister checkingContext(m_registerAllocator);
</span><span class="cx"> Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext);
</span><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::flagIsaffectedByActive());
</span><span class="lines">@@ -2501,12 +2501,9 @@
</span><span class="cx"> context->elementStyle->setEmptyState(isEmpty);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static void setElementStyleIsAffectedByEmptyAndUpdateRenderStyleIfNecessary(Element* element, bool isEmpty)
</del><ins>+static void setStyleOfSiblingsAffectedByEmpty(Element* element)
</ins><span class="cx"> {
</span><del>- element->setStyleAffectedByEmpty();
-
- if (element->renderStyle() && (element->document().styleSheetCollection().usesSiblingRules() || element->renderStyle()->unique()))
- element->renderStyle()->setEmptyState(isEmpty);
</del><ins>+ element->setStyleOfSiblingsAffectedByEmpty();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void SelectorCodeGenerator::generateElementIsEmpty(Assembler::JumpList& failureCases, const SelectorFragment& fragment)
</span><span class="lines">@@ -2525,7 +2522,7 @@
</span><span class="cx"> notEmpty.link(&m_assembler);
</span><span class="cx">
</span><span class="cx"> Assembler::Jump skipMarking;
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> {
</span><span class="cx"> LocalRegister checkingContext(m_registerAllocator);
</span><span class="cx"> skipMarking = jumpIfNotResolvingStyle(checkingContext);
</span><span class="lines">@@ -2546,8 +2543,8 @@
</span><span class="cx"> skipMarking = jumpIfNotResolvingStyle(checkingContext);
</span><span class="cx"> }
</span><span class="cx"> FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
</span><del>- functionCall.setFunctionAddress(setElementStyleIsAffectedByEmptyAndUpdateRenderStyleIfNecessary);
- functionCall.setTwoArguments(elementAddressRegister, isEmptyResults);
</del><ins>+ functionCall.setFunctionAddress(setStyleOfSiblingsAffectedByEmpty);
+ functionCall.setOneArgument(elementAddressRegister);
</ins><span class="cx"> functionCall.call();
</span><span class="cx"> }
</span><span class="cx"> skipMarking.link(&m_assembler);
</span><span class="lines">@@ -2592,7 +2589,7 @@
</span><span class="cx"> // Otherwise we need to apply setFirstChildState() on the RenderStyle.
</span><span class="cx"> failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isFirstChildRegister));
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment))
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment))
</ins><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::setFirstChildStateFlags());
</span><span class="cx"> else {
</span><span class="cx"> FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
</span><span class="lines">@@ -2629,7 +2626,7 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> LocalRegisterWithPreference checkingContext(m_registerAllocator, JSC::GPRInfo::argumentGPR1);
</span><span class="cx"> Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext);
</span><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::flagIsaffectedByHover());
</span><span class="lines">@@ -2712,7 +2709,7 @@
</span><span class="cx"> // Otherwise we need to apply setLastChildState() on the RenderStyle.
</span><span class="cx"> failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isLastChildRegister));
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment))
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment))
</ins><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::setLastChildStateFlags());
</span><span class="cx"> else {
</span><span class="cx"> FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
</span><span class="lines">@@ -2787,7 +2784,7 @@
</span><span class="cx"> // Otherwise we need to apply setLastChildState() on the RenderStyle.
</span><span class="cx"> failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isOnlyChildRegister));
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment))
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment))
</ins><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::setFirstChildStateFlags() | RenderStyle::NonInheritedFlags::setLastChildStateFlags());
</span><span class="cx"> else {
</span><span class="cx"> FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
</span><span class="lines">@@ -2957,7 +2954,7 @@
</span><span class="cx"> functionCall.setOneArgument(parentElement);
</span><span class="cx"> functionCall.call();
</span><span class="cx">
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> addFlagsToElementStyleFromContext(checkingContext, RenderStyle::NonInheritedFlags::flagIsUnique());
</span><span class="cx">
</span><span class="cx"> Assembler::RegisterID elementAddress = elementAddressRegister;
</span><span class="lines">@@ -3038,7 +3035,7 @@
</span><span class="cx"> ASSERT(fragment.pseudoElementSelector);
</span><span class="cx"> ASSERT_WITH_MESSAGE(m_selectorContext != SelectorContext::QuerySelector, "When the fragment has pseudo element, the selector becomes CannotMatchAnything for QuerySelector and this test function is not called.");
</span><span class="cx">
</span><del>- if (!shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (!fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> LocalRegister checkingContext(m_registerAllocator);
</span><span class="cx"> loadCheckingContext(checkingContext);
</span><span class="cx"> failureCases.append(branchOnResolvingModeWithCheckingContext(Assembler::Equal, SelectorChecker::Mode::ResolvingStyle, checkingContext));
</span><span class="lines">@@ -3052,7 +3049,7 @@
</span><span class="cx"> // Make sure that the requested pseudoId equals to the pseudo element of the rightmost fragment.
</span><span class="cx"> // If the rightmost fragment doesn't have a pseudo element, the requested pseudoId need to be NOPSEUDO to succeed the matching.
</span><span class="cx"> // Otherwise, if the requested pseudoId is not NOPSEUDO, the requested pseudoId need to equal to the pseudo element of the rightmost fragment.
</span><del>- if (shouldUseRenderStyleFromCheckingContext(m_selectorContext, fragment)) {
</del><ins>+ if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
</ins><span class="cx"> if (!fragment.pseudoElementSelector)
</span><span class="cx"> failureCases.append(m_assembler.branch8(Assembler::NotEqual, Assembler::Address(checkingContext, OBJECT_OFFSETOF(CheckingContext, pseudoId)), Assembler::TrustedImm32(NOPSEUDO)));
</span><span class="cx"> else {
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/dom/Element.cpp        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -1566,6 +1566,11 @@
</span><span class="cx"> if (!style || (!style->emptyState() || element.hasChildNodes()))
</span><span class="cx"> element.setNeedsStyleRecalc();
</span><span class="cx"> }
</span><ins>+
+ if (element.styleOfSiblingsAffectedByEmpty()) {
+ if (Element* parent = element.parentElement())
+ parent->setNeedsStyleRecalc();
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> enum SiblingCheckType { FinishedParsingChildren, SiblingElementRemoved, Other };
</span><span class="lines">@@ -2132,6 +2137,11 @@
</span><span class="cx"> ensureElementRareData().setStyleAffectedByEmpty(true);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void Element::setStyleOfSiblingsAffectedByEmpty()
+{
+ ensureElementRareData().setStyleOfSiblingsAffectedByEmpty(true);
+}
+
</ins><span class="cx"> void Element::setChildrenAffectedByActive()
</span><span class="cx"> {
</span><span class="cx"> ensureElementRareData().setChildrenAffectedByActive(true);
</span><span class="lines">@@ -2179,6 +2189,12 @@
</span><span class="cx"> return elementRareData()->styleAffectedByEmpty();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool Element::rareDataStyleOfSiblingsAffectedByEmpty() const
+{
+ ASSERT(hasRareData());
+ return elementRareData()->styleOfSiblingsAffectedByEmpty();
+}
+
</ins><span class="cx"> bool Element::rareDataChildrenAffectedByActive() const
</span><span class="cx"> {
</span><span class="cx"> ASSERT(hasRareData());
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.h (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.h        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/dom/Element.h        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -357,6 +357,7 @@
</span><span class="cx">
</span><span class="cx"> // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
</span><span class="cx"> bool styleAffectedByEmpty() const { return hasRareData() && rareDataStyleAffectedByEmpty(); }
</span><ins>+ bool styleOfSiblingsAffectedByEmpty() const { return hasRareData() && rareDataStyleOfSiblingsAffectedByEmpty(); }
</ins><span class="cx"> bool childrenAffectedByHover() const { return getFlag(ChildrenAffectedByHoverRulesFlag); }
</span><span class="cx"> bool childrenAffectedByActive() const { return hasRareData() && rareDataChildrenAffectedByActive(); }
</span><span class="cx"> bool childrenAffectedByDrag() const { return hasRareData() && rareDataChildrenAffectedByDrag(); }
</span><span class="lines">@@ -371,6 +372,7 @@
</span><span class="cx"> bool hasFlagsSetDuringStylingOfChildren() const;
</span><span class="cx">
</span><span class="cx"> void setStyleAffectedByEmpty();
</span><ins>+ void setStyleOfSiblingsAffectedByEmpty();
</ins><span class="cx"> void setChildrenAffectedByHover() { setFlag(ChildrenAffectedByHoverRulesFlag); }
</span><span class="cx"> void setChildrenAffectedByActive();
</span><span class="cx"> void setChildrenAffectedByDrag();
</span><span class="lines">@@ -646,6 +648,7 @@
</span><span class="cx"> void removeShadowRoot();
</span><span class="cx">
</span><span class="cx"> bool rareDataStyleAffectedByEmpty() const;
</span><ins>+ bool rareDataStyleOfSiblingsAffectedByEmpty() const;
</ins><span class="cx"> bool rareDataChildrenAffectedByHover() const;
</span><span class="cx"> bool rareDataChildrenAffectedByActive() const;
</span><span class="cx"> bool rareDataChildrenAffectedByDrag() const;
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementRareDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ElementRareData.h (172720 => 172721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ElementRareData.h        2014-08-18 20:41:27 UTC (rev 172720)
+++ trunk/Source/WebCore/dom/ElementRareData.h        2014-08-18 20:52:04 UTC (rev 172721)
</span><span class="lines">@@ -60,6 +60,9 @@
</span><span class="cx"> bool styleAffectedByEmpty() const { return m_styleAffectedByEmpty; }
</span><span class="cx"> void setStyleAffectedByEmpty(bool value) { m_styleAffectedByEmpty = value; }
</span><span class="cx">
</span><ins>+ bool styleOfSiblingsAffectedByEmpty() const { return m_styleOfSiblingsAffectedByEmpty; }
+ void setStyleOfSiblingsAffectedByEmpty(bool value) { m_styleOfSiblingsAffectedByEmpty = value; }
+
</ins><span class="cx"> RegionOversetState regionOversetState() const { return m_regionOversetState; }
</span><span class="cx"> void setRegionOversetState(RegionOversetState state) { m_regionOversetState = state; }
</span><span class="cx">
</span><span class="lines">@@ -121,6 +124,7 @@
</span><span class="cx"> unsigned m_tabIndexWasSetExplicitly : 1;
</span><span class="cx"> unsigned m_needsFocusAppearanceUpdateSoonAfterAttach : 1;
</span><span class="cx"> unsigned m_styleAffectedByEmpty : 1;
</span><ins>+ unsigned m_styleOfSiblingsAffectedByEmpty : 1;
</ins><span class="cx"> #if ENABLE(FULLSCREEN_API)
</span><span class="cx"> unsigned m_containsFullScreenElement : 1;
</span><span class="cx"> #endif
</span><span class="lines">@@ -165,6 +169,7 @@
</span><span class="cx"> , m_tabIndexWasSetExplicitly(false)
</span><span class="cx"> , m_needsFocusAppearanceUpdateSoonAfterAttach(false)
</span><span class="cx"> , m_styleAffectedByEmpty(false)
</span><ins>+ , m_styleOfSiblingsAffectedByEmpty(false)
</ins><span class="cx"> #if ENABLE(FULLSCREEN_API)
</span><span class="cx"> , m_containsFullScreenElement(false)
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>
</body>
</html>