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

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

Powered by Google App Engine
This is Rietveld 408576698