| Index: components/zoom/zoom_controller.cc
|
| diff --git a/components/zoom/zoom_controller.cc b/components/zoom/zoom_controller.cc
|
| index 8d258a5d7adb3ddaf7c36df2848d1be6af680252..dd0231226f9bf9a0488b38421ed6aacd17f47cd8 100644
|
| --- a/components/zoom/zoom_controller.cc
|
| +++ b/components/zoom/zoom_controller.cc
|
| @@ -6,12 +6,15 @@
|
|
|
| #include "components/zoom/zoom_event_manager.h"
|
| #include "components/zoom/zoom_observer.h"
|
| +#include "content/public/browser/browser_context.h"
|
| #include "content/public/browser/host_zoom_map.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_frame_host.h"
|
| #include "content/public/browser/render_process_host.h"
|
| #include "content/public/browser/render_view_host.h"
|
| +#include "content/public/browser/storage_partition.h"
|
| #include "content/public/browser/web_contents.h"
|
| #include "content/public/common/page_type.h"
|
| #include "content/public/common/page_zoom.h"
|
| @@ -36,12 +39,43 @@ double ZoomController::GetZoomLevelForWebContents(
|
| ZoomController::ZoomController(content::WebContents* web_contents)
|
| : content::WebContentsObserver(web_contents),
|
| can_show_bubble_(true),
|
| - zoom_mode_(ZOOM_MODE_DEFAULT),
|
| + default_scope_is_per_origin_(ZoomPrefsDelegate::kZoomScopeSettingDefault),
|
| zoom_level_(1.0),
|
| browser_context_(web_contents->GetBrowserContext()) {
|
| host_zoom_map_ = content::HostZoomMap::GetForWebContents(web_contents);
|
| zoom_level_ = host_zoom_map_->GetDefaultZoomLevel();
|
|
|
| + ZoomPrefsDelegate* zoom_prefs_delegate = static_cast<ZoomPrefsDelegate*>(
|
| + content::BrowserContext::GetStoragePartition(
|
| + browser_context_, web_contents->GetSiteInstance())
|
| + ->GetZoomLevelDelegate());
|
| + if (zoom_prefs_delegate) {
|
| + default_scope_is_per_origin_ =
|
| + zoom_prefs_delegate->GetZoomScopeIsPerOriginPref();
|
| + // TODO(mcnee) If the need to navigate between StoragePartitions is
|
| + // introduced by a new feature, we will need to add logic to update this
|
| + // subscription.
|
| + default_zoom_scope_subscription_ =
|
| + zoom_prefs_delegate->RegisterDefaultZoomScopeCallback(
|
| + base::Bind(&ZoomController::OnDefaultZoomScopeChanged,
|
| + base::Unretained(this)));
|
| + }
|
| + zoom_mode_ =
|
| + default_scope_is_per_origin_ ? ZOOM_MODE_DEFAULT : ZOOM_MODE_ISOLATED;
|
| +
|
| + // When in isolated zoom, a temporary zoom level needs to be set to override
|
| + // any existing per-host zoom levels.
|
| + // If this WebContents is a clone of another, don't overwrite the temporary
|
| + // level we've inherited.
|
| + int render_process_id = web_contents->GetRenderProcessHost()->GetID();
|
| + int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
|
| + if (zoom_mode_ == ZOOM_MODE_ISOLATED &&
|
| + !host_zoom_map_->UsesTemporaryZoomLevel(render_process_id,
|
| + render_view_id)) {
|
| + host_zoom_map_->SetTemporaryZoomLevel(render_process_id, render_view_id,
|
| + zoom_level_);
|
| + }
|
| +
|
| zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(
|
| base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this)));
|
|
|
| @@ -180,7 +214,8 @@ void ZoomController::SetZoomMode(ZoomMode new_mode) {
|
| DCHECK(!event_data_);
|
| event_data_.reset(new ZoomChangedEventData(
|
| web_contents(), original_zoom_level, original_zoom_level, new_mode,
|
| - new_mode != ZOOM_MODE_DEFAULT));
|
| + new_mode != (default_scope_is_per_origin_ ? ZOOM_MODE_DEFAULT
|
| + : ZOOM_MODE_ISOLATED)));
|
|
|
| switch (new_mode) {
|
| case ZOOM_MODE_DEFAULT: {
|
| @@ -261,28 +296,58 @@ void ZoomController::SetZoomMode(ZoomMode new_mode) {
|
| }
|
|
|
| void ZoomController::ResetZoomModeOnNavigationIfNeeded(const GURL& url) {
|
| - if (zoom_mode_ != ZOOM_MODE_ISOLATED && zoom_mode_ != ZOOM_MODE_MANUAL)
|
| + if (zoom_mode_ != (default_scope_is_per_origin_ ? ZOOM_MODE_ISOLATED
|
| + : ZOOM_MODE_DEFAULT) &&
|
| + zoom_mode_ != ZOOM_MODE_MANUAL)
|
| return;
|
|
|
| int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
|
| int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
|
| content::HostZoomMap* zoom_map =
|
| content::HostZoomMap::GetForWebContents(web_contents());
|
| + double old_zoom_level = GetZoomLevel();
|
| + // Set |zoom_level_| after calling GetZoomLevel() so we get the correct old
|
| + // zoom level if we're resetting from manual.
|
| zoom_level_ = zoom_map->GetDefaultZoomLevel();
|
| - double old_zoom_level = zoom_map->GetZoomLevel(web_contents());
|
| - double new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme(
|
| - url.scheme(), net::GetHostOrSpecFromURL(url));
|
| + ZoomMode new_mode;
|
| + double new_zoom_level;
|
| + if (default_scope_is_per_origin_) {
|
| + new_mode = ZOOM_MODE_DEFAULT;
|
| + new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme(
|
| + url.scheme(), net::GetHostOrSpecFromURL(url));
|
| + } else {
|
| + new_mode = ZOOM_MODE_ISOLATED;
|
| + new_zoom_level = zoom_level_;
|
| + }
|
| event_data_.reset(new ZoomChangedEventData(web_contents(), old_zoom_level,
|
| - new_zoom_level, ZOOM_MODE_DEFAULT,
|
| + new_zoom_level, new_mode,
|
| false /* can_show_bubble */));
|
| - // The call to ClearTemporaryZoomLevel() doesn't generate any events from
|
| - // HostZoomMap, but the call to UpdateState() at the end of this function
|
| - // will notify our observers.
|
| - // Note: it's possible the render_process/view ids have disappeared (e.g.
|
| - // if we navigated to a new origin), but this won't cause a problem in the
|
| - // call below.
|
| - zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
|
| - zoom_mode_ = ZOOM_MODE_DEFAULT;
|
| + if (default_scope_is_per_origin_) {
|
| + // The call to ClearTemporaryZoomLevel() doesn't generate any events from
|
| + // HostZoomMap, but the call to UpdateState() at the end of this function
|
| + // will notify our observers.
|
| + // Note: it's possible the render_process/view ids have disappeared (e.g.
|
| + // if we navigated to a new origin), but this won't cause a problem in the
|
| + // call below.
|
| + zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
|
| + } else {
|
| + // If we're resetting to isolated zoom, a temporary zoom level needs to
|
| + // be set to override any existing per-host zoom levels.
|
| + zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
|
| + new_zoom_level);
|
| + }
|
| + zoom_mode_ = new_mode;
|
| +}
|
| +
|
| +void ZoomController::UpdateZoomModeOnScopeChangeIfNeeded() {
|
| + if (zoom_mode_ != ZOOM_MODE_DEFAULT && zoom_mode_ != ZOOM_MODE_ISOLATED)
|
| + return;
|
| +
|
| + // When going from per-tab to per-host, if there isn't an existing per-host
|
| + // zoom level set and we have a non-default temporary zoom level, this
|
| + // ZoomController will set the per-host zoom level.
|
| + SetZoomMode(default_scope_is_per_origin_ ? ZOOM_MODE_DEFAULT
|
| + : ZOOM_MODE_ISOLATED);
|
| }
|
|
|
| void ZoomController::DidFinishNavigation(
|
| @@ -303,6 +368,9 @@ void ZoomController::DidFinishNavigation(
|
| }
|
|
|
| void ZoomController::WebContentsDestroyed() {
|
| + // Once our WebContents is destroyed, we can no longer respond to zoom scope
|
| + // changes.
|
| + default_zoom_scope_subscription_.reset();
|
| // At this point we should no longer be sending any zoom events with this
|
| // WebContents.
|
| observers_.Clear();
|
| @@ -311,9 +379,19 @@ void ZoomController::WebContentsDestroyed() {
|
| void ZoomController::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());
|
| +
|
| + // The HostZoomMap records temporary zoom levels per RenderView. When zooming
|
| + // is per-tab and our RenderView changes, we need to copy the level for our
|
| + // new RenderView so that the tab's zoom level is preserved.
|
| + if (old_host && !default_scope_is_per_origin_ &&
|
| + zoom_mode_ == ZOOM_MODE_ISOLATED) {
|
| + PreserveTemporaryZoomLevel(host_zoom_map_, new_host_zoom_map, old_host,
|
| + new_host);
|
| + }
|
| +
|
| + // If our associated HostZoomMap changes, update our event subscription.
|
| if (new_host_zoom_map == host_zoom_map_)
|
| return;
|
|
|
| @@ -322,11 +400,66 @@ void ZoomController::RenderFrameHostChanged(
|
| base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this)));
|
| }
|
|
|
| +void ZoomController::PreserveTemporaryZoomLevel(
|
| + const content::HostZoomMap* old_zoom_map,
|
| + content::HostZoomMap* new_zoom_map,
|
| + content::RenderFrameHost* old_host,
|
| + content::RenderFrameHost* new_host) const {
|
| + const content::RenderViewHost* old_view_host = old_host->GetRenderViewHost();
|
| + const content::RenderViewHost* new_view_host = new_host->GetRenderViewHost();
|
| +
|
| + DCHECK(old_zoom_map->UsesTemporaryZoomLevel(
|
| + old_view_host->GetProcess()->GetID(), old_view_host->GetRoutingID()));
|
| +
|
| + const double level = old_zoom_map->GetTemporaryZoomLevel(
|
| + old_view_host->GetProcess()->GetID(), old_view_host->GetRoutingID());
|
| + new_zoom_map->SetTemporaryZoomLevel(new_view_host->GetProcess()->GetID(),
|
| + new_view_host->GetRoutingID(), level);
|
| +}
|
| +
|
| +void ZoomController::PreserveTemporaryZoomLevel(
|
| + content::WebContents* old_web_contents,
|
| + content::WebContents* new_web_contents) const {
|
| + if (default_scope_is_per_origin_ || zoom_mode_ != ZOOM_MODE_ISOLATED)
|
| + return;
|
| +
|
| + content::RenderFrameHost* old_host = old_web_contents->GetMainFrame();
|
| + content::RenderFrameHost* new_host = new_web_contents->GetMainFrame();
|
| + const content::HostZoomMap* old_host_zoom_map =
|
| + content::HostZoomMap::GetForWebContents(old_web_contents);
|
| + content::HostZoomMap* new_host_zoom_map =
|
| + content::HostZoomMap::GetForWebContents(new_web_contents);
|
| +
|
| + PreserveTemporaryZoomLevel(old_host_zoom_map, new_host_zoom_map, old_host,
|
| + new_host);
|
| +}
|
| +
|
| +void ZoomController::DidCloneToNewWebContents(
|
| + content::WebContents* old_web_contents,
|
| + content::WebContents* new_web_contents) {
|
| + // If a WebContents is cloned when zooming is per-tab, have the clone inherit
|
| + // the original's zoom level.
|
| + PreserveTemporaryZoomLevel(old_web_contents, new_web_contents);
|
| +}
|
| +
|
| +void ZoomController::WebContentsReplaced(
|
| + content::WebContents* new_web_contents) {
|
| + // A tab may replace its WebContents with another, but from the user's
|
| + // perspective, this is still the same tab, so we need to preserve the
|
| + // per-tab zoom.
|
| + PreserveTemporaryZoomLevel(web_contents(), new_web_contents);
|
| +}
|
| +
|
| void ZoomController::OnZoomLevelChanged(
|
| const content::HostZoomMap::ZoomLevelChange& change) {
|
| UpdateState(change.host);
|
| }
|
|
|
| +void ZoomController::OnDefaultZoomScopeChanged() {
|
| + default_scope_is_per_origin_ = !default_scope_is_per_origin_;
|
| + UpdateZoomModeOnScopeChangeIfNeeded();
|
| +}
|
| +
|
| void ZoomController::UpdateState(const std::string& host) {
|
| // If |host| is empty, all observers should be updated.
|
| if (!host.empty()) {
|
|
|