OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "HTMLNames.h" | 6 #include "HTMLNames.h" |
7 #include "core/dom/Element.h" | 7 #include "core/dom/Element.h" |
8 #include "core/dom/ElementTraversal.h" | 8 #include "core/dom/ElementTraversal.h" |
9 #include "core/dom/NodeRenderStyle.h" | 9 #include "core/dom/NodeRenderStyle.h" |
10 #include "core/frame/FrameView.h" | 10 #include "core/frame/FrameView.h" |
11 #include "core/html/HTMLDocument.h" | 11 #include "core/html/HTMLDocument.h" |
12 #include "core/html/HTMLElement.h" | 12 #include "core/html/HTMLElement.h" |
13 #include "core/testing/DummyPageHolder.h" | 13 #include "core/testing/DummyPageHolder.h" |
14 #include <gtest/gtest.h> | 14 #include <gtest/gtest.h> |
15 | 15 |
16 using namespace WebCore; | 16 using namespace WebCore; |
17 using namespace HTMLNames; | 17 using namespace HTMLNames; |
18 | 18 |
19 namespace { | 19 namespace { |
20 | 20 |
21 class AffectedByFocusTest : public ::testing::Test { | 21 class AffectedByFocusTest : public ::testing::Test { |
22 | 22 |
23 protected: | 23 protected: |
24 | 24 |
25 struct ElementResult { | 25 struct ElementResult { |
26 const WebCore::QualifiedName tag; | 26 const WebCore::QualifiedName tag; |
27 bool affectedBy; | 27 bool affectedBy; |
28 bool childrenAffectedBy; | 28 bool childrenOrSiblingsAffectedBy; |
29 }; | 29 }; |
30 | 30 |
31 virtual void SetUp() OVERRIDE; | 31 virtual void SetUp() OVERRIDE; |
32 | 32 |
33 HTMLDocument& document() const { return *m_document; } | 33 HTMLDocument& document() const { return *m_document; } |
34 | 34 |
35 void setHtmlInnerHTML(const char* htmlContent); | 35 void setHtmlInnerHTML(const char* htmlContent); |
36 | 36 |
37 void checkElements(ElementResult expected[], unsigned expectedCount) const; | 37 void checkElements(ElementResult expected[], unsigned expectedCount) const; |
38 | 38 |
(...skipping 18 matching lines...) Expand all Loading... |
57 | 57 |
58 void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expec
tedCount) const | 58 void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expec
tedCount) const |
59 { | 59 { |
60 unsigned i = 0; | 60 unsigned i = 0; |
61 Element* elm = document().body(); | 61 Element* elm = document().body(); |
62 | 62 |
63 for (; elm && i < expectedCount; elm = ElementTraversal::next(*elm), ++i) { | 63 for (; elm && i < expectedCount; elm = ElementTraversal::next(*elm), ++i) { |
64 ASSERT_TRUE(elm->hasTagName(expected[i].tag)); | 64 ASSERT_TRUE(elm->hasTagName(expected[i].tag)); |
65 ASSERT(elm->renderStyle()); | 65 ASSERT(elm->renderStyle()); |
66 ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus())
; | 66 ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus())
; |
67 ASSERT_EQ(expected[i].childrenAffectedBy, elm->childrenAffectedByFocus()
); | 67 ASSERT_EQ(expected[i].childrenOrSiblingsAffectedBy, elm->childrenOrSibli
ngsAffectedByFocus()); |
68 } | 68 } |
69 | 69 |
70 ASSERT(!elm && i == expectedCount); | 70 ASSERT(!elm && i == expectedCount); |
71 } | 71 } |
72 | 72 |
73 // A global :focus rule in html.css currently causes every single element to be | 73 // A global :focus rule in html.css currently causes every single element to be |
74 // affectedByFocus. Check that all elements in a document with no :focus rules | 74 // affectedByFocus. Check that all elements in a document with no :focus rules |
75 // gets the affectedByFocus set on RenderStyle and not childrenAffectedByFocus. | 75 // gets the affectedByFocus set on RenderStyle and not childrenOrSiblingsAffecte
dByFocus. |
76 TEST_F(AffectedByFocusTest, UAUniversalFocusRule) | 76 TEST_F(AffectedByFocusTest, UAUniversalFocusRule) |
77 { | 77 { |
78 ElementResult expected[] = { | 78 ElementResult expected[] = { |
79 { bodyTag, true, false }, | 79 { bodyTag, true, false }, |
80 { divTag, true, false }, | 80 { divTag, true, false }, |
81 { divTag, true, false }, | 81 { divTag, true, false }, |
82 { divTag, true, false }, | 82 { divTag, true, false }, |
83 { spanTag, true, false } | 83 { spanTag, true, false } |
84 }; | 84 }; |
85 | 85 |
86 setHtmlInnerHTML("<body>" | 86 setHtmlInnerHTML("<body>" |
87 "<div><div></div></div>" | 87 "<div><div></div></div>" |
88 "<div><span></span></div>" | 88 "<div><span></span></div>" |
89 "</body>"); | 89 "</body>"); |
90 | 90 |
91 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | 91 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); |
92 } | 92 } |
93 | 93 |
94 // ":focus div" will mark ascendants of all divs with childrenAffectedByFocus. | 94 // ":focus div" will mark ascendants of all divs with childrenOrSiblingsAffected
ByFocus. |
95 TEST_F(AffectedByFocusTest, FocusedAscendant) | 95 TEST_F(AffectedByFocusTest, FocusedAscendant) |
96 { | 96 { |
97 ElementResult expected[] = { | 97 ElementResult expected[] = { |
98 { bodyTag, true, true }, | 98 { bodyTag, true, true }, |
99 { divTag, true, true }, | 99 { divTag, true, true }, |
100 { divTag, true, false }, | 100 { divTag, true, false }, |
101 { divTag, true, false }, | 101 { divTag, true, false }, |
102 { spanTag, true, false } | 102 { spanTag, true, false } |
103 }; | 103 }; |
104 | 104 |
105 setHtmlInnerHTML("<head>" | 105 setHtmlInnerHTML("<head>" |
106 "<style>:focus div { background-color: pink }</style>" | 106 "<style>:focus div { background-color: pink }</style>" |
107 "</head>" | 107 "</head>" |
108 "<body>" | 108 "<body>" |
109 "<div><div></div></div>" | 109 "<div><div></div></div>" |
110 "<div><span></span></div>" | 110 "<div><span></span></div>" |
111 "</body>"); | 111 "</body>"); |
112 | 112 |
113 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | 113 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); |
114 } | 114 } |
115 | 115 |
116 // "body:focus div" will mark the body element with childrenAffectedByFocus. | 116 // "body:focus div" will mark the body element with childrenOrSiblingsAffectedBy
Focus. |
117 TEST_F(AffectedByFocusTest, FocusedAscendantWithType) | 117 TEST_F(AffectedByFocusTest, FocusedAscendantWithType) |
118 { | 118 { |
119 ElementResult expected[] = { | 119 ElementResult expected[] = { |
120 { bodyTag, true, true }, | 120 { bodyTag, true, true }, |
121 { divTag, true, false }, | 121 { divTag, true, false }, |
122 { divTag, true, false }, | 122 { divTag, true, false }, |
123 { divTag, true, false }, | 123 { divTag, true, false }, |
124 { spanTag, true, false } | 124 { spanTag, true, false } |
125 }; | 125 }; |
126 | 126 |
127 setHtmlInnerHTML("<head>" | 127 setHtmlInnerHTML("<head>" |
128 "<style>body:focus div { background-color: pink }</style>" | 128 "<style>body:focus div { background-color: pink }</style>" |
129 "</head>" | 129 "</head>" |
130 "<body>" | 130 "<body>" |
131 "<div><div></div></div>" | 131 "<div><div></div></div>" |
132 "<div><span></span></div>" | 132 "<div><span></span></div>" |
133 "</body>"); | 133 "</body>"); |
134 | 134 |
135 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | 135 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); |
136 } | 136 } |
137 | 137 |
138 // ":not(body):focus div" should not mark the body element with childrenAffected
ByFocus. | 138 // ":not(body):focus div" should not mark the body element with childrenOrSiblin
gsAffectedByFocus. |
139 // Note that currently ":focus:not(body)" does not do the same. Then the :focus
is | 139 // Note that currently ":focus:not(body)" does not do the same. Then the :focus
is |
140 // checked and the childrenAffectedByFocus flag set before the negated type sele
ctor | 140 // checked and the childrenOrSiblingsAffectedByFocus flag set before the negated
type selector |
141 // is found. | 141 // is found. |
142 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType) | 142 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType) |
143 { | 143 { |
144 ElementResult expected[] = { | 144 ElementResult expected[] = { |
145 { bodyTag, true, false }, | 145 { bodyTag, true, false }, |
146 { divTag, true, true }, | 146 { divTag, true, true }, |
147 { divTag, true, false }, | 147 { divTag, true, false }, |
148 { divTag, true, false }, | 148 { divTag, true, false }, |
149 { spanTag, true, false } | 149 { spanTag, true, false } |
150 }; | 150 }; |
151 | 151 |
152 setHtmlInnerHTML("<head>" | 152 setHtmlInnerHTML("<head>" |
153 "<style>:not(body):focus div { background-color: pink }</style>" | 153 "<style>:not(body):focus div { background-color: pink }</style>" |
154 "</head>" | 154 "</head>" |
155 "<body>" | 155 "<body>" |
156 "<div><div></div></div>" | 156 "<div><div></div></div>" |
157 "<div><span></span></div>" | 157 "<div><span></span></div>" |
158 "</body>"); | 158 "</body>"); |
159 | 159 |
160 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | 160 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); |
161 } | 161 } |
162 | 162 |
163 // Checking current behavior for ":focus + div", but this is a BUG or at best | 163 // Checking current behavior for ":focus + div", but this is a BUG or at best |
164 // sub-optimal. The focused element will also in this case get childrenAffectedB
yFocus | 164 // sub-optimal. The focused element will also in this case get childrenOrSibling
sAffectedByFocus |
165 // even if it's really a sibling. Effectively, the whole sub-tree of the focused | 165 // even if it's really a sibling. Effectively, the whole sub-tree of the focused |
166 // element will have styles recalculated even though none of the children are | 166 // element will have styles recalculated even though none of the children are |
167 // affected. There are other mechanisms that makes sure the sibling also gets it
s | 167 // affected. There are other mechanisms that makes sure the sibling also gets it
s |
168 // styles recalculated. | 168 // styles recalculated. |
169 TEST_F(AffectedByFocusTest, FocusedSibling) | 169 TEST_F(AffectedByFocusTest, FocusedSibling) |
170 { | 170 { |
171 ElementResult expected[] = { | 171 ElementResult expected[] = { |
172 { bodyTag, true, false }, | 172 { bodyTag, true, false }, |
173 { divTag, true, true }, | 173 { divTag, true, true }, |
174 { spanTag, true, false }, | 174 { spanTag, true, false }, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 unsigned startCount = document().styleEngine()->resolverAccessCount(); | 212 unsigned startCount = document().styleEngine()->resolverAccessCount(); |
213 | 213 |
214 document().getElementById("d")->focus(); | 214 document().getElementById("d")->focus(); |
215 document().view()->updateLayoutAndStyleIfNeededRecursive(); | 215 document().view()->updateLayoutAndStyleIfNeededRecursive(); |
216 | 216 |
217 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; | 217 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; |
218 | 218 |
219 ASSERT_EQ(1U, accessCount); | 219 ASSERT_EQ(1U, accessCount); |
220 } | 220 } |
221 | 221 |
222 TEST_F(AffectedByFocusTest, ChildrenAffectedByFocusUpdate) | 222 TEST_F(AffectedByFocusTest, ChildrenOrSiblingsAffectedByFocusUpdate) |
223 { | 223 { |
224 // Check that when focussing the outer div in the document below, you get a | 224 // Check that when focussing the outer div in the document below, you get a |
225 // style recalc for the whole subtree. | 225 // style recalc for the whole subtree. |
226 | 226 |
227 setHtmlInnerHTML("<style>:focus div { border: 1px solid lime; }</style>" | 227 setHtmlInnerHTML("<style>:focus div { border: 1px solid lime; }</style>" |
228 "<div id=d tabIndex=1>" | 228 "<div id=d tabIndex=1>" |
229 "<div></div>" | 229 "<div></div>" |
230 "<div></div>" | 230 "<div></div>" |
231 "<div></div>" | 231 "<div></div>" |
232 "<div></div>" | 232 "<div></div>" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 | 278 |
279 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; | 279 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; |
280 | 280 |
281 ASSERT_EQ(2U, accessCount); | 281 ASSERT_EQ(2U, accessCount); |
282 } | 282 } |
283 | 283 |
284 TEST_F(AffectedByFocusTest, NoInvalidationSetFocusUpdate) | 284 TEST_F(AffectedByFocusTest, NoInvalidationSetFocusUpdate) |
285 { | 285 { |
286 // Check that when focussing the outer div in the document below, you get a | 286 // Check that when focussing the outer div in the document below, you get a |
287 // style recalc for the outer div only. The invalidation set for :focus will | 287 // style recalc for the outer div only. The invalidation set for :focus will |
288 // include 'a', but the id=d div should be affectedByFocus, not childrenAffe
ctedByFocus. | 288 // include 'a', but the id=d div should be affectedByFocus, not childrenOrSi
blingsAffectedByFocus. |
289 | 289 |
290 setHtmlInnerHTML("<style>#nomatch:focus .a { border: 1px solid lime; }</styl
e>" | 290 setHtmlInnerHTML("<style>#nomatch:focus .a { border: 1px solid lime; }</styl
e>" |
291 "<div id=d tabIndex=1>" | 291 "<div id=d tabIndex=1>" |
292 "<div></div>" | 292 "<div></div>" |
293 "<div></div>" | 293 "<div></div>" |
294 "<div></div>" | 294 "<div></div>" |
295 "<div></div>" | 295 "<div></div>" |
296 "<div></div>" | 296 "<div></div>" |
297 "<div></div>" | 297 "<div></div>" |
298 "<div></div>" | 298 "<div></div>" |
299 "<div></div>" | 299 "<div></div>" |
300 "<div></div>" | 300 "<div></div>" |
301 "<div class='a'></div>" | 301 "<div class='a'></div>" |
302 "</div>"); | 302 "</div>"); |
303 | 303 |
304 document().view()->updateLayoutAndStyleIfNeededRecursive(); | 304 document().view()->updateLayoutAndStyleIfNeededRecursive(); |
305 | 305 |
306 unsigned startCount = document().styleEngine()->resolverAccessCount(); | 306 unsigned startCount = document().styleEngine()->resolverAccessCount(); |
307 | 307 |
308 document().getElementById("d")->focus(); | 308 document().getElementById("d")->focus(); |
309 document().view()->updateLayoutAndStyleIfNeededRecursive(); | 309 document().view()->updateLayoutAndStyleIfNeededRecursive(); |
310 | 310 |
311 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; | 311 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta
rtCount; |
312 | 312 |
313 ASSERT_EQ(1U, accessCount); | 313 ASSERT_EQ(1U, accessCount); |
314 } | 314 } |
315 | 315 |
316 } // namespace | 316 } // namespace |
OLD | NEW |