1 // Copyright 2014 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.
5 #include "components/ui/zoom/zoom_controller.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/process/kill.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_commands.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
14 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "components/signin/core/common/profile_management_switches.h"
19 #include "content/public/browser/host_zoom_map.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/page_type.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "testing/gmock/include/gmock/gmock.h"
28 using ui_zoom::ZoomController
;
29 using ui_zoom::ZoomObserver
;
31 bool operator==(const ZoomController::ZoomChangedEventData
& lhs
,
32 const ZoomController::ZoomChangedEventData
& rhs
) {
33 return lhs
.web_contents
== rhs
.web_contents
&&
34 lhs
.old_zoom_level
== rhs
.old_zoom_level
&&
35 lhs
.new_zoom_level
== rhs
.new_zoom_level
&&
36 lhs
.zoom_mode
== rhs
.zoom_mode
&&
37 lhs
.can_show_bubble
== rhs
.can_show_bubble
;
40 class ZoomChangedWatcher
: public ZoomObserver
{
43 content::WebContents
* web_contents
,
44 const ZoomController::ZoomChangedEventData
& expected_event_data
)
45 : web_contents_(web_contents
),
46 expected_event_data_(expected_event_data
),
47 message_loop_runner_(new content::MessageLoopRunner
) {
48 ZoomController::FromWebContents(web_contents
)->AddObserver(this);
50 ~ZoomChangedWatcher() override
{}
52 void Wait() { message_loop_runner_
->Run(); }
55 const ZoomController::ZoomChangedEventData
& event_data
) override
{
56 if (event_data
== expected_event_data_
)
57 message_loop_runner_
->Quit();
61 content::WebContents
* web_contents_
;
62 ZoomController::ZoomChangedEventData expected_event_data_
;
63 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
65 DISALLOW_COPY_AND_ASSIGN(ZoomChangedWatcher
);
68 class ZoomControllerBrowserTest
: public InProcessBrowserTest
{
70 ZoomControllerBrowserTest() {}
71 ~ZoomControllerBrowserTest() override
{}
73 void TestResetOnNavigation(ZoomController::ZoomMode zoom_mode
) {
74 DCHECK(zoom_mode
== ZoomController::ZOOM_MODE_ISOLATED
||
75 zoom_mode
== ZoomController::ZOOM_MODE_MANUAL
);
76 content::WebContents
* web_contents
=
77 browser()->tab_strip_model()->GetActiveWebContents();
78 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
79 browser(), GURL("about:blank"), 1);
80 ZoomController
* zoom_controller
=
81 ZoomController::FromWebContents(web_contents
);
82 double zoom_level
= zoom_controller
->GetDefaultZoomLevel();
83 zoom_controller
->SetZoomMode(zoom_mode
);
85 // When the navigation occurs, the zoom_mode will be reset to
86 // ZOOM_MODE_DEFAULT, and this will be reflected in the event that
88 ZoomController::ZoomChangedEventData
zoom_change_data(
89 web_contents
, zoom_level
, zoom_level
, ZoomController::ZOOM_MODE_DEFAULT
,
91 ZoomChangedWatcher
zoom_change_watcher(web_contents
, zoom_change_data
);
93 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUISettingsURL
));
94 zoom_change_watcher
.Wait();
96 }; // ZoomControllerBrowserTest
98 #if defined(OS_ANDROID)
99 #define MAYBE_CrashedTabsDoNotChangeZoom DISABLED_CrashedTabsDoNotChangeZoom
101 #define MAYBE_CrashedTabsDoNotChangeZoom CrashedTabsDoNotChangeZoom
103 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
,
104 MAYBE_CrashedTabsDoNotChangeZoom
) {
105 // At the start of the test we are at a tab displaying about:blank.
106 content::WebContents
* web_contents
=
107 browser()->tab_strip_model()->GetActiveWebContents();
109 ZoomController
* zoom_controller
=
110 ZoomController::FromWebContents(web_contents
);
112 double old_zoom_level
= zoom_controller
->GetZoomLevel();
113 double new_zoom_level
= old_zoom_level
+ 0.5;
115 content::RenderProcessHost
* host
= web_contents
->GetRenderProcessHost();
117 content::RenderProcessHostWatcher
crash_observer(
118 host
, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
119 host
->Shutdown(0, false);
120 crash_observer
.Wait();
122 EXPECT_FALSE(web_contents
->GetRenderViewHost()->IsRenderViewLive());
124 // The following attempt to change the zoom level for a crashed tab should
126 zoom_controller
->SetZoomLevel(new_zoom_level
);
127 EXPECT_FLOAT_EQ(old_zoom_level
, zoom_controller
->GetZoomLevel());
130 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, OnPreferenceChanged
) {
131 content::WebContents
* web_contents
=
132 browser()->tab_strip_model()->GetActiveWebContents();
133 double new_default_zoom_level
= 1.0;
134 // Since this page uses the default zoom level, the changes to the default
135 // zoom level will change the zoom level for this web_contents.
136 ZoomController::ZoomChangedEventData
zoom_change_data(
138 new_default_zoom_level
,
139 new_default_zoom_level
,
140 ZoomController::ZOOM_MODE_DEFAULT
,
142 ZoomChangedWatcher
zoom_change_watcher(web_contents
, zoom_change_data
);
143 // TODO(wjmaclean): Convert this to call partition-specific zoom level prefs
144 // when they become available.
145 browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(
146 new_default_zoom_level
);
147 // Because this test relies on a round-trip IPC to/from the renderer process,
148 // we need to wait for it to propagate.
149 zoom_change_watcher
.Wait();
152 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, ErrorPagesCanZoom
) {
153 ui_test_utils::NavigateToURL(browser(), GURL("http://kjfhkjsdf.com"));
154 content::WebContents
* web_contents
=
155 browser()->tab_strip_model()->GetActiveWebContents();
157 ZoomController
* zoom_controller
=
158 ZoomController::FromWebContents(web_contents
);
160 content::PAGE_TYPE_ERROR
,
161 web_contents
->GetController().GetLastCommittedEntry()->GetPageType());
163 double old_zoom_level
= zoom_controller
->GetZoomLevel();
164 double new_zoom_level
= old_zoom_level
+ 0.5;
166 // The following attempt to change the zoom level for an error page should
168 zoom_controller
->SetZoomLevel(new_zoom_level
);
169 EXPECT_FLOAT_EQ(new_zoom_level
, zoom_controller
->GetZoomLevel());
172 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
,
173 ErrorPagesCanZoomAfterTabRestore
) {
174 // This url is meant to cause a network error page to be loaded.
175 // Tests can't reach the network, so this test should continue
176 // to work even if the domain listed is someday registered.
177 GURL
url("http://kjfhkjsdf.com");
179 TabStripModel
* tab_strip
= browser()->tab_strip_model();
180 ASSERT_TRUE(tab_strip
);
182 ui_test_utils::NavigateToURLWithDisposition(
183 browser(), url
, NEW_FOREGROUND_TAB
,
184 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
186 content::WebContents
* web_contents
= tab_strip
->GetActiveWebContents();
189 content::PAGE_TYPE_ERROR
,
190 web_contents
->GetController().GetLastCommittedEntry()->GetPageType());
192 content::WebContentsDestroyedWatcher
destroyed_watcher(web_contents
);
193 tab_strip
->CloseWebContentsAt(tab_strip
->active_index(),
194 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
);
195 destroyed_watcher
.Wait();
197 EXPECT_EQ(1, tab_strip
->count());
199 content::WebContentsAddedObserver new_web_contents_observer
;
200 chrome::RestoreTab(browser());
201 content::WebContents
* web_contents
=
202 new_web_contents_observer
.GetWebContents();
203 content::WaitForLoadStop(web_contents
);
205 EXPECT_EQ(2, tab_strip
->count());
208 content::PAGE_TYPE_ERROR
,
209 web_contents
->GetController().GetLastCommittedEntry()->GetPageType());
211 ZoomController
* zoom_controller
=
212 ZoomController::FromWebContents(web_contents
);
214 double old_zoom_level
= zoom_controller
->GetZoomLevel();
215 double new_zoom_level
= old_zoom_level
+ 0.5;
217 // The following attempt to change the zoom level for an error page should
219 zoom_controller
->SetZoomLevel(new_zoom_level
);
220 EXPECT_FLOAT_EQ(new_zoom_level
, zoom_controller
->GetZoomLevel());
223 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, Observe
) {
224 content::WebContents
* web_contents
=
225 browser()->tab_strip_model()->GetActiveWebContents();
227 double new_zoom_level
= 1.0;
228 // When the event is initiated from HostZoomMap, the old zoom level is not
230 ZoomController::ZoomChangedEventData
zoom_change_data(
234 ZoomController::ZOOM_MODE_DEFAULT
,
235 false); // The ZoomController did not initiate, so this will be 'false'.
236 ZoomChangedWatcher
zoom_change_watcher(web_contents
, zoom_change_data
);
238 content::HostZoomMap
* host_zoom_map
=
239 content::HostZoomMap::GetDefaultForBrowserContext(
240 web_contents
->GetBrowserContext());
242 host_zoom_map
->SetZoomLevelForHost("about:blank", new_zoom_level
);
243 zoom_change_watcher
.Wait();
246 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, ObserveDisabledModeEvent
) {
247 content::WebContents
* web_contents
=
248 browser()->tab_strip_model()->GetActiveWebContents();
250 ZoomController
* zoom_controller
=
251 ZoomController::FromWebContents(web_contents
);
253 double default_zoom_level
= zoom_controller
->GetDefaultZoomLevel();
254 double new_zoom_level
= default_zoom_level
+ 1.0;
255 zoom_controller
->SetZoomLevel(new_zoom_level
);
257 ZoomController::ZoomChangedEventData
zoom_change_data(
261 ZoomController::ZOOM_MODE_DISABLED
,
263 ZoomChangedWatcher
zoom_change_watcher(web_contents
, zoom_change_data
);
264 zoom_controller
->SetZoomMode(ZoomController::ZOOM_MODE_DISABLED
);
265 zoom_change_watcher
.Wait();
268 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, PerTabModeResetSendsEvent
) {
269 TestResetOnNavigation(ZoomController::ZOOM_MODE_ISOLATED
);
272 // Regression test: crbug.com/450909.
273 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
, NavigationResetsManualMode
) {
274 TestResetOnNavigation(ZoomController::ZOOM_MODE_MANUAL
);
277 #if !defined(OS_CHROMEOS)
278 // Regression test: crbug.com/438979.
279 IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest
,
280 SettingsZoomAfterSigninWorks
) {
282 std::string(chrome::kChromeUIChromeSigninURL
).append("?source=0"));
283 // We open the signin page in a new tab so that the ZoomController is
284 // created against the HostZoomMap of the special StoragePartition that
285 // backs the signin page. When we subsequently navigate away from the
286 // signin page, the HostZoomMap changes, and we need to test that the
287 // ZoomController correctly detects this.
288 ui_test_utils::NavigateToURLWithDisposition(
289 browser(), signin_url
, NEW_FOREGROUND_TAB
,
290 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
291 login_ui_test_utils::WaitUntilUIReady(browser());
292 content::WebContents
* web_contents
=
293 browser()->tab_strip_model()->GetActiveWebContents();
295 content::PAGE_TYPE_ERROR
,
296 web_contents
->GetController().GetLastCommittedEntry()->GetPageType());
298 EXPECT_EQ(signin_url
, web_contents
->GetLastCommittedURL());
299 ZoomController
* zoom_controller
=
300 ZoomController::FromWebContents(web_contents
);
302 content::HostZoomMap
* host_zoom_map_signin
=
303 content::HostZoomMap::GetForWebContents(web_contents
);
305 GURL
settings_url(chrome::kChromeUISettingsURL
);
306 ui_test_utils::NavigateToURL(browser(), settings_url
);
308 content::PAGE_TYPE_ERROR
,
309 web_contents
->GetController().GetLastCommittedEntry()->GetPageType());
311 // Verify new tab was created.
312 EXPECT_EQ(2, browser()->tab_strip_model()->count());
313 // Verify that the settings page is using the same WebContents.
314 EXPECT_EQ(web_contents
, browser()->tab_strip_model()->GetActiveWebContents());
315 // TODO(wjmaclean): figure out why this next line fails, i.e. why does this
316 // test not properly trigger a navigation to the settings page.
317 EXPECT_EQ(settings_url
, web_contents
->GetLastCommittedURL());
318 EXPECT_EQ(zoom_controller
, ZoomController::FromWebContents(web_contents
));
320 // For the webview based sign-in code, the sign in page uses the default host
322 if (!switches::IsEnableWebviewBasedSignin()) {
323 // We expect the navigation from the chrome sign in page to the settings
324 // page to invoke a storage partition switch, and thus a different
325 // HostZoomMap for the web_contents.
326 content::HostZoomMap
* host_zoom_map_settings
=
327 content::HostZoomMap::GetForWebContents(web_contents
);
328 EXPECT_NE(host_zoom_map_signin
, host_zoom_map_settings
);
331 // If we zoom the new page, it should still generate a ZoomController event.
332 double old_zoom_level
= zoom_controller
->GetZoomLevel();
333 double new_zoom_level
= old_zoom_level
+ 0.5;
335 ZoomController::ZoomChangedEventData
zoom_change_data(
339 ZoomController::ZOOM_MODE_DEFAULT
,
340 true); // We have a non-empty host, so this will be 'true'.
341 ZoomChangedWatcher
zoom_change_watcher(web_contents
, zoom_change_data
);
342 zoom_controller
->SetZoomLevel(new_zoom_level
);
343 zoom_change_watcher
.Wait();
345 #endif // !defined(OS_CHROMEOS)