Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(308)

Side by Side Diff: third_party/WebKit/Source/core/css/AffectedByFocusTest.cpp

Issue 2850743003: Stop matching scrollbar pseudo element without a scrollbar. (Closed)
Patch Set: Added unit test. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "core/HTMLNames.h"
6 #include "core/dom/Document.h"
7 #include "core/dom/Element.h"
8 #include "core/dom/ElementTraversal.h"
9 #include "core/dom/NodeComputedStyle.h"
10 #include "core/dom/StyleEngine.h"
11 #include "core/frame/FrameView.h"
12 #include "core/html/HTMLElement.h"
13 #include "core/testing/DummyPageHolder.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include <memory>
16
17 namespace blink {
18
19 using namespace HTMLNames;
20
21 class AffectedByFocusTest : public ::testing::Test {
22 protected:
23 struct ElementResult {
24 const blink::HTMLQualifiedName tag;
25 bool affected_by;
26 bool children_or_siblings_affected_by;
27 };
28
29 void SetUp() override;
30
31 Document& GetDocument() const { return *document_; }
32
33 void SetHtmlInnerHTML(const char* html_content);
34
35 void CheckElements(ElementResult expected[], unsigned expected_count) const;
36
37 private:
38 std::unique_ptr<DummyPageHolder> dummy_page_holder_;
39
40 Persistent<Document> document_;
41 };
42
43 void AffectedByFocusTest::SetUp() {
44 dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
45 document_ = &dummy_page_holder_->GetDocument();
46 DCHECK(document_);
47 }
48
49 void AffectedByFocusTest::SetHtmlInnerHTML(const char* html_content) {
50 GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content));
51 GetDocument().View()->UpdateAllLifecyclePhases();
52 }
53
54 void AffectedByFocusTest::CheckElements(ElementResult expected[],
55 unsigned expected_count) const {
56 unsigned i = 0;
57 HTMLElement* element = GetDocument().body();
58
59 for (; element && i < expected_count;
60 element = Traversal<HTMLElement>::Next(*element), ++i) {
61 ASSERT_TRUE(element->HasTagName(expected[i].tag));
62 DCHECK(element->GetComputedStyle());
63 ASSERT_EQ(expected[i].affected_by,
64 element->GetComputedStyle()->AffectedByFocus());
65 ASSERT_EQ(expected[i].children_or_siblings_affected_by,
66 element->ChildrenOrSiblingsAffectedByFocus());
67 }
68
69 DCHECK(!element);
70 DCHECK_EQ(i, expected_count);
71 }
72
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
75 // gets the affectedByFocus set on ComputedStyle and not
76 // childrenOrSiblingsAffectedByFocus.
77 TEST_F(AffectedByFocusTest, UAUniversalFocusRule) {
78 ElementResult expected[] = {{bodyTag, true, false},
79 {divTag, true, false},
80 {divTag, true, false},
81 {divTag, true, false},
82 {spanTag, true, false}};
83
84 SetHtmlInnerHTML(
85 "<body>"
86 "<div><div></div></div>"
87 "<div><span></span></div>"
88 "</body>");
89
90 CheckElements(expected, sizeof(expected) / sizeof(ElementResult));
91 }
92
93 // ":focus div" will mark ascendants of all divs with
94 // childrenOrSiblingsAffectedByFocus.
95 TEST_F(AffectedByFocusTest, FocusedAscendant) {
96 ElementResult expected[] = {{bodyTag, true, true},
97 {divTag, true, true},
98 {divTag, true, false},
99 {divTag, true, false},
100 {spanTag, true, false}};
101
102 SetHtmlInnerHTML(
103 "<head>"
104 "<style>:focus div { background-color: pink }</style>"
105 "</head>"
106 "<body>"
107 "<div><div></div></div>"
108 "<div><span></span></div>"
109 "</body>");
110
111 CheckElements(expected, sizeof(expected) / sizeof(ElementResult));
112 }
113
114 // "body:focus div" will mark the body element with
115 // childrenOrSiblingsAffectedByFocus.
116 TEST_F(AffectedByFocusTest, FocusedAscendantWithType) {
117 ElementResult expected[] = {{bodyTag, true, true},
118 {divTag, true, false},
119 {divTag, true, false},
120 {divTag, true, false},
121 {spanTag, true, false}};
122
123 SetHtmlInnerHTML(
124 "<head>"
125 "<style>body:focus div { background-color: pink }</style>"
126 "</head>"
127 "<body>"
128 "<div><div></div></div>"
129 "<div><span></span></div>"
130 "</body>");
131
132 CheckElements(expected, sizeof(expected) / sizeof(ElementResult));
133 }
134
135 // ":not(body):focus div" should not mark the body element with
136 // childrenOrSiblingsAffectedByFocus.
137 // Note that currently ":focus:not(body)" does not do the same. Then the :focus
138 // is checked and the childrenOrSiblingsAffectedByFocus flag set before the
139 // negated type selector is found.
140 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType) {
141 ElementResult expected[] = {{bodyTag, true, false},
142 {divTag, true, true},
143 {divTag, true, false},
144 {divTag, true, false},
145 {spanTag, true, false}};
146
147 SetHtmlInnerHTML(
148 "<head>"
149 "<style>:not(body):focus div { background-color: pink }</style>"
150 "</head>"
151 "<body>"
152 "<div><div></div></div>"
153 "<div><span></span></div>"
154 "</body>");
155
156 CheckElements(expected, sizeof(expected) / sizeof(ElementResult));
157 }
158
159 // Checking current behavior for ":focus + div", but this is a BUG or at best
160 // sub-optimal. The focused element will also in this case get
161 // childrenOrSiblingsAffectedByFocus even if it's really a sibling. Effectively,
162 // the whole sub-tree of the focused element will have styles recalculated even
163 // though none of the children are affected. There are other mechanisms that
164 // makes sure the sibling also gets its styles recalculated.
165 TEST_F(AffectedByFocusTest, FocusedSibling) {
166 ElementResult expected[] = {{bodyTag, true, false},
167 {divTag, true, true},
168 {spanTag, true, false},
169 {divTag, true, false}};
170
171 SetHtmlInnerHTML(
172 "<head>"
173 "<style>:focus + div { background-color: pink }</style>"
174 "</head>"
175 "<body>"
176 "<div>"
177 " <span></span>"
178 "</div>"
179 "<div></div>"
180 "</body>");
181
182 CheckElements(expected, sizeof(expected) / sizeof(ElementResult));
183 }
184
185 TEST_F(AffectedByFocusTest, AffectedByFocusUpdate) {
186 // Check that when focussing the outer div in the document below, you only
187 // get a single element style recalc.
188
189 SetHtmlInnerHTML(
190 "<style>:focus { border: 1px solid lime; }</style>"
191 "<div id=d tabIndex=1>"
192 "<div></div>"
193 "<div></div>"
194 "<div></div>"
195 "<div></div>"
196 "<div></div>"
197 "<div></div>"
198 "<div></div>"
199 "<div></div>"
200 "<div></div>"
201 "<div></div>"
202 "</div>");
203
204 GetDocument().View()->UpdateAllLifecyclePhases();
205
206 unsigned start_count = GetDocument().GetStyleEngine().StyleForElementCount();
207
208 GetDocument().getElementById("d")->focus();
209 GetDocument().View()->UpdateAllLifecyclePhases();
210
211 unsigned element_count =
212 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
213
214 ASSERT_EQ(1U, element_count);
215 }
216
217 TEST_F(AffectedByFocusTest, ChildrenOrSiblingsAffectedByFocusUpdate) {
218 // Check that when focussing the outer div in the document below, you get a
219 // style recalc for the whole subtree.
220
221 SetHtmlInnerHTML(
222 "<style>:focus div { border: 1px solid lime; }</style>"
223 "<div id=d tabIndex=1>"
224 "<div></div>"
225 "<div></div>"
226 "<div></div>"
227 "<div></div>"
228 "<div></div>"
229 "<div></div>"
230 "<div></div>"
231 "<div></div>"
232 "<div></div>"
233 "<div></div>"
234 "</div>");
235
236 GetDocument().View()->UpdateAllLifecyclePhases();
237
238 unsigned start_count = GetDocument().GetStyleEngine().StyleForElementCount();
239
240 GetDocument().getElementById("d")->focus();
241 GetDocument().View()->UpdateAllLifecyclePhases();
242
243 unsigned element_count =
244 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
245
246 ASSERT_EQ(11U, element_count);
247 }
248
249 TEST_F(AffectedByFocusTest, InvalidationSetFocusUpdate) {
250 // Check that when focussing the outer div in the document below, you get a
251 // style recalc for the outer div and the class=a div only.
252
253 SetHtmlInnerHTML(
254 "<style>:focus .a { border: 1px solid lime; }</style>"
255 "<div id=d tabIndex=1>"
256 "<div></div>"
257 "<div></div>"
258 "<div></div>"
259 "<div></div>"
260 "<div></div>"
261 "<div></div>"
262 "<div></div>"
263 "<div></div>"
264 "<div></div>"
265 "<div class='a'></div>"
266 "</div>");
267
268 GetDocument().View()->UpdateAllLifecyclePhases();
269
270 unsigned start_count = GetDocument().GetStyleEngine().StyleForElementCount();
271
272 GetDocument().getElementById("d")->focus();
273 GetDocument().View()->UpdateAllLifecyclePhases();
274
275 unsigned element_count =
276 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
277
278 ASSERT_EQ(2U, element_count);
279 }
280
281 TEST_F(AffectedByFocusTest, NoInvalidationSetFocusUpdate) {
282 // Check that when focussing the outer div in the document below, you get a
283 // style recalc for the outer div only. The invalidation set for :focus will
284 // include 'a', but the id=d div should be affectedByFocus, not
285 // childrenOrSiblingsAffectedByFocus.
286
287 SetHtmlInnerHTML(
288 "<style>#nomatch:focus .a { border: 1px solid lime; }</style>"
289 "<div id=d tabIndex=1>"
290 "<div></div>"
291 "<div></div>"
292 "<div></div>"
293 "<div></div>"
294 "<div></div>"
295 "<div></div>"
296 "<div></div>"
297 "<div></div>"
298 "<div></div>"
299 "<div class='a'></div>"
300 "</div>");
301
302 GetDocument().View()->UpdateAllLifecyclePhases();
303
304 unsigned start_count = GetDocument().GetStyleEngine().StyleForElementCount();
305
306 GetDocument().getElementById("d")->focus();
307 GetDocument().View()->UpdateAllLifecyclePhases();
308
309 unsigned element_count =
310 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
311
312 ASSERT_EQ(1U, element_count);
313 }
314
315 TEST_F(AffectedByFocusTest, FocusWithinCommonAncestor) {
316 // Check that when changing the focus between 2 elements we don't need a style
317 // recalc for all the ancestors affected by ":focus-within".
318
319 SetHtmlInnerHTML(
320 "<style>div:focus-within { background-color: lime; }</style>"
321 "<div>"
322 " <div>"
323 " <div id=focusme1 tabIndex=1></div>"
324 " <div id=focusme2 tabIndex=2></div>"
325 " <div>"
326 "</div>");
327
328 GetDocument().View()->UpdateAllLifecyclePhases();
329
330 unsigned start_count = GetDocument().GetStyleEngine().StyleForElementCount();
331
332 GetDocument().getElementById("focusme1")->focus();
333 GetDocument().View()->UpdateAllLifecyclePhases();
334
335 unsigned element_count =
336 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
337
338 EXPECT_EQ(3U, element_count);
339
340 start_count += element_count;
341
342 GetDocument().getElementById("focusme2")->focus();
343 GetDocument().View()->UpdateAllLifecyclePhases();
344
345 element_count =
346 GetDocument().GetStyleEngine().StyleForElementCount() - start_count;
347
348 // Only "focusme1" & "focusme2" elements need a recalc thanks to the common
349 // ancestor strategy.
350 EXPECT_EQ(2U, element_count);
351 }
352
353 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/BUILD.gn ('k') | third_party/WebKit/Source/core/css/AffectedByPseudoTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698