Diff
Modified: trunk/LayoutTests/ChangeLog (175017 => 175018)
--- trunk/LayoutTests/ChangeLog 2014-10-22 02:56:54 UTC (rev 175017)
+++ trunk/LayoutTests/ChangeLog 2014-10-22 03:28:29 UTC (rev 175018)
@@ -1,3 +1,30 @@
+2014-10-21 Benjamin Poulain <[email protected]>
+
+ 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.
+
2014-10-21 Brent Fulgham <[email protected]>
[Win] Unreviewed test updates after switching to Windows theme for tests.
Added: trunk/LayoutTests/fast/css/class-style-invalidation-optimization-expected.txt (0 => 175018)
--- 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)
@@ -0,0 +1,45 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/css/class-style-invalidation-optimization.html (0 => 175018)
--- 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)
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+* {
+ 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);
+}
+</style>
+</head>
+<body>
+ <div>
+ <!-- With renderer -->
+ <target></target>
+ </div>
+ <div style="display:none;">
+ <!-- Without renderer -->
+ <target></target>
+ </div>
+</body>
+<script>
+
+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("window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\"target\")[0])");
+ testFunction("window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\"target\")[1])");
+}
+
+function addClass(name) {
+ var allTargets = document.querySelectorAll("target");
+ allTargets[0].classList.add(name);
+ allTargets[1].classList.add(name);
+}
+
+function checkStyle(expectedColor) {
+ var allTargets = document.querySelectorAll("target");
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[0]).color', expectedColor);
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[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);
+</script>
+<script src=""
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1-expected.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ div + div {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div style="background-color: red; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-1.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ div + div {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2-expected.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ div + div {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div style="background-color: red; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-2.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ :matches(div + div) {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3-expected.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ div + div {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div style="background-color: red; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ <div style="background-color: green; border: 1px solid black; width: 100px; height: 100px;"></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/direct-adjacent-style-sharing-3.html (0 => 175018)
--- 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)
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <style type="text/css">
+ div {
+ background-color: red;
+ border: 1px solid black;
+ width: 100px;
+ height: 100px;
+ }
+
+ :matches(:matches(div + div)) {
+ background-color: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>If the test pass, there should be one red block followed by 3 green blocks.</p>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ </body>
+</html>
Added: trunk/LayoutTests/fast/css/id-style-invalidation-optimization-expected.txt (0 => 175018)
--- 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)
@@ -0,0 +1,37 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is true
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is true
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[0]) is false
+PASS window.internals.nodeNeedsStyleRecalc(document.querySelectorAll("target")[1]) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/css/id-style-invalidation-optimization.html (0 => 175018)
--- 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)
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+* {
+ 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);
+}
+</style>
+</head>
+<body>
+ <div>
+ <!-- With renderer -->
+ <target></target>
+ </div>
+ <div style="display:none;">
+ <!-- Without renderer -->
+ <target></target>
+ </div>
+</body>
+<script>
+
+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("window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\"target\")[0])");
+ testFunction("window.internals.nodeNeedsStyleRecalc(document.querySelectorAll(\"target\")[1])");
+}
+
+function setId(name) {
+ var allTargets = document.querySelectorAll("target");
+ allTargets[0].id = name;
+ allTargets[1].id = name;
+}
+
+function checkStyle(expectedColor) {
+ var allTargets = document.querySelectorAll("target");
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[0]).color', expectedColor);
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[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);
+</script>
+<script src=""
+</html>
Added: trunk/LayoutTests/fast/selectors/class-style-update-expected.txt (0 => 175018)
--- 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)
@@ -0,0 +1,51 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/selectors/class-style-update-with-not-expected.txt (0 => 175018)
--- 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)
@@ -0,0 +1,41 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(12, 13, 14)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(12, 13, 14)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+FAIL getComputedStyle(document.querySelectorAll("target")[0]).color should be rgb(3, 4, 5). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[1]).color should be rgb(3, 4, 5). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[0]).color should be rgb(6, 7, 8). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[1]).color should be rgb(6, 7, 8). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[0]).color should be rgb(9, 10, 11). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[1]).color should be rgb(9, 10, 11). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[0]).color should be rgb(12, 13, 14). Was rgb(0, 1, 2).
+FAIL getComputedStyle(document.querySelectorAll("target")[1]).color should be rgb(12, 13, 14). Was rgb(0, 1, 2).
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/selectors/class-style-update-with-not.html (0 => 175018)
--- 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)
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+* {
+ 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);
+}
+</style>
+</head>
+<body>
+ <div>
+ <!-- With renderer -->
+ <target class="Case1 Case2 Case3 Case5"></target>
+ </div>
+ <div style="display:none;">
+ <!-- Without renderer -->
+ <target class="Case1 Case2 Case3 Case5"></target>
+ </div>
+</body>
+<script>
+
+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("target");
+ allTargets[0].classList.add(name);
+ allTargets[1].classList.add(name);
+}
+
+function removeClass(name) {
+ var allTargets = document.querySelectorAll("target");
+ allTargets[0].classList.remove(name);
+ allTargets[1].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[0]).color', expectedColor);
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[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)');
+</script>
+<script src=""
+</html>
Added: trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of-expected.txt (0 => 175018)
--- 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)
@@ -0,0 +1,51 @@
+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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(0, 1, 2)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(3, 4, 5)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(6, 7, 8)"
+PASS getComputedStyle(document.querySelectorAll("target")[0]).color is "rgb(9, 10, 11)"
+PASS getComputedStyle(document.querySelectorAll("target")[1]).color is "rgb(9, 10, 11)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/selectors/class-style-update-with-nth-child-of.html (0 => 175018)
--- 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)
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+* {
+ 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);
+}
+</style>
+</head>
+<body>
+ <div>
+ <!-- With renderer -->
+ <padding></padding>
+ <target></target>
+ </div>
+ <div style="display:none;">
+ <!-- Without renderer -->
+ <padding></padding>
+ <target></target>
+ </div>
+</body>
+<script>
+
+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("target, padding");
+ for (var i = 0; i < allTargets.length; ++i)
+ allTargets[i].classList.add(name);
+}
+
+function removeClass(name) {
+ var allTargets = document.querySelectorAll(":matches(target, padding)");
+ for (var i = 0; i < allTargets.length; ++i)
+ allTargets[i].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[0]).color', expectedColor);
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[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)');
+</script>
+<script src=""
+</html>
Added: trunk/LayoutTests/fast/selectors/class-style-update.html (0 => 175018)
--- 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)
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+* {
+ 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);
+}
+</style>
+</head>
+<body>
+ <div>
+ <!-- With renderer -->
+ <target></target>
+ </div>
+ <div style="display:none;">
+ <!-- Without renderer -->
+ <target></target>
+ </div>
+</body>
+<script>
+
+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("target");
+ allTargets[0].classList.add(name);
+ allTargets[1].classList.add(name);
+}
+
+function removeClass(name) {
+ var allTargets = document.querySelectorAll("target");
+ allTargets[0].classList.remove(name);
+ allTargets[1].classList.remove(name);
+}
+
+function checkStyle(expectedColor) {
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[0]).color', expectedColor);
+ shouldBeEqualToString('getComputedStyle(document.querySelectorAll("target")[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)');
+</script>
+<script src=""
+</html>
Modified: trunk/Source/WebCore/ChangeLog (175017 => 175018)
--- 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)
@@ -1,3 +1,35 @@
+2014-10-21 Benjamin Poulain <[email protected]>
+
+ 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):
+
2014-10-21 Tim Horton <[email protected]>
Try to fix the iOS build after r175013.
Modified: trunk/Source/WebCore/css/RuleFeature.cpp (175017 => 175018)
--- 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)
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll ([email protected])
* (C) 2004-2005 Allan Sandfeld Jensen ([email protected])
* Copyright (C) 2006, 2007 Nicholas Shanks ([email protected])
- * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2012, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <[email protected]>
* Copyright (C) 2007, 2008 Eric Seidel <[email protected]>
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
@@ -30,36 +30,59 @@
#include "RuleFeature.h"
#include "CSSSelector.h"
+#include "CSSSelectorList.h"
namespace WebCore {
-void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector* selector)
+static void recursivelyCollectFeaturesFromSelector(RuleFeatureSet& features, const CSSSelector& firstSelector, bool& hasSiblingSelector)
{
- if (selector->match() == CSSSelector::Id)
- idsInRules.add(selector->value().impl());
- else if (selector->match() == CSSSelector::Class)
- classesInRules.add(selector->value().impl());
- else if (selector->isAttributeSelector()) {
- attributeCanonicalLocalNamesInRules.add(selector->attributeCanonicalLocalName().impl());
- attributeLocalNamesInRules.add(selector->attribute().localName().impl());
- } else if (selector->match() == CSSSelector::PseudoElement) {
- switch (selector->pseudoElementType()) {
- case CSSSelector::PseudoElementFirstLine:
- usesFirstLineRules = true;
- break;
- case CSSSelector::PseudoElementFirstLetter:
- usesFirstLetterRules = true;
- break;
- case CSSSelector::PseudoElementBefore:
- case CSSSelector::PseudoElementAfter:
- usesBeforeAfterRules = true;
- break;
- default:
- break;
+ const CSSSelector* selector = &firstSelector;
+ do {
+ if (selector->match() == CSSSelector::Id)
+ features.idsInRules.add(selector->value().impl());
+ else if (selector->match() == CSSSelector::Class)
+ features.classesInRules.add(selector->value().impl());
+ else if (selector->isAttributeSelector()) {
+ features.attributeCanonicalLocalNamesInRules.add(selector->attributeCanonicalLocalName().impl());
+ features.attributeLocalNamesInRules.add(selector->attribute().localName().impl());
+ } else if (selector->match() == CSSSelector::PseudoElement) {
+ switch (selector->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;
+ }
}
- }
+
+ if (!hasSiblingSelector && selector->isSiblingSelector())
+ hasSiblingSelector = true;
+
+ if (const CSSSelectorList* selectorList = selector->selectorList()) {
+ for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
+ if (!hasSiblingSelector && selector->isSiblingSelector())
+ hasSiblingSelector = true;
+ recursivelyCollectFeaturesFromSelector(features, *subSelector, hasSiblingSelector);
+ }
+ }
+
+ selector = selector->tagHistory();
+ } while (selector);
}
+void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& firstSelector, bool& hasSiblingSelector)
+{
+ hasSiblingSelector = false;
+ recursivelyCollectFeaturesFromSelector(*this, firstSelector, hasSiblingSelector);
+}
+
void RuleFeatureSet::add(const RuleFeatureSet& other)
{
idsInRules.add(other.idsInRules.begin(), other.idsInRules.end());
Modified: trunk/Source/WebCore/css/RuleFeature.h (175017 => 175018)
--- 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)
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999 Lars Knoll ([email protected])
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2011, 2014 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -54,7 +54,7 @@
void add(const RuleFeatureSet&);
void clear();
- void collectFeaturesFromSelector(const CSSSelector*);
+ void collectFeaturesFromSelector(const CSSSelector&, bool& hasSiblingSelector);
HashSet<AtomicStringImpl*> idsInRules;
HashSet<AtomicStringImpl*> classesInRules;
Modified: trunk/Source/WebCore/css/RuleSet.cpp (175017 => 175018)
--- 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)
@@ -166,20 +166,10 @@
static void collectFeaturesFromRuleData(RuleFeatureSet& features, const RuleData& ruleData)
{
- bool foundSiblingSelector = false;
- for (const CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) {
- features.collectFeaturesFromSelector(selector);
-
- if (const CSSSelectorList* selectorList = selector->selectorList()) {
- for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
- if (!foundSiblingSelector && selector->isSiblingSelector())
- foundSiblingSelector = true;
- features.collectFeaturesFromSelector(subSelector);
- }
- } else if (!foundSiblingSelector && selector->isSiblingSelector())
- foundSiblingSelector = true;
- }
- if (foundSiblingSelector)
+ bool hasSiblingSelector;
+ features.collectFeaturesFromSelector(*ruleData.selector(), hasSiblingSelector);
+
+ if (hasSiblingSelector)
features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
if (ruleData.containsUncommonAttributeSelector())
features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));