Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: content/browser/iframe_zoom_browsertest.cc

Issue 1804023002: Fix page zoom to be frame-centric for out-of-process frames. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add tests, address comments. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW
« no previous file with comments | « content/browser/host_zoom_map_impl_browsertest.cc ('k') | content/browser/renderer_host/render_view_host_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698