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

Side by Side Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp

Issue 2589003002: Split paint property update tests out of PaintPropertyTreeBuilderTest (Closed)
Patch Set: Rebase, minor cleanup Created 4 years 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 | « third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp ('k') | no next file » | 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 2016 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/html/HTMLIFrameElement.h"
6 #include "core/paint/PaintPropertyTreeBuilderTest.h"
7 #include "core/paint/PaintPropertyTreePrinter.h"
8
9 namespace blink {
10
11 // Tests covering incremental updates of paint property trees.
12 class PaintPropertyTreeUpdateTest : public PaintPropertyTreeBuilderTest {};
13
14 TEST_P(PaintPropertyTreeUpdateTest,
15 ThreadedScrollingDisabledMainThreadScrollReason) {
16 setBodyInnerHTML(
17 "<style>"
18 " #overflowA {"
19 " position: absolute;"
20 " overflow: scroll;"
21 " width: 20px;"
22 " height: 20px;"
23 " }"
24 " .forceScroll {"
25 " height: 4000px;"
26 " }"
27 "</style>"
28 "<div id='overflowA'>"
29 " <div class='forceScroll'></div>"
30 "</div>"
31 "<div class='forceScroll'></div>");
32 Element* overflowA = document().getElementById("overflowA");
33 EXPECT_FALSE(frameScroll()->threadedScrollingDisabled());
34 EXPECT_FALSE(overflowA->layoutObject()
35 ->paintProperties()
36 ->scroll()
37 ->threadedScrollingDisabled());
38
39 document().settings()->setThreadedScrollingEnabled(false);
40 // TODO(pdr): The main thread scrolling setting should invalidate properties.
41 document().view()->setNeedsPaintPropertyUpdate();
42 overflowA->layoutObject()->setNeedsPaintPropertyUpdate();
43 document().view()->updateAllLifecyclePhases();
44
45 EXPECT_TRUE(frameScroll()->threadedScrollingDisabled());
46 EXPECT_TRUE(overflowA->layoutObject()
47 ->paintProperties()
48 ->scroll()
49 ->threadedScrollingDisabled());
50 }
51
52 TEST_P(PaintPropertyTreeUpdateTest,
53 BackgroundAttachmentFixedMainThreadScrollReasonsWithNestedScrollers) {
54 setBodyInnerHTML(
55 "<style>"
56 " #overflowA {"
57 " position: absolute;"
58 " overflow: scroll;"
59 " width: 20px;"
60 " height: 20px;"
61 " }"
62 " #overflowB {"
63 " position: absolute;"
64 " overflow: scroll;"
65 " width: 5px;"
66 " height: 3px;"
67 " }"
68 " .backgroundAttachmentFixed {"
69 " background-image: url('foo');"
70 " background-attachment: fixed;"
71 " }"
72 " .forceScroll {"
73 " height: 4000px;"
74 " }"
75 "</style>"
76 "<div id='overflowA'>"
77 " <div id='overflowB' class='backgroundAttachmentFixed'>"
78 " <div class='forceScroll'></div>"
79 " </div>"
80 " <div class='forceScroll'></div>"
81 "</div>"
82 "<div class='forceScroll'></div>");
83 Element* overflowA = document().getElementById("overflowA");
84 Element* overflowB = document().getElementById("overflowB");
85
86 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
87 EXPECT_TRUE(overflowA->layoutObject()
88 ->paintProperties()
89 ->scroll()
90 ->hasBackgroundAttachmentFixedDescendants());
91 EXPECT_FALSE(overflowB->layoutObject()
92 ->paintProperties()
93 ->scroll()
94 ->hasBackgroundAttachmentFixedDescendants());
95
96 // Removing a main thread scrolling reason should update the entire tree.
97 overflowB->removeAttribute("class");
98 document().view()->updateAllLifecyclePhases();
99 EXPECT_FALSE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
100 EXPECT_FALSE(overflowA->layoutObject()
101 ->paintProperties()
102 ->scroll()
103 ->hasBackgroundAttachmentFixedDescendants());
104 EXPECT_FALSE(overflowB->layoutObject()
105 ->paintProperties()
106 ->scroll()
107 ->hasBackgroundAttachmentFixedDescendants());
108
109 // Adding a main thread scrolling reason should update the entire tree.
110 overflowB->setAttribute(HTMLNames::classAttr, "backgroundAttachmentFixed");
111 document().view()->updateAllLifecyclePhases();
112 EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
113 EXPECT_TRUE(overflowA->layoutObject()
114 ->paintProperties()
115 ->scroll()
116 ->hasBackgroundAttachmentFixedDescendants());
117 EXPECT_FALSE(overflowB->layoutObject()
118 ->paintProperties()
119 ->scroll()
120 ->hasBackgroundAttachmentFixedDescendants());
121 }
122
123 TEST_P(PaintPropertyTreeUpdateTest,
124 BackgroundAttachmentFixedMainThreadScrollReasonsWithFixedScroller) {
125 setBodyInnerHTML(
126 "<style>"
127 " #overflowA {"
128 " position: absolute;"
129 " overflow: scroll;"
130 " width: 20px;"
131 " height: 20px;"
132 " }"
133 " #overflowB {"
134 " position: fixed;"
135 " overflow: scroll;"
136 " width: 5px;"
137 " height: 3px;"
138 " }"
139 " .backgroundAttachmentFixed {"
140 " background-image: url('foo');"
141 " background-attachment: fixed;"
142 " }"
143 " .forceScroll {"
144 " height: 4000px;"
145 " }"
146 "</style>"
147 "<div id='overflowA'>"
148 " <div id='overflowB' class='backgroundAttachmentFixed'>"
149 " <div class='forceScroll'></div>"
150 " </div>"
151 " <div class='forceScroll'></div>"
152 "</div>"
153 "<div class='forceScroll'></div>");
154 Element* overflowA = document().getElementById("overflowA");
155 Element* overflowB = document().getElementById("overflowB");
156
157 // This should be false. We are not as strict about main thread scrolling
158 // reasons as we could be.
159 EXPECT_TRUE(overflowA->layoutObject()
160 ->paintProperties()
161 ->scroll()
162 ->hasBackgroundAttachmentFixedDescendants());
163 EXPECT_FALSE(overflowB->layoutObject()
164 ->paintProperties()
165 ->scroll()
166 ->hasBackgroundAttachmentFixedDescendants());
167 EXPECT_TRUE(overflowB->layoutObject()
168 ->paintProperties()
169 ->scroll()
170 ->parent()
171 ->isRoot());
172
173 // Removing a main thread scrolling reason should update the entire tree.
174 overflowB->removeAttribute("class");
175 document().view()->updateAllLifecyclePhases();
176 EXPECT_FALSE(overflowA->layoutObject()
177 ->paintProperties()
178 ->scroll()
179 ->hasBackgroundAttachmentFixedDescendants());
180 EXPECT_FALSE(overflowB->layoutObject()
181 ->paintProperties()
182 ->scroll()
183 ->hasBackgroundAttachmentFixedDescendants());
184 EXPECT_FALSE(overflowB->layoutObject()
185 ->paintProperties()
186 ->scroll()
187 ->parent()
188 ->hasBackgroundAttachmentFixedDescendants());
189 }
190
191 TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
192 setBodyInnerHTML(
193 "<style>body { margin: 0; }</style>"
194 "<div id='divWithTransform' style='transform: translate3d(1px,2px,3px);'>"
195 " <iframe style='border: 7px solid black'></iframe>"
196 "</div>");
197 setChildFrameHTML(
198 "<style>body { margin: 0; }</style><div id='transform' style='transform: "
199 "translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>");
200
201 FrameView* frameView = document().view();
202 frameView->updateAllLifecyclePhases();
203
204 LayoutObject* divWithTransform =
205 document().getElementById("divWithTransform")->layoutObject();
206 LayoutObject* childLayoutView = childDocument().layoutView();
207 LayoutObject* innerDivWithTransform =
208 childDocument().getElementById("transform")->layoutObject();
209
210 // Initially, no objects should need a descendant update.
211 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
212 EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
213 EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
214 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
215
216 // Marking the child div as needing a paint property update should propagate
217 // up the tree and across frames.
218 innerDivWithTransform->setNeedsPaintPropertyUpdate();
219 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
220 EXPECT_TRUE(divWithTransform->descendantNeedsPaintPropertyUpdate());
221 EXPECT_TRUE(childLayoutView->descendantNeedsPaintPropertyUpdate());
222 EXPECT_TRUE(innerDivWithTransform->needsPaintPropertyUpdate());
223 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
224
225 // After a lifecycle update, no nodes should need a descendant update.
226 frameView->updateAllLifecyclePhases();
227 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
228 EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
229 EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
230 EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
231
232 // A child frame marked as needing a paint property update should not be
233 // skipped if the owning layout tree does not need an update.
234 FrameView* childFrameView = childDocument().view();
235 childFrameView->setNeedsPaintPropertyUpdate();
236 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
237 frameView->updateAllLifecyclePhases();
238 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
239 EXPECT_FALSE(frameView->needsPaintPropertyUpdate());
240 EXPECT_FALSE(childFrameView->needsPaintPropertyUpdate());
241 }
242
243 TEST_P(PaintPropertyTreeUpdateTest, UpdatingFrameViewContentClip) {
244 setBodyInnerHTML("hello world.");
245 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
246 document().view()->resize(800, 599);
247 document().view()->updateAllLifecyclePhases();
248 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), frameContentClip()->clipRect());
249 document().view()->resize(800, 600);
250 document().view()->updateAllLifecyclePhases();
251 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
252 document().view()->resize(5, 5);
253 document().view()->updateAllLifecyclePhases();
254 EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), frameContentClip()->clipRect());
255 }
256
257 TEST_P(PaintPropertyTreeUpdateTest, BuildingStopsAtThrottledFrames) {
258 setBodyInnerHTML(
259 "<style>body { margin: 0; }</style>"
260 "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'>"
261 "</div>"
262 "<iframe id='iframe' sandbox></iframe>");
263 setChildFrameHTML(
264 "<style>body { margin: 0; }</style>"
265 "<div id='iframeTransform'"
266 " style='transform: translate3d(4px, 5px, 6px);'/>");
267
268 // Move the child frame offscreen so it becomes available for throttling.
269 auto* iframe = toHTMLIFrameElement(document().getElementById("iframe"));
270 iframe->setAttribute(HTMLNames::styleAttr, "transform: translateY(5555px)");
271 document().view()->updateAllLifecyclePhases();
272 // Ensure intersection observer notifications get delivered.
273 testing::runPendingTasks();
274 EXPECT_FALSE(document().view()->isHiddenForThrottling());
275 EXPECT_TRUE(childDocument().view()->isHiddenForThrottling());
276
277 auto* transform = document().getElementById("transform")->layoutObject();
278 auto* iframeLayoutView = childDocument().layoutView();
279 auto* iframeTransform =
280 childDocument().getElementById("iframeTransform")->layoutObject();
281
282 // Invalidate properties in the iframe and ensure ancestors are marked.
283 iframeTransform->setNeedsPaintPropertyUpdate();
284 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
285 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
286 EXPECT_FALSE(transform->needsPaintPropertyUpdate());
287 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
288 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
289 EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
290 EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
291 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
292
293 transform->setNeedsPaintPropertyUpdate();
294 EXPECT_TRUE(transform->needsPaintPropertyUpdate());
295 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
296
297 {
298 DocumentLifecycle::AllowThrottlingScope throttlingScope(
299 document().lifecycle());
300 EXPECT_FALSE(document().view()->shouldThrottleRendering());
301 EXPECT_TRUE(childDocument().view()->shouldThrottleRendering());
302
303 // A lifecycle update should update all properties except those with
304 // actively throttled descendants.
305 document().view()->updateAllLifecyclePhases();
306 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
307 EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
308 EXPECT_FALSE(transform->needsPaintPropertyUpdate());
309 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
310 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
311 EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
312 EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
313 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
314 }
315
316 EXPECT_FALSE(document().view()->shouldThrottleRendering());
317 EXPECT_FALSE(childDocument().view()->shouldThrottleRendering());
318 // Once unthrottled, a lifecycel update should update all properties.
319 document().view()->updateAllLifecyclePhases();
320 EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
321 EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
322 EXPECT_FALSE(transform->needsPaintPropertyUpdate());
323 EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
324 EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
325 EXPECT_FALSE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
326 EXPECT_FALSE(iframeTransform->needsPaintPropertyUpdate());
327 EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
328 }
329
330 TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
331 setBodyInnerHTML(
332 "<style>"
333 " body { margin:0 }"
334 " #div { overflow:hidden; height:0px; }"
335 "</style>"
336 "<div id='div'></div>");
337 auto* div = document().getElementById("div");
338 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
339 document().view()->updateAllLifecyclePhases();
340 auto* clipProperties = div->layoutObject()->paintProperties()->overflowClip();
341 EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
342
343 // Width changes should update the overflow clip.
344 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
345 document().view()->updateAllLifecyclePhases();
346 clipProperties = div->layoutObject()->paintProperties()->overflowClip();
347 EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
348 div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:9px;");
349 document().view()->updateAllLifecyclePhases();
350 EXPECT_EQ(FloatRect(0, 0, 9, 0), clipProperties->clipRect().rect());
351
352 // An inline block's overflow clip should be updated when padding changes,
353 // even if the border box remains unchanged.
354 div->setAttribute(HTMLNames::styleAttr,
355 "display:inline-block; width:7px; padding-right:3px;");
356 document().view()->updateAllLifecyclePhases();
357 clipProperties = div->layoutObject()->paintProperties()->overflowClip();
358 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
359 div->setAttribute(HTMLNames::styleAttr,
360 "display:inline-block; width:8px; padding-right:2px;");
361 document().view()->updateAllLifecyclePhases();
362 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
363 div->setAttribute(HTMLNames::styleAttr,
364 "display:inline-block; width:8px;"
365 "padding-right:1px; padding-left:1px;");
366 document().view()->updateAllLifecyclePhases();
367 EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
368
369 // An block's overflow clip should be updated when borders change.
370 div->setAttribute(HTMLNames::styleAttr, "border-right:3px solid red;");
371 document().view()->updateAllLifecyclePhases();
372 clipProperties = div->layoutObject()->paintProperties()->overflowClip();
373 EXPECT_EQ(FloatRect(0, 0, 797, 0), clipProperties->clipRect().rect());
374 div->setAttribute(HTMLNames::styleAttr, "border-right:5px solid red;");
375 document().view()->updateAllLifecyclePhases();
376 EXPECT_EQ(FloatRect(0, 0, 795, 0), clipProperties->clipRect().rect());
377
378 // Removing overflow clip should remove the property.
379 div->setAttribute(HTMLNames::styleAttr, "overflow:hidden;");
380 document().view()->updateAllLifecyclePhases();
381 clipProperties = div->layoutObject()->paintProperties()->overflowClip();
382 EXPECT_EQ(FloatRect(0, 0, 800, 0), clipProperties->clipRect().rect());
383 div->setAttribute(HTMLNames::styleAttr, "overflow:visible;");
384 document().view()->updateAllLifecyclePhases();
385 EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
386 !div->layoutObject()->paintProperties()->overflowClip());
387 }
388
389 TEST_P(PaintPropertyTreeUpdateTest, ContainPaintChangesUpdateOverflowClip) {
390 setBodyInnerHTML(
391 "<style>"
392 " body { margin:0 }"
393 " #div { will-change:transform; width:7px; height:6px; }"
394 "</style>"
395 "<div id='div' style='contain:paint;'></div>");
396 document().view()->updateAllLifecyclePhases();
397 auto* div = document().getElementById("div");
398 auto* properties = div->layoutObject()->paintProperties()->overflowClip();
399 EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->clipRect().rect());
400
401 div->setAttribute(HTMLNames::styleAttr, "");
402 document().view()->updateAllLifecyclePhases();
403 EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
404 !div->layoutObject()->paintProperties()->overflowClip());
405 }
406
407 // A basic sanity check for over-invalidation of paint properties.
408 TEST_P(PaintPropertyTreeUpdateTest, NoPaintPropertyUpdateOnBackgroundChange) {
409 setBodyInnerHTML("<div id='div' style='background-color: blue'>DIV</div>");
410 auto* div = document().getElementById("div");
411
412 document().view()->updateAllLifecyclePhases();
413 div->setAttribute(HTMLNames::styleAttr, "background-color: green");
414 document().view()->updateLifecycleToLayoutClean();
415 EXPECT_FALSE(div->layoutObject()->needsPaintPropertyUpdate());
416 }
417
418 // Disabled due to stale scrollsOverflow values, see: https://crbug.com/675296.
419 TEST_P(PaintPropertyTreeUpdateTest,
420 DISABLED_FrameVisibilityChangeUpdatesProperties) {
421 setBodyInnerHTML(
422 "<style>body { margin: 0; }</style>"
423 "<div id='iframeContainer'>"
424 " <iframe id='iframe' style='width: 100px; height: 100px;'></iframe>"
425 "</div>");
426 setChildFrameHTML(
427 "<style>body { margin: 0; }</style>"
428 "<div id='forceScroll' style='height: 3000px;'></div>");
429
430 FrameView* frameView = document().view();
431 frameView->updateAllLifecyclePhases();
432 EXPECT_EQ(nullptr, frameScroll(frameView));
433 FrameView* childFrameView = childDocument().view();
434 EXPECT_NE(nullptr, frameScroll(childFrameView));
435
436 auto* iframeContainer = document().getElementById("iframeContainer");
437 iframeContainer->setAttribute(HTMLNames::styleAttr, "visibility: hidden;");
438 frameView->updateAllLifecyclePhases();
439
440 EXPECT_EQ(nullptr, frameScroll(frameView));
441 EXPECT_EQ(nullptr, frameScroll(childFrameView));
442 }
443
444 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698