Chromium Code Reviews| 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/shell/browser/shell.h" | |
| 17 #include "content/test/content_browser_test_utils_internal.h" | |
| 18 #include "net/dns/mock_host_resolver.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "url/gurl.h" | |
| 21 | |
| 22 namespace content { | |
| 23 | |
| 24 class IFrameZoomBrowserTest : public ContentBrowserTest { | |
| 25 public: | |
| 26 IFrameZoomBrowserTest() {} | |
| 27 | |
| 28 protected: | |
| 29 void SetUpOnMainThread() override { | |
| 30 host_resolver()->AddRule("*", "127.0.0.1"); | |
| 31 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 32 SetupCrossSiteRedirector(embedded_test_server()); | |
| 33 } | |
| 34 | |
| 35 WebContentsImpl* web_contents() { | |
| 36 return static_cast<WebContentsImpl*>(shell()->web_contents()); | |
| 37 } | |
| 38 }; | |
| 39 | |
| 40 double GetMainframeWindowBorder(const ToRenderFrameHost& adapter) { | |
| 41 double border; | |
| 42 const char kGetMainframeBorder[] = "window.domAutomationController.send(" | |
| 43 "window.outerWidth - window.innerWidth" | |
| 44 ");"; | |
| 45 EXPECT_TRUE( | |
| 46 ExecuteScriptAndExtractDouble(adapter, kGetMainframeBorder, &border)); | |
| 47 return border; | |
| 48 } | |
| 49 | |
| 50 double GetMainframeZoomFactor(const ToRenderFrameHost& adapter, double border) { | |
| 51 const char kGetMainframeZoomLevel[] = | |
| 52 "window.domAutomationController.send(" | |
| 53 "(window.outerWidth - %f)/window.innerWidth" | |
| 54 ");"; | |
| 55 double zoom_factor; | |
| 56 EXPECT_TRUE(ExecuteScriptAndExtractDouble( | |
| 57 adapter, base::StringPrintf(kGetMainframeZoomLevel, border), | |
| 58 &zoom_factor)); | |
| 59 return zoom_factor; | |
| 60 } | |
| 61 | |
| 62 double GetSubframeWidth(const ToRenderFrameHost& adapter) { | |
| 63 double width; | |
| 64 EXPECT_TRUE(ExecuteScriptAndExtractDouble( | |
| 65 adapter, "window.domAutomationController.send(window.innerWidth);", | |
| 66 &width)); | |
| 67 return width; | |
| 68 } | |
| 69 | |
| 70 #define SETUP_A_B_A_NESTED_FRAMES() \ | |
| 71 std::string top_level_host("a.com"); \ | |
| 72 GURL main_url(embedded_test_server()->GetURL( \ | |
| 73 top_level_host, "/cross_site_iframe_factory.html?a(b(a))")); \ | |
| 74 EXPECT_TRUE(NavigateToURL(shell(), main_url)); \ | |
| 75 NavigationEntry* entry = \ | |
| 76 web_contents()->GetController().GetLastCommittedEntry(); \ | |
| 77 ASSERT_TRUE(entry); \ | |
| 78 GURL loaded_url = HostZoomMap::GetURLFromEntry(entry); \ | |
| 79 EXPECT_EQ(top_level_host, loaded_url.host()); \ | |
| 80 \ | |
| 81 FrameTreeNode* root = \ | |
| 82 static_cast<WebContentsImpl*>(web_contents())->GetFrameTree()->root(); \ | |
| 83 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.
| |
| 84 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
| |
| 85 \ | |
| 86 /* The following calls must be made when the page's scale factor = 1.0.*/ \ | |
| 87 double scale_one_subframe1_width = GetSubframeWidth(subframe1); \ | |
| 88 double scale_one_subframe2_width = GetSubframeWidth(subframe2); \ | |
| 89 double main_frame_window_border = GetMainframeWindowBorder(web_contents()); \ | |
| 90 \ | |
| 91 HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents()); \ | |
| 92 double default_zoom_level = host_zoom_map->GetDefaultZoomLevel(); \ | |
| 93 EXPECT_EQ(0.0, default_zoom_level); \ | |
| 94 \ | |
| 95 EXPECT_DOUBLE_EQ(1.0, GetMainframeZoomFactor(web_contents(), \ | |
| 96 main_frame_window_border)); | |
| 97 | |
| 98 struct FrameResizeObserver { | |
| 99 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.
| |
| 100 std::string label, | |
| 101 double inner_width, | |
| 102 double tol) | |
|
alexmos
2016/04/21 17:35:35
nit: s/tol/tolerance/
wjmaclean
2016/04/22 19:57:01
Done.
| |
| 103 : frame_adapter(adapter), | |
| 104 msg_label(std::move(label)), | |
| 105 resized(false), | |
| 106 expected_inner_width(inner_width), | |
| 107 tolerance(tol) { | |
| 108 SetupOnResizeCallback(adapter, msg_label); | |
| 109 } | |
| 110 | |
| 111 void SetupOnResizeCallback(const ToRenderFrameHost& adapter, | |
| 112 const std::string& label) { | |
| 113 const char kOnResizeCallbackSetup[] = | |
| 114 "document.body.onresize = function(){" | |
| 115 " window.domAutomationController.setAutomationId(0);" | |
| 116 " window.domAutomationController.send('%s ' + window.innerWidth);" | |
| 117 "};"; | |
| 118 EXPECT_TRUE(ExecuteScript( | |
| 119 adapter, base::StringPrintf(kOnResizeCallbackSetup, label.c_str()))); | |
| 120 } | |
| 121 | |
| 122 void Check(const std::string& status_msg) { | |
| 123 if (status_msg.find(msg_label) != 0) | |
| 124 return; | |
| 125 | |
| 126 double inner_width = std::stod(status_msg.substr(msg_label.length() + 1)); | |
| 127 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
| |
| 128 } | |
| 129 | |
| 130 FrameResizeObserver* toThis() {return this;} | |
| 131 | |
| 132 RenderFrameHost* frame_adapter; | |
| 133 std::string msg_label; | |
| 134 bool resized; | |
| 135 double expected_inner_width; | |
| 136 double tolerance; | |
| 137 }; | |
| 138 | |
| 139 void WaitAndCheckFrameResize( | |
| 140 DOMMessageQueue& msg_queue, | |
| 141 std::vector<FrameResizeObserver>& frame_observers) { | |
| 142 std::string status; | |
| 143 while (msg_queue.WaitForMessage(&status)) { | |
| 144 // Strip the double quotes from the message. | |
| 145 status = status.substr(1, status.length() -2); | |
| 146 | |
| 147 bool all_resized = true; | |
| 148 | |
| 149 // Use auto& to operate on a reference, and not a copy. | |
| 150 for (auto& observer : frame_observers) { | |
| 151 observer.Check(status); | |
| 152 all_resized = all_resized && observer.resized; | |
| 153 } | |
| 154 | |
| 155 if (all_resized) | |
| 156 break; | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesZoomProperly) { | |
| 161 SETUP_A_B_A_NESTED_FRAMES(); | |
| 162 | |
| 163 const double new_zoom_factor = 2.5; | |
| 164 { | |
| 165 DOMMessageQueue msg_queue; | |
| 166 | |
| 167 const double kTolerance = 0.1; | |
| 168 std::vector<FrameResizeObserver> frame_observers; | |
| 169 frame_observers.emplace_back(subframe1, "subframe1", | |
| 170 scale_one_subframe1_width, kTolerance); | |
| 171 frame_observers.emplace_back(subframe2, "subframe2", | |
| 172 scale_one_subframe2_width, kTolerance); | |
| 173 | |
| 174 const double new_zoom_level = | |
| 175 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
| 176 host_zoom_map->SetZoomLevelForHost(top_level_host, new_zoom_level); | |
| 177 | |
| 178 WaitAndCheckFrameResize(msg_queue, frame_observers); | |
| 179 } | |
| 180 | |
| 181 EXPECT_DOUBLE_EQ( | |
| 182 new_zoom_factor, | |
| 183 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
| 184 } | |
| 185 | |
| 186 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, SubframesDontZoomIndependently) { | |
| 187 SETUP_A_B_A_NESTED_FRAMES(); | |
| 188 | |
| 189 const double new_zoom_factor = 2.0; | |
| 190 const double new_zoom_level = | |
| 191 default_zoom_level + ZoomFactorToZoomLevel(new_zoom_factor); | |
| 192 | |
| 193 // This should not cause the nested iframe to change its zoom. | |
| 194 host_zoom_map->SetZoomLevelForHost("b.com", new_zoom_level); | |
| 195 | |
| 196 EXPECT_DOUBLE_EQ( | |
| 197 1.0, GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
| 198 EXPECT_EQ(scale_one_subframe1_width, GetSubframeWidth(subframe1)); | |
| 199 EXPECT_EQ(scale_one_subframe2_width, GetSubframeWidth(subframe2)); | |
| 200 | |
| 201 // When we navigate so that b.com is the top-level site, then it has the | |
| 202 // expected zoom. | |
| 203 EXPECT_TRUE(NavigateToURL( | |
| 204 shell(), embedded_test_server()->GetURL( | |
| 205 "b.com", "/cross_site_iframe_factory.html?b"))); | |
| 206 EXPECT_DOUBLE_EQ( | |
| 207 new_zoom_factor, | |
| 208 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
| 209 } | |
| 210 | |
| 211 IN_PROC_BROWSER_TEST_F(IFrameZoomBrowserTest, AllFramesGetDefaultZoom) { | |
| 212 SETUP_A_B_A_NESTED_FRAMES(); | |
| 213 | |
| 214 const double new_default_zoom_factor = 2.0; | |
| 215 { | |
| 216 DOMMessageQueue msg_queue; | |
| 217 | |
| 218 const double kTolerance = 0.1; | |
| 219 std::vector<FrameResizeObserver> frame_observers; | |
| 220 frame_observers.emplace_back(subframe1, "subframe1", | |
| 221 scale_one_subframe1_width, kTolerance); | |
| 222 frame_observers.emplace_back(subframe2, "subframe2", | |
| 223 scale_one_subframe2_width, kTolerance); | |
| 224 | |
| 225 const double new_default_zoom_level = | |
| 226 default_zoom_level + ZoomFactorToZoomLevel(new_default_zoom_factor); | |
| 227 | |
| 228 host_zoom_map->SetZoomLevelForHost("b.com", new_default_zoom_level + 1.0); | |
| 229 host_zoom_map->SetDefaultZoomLevel(new_default_zoom_level); | |
| 230 | |
| 231 WaitAndCheckFrameResize(msg_queue, frame_observers); | |
| 232 } | |
| 233 EXPECT_DOUBLE_EQ( | |
| 234 new_default_zoom_factor, | |
| 235 GetMainframeZoomFactor(web_contents(), main_frame_window_border)); | |
| 236 } | |
|
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
| |
| 237 | |
| 238 } // namespace content | |
| OLD | NEW |