Commit d70bf37b authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

Touch MLP CL1: Enable mobile-like behavior of webpages in tablet mode

When in tablet mode on Chrome OS, webpages should have a
mobile-like behavior such as:
- Shrink viewport contents to fit the window size.
- Mobile viewport style.

This also exposes WebContents::NotifyPreferencesChanged() so
that it's possible to trigger an update of all RVHs associated
with a WebContents including OOPIFs

BUG=822455,828697
TEST=browser_tests --gtest_filter=TabletModePageBehaviorTest.*

Change-Id: Id80316fdb7c504a8a6f40ca9127c13ca58a9eee9
Reviewed-on: https://chromium-review.googlesource.com/978519
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548104}
parent f6904319
......@@ -278,6 +278,7 @@
#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h"
#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_backend_delegate.h"
#include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
#include "chrome/browser/chromeos/chrome_content_browser_client_chromeos_part.h"
#include "chrome/browser/chromeos/chrome_service_name.h"
#include "chrome/browser/chromeos/drive/fileapi/file_system_backend_delegate.h"
#include "chrome/browser/chromeos/file_manager/app_id.h"
......@@ -948,6 +949,10 @@ ChromeContentBrowserClient::ChromeContentBrowserClient()
TtsController::GetInstance()->SetTtsEngineDelegate(tts_extension_engine);
#endif
#if defined(OS_CHROMEOS)
extra_parts_.push_back(new ChromeContentBrowserClientChromeOsPart);
#endif // defined(OS_CHROMEOS)
#if BUILDFLAG(ENABLE_EXTENSIONS)
extra_parts_.push_back(new ChromeContentBrowserClientExtensionsPart);
#endif
......
......@@ -78,6 +78,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
// update our I/O thread cache of this value.
static void SetApplicationLocale(const std::string& locale);
// content::ContentBrowserClient:
content::BrowserMainParts* CreateBrowserMainParts(
const content::MainFunctionParams& parameters) override;
void PostAfterStartupTask(const base::Location& from_here,
......@@ -132,7 +133,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
bool ShouldStayInParentProcessForNTP(
const GURL& url,
content::SiteInstance* parent_site_instance) override;
bool IsSuitableHost(content::RenderProcessHost* process_host,
const GURL& site_url) override;
bool MayReuseHost(content::RenderProcessHost* process_host) override;
......@@ -220,7 +220,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
content::BrowserContext* context,
content::StoragePartition* partition,
storage::OptionalQuotaSettingsCallback callback) override;
void AllowCertificateError(
content::WebContents* web_contents,
int cert_error,
......@@ -298,7 +297,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
void OverridePageVisibilityState(
content::RenderFrameHost* render_frame_host,
blink::mojom::PageVisibilityState* visibility_state) override;
#if defined(OS_POSIX) && !defined(OS_MACOSX)
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
......@@ -358,13 +356,11 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
std::unique_ptr<content::MemoryCoordinatorDelegate>
GetMemoryCoordinatorDelegate() override;
::rappor::RapporService* GetRapporService() override;
#if BUILDFLAG(ENABLE_MEDIA_REMOTING)
void CreateMediaRemoter(content::RenderFrameHost* render_frame_host,
media::mojom::RemotingSourcePtr source,
media::mojom::RemoterRequest request) final;
#endif // BUILDFLAG(ENABLE_MEDIA_REMOTING)
std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams()
override;
base::FilePath GetLoggingFileName(
......@@ -391,7 +387,6 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
content::BrowserContext* context,
bool in_memory,
const base::FilePath& relative_partition_path) override;
bool AllowRenderingMhtmlOverHttp(
content::NavigationUIData* navigation_ui_data) override;
bool ShouldForceDownloadResource(const GURL& url,
......
......@@ -496,6 +496,8 @@ source_set("chromeos") {
"certificate_provider/thread_safe_certificate_map.h",
"chrome_browser_main_chromeos.cc",
"chrome_browser_main_chromeos.h",
"chrome_content_browser_client_chromeos_part.cc",
"chrome_content_browser_client_chromeos_part.h",
"chrome_service_name.cc",
"chrome_service_name.h",
"crostini/crostini_manager.cc",
......
// Copyright 2018 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 "chrome/browser/chromeos/chrome_content_browser_client_chromeos_part.h"
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
ChromeContentBrowserClientChromeOsPart ::
ChromeContentBrowserClientChromeOsPart() = default;
ChromeContentBrowserClientChromeOsPart ::
~ChromeContentBrowserClientChromeOsPart() = default;
void ChromeContentBrowserClientChromeOsPart::OverrideWebkitPrefs(
content::RenderViewHost* rvh,
content::WebPreferences* web_prefs) {
content::WebContents* contents =
content::WebContents::FromRenderViewHost(rvh);
if (!TabletModeClient::Get() ||
!TabletModeClient::Get()->tablet_mode_enabled() ||
!chrome::FindBrowserWithWebContents(contents)) {
return;
}
// Enable some mobile-like behaviors when in tablet mode on Chrome OS. Do
// this only for webcontents displayed in browsers.
web_prefs->viewport_enabled = true;
web_prefs->viewport_meta_enabled = true;
web_prefs->shrinks_viewport_contents_to_fit = true;
web_prefs->viewport_style = content::ViewportStyle::MOBILE;
web_prefs->main_frame_resizes_are_orientation_changes = true;
web_prefs->default_minimum_page_scale_factor = 0.25f;
web_prefs->default_maximum_page_scale_factor = 5.0;
}
// Copyright 2018 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.
#ifndef CHROME_BROWSER_CHROMEOS_CHROME_CONTENT_BROWSER_CLIENT_CHROMEOS_PART_H_
#define CHROME_BROWSER_CHROMEOS_CHROME_CONTENT_BROWSER_CLIENT_CHROMEOS_PART_H_
#include "base/macros.h"
#include "chrome/browser/chrome_content_browser_client_parts.h"
class ChromeContentBrowserClientChromeOsPart
: public ChromeContentBrowserClientParts {
public:
ChromeContentBrowserClientChromeOsPart();
~ChromeContentBrowserClientChromeOsPart() override;
// ChromeContentBrowserClientParts:
void OverrideWebkitPrefs(content::RenderViewHost* rvh,
content::WebPreferences* web_prefs) override;
private:
DISALLOW_COPY_AND_ASSIGN(ChromeContentBrowserClientChromeOsPart);
};
#endif // CHROME_BROWSER_CHROMEOS_CHROME_CONTENT_BROWSER_CLIENT_CHROMEOS_PART_H_
......@@ -8,6 +8,11 @@
#include "ash/public/interfaces/constants.mojom.h"
#include "chrome/browser/ui/ash/tablet_mode_client_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tab_strip_tracker.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/service_manager_connection.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -54,11 +59,33 @@ void TabletModeClient::RemoveObserver(TabletModeClientObserver* observer) {
}
void TabletModeClient::OnTabletModeToggled(bool enabled) {
if (tablet_mode_enabled_ == enabled)
return;
tablet_mode_enabled_ = enabled;
SetMobileLikeBehaviorEnabled(enabled);
for (auto& observer : observers_)
observer.OnTabletModeToggled(enabled);
}
bool TabletModeClient::ShouldTrackBrowser(Browser* browser) {
return tablet_mode_enabled_;
}
void TabletModeClient::TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) {
// We limit the mobile-like behavior to webcontents in tabstrips since many
// apps and extensions draw their own caption buttons and header frames. We
// don't want those to shrink down and resize to fit the width of their
// windows like webpages on mobile do. So this behavior is limited to webpages
// in tabs and packaged apps.
contents->NotifyPreferencesChanged();
}
void TabletModeClient::FlushForTesting() {
tablet_mode_controller_.FlushForTesting();
}
......@@ -68,3 +95,32 @@ void TabletModeClient::BindAndSetClient() {
binding_.Bind(mojo::MakeRequest(&client));
tablet_mode_controller_->SetClient(std::move(client));
}
void TabletModeClient::SetMobileLikeBehaviorEnabled(bool enabled) {
// Toggling tablet mode on/off should trigger refreshing the WebKit
// preferences, since in tablet mode, we enable certain mobile-like features
// such as "double tap to zoom", "shrink page contents to fit", ... etc.
// Do this only for webpages that belong to existing browsers as well as
// future browsers and webcontents.
if (enabled) {
// On calling Init() of the |tab_strip_tracker_|, we will get a call to
// TabInsertedAt() for all the existing webcontents, upon which we will
// trigger a refresh of their WebKit preferences.
tab_strip_tracker_ =
std::make_unique<BrowserTabStripTracker>(this, this, nullptr);
tab_strip_tracker_->Init();
} else {
// Manually trigger a refresh for the existing webcontents' preferences.
for (Browser* browser : *BrowserList::GetInstance()) {
TabStripModel* tab_strip_model = browser->tab_strip_model();
for (int i = 0; i < tab_strip_model->count(); ++i) {
content::WebContents* web_contents =
tab_strip_model->GetWebContentsAt(i);
DCHECK(web_contents);
web_contents->NotifyPreferencesChanged();
}
}
tab_strip_tracker_ = nullptr;
}
}
......@@ -5,17 +5,24 @@
#ifndef CHROME_BROWSER_UI_ASH_TABLET_MODE_CLIENT_H_
#define CHROME_BROWSER_UI_ASH_TABLET_MODE_CLIENT_H_
#include <memory>
#include "ash/public/interfaces/tablet_mode.mojom.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/browser_tab_strip_tracker_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "mojo/public/cpp/bindings/binding.h"
class BrowserTabStripTracker;
class TabletModeClientObserver;
// Holds tablet mode state in chrome. Observes ash for changes, then
// synchronously fires all its observers. This allows all tablet mode code in
// chrome to see a state change at the same time.
class TabletModeClient : public ash::mojom::TabletModeClient {
class TabletModeClient : public ash::mojom::TabletModeClient,
public BrowserTabStripTrackerDelegate,
public TabStripModelObserver {
public:
TabletModeClient();
~TabletModeClient() override;
......@@ -38,6 +45,15 @@ class TabletModeClient : public ash::mojom::TabletModeClient {
// ash::mojom::TabletModeClient:
void OnTabletModeToggled(bool enabled) override;
// BrowserTabStripTrackerDelegate:
bool ShouldTrackBrowser(Browser* browser) override;
// TabStripModelObserver:
void TabInsertedAt(TabStripModel* tab_strip_model,
content::WebContents* contents,
int index,
bool foreground) override;
// Flushes the mojo pipe to ash.
void FlushForTesting();
......@@ -45,8 +61,21 @@ class TabletModeClient : public ash::mojom::TabletModeClient {
// Binds this object to its mojo interface and sets it as the ash client.
void BindAndSetClient();
// Enables/disables mobile-like bahvior for webpages in existing browsers, as
// well as starts observing new browser pages if |enabled| is true.
void SetMobileLikeBehaviorEnabled(bool enabled);
bool tablet_mode_enabled_ = false;
// We only override the WebKit preferences of webcontents that belong to
// tabstrips in browsers. When a webcontents is newly created, its WebKit
// preferences are refreshed *before* it's added to any tabstrip, hence
// ChromeContentBrowserClientChromeOsPart::OverrideWebkitPrefs() wouldn't be
// able to override the mobile-like behavior prefs we want. Therefore, we need
// to observe webcontents being added to the tabstrips in order to trigger
// a refresh of its WebKit prefs.
std::unique_ptr<BrowserTabStripTracker> tab_strip_tracker_;
// Binds to the client interface in ash.
mojo::Binding<ash::mojom::TabletModeClient> binding_;
......
// Copyright 2018 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 "ash/public/cpp/ash_switches.h"
#include "base/command_line.h"
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "content/public/test/browser_test_utils.h"
namespace {
class TabletModePageBehaviorTest : public InProcessBrowserTest {
public:
TabletModePageBehaviorTest() = default;
~TabletModePageBehaviorTest() override = default;
// InProcessBrowserTest:
void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
command_line->AppendSwitch(ash::switches::kAshEnableTabletMode);
}
void ToggleTabletMode() {
auto* tablet_mode_client = TabletModeClient::Get();
tablet_mode_client->OnTabletModeToggled(
!tablet_mode_client->tablet_mode_enabled());
}
bool GetTabletModeEnabled() const {
return TabletModeClient::Get()->tablet_mode_enabled();
}
content::WebContents* GetActiveWebContents(Browser* browser) const {
return browser->tab_strip_model()->GetActiveWebContents();
}
content::WebPreferences GetWebKitPreferences(
const content::WebContents* web_contents) const {
return web_contents->GetRenderViewHost()->GetWebkitPreferences();
}
void ValidateWebPrefs(const content::WebPreferences& web_prefs,
bool tablet_mode_enabled) const {
if (tablet_mode_enabled) {
EXPECT_TRUE(web_prefs.viewport_enabled);
EXPECT_TRUE(web_prefs.viewport_meta_enabled);
EXPECT_TRUE(web_prefs.shrinks_viewport_contents_to_fit);
EXPECT_EQ(web_prefs.viewport_style, content::ViewportStyle::MOBILE);
EXPECT_TRUE(web_prefs.main_frame_resizes_are_orientation_changes);
EXPECT_FLOAT_EQ(web_prefs.default_minimum_page_scale_factor, 0.25f);
EXPECT_FLOAT_EQ(web_prefs.default_maximum_page_scale_factor, 5.0f);
} else {
EXPECT_FALSE(web_prefs.viewport_enabled);
EXPECT_FALSE(web_prefs.viewport_meta_enabled);
EXPECT_FALSE(web_prefs.shrinks_viewport_contents_to_fit);
EXPECT_NE(web_prefs.viewport_style, content::ViewportStyle::MOBILE);
EXPECT_FALSE(web_prefs.main_frame_resizes_are_orientation_changes);
EXPECT_FLOAT_EQ(web_prefs.default_minimum_page_scale_factor, 1.0f);
EXPECT_FLOAT_EQ(web_prefs.default_maximum_page_scale_factor, 4.0f);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(TabletModePageBehaviorTest);
};
IN_PROC_BROWSER_TEST_F(TabletModePageBehaviorTest,
TestWebKitPrefsWithTabletModeToggles) {
EXPECT_FALSE(GetTabletModeEnabled());
AddBlankTabAndShow(browser());
auto* web_contents = GetActiveWebContents(browser());
ASSERT_TRUE(web_contents);
// Validate that before tablet mode is enabled, mobile-behavior-related prefs
// are disabled.
ValidateWebPrefs(GetWebKitPreferences(web_contents),
false /* tablet_mode_enabled */);
// Now enable tablet mode, and expect that the same page's web prefs get
// updated.
ToggleTabletMode();
ASSERT_TRUE(GetTabletModeEnabled());
ValidateWebPrefs(GetWebKitPreferences(web_contents),
true /* tablet_mode_enabled */);
// Any newly added pages should have the correct tablet mode prefs.
Browser* browser_2 = CreateBrowser(browser()->profile());
auto* web_contents_2 = GetActiveWebContents(browser_2);
ASSERT_TRUE(web_contents_2);
ValidateWebPrefs(GetWebKitPreferences(web_contents_2),
true /* tablet_mode_enabled */);
// Disable tablet mode and expect both pages's prefs are updated.
ToggleTabletMode();
ASSERT_FALSE(GetTabletModeEnabled());
ValidateWebPrefs(GetWebKitPreferences(web_contents),
false /* tablet_mode_enabled */);
ValidateWebPrefs(GetWebKitPreferences(web_contents_2),
false /* tablet_mode_enabled */);
}
} // namespace
......@@ -1680,6 +1680,7 @@ test("browser_tests") {
"../browser/ui/ash/shelf_browsertest.cc",
"../browser/ui/ash/system_tray_client_browsertest.cc",
"../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc",
"../browser/ui/ash/tablet_mode_page_behavior_browsertest.cc",
"../browser/ui/ash/time_to_first_present_recorder_browsertest.cc",
"../browser/ui/ash/volume_controller_browsertest.cc",
"../browser/ui/sort_windows_by_z_index_browsertest.cc",
......
......@@ -1663,6 +1663,22 @@ void WebContentsImpl::DidChangeVisibleSecurityState() {
}
}
void WebContentsImpl::NotifyPreferencesChanged() {
std::set<RenderViewHost*> render_view_host_set;
for (FrameTreeNode* node : frame_tree_.Nodes()) {
RenderWidgetHost* render_widget_host =
node->current_frame_host()->GetRenderWidgetHost();
if (!render_widget_host)
continue;
RenderViewHost* render_view_host = RenderViewHost::From(render_widget_host);
if (!render_view_host)
continue;
render_view_host_set.insert(render_view_host);
}
for (RenderViewHost* render_view_host : render_view_host_set)
render_view_host->OnWebkitPreferencesChanged();
}
void WebContentsImpl::Stop() {
for (FrameTreeNode* node : frame_tree_.Nodes())
node->StopLoading();
......@@ -6234,22 +6250,6 @@ bool WebContentsImpl::IsShowingContextMenuOnPage() const {
return showing_context_menu_;
}
void WebContentsImpl::NotifyPreferencesChanged() {
std::set<RenderViewHost*> render_view_host_set;
for (FrameTreeNode* node : frame_tree_.Nodes()) {
RenderWidgetHost* render_widget_host =
node->current_frame_host()->GetRenderWidgetHost();
if (!render_widget_host)
continue;
RenderViewHost* render_view_host = RenderViewHost::From(render_widget_host);
if (!render_view_host)
continue;
render_view_host_set.insert(render_view_host);
}
for (RenderViewHost* render_view_host : render_view_host_set)
render_view_host->OnWebkitPreferencesChanged();
}
download::DownloadUrlParameters::RequestHeadersType
WebContentsImpl::ParseDownloadHeaders(const std::string& headers) {
download::DownloadUrlParameters::RequestHeadersType request_headers;
......
......@@ -367,6 +367,7 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
RenderFrameHost* outer_contents_frame) override;
WebContentsImpl* GetOuterWebContents() override;
void DidChangeVisibleSecurityState() override;
void NotifyPreferencesChanged() override;
void Stop() override;
void FreezePage() override;
......@@ -1325,10 +1326,6 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents,
// certificate via --allow-insecure-localhost.
void ShowInsecureLocalhostWarningIfNeeded();
// Notify this WebContents that the preferences have changed. This will send
// an IPC to all the renderer process associated with this WebContents.
void NotifyPreferencesChanged();
// Format of |headers| is a new line separated list of key value pairs:
// "<key1>: <value1>\r\n<key2>: <value2>".
static download::DownloadUrlParameters::RequestHeadersType
......
......@@ -480,6 +480,10 @@ class WebContents : public PageNavigator,
// Invoked when visible security state changes.
virtual void DidChangeVisibleSecurityState() = 0;
// Notify this WebContents that the preferences have changed. This will send
// an IPC to all the renderer processes associated with this WebContents.
virtual void NotifyPreferencesChanged() = 0;
// Commands ------------------------------------------------------------------
// Stop any pending navigation.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment