Chromium Code Reviews

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

Issue 135183002: Avoid unnecessary style recalc for subtree of focused element. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Corrected comments in tests. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « Source/core/core.gypi ('k') | Source/core/dom/ContainerNode.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "config.h"
6 #include "HTMLNames.h"
7 #include "core/dom/Element.h"
8 #include "core/dom/ElementTraversal.h"
9 #include "core/frame/FrameView.h"
10 #include "core/html/HTMLDocument.h"
11 #include "core/html/HTMLElement.h"
12 #include "core/testing/DummyPageHolder.h"
13 #include <gtest/gtest.h>
14
15 using namespace WebCore;
16 using namespace HTMLNames;
17
18 namespace {
19
20 class AffectedByFocusTest : public ::testing::Test {
eseidel 2014/01/31 06:25:19 Very cool that we're building up more unittest arc
21
22 protected:
23
24 struct ElementResult {
25 const WebCore::QualifiedName tag;
26 bool affectedBy;
27 bool childrenAffectedBy;
28 };
29
30 virtual void SetUp() OVERRIDE;
31
32 HTMLDocument& document() const { return *m_document; }
33
34 void setHtmlInnerHTML(const char* htmlContent);
35
36 void checkElements(ElementResult expected[], unsigned expectedCount) const;
37
38 private:
39 OwnPtr<DummyPageHolder> m_dummyPageHolder;
40
41 HTMLDocument* m_document;
42 };
43
44 void AffectedByFocusTest::SetUp()
45 {
46 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
47 m_document = toHTMLDocument(&m_dummyPageHolder->document());
48 ASSERT(m_document);
49 }
50
51 void AffectedByFocusTest::setHtmlInnerHTML(const char* htmlContent)
52 {
53 document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), AS SERT_NO_EXCEPTION);
54 document().view()->updateLayoutAndStyleIfNeededRecursive();
55 }
56
57 void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expec tedCount) const
58 {
59 unsigned i = 0;
60 Element* elm = document().body();
61
62 for (; elm && i < 5; elm = ElementTraversal::next(*elm), ++i) {
63 ASSERT_TRUE(elm->hasTagName(expected[i].tag));
64 ASSERT(elm->renderStyle());
65 ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus()) ;
66 ASSERT_EQ(expected[i].childrenAffectedBy, elm->childrenAffectedByFocus() );
67 }
68
69 ASSERT(!elm && i == size);
70 }
71
72 // A global :focus rule in html.css currently causes every single element to be
eseidel 2014/01/31 06:25:19 We have a bug open with the w3c about this: https
73 // affectedByFocus. Check that all elements in a document with no :focus rules
74 // gets the affectedByFocus set on RenderStyle and not childrenAffectedByFocus.
75 TEST_F(AffectedByFocusTest, UAUniversalFocusRule)
76 {
77 ElementResult expected[] = {
78 { bodyTag, true, false },
79 { divTag, true, false },
80 { divTag, true, false },
81 { divTag, true, false },
82 { spanTag, true, false }
83 };
84
85 setHtmlInnerHTML("<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 childrenAffectedByFocus.
94 TEST_F(AffectedByFocusTest, FocusedAscendant)
95 {
96 ElementResult expected[] = {
97 { bodyTag, true, true },
98 { divTag, true, true },
99 { divTag, true, false },
100 { divTag, true, false },
101 { spanTag, true, false }
102 };
103
104 setHtmlInnerHTML("<head>"
105 "<style>:focus div { background-color: pink }</style>"
106 "</head>"
107 "<body>"
108 "<div><div></div></div>"
109 "<div><span></span></div>"
110 "</body>");
111
112 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
113 }
114
115 // "body:focus div" will mark the body element with childrenAffectedByFocus.
116 TEST_F(AffectedByFocusTest, FocusedAscendantWithType)
117 {
118 ElementResult expected[] = {
119 { bodyTag, true, true },
120 { divTag, true, false },
121 { divTag, true, false },
122 { divTag, true, false },
123 { spanTag, true, false }
124 };
125
126 setHtmlInnerHTML("<head>"
127 "<style>body:focus div { background-color: pink }</style>"
128 "</head>"
129 "<body>"
130 "<div><div></div></div>"
131 "<div><span></span></div>"
132 "</body>");
133
134 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
135 }
136
137 // ":not(body):focus div" should not mark the body element with childrenAffected ByFocus.
138 // Note that currently ":focus:not(body)" does not do the same. Then the :focus is
139 // checked and the childrenAffectedByFocus flag set before the negated type sele ctor
140 // is found.
141 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType)
142 {
143 ElementResult expected[] = {
144 { bodyTag, true, false },
145 { divTag, true, true },
146 { divTag, true, false },
147 { divTag, true, false },
148 { spanTag, true, false }
149 };
150
151 setHtmlInnerHTML("<head>"
152 "<style>:not(body):focus div { background-color: pink }</style>"
153 "</head>"
154 "<body>"
155 "<div><div></div></div>"
156 "<div><span></span></div>"
157 "</body>");
158
159 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
160 }
161
162 // Checking current behavior for ":focus + div", but this is a BUG or at best
163 // sub-optimal. The focused element will also in this case get childrenAffectedB yFocus
164 // even if it's really a sibling. Effectively, the whole sub-tree of the focused
165 // element will have styles recalculated even though none of the children are
166 // affected. There are other mechanisms that makes sure the sibling also gets it s
167 // styles recalculated.
168 TEST_F(AffectedByFocusTest, FocusedSibling)
169 {
170 ElementResult expected[] = {
171 { bodyTag, true, false },
172 { divTag, true, true },
173 { spanTag, true, false },
174 { divTag, true, false }
175 };
176
177 setHtmlInnerHTML("<head>"
178 "<style>:focus + div { background-color: pink }</style>"
179 "</head>"
180 "<body>"
181 "<div>"
182 " <span></span>"
183 "</div>"
184 "<div></div>"
185 "</body>");
186
187 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
188 }
189
190 TEST_F(AffectedByFocusTest, AffectedByFocusUpdate)
191 {
192 // Check that when focussing the outer div in the document below, you only
193 // get a single element style recalc.
194
195 setHtmlInnerHTML("<style>:focus { border: 1px solid lime; }</style>"
196 "<div id=d tabIndex=1>"
197 "<div></div>"
198 "<div></div>"
199 "<div></div>"
200 "<div></div>"
201 "<div></div>"
202 "<div></div>"
203 "<div></div>"
204 "<div></div>"
205 "<div></div>"
206 "<div></div>"
207 "</div>");
208
209 document().view()->updateLayoutAndStyleIfNeededRecursive();
210
211 unsigned startCount = document().styleEngine()->resolverAccessCount();
212
213 document().getElementById("d")->focus();
214 document().view()->updateLayoutAndStyleIfNeededRecursive();
215
216 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount;
217
218 ASSERT_EQ(1U, accessCount);
219 }
220
221 TEST_F(AffectedByFocusTest, ChildrenAffectedByFocusUpdate)
222 {
223 // Check that when focussing the outer div in the document below, you get a
224 // style recalc for the whole subtree.
225
226 setHtmlInnerHTML("<style>:focus div { border: 1px solid lime; }</style>"
227 "<div id=d tabIndex=1>"
228 "<div></div>"
229 "<div></div>"
230 "<div></div>"
231 "<div></div>"
232 "<div></div>"
233 "<div></div>"
234 "<div></div>"
235 "<div></div>"
236 "<div></div>"
237 "<div></div>"
238 "</div>");
239
240 document().view()->updateLayoutAndStyleIfNeededRecursive();
241
242 unsigned startCount = document().styleEngine()->resolverAccessCount();
243
244 document().getElementById("d")->focus();
245 document().view()->updateLayoutAndStyleIfNeededRecursive();
246
247 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount;
248
249 ASSERT_EQ(11U, accessCount);
250 }
251
252 } // namespace
OLDNEW
« no previous file with comments | « Source/core/core.gypi ('k') | Source/core/dom/ContainerNode.cpp » ('j') | no next file with comments »

Powered by Google App Engine