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 "base/strings/string_util.h"
8 #include "content/browser/frame_host/frame_tree_node.h"
9 #include "content/browser/frame_host/render_frame_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/public/browser/host_zoom_map.h"
12 #include "content/public/browser/navigation_entry.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/browser/notification_types.h"
15 #include "content/public/test/browser_test_utils.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/public/test/test_navigation_observer.h"
19 #include "content/shell/browser/shell.h"
20 #include "content/test/content_browser_test_utils_internal.h"
21 #include "net/dns/mock_host_resolver.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/blink/public/common/page/page_zoom.h"
24 #include "url/gurl.h"
25
26 namespace content {
27
28 // This class contains basic tests of zoom functionality.
29 class ZoomBrowserTest : public ContentBrowserTest {
30 public:
ZoomBrowserTest()31 ZoomBrowserTest() {}
32
33 protected:
SetUpOnMainThread()34 void SetUpOnMainThread() override {
35 host_resolver()->AddRule("*", "127.0.0.1");
36 SetupCrossSiteRedirector(embedded_test_server());
37 ASSERT_TRUE(embedded_test_server()->Start());
38 }
39
web_contents()40 WebContentsImpl* web_contents() {
41 return static_cast<WebContentsImpl*>(shell()->web_contents());
42 }
43 };
44
45
46 // This class contains tests to make sure that subframes zoom in a manner
47 // consistent with the top-level frame, even when the subframes are cross-site.
48 // Particular things we want to make sure of:
49 //
50 // * Subframes should always have the same zoom level as their main frame, even
51 // if the subframe's domain has a different zoom level stored in HostZoomMap.
52 //
53 // * The condition above should continue to hold after a navigation of the
54 // subframe.
55 //
56 // * Zoom changes applied to the mainframe should propagate to all subframes,
57 // regardless of whether they are same site or cross-site to the frame they are
58 // children of.
59 //
60 // The tests in this file rely on the notion that, when a page zooms, that
61 // subframes have both (1) a change in their frame rect, and (2) a change in
62 // their frame's scale. Since the page should scale as a unit, this means the
63 // innerWidth value of any subframe should be the same before and after the
64 // zoom (though it may transiently take on a different value). The
65 // FrameSizeObserver serves to watch for onresize events, and observes when
66 // the innerWidth is correctly set.
67 class IFrameZoomBrowserTest : public ContentBrowserTest {
68 public:
IFrameZoomBrowserTest()69 IFrameZoomBrowserTest() {}
70
71 protected:
SetUpOnMainThread()72 void SetUpOnMainThread() override {
73 host_resolver()->AddRule("*", "127.0.0.1");
74 SetupCrossSiteRedirector(embedded_test_server());
75 ASSERT_TRUE(embedded_test_server()->Start());
76 }
77
web_contents()78 WebContentsImpl* web_contents() {
79 return static_cast<WebContentsImpl*>(shell()->web_contents());
80 }
81 };
82
83 namespace {
84
85 const double kTolerance = 0.1; // In CSS pixels.
86
GetMainframeWindowBorder(const ToRenderFrameHost & adapter)87 double GetMainframeWindowBorder(const ToRenderFrameHost& adapter) {
88 double border;
89 const char kGetMainframeBorder[] = "window.domAutomationController.send("
90 "window.outerWidth - window.innerWidth"
91 ");";
92 EXPECT_TRUE(
93 ExecuteScriptAndExtractDouble(adapter, kGetMainframeBorder, &border));
94 return border;
95 }
96
GetMainFrameZoomFactor(const ToRenderFrameHost & adapter,double border)97 double GetMainFrameZoomFactor(const ToRenderFrameHost& adapter, double border) {
98 double zoom_factor;
99 EXPECT_TRUE(ExecuteScriptAndExtractDouble(
100 adapter,
101 JsReplace("window.domAutomationController.send("
102 " (window.outerWidth - $1) / window.innerWidth);",
103 border),
104 &zoom_factor));
105 return zoom_factor;
106 }
107
GetSubframeWidth(const ToRenderFrameHost & adapter)108 double GetSubframeWidth(const ToRenderFrameHost& adapter) {
109 double width;
110 EXPECT_TRUE(ExecuteScriptAndExtractDouble(
111 adapter, "window.domAutomationController.send(window.innerWidth);",
112 &width));
113 return width;
114 }
115
116 // This struct is used to track changes to subframes after a main frame zoom
117 // change, so that we can test subframe inner widths with assurance that all the
118 // changes have finished propagating.
119 struct FrameResizeObserver {
FrameResizeObservercontent::__anon9b4d21b90111::FrameResizeObserver120 FrameResizeObserver(RenderFrameHost* host,
121 std::string label,
122 double inner_width,
123 double tolerance)
124 : frame_host(host),
125 msg_label(std::move(label)),
126 zoomed_correctly(false),
127 expected_inner_width(inner_width),
128 tolerance(tolerance) {
129 SetupOnResizeCallback(host, msg_label);
130 }
131
SetupOnResizeCallbackcontent::__anon9b4d21b90111::FrameResizeObserver132 void SetupOnResizeCallback(const ToRenderFrameHost& adapter,
133 const std::string& label) {
134 const char kOnResizeCallbackSetup[] =
135 "document.body.onresize = function(){"
136 " window.domAutomationController.send('%s ' + window.innerWidth);"
137 "};";
138 EXPECT_TRUE(ExecuteScript(
139 adapter, base::StringPrintf(kOnResizeCallbackSetup, label.c_str())));
140 }
141
Checkcontent::__anon9b4d21b90111::FrameResizeObserver142 void Check(const std::string& status_msg) {
143 if (!base::StartsWith(status_msg, msg_label, base::CompareCase::SENSITIVE))
144 return;
145
146 double inner_width = std::stod(status_msg.substr(msg_label.length() + 1));
147 zoomed_correctly = std::abs(expected_inner_width - inner_width) < tolerance;
148 }
149
toThiscontent::__anon9b4d21b90111::FrameResizeObserver150 FrameResizeObserver* toThis() {return this;}
151
152 RenderFrameHost* frame_host;
153 std::string msg_label;
154 bool zoomed_correctly;
155 double expected_inner_width;
156 double tolerance;
157 };
158
159 // This struct is used to wait until a resize has occurred.
160 struct ResizeObserver {
ResizeObservercontent::__anon9b4d21b90111::ResizeObserver161 ResizeObserver(RenderFrameHost* host)
162 : frame_host(host) {
163 SetupOnResizeCallback(host);
164 }
165
SetupOnResizeCallbackcontent::__anon9b4d21b90111::ResizeObserver166 void SetupOnResizeCallback(const ToRenderFrameHost& adapter) {
167 const char kOnResizeCallbackSetup[] =
168 "document.body.onresize = function(){"
169 " window.domAutomationController.send('Resized');"
170 "};";
171 EXPECT_TRUE(ExecuteScript(
172 adapter, kOnResizeCallbackSetup));
173 }
174
IsResizeCallbackcontent::__anon9b4d21b90111::ResizeObserver175 bool IsResizeCallback(const std::string& status_msg) {
176 return status_msg == "Resized";
177 }
178
179 RenderFrameHost* frame_host;
180 };
181
WaitForResize(DOMMessageQueue & msg_queue,ResizeObserver & observer)182 void WaitForResize(DOMMessageQueue& msg_queue, ResizeObserver& observer) {
183 std::string status;
184 while (msg_queue.WaitForMessage(&status)) {
185 // Strip the double quotes from the message.
186 status = status.substr(1, status.length() -2);
187 if (observer.IsResizeCallback(status))
188 break;
189 }
190 }
191
WaitAndCheckFrameZoom(DOMMessageQueue & msg_queue,std::vector<FrameResizeObserver> & frame_observers)192 void WaitAndCheckFrameZoom(
193 DOMMessageQueue& msg_queue,
194 std::vector<FrameResizeObserver>& frame_observers) {
195 std::string status;
196 while (msg_queue.WaitForMessage(&status)) {
197 // Strip the double quotes from the message.
198 status = status.substr(1, status.length() -2);
199
200 bool all_zoomed_correctly = true;
201
202 // Use auto& to operate on a reference, and not a copy.
203 for (auto& observer : frame_observers) {
204 observer.Check(status);
205 all_zoomed_correctly = all_zoomed_correctly && observer.zoomed_correctly;
206 }
207
208 if (all_zoomed_correctly)
209 break;
210 }
211 }
212
213 } // namespace
214
IN_PROC_BROWSER_TEST_F(ZoomBrowserTest,ZoomPreservedOnReload)215 IN_PROC_BROWSER_TEST_F(ZoomBrowserTest, ZoomPreservedOnReload) {
216 std::string top_level_host("a.com");
217
218 GURL main_url(embedded_test_server()->GetURL(
219 top_level_host, "/cross_site_iframe_factory.html?a(b(a))"));
220 EXPECT_TRUE(NavigateToURL(shell(), main_url));
221 NavigationEntry* entry =
222 web_contents()->GetController().GetLastCommittedEntry();
223 ASSERT_TRUE(entry);
224 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
225 EXPECT_EQ(top_level_host, loaded_url.host());
226
227 FrameTreeNode* root =
228 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
229 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
230
231 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
232 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
233 EXPECT_EQ(0.0, default_zoom_level);
234
235 EXPECT_DOUBLE_EQ(
236 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
237
238 const double new_zoom_factor = 2.5;
239
240 // Set the new zoom, wait for the page to be resized, and sanity-check that
241 // the zoom was applied.
242 {
243 DOMMessageQueue msg_queue;
244 ResizeObserver observer(root->current_frame_host());
245
246 const double new_zoom_level =
247 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
248 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level);
249
250 WaitForResize(msg_queue, observer);
251 }
252
253 // Make this comparison approximate for Nexus5X test;
254 // https://crbug.com/622858.
255 EXPECT_NEAR(
256 new_zoom_factor,
257 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
258 0.01);
259
260 // Now the actual test: Reload the page and check that the main frame is
261 // still properly zoomed.
262 WindowedNotificationObserver load_stop_observer(
263 NOTIFICATION_LOAD_STOP,
264 NotificationService::AllSources());
265 shell()->Reload();
266 load_stop_observer.Wait();
267
268 EXPECT_NEAR(
269 new_zoom_factor,
270 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
271 0.01);
272 }
273
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,SubframesZoomProperly)274 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesZoomProperly) {
275 std::string top_level_host("a.com");
276 GURL main_url(embedded_test_server()->GetURL(
277 top_level_host, "/cross_site_iframe_factory.html?a(b(a))"));
278 EXPECT_TRUE(NavigateToURL(shell(), main_url));
279 NavigationEntry* entry =
280 web_contents()->GetController().GetLastCommittedEntry();
281 ASSERT_TRUE(entry);
282 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
283 EXPECT_EQ(top_level_host, loaded_url.host());
284
285 FrameTreeNode* root =
286 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
287 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
288 RenderFrameHostImpl* grandchild =
289 root->child_at(0)->child_at(0)->current_frame_host();
290
291 // The following calls must be made when the page's scale factor = 1.0.
292 double scale_one_child_width = GetSubframeWidth(child);
293 double scale_one_grandchild_width = GetSubframeWidth(grandchild);
294 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
295
296 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
297 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
298 EXPECT_EQ(0.0, default_zoom_level);
299
300 EXPECT_DOUBLE_EQ(
301 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
302
303 const double new_zoom_factor = 2.5;
304 {
305 DOMMessageQueue msg_queue;
306
307 std::vector<FrameResizeObserver> frame_observers;
308 frame_observers.emplace_back(child, "child",
309 scale_one_child_width, kTolerance);
310 frame_observers.emplace_back(grandchild, "grandchild",
311 scale_one_grandchild_width, kTolerance);
312
313 const double new_zoom_level =
314 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
315 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level);
316
317 WaitAndCheckFrameZoom(msg_queue, frame_observers);
318 }
319
320 // Make this comparison approximate for Nexus5X test;
321 // https://crbug.com/622858.
322 EXPECT_NEAR(
323 new_zoom_factor,
324 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
325 0.01);
326 }
327
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,SubframesDontZoomIndependently)328 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesDontZoomIndependently) {
329 std::string top_level_host("a.com");
330 GURL main_url(embedded_test_server()->GetURL(
331 top_level_host, "/cross_site_iframe_factory.html?a(b(a))"));
332 EXPECT_TRUE(NavigateToURL(shell(), main_url));
333 NavigationEntry* entry =
334 web_contents()->GetController().GetLastCommittedEntry();
335 ASSERT_TRUE(entry);
336 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
337 EXPECT_EQ(top_level_host, loaded_url.host());
338
339 FrameTreeNode* root =
340 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
341 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
342 RenderFrameHostImpl* grandchild =
343 root->child_at(0)->child_at(0)->current_frame_host();
344
345 // The following calls must be made when the page's scale factor = 1.0.
346 double scale_one_child_width = GetSubframeWidth(child);
347 double scale_one_grandchild_width = GetSubframeWidth(grandchild);
348 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
349
350 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
351 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
352 EXPECT_EQ(0.0, default_zoom_level);
353
354 EXPECT_DOUBLE_EQ(
355 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
356
357 const double new_zoom_factor = 2.0;
358 const double new_zoom_level =
359 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
360
361 // This should not cause the nested iframe to change its zoom.
362 host_zoom_map->SetZoomLevelForHost("b.com", new_zoom_level);
363
364 EXPECT_DOUBLE_EQ(
365 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
366 EXPECT_EQ(scale_one_child_width, GetSubframeWidth(child));
367 EXPECT_EQ(scale_one_grandchild_width, GetSubframeWidth(grandchild));
368
369 // When we navigate so that b.com is the top-level site, then it has the
370 // expected zoom.
371 GURL new_url = embedded_test_server()->GetURL("b.com", "/title1.html");
372 EXPECT_TRUE(NavigateToURL(shell(), new_url));
373 EXPECT_DOUBLE_EQ(
374 new_zoom_factor,
375 GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
376 }
377
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,AllFramesGetDefaultZoom)378 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, AllFramesGetDefaultZoom) {
379 std::string top_level_host("a.com");
380 GURL main_url(embedded_test_server()->GetURL(
381 top_level_host, "/cross_site_iframe_factory.html?a(b(a))"));
382 EXPECT_TRUE(NavigateToURL(shell(), main_url));
383 NavigationEntry* entry =
384 web_contents()->GetController().GetLastCommittedEntry();
385 ASSERT_TRUE(entry);
386 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
387 EXPECT_EQ(top_level_host, loaded_url.host());
388
389 FrameTreeNode* root =
390 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
391 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
392 RenderFrameHostImpl* grandchild =
393 root->child_at(0)->child_at(0)->current_frame_host();
394
395 // The following calls must be made when the page's scale factor = 1.0.
396 double scale_one_child_width = GetSubframeWidth(child);
397 double scale_one_grandchild_width = GetSubframeWidth(grandchild);
398 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
399
400 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
401 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
402 EXPECT_EQ(0.0, default_zoom_level);
403
404 EXPECT_DOUBLE_EQ(
405 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
406
407 const double new_default_zoom_factor = 2.0;
408 {
409 DOMMessageQueue msg_queue;
410
411 std::vector<FrameResizeObserver> frame_observers;
412 frame_observers.emplace_back(child, "child",
413 scale_one_child_width, kTolerance);
414 frame_observers.emplace_back(grandchild, "grandchild",
415 scale_one_grandchild_width, kTolerance);
416
417 const double new_default_zoom_level =
418 default_zoom_level +
419 blink::PageZoomFactorToZoomLevel(new_default_zoom_factor);
420
421 host_zoom_map->SetZoomLevelForHost("b.com", new_default_zoom_level + 1.0);
422 host_zoom_map->SetDefaultZoomLevel(new_default_zoom_level);
423
424 WaitAndCheckFrameZoom(msg_queue, frame_observers);
425 }
426 // Make this comparison approximate for Nexus5X test;
427 // https://crbug.com/622858.
428 EXPECT_NEAR(
429 new_default_zoom_factor,
430 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
431 0.01
432 );
433 }
434
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,SiblingFramesZoom)435 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SiblingFramesZoom) {
436 std::string top_level_host("a.com");
437 GURL main_url(embedded_test_server()->GetURL(
438 top_level_host, "/cross_site_iframe_factory.html?a(b,b)"));
439 EXPECT_TRUE(NavigateToURL(shell(), main_url));
440 NavigationEntry* entry =
441 web_contents()->GetController().GetLastCommittedEntry();
442 ASSERT_TRUE(entry);
443 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
444 EXPECT_EQ(top_level_host, loaded_url.host());
445
446 FrameTreeNode* root =
447 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
448 RenderFrameHostImpl* child1 = root->child_at(0)->current_frame_host();
449 RenderFrameHostImpl* child2 = root->child_at(1)->current_frame_host();
450
451 // The following calls must be made when the page's scale factor = 1.0.
452 double scale_one_child1_width = GetSubframeWidth(child1);
453 double scale_one_child2_width = GetSubframeWidth(child2);
454 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
455
456 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
457 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
458 EXPECT_EQ(0.0, default_zoom_level);
459
460 EXPECT_DOUBLE_EQ(
461 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
462
463 const double new_zoom_factor = 2.5;
464 {
465 DOMMessageQueue msg_queue;
466
467 std::vector<FrameResizeObserver> frame_observers;
468 frame_observers.emplace_back(child1, "child1",
469 scale_one_child1_width, kTolerance);
470 frame_observers.emplace_back(child2, "child2",
471 scale_one_child2_width, kTolerance);
472
473 const double new_zoom_level =
474 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
475 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level);
476
477 WaitAndCheckFrameZoom(msg_queue, frame_observers);
478 }
479
480 // Make this comparison approximate for Nexus5X test;
481 // https://crbug.com/622858.
482 EXPECT_NEAR(
483 new_zoom_factor,
484 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
485 0.01);
486 }
487
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,SubframeRetainsZoomOnNavigation)488 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframeRetainsZoomOnNavigation) {
489 std::string top_level_host("a.com");
490 GURL main_url(embedded_test_server()->GetURL(
491 top_level_host, "/cross_site_iframe_factory.html?a(b)"));
492 EXPECT_TRUE(NavigateToURL(shell(), main_url));
493 NavigationEntry* entry =
494 web_contents()->GetController().GetLastCommittedEntry();
495 ASSERT_TRUE(entry);
496 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
497 EXPECT_EQ(top_level_host, loaded_url.host());
498
499 FrameTreeNode* root =
500 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root();
501 RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
502
503 // The following calls must be made when the page's scale factor = 1.0.
504 double scale_one_child_width = GetSubframeWidth(child);
505 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
506
507 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
508 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
509 EXPECT_EQ(0.0, default_zoom_level);
510
511 EXPECT_DOUBLE_EQ(
512 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
513
514 const double new_zoom_factor = 0.5;
515 {
516 DOMMessageQueue msg_queue;
517
518 std::vector<FrameResizeObserver> frame_observers;
519 frame_observers.emplace_back(child, "child",
520 scale_one_child_width, kTolerance);
521
522 const double new_zoom_level =
523 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
524 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level);
525
526 WaitAndCheckFrameZoom(msg_queue, frame_observers);
527 }
528
529 // Make this comparison approximate for Nexus5X test;
530 // https://crbug.com/622858.
531 EXPECT_NEAR(
532 new_zoom_factor,
533 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
534 0.01
535 );
536
537 // Navigate child frame cross site, and make sure zoom is the same.
538 TestNavigationObserver observer(web_contents());
539 GURL url = embedded_test_server()->GetURL("c.com", "/title1.html");
540 NavigateFrameToURL(root->child_at(0), url);
541 EXPECT_TRUE(observer.last_navigation_succeeded());
542 EXPECT_EQ(url, observer.last_navigation_url());
543
544 // Check that the child frame maintained the same scale after navigating
545 // cross-site.
546 double new_child_width =
547 GetSubframeWidth(root->child_at(0)->current_frame_host());
548 EXPECT_EQ(scale_one_child_width, new_child_width);
549 }
550
551 // http://crbug.com/609213
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,RedirectToPageWithSubframeZoomsCorrectly)552 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,
553 RedirectToPageWithSubframeZoomsCorrectly) {
554 std::string initial_host("a.com");
555 std::string redirected_host("b.com");
556 EXPECT_TRUE(NavigateToURL(shell(), GURL(embedded_test_server()->GetURL(
557 initial_host, "/title2.html"))));
558 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
559 EXPECT_DOUBLE_EQ(
560 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
561
562 // Set a zoom level for b.com before we navigate to it.
563 const double kZoomFactorForRedirectedHost = 1.5;
564 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
565 host_zoom_map->SetZoomLevelForHost(
566 redirected_host,
567 blink::PageZoomFactorToZoomLevel(kZoomFactorForRedirectedHost));
568
569 // Navigation to a.com doesn't change the zoom level, but when it redirects
570 // to b.com, and then a subframe loads, the zoom should change.
571 GURL redirect_url(embedded_test_server()->GetURL(
572 redirected_host, "/cross_site_iframe_factory.html?b(b)"));
573 GURL url(embedded_test_server()->GetURL(
574 initial_host, "/client-redirect?" + redirect_url.spec()));
575
576 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 2);
577 EXPECT_TRUE(IsLastCommittedEntryOfPageType(web_contents(), PAGE_TYPE_NORMAL));
578 EXPECT_EQ(redirect_url, web_contents()->GetLastCommittedURL());
579
580 EXPECT_NEAR(kZoomFactorForRedirectedHost,
581 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
582 0.01);
583 }
584
585 // Tests that on cross-site navigation from a page that has a subframe, the
586 // appropriate zoom is applied to the new page.
587 // crbug.com/673065
IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,SubframesDontBreakConnectionToRenderer)588 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest,
589 SubframesDontBreakConnectionToRenderer) {
590 std::string top_level_host("a.com");
591 GURL main_url(embedded_test_server()->GetURL(
592 top_level_host, "/page_with_iframe_and_link.html"));
593 EXPECT_TRUE(NavigateToURL(shell(), main_url));
594 NavigationEntry* entry =
595 web_contents()->GetController().GetLastCommittedEntry();
596 ASSERT_TRUE(entry);
597 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry);
598 EXPECT_EQ(top_level_host, loaded_url.host());
599
600 // The following calls must be made when the page's scale factor = 1.0.
601 double main_frame_window_border = GetMainframeWindowBorder(web_contents());
602
603 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents());
604 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel();
605 EXPECT_EQ(0.0, default_zoom_level);
606 EXPECT_DOUBLE_EQ(
607 1.0, GetMainFrameZoomFactor(web_contents(), main_frame_window_border));
608
609 // Set a zoom for a host that will be navigated to below.
610 const double new_zoom_factor = 2.0;
611 const double new_zoom_level =
612 default_zoom_level + blink::PageZoomFactorToZoomLevel(new_zoom_factor);
613 host_zoom_map->SetZoomLevelForHost("foo.com", new_zoom_level);
614
615 // Navigate forward in the same RFH to a site with that host via a
616 // renderer-initiated navigation.
617 {
618 const char kReplacePortNumber[] =
619 "window.domAutomationController.send(setPortNumber(%d));";
620 uint16_t port_number = embedded_test_server()->port();
621 bool success = false;
622 EXPECT_TRUE(ExecuteScriptAndExtractBool(
623 shell(), base::StringPrintf(kReplacePortNumber, port_number),
624 &success));
625 TestNavigationObserver observer(shell()->web_contents());
626 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
627 success = false;
628 EXPECT_TRUE(ExecuteScriptAndExtractBool(
629 shell(), "window.domAutomationController.send(clickCrossSiteLink());",
630 &success));
631 EXPECT_TRUE(success);
632 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
633 EXPECT_EQ(url, observer.last_navigation_url());
634 EXPECT_TRUE(observer.last_navigation_succeeded());
635 }
636
637 // Check that the requested zoom has been applied to the new site.
638 // NOTE: Local observation on Linux has shown that this comparison has to be
639 // approximate. As the common failure mode would be that the zoom is ~1
640 // instead of ~2, this approximation shouldn't be problematic.
641 EXPECT_NEAR(
642 new_zoom_factor,
643 GetMainFrameZoomFactor(web_contents(), main_frame_window_border),
644 .1);
645 }
646
647 } // namespace content
648