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

Side by Side Diff: third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp

Issue 2885313003: [scheduler] Fix --disable-background-timer-throttling flag. (Closed)
Patch Set: fix test crash 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 2015 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 "bindings/core/v8/ScriptController.h"
6 #include "bindings/core/v8/ScriptSourceCode.h"
7 #include "core/dom/Document.h"
8 #include "core/dom/Element.h"
9 #include "core/frame/FrameView.h"
10 #include "core/frame/LocalFrame.h"
11 #include "core/html/HTMLIFrameElement.h"
12 #include "core/layout/api/LayoutViewItem.h"
13 #include "core/layout/compositing/CompositedLayerMapping.h"
14 #include "core/page/FocusController.h"
15 #include "core/page/Page.h"
16 #include "core/paint/PaintLayer.h"
17 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
18 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
19 #include "platform/testing/URLTestHelpers.h"
20 #include "platform/testing/UnitTestHelpers.h"
21 #include "public/platform/WebDisplayItemList.h"
22 #include "public/platform/WebLayer.h"
23 #include "public/web/WebFrameContentDumper.h"
24 #include "public/web/WebHitTestResult.h"
25 #include "public/web/WebSettings.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "web/WebLocalFrameImpl.h"
28 #include "web/WebRemoteFrameImpl.h"
29 #include "web/tests/sim/SimCompositor.h"
30 #include "web/tests/sim/SimDisplayItemList.h"
31 #include "web/tests/sim/SimRequest.h"
32 #include "web/tests/sim/SimTest.h"
33
34 using testing::_;
35
36 namespace blink {
37
38 using namespace HTMLNames;
39
40 // NOTE: This test uses <iframe sandbox> to create cross origin iframes.
41
42 namespace {
43
44 class MockWebDisplayItemList : public WebDisplayItemList {
45 public:
46 ~MockWebDisplayItemList() override {}
47
48 MOCK_METHOD2(AppendDrawingItem,
49 void(const WebRect&, sk_sp<const PaintRecord>));
50 };
51
52 void PaintRecursively(GraphicsLayer* layer, WebDisplayItemList* display_items) {
53 if (layer->DrawsContent()) {
54 layer->SetNeedsDisplay();
55 layer->ContentLayerDelegateForTesting()->PaintContents(
56 display_items, ContentLayerDelegate::kPaintDefaultBehaviorForTest);
57 }
58 for (const auto& child : layer->Children())
59 PaintRecursively(child, display_items);
60 }
61
62 } // namespace
63
64 class FrameThrottlingTest : public SimTest,
65 public ::testing::WithParamInterface<bool>,
66 private ScopedRootLayerScrollingForTest {
67 protected:
68 FrameThrottlingTest() : ScopedRootLayerScrollingForTest(GetParam()) {
69 WebView().Resize(WebSize(640, 480));
70 }
71
72 SimDisplayItemList CompositeFrame() {
73 SimDisplayItemList display_items = Compositor().BeginFrame();
74 // Ensure intersection observer notifications get delivered.
75 testing::RunPendingTasks();
76 return display_items;
77 }
78
79 // Number of rectangles that make up the root layer's touch handler region.
80 size_t TouchHandlerRegionSize() {
81 size_t result = 0;
82 PaintLayer* layer =
83 WebView().MainFrameImpl()->GetFrame()->ContentLayoutObject()->Layer();
84 GraphicsLayer* own_graphics_layer =
85 layer->GraphicsLayerBacking(&layer->GetLayoutObject());
86 if (own_graphics_layer) {
87 result +=
88 own_graphics_layer->PlatformLayer()->TouchEventHandlerRegion().size();
89 }
90 GraphicsLayer* child_graphics_layer = layer->GraphicsLayerBacking();
91 if (child_graphics_layer && child_graphics_layer != own_graphics_layer) {
92 result += child_graphics_layer->PlatformLayer()
93 ->TouchEventHandlerRegion()
94 .size();
95 }
96 return result;
97 }
98 };
99
100 INSTANTIATE_TEST_CASE_P(All, FrameThrottlingTest, ::testing::Bool());
101
102 TEST_P(FrameThrottlingTest, ThrottleInvisibleFrames) {
103 SimRequest main_resource("https://example.com/", "text/html");
104
105 LoadURL("https://example.com/");
106 main_resource.Complete("<iframe sandbox id=frame></iframe>");
107
108 auto* frame_element =
109 toHTMLIFrameElement(GetDocument().getElementById("frame"));
110 auto* frame_document = frame_element->contentDocument();
111
112 // Initially both frames are visible.
113 EXPECT_FALSE(GetDocument().View()->IsHiddenForThrottling());
114 EXPECT_FALSE(frame_document->View()->IsHiddenForThrottling());
115
116 // Moving the child fully outside the parent makes it invisible.
117 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
118 CompositeFrame();
119 EXPECT_FALSE(GetDocument().View()->IsHiddenForThrottling());
120 EXPECT_TRUE(frame_document->View()->IsHiddenForThrottling());
121
122 // A partially visible child is considered visible.
123 frame_element->setAttribute(styleAttr,
124 "transform: translate(-50px, 0px, 0px)");
125 CompositeFrame();
126 EXPECT_FALSE(GetDocument().View()->IsHiddenForThrottling());
127 EXPECT_FALSE(frame_document->View()->IsHiddenForThrottling());
128 }
129
130 TEST_P(FrameThrottlingTest, HiddenSameOriginFramesAreNotThrottled) {
131 SimRequest main_resource("https://example.com/", "text/html");
132 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
133
134 LoadURL("https://example.com/");
135 main_resource.Complete("<iframe id=frame src=iframe.html></iframe>");
136 frame_resource.Complete("<iframe id=innerFrame></iframe>");
137
138 auto* frame_element =
139 toHTMLIFrameElement(GetDocument().getElementById("frame"));
140 auto* frame_document = frame_element->contentDocument();
141
142 HTMLIFrameElement* inner_frame_element =
143 toHTMLIFrameElement(frame_document->getElementById("innerFrame"));
144 auto* inner_frame_document = inner_frame_element->contentDocument();
145
146 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
147 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
148 EXPECT_FALSE(inner_frame_document->View()->CanThrottleRendering());
149
150 // Hidden same origin frames are not throttled.
151 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
152 CompositeFrame();
153 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
154 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
155 EXPECT_FALSE(inner_frame_document->View()->CanThrottleRendering());
156 }
157
158 TEST_P(FrameThrottlingTest, HiddenCrossOriginFramesAreThrottled) {
159 // Create a document with doubly nested iframes.
160 SimRequest main_resource("https://example.com/", "text/html");
161 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
162
163 LoadURL("https://example.com/");
164 main_resource.Complete("<iframe id=frame src=iframe.html></iframe>");
165 frame_resource.Complete("<iframe id=innerFrame sandbox></iframe>");
166
167 auto* frame_element =
168 toHTMLIFrameElement(GetDocument().getElementById("frame"));
169 auto* frame_document = frame_element->contentDocument();
170
171 auto* inner_frame_element =
172 toHTMLIFrameElement(frame_document->getElementById("innerFrame"));
173 auto* inner_frame_document = inner_frame_element->contentDocument();
174
175 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
176 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
177 EXPECT_FALSE(inner_frame_document->View()->CanThrottleRendering());
178
179 // Hidden cross origin frames are throttled.
180 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
181 CompositeFrame();
182 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
183 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
184 EXPECT_TRUE(inner_frame_document->View()->CanThrottleRendering());
185 }
186
187 TEST_P(FrameThrottlingTest, HiddenCrossOriginZeroByZeroFramesAreNotThrottled) {
188 // Create a document with doubly nested iframes.
189 SimRequest main_resource("https://example.com/", "text/html");
190 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
191
192 LoadURL("https://example.com/");
193 main_resource.Complete("<iframe id=frame src=iframe.html></iframe>");
194 frame_resource.Complete(
195 "<iframe id=innerFrame width=0 height=0 sandbox></iframe>");
196
197 auto* frame_element =
198 toHTMLIFrameElement(GetDocument().getElementById("frame"));
199 auto* frame_document = frame_element->contentDocument();
200
201 auto* inner_frame_element =
202 toHTMLIFrameElement(frame_document->getElementById("innerFrame"));
203 auto* inner_frame_document = inner_frame_element->contentDocument();
204
205 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
206 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
207 EXPECT_FALSE(inner_frame_document->View()->CanThrottleRendering());
208
209 // The frame is not throttled because its dimensions are 0x0.
210 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
211 CompositeFrame();
212 EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
213 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
214 EXPECT_FALSE(inner_frame_document->View()->CanThrottleRendering());
215 }
216
217 TEST_P(FrameThrottlingTest, ThrottledLifecycleUpdate) {
218 SimRequest main_resource("https://example.com/", "text/html");
219
220 LoadURL("https://example.com/");
221 main_resource.Complete("<iframe sandbox id=frame></iframe>");
222
223 auto* frame_element =
224 toHTMLIFrameElement(GetDocument().getElementById("frame"));
225 auto* frame_document = frame_element->contentDocument();
226
227 // Enable throttling for the child frame.
228 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
229 CompositeFrame();
230 EXPECT_TRUE(frame_document->View()->CanThrottleRendering());
231 EXPECT_EQ(DocumentLifecycle::kPaintClean,
232 frame_document->Lifecycle().GetState());
233
234 // Mutating the throttled frame followed by a beginFrame will not result in
235 // a complete lifecycle update.
236 // TODO(skyostil): these expectations are either wrong, or the test is
237 // not exercising the code correctly. PaintClean means the entire lifecycle
238 // ran.
239 frame_element->setAttribute(widthAttr, "50");
240 CompositeFrame();
241 EXPECT_EQ(DocumentLifecycle::kPaintClean,
242 frame_document->Lifecycle().GetState());
243
244 // A hit test will not force a complete lifecycle update.
245 WebView().HitTestResultAt(WebPoint(0, 0));
246 EXPECT_EQ(DocumentLifecycle::kPaintClean,
247 frame_document->Lifecycle().GetState());
248 }
249
250 TEST_P(FrameThrottlingTest, UnthrottlingFrameSchedulesAnimation) {
251 SimRequest main_resource("https://example.com/", "text/html");
252
253 LoadURL("https://example.com/");
254 main_resource.Complete("<iframe sandbox id=frame></iframe>");
255
256 auto* frame_element =
257 toHTMLIFrameElement(GetDocument().getElementById("frame"));
258
259 // First make the child hidden to enable throttling.
260 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
261 CompositeFrame();
262 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
263 EXPECT_FALSE(Compositor().NeedsBeginFrame());
264
265 // Then bring it back on-screen. This should schedule an animation update.
266 frame_element->setAttribute(styleAttr, "");
267 CompositeFrame();
268 EXPECT_TRUE(Compositor().NeedsBeginFrame());
269 }
270
271 TEST_P(FrameThrottlingTest, MutatingThrottledFrameDoesNotCauseAnimation) {
272 SimRequest main_resource("https://example.com/", "text/html");
273 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
274
275 LoadURL("https://example.com/");
276 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
277 frame_resource.Complete("<style> html { background: red; } </style>");
278
279 // Check that the frame initially shows up.
280 auto display_items1 = CompositeFrame();
281 EXPECT_TRUE(display_items1.Contains(SimCanvas::kRect, "red"));
282
283 auto* frame_element =
284 toHTMLIFrameElement(GetDocument().getElementById("frame"));
285
286 // Move the frame offscreen to throttle it.
287 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
288 CompositeFrame();
289 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
290
291 // Mutating the throttled frame should not cause an animation to be scheduled.
292 frame_element->contentDocument()->documentElement()->setAttribute(
293 styleAttr, "background: green");
294 EXPECT_FALSE(Compositor().NeedsBeginFrame());
295
296 // Move the frame back on screen to unthrottle it.
297 frame_element->setAttribute(styleAttr, "");
298 EXPECT_TRUE(Compositor().NeedsBeginFrame());
299
300 // The first frame we composite after unthrottling won't contain the
301 // frame's new contents because unthrottling happens at the end of the
302 // lifecycle update. We need to do another composite to refresh the frame's
303 // contents.
304 auto display_items2 = CompositeFrame();
305 EXPECT_FALSE(display_items2.Contains(SimCanvas::kRect, "green"));
306 EXPECT_TRUE(Compositor().NeedsBeginFrame());
307
308 auto display_items3 = CompositeFrame();
309 EXPECT_TRUE(display_items3.Contains(SimCanvas::kRect, "green"));
310 }
311
312 TEST_P(FrameThrottlingTest, SynchronousLayoutInThrottledFrame) {
313 // Create a hidden frame which is throttled.
314 SimRequest main_resource("https://example.com/", "text/html");
315 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
316
317 LoadURL("https://example.com/");
318 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
319 frame_resource.Complete("<div id=div></div>");
320
321 auto* frame_element =
322 toHTMLIFrameElement(GetDocument().getElementById("frame"));
323
324 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
325 CompositeFrame();
326
327 // Change the size of a div in the throttled frame.
328 auto* div_element = frame_element->contentDocument()->getElementById("div");
329 div_element->setAttribute(styleAttr, "width: 50px");
330
331 // Querying the width of the div should do a synchronous layout update even
332 // though the frame is being throttled.
333 EXPECT_EQ(50, div_element->clientWidth());
334 }
335
336 TEST_P(FrameThrottlingTest, UnthrottlingTriggersRepaint) {
337 // Create a hidden frame which is throttled.
338 SimRequest main_resource("https://example.com/", "text/html");
339 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
340
341 LoadURL("https://example.com/");
342 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
343 frame_resource.Complete("<style> html { background: green; } </style>");
344
345 // Move the frame offscreen to throttle it.
346 auto* frame_element =
347 toHTMLIFrameElement(GetDocument().getElementById("frame"));
348 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
349 EXPECT_FALSE(
350 frame_element->contentDocument()->View()->CanThrottleRendering());
351 CompositeFrame();
352 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
353
354 // Scroll down to unthrottle the frame. The first frame we composite after
355 // scrolling won't contain the frame yet, but will schedule another repaint.
356 WebView()
357 .MainFrameImpl()
358 ->GetFrameView()
359 ->LayoutViewportScrollableArea()
360 ->SetScrollOffset(ScrollOffset(0, 480), kProgrammaticScroll);
361 auto display_items = CompositeFrame();
362 EXPECT_FALSE(display_items.Contains(SimCanvas::kRect, "green"));
363
364 // Now the frame contents should be visible again.
365 auto display_items2 = CompositeFrame();
366 EXPECT_TRUE(display_items2.Contains(SimCanvas::kRect, "green"));
367 }
368
369 TEST_P(FrameThrottlingTest, UnthrottlingTriggersRepaintInCompositedChild) {
370 // Create a hidden frame with a composited child layer.
371 SimRequest main_resource("https://example.com/", "text/html");
372 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
373
374 LoadURL("https://example.com/");
375 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
376 frame_resource.Complete(
377 "<style>"
378 "div { "
379 " width: 100px;"
380 " height: 100px;"
381 " background-color: green;"
382 " transform: translateZ(0);"
383 "}"
384 "</style><div></div>");
385
386 // Move the frame offscreen to throttle it.
387 auto* frame_element =
388 toHTMLIFrameElement(GetDocument().getElementById("frame"));
389 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
390 EXPECT_FALSE(
391 frame_element->contentDocument()->View()->CanThrottleRendering());
392 CompositeFrame();
393 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
394
395 // Scroll down to unthrottle the frame. The first frame we composite after
396 // scrolling won't contain the frame yet, but will schedule another repaint.
397 WebView()
398 .MainFrameImpl()
399 ->GetFrameView()
400 ->LayoutViewportScrollableArea()
401 ->SetScrollOffset(ScrollOffset(0, 480), kProgrammaticScroll);
402 auto display_items = CompositeFrame();
403 EXPECT_FALSE(display_items.Contains(SimCanvas::kRect, "green"));
404
405 // Now the composited child contents should be visible again.
406 auto display_items2 = CompositeFrame();
407 EXPECT_TRUE(display_items2.Contains(SimCanvas::kRect, "green"));
408 }
409
410 TEST_P(FrameThrottlingTest, ChangeStyleInThrottledFrame) {
411 // Create a hidden frame which is throttled.
412 SimRequest main_resource("https://example.com/", "text/html");
413 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
414
415 LoadURL("https://example.com/");
416 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
417 frame_resource.Complete("<style> html { background: red; } </style>");
418
419 // Move the frame offscreen to throttle it.
420 auto* frame_element =
421 toHTMLIFrameElement(GetDocument().getElementById("frame"));
422 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
423 EXPECT_FALSE(
424 frame_element->contentDocument()->View()->CanThrottleRendering());
425 CompositeFrame();
426 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
427
428 // Change the background color of the frame's contents from red to green.
429 frame_element->contentDocument()->body()->setAttribute(styleAttr,
430 "background: green");
431
432 // Scroll down to unthrottle the frame.
433 WebView()
434 .MainFrameImpl()
435 ->GetFrameView()
436 ->LayoutViewportScrollableArea()
437 ->SetScrollOffset(ScrollOffset(0, 480), kProgrammaticScroll);
438 auto display_items = CompositeFrame();
439 EXPECT_FALSE(display_items.Contains(SimCanvas::kRect, "red"));
440 EXPECT_FALSE(display_items.Contains(SimCanvas::kRect, "green"));
441
442 // Make sure the new style shows up instead of the old one.
443 auto display_items2 = CompositeFrame();
444 EXPECT_TRUE(display_items2.Contains(SimCanvas::kRect, "green"));
445 }
446
447 TEST_P(FrameThrottlingTest, ChangeOriginInThrottledFrame) {
448 // Create a hidden frame which is throttled.
449 SimRequest main_resource("http://example.com/", "text/html");
450 SimRequest frame_resource("http://sub.example.com/iframe.html", "text/html");
451 LoadURL("http://example.com/");
452 main_resource.Complete(
453 "<iframe style='position: absolute; top: 10000px' id=frame "
454 "src=http://sub.example.com/iframe.html></iframe>");
455 frame_resource.Complete("");
456
457 auto* frame_element =
458 toHTMLIFrameElement(GetDocument().getElementById("frame"));
459
460 CompositeFrame();
461
462 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
463 EXPECT_TRUE(
464 frame_element->contentDocument()->GetFrame()->IsCrossOriginSubframe());
465 EXPECT_FALSE(frame_element->contentDocument()
466 ->View()
467 ->GetLayoutView()
468 ->NeedsPaintPropertyUpdate());
469
470 NonThrowableExceptionState exception_state;
471
472 // Security policy requires setting domain on both frames.
473 GetDocument().setDomain(String("example.com"), exception_state);
474 frame_element->contentDocument()->setDomain(String("example.com"),
475 exception_state);
476
477 EXPECT_FALSE(
478 frame_element->contentDocument()->GetFrame()->IsCrossOriginSubframe());
479 EXPECT_FALSE(
480 frame_element->contentDocument()->View()->CanThrottleRendering());
481 EXPECT_TRUE(frame_element->contentDocument()
482 ->View()
483 ->GetLayoutView()
484 ->NeedsPaintPropertyUpdate());
485 }
486
487 TEST_P(FrameThrottlingTest, ThrottledFrameWithFocus) {
488 WebView().GetSettings()->SetJavaScriptEnabled(true);
489 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
490 RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
491
492 // Create a hidden frame which is throttled and has a text selection.
493 SimRequest main_resource("https://example.com/", "text/html");
494 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
495
496 LoadURL("https://example.com/");
497 main_resource.Complete(
498 "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
499 frame_resource.Complete(
500 "some text to select\n"
501 "<script>\n"
502 "var range = document.createRange();\n"
503 "range.selectNode(document.body);\n"
504 "window.getSelection().addRange(range);\n"
505 "</script>\n");
506
507 // Move the frame offscreen to throttle it.
508 auto* frame_element =
509 toHTMLIFrameElement(GetDocument().getElementById("frame"));
510 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
511 EXPECT_FALSE(
512 frame_element->contentDocument()->View()->CanThrottleRendering());
513 CompositeFrame();
514 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
515
516 // Give the frame focus and do another composite. The selection in the
517 // compositor should be cleared because the frame is throttled.
518 EXPECT_FALSE(Compositor().HasSelection());
519 GetDocument().GetPage()->GetFocusController().SetFocusedFrame(
520 frame_element->contentDocument()->GetFrame());
521 GetDocument().body()->setAttribute(styleAttr, "background: green");
522 CompositeFrame();
523 EXPECT_FALSE(Compositor().HasSelection());
524 }
525
526 TEST_P(FrameThrottlingTest, ScrollingCoordinatorShouldSkipThrottledFrame) {
527 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
528
529 // Create a hidden frame which is throttled.
530 SimRequest main_resource("https://example.com/", "text/html");
531 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
532
533 LoadURL("https://example.com/");
534 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
535 frame_resource.Complete(
536 "<style> html { background-image: linear-gradient(red, blue); "
537 "background-attachment: fixed; } </style>");
538
539 // Move the frame offscreen to throttle it.
540 auto* frame_element =
541 toHTMLIFrameElement(GetDocument().getElementById("frame"));
542 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
543 EXPECT_FALSE(
544 frame_element->contentDocument()->View()->CanThrottleRendering());
545 CompositeFrame();
546 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
547
548 // Change style of the frame's content to make it in VisualUpdatePending
549 // state.
550 frame_element->contentDocument()->body()->setAttribute(styleAttr,
551 "background: green");
552 // Change root frame's layout so that the next lifecycle update will call
553 // ScrollingCoordinator::updateAfterCompositingChangeIfNeeded().
554 GetDocument().body()->setAttribute(styleAttr, "margin: 20px");
555 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
556 frame_element->contentDocument()->Lifecycle().GetState());
557
558 DocumentLifecycle::AllowThrottlingScope throttling_scope(
559 GetDocument().Lifecycle());
560 // This will call ScrollingCoordinator::updateAfterCompositingChangeIfNeeded()
561 // and should not cause assert failure about
562 // isAllowedToQueryCompositingState() in the throttled frame.
563 GetDocument().View()->UpdateAllLifecyclePhases();
564 testing::RunPendingTasks();
565 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
566 frame_element->contentDocument()->Lifecycle().GetState());
567 // The fixed background in the throttled sub frame should not cause main
568 // thread scrolling.
569 EXPECT_FALSE(GetDocument()
570 .View()
571 ->LayoutViewportScrollableArea()
572 ->ShouldScrollOnMainThread());
573
574 // Make the frame visible by changing its transform. This doesn't cause a
575 // layout, but should still unthrottle the frame.
576 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
577 CompositeFrame();
578 EXPECT_FALSE(
579 frame_element->contentDocument()->View()->CanThrottleRendering());
580 // The fixed background in the throttled sub frame should be considered.
581 EXPECT_TRUE(frame_element->contentDocument()
582 ->View()
583 ->LayoutViewportScrollableArea()
584 ->ShouldScrollOnMainThread());
585 EXPECT_FALSE(GetDocument()
586 .View()
587 ->LayoutViewportScrollableArea()
588 ->ShouldScrollOnMainThread());
589 }
590
591 TEST_P(FrameThrottlingTest, ScrollingCoordinatorShouldSkipThrottledLayer) {
592 WebView().GetSettings()->SetJavaScriptEnabled(true);
593 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
594 WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
595
596 // Create a hidden frame which is throttled and has a touch handler inside a
597 // composited layer.
598 SimRequest main_resource("https://example.com/", "text/html");
599 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
600
601 LoadURL("https://example.com/");
602 main_resource.Complete(
603 "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
604 frame_resource.Complete(
605 "<div id=div style='transform: translateZ(0)' ontouchstart='foo()'>touch "
606 "handler</div>");
607
608 // Move the frame offscreen to throttle it.
609 auto* frame_element =
610 toHTMLIFrameElement(GetDocument().getElementById("frame"));
611 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
612 EXPECT_FALSE(
613 frame_element->contentDocument()->View()->CanThrottleRendering());
614 CompositeFrame();
615 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
616
617 // Change style of the frame's content to make it in VisualUpdatePending
618 // state.
619 frame_element->contentDocument()->body()->setAttribute(styleAttr,
620 "background: green");
621 // Change root frame's layout so that the next lifecycle update will call
622 // ScrollingCoordinator::updateAfterCompositingChangeIfNeeded().
623 GetDocument().body()->setAttribute(styleAttr, "margin: 20px");
624 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
625 frame_element->contentDocument()->Lifecycle().GetState());
626
627 DocumentLifecycle::AllowThrottlingScope throttling_scope(
628 GetDocument().Lifecycle());
629 // This will call ScrollingCoordinator::updateAfterCompositingChangeIfNeeded()
630 // and should not cause assert failure about
631 // isAllowedToQueryCompositingState() in the throttled frame.
632 GetDocument().View()->UpdateAllLifecyclePhases();
633 testing::RunPendingTasks();
634 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
635 frame_element->contentDocument()->Lifecycle().GetState());
636 }
637
638 TEST_P(FrameThrottlingTest,
639 ScrollingCoordinatorShouldSkipCompositedThrottledFrame) {
640 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
641 WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
642
643 // Create a hidden frame which is throttled.
644 SimRequest main_resource("https://example.com/", "text/html");
645 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
646
647 LoadURL("https://example.com/");
648 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
649 frame_resource.Complete("<div style='height: 2000px'></div>");
650
651 // Move the frame offscreen to throttle it.
652 auto* frame_element =
653 toHTMLIFrameElement(GetDocument().getElementById("frame"));
654 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
655 EXPECT_FALSE(
656 frame_element->contentDocument()->View()->CanThrottleRendering());
657 CompositeFrame();
658 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
659
660 // Change style of the frame's content to make it in VisualUpdatePending
661 // state.
662 frame_element->contentDocument()->body()->setAttribute(styleAttr,
663 "background: green");
664 // Change root frame's layout so that the next lifecycle update will call
665 // ScrollingCoordinator::updateAfterCompositingChangeIfNeeded().
666 GetDocument().body()->setAttribute(styleAttr, "margin: 20px");
667 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
668 frame_element->contentDocument()->Lifecycle().GetState());
669
670 DocumentLifecycle::AllowThrottlingScope throttling_scope(
671 GetDocument().Lifecycle());
672 // This will call ScrollingCoordinator::updateAfterCompositingChangeIfNeeded()
673 // and should not cause assert failure about
674 // isAllowedToQueryCompositingState() in the throttled frame.
675 CompositeFrame();
676 EXPECT_EQ(DocumentLifecycle::kVisualUpdatePending,
677 frame_element->contentDocument()->Lifecycle().GetState());
678
679 // Make the frame visible by changing its transform. This doesn't cause a
680 // layout, but should still unthrottle the frame.
681 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
682 CompositeFrame(); // Unthrottle the frame.
683 CompositeFrame(); // Handle the pending visual update of the unthrottled
684 // frame.
685 EXPECT_EQ(DocumentLifecycle::kPaintClean,
686 frame_element->contentDocument()->Lifecycle().GetState());
687 EXPECT_TRUE(
688 frame_element->contentDocument()->View()->UsesCompositedScrolling());
689 }
690
691 TEST_P(FrameThrottlingTest, UnthrottleByTransformingWithoutLayout) {
692 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
693
694 // Create a hidden frame which is throttled.
695 SimRequest main_resource("https://example.com/", "text/html");
696 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
697
698 LoadURL("https://example.com/");
699 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
700 frame_resource.Complete("");
701
702 // Move the frame offscreen to throttle it.
703 auto* frame_element =
704 toHTMLIFrameElement(GetDocument().getElementById("frame"));
705 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
706 EXPECT_FALSE(
707 frame_element->contentDocument()->View()->CanThrottleRendering());
708 CompositeFrame();
709 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
710
711 // Make the frame visible by changing its transform. This doesn't cause a
712 // layout, but should still unthrottle the frame.
713 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
714 CompositeFrame();
715 EXPECT_FALSE(
716 frame_element->contentDocument()->View()->CanThrottleRendering());
717 }
718
719 TEST_P(FrameThrottlingTest, ThrottledTopLevelEventHandlerIgnored) {
720 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
721 WebView().GetSettings()->SetJavaScriptEnabled(true);
722 EXPECT_EQ(0u, TouchHandlerRegionSize());
723
724 // Create a frame which is throttled and has two different types of
725 // top-level touchstart handlers.
726 SimRequest main_resource("https://example.com/", "text/html");
727 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
728
729 LoadURL("https://example.com/");
730 main_resource.Complete(
731 "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
732 frame_resource.Complete(
733 "<script>"
734 "window.addEventListener('touchstart', function(){}, {passive: false});"
735 "document.addEventListener('touchstart', function(){}, {passive: false});"
736 "</script>");
737 auto* frame_element =
738 toHTMLIFrameElement(GetDocument().getElementById("frame"));
739 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
740 CompositeFrame(); // Throttle the frame.
741 CompositeFrame(); // Update touch handler regions.
742
743 // The touch handlers in the throttled frame should have been ignored.
744 EXPECT_EQ(0u, TouchHandlerRegionSize());
745
746 // Unthrottling the frame makes the touch handlers active again. Note that
747 // both handlers get combined into the same rectangle in the region, so
748 // there is only one rectangle in total.
749 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
750 CompositeFrame(); // Unthrottle the frame.
751 CompositeFrame(); // Update touch handler regions.
752 EXPECT_EQ(1u, TouchHandlerRegionSize());
753 }
754
755 TEST_P(FrameThrottlingTest, ThrottledEventHandlerIgnored) {
756 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
757 WebView().GetSettings()->SetJavaScriptEnabled(true);
758 EXPECT_EQ(0u, TouchHandlerRegionSize());
759
760 // Create a frame which is throttled and has a non-top-level touchstart
761 // handler.
762 SimRequest main_resource("https://example.com/", "text/html");
763 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
764
765 LoadURL("https://example.com/");
766 main_resource.Complete(
767 "<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
768 frame_resource.Complete(
769 "<div id=d>touch handler</div>"
770 "<script>"
771 "document.querySelector('#d').addEventListener('touchstart', "
772 "function(){});"
773 "</script>");
774 auto* frame_element =
775 toHTMLIFrameElement(GetDocument().getElementById("frame"));
776 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
777 CompositeFrame(); // Throttle the frame.
778 CompositeFrame(); // Update touch handler regions.
779
780 // The touch handler in the throttled frame should have been ignored.
781 EXPECT_EQ(0u, TouchHandlerRegionSize());
782
783 // Unthrottling the frame makes the touch handler active again.
784 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
785 CompositeFrame(); // Unthrottle the frame.
786 CompositeFrame(); // Update touch handler regions.
787 EXPECT_EQ(1u, TouchHandlerRegionSize());
788 }
789
790 TEST_P(FrameThrottlingTest, DumpThrottledFrame) {
791 WebView().GetSettings()->SetJavaScriptEnabled(true);
792
793 // Create a frame which is throttled.
794 SimRequest main_resource("https://example.com/", "text/html");
795 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
796
797 LoadURL("https://example.com/");
798 main_resource.Complete(
799 "main <iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
800 frame_resource.Complete("");
801 auto* frame_element =
802 toHTMLIFrameElement(GetDocument().getElementById("frame"));
803 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
804 CompositeFrame();
805 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
806
807 LocalFrame* local_frame = ToLocalFrame(frame_element->ContentFrame());
808 local_frame->GetScriptController().ExecuteScriptInMainWorld(
809 "document.body.innerHTML = 'throttled'");
810 EXPECT_FALSE(Compositor().NeedsBeginFrame());
811
812 // The dumped contents should not include the throttled frame.
813 DocumentLifecycle::AllowThrottlingScope throttling_scope(
814 GetDocument().Lifecycle());
815 WebString result = WebFrameContentDumper::DeprecatedDumpFrameTreeAsText(
816 WebView().MainFrameImpl(), 1024);
817 EXPECT_NE(std::string::npos, result.Utf8().find("main"));
818 EXPECT_EQ(std::string::npos, result.Utf8().find("throttled"));
819 }
820
821 TEST_P(FrameThrottlingTest, PaintingViaContentLayerDelegateIsThrottled) {
822 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
823 WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
824
825 // Create a hidden frame which is throttled.
826 SimRequest main_resource("https://example.com/", "text/html");
827 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
828
829 LoadURL("https://example.com/");
830 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
831 frame_resource.Complete("throttled");
832 CompositeFrame();
833
834 // Move the frame offscreen to throttle it and make sure it is backed by a
835 // graphics layer.
836 auto* frame_element =
837 toHTMLIFrameElement(GetDocument().getElementById("frame"));
838 frame_element->setAttribute(styleAttr,
839 "transform: translateY(480px) translateZ(0px)");
840 EXPECT_FALSE(
841 frame_element->contentDocument()->View()->CanThrottleRendering());
842 CompositeFrame();
843 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
844
845 // If painting of the iframe is throttled, we should only receive two
846 // drawing items.
847 MockWebDisplayItemList display_items;
848 EXPECT_CALL(display_items, AppendDrawingItem(_, _)).Times(2);
849
850 GraphicsLayer* layer = WebView().RootGraphicsLayer();
851 PaintRecursively(layer, &display_items);
852 }
853
854 TEST_P(FrameThrottlingTest, ThrottleSubtreeAtomically) {
855 // Create two nested frames which are throttled.
856 SimRequest main_resource("https://example.com/", "text/html");
857 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
858 SimRequest child_frame_resource("https://example.com/child-iframe.html",
859 "text/html");
860
861 LoadURL("https://example.com/");
862 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
863 frame_resource.Complete(
864 "<iframe id=child-frame sandbox src=child-iframe.html></iframe>");
865 child_frame_resource.Complete("");
866
867 // Move both frames offscreen, but don't run the intersection observers yet.
868 auto* frame_element =
869 toHTMLIFrameElement(GetDocument().getElementById("frame"));
870 auto* child_frame_element = toHTMLIFrameElement(
871 frame_element->contentDocument()->getElementById("child-frame"));
872 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
873 Compositor().BeginFrame();
874 EXPECT_FALSE(
875 frame_element->contentDocument()->View()->CanThrottleRendering());
876 EXPECT_FALSE(
877 child_frame_element->contentDocument()->View()->CanThrottleRendering());
878
879 // Only run the intersection observer for the parent frame. Both frames
880 // should immediately become throttled. This simulates the case where a task
881 // such as BeginMainFrame runs in the middle of dispatching intersection
882 // observer notifications.
883 frame_element->contentDocument()
884 ->View()
885 ->UpdateRenderThrottlingStatusForTesting();
886 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
887 EXPECT_TRUE(
888 child_frame_element->contentDocument()->View()->CanThrottleRendering());
889
890 // Both frames should still be throttled after the second notification.
891 child_frame_element->contentDocument()
892 ->View()
893 ->UpdateRenderThrottlingStatusForTesting();
894 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
895 EXPECT_TRUE(
896 child_frame_element->contentDocument()->View()->CanThrottleRendering());
897
898 // Move the frame back on screen but don't update throttling yet.
899 frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
900 Compositor().BeginFrame();
901 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
902 EXPECT_TRUE(
903 child_frame_element->contentDocument()->View()->CanThrottleRendering());
904
905 // Update throttling for the child. It should remain throttled because the
906 // parent is still throttled.
907 child_frame_element->contentDocument()
908 ->View()
909 ->UpdateRenderThrottlingStatusForTesting();
910 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
911 EXPECT_TRUE(
912 child_frame_element->contentDocument()->View()->CanThrottleRendering());
913
914 // Updating throttling on the parent should unthrottle both frames.
915 frame_element->contentDocument()
916 ->View()
917 ->UpdateRenderThrottlingStatusForTesting();
918 EXPECT_FALSE(
919 frame_element->contentDocument()->View()->CanThrottleRendering());
920 EXPECT_FALSE(
921 child_frame_element->contentDocument()->View()->CanThrottleRendering());
922 }
923
924 TEST_P(FrameThrottlingTest, SkipPaintingLayersInThrottledFrames) {
925 WebView().GetSettings()->SetAcceleratedCompositingEnabled(true);
926 WebView().GetSettings()->SetPreferCompositingToLCDTextEnabled(true);
927
928 SimRequest main_resource("https://example.com/", "text/html");
929 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
930
931 LoadURL("https://example.com/");
932 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
933 frame_resource.Complete(
934 "<div id=div style='transform: translateZ(0); background: "
935 "red'>layer</div>");
936 auto display_items = CompositeFrame();
937 EXPECT_TRUE(display_items.Contains(SimCanvas::kRect, "red"));
938
939 auto* frame_element =
940 toHTMLIFrameElement(GetDocument().getElementById("frame"));
941 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
942 CompositeFrame();
943 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
944
945 auto* frame_document = frame_element->contentDocument();
946 EXPECT_EQ(DocumentLifecycle::kPaintClean,
947 frame_document->Lifecycle().GetState());
948
949 // Simulate the paint for a graphics layer being externally invalidated
950 // (e.g., by video playback).
951 frame_document->View()
952 ->GetLayoutViewItem()
953 .InvalidatePaintForViewAndCompositedLayers();
954
955 // The layer inside the throttled frame should not get painted.
956 auto display_items2 = CompositeFrame();
957 EXPECT_FALSE(display_items2.Contains(SimCanvas::kRect, "red"));
958 }
959
960 TEST_P(FrameThrottlingTest, SynchronousLayoutInAnimationFrameCallback) {
961 WebView().GetSettings()->SetJavaScriptEnabled(true);
962
963 // Prepare a page with two cross origin frames (from the same origin so they
964 // are able to access eachother).
965 SimRequest main_resource("https://example.com/", "text/html");
966 SimRequest first_frame_resource("https://thirdparty.com/first.html",
967 "text/html");
968 SimRequest second_frame_resource("https://thirdparty.com/second.html",
969 "text/html");
970 LoadURL("https://example.com/");
971 main_resource.Complete(
972 "<iframe id=first name=first "
973 "src='https://thirdparty.com/first.html'></iframe>\n"
974 "<iframe id=second name=second "
975 "src='https://thirdparty.com/second.html'></iframe>");
976
977 // The first frame contains just a simple div. This frame will be made
978 // throttled.
979 first_frame_resource.Complete("<div id=d>first frame</div>");
980
981 // The second frame just used to execute a requestAnimationFrame callback.
982 second_frame_resource.Complete("");
983
984 // Throttle the first frame.
985 auto* first_frame_element =
986 toHTMLIFrameElement(GetDocument().getElementById("first"));
987 first_frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
988 CompositeFrame();
989 EXPECT_TRUE(
990 first_frame_element->contentDocument()->View()->CanThrottleRendering());
991
992 // Run a animation frame callback in the second frame which mutates the
993 // contents of the first frame and causes a synchronous style update. This
994 // should not result in an unexpected lifecycle state even if the first
995 // frame is throttled during the animation frame callback.
996 auto* second_frame_element =
997 toHTMLIFrameElement(GetDocument().getElementById("second"));
998 LocalFrame* local_frame = ToLocalFrame(second_frame_element->ContentFrame());
999 local_frame->GetScriptController().ExecuteScriptInMainWorld(
1000 "window.requestAnimationFrame(function() {\n"
1001 " var throttledFrame = window.parent.frames.first;\n"
1002 " throttledFrame.document.documentElement.style = 'margin: 50px';\n"
1003 " throttledFrame.document.querySelector('#d').getBoundingClientRect();\n"
1004 "});\n");
1005 CompositeFrame();
1006 }
1007
1008 TEST_P(FrameThrottlingTest, AllowOneAnimationFrame) {
1009 WebView().GetSettings()->SetJavaScriptEnabled(true);
1010
1011 // Prepare a page with two cross origin frames (from the same origin so they
1012 // are able to access eachother).
1013 SimRequest main_resource("https://example.com/", "text/html");
1014 SimRequest frame_resource("https://thirdparty.com/frame.html", "text/html");
1015 LoadURL("https://example.com/");
1016 main_resource.Complete(
1017 "<iframe id=frame style=\"position: fixed; top: -10000px\" "
1018 "src='https://thirdparty.com/frame.html'></iframe>");
1019
1020 frame_resource.Complete(
1021 "<script>"
1022 "window.requestAnimationFrame(() => { window.didRaf = true; });"
1023 "</script>");
1024
1025 auto* frame_element =
1026 toHTMLIFrameElement(GetDocument().getElementById("frame"));
1027 CompositeFrame();
1028 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
1029
1030 LocalFrame* local_frame = ToLocalFrame(frame_element->ContentFrame());
1031 v8::HandleScope scope(v8::Isolate::GetCurrent());
1032 v8::Local<v8::Value> result =
1033 local_frame->GetScriptController().ExecuteScriptInMainWorldAndReturnValue(
1034 ScriptSourceCode("window.didRaf;"));
1035 EXPECT_TRUE(result->IsTrue());
1036 }
1037
1038 TEST_P(FrameThrottlingTest, UpdatePaintPropertiesOnUnthrottling) {
1039 if (!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
1040 return;
1041
1042 SimRequest main_resource("https://example.com/", "text/html");
1043 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
1044
1045 LoadURL("https://example.com/");
1046 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
1047 frame_resource.Complete("<div id='div'>Inner</div>");
1048 CompositeFrame();
1049
1050 auto* frame_element =
1051 toHTMLIFrameElement(GetDocument().getElementById("frame"));
1052 auto* frame_document = frame_element->contentDocument();
1053 auto* inner_div = frame_document->getElementById("div");
1054 auto* inner_div_object = inner_div->GetLayoutObject();
1055 EXPECT_FALSE(frame_document->View()->ShouldThrottleRendering());
1056
1057 frame_element->setAttribute(HTMLNames::styleAttr,
1058 "transform: translateY(1000px)");
1059 CompositeFrame();
1060 EXPECT_TRUE(frame_document->View()->CanThrottleRendering());
1061 EXPECT_FALSE(inner_div_object->PaintProperties());
1062
1063 // Mutating the throttled frame should not cause paint property update.
1064 inner_div->setAttribute(HTMLNames::styleAttr, "transform: translateY(20px)");
1065 EXPECT_FALSE(Compositor().NeedsBeginFrame());
1066 EXPECT_TRUE(frame_document->View()->CanThrottleRendering());
1067 {
1068 DocumentLifecycle::AllowThrottlingScope throttling_scope(
1069 GetDocument().Lifecycle());
1070 GetDocument().View()->UpdateAllLifecyclePhases();
1071 }
1072 EXPECT_FALSE(inner_div_object->PaintProperties());
1073
1074 // Move the frame back on screen to unthrottle it.
1075 frame_element->setAttribute(HTMLNames::styleAttr, "");
1076 // The first update unthrottles the frame, the second actually update layout
1077 // and paint properties etc.
1078 CompositeFrame();
1079 CompositeFrame();
1080 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
1081 EXPECT_EQ(
1082 TransformationMatrix().Translate(0, 20),
1083 inner_div->GetLayoutObject()->PaintProperties()->Transform()->Matrix());
1084 }
1085
1086 TEST_P(FrameThrottlingTest, DisplayNoneNotThrottled) {
1087 SimRequest main_resource("https://example.com/", "text/html");
1088
1089 LoadURL("https://example.com/");
1090 main_resource.Complete(
1091 "<style>iframe { transform: translateY(480px); }</style>"
1092 "<iframe sandbox id=frame></iframe>");
1093
1094 auto* frame_element =
1095 toHTMLIFrameElement(GetDocument().getElementById("frame"));
1096 auto* frame_document = frame_element->contentDocument();
1097
1098 // Initially the frame is throttled as it is offscreen.
1099 CompositeFrame();
1100 EXPECT_TRUE(frame_document->View()->CanThrottleRendering());
1101
1102 // Setting display:none unthrottles the frame.
1103 frame_element->setAttribute(styleAttr, "display: none");
1104 CompositeFrame();
1105 EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
1106 }
1107
1108 TEST_P(FrameThrottlingTest, DisplayNoneChildrenRemainThrottled) {
1109 // Create two nested frames which are throttled.
1110 SimRequest main_resource("https://example.com/", "text/html");
1111 SimRequest frame_resource("https://example.com/iframe.html", "text/html");
1112 SimRequest child_frame_resource("https://example.com/child-iframe.html",
1113 "text/html");
1114
1115 LoadURL("https://example.com/");
1116 main_resource.Complete("<iframe id=frame sandbox src=iframe.html></iframe>");
1117 frame_resource.Complete(
1118 "<iframe id=child-frame sandbox src=child-iframe.html></iframe>");
1119 child_frame_resource.Complete("");
1120
1121 // Move both frames offscreen to make them throttled.
1122 auto* frame_element =
1123 toHTMLIFrameElement(GetDocument().getElementById("frame"));
1124 auto* child_frame_element = toHTMLIFrameElement(
1125 frame_element->contentDocument()->getElementById("child-frame"));
1126 frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
1127 CompositeFrame();
1128 EXPECT_TRUE(frame_element->contentDocument()->View()->CanThrottleRendering());
1129 EXPECT_TRUE(
1130 child_frame_element->contentDocument()->View()->CanThrottleRendering());
1131
1132 // Setting display:none for the parent frame unthrottles the parent but not
1133 // the child. This behavior matches Safari.
1134 frame_element->setAttribute(styleAttr, "display: none");
1135 CompositeFrame();
1136 EXPECT_FALSE(
1137 frame_element->contentDocument()->View()->CanThrottleRendering());
1138 EXPECT_TRUE(
1139 child_frame_element->contentDocument()->View()->CanThrottleRendering());
1140 }
1141
1142 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698