refactor: update WebContentsZoomController
(#39428)
refactor: update WebContentsZoomController
This commit is contained in:
parent
5d11c30720
commit
8e3dcc8b17
7 changed files with 305 additions and 121 deletions
|
@ -494,6 +494,7 @@ filenames = {
|
|||
"shell/browser/web_contents_preferences.h",
|
||||
"shell/browser/web_contents_zoom_controller.cc",
|
||||
"shell/browser/web_contents_zoom_controller.h",
|
||||
"shell/browser/web_contents_zoom_observer.h",
|
||||
"shell/browser/web_view_guest_delegate.cc",
|
||||
"shell/browser/web_view_guest_delegate.h",
|
||||
"shell/browser/web_view_manager.cc",
|
||||
|
|
|
@ -42,19 +42,19 @@ void ZoomModeToZoomSettings(WebContentsZoomController::ZoomMode zoom_mode,
|
|||
api::tabs::ZoomSettings* zoom_settings) {
|
||||
DCHECK(zoom_settings);
|
||||
switch (zoom_mode) {
|
||||
case WebContentsZoomController::ZoomMode::kDefault:
|
||||
case WebContentsZoomController::ZOOM_MODE_DEFAULT:
|
||||
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
|
||||
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN;
|
||||
break;
|
||||
case WebContentsZoomController::ZoomMode::kIsolated:
|
||||
case WebContentsZoomController::ZOOM_MODE_ISOLATED:
|
||||
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
|
||||
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
break;
|
||||
case WebContentsZoomController::ZoomMode::kManual:
|
||||
case WebContentsZoomController::ZOOM_MODE_MANUAL:
|
||||
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_MANUAL;
|
||||
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
break;
|
||||
case WebContentsZoomController::ZoomMode::kDisabled:
|
||||
case WebContentsZoomController::ZOOM_MODE_DISABLED:
|
||||
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_DISABLED;
|
||||
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
break;
|
||||
|
@ -427,24 +427,24 @@ ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
|
|||
// Determine the correct internal zoom mode to set |web_contents| to from the
|
||||
// user-specified |zoom_settings|.
|
||||
WebContentsZoomController::ZoomMode zoom_mode =
|
||||
WebContentsZoomController::ZoomMode::kDefault;
|
||||
WebContentsZoomController::ZOOM_MODE_DEFAULT;
|
||||
switch (params->zoom_settings.mode) {
|
||||
case tabs::ZOOM_SETTINGS_MODE_NONE:
|
||||
case tabs::ZOOM_SETTINGS_MODE_AUTOMATIC:
|
||||
switch (params->zoom_settings.scope) {
|
||||
case tabs::ZOOM_SETTINGS_SCOPE_NONE:
|
||||
case tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN:
|
||||
zoom_mode = WebContentsZoomController::ZoomMode::kDefault;
|
||||
zoom_mode = WebContentsZoomController::ZOOM_MODE_DEFAULT;
|
||||
break;
|
||||
case tabs::ZOOM_SETTINGS_SCOPE_PER_TAB:
|
||||
zoom_mode = WebContentsZoomController::ZoomMode::kIsolated;
|
||||
zoom_mode = WebContentsZoomController::ZOOM_MODE_ISOLATED;
|
||||
}
|
||||
break;
|
||||
case tabs::ZOOM_SETTINGS_MODE_MANUAL:
|
||||
zoom_mode = WebContentsZoomController::ZoomMode::kManual;
|
||||
zoom_mode = WebContentsZoomController::ZOOM_MODE_MANUAL;
|
||||
break;
|
||||
case tabs::ZOOM_SETTINGS_MODE_DISABLED:
|
||||
zoom_mode = WebContentsZoomController::ZoomMode::kDisabled;
|
||||
zoom_mode = WebContentsZoomController::ZOOM_MODE_DISABLED;
|
||||
}
|
||||
|
||||
contents->GetZoomController()->SetZoomMode(zoom_mode);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
|
@ -16,72 +17,122 @@
|
|||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "content/public/common/page_type.h"
|
||||
#include "net/base/url_util.h"
|
||||
#include "shell/browser/web_contents_zoom_observer.h"
|
||||
#include "third_party/blink/public/common/page/page_zoom.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
const double kPageZoomEpsilon = 0.001;
|
||||
|
||||
} // namespace
|
||||
|
||||
WebContentsZoomController::WebContentsZoomController(
|
||||
content::WebContents* web_contents)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
content::WebContentsUserData<WebContentsZoomController>(*web_contents) {
|
||||
default_zoom_factor_ = kPageZoomEpsilon;
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
host_zoom_map_ = content::HostZoomMap::GetForWebContents(web_contents);
|
||||
zoom_level_ = host_zoom_map_->GetDefaultZoomLevel();
|
||||
default_zoom_factor_ = kPageZoomEpsilon;
|
||||
|
||||
zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(
|
||||
base::BindRepeating(&WebContentsZoomController::OnZoomLevelChanged,
|
||||
base::Unretained(this)));
|
||||
|
||||
UpdateState(std::string());
|
||||
}
|
||||
|
||||
WebContentsZoomController::~WebContentsZoomController() = default;
|
||||
WebContentsZoomController::~WebContentsZoomController() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnZoomControllerDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentsZoomController::AddObserver(
|
||||
WebContentsZoomController::Observer* observer) {
|
||||
void WebContentsZoomController::AddObserver(WebContentsZoomObserver* observer) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::RemoveObserver(
|
||||
WebContentsZoomController::Observer* observer) {
|
||||
WebContentsZoomObserver* observer) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
observers_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::SetEmbedderZoomController(
|
||||
WebContentsZoomController* controller) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
embedder_zoom_controller_ = controller;
|
||||
}
|
||||
|
||||
void WebContentsZoomController::SetZoomLevel(double level) {
|
||||
if (!web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive() ||
|
||||
blink::PageZoomValuesEqual(GetZoomLevel(), level) ||
|
||||
zoom_mode_ == ZoomMode::kDisabled)
|
||||
return;
|
||||
bool WebContentsZoomController::SetZoomLevel(double level) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
content::NavigationEntry* entry =
|
||||
web_contents()->GetController().GetLastCommittedEntry();
|
||||
// Cannot zoom in disabled mode. Also, don't allow changing zoom level on
|
||||
// a crashed tab, an error page or an interstitial page.
|
||||
if (zoom_mode_ == ZOOM_MODE_DISABLED ||
|
||||
!web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive())
|
||||
return false;
|
||||
|
||||
content::GlobalRenderFrameHostId rfh_id =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
// Do not actually rescale the page in manual mode.
|
||||
if (zoom_mode_ == ZOOM_MODE_MANUAL) {
|
||||
// If the zoom level hasn't changed, early out to avoid sending an event.
|
||||
if (blink::PageZoomValuesEqual(zoom_level_, level))
|
||||
return true;
|
||||
|
||||
if (zoom_mode_ == ZoomMode::kManual) {
|
||||
double old_zoom_level = zoom_level_;
|
||||
zoom_level_ = level;
|
||||
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), level, true);
|
||||
ZoomChangedEventData zoom_change_data(web_contents(), old_zoom_level,
|
||||
zoom_level_, false /* temporary */,
|
||||
zoom_mode_);
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(zoom_change_data);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
content::HostZoomMap* zoom_map =
|
||||
content::HostZoomMap::GetForWebContents(web_contents());
|
||||
if (zoom_mode_ == ZoomMode::kIsolated ||
|
||||
DCHECK(zoom_map);
|
||||
DCHECK(!event_data_);
|
||||
event_data_ = std::make_unique<ZoomChangedEventData>(
|
||||
web_contents(), GetZoomLevel(), level, false /* temporary */, zoom_mode_);
|
||||
|
||||
content::GlobalRenderFrameHostId rfh_id =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
if (zoom_mode_ == ZOOM_MODE_ISOLATED ||
|
||||
zoom_map->UsesTemporaryZoomLevel(rfh_id)) {
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, level);
|
||||
// Notify observers of zoom level changes.
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), level, true);
|
||||
ZoomChangedEventData zoom_change_data(web_contents(), zoom_level_, level,
|
||||
true /* temporary */, zoom_mode_);
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(zoom_change_data);
|
||||
} else {
|
||||
content::HostZoomMap::SetZoomLevel(web_contents(), level);
|
||||
|
||||
// Notify observers of zoom level changes.
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), level, false);
|
||||
if (!entry) {
|
||||
// If we exit without triggering an update, we should clear event_data_,
|
||||
// else we may later trigger a DCHECK(event_data_).
|
||||
event_data_.reset();
|
||||
return false;
|
||||
}
|
||||
std::string host =
|
||||
net::GetHostOrSpecFromURL(content::HostZoomMap::GetURLFromEntry(entry));
|
||||
zoom_map->SetZoomLevelForHost(host, level);
|
||||
}
|
||||
|
||||
DCHECK(!event_data_);
|
||||
return true;
|
||||
}
|
||||
|
||||
double WebContentsZoomController::GetZoomLevel() {
|
||||
return zoom_mode_ == ZoomMode::kManual
|
||||
double WebContentsZoomController::GetZoomLevel() const {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
return zoom_mode_ == ZOOM_MODE_MANUAL
|
||||
? zoom_level_
|
||||
: content::HostZoomMap::GetZoomLevel(web_contents());
|
||||
}
|
||||
|
@ -95,32 +146,44 @@ double WebContentsZoomController::GetDefaultZoomFactor() {
|
|||
}
|
||||
|
||||
void WebContentsZoomController::SetTemporaryZoomLevel(double level) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
content::GlobalRenderFrameHostId old_rfh_id_ =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
host_zoom_map_->SetTemporaryZoomLevel(old_rfh_id_, level);
|
||||
|
||||
// Notify observers of zoom level changes.
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), level, true);
|
||||
ZoomChangedEventData zoom_change_data(web_contents(), zoom_level_, level,
|
||||
true /* temporary */, zoom_mode_);
|
||||
for (WebContentsZoomObserver& observer : observers_)
|
||||
observer.OnZoomChanged(zoom_change_data);
|
||||
}
|
||||
|
||||
bool WebContentsZoomController::UsesTemporaryZoomLevel() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
content::GlobalRenderFrameHostId rfh_id =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
return host_zoom_map_->UsesTemporaryZoomLevel(rfh_id);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::SetZoomMode(ZoomMode new_mode) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (new_mode == zoom_mode_)
|
||||
return;
|
||||
|
||||
content::HostZoomMap* zoom_map =
|
||||
content::HostZoomMap::GetForWebContents(web_contents());
|
||||
DCHECK(zoom_map);
|
||||
content::GlobalRenderFrameHostId rfh_id =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
double original_zoom_level = GetZoomLevel();
|
||||
|
||||
DCHECK(!event_data_);
|
||||
event_data_ = std::make_unique<ZoomChangedEventData>(
|
||||
web_contents(), original_zoom_level, original_zoom_level,
|
||||
false /* temporary */, new_mode);
|
||||
|
||||
switch (new_mode) {
|
||||
case ZoomMode::kDefault: {
|
||||
case ZOOM_MODE_DEFAULT: {
|
||||
content::NavigationEntry* entry =
|
||||
web_contents()->GetController().GetLastCommittedEntry();
|
||||
|
||||
|
@ -135,6 +198,7 @@ void WebContentsZoomController::SetZoomMode(ZoomMode new_mode) {
|
|||
// the correct zoom level.
|
||||
double origin_zoom_level =
|
||||
zoom_map->GetZoomLevelForHostAndScheme(url.scheme(), host);
|
||||
event_data_->new_zoom_level = origin_zoom_level;
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, origin_zoom_level);
|
||||
} else {
|
||||
// The host will need a level prior to removing the temporary level.
|
||||
|
@ -147,101 +211,128 @@ void WebContentsZoomController::SetZoomMode(ZoomMode new_mode) {
|
|||
zoom_map->ClearTemporaryZoomLevel(rfh_id);
|
||||
break;
|
||||
}
|
||||
case ZoomMode::kIsolated: {
|
||||
// Unless the zoom mode was |ZoomMode::kDisabled| before this call, the
|
||||
case ZOOM_MODE_ISOLATED: {
|
||||
// Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
|
||||
// page needs an initial isolated zoom back to the same level it was at
|
||||
// in the other mode.
|
||||
if (zoom_mode_ != ZoomMode::kDisabled) {
|
||||
if (zoom_mode_ != ZOOM_MODE_DISABLED) {
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, original_zoom_level);
|
||||
} else {
|
||||
// When we don't call any HostZoomMap set functions, we send the event
|
||||
// manually.
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), original_zoom_level,
|
||||
false);
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(*event_data_);
|
||||
event_data_.reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZoomMode::kManual: {
|
||||
// Unless the zoom mode was |ZoomMode::kDisabled| before this call, the
|
||||
case ZOOM_MODE_MANUAL: {
|
||||
// Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
|
||||
// page needs to be resized to the default zoom. While in manual mode,
|
||||
// the zoom level is handled independently.
|
||||
if (zoom_mode_ != ZoomMode::kDisabled) {
|
||||
if (zoom_mode_ != ZOOM_MODE_DISABLED) {
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, GetDefaultZoomLevel());
|
||||
zoom_level_ = original_zoom_level;
|
||||
} else {
|
||||
// When we don't call any HostZoomMap set functions, we send the event
|
||||
// manually.
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), original_zoom_level,
|
||||
false);
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(*event_data_);
|
||||
event_data_.reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZoomMode::kDisabled: {
|
||||
case ZOOM_MODE_DISABLED: {
|
||||
// The page needs to be zoomed back to default before disabling the zoom
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, GetDefaultZoomLevel());
|
||||
double new_zoom_level = GetDefaultZoomLevel();
|
||||
event_data_->new_zoom_level = new_zoom_level;
|
||||
zoom_map->SetTemporaryZoomLevel(rfh_id, new_zoom_level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Any event data we've stored should have been consumed by this point.
|
||||
DCHECK(!event_data_);
|
||||
|
||||
zoom_mode_ = new_mode;
|
||||
}
|
||||
|
||||
void WebContentsZoomController::ResetZoomModeOnNavigationIfNeeded(
|
||||
const GURL& url) {
|
||||
if (zoom_mode_ != ZoomMode::kIsolated && zoom_mode_ != ZoomMode::kManual)
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (zoom_mode_ != ZOOM_MODE_ISOLATED && zoom_mode_ != ZOOM_MODE_MANUAL)
|
||||
return;
|
||||
|
||||
content::GlobalRenderFrameHostId rfh_id =
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId();
|
||||
content::HostZoomMap* zoom_map =
|
||||
content::HostZoomMap::GetForWebContents(web_contents());
|
||||
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));
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomLevelChanged(web_contents(), new_zoom_level, false);
|
||||
zoom_map->ClearTemporaryZoomLevel(rfh_id);
|
||||
zoom_mode_ = ZoomMode::kDefault;
|
||||
event_data_ = std::make_unique<ZoomChangedEventData>(
|
||||
web_contents(), old_zoom_level, new_zoom_level, false, ZOOM_MODE_DEFAULT);
|
||||
// The call to ClearTemporaryZoomLevel() doesn't generate any events from
|
||||
// HostZoomMap, but the call to UpdateState() at the end of
|
||||
// DidFinishNavigation will notify our observers.
|
||||
// Note: it's possible the render_process/frame 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(
|
||||
web_contents()->GetPrimaryMainFrame()->GetGlobalId());
|
||||
zoom_mode_ = ZOOM_MODE_DEFAULT;
|
||||
}
|
||||
|
||||
void WebContentsZoomController::DidFinishNavigation(
|
||||
content::NavigationHandle* navigation_handle) {
|
||||
if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
|
||||
return;
|
||||
|
||||
if (navigation_handle->IsErrorPage()) {
|
||||
content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents());
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (!navigation_handle->IsInPrimaryMainFrame() ||
|
||||
!navigation_handle->HasCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResetZoomModeOnNavigationIfNeeded(navigation_handle->GetURL());
|
||||
SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL());
|
||||
if (navigation_handle->IsErrorPage())
|
||||
content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents());
|
||||
|
||||
if (!navigation_handle->IsSameDocument()) {
|
||||
ResetZoomModeOnNavigationIfNeeded(navigation_handle->GetURL());
|
||||
SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL());
|
||||
}
|
||||
|
||||
// If the main frame's content has changed, the new page may have a different
|
||||
// zoom level from the old one.
|
||||
UpdateState(std::string());
|
||||
DCHECK(!event_data_);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::WebContentsDestroyed() {
|
||||
for (Observer& observer : observers_)
|
||||
observer.OnZoomControllerWebContentsDestroyed();
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
// At this point we should no longer be sending any zoom events with this
|
||||
// WebContents.
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnZoomControllerDestroyed(this);
|
||||
}
|
||||
|
||||
observers_.Clear();
|
||||
embedder_zoom_controller_ = nullptr;
|
||||
}
|
||||
|
||||
void WebContentsZoomController::RenderFrameHostChanged(
|
||||
content::RenderFrameHost* old_host,
|
||||
content::RenderFrameHost* new_host) {
|
||||
// If our associated HostZoomMap changes, update our event subscription.
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
// If our associated HostZoomMap changes, update our 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::BindRepeating(&WebContentsZoomController::OnZoomLevelChanged,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void WebContentsZoomController::SetZoomFactorOnNavigationIfNeeded(
|
||||
const GURL& url) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (blink::PageZoomValuesEqual(GetDefaultZoomFactor(), kPageZoomEpsilon))
|
||||
return;
|
||||
|
||||
|
@ -276,6 +367,42 @@ void WebContentsZoomController::SetZoomFactorOnNavigationIfNeeded(
|
|||
SetZoomLevel(zoom_level);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::OnZoomLevelChanged(
|
||||
const content::HostZoomMap::ZoomLevelChange& change) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
UpdateState(change.host);
|
||||
}
|
||||
|
||||
void WebContentsZoomController::UpdateState(const std::string& host) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
// If |host| is empty, all observers should be updated.
|
||||
if (!host.empty()) {
|
||||
// Use the navigation entry's URL instead of the WebContents' so virtual
|
||||
// URLs work (e.g. chrome://settings). http://crbug.com/153950
|
||||
content::NavigationEntry* entry =
|
||||
web_contents()->GetController().GetLastCommittedEntry();
|
||||
if (!entry || host != net::GetHostOrSpecFromURL(
|
||||
content::HostZoomMap::GetURLFromEntry(entry))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event_data_) {
|
||||
// For state changes initiated within the ZoomController, information about
|
||||
// the change should be sent.
|
||||
ZoomChangedEventData zoom_change_data = *event_data_;
|
||||
event_data_.reset();
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(zoom_change_data);
|
||||
} else {
|
||||
double zoom_level = GetZoomLevel();
|
||||
ZoomChangedEventData zoom_change_data(web_contents(), zoom_level,
|
||||
zoom_level, false, zoom_mode_);
|
||||
for (auto& observer : observers_)
|
||||
observer.OnZoomChanged(zoom_change_data);
|
||||
}
|
||||
}
|
||||
|
||||
WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsZoomController);
|
||||
|
||||
} // namespace electron
|
||||
|
|
|
@ -14,40 +14,49 @@
|
|||
|
||||
namespace electron {
|
||||
|
||||
class WebContentsZoomObserver;
|
||||
|
||||
// Manages the zoom changes of WebContents.
|
||||
class WebContentsZoomController
|
||||
: public content::WebContentsObserver,
|
||||
public content::WebContentsUserData<WebContentsZoomController> {
|
||||
public:
|
||||
class Observer : public base::CheckedObserver {
|
||||
public:
|
||||
virtual void OnZoomLevelChanged(content::WebContents* web_contents,
|
||||
double level,
|
||||
bool is_temporary) {}
|
||||
virtual void OnZoomControllerWebContentsDestroyed() {}
|
||||
|
||||
protected:
|
||||
~Observer() override {}
|
||||
};
|
||||
|
||||
// Defines how zoom changes are handled.
|
||||
enum class ZoomMode {
|
||||
enum ZoomMode {
|
||||
// Results in default zoom behavior, i.e. zoom changes are handled
|
||||
// automatically and on a per-origin basis, meaning that other tabs
|
||||
// navigated to the same origin will also zoom.
|
||||
kDefault,
|
||||
ZOOM_MODE_DEFAULT,
|
||||
// Results in zoom changes being handled automatically, but on a per-tab
|
||||
// basis. Tabs in this zoom mode will not be affected by zoom changes in
|
||||
// other tabs, and vice versa.
|
||||
kIsolated,
|
||||
ZOOM_MODE_ISOLATED,
|
||||
// Overrides the automatic handling of zoom changes. The |onZoomChange|
|
||||
// event will still be dispatched, but the page will not actually be zoomed.
|
||||
// These zoom changes can be handled manually by listening for the
|
||||
// |onZoomChange| event. Zooming in this mode is also on a per-tab basis.
|
||||
kManual,
|
||||
ZOOM_MODE_MANUAL,
|
||||
// Disables all zooming in this tab. The tab will revert to the default
|
||||
// zoom level, and all attempted zoom changes will be ignored.
|
||||
kDisabled,
|
||||
ZOOM_MODE_DISABLED,
|
||||
};
|
||||
|
||||
struct ZoomChangedEventData {
|
||||
ZoomChangedEventData(content::WebContents* web_contents,
|
||||
double old_zoom_level,
|
||||
double new_zoom_level,
|
||||
bool temporary,
|
||||
WebContentsZoomController::ZoomMode zoom_mode)
|
||||
: web_contents(web_contents),
|
||||
old_zoom_level(old_zoom_level),
|
||||
new_zoom_level(new_zoom_level),
|
||||
temporary(temporary),
|
||||
zoom_mode(zoom_mode) {}
|
||||
raw_ptr<content::WebContents> web_contents;
|
||||
double old_zoom_level;
|
||||
double new_zoom_level;
|
||||
bool temporary;
|
||||
WebContentsZoomController::ZoomMode zoom_mode;
|
||||
};
|
||||
|
||||
explicit WebContentsZoomController(content::WebContents* web_contents);
|
||||
|
@ -58,24 +67,29 @@ class WebContentsZoomController
|
|||
WebContentsZoomController& operator=(const WebContentsZoomController&) =
|
||||
delete;
|
||||
|
||||
void AddObserver(Observer* observer);
|
||||
void RemoveObserver(Observer* observer);
|
||||
void AddObserver(WebContentsZoomObserver* observer);
|
||||
void RemoveObserver(WebContentsZoomObserver* observer);
|
||||
|
||||
void SetEmbedderZoomController(WebContentsZoomController* controller);
|
||||
|
||||
// Methods for managing zoom levels.
|
||||
void SetZoomLevel(double level);
|
||||
double GetZoomLevel();
|
||||
// Gets the current zoom level by querying HostZoomMap (if not in manual zoom
|
||||
// mode) or from the ZoomController local value otherwise.
|
||||
double GetZoomLevel() const;
|
||||
|
||||
// Sets the zoom level through HostZoomMap.
|
||||
// Returns true on success.
|
||||
bool SetZoomLevel(double zoom_level);
|
||||
|
||||
void SetDefaultZoomFactor(double factor);
|
||||
double GetDefaultZoomFactor();
|
||||
|
||||
// Sets the temporary zoom level through HostZoomMap.
|
||||
void SetTemporaryZoomLevel(double level);
|
||||
bool UsesTemporaryZoomLevel();
|
||||
|
||||
// Sets the zoom mode, which defines zoom behavior (see enum ZoomMode).
|
||||
void SetZoomMode(ZoomMode zoom_mode);
|
||||
|
||||
void ResetZoomModeOnNavigationIfNeeded(const GURL& url);
|
||||
|
||||
ZoomMode zoom_mode() const { return zoom_mode_; }
|
||||
|
||||
// Convenience method to get default zoom level. Implemented here for
|
||||
|
@ -86,8 +100,9 @@ class WebContentsZoomController
|
|||
}
|
||||
|
||||
protected:
|
||||
// content::WebContentsObserver:
|
||||
void DidFinishNavigation(content::NavigationHandle* handle) override;
|
||||
// content::WebContentsObserver overrides:
|
||||
void DidFinishNavigation(
|
||||
content::NavigationHandle* navigation_handle) override;
|
||||
void WebContentsDestroyed() override;
|
||||
void RenderFrameHostChanged(content::RenderFrameHost* old_host,
|
||||
content::RenderFrameHost* new_host) override;
|
||||
|
@ -95,29 +110,40 @@ class WebContentsZoomController
|
|||
private:
|
||||
friend class content::WebContentsUserData<WebContentsZoomController>;
|
||||
|
||||
// Called after a navigation has committed to set default zoom factor.
|
||||
void ResetZoomModeOnNavigationIfNeeded(const GURL& url);
|
||||
void SetZoomFactorOnNavigationIfNeeded(const GURL& url);
|
||||
void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
|
||||
|
||||
// Updates the zoom icon and zoom percentage based on current values and
|
||||
// notifies the observer if changes have occurred. |host| may be empty,
|
||||
// meaning the change should apply to ~all sites. If it is not empty, the
|
||||
// change only affects sites with the given host.
|
||||
void UpdateState(const std::string& host);
|
||||
|
||||
// The current zoom mode.
|
||||
ZoomMode zoom_mode_ = ZoomMode::kDefault;
|
||||
ZoomMode zoom_mode_ = ZOOM_MODE_DEFAULT;
|
||||
|
||||
// Current zoom level.
|
||||
double zoom_level_ = 1.0;
|
||||
// The current zoom level.
|
||||
double zoom_level_;
|
||||
|
||||
// kZoomFactor.
|
||||
double default_zoom_factor_ = 0;
|
||||
|
||||
const double kPageZoomEpsilon = 0.001;
|
||||
// The current default zoom factor.
|
||||
double default_zoom_factor_;
|
||||
|
||||
int old_process_id_ = -1;
|
||||
int old_view_id_ = -1;
|
||||
|
||||
std::unique_ptr<ZoomChangedEventData> event_data_;
|
||||
|
||||
raw_ptr<WebContentsZoomController> embedder_zoom_controller_ = nullptr;
|
||||
|
||||
base::ObserverList<Observer> observers_;
|
||||
// Observer receiving notifications on state changes.
|
||||
base::ObserverList<WebContentsZoomObserver> observers_;
|
||||
|
||||
// Keep track of the HostZoomMap we're currently subscribed to.
|
||||
raw_ptr<content::HostZoomMap> host_zoom_map_;
|
||||
|
||||
base::CallbackListSubscription zoom_subscription_;
|
||||
|
||||
WEB_CONTENTS_USER_DATA_KEY_DECL();
|
||||
};
|
||||
|
||||
|
|
29
shell/browser/web_contents_zoom_observer.h
Normal file
29
shell/browser/web_contents_zoom_observer.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2023 Microsoft, GmbH
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_WEB_CONTENTS_ZOOM_OBSERVER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_WEB_CONTENTS_ZOOM_OBSERVER_H_
|
||||
|
||||
#include "shell/browser/web_contents_zoom_controller.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Interface for objects that wish to be notified of changes in
|
||||
// WebContentsZoomController.
|
||||
class WebContentsZoomObserver : public base::CheckedObserver {
|
||||
public:
|
||||
// Fired when the ZoomController is destructed. Observers should deregister
|
||||
// themselves from the ZoomObserver in this event handler. Note that
|
||||
// ZoomController::FromWebContents() returns nullptr at this point already.
|
||||
virtual void OnZoomControllerDestroyed(
|
||||
WebContentsZoomController* zoom_controller) = 0;
|
||||
|
||||
// Notification that the zoom percentage has changed.
|
||||
virtual void OnZoomChanged(
|
||||
const WebContentsZoomController::ZoomChangedEventData& data) {}
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_WEB_CONTENTS_ZOOM_OBSERVER_H_
|
|
@ -73,23 +73,23 @@ content::WebContents* WebViewGuestDelegate::GetOwnerWebContents() {
|
|||
return embedder_web_contents_;
|
||||
}
|
||||
|
||||
void WebViewGuestDelegate::OnZoomLevelChanged(
|
||||
content::WebContents* web_contents,
|
||||
double level,
|
||||
bool is_temporary) {
|
||||
if (web_contents == GetOwnerWebContents()) {
|
||||
if (is_temporary) {
|
||||
api_web_contents_->GetZoomController()->SetTemporaryZoomLevel(level);
|
||||
void WebViewGuestDelegate::OnZoomChanged(
|
||||
const WebContentsZoomController::ZoomChangedEventData& data) {
|
||||
if (data.web_contents == GetOwnerWebContents()) {
|
||||
if (data.temporary) {
|
||||
api_web_contents_->GetZoomController()->SetTemporaryZoomLevel(
|
||||
data.new_zoom_level);
|
||||
} else {
|
||||
api_web_contents_->GetZoomController()->SetZoomLevel(level);
|
||||
api_web_contents_->GetZoomController()->SetZoomLevel(data.new_zoom_level);
|
||||
}
|
||||
// Change the default zoom factor to match the embedders' new zoom level.
|
||||
double zoom_factor = blink::PageZoomLevelToZoomFactor(level);
|
||||
double zoom_factor = blink::PageZoomLevelToZoomFactor(data.new_zoom_level);
|
||||
api_web_contents_->GetZoomController()->SetDefaultZoomFactor(zoom_factor);
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewGuestDelegate::OnZoomControllerWebContentsDestroyed() {
|
||||
void WebViewGuestDelegate::OnZoomControllerDestroyed(
|
||||
WebContentsZoomController* zoom_controller) {
|
||||
ResetZoomController();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/memory/raw_ptr.h"
|
||||
#include "content/public/browser/browser_plugin_guest_delegate.h"
|
||||
#include "shell/browser/web_contents_zoom_controller.h"
|
||||
#include "shell/browser/web_contents_zoom_observer.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
@ -18,7 +19,7 @@ class WebContents;
|
|||
}
|
||||
|
||||
class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
|
||||
public WebContentsZoomController::Observer {
|
||||
public WebContentsZoomObserver {
|
||||
public:
|
||||
WebViewGuestDelegate(content::WebContents* embedder,
|
||||
api::WebContents* api_web_contents);
|
||||
|
@ -41,11 +42,11 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
|
|||
base::WeakPtr<content::BrowserPluginGuestDelegate> GetGuestDelegateWeakPtr()
|
||||
final;
|
||||
|
||||
// WebContentsZoomController::Observer:
|
||||
void OnZoomLevelChanged(content::WebContents* web_contents,
|
||||
double level,
|
||||
bool is_temporary) override;
|
||||
void OnZoomControllerWebContentsDestroyed() override;
|
||||
// WebContentsZoomObserver:
|
||||
void OnZoomControllerDestroyed(
|
||||
WebContentsZoomController* zoom_controller) override;
|
||||
void OnZoomChanged(
|
||||
const WebContentsZoomController::ZoomChangedEventData& data) override;
|
||||
|
||||
private:
|
||||
void ResetZoomController();
|
||||
|
|
Loading…
Reference in a new issue