From 63c0e4cbb1865b493e6b049cf1316901e8042c65 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Mon, 30 Jan 2017 16:48:40 +0530 Subject: [PATCH] Add ZoomController to manager zoom changes for webcontents --- atom/browser/api/atom_api_web_contents.cc | 59 +++----- atom/browser/api/atom_api_web_contents.h | 14 +- atom/browser/api/atom_api_web_view_manager.cc | 7 + atom/browser/web_contents_zoom_controller.cc | 139 ++++++++++++++++++ atom/browser/web_contents_zoom_controller.h | 73 +++++++++ atom/browser/web_view_guest_delegate.cc | 13 ++ atom/browser/web_view_guest_delegate.h | 12 +- filenames.gypi | 2 + lib/browser/guest-view-manager.js | 2 +- lib/renderer/web-view/web-view.js | 1 - 10 files changed, 269 insertions(+), 53 deletions(-) create mode 100644 atom/browser/web_contents_zoom_controller.cc create mode 100644 atom/browser/web_contents_zoom_controller.h diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index fe73164d8b75..8e513923de2e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -22,6 +22,7 @@ #include "atom/browser/ui/drag_util.h" #include "atom/browser/web_contents_permission_helper.h" #include "atom/browser/web_contents_preferences.h" +#include "atom/browser/web_contents_zoom_controller.h" #include "atom/browser/web_view_guest_delegate.h" #include "atom/common/api/api_messages.h" #include "atom/common/api/event_emitter_caller.h" @@ -49,7 +50,6 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/view_messages.h" #include "content/public/browser/favicon_status.h" -#include "content/public/browser/host_zoom_map.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" @@ -68,7 +68,6 @@ #include "content/public/common/context_menu_params.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" -#include "net/base/url_util.h" #include "net/url_request/url_request_context.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" #include "third_party/WebKit/public/web/WebFindOptions.h" @@ -249,13 +248,12 @@ WebContents::WebContents(v8::Isolate* isolate, content::WebContents* web_contents, Type type) : content::WebContentsObserver(web_contents), + zoom_controller_(nullptr), embedder_(nullptr), type_(type), request_id_(0), background_throttling_(true), - enable_devtools_(true), - zoom_factor_(content::kMinimumZoomFactor) { - + enable_devtools_(true) { if (type == REMOTE) { web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); Init(isolate); @@ -268,17 +266,15 @@ WebContents::WebContents(v8::Isolate* isolate, } } -WebContents::WebContents(v8::Isolate* isolate, - const mate::Dictionary& options) - : embedder_(nullptr), +WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options) + : zoom_controller_(nullptr), + embedder_(nullptr), type_(BROWSER_WINDOW), request_id_(0), background_throttling_(true), - enable_devtools_(true), - zoom_factor_(content::kMinimumZoomFactor) { + enable_devtools_(true) { // Read options. options.Get("backgroundThrottling", &background_throttling_); - options.Get("zoomFactor", &zoom_factor_); // FIXME(zcbenz): We should read "type" parameter for better design, but // on Windows we have encountered a compiler bug that if we read "type" @@ -350,10 +346,16 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, // Save the preferences in C++. new WebContentsPreferences(web_contents, options); - // Intialize permission helper. + // Initialize permission helper. WebContentsPermissionHelper::CreateForWebContents(web_contents); - // Intialize security state client. + // Initialize security state client. SecurityStateTabHelper::CreateForWebContents(web_contents); + // Initialize zoom controller. + WebContentsZoomController::CreateForWebContents(web_contents); + zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents); + double zoom_factor; + if (options.Get("zoomFactor", &zoom_factor)) + zoom_controller_->SetDefaultZoomFactor(zoom_factor); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); @@ -738,8 +740,6 @@ void WebContents::DidFinishNavigation( auto url = navigation_handle->GetURL(); bool is_in_page = navigation_handle->IsSamePage(); if (is_main_frame && !is_in_page) { - // Set initial zoom factor if needed. - SetZoomFactorIfNeeded(url); Emit("did-navigate", url); } else if (is_in_page) { Emit("did-navigate-in-page", url, is_main_frame); @@ -1506,20 +1506,11 @@ void WebContents::Invalidate() { } void WebContents::SetZoomLevel(double level) { - auto factor = content::ZoomLevelToZoomFactor(level); - if (!content::ZoomValuesEqual(zoom_factor_, factor)) { - content::NavigationEntry* entry = - web_contents()->GetController().GetLastCommittedEntry(); - if (entry) { - std::string host = net::GetHostOrSpecFromURL(entry->GetURL()); - host_zoom_factor_[host] = factor; - } - } - content::HostZoomMap::SetZoomLevel(web_contents(), level); + zoom_controller_->SetZoomLevel(level); } double WebContents::GetZoomLevel() { - return content::HostZoomMap::GetZoomLevel(web_contents()); + return zoom_controller_->GetZoomLevel(); } void WebContents::SetZoomFactor(double factor) { @@ -1532,22 +1523,6 @@ double WebContents::GetZoomFactor() { return content::ZoomLevelToZoomFactor(level); } -void WebContents::SetZoomFactorIfNeeded(const GURL& url) { - if (zoom_factor_ == content::kMinimumZoomFactor) - return; - - std::string host = net::GetHostOrSpecFromURL(url); - double zoom_factor = zoom_factor_; - auto it = host_zoom_factor_.find(host); - if (it != host_zoom_factor_.end()) - zoom_factor = it->second; - auto level = content::ZoomFactorToZoomLevel(zoom_factor); - if (content::ZoomValuesEqual(level, GetZoomLevel())) - return; - - SetZoomLevel(level); -} - v8::Local WebContents::GetWebPreferences(v8::Isolate* isolate) { WebContentsPreferences* web_preferences = WebContentsPreferences::FromWebContents(web_contents()); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index be93c4c13103..c65560a63d9b 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -39,6 +39,7 @@ namespace atom { struct SetSizeParams; class AtomBrowserContext; +class WebContentsZoomController; class WebViewGuestDelegate; namespace api { @@ -206,6 +207,8 @@ class WebContents : public mate::TrackableObject, v8::Local DevToolsWebContents(v8::Isolate* isolate); v8::Local Debugger(v8::Isolate* isolate); + WebContentsZoomController* GetZoomController() { return zoom_controller_; } + protected: WebContents(v8::Isolate* isolate, content::WebContents* web_contents, @@ -349,20 +352,18 @@ class WebContents : public mate::TrackableObject, const base::ListValue& args, IPC::Message* message); - // Called after committing a navigation, to set the zoom - // factor. - void SetZoomFactorIfNeeded(const GURL& url); - v8::Global session_; v8::Global devtools_web_contents_; v8::Global debugger_; std::unique_ptr guest_delegate_; - std::map host_zoom_factor_; // The host webcontents that may contain this webcontents. WebContents* embedder_; + // The zoom controller for this webContents. + WebContentsZoomController* zoom_controller_; + // The type of current WebContents. Type type_; @@ -375,9 +376,6 @@ class WebContents : public mate::TrackableObject, // Whether to enable devtools. bool enable_devtools_; - // Initial zoom factor. - double zoom_factor_; - DISALLOW_COPY_AND_ASSIGN(WebContents); }; diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index 1586c3a10dde..33205b80c6e4 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "atom/browser/web_contents_preferences.h" +#include "atom/browser/web_contents_zoom_controller.h" #include "atom/browser/web_view_manager.h" #include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/native_mate_converters/value_converter.h" @@ -24,6 +25,12 @@ void AddGuest(int guest_instance_id, manager->AddGuest(guest_instance_id, element_instance_id, embedder, guest_web_contents); + double zoom_factor; + if (options.GetDouble("zoomFactor", &zoom_factor)) { + atom::WebContentsZoomController::FromWebContents(guest_web_contents) + ->SetDefaultZoomFactor(zoom_factor); + } + WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options); } diff --git a/atom/browser/web_contents_zoom_controller.cc b/atom/browser/web_contents_zoom_controller.cc new file mode 100644 index 000000000000..d0a8975eae9b --- /dev/null +++ b/atom/browser/web_contents_zoom_controller.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/web_contents_zoom_controller.h" + +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/page_type.h" +#include "content/public/common/page_zoom.h" +#include "net/base/url_util.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsZoomController); + +namespace atom { + +WebContentsZoomController::WebContentsZoomController( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) { + default_zoom_factor_ = content::kEpsilon; + host_zoom_map_ = content::HostZoomMap::GetForWebContents(web_contents); + zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(base::Bind( + &WebContentsZoomController::OnZoomLevelChanged, base::Unretained(this))); +} + +WebContentsZoomController::~WebContentsZoomController() {} + +void WebContentsZoomController::AddObserver( + WebContentsZoomController::Observer* observer) { + observers_.AddObserver(observer); +} + +void WebContentsZoomController::RemoveObserver( + WebContentsZoomController::Observer* observer) { + observers_.RemoveObserver(observer); +} + +void WebContentsZoomController::SetZoomLevel(double level) { + if (!web_contents()->GetRenderViewHost()->IsRenderViewLive() || + content::ZoomValuesEqual(GetZoomLevel(), level)) + return; + auto new_zoom_factor = content::ZoomLevelToZoomFactor(level); + content::NavigationEntry* entry = + web_contents()->GetController().GetLastCommittedEntry(); + if (entry) { + std::string host = net::GetHostOrSpecFromURL(entry->GetURL()); + // When new zoom level varies from kZoomFactor, it takes preference. + if (!content::ZoomValuesEqual(GetDefaultZoomFactor(), new_zoom_factor)) + host_zoom_factor_[host] = new_zoom_factor; + content::HostZoomMap::SetZoomLevel(web_contents(), level); + // Notify observers of zoom level changes. + FOR_EACH_OBSERVER(WebContentsZoomController::Observer, observers_, + OnZoomLevelChanged(web_contents(), level)); + } +} + +double WebContentsZoomController::GetZoomLevel() { + return content::HostZoomMap::GetZoomLevel(web_contents()); +} + +void WebContentsZoomController::SetDefaultZoomFactor(double factor) { + default_zoom_factor_ = factor; +} + +double WebContentsZoomController::GetDefaultZoomFactor() { + return default_zoom_factor_; +} + +void WebContentsZoomController::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted()) + return; + + if (navigation_handle->IsErrorPage()) { + content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents()); + return; + } + + if (!navigation_handle->IsSamePage()) + SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL()); +} + +void WebContentsZoomController::WebContentsDestroyed() { + observers_.Clear(); + host_zoom_factor_.clear(); +} + +void WebContentsZoomController::RenderFrameHostChanged( + content::RenderFrameHost* old_host, + content::RenderFrameHost* new_host) { + // If our associated HostZoomMap changes, update our event subscription. + content::HostZoomMap* new_host_zoom_map = + content::HostZoomMap::GetForWebContents(web_contents()); + if (new_host_zoom_map == host_zoom_map_) + return; + + host_zoom_map_ = new_host_zoom_map; + zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(base::Bind( + &WebContentsZoomController::OnZoomLevelChanged, base::Unretained(this))); +} + +void WebContentsZoomController::SetZoomFactorOnNavigationIfNeeded( + const GURL& url) { + if (content::ZoomValuesEqual(GetDefaultZoomFactor(), content::kEpsilon)) + return; + + // When kZoomFactor is available, it takes precedence over + // pref store values but if the host has zoom factor set explicitly + // then it takes precendence. + // pref store < kZoomFactor < setZoomLevel + std::string host = net::GetHostOrSpecFromURL(url); + double zoom_factor = GetDefaultZoomFactor(); + auto it = host_zoom_factor_.find(host); + if (it != host_zoom_factor_.end()) + zoom_factor = it->second; + auto level = content::ZoomFactorToZoomLevel(zoom_factor); + if (content::ZoomValuesEqual(level, GetZoomLevel())) + return; + + SetZoomLevel(level); +} + +void WebContentsZoomController::OnZoomLevelChanged( + const content::HostZoomMap::ZoomLevelChange& change) { + if (change.mode == content::HostZoomMap::ZOOM_CHANGED_FOR_HOST) { + auto it = host_zoom_factor_.find(change.host); + if (it == host_zoom_factor_.end()) + return; + host_zoom_factor_.insert( + it, std::make_pair(change.host, + content::ZoomLevelToZoomFactor(change.zoom_level))); + } +} + +} // namespace atom diff --git a/atom/browser/web_contents_zoom_controller.h b/atom/browser/web_contents_zoom_controller.h new file mode 100644 index 000000000000..d109ccd8d8e5 --- /dev/null +++ b/atom/browser/web_contents_zoom_controller.h @@ -0,0 +1,73 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_WEB_CONTENTS_ZOOM_CONTROLLER_H_ +#define ATOM_BROWSER_WEB_CONTENTS_ZOOM_CONTROLLER_H_ + +#include "content/public/browser/host_zoom_map.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace atom { + +// Manages the zoom changes of WebContents. +class WebContentsZoomController + : public content::WebContentsObserver, + public content::WebContentsUserData { + public: + class Observer { + public: + virtual void OnZoomLevelChanged(content::WebContents* web_contents, + double level) {} + + protected: + virtual ~Observer() {} + }; + + explicit WebContentsZoomController(content::WebContents* web_contents); + ~WebContentsZoomController() override; + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Methods for managing zoom levels. + void SetZoomLevel(double level); + double GetZoomLevel(); + void SetDefaultZoomFactor(double factor); + double GetDefaultZoomFactor(); + + protected: + // content::WebContentsObserver: + void DidFinishNavigation(content::NavigationHandle* handle) override; + void WebContentsDestroyed() override; + void RenderFrameHostChanged(content::RenderFrameHost* old_host, + content::RenderFrameHost* new_host) override; + + private: + friend class content::WebContentsUserData; + + // Called after a navigation has committed to set default zoom factor. + void SetZoomFactorOnNavigationIfNeeded(const GURL& url); + + // Track zoom changes of a host in other instances of a partition. + void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change); + + // kZoomFactor. + double default_zoom_factor_; + + // Map between zoom factor and hosts in this webContent. + std::map host_zoom_factor_; + + base::ObserverList observers_; + + content::HostZoomMap* host_zoom_map_; + + std::unique_ptr zoom_subscription_; + + DISALLOW_COPY_AND_ASSIGN(WebContentsZoomController); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_WEB_CONTENTS_ZOOM_CONTROLLER_H_ diff --git a/atom/browser/web_view_guest_delegate.cc b/atom/browser/web_view_guest_delegate.cc index cfb326496355..85b034d02a3f 100644 --- a/atom/browser/web_view_guest_delegate.cc +++ b/atom/browser/web_view_guest_delegate.cc @@ -39,7 +39,9 @@ void WebViewGuestDelegate::Initialize(api::WebContents* api_web_contents) { void WebViewGuestDelegate::Destroy() { // Give the content module an opportunity to perform some cleanup. + embedder_zoom_controller_->RemoveObserver(this); guest_host_->WillDestroy(); + embedder_zoom_controller_ = nullptr; guest_host_ = nullptr; } @@ -107,6 +109,9 @@ void WebViewGuestDelegate::DidFinishNavigation( void WebViewGuestDelegate::DidAttach(int guest_proxy_routing_id) { api_web_contents_->Emit("did-attach"); + embedder_zoom_controller_ = + WebContentsZoomController::FromWebContents(embedder_web_contents_); + embedder_zoom_controller_->AddObserver(this); } content::WebContents* WebViewGuestDelegate::GetOwnerWebContents() const { @@ -134,6 +139,14 @@ void WebViewGuestDelegate::WillAttach( completion_callback.Run(); } +void WebViewGuestDelegate::OnZoomLevelChanged( + content::WebContents* web_contents, + double level) { + if (web_contents == GetOwnerWebContents()) { + api_web_contents_->GetZoomController()->SetZoomLevel(level); + } +} + void WebViewGuestDelegate::GuestSizeChangedDueToAutoSize( const gfx::Size& old_size, const gfx::Size& new_size) { api_web_contents_->Emit("size-changed", diff --git a/atom/browser/web_view_guest_delegate.h b/atom/browser/web_view_guest_delegate.h index eade31234c2c..4fc000fb06cb 100644 --- a/atom/browser/web_view_guest_delegate.h +++ b/atom/browser/web_view_guest_delegate.h @@ -5,6 +5,7 @@ #ifndef ATOM_BROWSER_WEB_VIEW_GUEST_DELEGATE_H_ #define ATOM_BROWSER_WEB_VIEW_GUEST_DELEGATE_H_ +#include "atom/browser/web_contents_zoom_controller.h" #include "content/public/browser/browser_plugin_guest_delegate.h" #include "content/public/browser/web_contents_observer.h" @@ -31,7 +32,8 @@ struct SetSizeParams { }; class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, - public content::WebContentsObserver { + public content::WebContentsObserver, + public WebContentsZoomController::Observer { public: WebViewGuestDelegate(); ~WebViewGuestDelegate() override; @@ -63,6 +65,10 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, content::RenderWidgetHost* GetOwnerRenderWidgetHost() override; content::SiteInstance* GetOwnerSiteInstance() override; + // WebContentsZoomController::Observer: + void OnZoomLevelChanged(content::WebContents* web_contents, + double level) override; + private: // This method is invoked when the contents auto-resized to give the container // an opportunity to match it if it wishes. @@ -78,6 +84,10 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, // The WebContents that attaches this guest view. content::WebContents* embedder_web_contents_; + // The zoom controller of the embedder that is used + // to subscribe for zoom changes. + WebContentsZoomController* embedder_zoom_controller_; + // The size of the container element. gfx::Size element_size_; diff --git a/filenames.gypi b/filenames.gypi index 5b16beaa91a1..d3dc7ed22cef 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -341,6 +341,8 @@ 'atom/browser/web_contents_permission_helper.h', 'atom/browser/web_contents_preferences.cc', 'atom/browser/web_contents_preferences.h', + 'atom/browser/web_contents_zoom_controller.cc', + 'atom/browser/web_contents_zoom_controller.h', 'atom/browser/web_dialog_helper.cc', 'atom/browser/web_dialog_helper.h', 'atom/browser/web_view_guest_delegate.cc', diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index f1a460271b45..e61b2574ad32 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -184,7 +184,7 @@ const attachGuest = function (event, elementInstanceId, guestInstanceId, params) guestInstanceId: guestInstanceId, nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false, plugins: params.plugins, - zoomFactor: params.zoomFactor, + zoomFactor: embedder.getZoomFactor(), webSecurity: !params.disablewebsecurity, blinkFeatures: params.blinkfeatures, disableBlinkFeatures: params.disableblinkfeatures diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index ba8ae32d46d5..9800bf994936 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -231,7 +231,6 @@ class WebViewImpl { const params = { instanceId: this.viewInstanceId, userAgentOverride: this.userAgentOverride, - zoomFactor: webFrame.getZoomFactor() } for (const attributeName in this.attributes) { if (hasProp.call(this.attributes, attributeName)) {