OLD | NEW |
---|---|
(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 "config.h" | |
6 | |
7 #include "core/dom/Document.h" | |
8 #include "core/frame/FrameView.h" | |
9 #include "public/web/WebElement.h" | |
10 #include "web/WebLocalFrameImpl.h" | |
11 #include "web/tests/FrameTestHelpers.h" | |
12 #include "web/tests/sim/SimCompositor.h" | |
13 #include "web/tests/sim/SimDisplayItemList.h" | |
14 #include "web/tests/sim/SimLayerTreeView.h" | |
15 #include "web/tests/sim/SimWebViewClient.h" | |
16 #include <gtest/gtest.h> | |
17 | |
18 namespace blink { | |
19 | |
20 class FrameThrottlingTest : public ::testing::Test { | |
21 protected: | |
22 using SecurityOriginStatus = FrameView::SecurityOriginStatus; | |
23 using ViewportVisibility = FrameView::ViewportVisibility; | |
24 | |
25 FrameThrottlingTest() | |
26 : m_webViewClient(m_layerTreeView) | |
27 , m_compositor(m_layerTreeView) | |
28 { | |
29 m_webViewHelper.initialize(true, &m_webFrameClient, &m_webViewClient); | |
30 m_compositor.setWebViewImpl(webView()); | |
31 webView().resize(WebSize(640, 480)); | |
32 } | |
33 | |
34 ~FrameThrottlingTest() override { } | |
35 | |
36 void setInnerHTML(const String& html) | |
37 { | |
38 document().documentElement()->setInnerHTML(html, ASSERT_NO_EXCEPTION); | |
39 m_webFrameClient.waitForLoadToComplete(); | |
40 webView().layout(); | |
41 } | |
42 | |
43 void setupPageWithThrottleableFrame() | |
44 { | |
45 setInnerHTML("<iframe sandbox=\"\"></iframe>"); | |
46 } | |
47 | |
48 Document& document() | |
49 { | |
50 return *webView().mainFrameImpl()->frame()->document(); | |
51 } | |
52 | |
53 WebNode root() | |
54 { | |
55 return WebNode(document().documentElement()); | |
56 } | |
57 | |
58 WebViewImpl& webView() | |
59 { | |
60 return *m_webViewHelper.webViewImpl(); | |
61 } | |
62 | |
63 ViewportVisibility viewportVisibility(FrameView* frameView) | |
64 { | |
65 return frameView->m_viewportVisibility; | |
66 } | |
67 | |
68 SimLayerTreeView m_layerTreeView; | |
69 SimWebViewClient m_webViewClient; | |
70 SimCompositor m_compositor; | |
71 FrameTestHelpers::TestWebFrameClient m_webFrameClient; | |
72 FrameTestHelpers::WebViewHelper m_webViewHelper; | |
73 }; | |
74 | |
75 TEST_F(FrameThrottlingTest, ThrottleInvisibleFrames) | |
76 { | |
77 setupPageWithThrottleableFrame(); | |
78 | |
79 // Initially both frames are visible. | |
80 FrameView* frameView = document().view(); | |
81 FrameView* childFrameView = toLocalFrame(frameView->frame().tree().firstChil d())->view(); | |
82 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
83 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView)); | |
84 | |
85 // Moving the child fully outside the parent makes it invisible. | |
86 childFrameView->move(0, frameView->height()); | |
87 frameView->updateAllLifecyclePhases(); | |
88 frameView->finalizeLifecycleUpdate(); | |
89 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
90 EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView)); | |
91 | |
92 // A partially visible child is considered visible. | |
93 childFrameView->move(-childFrameView->width() / 2, 0); | |
94 frameView->updateAllLifecyclePhases(); | |
95 frameView->finalizeLifecycleUpdate(); | |
esprehn
2015/10/01 08:21:37
m_compositor.beginFrame()
Sami
2015/10/05 17:58:24
Done.
| |
96 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
97 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView)); | |
98 } | |
99 | |
100 TEST_F(FrameThrottlingTest, viewportVisibilityFullyClipped) | |
101 { | |
102 setupPageWithThrottleableFrame(); | |
103 | |
104 // A child which is fully clipped away by its ancestor should become invisib le. | |
105 FrameView* frameView = document().view(); | |
106 FrameView* childFrameView = toLocalFrame(frameView->frame().tree().firstChil d())->view(); | |
107 webView().resize(WebSize(0, 0)); | |
108 webView().layout(); | |
esprehn
2015/10/01 08:21:37
ditto, layout is only triggered from frames, so yo
Sami
2015/10/05 17:58:24
Done.
| |
109 frameView->updateAllLifecyclePhases(); | |
110 frameView->finalizeLifecycleUpdate(); | |
esprehn
2015/10/01 08:21:36
and then you don't need this
Sami
2015/10/05 17:58:24
Done.
| |
111 EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView)); | |
112 EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView)); | |
113 } | |
114 | |
115 TEST_F(FrameThrottlingTest, hiddenCrossOriginFramesAreThrottled) | |
116 { | |
117 // Create a document with doubly nested iframes. | |
118 setInnerHTML("<iframe srcdoc=\"<iframe></iframe>\"></iframe>"); | |
119 | |
120 FrameView* frameView = document().view(); | |
121 LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild() ); | |
122 LocalFrame* grandChildFrame = toLocalFrame(childFrame->tree().firstChild()); | |
123 FrameView* childFrameView = childFrame->view(); | |
124 FrameView* grandChildFrameView = grandChildFrame->view(); | |
125 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
126 EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline()); | |
127 EXPECT_FALSE(grandChildFrameView->shouldThrottleRenderingPipeline()); | |
128 | |
129 // Just being hidden doesn't make a frame throttled. | |
130 grandChildFrameView->move(0, frameView->height()); | |
esprehn
2015/10/01 08:21:36
this can't happen in a real page, set some style t
Sami
2015/10/05 17:58:24
Done.
| |
131 frameView->finalizeLifecycleUpdate(); | |
132 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
133 EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline()); | |
134 EXPECT_FALSE(grandChildFrameView->shouldThrottleRenderingPipeline()); | |
135 | |
136 // Making the middle frame cross origin enables throttling for the grand chi ld. | |
137 childFrame->securityContext()->setSecurityOrigin(SecurityOrigin::createUniqu e()); | |
138 frameView->finalizeLifecycleUpdate(); | |
esprehn
2015/10/01 08:21:36
why would this happen again in a real page?
Sami
2015/10/05 17:58:24
You're right, it wouldn't. To make this more reali
| |
139 EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline()); | |
140 EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline()); | |
141 EXPECT_TRUE(grandChildFrameView->shouldThrottleRenderingPipeline()); | |
142 } | |
143 | |
144 TEST_F(FrameThrottlingTest, throttledLifecycleUpdate) | |
145 { | |
146 setupPageWithThrottleableFrame(); | |
147 | |
148 FrameView* frameView = document().view(); | |
149 LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild() ); | |
150 FrameView* childFrameView = childFrame->view(); | |
151 | |
152 // Enable throttling for the child frame. | |
153 childFrameView->move(0, frameView->height()); | |
esprehn
2015/10/01 08:21:36
move with style, real pages can't go through ->mov
Sami
2015/10/05 17:58:25
Done.
| |
154 frameView->updateAllLifecyclePhases(); | |
155 frameView->finalizeLifecycleUpdate(); | |
esprehn
2015/10/01 08:21:36
ditto, beginFrame()
Sami
2015/10/05 17:58:24
Done.
| |
156 EXPECT_TRUE(childFrameView->shouldThrottleRenderingPipeline()); | |
157 | |
158 // Doing a lifecycle update while allowing throttling shouldn't clear the | |
159 // needs layout bit on the child frame. | |
160 childFrameView->setNeedsLayout(); | |
esprehn
2015/10/01 08:21:37
don't artificially cause layout, do something real
Sami
2015/10/05 17:58:24
Done.
| |
161 EXPECT_TRUE(childFrameView->needsLayout()); | |
162 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
esprehn
2015/10/01 08:21:37
this can't really happen
Sami
2015/10/05 17:58:24
Replaced with another beginFrame().
| |
163 EXPECT_TRUE(childFrameView->needsLayout()); | |
164 | |
165 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Disal low); | |
166 EXPECT_FALSE(childFrameView->needsLayout()); | |
167 } | |
168 | |
169 TEST_F(FrameThrottlingTest, unthrottlingFrameSchedulesAnimation) | |
170 { | |
171 setupPageWithThrottleableFrame(); | |
172 FrameView* frameView = document().view(); | |
173 LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild() ); | |
174 FrameView* childFrameView = childFrame->view(); | |
175 | |
176 // First make the child hidden to enable throttling. | |
177 childFrameView->move(0, frameView->height()); | |
esprehn
2015/10/01 08:21:37
ditto
Sami
2015/10/05 17:58:24
Done.
| |
178 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
179 m_layerTreeView.clearNeedsAnimate(); | |
180 frameView->finalizeLifecycleUpdate(); | |
181 EXPECT_FALSE(m_layerTreeView.needsAnimate()); | |
182 | |
183 // Then bring it back on-screen. This should schedule an animation update. | |
184 childFrameView->move(0, 0); | |
185 frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow ); | |
186 m_layerTreeView.clearNeedsAnimate(); | |
esprehn
2015/10/01 08:21:36
beginFrame() clears this bit, real pages never cle
Sami
2015/10/05 17:58:24
Thanks, replaced this with beginFrame too, but had
| |
187 frameView->finalizeLifecycleUpdate(); | |
188 EXPECT_TRUE(m_layerTreeView.needsAnimate()); | |
189 } | |
190 | |
191 TEST_F(FrameThrottlingTest, mutatingThrottledFrameDoesNotCauseAnimation) | |
192 { | |
193 setInnerHTML("<iframe id=\"frame\" sandbox=\"\" srcdoc=\"<style> html { back ground: red; } </style>\"></iframe>"); | |
194 WebExceptionCode ec; | |
195 WebElement frameElement = root().querySelector("#frame", ec); | |
196 EXPECT_EQ(0, ec); | |
197 | |
198 // Check that the frame initially shows up. | |
199 m_layerTreeView.setDeferCommits(false); | |
200 SimDisplayItemList displayItems1 = m_compositor.beginFrame(); | |
201 EXPECT_TRUE(displayItems1.contains(SimCanvas::Rect, "red")); | |
202 | |
203 // Move the frame offscreen to throttle it. | |
204 FrameView* frameView = document().view(); | |
205 LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild() ); | |
206 frameElement.setAttribute("style", "transform: translateY(480px)"); | |
207 webView().layout(); | |
208 frameView->finalizeLifecycleUpdate(); | |
209 | |
210 // Mutating the throttled frame should not cause an animation to be schedule d. | |
211 m_layerTreeView.clearNeedsAnimate(); | |
212 childFrame->document()->documentElement()->setInnerHTML("<style> html { back ground: green; } </style>", ASSERT_NO_EXCEPTION); | |
213 EXPECT_FALSE(m_layerTreeView.needsAnimate()); | |
214 | |
215 // Moving the frame back on screen should make its new contents show up. | |
216 frameElement.setAttribute("style", ""); | |
217 EXPECT_TRUE(m_layerTreeView.needsAnimate()); | |
218 webView().layout(); | |
esprehn
2015/10/01 08:21:36
beginFrame()
| |
219 frameView->finalizeLifecycleUpdate(); | |
esprehn
2015/10/01 08:21:36
How does this happen in a real page? You cause an
Sami
2015/10/05 17:58:24
Replaced this with a series of composites that sho
| |
220 | |
221 SimDisplayItemList displayItems2 = m_compositor.beginFrame(); | |
222 EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green")); | |
223 } | |
224 | |
225 } // namespace blink | |
OLD | NEW |