Chromium Code Reviews| Index: content/browser/iframe_zoom_browsertest.cc |
| diff --git a/content/browser/iframe_zoom_browsertest.cc b/content/browser/iframe_zoom_browsertest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..aec2df88e7a39e366f7efa8ba7066b57130bf989 |
| --- /dev/null |
| +++ b/content/browser/iframe_zoom_browsertest.cc |
| @@ -0,0 +1,238 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <vector> |
| + |
| +#include "content/browser/frame_host/frame_tree_node.h" |
| +#include "content/browser/frame_host/render_frame_host_impl.h" |
| +#include "content/browser/web_contents/web_contents_impl.h" |
| +#include "content/public/browser/host_zoom_map.h" |
| +#include "content/public/browser/navigation_entry.h" |
| +#include "content/public/common/page_zoom.h" |
| +#include "content/public/test/browser_test_utils.h" |
| +#include "content/public/test/content_browser_test.h" |
| +#include "content/public/test/content_browser_test_utils.h" |
| +#include "content/shell/browser/shell.h" |
| +#include "content/test/content_browser_test_utils_internal.h" |
| +#include "net/dns/mock_host_resolver.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "url/gurl.h" |
| + |
| +namespace content { |
| + |
| +class IFrameZoomBrowserTest : public ContentBrowserTest { |
| + public: |
| + IFrameZoomBrowserTest() {} |
| + |
| + protected: |
| + void SetUpOnMainThread() override { |
| + host_resolver()->AddRule("*", "127.0.0.1"); |
| + ASSERT_TRUE(embedded_test_server()->Start()); |
| + SetupCrossSiteRedirector(embedded_test_server()); |
| + } |
| + |
| + WebContentsImpl* web_contents() { |
| + return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| + } |
| +}; |
| + |
| +double GetMainframeWindowBorder(const ToRenderFrameHost& adapter) { |
| + double border; |
| + const char kGetMainframeBorder[] = "window.domAutomationController.send(" |
| + "window.outerWidth - window.innerWidth" |
| + ");"; |
| + EXPECT_TRUE( |
| + ExecuteScriptAndExtractDouble(adapter, kGetMainframeBorder, &border)); |
| + return border; |
| +} |
| + |
| +double GetMainframeZoomFactor(const ToRenderFrameHost& adapter, double border) { |
| + const char kGetMainframeZoomLevel[] = |
| + "window.domAutomationController.send(" |
| + "(window.outerWidth - %f)/window.innerWidth" |
| + ");"; |
| + double zoom_factor; |
| + EXPECT_TRUE(ExecuteScriptAndExtractDouble( |
| + adapter, base::StringPrintf(kGetMainframeZoomLevel, border), |
| + &zoom_factor)); |
| + return zoom_factor; |
| +} |
| + |
| +double GetSubframeWidth(const ToRenderFrameHost& adapter) { |
| + double width; |
| + EXPECT_TRUE(ExecuteScriptAndExtractDouble( |
| + adapter, "window.domAutomationController.send(window.innerWidth);", |
| + &width)); |
| + return width; |
| +} |
| + |
| +#define SETUP_A_B_A_NESTED_FRAMES() \ |
| + std::string top_level_host("a.com"); \ |
| + GURL main_url(embedded_test_server()->GetURL( \ |
| + top_level_host, "/cross_site_iframe_factory.html?a(b(a))")); \ |
| + EXPECT_TRUE(NavigateToURL(shell(), main_url)); \ |
| + NavigationEntry* entry = \ |
| + web_contents()->GetController().GetLastCommittedEntry(); \ |
| + ASSERT_TRUE(entry); \ |
| + GURL loaded_url = HostZoomMap::GetURLFromEntry(entry); \ |
| + EXPECT_EQ(top_level_host, loaded_url.host()); \ |
| + \ |
| + FrameTreeNode* root = \ |
| + static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root(); \ |
| + auto subframe1 = root->child_at(0)->current_frame_host(); \ |
|
alexmos
2016/04/21 17:35:35
I'd spell out the RenderFrameHost* type for better
alexmos
2016/04/21 17:35:35
"child" and "grandchild" might be better names, si
wjmaclean
2016/04/22 19:57:01
Done & Done.
|
| + auto subframe2 = root->child_at(0)->child_at(0)->current_frame_host(); \ |
|
alexmos
2016/04/21 17:35:35
nit: subframe1->child_at(0)->current_frame_host()
wjmaclean
2016/04/22 19:57:01
subframe1 is a RenderFrameHostImpl*, so this doesn
alexmos
2016/04/25 22:43:27
Acknowledged. I'm too used to these kinds of thin
|
| + \ |
| + /* The following calls must be made when the page's scale factor = 1.0.*/ \ |
| + double scale_one_subframe1_width = GetSubframeWidth(subframe1); \ |
| + double scale_one_subframe2_width = GetSubframeWidth(subframe2); \ |
| + double main_frame_window_border = GetMainframeWindowBorder(web_contents()); \ |
| + \ |
| + HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents()); \ |
| + double default_zoom_level = host_zoom_map->GetDefaultZoomLevel(); \ |
| + EXPECT_EQ(0.0, default_zoom_level); \ |
| + \ |
| + EXPECT_DOUBLE_EQ(1.0, GetMainframeZoomFactor(web_contents(), \ |
| + main_frame_window_border)); |
| + |
| +struct FrameResizeObserver { |
| + FrameResizeObserver(RenderFrameHost* adapter, |
|
alexmos
2016/04/21 17:35:35
nit: rename adapter to host or frame or similar.
wjmaclean
2016/04/22 19:57:01
Done.
|
| + std::string label, |
| + double inner_width, |
| + double tol) |
|
alexmos
2016/04/21 17:35:35
nit: s/tol/tolerance/
wjmaclean
2016/04/22 19:57:01
Done.
|
| + : frame_adapter(adapter), |
| + msg_label(std::move(label)), |
| + resized(false), |
| + expected_inner_width(inner_width), |
| + tolerance(tol) { |
| + SetupOnResizeCallback(adapter, msg_label); |
| + } |
| + |
| + void SetupOnResizeCallback(const ToRenderFrameHost& adapter, |
| + const std::string& label) { |
| + const char kOnResizeCallbackSetup[] = |
| + "document.body.onresize = function(){" |
| + " window.domAutomationController.setAutomationId(0);" |
| + " window.domAutomationController.send('%s ' + window.innerWidth);" |
| + "};"; |
| + EXPECT_TRUE(ExecuteScript( |
| + adapter, base::StringPrintf(kOnResizeCallbackSetup, label.c_str()))); |
| + } |
| + |
| + void Check(const std::string& status_msg) { |
| + if (status_msg.find(msg_label) != 0) |
| + return; |
| + |
| + double inner_width = std::stod(status_msg.substr(msg_label.length() + 1)); |
| + resized = std::abs(expected_inner_width - inner_width) < tolerance; |
|
alexmos
2016/04/21 17:35:35
So this won't check whether the subframes zoomed t
wjmaclean
2016/04/21 17:59:35
I think you've got it backwards: this method allow
alexmos
2016/04/21 19:02:40
Ah, I see. Thanks for clarifying! (Let's explain
alexmos
2016/04/21 19:08:45
Also, maybe rename |resized| to |zoomed_correctly|
wjmaclean
2016/04/22 19:57:01
It *seems* like it always fires ... but I can't po
alexmos
2016/04/25 22:43:27
Acknowledged. It might be good to document the fa
|
| + } |
| + |
| + FrameResizeObserver* toThis() {return this;} |
| + |
| + RenderFrameHost* frame_adapter; |
| + std::string msg_label; |
| + bool resized; |
| + double expected_inner_width; |
| + double tolerance; |
| +}; |
| + |
| +void WaitAndCheckFrameResize( |
| + DOMMessageQueue& msg_queue, |
| + std::vector<FrameResizeObserver>& frame_observers) { |
| + std::string status; |
| + while (msg_queue.WaitForMessage(&status)) { |
| + // Strip the double quotes from the message. |
| + status = status.substr(1, status.length() -2); |
| + |
| + bool all_resized = true; |
| + |
| + // Use auto& to operate on a reference, and not a copy. |
| + for (auto& observer : frame_observers) { |
| + observer.Check(status); |
| + all_resized = all_resized && observer.resized; |
| + } |
| + |
| + if (all_resized) |
| + break; |
| + } |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesZoomProperly) { |
| + SETUP_A_B_A_NESTED_FRAMES(); |
| + |
| + const double new_zoom_factor = 2.5; |
| + { |
| + DOMMessageQueue msg_queue; |
| + |
| + const double kTolerance = 0.1; |
| + std::vector<FrameResizeObserver> frame_observers; |
| + frame_observers.emplace_back(subframe1, "subframe1", |
| + scale_one_subframe1_width, kTolerance); |
| + frame_observers.emplace_back(subframe2, "subframe2", |
| + scale_one_subframe2_width, kTolerance); |
| + |
| + const double new_zoom_level = |
| + default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); |
| + host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level); |
| + |
| + WaitAndCheckFrameResize(msg_queue, frame_observers); |
| + } |
| + |
| + EXPECT_DOUBLE_EQ( |
| + new_zoom_factor, |
| + GetMainframeZoomFactor(web_contents(), main_frame_window_border)); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesDontZoomIndependently) { |
| + SETUP_A_B_A_NESTED_FRAMES(); |
| + |
| + const double new_zoom_factor = 2.0; |
| + const double new_zoom_level = |
| + default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); |
| + |
| + // This should not cause the nested iframe to change its zoom. |
| + host_zoom_map->SetZoomLevelForHost("b.com", new_zoom_level); |
| + |
| + EXPECT_DOUBLE_EQ( |
| + 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); |
| + EXPECT_EQ(scale_one_subframe1_width, GetSubframeWidth(subframe1)); |
| + EXPECT_EQ(scale_one_subframe2_width, GetSubframeWidth(subframe2)); |
| + |
| + // When we navigate so that b.com is the top-level site, then it has the |
| + // expected zoom. |
| + EXPECT_TRUE(NavigateToURL( |
| + shell(), embedded_test_server()->GetURL( |
| + "b.com", "/cross_site_iframe_factory.html?b"))); |
| + EXPECT_DOUBLE_EQ( |
| + new_zoom_factor, |
| + GetMainframeZoomFactor(web_contents(), main_frame_window_border)); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, AllFramesGetDefaultZoom) { |
| + SETUP_A_B_A_NESTED_FRAMES(); |
| + |
| + const double new_default_zoom_factor = 2.0; |
| + { |
| + DOMMessageQueue msg_queue; |
| + |
| + const double kTolerance = 0.1; |
| + std::vector<FrameResizeObserver> frame_observers; |
| + frame_observers.emplace_back(subframe1, "subframe1", |
| + scale_one_subframe1_width, kTolerance); |
| + frame_observers.emplace_back(subframe2, "subframe2", |
| + scale_one_subframe2_width, kTolerance); |
| + |
| + const double new_default_zoom_level = |
| + default_zoom_level + ZoomFactorToZoomLevel(new_default_zoom_factor); |
| + |
| + host_zoom_map->SetZoomLevelForHost("b.com", new_default_zoom_level + 1.0); |
| + host_zoom_map->SetDefaultZoomLevel(new_default_zoom_level); |
| + |
| + WaitAndCheckFrameResize(msg_queue, frame_observers); |
| + } |
| + EXPECT_DOUBLE_EQ( |
| + new_default_zoom_factor, |
| + GetMainframeZoomFactor(web_contents(), main_frame_window_border)); |
| +} |
|
alexmos
2016/04/21 17:35:35
So far, these are are about A-B-A without subframe
wjmaclean
2016/04/21 17:59:35
I'm ok with adding some tests to test subframe nav
|
| + |
| +} // namespace content |