|  | // Copyright 2014 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "components/zoom/zoom_controller.h" | 
|  |  | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "base/process/kill.h" | 
|  | #include "base/scoped_observation.h" | 
|  | #include "base/test/bind.h" | 
|  | #include "build/build_config.h" | 
|  | #include "chrome/app/chrome_command_ids.h" | 
|  | #include "chrome/browser/profiles/profile.h" | 
|  | #include "chrome/browser/ui/browser.h" | 
|  | #include "chrome/browser/ui/browser_commands.h" | 
|  | #include "chrome/browser/ui/tabs/tab_enums.h" | 
|  | #include "chrome/browser/ui/tabs/tab_strip_model.h" | 
|  | #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h" | 
|  | #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h" | 
|  | #include "chrome/common/url_constants.h" | 
|  | #include "chrome/test/base/in_process_browser_test.h" | 
|  | #include "chrome/test/base/ui_test_utils.h" | 
|  | #include "components/prefs/pref_service.h" | 
|  | #include "components/zoom/test/zoom_test_utils.h" | 
|  | #include "components/zoom/zoom_observer.h" | 
|  | #include "content/public/browser/disallow_activation_reason.h" | 
|  | #include "content/public/browser/host_zoom_map.h" | 
|  | #include "content/public/browser/navigation_entry.h" | 
|  | #include "content/public/browser/render_frame_host.h" | 
|  | #include "content/public/browser/render_process_host.h" | 
|  | #include "content/public/browser/render_widget_host_view.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/common/page_type.h" | 
|  | #include "content/public/test/browser_test.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  | #include "content/public/test/prerender_test_util.h" | 
|  | #include "net/dns/mock_host_resolver.h" | 
|  | #include "net/test/embedded_test_server/embedded_test_server.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  |  | 
|  | using zoom::ZoomChangedWatcher; | 
|  | using zoom::ZoomController; | 
|  | using zoom::ZoomObserver; | 
|  |  | 
|  | class ZoomControllerBrowserTest : public InProcessBrowserTest { | 
|  | public: | 
|  | ZoomControllerBrowserTest() = default; | 
|  | ~ZoomControllerBrowserTest() override = default; | 
|  |  | 
|  | void SetUpOnMainThread() override { | 
|  | InProcessBrowserTest::SetUpOnMainThread(); | 
|  | host_resolver()->AddRule("a.com", "127.0.0.1"); | 
|  | host_resolver()->AddRule("b.com", "127.0.0.1"); | 
|  | } | 
|  |  | 
|  | void TestResetOnNavigation(ZoomController::ZoomMode zoom_mode) { | 
|  | DCHECK(zoom_mode == ZoomController::ZOOM_MODE_ISOLATED || | 
|  | zoom_mode == ZoomController::ZOOM_MODE_MANUAL); | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  | ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( | 
|  | browser(), GURL("about:blank"), 1); | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  | double zoom_level = zoom_controller->GetDefaultZoomLevel(); | 
|  | zoom_controller->SetZoomMode(zoom_mode); | 
|  |  | 
|  | // When the navigation occurs, the zoom_mode will be reset to | 
|  | // ZOOM_MODE_DEFAULT, and this will be reflected in the event that | 
|  | // is generated. | 
|  | ZoomController::ZoomChangedEventData zoom_change_data( | 
|  | web_contents, web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId(), | 
|  | zoom_level, zoom_level, ZoomController::ZOOM_MODE_DEFAULT, false); | 
|  | ZoomChangedWatcher zoom_change_watcher(web_contents, zoom_change_data); | 
|  |  | 
|  | ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
|  | browser(), GURL(chrome::kChromeUISettingsURL))); | 
|  | zoom_change_watcher.Wait(); | 
|  | } | 
|  | };  // ZoomControllerBrowserTest | 
|  |  | 
|  | #if BUILDFLAG(IS_ANDROID) | 
|  | #define MAYBE_CrashedTabsDoNotChangeZoom DISABLED_CrashedTabsDoNotChangeZoom | 
|  | #else | 
|  | #define MAYBE_CrashedTabsDoNotChangeZoom CrashedTabsDoNotChangeZoom | 
|  | #endif | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, | 
|  | MAYBE_CrashedTabsDoNotChangeZoom) { | 
|  | // At the start of the test we are at a tab displaying about:blank. | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  |  | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  |  | 
|  | double old_zoom_level = zoom_controller->GetZoomLevel(); | 
|  | double new_zoom_level = old_zoom_level + 0.5; | 
|  |  | 
|  | content::RenderProcessHost* host = | 
|  | web_contents->GetPrimaryMainFrame()->GetProcess(); | 
|  | { | 
|  | content::RenderProcessHostWatcher crash_observer( | 
|  | host, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | 
|  | host->Shutdown(0); | 
|  | crash_observer.Wait(); | 
|  | } | 
|  | EXPECT_FALSE(web_contents->GetPrimaryMainFrame()->IsRenderFrameLive()); | 
|  |  | 
|  | // The following attempt to change the zoom level for a crashed tab should | 
|  | // fail. | 
|  | zoom_controller->SetZoomLevel(new_zoom_level); | 
|  | EXPECT_FLOAT_EQ(old_zoom_level, zoom_controller->GetZoomLevel()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, OnPreferenceChanged) { | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  | double new_default_zoom_level = 1.0; | 
|  | // Since this page uses the default zoom level, the changes to the default | 
|  | // zoom level will change the zoom level for this web_contents. | 
|  | ZoomController::ZoomChangedEventData zoom_change_data( | 
|  | web_contents, web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId(), | 
|  | new_default_zoom_level, new_default_zoom_level, | 
|  | ZoomController::ZOOM_MODE_DEFAULT, false); | 
|  | ZoomChangedWatcher zoom_change_watcher(web_contents, zoom_change_data); | 
|  | // TODO(wjmaclean): Convert this to call partition-specific zoom level prefs | 
|  | // when they become available. | 
|  | browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref( | 
|  | new_default_zoom_level); | 
|  | // Because this test relies on a round-trip IPC to/from the renderer process, | 
|  | // we need to wait for it to propagate. | 
|  | zoom_change_watcher.Wait(); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, ErrorPagesCanZoom) { | 
|  | ASSERT_TRUE( | 
|  | ui_test_utils::NavigateToURL(browser(), GURL("http://kjfhkjsdf.com"))); | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  |  | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  | EXPECT_EQ( | 
|  | content::PAGE_TYPE_ERROR, | 
|  | web_contents->GetController().GetLastCommittedEntry()->GetPageType()); | 
|  | EXPECT_EQ(GURL(content::kUnreachableWebDataURL), | 
|  | content::HostZoomMap::GetURLForWebContents(web_contents)); | 
|  |  | 
|  | double old_zoom_level = zoom_controller->GetZoomLevel(); | 
|  | double new_zoom_level = old_zoom_level + 0.5; | 
|  |  | 
|  | // The following attempt to change the zoom level for an error page should | 
|  | // fail. | 
|  | zoom_controller->SetZoomLevel(new_zoom_level); | 
|  | EXPECT_FLOAT_EQ(new_zoom_level, zoom_controller->GetZoomLevel()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, | 
|  | ErrorPagesCanZoomAfterTabRestore) { | 
|  | // This url is meant to cause a network error page to be loaded. | 
|  | // Tests can't reach the network, so this test should continue | 
|  | // to work even if the domain listed is someday registered. | 
|  | GURL url("http://kjfhkjsdf.com"); | 
|  |  | 
|  | TabStripModel* tab_strip = browser()->tab_strip_model(); | 
|  | ASSERT_TRUE(tab_strip); | 
|  |  | 
|  | ui_test_utils::NavigateToURLWithDisposition( | 
|  | browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, | 
|  | ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); | 
|  | { | 
|  | content::WebContents* web_contents = tab_strip->GetActiveWebContents(); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | content::PAGE_TYPE_ERROR, | 
|  | web_contents->GetController().GetLastCommittedEntry()->GetPageType()); | 
|  |  | 
|  | content::WebContentsDestroyedWatcher destroyed_watcher(web_contents); | 
|  | tab_strip->CloseWebContentsAt(tab_strip->active_index(), | 
|  | TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB); | 
|  | destroyed_watcher.Wait(); | 
|  | } | 
|  | EXPECT_EQ(1, tab_strip->count()); | 
|  |  | 
|  | content::WebContentsAddedObserver new_web_contents_observer; | 
|  | chrome::RestoreTab(browser()); | 
|  | content::WebContents* web_contents = | 
|  | new_web_contents_observer.GetWebContents(); | 
|  | content::WaitForLoadStop(web_contents); | 
|  |  | 
|  | EXPECT_EQ(2, tab_strip->count()); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | content::PAGE_TYPE_ERROR, | 
|  | web_contents->GetController().GetLastCommittedEntry()->GetPageType()); | 
|  |  | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  |  | 
|  | double old_zoom_level = zoom_controller->GetZoomLevel(); | 
|  | double new_zoom_level = old_zoom_level + 0.5; | 
|  |  | 
|  | // The following attempt to change the zoom level for an error page should | 
|  | // fail. | 
|  | zoom_controller->SetZoomLevel(new_zoom_level); | 
|  | EXPECT_FLOAT_EQ(new_zoom_level, zoom_controller->GetZoomLevel()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, Observe) { | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  |  | 
|  | double new_zoom_level = 1.0; | 
|  | // When the event is initiated from HostZoomMap, the old zoom level is not | 
|  | // available. | 
|  | ZoomController::ZoomChangedEventData zoom_change_data( | 
|  | web_contents, web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId(), | 
|  | new_zoom_level, new_zoom_level, ZoomController::ZOOM_MODE_DEFAULT, | 
|  | false);  // The ZoomController did not initiate, so this will be 'false'. | 
|  | ZoomChangedWatcher zoom_change_watcher(web_contents, zoom_change_data); | 
|  |  | 
|  | content::HostZoomMap* host_zoom_map = | 
|  | content::HostZoomMap::GetDefaultForBrowserContext( | 
|  | web_contents->GetBrowserContext()); | 
|  |  | 
|  | host_zoom_map->SetZoomLevelForHost("about:blank", new_zoom_level); | 
|  | zoom_change_watcher.Wait(); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, ObserveDisabledModeEvent) { | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  |  | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  |  | 
|  | double default_zoom_level = zoom_controller->GetDefaultZoomLevel(); | 
|  | double new_zoom_level = default_zoom_level + 1.0; | 
|  | zoom_controller->SetZoomLevel(new_zoom_level); | 
|  |  | 
|  | ZoomController::ZoomChangedEventData zoom_change_data( | 
|  | web_contents, web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId(), | 
|  | new_zoom_level, default_zoom_level, ZoomController::ZOOM_MODE_DISABLED, | 
|  | true); | 
|  | ZoomChangedWatcher zoom_change_watcher(web_contents, zoom_change_data); | 
|  | zoom_controller->SetZoomMode(ZoomController::ZOOM_MODE_DISABLED); | 
|  | zoom_change_watcher.Wait(); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, PerTabModeResetSendsEvent) { | 
|  | TestResetOnNavigation(ZoomController::ZOOM_MODE_ISOLATED); | 
|  | } | 
|  |  | 
|  | // Regression test: crbug.com/450909. | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, NavigationResetsManualMode) { | 
|  | TestResetOnNavigation(ZoomController::ZOOM_MODE_MANUAL); | 
|  | } | 
|  |  | 
|  | // Mac does not have touchscreen pinch. | 
|  | #if !BUILDFLAG(IS_MAC) | 
|  | // Ensure that when a history navigation restores the page scale factor from a | 
|  | // previous pinch zoom, the browser is notified of the page scale restoration. | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, | 
|  | RestoredPageScaleFromNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  |  | 
|  | const GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); | 
|  | const GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); | 
|  |  | 
|  | content::RenderFrameHostWrapper rfh_a( | 
|  | ui_test_utils::NavigateToURL(browser(), url_a)); | 
|  | ASSERT_TRUE(rfh_a); | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  | zoom::ZoomController* zoom_controller = | 
|  | zoom::ZoomController::FromWebContents(web_contents); | 
|  | EXPECT_TRUE(zoom_controller->PageScaleFactorIsOne()); | 
|  | EXPECT_FALSE(chrome::CanResetZoom(web_contents)); | 
|  | EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL)); | 
|  |  | 
|  | // Perform a pinch zoom to change the page scale factor. | 
|  | // The anchor is not important for this test, but we can't have it near the | 
|  | // edge of the contents, otherwise the simulated pinch's touch events wouldn't | 
|  | // be within the contents' bounds. | 
|  | const gfx::Rect contents_rect = web_contents->GetContainerBounds(); | 
|  | const gfx::PointF anchor(contents_rect.width() / 2, | 
|  | contents_rect.height() / 2); | 
|  | const float scale_change = 1.5; | 
|  | base::RunLoop run_loop; | 
|  | content::SimulateTouchscreenPinch(web_contents, anchor, scale_change, | 
|  | run_loop.QuitClosure()); | 
|  | run_loop.Run(); | 
|  |  | 
|  | // The page scale factor propagates from the compositor thread to the main | 
|  | // thread to the browser process, so we'll roundtrip before checking the page | 
|  | // scale from the browser side in order to avoid flakiness. | 
|  | base::RepeatingClosure synchronize_threads = | 
|  | base::BindLambdaForTesting([web_contents]() { | 
|  | content::MainThreadFrameObserver observer( | 
|  | web_contents->GetRenderWidgetHostView()->GetRenderWidgetHost()); | 
|  | observer.Wait(); | 
|  | }); | 
|  |  | 
|  | synchronize_threads.Run(); | 
|  | EXPECT_FALSE(zoom_controller->PageScaleFactorIsOne()); | 
|  | EXPECT_TRUE(chrome::CanResetZoom(web_contents)); | 
|  | EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL)); | 
|  |  | 
|  | // Navigate to a different page. | 
|  | ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_b)); | 
|  |  | 
|  | // If the previous page was bfcached, evict it, in order to test the | 
|  | // conditions that were the cause of https://crbug.com/1264958 (the page scale | 
|  | // needs to apply to a new RenderFrameHost). | 
|  | if (rfh_a) { | 
|  | ASSERT_TRUE(rfh_a->IsInactiveAndDisallowActivation( | 
|  | content::DisallowActivationReasonId::kForTesting)); | 
|  | } | 
|  | ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted()); | 
|  |  | 
|  | synchronize_threads.Run(); | 
|  | EXPECT_TRUE(zoom_controller->PageScaleFactorIsOne()); | 
|  | EXPECT_FALSE(chrome::CanResetZoom(web_contents)); | 
|  | EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL)); | 
|  |  | 
|  | // Navigate to the previous page which was pinch zoomed. The page scale will | 
|  | // be restored in the renderer and the browser should be made aware of this. | 
|  | ASSERT_TRUE(web_contents->GetController().CanGoBack()); | 
|  | web_contents->GetController().GoBack(); | 
|  | ASSERT_TRUE(content::WaitForLoadStop(web_contents)); | 
|  |  | 
|  | synchronize_threads.Run(); | 
|  | EXPECT_FALSE(zoom_controller->PageScaleFactorIsOne()); | 
|  | EXPECT_TRUE(chrome::CanResetZoom(web_contents)); | 
|  | EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ZOOM_NORMAL)); | 
|  | } | 
|  | #endif  // !BUILDFLAG(IS_MAC) | 
|  |  | 
|  | #if !BUILDFLAG(IS_CHROMEOS) | 
|  | // Regression test: crbug.com/438979. | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, | 
|  | SettingsZoomAfterSigninWorks) { | 
|  | GURL signin_url(std::string(chrome::kChromeUIChromeSigninURL) | 
|  | .append("?access_point=0&reason=5")); | 
|  | // We open the signin page in a new tab so that the ZoomController is | 
|  | // created against the HostZoomMap of the special StoragePartition that | 
|  | // backs the signin page. When we subsequently navigate away from the | 
|  | // signin page, the HostZoomMap changes, and we need to test that the | 
|  | // ZoomController correctly detects this. | 
|  | ui_test_utils::NavigateToURLWithDisposition( | 
|  | browser(), signin_url, WindowOpenDisposition::NEW_FOREGROUND_TAB, | 
|  | ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); | 
|  | login_ui_test_utils::WaitUntilUIReady(browser()); | 
|  | content::WebContents* web_contents = | 
|  | browser()->tab_strip_model()->GetActiveWebContents(); | 
|  | EXPECT_NE( | 
|  | content::PAGE_TYPE_ERROR, | 
|  | web_contents->GetController().GetLastCommittedEntry()->GetPageType()); | 
|  |  | 
|  | EXPECT_EQ(signin_url, web_contents->GetLastCommittedURL()); | 
|  | ZoomController* zoom_controller = | 
|  | ZoomController::FromWebContents(web_contents); | 
|  |  | 
|  | GURL settings_url(chrome::kChromeUISettingsURL); | 
|  | ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), settings_url)); | 
|  | EXPECT_NE( | 
|  | content::PAGE_TYPE_ERROR, | 
|  | web_contents->GetController().GetLastCommittedEntry()->GetPageType()); | 
|  |  | 
|  | // Verify new tab was created. | 
|  | EXPECT_EQ(2, browser()->tab_strip_model()->count()); | 
|  | // Verify that the settings page is using the same WebContents. | 
|  | EXPECT_EQ(web_contents, browser()->tab_strip_model()->GetActiveWebContents()); | 
|  | // TODO(wjmaclean): figure out why this next line fails, i.e. why does this | 
|  | // test not properly trigger a navigation to the settings page. | 
|  | EXPECT_EQ(settings_url, web_contents->GetLastCommittedURL()); | 
|  | EXPECT_EQ(zoom_controller, ZoomController::FromWebContents(web_contents)); | 
|  |  | 
|  | // If we zoom the new page, it should still generate a ZoomController event. | 
|  | double old_zoom_level = zoom_controller->GetZoomLevel(); | 
|  | double new_zoom_level = old_zoom_level + 0.5; | 
|  |  | 
|  | ZoomController::ZoomChangedEventData zoom_change_data( | 
|  | web_contents, web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId(), | 
|  | old_zoom_level, new_zoom_level, ZoomController::ZOOM_MODE_DEFAULT, | 
|  | true);  // We have a non-empty host, so this will be 'true'. | 
|  | ZoomChangedWatcher zoom_change_watcher(web_contents, zoom_change_data); | 
|  | zoom_controller->SetZoomLevel(new_zoom_level); | 
|  | zoom_change_watcher.Wait(); | 
|  | } | 
|  | #endif  // !BUILDFLAG(IS_CHROMEOS) | 
|  |  | 
|  | class ZoomControllerForPrerenderingTest : public ZoomControllerBrowserTest, | 
|  | public zoom::ZoomObserver { | 
|  | public: | 
|  | ZoomControllerForPrerenderingTest() | 
|  | : prerender_helper_(base::BindRepeating( | 
|  | &ZoomControllerForPrerenderingTest::GetWebContents, | 
|  | base::Unretained(this))) {} | 
|  | ~ZoomControllerForPrerenderingTest() override = default; | 
|  |  | 
|  | void SetUp() override { | 
|  | prerender_helper_.RegisterServerRequestMonitor(embedded_test_server()); | 
|  | ZoomControllerBrowserTest::SetUp(); | 
|  | } | 
|  |  | 
|  | void SetUpOnMainThread() override { | 
|  | host_resolver()->AddRule("*", "127.0.0.1"); | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  |  | 
|  | auto* zoom_controller = ZoomController::FromWebContents(GetWebContents()); | 
|  | zoom_observation_.Observe(zoom_controller); | 
|  | } | 
|  |  | 
|  | void TearDownOnMainThread() override { zoom_observation_.Reset(); } | 
|  |  | 
|  | content::test::PrerenderTestHelper& prerender_helper() { | 
|  | return prerender_helper_; | 
|  | } | 
|  |  | 
|  | content::WebContents* GetWebContents() { | 
|  | return browser()->tab_strip_model()->GetActiveWebContents(); | 
|  | } | 
|  |  | 
|  | // ZoomObserver implementation: | 
|  | void OnZoomControllerDestroyed( | 
|  | zoom::ZoomController* zoom_controller) override { | 
|  | zoom_observation_.Reset(); | 
|  | } | 
|  | void OnZoomChanged( | 
|  | const zoom::ZoomController::ZoomChangedEventData& data) override { | 
|  | is_on_zoom_changed_called_ = true; | 
|  | } | 
|  |  | 
|  | void reset_is_on_zoom_changed_called() { is_on_zoom_changed_called_ = false; } | 
|  | bool is_on_zoom_changed_called() { return is_on_zoom_changed_called_; } | 
|  |  | 
|  | private: | 
|  | bool is_on_zoom_changed_called_ = false; | 
|  |  | 
|  | content::test::PrerenderTestHelper prerender_helper_; | 
|  | base::ScopedObservation<zoom::ZoomController, zoom::ZoomObserver> | 
|  | zoom_observation_{this}; | 
|  | }; | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ZoomControllerForPrerenderingTest, | 
|  | DontFireZoomChangedListenerOnPrerender) { | 
|  | GURL initial_url = embedded_test_server()->GetURL("/empty.html"); | 
|  | GURL prerender_url = embedded_test_server()->GetURL("/title1.html"); | 
|  | ASSERT_NE(ui_test_utils::NavigateToURL(browser(), initial_url), nullptr); | 
|  |  | 
|  | // Reset |is_on_zoom_changed_called_| to check that it is not called during | 
|  | // the prerendering. | 
|  | reset_is_on_zoom_changed_called(); | 
|  |  | 
|  | content::FrameTreeNodeId host_id = | 
|  | prerender_helper().AddPrerender(prerender_url); | 
|  | content::test::PrerenderHostObserver host_observer(*GetWebContents(), | 
|  | host_id); | 
|  |  | 
|  | // Make sure that the prerender was not activated. | 
|  | EXPECT_FALSE(host_observer.was_activated()); | 
|  | // OnZoomChanged should not be called during the prerendering. | 
|  | EXPECT_FALSE(is_on_zoom_changed_called()); | 
|  |  | 
|  | // Navigate the primary page to the URL. | 
|  | prerender_helper().NavigatePrimaryPage(prerender_url); | 
|  |  | 
|  | // Make sure that the prerender was activated. | 
|  | EXPECT_TRUE(host_observer.was_activated()); | 
|  | // OnZoomChanged should be called after the prerendered page was activated. | 
|  | EXPECT_TRUE(is_on_zoom_changed_called()); | 
|  | } |