WebCore:
Make :first-child and :first-of-type properly dynamic when the DOM changes. Brings the Acid3 score up
to 66/100.
Reviewed by olliej
Added fast/css/first-child-pseudo-class.html, fast/css/first-of-type-pseudo-class.html, fast/css/empty-body-test.html
* css/CSSGrammar.y:
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::checkOneSelector):
* dom/Element.cpp:
(WebCore::Element::recalcStyle):
(WebCore::Element::childrenChanged):
* rendering/RenderStyle.cpp:
(WebCore::RenderStyle::RenderStyle):
* rendering/RenderStyle.h:
(WebCore::RenderStyle::childrenAffectedByFirstChildRules):
(WebCore::RenderStyle::setChildrenAffectedByFirstChildRules):
(WebCore::RenderStyle::childrenAffectedByLastChildRules):
(WebCore::RenderStyle::setChildrenAffectedByLastChildRules):
(WebCore::RenderStyle::childrenAffectedByPositionalRules):
(WebCore::RenderStyle::setChildrenAffectedByPositionalRules):
(WebCore::RenderStyle::firstChildState):
(WebCore::RenderStyle::setFirstChildState):
(WebCore::RenderStyle::lastChildState):
(WebCore::RenderStyle::setLastChildState):
LayoutTests:
Added tests for dynamic :first-child support (Acid3).
Reviewed by olliej
* fast/css/empty-body-test.html: Added.
* fast/css/first-child-pseudo-class.html: Added.
* fast/css/first-of-type-pseudo-class.html: Added.
* platform/mac/fast/css/empty-body-test-expected.checksum: Added.
* platform/mac/fast/css/empty-body-test-expected.png: Added.
* platform/mac/fast/css/empty-body-test-expected.txt: Added.
* platform/mac/fast/css/first-child-pseudo-class-expected.checksum: Added.
* platform/mac/fast/css/first-child-pseudo-class-expected.png: Added.
* platform/mac/fast/css/first-child-pseudo-class-expected.txt: Added.
* platform/mac/fast/css/first-of-type-pseudo-class-expected.checksum: Added.
* platform/mac/fast/css/first-of-type-pseudo-class-expected.png: Added.
* platform/mac/fast/css/first-of-type-pseudo-class-expected.txt: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@29932 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index be3c2ce3..2d2742e 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,22 @@
+2008-02-01 David Hyatt <hyatt@apple.com>
+
+ Added tests for dynamic :first-child support (Acid3).
+
+ Reviewed by olliej
+
+ * fast/css/empty-body-test.html: Added.
+ * fast/css/first-child-pseudo-class.html: Added.
+ * fast/css/first-of-type-pseudo-class.html: Added.
+ * platform/mac/fast/css/empty-body-test-expected.checksum: Added.
+ * platform/mac/fast/css/empty-body-test-expected.png: Added.
+ * platform/mac/fast/css/empty-body-test-expected.txt: Added.
+ * platform/mac/fast/css/first-child-pseudo-class-expected.checksum: Added.
+ * platform/mac/fast/css/first-child-pseudo-class-expected.png: Added.
+ * platform/mac/fast/css/first-child-pseudo-class-expected.txt: Added.
+ * platform/mac/fast/css/first-of-type-pseudo-class-expected.checksum: Added.
+ * platform/mac/fast/css/first-of-type-pseudo-class-expected.png: Added.
+ * platform/mac/fast/css/first-of-type-pseudo-class-expected.txt: Added.
+
2008-02-02 Dan Bernstein <mitz@apple.com>
- added Tiger-only results for a test
diff --git a/LayoutTests/fast/css/empty-body-test.html b/LayoutTests/fast/css/empty-body-test.html
new file mode 100644
index 0000000..bedc71b
--- /dev/null
+++ b/LayoutTests/fast/css/empty-body-test.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<style type="text/css">
+body:empty { background-color:red; }
+div#appendChild { padding: 1em;}
+</style>
+</head>
+<body>
+<p>There should be no RED on the page</p>
+<div id='appendChild'></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/css/first-child-pseudo-class.html b/LayoutTests/fast/css/first-child-pseudo-class.html
new file mode 100644
index 0000000..eff1797
--- /dev/null
+++ b/LayoutTests/fast/css/first-child-pseudo-class.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>:first-child</title>
+
+ <style type='text/css'>
+ <!--
+
+ body { background: #fff; color: 000; font-family: Arial, Helvetica, sans-serif; }
+ pre { background: #fff; padding: 0.5em; }
+ li { background: #aaa; padding: 1em; width: 80%; margin: 0 0 3em; }
+ .test { display: block; padding: 0.75em; }
+ .base, .defaultgreen { background-color: #090; }
+ .defaultred { background-color: #900; }
+
+ .defaultred :first-child {
+ background-color: #090;
+ }
+
+ .defaultgreen :first-child {
+ background-color: #900;
+ }
+
+ blockquote {
+ margin: 0;
+ }
+
+ -->
+ </style>
+ </head>
+
+ <body>
+ <p>This page is part of the <a href="http://www.css3.info">CSS3.info</a> <a href="http://www.css3.info/selectors-test/">CSS selectors test</a>. See more info on <a href="http://www.css3.info/preview/attribute-selectors.html">CSS3 selectors</a>.</p>
+
+ <div class='base'></div>
+
+ <ol>
+ <li>
+ <div class='defaultred'>
+ <div class='test required'></div>
+ </div>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <div></div>
+</div></pre>
+
+ <p>
+ The CSS selector should match the inner div element, because it is the only child of the outer div element
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div class='test'></div>
+ <blockquote></blockquote>
+ </div>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <div></div>
+ <blockquote></blockquote>
+</div></pre>
+
+ <p>
+ The CSS selector should match the inner div element, because it is the first child of the outer div element
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <!-- Just a comment -->
+ <div class='test'></div>
+ </div>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <!-- Just a comment -->
+ <div></div>
+</div></pre>
+
+ <p>
+ The CSS selector should match the inner div element, because it is the first child of the outer div element
+ Comments are not elements, so they should not be considered when determining the first child.
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ .
+ <div class='test'></div>
+ </div>
+
+ <pre>div :first-child {
+}
+
+<div>
+ How about regular text...
+ <div></div>
+</div></pre>
+
+ <p>
+ The CSS selector should match the inner div element, because it is the first child of the outer div element.
+ Regular text is not an element, so it should not be considered when determining the first child.
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultgreen'>
+ <blockquote></blockquote>
+ <div class='test default required'></div>
+ </div>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <blockquote></blockquote>
+ <div></div>
+</div></pre>
+
+ <p>
+ The CSS selector should not match the inner div element, because it is the second child of the outer div element
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div id='insertBefore1'></div>
+ </div>
+
+ <script type="text/javascript">
+ <!--
+
+ var ib = document.getElementById('insertBefore1');
+ var el = document.createElement("div");
+ el.className = 'test';
+ ib.parentNode.insertBefore(el, ib);
+
+
+ //-->
+ </script>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <div id='insertBefore'></div>
+</div>
+
+var ib = document.getElementById('insertBefore');
+ib.parentElement.insertBefore(document.createElement("div"), ib);</pre>
+
+ <p>
+ The CSS selector should match the div element that is inserted by the Javascript code.
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultgreen'>
+ <div id='insertBefore2' class='test default'></div>
+ </div>
+
+ <script type="text/javascript">
+ <!--
+
+ var ib = document.getElementById('insertBefore2');
+ ib.parentNode.insertBefore(document.createElement("div"), ib);
+
+ //-->
+ </script>
+
+ <pre>div :first-child {
+}
+
+<div>
+ <div id='insertBefore'></div>
+</div>
+
+var ib = document.getElementById('insertBefore');
+ib.parentElement.insertBefore(document.createElement("div"), ib);</pre>
+
+ <p>
+ The original div element should not be a match for the :first-child selector.
+ </p>
+ </li>
+ </ol>
+ </body>
+</html>
diff --git a/LayoutTests/fast/css/first-of-type-pseudo-class.html b/LayoutTests/fast/css/first-of-type-pseudo-class.html
new file mode 100644
index 0000000..40b00df
--- /dev/null
+++ b/LayoutTests/fast/css/first-of-type-pseudo-class.html
@@ -0,0 +1,242 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>:first-of-type</title>
+
+ <style type='text/css'>
+ <!--
+
+ body { background: #fff; color: 000; font-family: Arial, Helvetica, sans-serif; }
+ pre { background: #fff; padding: 0.5em; }
+ li { background: #aaa; padding: 1em; width: 80%; margin: 0 0 3em; }
+ .test { display: block; padding: 0.75em; }
+ .base, .defaultgreen { background-color: #090; }
+ .defaultred { background-color: #900; }
+
+ .defaultred :first-of-type {
+ background-color: #090;
+ }
+
+ .defaultgreen :first-of-type {
+ background-color: #900;
+ }
+
+ blockquote {
+ margin: 0;
+ }
+
+ -->
+ </style>
+ </head>
+
+ <body>
+ <p>This page is part of the <a href="http://www.css3.info">CSS3.info</a> <a href="http://www.css3.info/selectors-test/">CSS selectors test</a>. See more info on <a href="http://www.css3.info/preview/attribute-selectors.html">CSS3 selectors</a>.</p>
+
+ <div class='base'></div>
+
+ <ol>
+ <li>
+ <div class='defaultred'>
+ <div class='test required'></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<div>Does this element match?</div></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the only element of this type
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div class='test'></div>
+ <div></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<div>Does this element match?</div>
+<div></div></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the first element of this type
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <blockquote></blockquote>
+ <div class='test required'></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<blockquote></blockquote>
+<div>Does this element match?</div></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the first element of this type
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div></div>
+ <blockquote>
+ <div class='test'></div>
+ </blockquote>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<div></div>
+<blockquote>
+ <div>Does this element match?</div>
+</blockquote></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the first element of this type in this scope
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div>
+ <div class='test'></div>
+ </div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<div>
+ <div>Does this element match?</div>
+</div></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the first element of this type in the current scope
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <blockquote>
+ <div></div>
+ </blockquote>
+ <div class='test'></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<blockquote>
+ <div></div>
+</blockquote>
+<div>Does this element match?</div></pre>
+
+ <p>
+ The CSS selector should match the marked div element, because it is the first element of this type in the current scope
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultgreen'>
+ <div></div>
+ <div class='test default required'></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<div></div>
+<div>Does this element match?</div></pre>
+
+ <p>
+ The CSS selector should not match the marked div element, because it is the second element of this type
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultgreen'>
+ <DIV></DIV>
+ <div class='test default'></div>
+ </div>
+
+ <pre>div:first-of-type {
+}
+
+<DIV></DIV>
+<div>Does this element match?</div></pre>
+
+ <p>
+ The CSS selector should not match the marked div element, because it is the second element of this type
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultred'>
+ <div id='insertBefore1'></div>
+ </div>
+
+ <script type="text/javascript">
+ <!--
+
+ var ib = document.getElementById('insertBefore1');
+ var el = document.createElement("div");
+ el.className = 'test';
+ ib.parentNode.insertBefore(el, ib);
+
+
+ //-->
+ </script>
+
+ <pre>div:first-of-type {
+}
+
+<div id='insertBefore'></div>
+
+var ib = document.getElementById('insertBefore');
+ib.parentElement.insertBefore(document.createElement("div"), ib);</pre>
+
+ <p>
+ The CSS selector should match the div element that is inserted by the Javascript code.
+ </p>
+ </li>
+
+ <li>
+ <div class='defaultgreen'>
+ <div id='insertBefore2' class='test default'></div>
+ </div>
+
+ <script type="text/javascript">
+ <!--
+
+ var ib = document.getElementById('insertBefore2');
+ ib.parentNode.insertBefore(document.createElement("div"), ib);
+
+ //-->
+ </script>
+
+ <pre>div:first-of-type {
+}
+
+<div id='insertBefore'></div>
+
+var ib = document.getElementById('insertBefore');
+ib.parentElement.insertBefore(document.createElement("div"), ib);</pre>
+
+ <p>
+ The original div element should not be a match for the :first-of-type selector.
+ </p>
+ </li>
+ </ol>
+ </body>
+</html>
diff --git a/LayoutTests/platform/mac/fast/css/empty-body-test-expected.checksum b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.checksum
new file mode 100644
index 0000000..143be62
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.checksum
@@ -0,0 +1 @@
+a9689d3d3e38cffa14b833e060094e0f
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/css/empty-body-test-expected.png b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.png
new file mode 100644
index 0000000..b90eba1
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.png
Binary files differ
diff --git a/LayoutTests/platform/mac/fast/css/empty-body-test-expected.txt b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.txt
new file mode 100644
index 0000000..1373f34
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/empty-body-test-expected.txt
@@ -0,0 +1,9 @@
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x90
+ RenderBlock {HTML} at (0,0) size 800x90
+ RenderBody {BODY} at (8,16) size 784x66
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {#text} at (0,0) size 236x18
+ text run at (0,0) width 236: "There should be no RED on the page"
+ RenderBlock {DIV} at (0,34) size 784x32
diff --git a/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.checksum b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.checksum
new file mode 100644
index 0000000..4caf6fd
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.checksum
@@ -0,0 +1 @@
+8e07410b3e969cae315fdbf7bac24ca7
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.png b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.png
new file mode 100644
index 0000000..936b976
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.png
Binary files differ
diff --git a/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.txt b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.txt
new file mode 100644
index 0000000..d76d0f2
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-child-pseudo-class-expected.txt
@@ -0,0 +1,193 @@
+layer at (0,0) size 785x2263
+ RenderView at (0,0) size 785x600
+layer at (0,0) size 785x2263
+ RenderBlock {HTML} at (0,0) size 785x2263
+ RenderBody {BODY} at (8,16) size 769x2199 [bgcolor=#FFFFFF]
+ RenderBlock {P} at (0,0) size 769x18
+ RenderText {#text} at (0,0) size 165x17
+ text run at (0,0) width 165: "This page is part of the "
+ RenderInline {A} at (0,0) size 73x17 [color=#0000EE]
+ RenderText {#text} at (165,0) size 73x17
+ text run at (165,0) width 73: "CSS3.info"
+ RenderText {#text} at (238,0) size 4x17
+ text run at (238,0) width 4: " "
+ RenderInline {A} at (0,0) size 131x17 [color=#0000EE]
+ RenderText {#text} at (242,0) size 131x17
+ text run at (242,0) width 131: "CSS selectors test"
+ RenderText {#text} at (373,0) size 133x17
+ text run at (373,0) width 133: ". See more info on "
+ RenderInline {A} at (0,0) size 111x17 [color=#0000EE]
+ RenderText {#text} at (506,0) size 111x17
+ text run at (506,0) width 111: "CSS3 selectors"
+ RenderText {#text} at (617,0) size 4x17
+ text run at (617,0) width 4: "."
+ RenderBlock {DIV} at (0,34) size 769x0 [bgcolor=#009900]
+ RenderBlock {OL} at (0,34) size 769x2165
+ RenderListItem {LI} at (40,0) size 615x242 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,53) size 583x105 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "1"
+ RenderText {#text} at (6,8) size 144x91
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 40: "<div>"
+ text run at (46,54) width 0: " "
+ text run at (6,69) width 112: " <div></div>"
+ text run at (118,69) width 0: " "
+ text run at (6,84) width 48: "</div>"
+ RenderBlock {P} at (16,174) size 583x36
+ RenderText {#text} at (0,0) size 572x35
+ text run at (0,0) width 572: "The CSS selector should match the inner div element, because it is the only child"
+ text run at (0,18) width 165: "of the outer div element"
+ RenderListItem {LI} at (40,290) size 615x257 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {BLOCKQUOTE} at (0,24) size 583x0
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "2"
+ RenderText {#text} at (6,8) size 224x106
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 48: "<div> "
+ text run at (54,54) width 0: " "
+ text run at (6,69) width 112: " <div></div>"
+ text run at (118,69) width 0: " "
+ text run at (6,84) width 224: " <blockquote></blockquote>"
+ text run at (230,84) width 0: " "
+ text run at (6,99) width 48: "</div>"
+ RenderBlock {P} at (16,189) size 583x36
+ RenderText {#text} at (0,0) size 567x35
+ text run at (0,0) width 567: "The CSS selector should match the inner div element, because it is the first child"
+ text run at (0,18) width 165: "of the outer div element"
+ RenderListItem {LI} at (40,595) size 615x275 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "3"
+ RenderText {#text} at (6,8) size 208x106
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 48: "<div> "
+ text run at (54,54) width 0: " "
+ text run at (6,69) width 208: " <!-- Just a comment -->"
+ text run at (214,69) width 0: " "
+ text run at (6,84) width 112: " <div></div>"
+ text run at (118,84) width 0: " "
+ text run at (6,99) width 48: "</div>"
+ RenderBlock {P} at (16,189) size 583x54
+ RenderText {#text} at (0,0) size 567x53
+ text run at (0,0) width 567: "The CSS selector should match the inner div element, because it is the first child"
+ text run at (0,18) width 169: "of the outer div element "
+ text run at (169,18) width 358: "Comments are not elements, so they should not be"
+ text run at (0,36) width 307: "considered when determining the first child."
+ RenderListItem {LI} at (40,918) size 615x290 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x42 [bgcolor=#990000]
+ RenderBlock (anonymous) at (0,0) size 583x18
+ RenderListMarker at (-37,0) size 17x17: "4"
+ RenderText {#text} at (0,0) size 4x17
+ text run at (0,0) width 4: "."
+ RenderBlock {DIV} at (0,18) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,71) size 583x117 [bgcolor=#FFFFFF]
+ RenderText {#text} at (6,6) size 224x105
+ text run at (6,6) width 144: "div :first-child {"
+ text run at (150,6) width 0: " "
+ text run at (6,21) width 8: "}"
+ text run at (14,21) width 0: " "
+ text run at (6,36) width 0: " "
+ text run at (6,51) width 48: "<div> "
+ text run at (54,51) width 0: " "
+ text run at (6,66) width 224: " How about regular text..."
+ text run at (230,66) width 0: " "
+ text run at (6,81) width 112: " <div></div>"
+ text run at (118,81) width 0: " "
+ text run at (6,96) width 48: "</div>"
+ RenderBlock {P} at (16,204) size 583x54
+ RenderText {#text} at (0,0) size 567x53
+ text run at (0,0) width 567: "The CSS selector should match the inner div element, because it is the first child"
+ text run at (0,18) width 173: "of the outer div element. "
+ text run at (173,18) width 348: "Regular text is not an element, so it should not be"
+ text run at (0,36) width 307: "considered when determining the first child."
+ RenderListItem {LI} at (40,1256) size 615x257 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#009900]
+ RenderBlock {BLOCKQUOTE} at (0,0) size 583x0 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "5"
+ RenderText {#text} at (6,8) size 224x106
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 48: "<div> "
+ text run at (54,54) width 0: " "
+ text run at (6,69) width 224: " <blockquote></blockquote>"
+ text run at (230,69) width 0: " "
+ text run at (6,84) width 112: " <div></div>"
+ text run at (118,84) width 0: " "
+ text run at (6,99) width 48: "</div>"
+ RenderBlock {P} at (16,189) size 583x36
+ RenderText {#text} at (0,0) size 582x35
+ text run at (0,0) width 582: "The CSS selector should not match the inner div element, because it is the second"
+ text run at (0,18) width 203: "child of the outer div element"
+ RenderListItem {LI} at (40,1561) size 615x287 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,24) size 583x0
+ RenderBlock {PRE} at (16,53) size 583x150 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "6"
+ RenderText {#text} at (6,8) size 520x136
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 40: "<div>"
+ text run at (46,54) width 0: " "
+ text run at (6,69) width 256: " <div id='insertBefore'></div>"
+ text run at (262,69) width 0: " "
+ text run at (6,84) width 48: "</div>"
+ text run at (54,84) width 0: " "
+ text run at (6,99) width 0: " "
+ text run at (6,114) width 392: "var ib = document.getElementById('insertBefore');"
+ text run at (398,114) width 0: " "
+ text run at (6,129) width 520: "ib.parentElement.insertBefore(document.createElement(\"div\"), ib);"
+ RenderBlock {P} at (16,219) size 583x36
+ RenderText {#text} at (0,0) size 567x35
+ text run at (0,0) width 567: "The CSS selector should match the div element that is inserted by the Javascript"
+ text run at (0,18) width 39: "code."
+ RenderListItem {LI} at (40,1896) size 615x269 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x0 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x150 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "7"
+ RenderText {#text} at (6,8) size 520x136
+ text run at (6,8) width 144: "div :first-child {"
+ text run at (150,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 40: "<div>"
+ text run at (46,54) width 0: " "
+ text run at (6,69) width 256: " <div id='insertBefore'></div>"
+ text run at (262,69) width 0: " "
+ text run at (6,84) width 48: "</div>"
+ text run at (54,84) width 0: " "
+ text run at (6,99) width 0: " "
+ text run at (6,114) width 392: "var ib = document.getElementById('insertBefore');"
+ text run at (398,114) width 0: " "
+ text run at (6,129) width 520: "ib.parentElement.insertBefore(document.createElement(\"div\"), ib);"
+ RenderBlock {P} at (16,219) size 583x18
+ RenderText {#text} at (0,0) size 515x17
+ text run at (0,0) width 515: "The original div element should not be a match for the :first-child selector."
diff --git a/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.checksum b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.checksum
new file mode 100644
index 0000000..8df87ce
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.checksum
@@ -0,0 +1 @@
+3840473f25447e19cd6cce4493f3768e
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.png b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.png
new file mode 100644
index 0000000..a1cf3d9
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.png
Binary files differ
diff --git a/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.txt b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.txt
new file mode 100644
index 0000000..bf464a4
--- /dev/null
+++ b/LayoutTests/platform/mac/fast/css/first-of-type-pseudo-class-expected.txt
@@ -0,0 +1,229 @@
+layer at (0,0) size 785x2902
+ RenderView at (0,0) size 785x600
+layer at (0,0) size 785x2902
+ RenderBlock {HTML} at (0,0) size 785x2902
+ RenderBody {BODY} at (8,16) size 769x2838 [bgcolor=#FFFFFF]
+ RenderBlock {P} at (0,0) size 769x18
+ RenderText {#text} at (0,0) size 165x17
+ text run at (0,0) width 165: "This page is part of the "
+ RenderInline {A} at (0,0) size 73x17 [color=#0000EE]
+ RenderText {#text} at (165,0) size 73x17
+ text run at (165,0) width 73: "CSS3.info"
+ RenderText {#text} at (238,0) size 4x17
+ text run at (238,0) width 4: " "
+ RenderInline {A} at (0,0) size 131x17 [color=#0000EE]
+ RenderText {#text} at (242,0) size 131x17
+ text run at (242,0) width 131: "CSS selectors test"
+ RenderText {#text} at (373,0) size 133x17
+ text run at (373,0) width 133: ". See more info on "
+ RenderInline {A} at (0,0) size 111x17 [color=#0000EE]
+ RenderText {#text} at (506,0) size 111x17
+ text run at (506,0) width 111: "CSS3 selectors"
+ RenderText {#text} at (617,0) size 4x17
+ text run at (617,0) width 4: "."
+ RenderBlock {DIV} at (0,34) size 769x0 [bgcolor=#009900]
+ RenderBlock {OL} at (0,34) size 769x2804
+ RenderListItem {LI} at (40,0) size 615x212 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,53) size 583x75 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "1"
+ RenderText {#text} at (6,8) size 280x61
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 280: "<div>Does this element match?</div>"
+ RenderBlock {P} at (16,144) size 583x36
+ RenderText {#text} at (0,0) size 551x35
+ text run at (0,0) width 551: "The CSS selector should match the marked div element, because it is the only"
+ text run at (0,18) width 137: "element of this type"
+ RenderListItem {LI} at (40,260) size 615x227 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,24) size 583x0
+ RenderBlock {PRE} at (16,53) size 583x90 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "2"
+ RenderText {#text} at (6,8) size 280x76
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 280: "<div>Does this element match?</div>"
+ text run at (286,54) width 0: " "
+ text run at (6,69) width 88: "<div></div>"
+ RenderBlock {P} at (16,159) size 583x36
+ RenderText {#text} at (0,0) size 546x35
+ text run at (0,0) width 546: "The CSS selector should match the marked div element, because it is the first"
+ text run at (0,18) width 137: "element of this type"
+ RenderListItem {LI} at (40,535) size 615x227 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {BLOCKQUOTE} at (0,0) size 583x0 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,53) size 583x90 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "3"
+ RenderText {#text} at (6,8) size 280x76
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 200: "<blockquote></blockquote>"
+ text run at (206,54) width 0: " "
+ text run at (6,69) width 280: "<div>Does this element match?</div>"
+ RenderBlock {P} at (16,159) size 583x36
+ RenderText {#text} at (0,0) size 546x35
+ text run at (0,0) width 546: "The CSS selector should match the marked div element, because it is the first"
+ text run at (0,18) width 137: "element of this type"
+ RenderListItem {LI} at (40,810) size 615x257 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x0 [bgcolor=#009900]
+ RenderBlock {BLOCKQUOTE} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "4"
+ RenderText {#text} at (6,8) size 304x106
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 88: "<div></div>"
+ text run at (94,54) width 0: " "
+ text run at (6,69) width 96: "<blockquote>"
+ text run at (102,69) width 0: " "
+ text run at (6,84) width 304: " <div>Does this element match?</div>"
+ text run at (310,84) width 0: " "
+ text run at (6,99) width 104: "</blockquote>"
+ RenderBlock {P} at (16,189) size 583x36
+ RenderText {#text} at (0,0) size 546x35
+ text run at (0,0) width 546: "The CSS selector should match the marked div element, because it is the first"
+ text run at (0,18) width 230: "element of this type in this scope"
+ RenderListItem {LI} at (40,1115) size 615x242 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x105 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "5"
+ RenderText {#text} at (6,8) size 304x91
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 40: "<div>"
+ text run at (46,54) width 0: " "
+ text run at (6,69) width 304: " <div>Does this element match?</div>"
+ text run at (310,69) width 0: " "
+ text run at (6,84) width 48: "</div>"
+ RenderBlock {P} at (16,174) size 583x36
+ RenderText {#text} at (0,0) size 546x35
+ text run at (0,0) width 546: "The CSS selector should match the marked div element, because it is the first"
+ text run at (0,18) width 280: "element of this type in the current scope"
+ RenderListItem {LI} at (40,1405) size 615x257 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {BLOCKQUOTE} at (0,0) size 583x0 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x0
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "6"
+ RenderText {#text} at (6,8) size 280x106
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 96: "<blockquote>"
+ text run at (102,54) width 0: " "
+ text run at (6,69) width 112: " <div></div>"
+ text run at (118,69) width 0: " "
+ text run at (6,84) width 104: "</blockquote>"
+ text run at (110,84) width 0: " "
+ text run at (6,99) width 280: "<div>Does this element match?</div>"
+ RenderBlock {P} at (16,189) size 583x36
+ RenderText {#text} at (0,0) size 546x35
+ text run at (0,0) width 546: "The CSS selector should match the marked div element, because it is the first"
+ text run at (0,18) width 280: "element of this type in the current scope"
+ RenderListItem {LI} at (40,1710) size 615x227 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x0 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x90 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "7"
+ RenderText {#text} at (6,8) size 280x76
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 88: "<div></div>"
+ text run at (94,54) width 0: " "
+ text run at (6,69) width 280: "<div>Does this element match?</div>"
+ RenderBlock {P} at (16,159) size 583x36
+ RenderText {#text} at (0,0) size 543x35
+ text run at (0,0) width 543: "The CSS selector should not match the marked div element, because it is the"
+ text run at (0,18) width 193: "second element of this type"
+ RenderListItem {LI} at (40,1985) size 615x227 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x0 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x90 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "8"
+ RenderText {#text} at (6,8) size 280x76
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 88: "<DIV></DIV>"
+ text run at (94,54) width 0: " "
+ text run at (6,69) width 280: "<div>Does this element match?</div>"
+ RenderBlock {P} at (16,159) size 583x36
+ RenderText {#text} at (0,0) size 543x35
+ text run at (0,0) width 543: "The CSS selector should not match the marked div element, because it is the"
+ text run at (0,18) width 193: "second element of this type"
+ RenderListItem {LI} at (40,2260) size 615x257 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,24) size 583x0
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-37,6) size 17x17: "9"
+ RenderText {#text} at (6,8) size 520x106
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 232: "<div id='insertBefore'></div>"
+ text run at (238,54) width 0: " "
+ text run at (6,69) width 0: " "
+ text run at (6,84) width 392: "var ib = document.getElementById('insertBefore');"
+ text run at (398,84) width 0: " "
+ text run at (6,99) width 520: "ib.parentElement.insertBefore(document.createElement(\"div\"), ib);"
+ RenderBlock {P} at (16,189) size 583x36
+ RenderText {#text} at (0,0) size 567x35
+ text run at (0,0) width 567: "The CSS selector should match the div element that is inserted by the Javascript"
+ text run at (0,18) width 39: "code."
+ RenderListItem {LI} at (40,2565) size 615x239 [bgcolor=#AAAAAA]
+ RenderBlock {DIV} at (16,16) size 583x24 [bgcolor=#009900]
+ RenderBlock {DIV} at (0,0) size 583x0 [bgcolor=#990000]
+ RenderBlock {DIV} at (0,0) size 583x24
+ RenderBlock {PRE} at (16,53) size 583x120 [bgcolor=#FFFFFF]
+ RenderListMarker at (-46,6) size 26x17: "10"
+ RenderText {#text} at (6,8) size 520x106
+ text run at (6,8) width 152: "div:first-of-type {"
+ text run at (158,8) width 0: " "
+ text run at (6,24) width 8: "}"
+ text run at (14,24) width 0: " "
+ text run at (6,39) width 0: " "
+ text run at (6,54) width 232: "<div id='insertBefore'></div>"
+ text run at (238,54) width 0: " "
+ text run at (6,69) width 0: " "
+ text run at (6,84) width 392: "var ib = document.getElementById('insertBefore');"
+ text run at (398,84) width 0: " "
+ text run at (6,99) width 520: "ib.parentElement.insertBefore(document.createElement(\"div\"), ib);"
+ RenderBlock {P} at (16,189) size 583x18
+ RenderText {#text} at (0,0) size 529x17
+ text run at (0,0) width 529: "The original div element should not be a match for the :first-of-type selector."
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 164dd92..29cfac7 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,32 @@
+2008-02-01 David Hyatt <hyatt@apple.com>
+
+ Make :first-child and :first-of-type properly dynamic when the DOM changes. Brings the Acid3 score up
+ to 66/100.
+
+ Reviewed by olliej
+
+ Added fast/css/first-child-pseudo-class.html, fast/css/first-of-type-pseudo-class.html, fast/css/empty-body-test.html
+
+ * css/CSSGrammar.y:
+ * css/CSSStyleSelector.cpp:
+ (WebCore::CSSStyleSelector::checkOneSelector):
+ * dom/Element.cpp:
+ (WebCore::Element::recalcStyle):
+ (WebCore::Element::childrenChanged):
+ * rendering/RenderStyle.cpp:
+ (WebCore::RenderStyle::RenderStyle):
+ * rendering/RenderStyle.h:
+ (WebCore::RenderStyle::childrenAffectedByFirstChildRules):
+ (WebCore::RenderStyle::setChildrenAffectedByFirstChildRules):
+ (WebCore::RenderStyle::childrenAffectedByLastChildRules):
+ (WebCore::RenderStyle::setChildrenAffectedByLastChildRules):
+ (WebCore::RenderStyle::childrenAffectedByPositionalRules):
+ (WebCore::RenderStyle::setChildrenAffectedByPositionalRules):
+ (WebCore::RenderStyle::firstChildState):
+ (WebCore::RenderStyle::setFirstChildState):
+ (WebCore::RenderStyle::lastChildState):
+ (WebCore::RenderStyle::setLastChildState):
+
2008-02-02 Dan Bernstein <mitz@apple.com>
Reviewed by Oliver Hunt.
diff --git a/WebCore/css/CSSGrammar.y b/WebCore/css/CSSGrammar.y
index 9c07b9e..04bdde3 100644
--- a/WebCore/css/CSSGrammar.y
+++ b/WebCore/css/CSSGrammar.y
@@ -855,7 +855,8 @@
if (type == CSSSelector::PseudoUnknown)
$$ = 0;
else if (type == CSSSelector::PseudoEmpty ||
- type == CSSSelector::PseudoFirstChild) {
+ type == CSSSelector::PseudoFirstChild ||
+ type == CSSSelector::PseudoFirstOfType) {
CSSParser* p = static_cast<CSSParser*>(parser);
Document* doc = p->document();
if (doc)
diff --git a/WebCore/css/CSSStyleSelector.cpp b/WebCore/css/CSSStyleSelector.cpp
index 9295b92..f85e9e5 100644
--- a/WebCore/css/CSSStyleSelector.cpp
+++ b/WebCore/css/CSSStyleSelector.cpp
@@ -1593,35 +1593,54 @@
}
}
}
- if (m_element == e)
- m_style->setEmptyState(result);
- else if (e && e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))
- e->renderStyle()->setEmptyState(result);
+ if (!m_collectRulesOnly) {
+ if (m_element == e)
+ m_style->setEmptyState(result);
+ else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))
+ e->renderStyle()->setEmptyState(result);
+ }
return result;
}
case CSSSelector::PseudoFirstChild: {
- // first-child matches the first child that is an element!
+ // first-child matches the first child that is an element
if (e->parentNode() && e->parentNode()->isElementNode()) {
- Node *n = e->previousSibling();
+ bool result = false;
+ Node* n = e->previousSibling();
while (n && !n->isElementNode())
n = n->previousSibling();
if (!n)
- return true;
+ result = true;
+ if (!m_collectRulesOnly) {
+ RenderStyle* childStyle = (m_element == e) ? m_style : e->renderStyle();
+ RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
+ if (parentStyle)
+ parentStyle->setChildrenAffectedByFirstChildRules();
+ if (result && childStyle)
+ childStyle->setFirstChildState();
+ }
+ return result;
}
break;
}
case CSSSelector::PseudoFirstOfType: {
- // first-of-type matches the first element of its type!
+ // first-of-type matches the first element of its type
if (e->parentNode() && e->parentNode()->isElementNode()) {
+ bool result = false;
const QualifiedName& type = e->tagQName();
- Node *n = e->previousSibling();
+ Node* n = e->previousSibling();
while (n) {
if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
break;
n = n->previousSibling();
}
if (!n)
- return true;
+ result = true;
+ if (!m_collectRulesOnly) {
+ RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
+ if (parentStyle)
+ parentStyle->setChildrenAffectedByPositionalRules();
+ }
+ return result;
}
break;
}
diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp
index 920b36a..42d3787 100644
--- a/WebCore/dom/Element.cpp
+++ b/WebCore/dom/Element.cpp
@@ -698,9 +698,10 @@
void Element::recalcStyle(StyleChange change)
{
- // ### should go away and be done in renderobject
RenderStyle* currentStyle = renderStyle();
bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
+ bool hasPositionalChildren = currentStyle && (currentStyle->childrenAffectedByFirstChildRules() || currentStyle->childrenAffectedByLastChildRules() ||
+ currentStyle->childrenAffectedByPositionalRules());
#if ENABLE(SVG)
if (!hasParentStyle && isShadowNode() && isSVGElement())
@@ -727,13 +728,20 @@
}
if (currentStyle && newStyle) {
- // Preserve "affected by" bits that were propagated to us from descendants
+ // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
+ // style change (e.g., only inline style changed).
if (currentStyle->affectedByHoverRules())
newStyle->setAffectedByHoverRules(true);
if (currentStyle->affectedByActiveRules())
newStyle->setAffectedByActiveRules(true);
if (currentStyle->affectedByDragRules())
newStyle->setAffectedByDragRules(true);
+ if (currentStyle->childrenAffectedByPositionalRules())
+ newStyle->setChildrenAffectedByPositionalRules();
+ if (currentStyle->childrenAffectedByFirstChildRules())
+ newStyle->setChildrenAffectedByFirstChildRules();
+ if (currentStyle->childrenAffectedByLastChildRules())
+ newStyle->setChildrenAffectedByLastChildRules();
}
if (ch != NoChange) {
@@ -753,7 +761,7 @@
newStyle->deref(document()->renderArena());
if (change != Force) {
- if (document()->usesDescendantRules() && styleChangeType() == FullStyleChange)
+ if ((document()->usesDescendantRules() || hasPositionalChildren) && styleChangeType() == FullStyleChange)
change = Force;
else
change = ch;
@@ -785,6 +793,55 @@
}
}
+static bool checkFirstChildRules(Element* e, RenderStyle* style)
+{
+ if (style->childrenAffectedByFirstChildRules()) {
+ // Check our first two children. They need to be true and false respectively.
+ bool checkingFirstChild = true;
+ for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
+ if (n->isElementNode()) {
+ if (checkingFirstChild) {
+ if (n->attached() && n->renderStyle() && !n->renderStyle()->firstChildState())
+ return true;
+ checkingFirstChild = false;
+ } else {
+ if (n->attached() && n->renderStyle() && n->renderStyle()->firstChildState())
+ return true;
+ break;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool checkLastChildRules(Element* e, RenderStyle* style)
+{
+ if (style->childrenAffectedByLastChildRules()) {
+ // Check our last two children. They need to be true and false respectively.
+ bool checkingLastChild = true;
+ for (Node* n = e->lastChild(); n; n = n->previousSibling()) {
+ if (n->isElementNode()) {
+ if (checkingLastChild) {
+ if (n->attached() && n->renderStyle() && !n->renderStyle()->lastChildState())
+ return true;
+ checkingLastChild = false;
+ } else {
+ if (n->attached() && n->renderStyle() && n->renderStyle()->lastChildState())
+ return true;
+ break;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool checkEmptyRules(Element* e, RenderStyle* style)
+{
+ return (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()));
+}
+
void Element::childrenChanged()
{
ContainerNode::childrenChanged();
@@ -796,8 +853,15 @@
if (!style)
return;
- if (style->affectedByEmpty() && (!style->emptyState() || hasChildNodes()))
- setChanged(); // Need to resolve style again, since our :empty state has potentially changed.
+ if (style->childrenAffectedByPositionalRules()) {
+ setChanged();
+ return;
+ }
+
+ if (checkFirstChildRules(this, style) || checkLastChildRules(this, style) || checkEmptyRules(this, style)) {
+ setChanged();
+ return;
+ }
}
void Element::dispatchAttrRemovalEvent(Attribute*)
diff --git a/WebCore/rendering/RenderStyle.cpp b/WebCore/rendering/RenderStyle.cpp
index 7d51fba..516c4fd 100644
--- a/WebCore/rendering/RenderStyle.cpp
+++ b/WebCore/rendering/RenderStyle.cpp
@@ -932,6 +932,11 @@
, m_unique(false)
, m_affectedByEmpty(false)
, m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
, m_ref(0)
#if ENABLE(SVG)
, m_svgStyle(defaultStyle->m_svgStyle)
@@ -947,6 +952,11 @@
, m_unique(false)
, m_affectedByEmpty(false)
, m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
, m_ref(1)
{
setBitDefaults();
@@ -984,6 +994,11 @@
, m_unique(false)
, m_affectedByEmpty(false)
, m_emptyState(false)
+ , m_childrenAffectedByFirstChildRules(false)
+ , m_childrenAffectedByLastChildRules(false)
+ , m_childrenAffectedByPositionalRules(false)
+ , m_firstChildState(false)
+ , m_lastChildState(false)
, m_ref(0)
#if ENABLE(SVG)
, m_svgStyle(o.m_svgStyle)
diff --git a/WebCore/rendering/RenderStyle.h b/WebCore/rendering/RenderStyle.h
index ef81db8..c8cea7c 100644
--- a/WebCore/rendering/RenderStyle.h
+++ b/WebCore/rendering/RenderStyle.h
@@ -1470,6 +1470,14 @@
bool m_affectedByEmpty : 1;
bool m_emptyState : 1;
+ // We optimize for :first-child and :last-child. The other positional child selectors like nth-child or
+ // *-child-of-type, we will just give up and re-evaluate whenever children change at all.
+ bool m_childrenAffectedByFirstChildRules : 1;
+ bool m_childrenAffectedByLastChildRules : 1;
+ bool m_childrenAffectedByPositionalRules : 1;
+ bool m_firstChildState : 1;
+ bool m_lastChildState : 1;
+
int m_ref;
#if ENABLE(SVG)
@@ -2116,6 +2124,16 @@
bool affectedByEmpty() const { return m_affectedByEmpty; }
bool emptyState() const { return m_emptyState; }
void setEmptyState(bool b) { m_affectedByEmpty = true; m_unique = true; m_emptyState = b; }
+ bool childrenAffectedByFirstChildRules() const { return m_childrenAffectedByFirstChildRules; }
+ void setChildrenAffectedByFirstChildRules() { m_childrenAffectedByFirstChildRules = true; }
+ bool childrenAffectedByLastChildRules() const { return m_childrenAffectedByLastChildRules; }
+ void setChildrenAffectedByLastChildRules() { m_childrenAffectedByLastChildRules = true; }
+ bool childrenAffectedByPositionalRules() const { return m_childrenAffectedByPositionalRules; }
+ void setChildrenAffectedByPositionalRules() { m_childrenAffectedByPositionalRules = true; }
+ bool firstChildState() const { return m_firstChildState; }
+ void setFirstChildState() { m_firstChildState = true; }
+ bool lastChildState() const { return m_lastChildState; }
+ void setLastChildState() { m_lastChildState = true; }
// Initial values for all the properties
static bool initialBackgroundAttachment() { return true; }