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

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

Issue 169643003: Avoid unnecessary style recalc for subtree of focused element. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 10 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
« 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/dom/NodeRenderStyle.h"
10 #include "core/frame/FrameView.h"
11 #include "core/html/HTMLDocument.h"
12 #include "core/html/HTMLElement.h"
13 #include "core/testing/DummyPageHolder.h"
14 #include <gtest/gtest.h>
15
16 using namespace WebCore;
17 using namespace HTMLNames;
18
19 namespace {
20
21 class AffectedByFocusTest : public ::testing::Test {
22
23 protected:
24
25 struct ElementResult {
26 const WebCore::QualifiedName tag;
27 bool affectedBy;
28 bool childrenAffectedBy;
29 };
30
31 virtual void SetUp() OVERRIDE;
32
33 HTMLDocument& document() const { return *m_document; }
34
35 void setHtmlInnerHTML(const char* htmlContent);
36
37 void checkElements(ElementResult expected[], unsigned expectedCount) const;
38
39 private:
40 OwnPtr<DummyPageHolder> m_dummyPageHolder;
41
42 HTMLDocument* m_document;
43 };
44
45 void AffectedByFocusTest::SetUp()
46 {
47 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
48 m_document = toHTMLDocument(&m_dummyPageHolder->document());
49 ASSERT(m_document);
50 }
51
52 void AffectedByFocusTest::setHtmlInnerHTML(const char* htmlContent)
53 {
54 document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), AS SERT_NO_EXCEPTION);
55 document().view()->updateLayoutAndStyleIfNeededRecursive();
56 }
57
58 void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expec tedCount) const
59 {
60 unsigned i = 0;
61 Element* elm = document().body();
62
63 for (; elm && i < expectedCount; elm = ElementTraversal::next(*elm), ++i) {
64 ASSERT_TRUE(elm->hasTagName(expected[i].tag));
65 ASSERT(elm->renderStyle());
66 ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus()) ;
67 ASSERT_EQ(expected[i].childrenAffectedBy, elm->childrenAffectedByFocus() );
68 }
69
70 ASSERT(!elm && i == expectedCount);
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 RenderStyle and not childrenAffectedByFocus.
76 TEST_F(AffectedByFocusTest, UAUniversalFocusRule)
77 {
78 ElementResult expected[] = {
79 { bodyTag, true, false },
80 { divTag, true, false },
81 { divTag, true, false },
82 { divTag, true, false },
83 { spanTag, true, false }
84 };
85
86 setHtmlInnerHTML("<body>"
87 "<div><div></div></div>"
88 "<div><span></span></div>"
89 "</body>");
90
91 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
92 }
93
94 // ":focus div" will mark ascendants of all divs with childrenAffectedByFocus.
95 TEST_F(AffectedByFocusTest, FocusedAscendant)
96 {
97 ElementResult expected[] = {
98 { bodyTag, true, true },
99 { divTag, true, true },
100 { divTag, true, false },
101 { divTag, true, false },
102 { spanTag, true, false }
103 };
104
105 setHtmlInnerHTML("<head>"
106 "<style>:focus div { background-color: pink }</style>"
107 "</head>"
108 "<body>"
109 "<div><div></div></div>"
110 "<div><span></span></div>"
111 "</body>");
112
113 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
114 }
115
116 // "body:focus div" will mark the body element with childrenAffectedByFocus.
117 TEST_F(AffectedByFocusTest, FocusedAscendantWithType)
118 {
119 ElementResult expected[] = {
120 { bodyTag, true, true },
121 { divTag, true, false },
122 { divTag, true, false },
123 { divTag, true, false },
124 { spanTag, true, false }
125 };
126
127 setHtmlInnerHTML("<head>"
128 "<style>body:focus div { background-color: pink }</style>"
129 "</head>"
130 "<body>"
131 "<div><div></div></div>"
132 "<div><span></span></div>"
133 "</body>");
134
135 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
136 }
137
138 // ":not(body):focus div" should not mark the body element with childrenAffected ByFocus.
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
141 // is found.
142 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType)
143 {
144 ElementResult expected[] = {
145 { bodyTag, true, false },
146 { divTag, true, true },
147 { divTag, true, false },
148 { divTag, true, false },
149 { spanTag, true, false }
150 };
151
152 setHtmlInnerHTML("<head>"
153 "<style>:not(body):focus div { background-color: pink }</style>"
154 "</head>"
155 "<body>"
156 "<div><div></div></div>"
157 "<div><span></span></div>"
158 "</body>");
159
160 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
161 }
162
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
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
167 // affected. There are other mechanisms that makes sure the sibling also gets it s
168 // styles recalculated.
169 TEST_F(AffectedByFocusTest, FocusedSibling)
170 {
171 ElementResult expected[] = {
172 { bodyTag, true, false },
173 { divTag, true, true },
174 { spanTag, true, false },
175 { divTag, true, false }
176 };
177
178 setHtmlInnerHTML("<head>"
179 "<style>:focus + div { background-color: pink }</style>"
180 "</head>"
181 "<body>"
182 "<div>"
183 " <span></span>"
184 "</div>"
185 "<div></div>"
186 "</body>");
187
188 checkElements(expected, sizeof(expected) / sizeof(ElementResult));
189 }
190
191 TEST_F(AffectedByFocusTest, AffectedByFocusUpdate)
192 {
193 // Check that when focussing the outer div in the document below, you only
194 // get a single element style recalc.
195
196 setHtmlInnerHTML("<style>:focus { border: 1px solid lime; }</style>"
197 "<div id=d tabIndex=1>"
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></div>"
208 "</div>");
209
210 document().view()->updateLayoutAndStyleIfNeededRecursive();
211
212 unsigned startCount = document().styleEngine()->resolverAccessCount();
213
214 document().getElementById("d")->focus();
215 document().view()->updateLayoutAndStyleIfNeededRecursive();
216
217 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount;
218
219 ASSERT_EQ(1U, accessCount);
220 }
221
222 TEST_F(AffectedByFocusTest, ChildrenAffectedByFocusUpdate)
223 {
224 // Check that when focussing the outer div in the document below, you get a
225 // style recalc for the whole subtree.
226
227 setHtmlInnerHTML("<style>:focus div { border: 1px solid lime; }</style>"
228 "<div id=d tabIndex=1>"
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></div>"
239 "</div>");
240
241 document().view()->updateLayoutAndStyleIfNeededRecursive();
242
243 unsigned startCount = document().styleEngine()->resolverAccessCount();
244
245 document().getElementById("d")->focus();
246 document().view()->updateLayoutAndStyleIfNeededRecursive();
247
248 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount;
249
250 ASSERT_EQ(11U, accessCount);
251 }
252
253 } // 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
This is Rietveld 408576698