OLD | NEW |
---|---|
(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 <vector> | |
6 | |
7 #include "content/browser/frame_host/frame_tree_node.h" | |
8 #include "content/browser/frame_host/render_frame_host_impl.h" | |
9 #include "content/browser/web_contents/web_contents_impl.h" | |
10 #include "content/public/browser/host_zoom_map.h" | |
11 #include "content/public/browser/navigation_entry.h" | |
12 #include "content/public/common/page_zoom.h" | |
13 #include "content/public/test/browser_test_utils.h" | |
14 #include "content/public/test/content_browser_test.h" | |
15 #include "content/public/test/content_browser_test_utils.h" | |
16 #include "content/public/test/test_navigation_observer.h" | |
17 #include "content/shell/browser/shell.h" | |
18 #include "content/test/content_browser_test_utils_internal.h" | |
19 #include "net/dns/mock_host_resolver.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 #include "url/gurl.h" | |
22 | |
23 namespace content { | |
24 | |
25 class IFrameZoomBrowserTest : public ContentBrowserTest { | |
alexmos
2016/04/25 22:43:27
A comment with a high-level overview of how these
wjmaclean
2016/04/27 13:43:57
I've tried to improve this ... let me know what yo
alexmos
2016/04/27 23:39:51
This is great - thanks for adding this!
| |
26 public: | |
27 IFrameZoomBrowserTest() {} | |
28 | |
29 protected: | |
30 void SetUpOnMainThread() override { | |
31 host_resolver()->AddRule("*", "127.0.0.1"); | |
32 ASSERT_TRUE(embedded_test_server()->Start()); | |
33 SetupCrossSiteRedirector(embedded_test_server()); | |
34 } | |
35 | |
36 WebContentsImpl* web_contents() { | |
37 return static_cast<WebContentsImpl*>(shell()->web_contents()); | |
38 } | |
39 }; | |
40 | |
41 double GetMainframeWindowBorder(const ToRenderFrameHost& adapter) { | |
42 double border; | |
43 const char kGetMainframeBorder[] = "window.domAutomationController.send(" | |
44 "window.outerWidth - window.innerWidth" | |
45 ");"; | |
46 EXPECT_TRUE( | |
47 ExecuteScriptAndExtractDouble(adapter, kGetMainframeBorder, &border)); | |
48 return border; | |
49 } | |
50 | |
51 double GetMainframeZoomFactor(const ToRenderFrameHost& adapter, double border) { | |
alexmos
2016/04/25 22:43:27
nit: s/GetMainframeZoomFactor/GetMainFrameZoomFact
wjmaclean
2016/04/27 13:43:57
Done. I had used 'Mainframe' to match 'Subframe',
| |
52 const char kGetMainframeZoomLevel[] = | |
53 "window.domAutomationController.send(" | |
54 "(window.outerWidth - %f)/window.innerWidth" | |
55 ");"; | |
56 double zoom_factor; | |
57 EXPECT_TRUE(ExecuteScriptAndExtractDouble( | |
58 adapter, base::StringPrintf(kGetMainframeZoomLevel, border), | |
59 &zoom_factor)); | |
60 return zoom_factor; | |
61 } | |
62 | |
63 double GetSubframeWidth(const ToRenderFrameHost& adapter) { | |
64 double width; | |
65 EXPECT_TRUE(ExecuteScriptAndExtractDouble( | |
66 adapter, "window.domAutomationController.send(window.innerWidth);", | |
67 &width)); | |
68 return width; | |
69 } | |
70 | |
71 #define SETUP_A_B_A_NESTED_FRAMES() \ | |
alexmos
2016/04/25 22:43:27
I'm not sure how I feel about this macro. :) I'm
wjmaclean
2016/04/27 13:43:57
I've replicated the macro, and moved the helpers i
| |
72 std::string top_level_host("a.com"); \ | |
73 GURL main_url(embedded_test_server()->GetURL( \ | |
74 top_level_host, "/cross_site_iframe_factory.html?a(b(a))")); \ | |
75 EXPECT_TRUE(NavigateToURL(shell(), main_url)); \ | |
76 NavigationEntry* entry = \ | |
77 web_contents()->GetController().GetLastCommittedEntry(); \ | |
78 ASSERT_TRUE(entry); \ | |
79 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry); \ | |
80 EXPECT_EQ(top_level_host, loaded_url.host()); \ | |
81 \ | |
82 FrameTreeNode* root = \ | |
83 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root(); \ | |
84 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host(); \ | |
85 RenderFrameHostImpl* grandchild = \ | |
86 root->child_at(0)->child_at(0)->current_frame_host(); \ | |
87 \ | |
88 /* The following calls must be made when the page's scale factor = 1.0.*/ \ | |
89 double scale_one_child_width = GetSubframeWidth(child); \ | |
90 double scale_one_grandchild_width = GetSubframeWidth(grandchild); \ | |
91 double main_frame_window_border = GetMainframeWindowBorder(web_contents()); \ | |
92 \ | |
93 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents()); \ | |
94 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel(); \ | |
95 EXPECT_EQ(0.0, default_zoom_level); \ | |
96 \ | |
97 EXPECT_DOUBLE_EQ( \ | |
98 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
99 | |
100 // The tests in this file rely on the notion that, when a page zooms, that | |
101 // subframes both (1) a change in their frame rect, and (2) a change in their | |
102 // frame's scale. Since the page should scale as a unit, this means the | |
103 // innerWidth value of any subframe should be the same before and after the | |
104 // zoom (though it may transiently take on a different value). The | |
105 // FrameSizeObserver serves to watch for onresize events, and observes when | |
106 // the innerWidth is correctly set. | |
107 struct FrameResizeObserver { | |
108 FrameResizeObserver(RenderFrameHost* host, | |
109 std::string label, | |
110 double inner_width, | |
111 double tolerance) | |
112 : frame_host(host), | |
113 msg_label(std::move(label)), | |
114 zoomed_correctly(false), | |
115 expected_inner_width(inner_width), | |
116 tolerance(tolerance) { | |
117 SetupOnResizeCallback(host, msg_label); | |
118 } | |
119 | |
120 void SetupOnResizeCallback(const ToRenderFrameHost& adapter, | |
121 const std::string& label) { | |
122 const char kOnResizeCallbackSetup[] = | |
123 "document.body.onresize = function(){" | |
124 " window.domAutomationController.setAutomationId(0);" | |
125 " window.domAutomationController.send('%s ' + window.innerWidth);" | |
126 "};"; | |
127 EXPECT_TRUE(ExecuteScript( | |
128 adapter, base::StringPrintf(kOnResizeCallbackSetup, label.c_str()))); | |
129 } | |
130 | |
131 void Check(const std::string& status_msg) { | |
132 if (status_msg.find(msg_label) != 0) | |
133 return; | |
134 | |
135 double inner_width = std::stod(status_msg.substr(msg_label.length() + 1)); | |
136 zoomed_correctly = std::abs(expected_inner_width - inner_width) < tolerance; | |
137 } | |
138 | |
139 FrameResizeObserver* toThis() {return this;} | |
140 | |
141 RenderFrameHost* frame_host; | |
142 std::string msg_label; | |
143 bool zoomed_correctly; | |
144 double expected_inner_width; | |
145 double tolerance; | |
146 }; | |
147 | |
148 void WaitAndCheckFrameZoom( | |
149 DOMMessageQueue& msg_queue, | |
150 std::vector<FrameResizeObserver>& frame_observers) { | |
151 std::string status; | |
152 while (msg_queue.WaitForMessage(&status)) { | |
153 // Strip the double quotes from the message. | |
154 status = status.substr(1, status.length() -2); | |
155 | |
156 bool all_zoomed_correctly = true; | |
157 | |
158 // Use auto& to operate on a reference, and not a copy. | |
159 for (auto& observer : frame_observers) { | |
160 observer.Check(status); | |
161 all_zoomed_correctly = all_zoomed_correctly && observer.zoomed_correctly; | |
162 } | |
163 | |
164 if (all_zoomed_correctly) | |
165 break; | |
166 } | |
167 } | |
168 | |
169 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesZoomProperly) { | |
170 SETUP_A_B_A_NESTED_FRAMES(); | |
171 | |
172 const double new_zoom_factor = 2.5; | |
173 { | |
174 DOMMessageQueue msg_queue; | |
175 | |
176 const double kTolerance = 0.1; | |
177 std::vector<FrameResizeObserver> frame_observers; | |
178 frame_observers.emplace_back(child, "child", | |
179 scale_one_child_width, kTolerance); | |
180 frame_observers.emplace_back(grandchild, "grandchild", | |
181 scale_one_grandchild_width, kTolerance); | |
182 | |
183 const double new_zoom_level = | |
184 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
185 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level); | |
186 | |
187 WaitAndCheckFrameZoom(msg_queue, frame_observers); | |
188 } | |
189 | |
190 EXPECT_DOUBLE_EQ( | |
191 new_zoom_factor, | |
192 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
193 } | |
194 | |
195 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesDontZoomIndependently) { | |
196 SETUP_A_B_A_NESTED_FRAMES(); | |
197 | |
198 const double new_zoom_factor = 2.0; | |
199 const double new_zoom_level = | |
200 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
201 | |
202 // This should not cause the nested iframe to change its zoom. | |
203 host_zoom_map->SetZoomLevelForHost("b.com", new_zoom_level); | |
204 | |
205 EXPECT_DOUBLE_EQ( | |
206 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
207 EXPECT_EQ(scale_one_child_width, GetSubframeWidth(child)); | |
208 EXPECT_EQ(scale_one_grandchild_width, GetSubframeWidth(grandchild)); | |
209 | |
210 // When we navigate so that b.com is the top-level site, then it has the | |
211 // expected zoom. | |
212 EXPECT_TRUE(NavigateToURL( | |
213 shell(), embedded_test_server()->GetURL( | |
214 "b.com", "/cross_site_iframe_factory.html?b"))); | |
215 EXPECT_DOUBLE_EQ( | |
216 new_zoom_factor, | |
217 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
218 } | |
219 | |
220 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, AllFramesGetDefaultZoom) { | |
221 SETUP_A_B_A_NESTED_FRAMES(); | |
222 | |
223 const double new_default_zoom_factor = 2.0; | |
224 { | |
225 DOMMessageQueue msg_queue; | |
226 | |
227 const double kTolerance = 0.1; | |
228 std::vector<FrameResizeObserver> frame_observers; | |
229 frame_observers.emplace_back(child, "child", | |
230 scale_one_child_width, kTolerance); | |
231 frame_observers.emplace_back(grandchild, "grandchild", | |
232 scale_one_grandchild_width, kTolerance); | |
233 | |
234 const double new_default_zoom_level = | |
235 default_zoom_level + ZoomFactorToZoomLevel(new_default_zoom_factor); | |
236 | |
237 host_zoom_map->SetZoomLevelForHost("b.com", new_default_zoom_level + 1.0); | |
238 host_zoom_map->SetDefaultZoomLevel(new_default_zoom_level); | |
239 | |
240 WaitAndCheckFrameZoom(msg_queue, frame_observers); | |
241 } | |
242 EXPECT_DOUBLE_EQ( | |
243 new_default_zoom_factor, | |
244 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
245 } | |
246 | |
247 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SiblingFramesZoom) { | |
248 std::string top_level_host("a.com"); | |
249 GURL main_url(embedded_test_server()->GetURL( | |
250 top_level_host, "/cross_site_iframe_factory.html?a(b,b)")); | |
251 EXPECT_TRUE(NavigateToURL(shell(), main_url)); | |
252 NavigationEntry* entry = | |
253 web_contents()->GetController().GetLastCommittedEntry(); | |
254 ASSERT_TRUE(entry); | |
255 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry); | |
256 EXPECT_EQ(top_level_host, loaded_url.host()); | |
alexmos
2016/04/25 22:43:27
Maybe it's enough to have coverage for lines 252-2
alexmos
2016/04/27 23:39:51
Just making sure you saw this -- though it's also
| |
257 | |
258 FrameTreeNode* root = | |
259 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root(); | |
260 RenderFrameHostImpl* child1 = root->child_at(0)->current_frame_host(); | |
261 RenderFrameHostImpl* child2 = root->child_at(1)->current_frame_host(); | |
262 | |
263 /* The following calls must be made when the page's scale factor = 1.0.*/ | |
alexmos
2016/04/25 22:43:27
Any reason not to use // instead of /* */ here for
wjmaclean
2016/04/27 13:43:57
This migrated from a macro, hence the old-style co
| |
264 double scale_one_child1_width = GetSubframeWidth(child1); | |
265 double scale_one_child2_width = GetSubframeWidth(child2); | |
266 double main_frame_window_border = GetMainframeWindowBorder(web_contents()); | |
267 | |
268 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents()); | |
269 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel(); | |
270 EXPECT_EQ(0.0, default_zoom_level); | |
271 | |
272 EXPECT_DOUBLE_EQ( | |
273 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
274 | |
275 const double new_zoom_factor = 2.5; | |
276 { | |
277 DOMMessageQueue msg_queue; | |
278 | |
279 const double kTolerance = 0.1; | |
alexmos
2016/04/25 22:43:27
How about moving this to be declared only once som
wjmaclean
2016/04/27 13:43:57
Done.
| |
280 std::vector<FrameResizeObserver> frame_observers; | |
281 frame_observers.emplace_back(child1, "child1", | |
282 scale_one_child1_width, kTolerance); | |
283 frame_observers.emplace_back(child2, "child2", | |
284 scale_one_child2_width, kTolerance); | |
285 | |
286 const double new_zoom_level = | |
287 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
288 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level); | |
289 | |
290 WaitAndCheckFrameZoom(msg_queue, frame_observers); | |
291 } | |
292 | |
293 EXPECT_DOUBLE_EQ( | |
294 new_zoom_factor, | |
295 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
296 } | |
297 | |
298 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframeRetainsZoomOnNavigation) { | |
299 std::string top_level_host("a.com"); | |
300 GURL main_url(embedded_test_server()->GetURL( | |
301 top_level_host, "/cross_site_iframe_factory.html?a(b)")); | |
302 EXPECT_TRUE(NavigateToURL(shell(), main_url)); | |
303 NavigationEntry* entry = | |
304 web_contents()->GetController().GetLastCommittedEntry(); | |
305 ASSERT_TRUE(entry); | |
306 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry); | |
307 EXPECT_EQ(top_level_host, loaded_url.host()); | |
308 | |
309 FrameTreeNode* root = | |
310 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root(); | |
311 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host(); | |
312 | |
313 /* The following calls must be made when the page's scale factor = 1.0.*/ | |
314 double scale_one_child_width = GetSubframeWidth(child); | |
315 double main_frame_window_border = GetMainframeWindowBorder(web_contents()); | |
316 | |
317 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents()); | |
318 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel(); | |
319 EXPECT_EQ(0.0, default_zoom_level); | |
320 | |
321 EXPECT_DOUBLE_EQ( | |
322 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
323 | |
324 const double new_zoom_factor = 2.5; | |
alexmos
2016/04/25 22:43:27
It probably doesn't make any difference, but maybe
wjmaclean
2016/04/27 13:43:57
Actually, I don't think it makes any difference, a
| |
325 { | |
326 DOMMessageQueue msg_queue; | |
327 | |
328 const double kTolerance = 0.1; | |
329 std::vector<FrameResizeObserver> frame_observers; | |
330 frame_observers.emplace_back(child, "child", | |
331 scale_one_child_width, kTolerance); | |
332 | |
333 const double new_zoom_level = | |
334 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
335 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level); | |
336 | |
337 WaitAndCheckFrameZoom(msg_queue, frame_observers); | |
338 } | |
339 | |
340 EXPECT_DOUBLE_EQ( | |
341 new_zoom_factor, | |
342 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
343 | |
344 // Navigate child frame, and make sure zoom is the same. | |
alexmos
2016/04/25 22:43:27
nit: "Navigate the child frame cross-site"
wjmaclean
2016/04/27 13:43:57
Done.
| |
345 TestNavigationObserver observer(web_contents()); | |
346 GURL url = embedded_test_server()->GetURL("c.com", "/title1.html"); | |
347 NavigateFrameToURL(root->child_at(0), url); | |
348 EXPECT_TRUE(observer.last_navigation_succeeded()); | |
349 EXPECT_EQ(url, observer.last_navigation_url()); | |
350 | |
351 // After the navigation, we expect the child sub-frame to have the same scale, | |
352 // even if its domain has a different value specified. | |
alexmos
2016/04/25 22:43:27
nit: "Check that the child frame maintained the sa
wjmaclean
2016/04/27 13:43:57
Done.
| |
353 double new_child_width = | |
354 GetSubframeWidth(root->child_at(0)->current_frame_host()); | |
355 EXPECT_EQ(scale_one_child_width, new_child_width); | |
356 } | |
357 | |
358 } // namespace content | |
OLD | NEW |