Commit 5732a8da authored by Marshall Greenblatt's avatar Marshall Greenblatt

Unfork streamsPrivate API and add resourcesPrivate and tabs zoom APIs required...

Unfork streamsPrivate API and add resourcesPrivate and tabs zoom APIs required by the PDF extension (issue #1947)
parent f4425a9a
......@@ -243,12 +243,14 @@ static_library("libcef_static") {
"libcef/browser/download_item_impl.h",
"libcef/browser/download_manager_delegate.cc",
"libcef/browser/download_manager_delegate.h",
"libcef/browser/extensions/api/streams_private/streams_private_api.cc",
"libcef/browser/extensions/api/streams_private/streams_private_api.h",
"libcef/browser/extensions/api/tabs/tabs_api.cc",
"libcef/browser/extensions/api/tabs/tabs_api.h",
"libcef/browser/extensions/browser_context_keyed_service_factories.cc",
"libcef/browser/extensions/browser_context_keyed_service_factories.h",
"libcef/browser/extensions/browser_extensions_util.cc",
"libcef/browser/extensions/browser_extensions_util.h",
"libcef/browser/extensions/chrome_api_registration.cc",
"libcef/browser/extensions/chrome_api_registration.h",
"libcef/browser/extensions/component_extension_resource_manager.cc",
"libcef/browser/extensions/component_extension_resource_manager.h",
"libcef/browser/extensions/extensions_api_client.cc",
......@@ -409,6 +411,8 @@ static_library("libcef_static") {
"libcef/common/crash_reporter_client.h",
"libcef/common/drag_data_impl.cc",
"libcef/common/drag_data_impl.h",
"libcef/common/extensions/chrome_generated_schemas.cc",
"libcef/common/extensions/chrome_generated_schemas.h",
"libcef/common/extensions/extensions_client.cc",
"libcef/common/extensions/extensions_client.h",
"libcef/common/extensions/extensions_util.cc",
......@@ -540,8 +544,10 @@ static_library("libcef_static") {
":repack_locales_pack",
# Generate API bindings for extensions.
"libcef/common/extensions/api",
"libcef/common/extensions/api:api_registration",
# TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
# libcef/common/extensions/api/README.txt for details.
#"libcef/common/extensions/api",
#"libcef/common/extensions/api:api_registration",
# Normal build dependencies. Should be sorted alphabetically.
"//base",
......
......@@ -1007,9 +1007,11 @@
'<(DEPTH)/v8/src/v8.gyp:v8',
# Necessary to generate the grit include files.
'cef_pak',
# Necessary to generate API bindings for extensions.
'libcef/browser/extensions/api/api_registration.gyp:cef_api_registration',
'libcef/common/extensions/api/api.gyp:cef_api',
# Generate API bindings for extensions.
# TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
# libcef/common/extensions/api/README.txt for details.
#'libcef/browser/extensions/api/api_registration.gyp:cef_api_registration',
#'libcef/common/extensions/api/api.gyp:cef_api',
],
'sources': [
'<@(includes_common)',
......@@ -1062,12 +1064,14 @@
'libcef/browser/download_item_impl.h',
'libcef/browser/download_manager_delegate.cc',
'libcef/browser/download_manager_delegate.h',
'libcef/browser/extensions/api/streams_private/streams_private_api.cc',
'libcef/browser/extensions/api/streams_private/streams_private_api.h',
'libcef/browser/extensions/api/tabs/tabs_api.cc',
'libcef/browser/extensions/api/tabs/tabs_api.h',
'libcef/browser/extensions/browser_context_keyed_service_factories.cc',
'libcef/browser/extensions/browser_context_keyed_service_factories.h',
'libcef/browser/extensions/browser_extensions_util.cc',
'libcef/browser/extensions/browser_extensions_util.h',
'libcef/browser/extensions/chrome_api_registration.cc',
'libcef/browser/extensions/chrome_api_registration.h',
'libcef/browser/extensions/component_extension_resource_manager.cc',
'libcef/browser/extensions/component_extension_resource_manager.h',
'libcef/browser/extensions/extensions_api_client.cc',
......@@ -1228,6 +1232,8 @@
'libcef/common/crash_reporter_client.h',
'libcef/common/drag_data_impl.cc',
'libcef/common/drag_data_impl.h',
'libcef/common/extensions/chrome_generated_schemas.cc',
'libcef/common/extensions/chrome_generated_schemas.h',
'libcef/common/extensions/extensions_client.cc',
'libcef/common/extensions/extensions_client.h',
'libcef/common/extensions/extensions_util.cc',
......
......@@ -39,9 +39,11 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
#include "components/zoom/zoom_controller.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/common/view_messages.h"
......@@ -2800,6 +2802,12 @@ CefBrowserHostImpl::CefBrowserHostImpl(
PrefsTabHelper::CreateForWebContents(web_contents_.get());
printing::CefPrintViewManager::CreateForWebContents(web_contents_.get());
if (extensions::ExtensionsEnabled()) {
// Used by the tabs extension API.
SessionTabHelper::CreateForWebContents(web_contents_.get());
zoom::ZoomController::CreateForWebContents(web_contents_.get());
}
// Make sure RenderViewCreated is called at least one time.
RenderViewCreated(web_contents->GetRenderViewHost());
......
......@@ -435,6 +435,11 @@ scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfoForFrame(
is_guest_view);
}
void CefBrowserInfoManager::GetBrowserInfoList(BrowserInfoList& list) {
base::AutoLock lock_scope(browser_info_lock_);
list = browser_info_list_;
}
void CefBrowserInfoManager::RenderProcessHostDestroyed(
content::RenderProcessHost* host) {
base::AutoLock lock_scope(browser_info_lock_);
......
......@@ -128,6 +128,10 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
int render_routing_id,
bool* is_guest_view);
// Retrieves all existing CefBrowserInfo objects.
typedef std::list<scoped_refptr<CefBrowserInfo> > BrowserInfoList;
void GetBrowserInfoList(BrowserInfoList& list);
private:
// RenderProcessHostObserver methods:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
......@@ -220,7 +224,6 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
// Access to the below members must be protected by |browser_info_lock_|.
typedef std::list<scoped_refptr<CefBrowserInfo> > BrowserInfoList;
BrowserInfoList browser_info_list_;
int next_browser_id_;
......
......@@ -83,9 +83,7 @@ void ChromeBrowserProcessStub::Shutdown() {
profile_manager_.reset();
event_router_forwarder_ = nullptr;
if (component_updater_.get())
component_updater_.reset(NULL);
component_updater_.reset();
shutdown_ = true;
}
......
......@@ -64,6 +64,7 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/storage_quota_params.h"
#include "content/public/common/web_preferences.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
......@@ -516,6 +517,62 @@ bool CefContentBrowserClient::IsHandledURL(const GURL& url) {
return CefContentClient::Get()->HasCustomScheme(scheme);
}
void CefContentBrowserClient::SiteInstanceGotProcess(
content::SiteInstance* site_instance) {
if (!extensions::ExtensionsEnabled())
return;
// If this isn't an extension renderer there's nothing to do.
const extensions::Extension* extension = GetExtension(site_instance);
if (!extension)
return;
CefBrowserContext* browser_context =
static_cast<CefBrowserContext*>(site_instance->GetBrowserContext());
extensions::ProcessMap::Get(browser_context)
->Insert(extension->id(),
site_instance->GetProcess()->GetID(),
site_instance->GetId());
CEF_POST_TASK(CEF_IOT,
base::Bind(&extensions::InfoMap::RegisterExtensionProcess,
browser_context->extension_system()->info_map(),
extension->id(),
site_instance->GetProcess()->GetID(),
site_instance->GetId()));
}
void CefContentBrowserClient::SiteInstanceDeleting(
content::SiteInstance* site_instance) {
if (!extensions::ExtensionsEnabled())
return;
// May be NULL during shutdown.
if (!extensions::ExtensionsBrowserClient::Get())
return;
// If this isn't an extension renderer there's nothing to do.
const extensions::Extension* extension = GetExtension(site_instance);
if (!extension)
return;
CefBrowserContext* browser_context =
static_cast<CefBrowserContext*>(site_instance->GetBrowserContext());
extensions::ProcessMap::Get(browser_context)
->Remove(extension->id(),
site_instance->GetProcess()->GetID(),
site_instance->GetId());
CEF_POST_TASK(CEF_IOT,
base::Bind(&extensions::InfoMap::UnregisterExtensionProcess,
browser_context->extension_system()->info_map(),
extension->id(),
site_instance->GetProcess()->GetID(),
site_instance->GetId()));
}
void CefContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line, int child_process_id) {
const base::CommandLine* browser_cmd =
......@@ -864,3 +921,11 @@ CefContentBrowserClient::browser_context() const {
CefDevToolsDelegate* CefContentBrowserClient::devtools_delegate() const {
return browser_main_parts_->devtools_delegate();
}
const extensions::Extension* CefContentBrowserClient::GetExtension(
content::SiteInstance* site_instance) {
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext());
return registry->enabled_extensions().GetExtensionOrAppByURL(
site_instance->GetSiteURL());
}
......@@ -44,6 +44,8 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
bool ShouldUseProcessPerSite(content::BrowserContext* browser_context,
const GURL& effective_url) override;
bool IsHandledURL(const GURL& url) override;
void SiteInstanceGotProcess(content::SiteInstance* site_instance) override;
void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) override;
content::QuotaPermissionContext*
......@@ -113,6 +115,10 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
CefDevToolsDelegate* devtools_delegate() const;
private:
// Returns the extension or app associated with |site_instance| or NULL.
const extensions::Extension* GetExtension(
content::SiteInstance* site_instance);
CefBrowserMainParts* browser_main_parts_;
std::unique_ptr<content::PluginServiceFilter> plugin_service_filter_;
......
// Copyright (c) 2012 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 "libcef/browser/extensions/api/streams_private/streams_private_api.h"
#include <limits.h>
#include <utility>
#include "base/lazy_instance.h"
#include "base/values.h"
#include "cef/libcef/common/extensions/api/streams_private.h"
#include "content/public/browser/stream_handle.h"
#include "content/public/browser/stream_info.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/common/manifest_handlers/mime_types_handler.h"
#include "net/http/http_response_headers.h"
namespace extensions {
namespace {
void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers,
base::DictionaryValue* result) {
if (!headers)
return;
size_t iter = 0;
std::string header_name;
std::string header_value;
while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
base::Value* existing_value = NULL;
if (result->Get(header_name, &existing_value)) {
base::StringValue* existing_string_value =
static_cast<base::StringValue*>(existing_value);
existing_string_value->GetString()->append(", ").append(header_value);
} else {
result->SetString(header_name, header_value);
}
}
}
} // namespace
namespace streams_private = api::cef::streams_private;
// static
CefStreamsPrivateAPI* CefStreamsPrivateAPI::Get(
content::BrowserContext* context) {
return GetFactoryInstance()->Get(context);
}
CefStreamsPrivateAPI::CefStreamsPrivateAPI(content::BrowserContext* context)
: browser_context_(context),
extension_registry_observer_(this),
weak_ptr_factory_(this) {
extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
}
CefStreamsPrivateAPI::~CefStreamsPrivateAPI() {
}
void CefStreamsPrivateAPI::ExecuteMimeTypeHandler(
const std::string& extension_id,
int tab_id,
std::unique_ptr<content::StreamInfo> stream,
const std::string& view_id,
int64_t expected_content_size,
bool embedded,
int render_process_id,
int render_frame_id) {
const Extension* extension = ExtensionRegistry::Get(browser_context_)
->enabled_extensions()
.GetByID(extension_id);
if (!extension)
return;
MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
// If the mime handler uses MimeHandlerViewGuest, the MimeHandlerViewGuest
// will take ownership of the stream. Otherwise, store the stream handle in
// |streams_| and fire an event notifying the extension.
if (handler->HasPlugin()) {
GURL handler_url(Extension::GetBaseURLFromExtensionId(extension_id).spec() +
handler->handler_url());
std::unique_ptr<StreamContainer> stream_container(new StreamContainer(
std::move(stream), tab_id, embedded, handler_url, extension_id));
MimeHandlerStreamManager::Get(browser_context_)
->AddStream(view_id, std::move(stream_container), render_process_id,
render_frame_id);
return;
}
// Create the event's arguments value.
streams_private::StreamInfo info;
info.mime_type = stream->mime_type;
info.original_url = stream->original_url.spec();
info.stream_url = stream->handle->GetURL().spec();
info.tab_id = tab_id;
info.embedded = embedded;
if (!view_id.empty()) {
info.view_id.reset(new std::string(view_id));
}
int size = -1;
if (expected_content_size <= INT_MAX)
size = expected_content_size;
info.expected_content_size = size;
CreateResponseHeadersDictionary(stream->response_headers.get(),
&info.response_headers.additional_properties);
std::unique_ptr<Event> event(
new Event(events::STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER,
streams_private::OnExecuteMimeTypeHandler::kEventName,
streams_private::OnExecuteMimeTypeHandler::Create(info)));
EventRouter::Get(browser_context_)
->DispatchEventToExtension(extension_id, std::move(event));
GURL url = stream->handle->GetURL();
streams_[extension_id][url] = make_linked_ptr(stream->handle.release());
}
void CefStreamsPrivateAPI::AbortStream(const std::string& extension_id,
const GURL& stream_url,
const base::Closure& callback) {
StreamMap::iterator extension_it = streams_.find(extension_id);
if (extension_it == streams_.end()) {
callback.Run();
return;
}
StreamMap::mapped_type* url_map = &extension_it->second;
StreamMap::mapped_type::iterator url_it = url_map->find(stream_url);
if (url_it == url_map->end()) {
callback.Run();
return;
}
url_it->second->AddCloseListener(callback);
url_map->erase(url_it);
}
void CefStreamsPrivateAPI::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionInfo::Reason reason) {
streams_.erase(extension->id());
}
CefStreamsPrivateAbortFunction::CefStreamsPrivateAbortFunction() {
}
ExtensionFunction::ResponseAction CefStreamsPrivateAbortFunction::Run() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &stream_url_));
CefStreamsPrivateAPI::Get(browser_context())->AbortStream(
extension_id(), GURL(stream_url_), base::Bind(
&CefStreamsPrivateAbortFunction::OnClose, this));
return RespondLater();
}
void CefStreamsPrivateAbortFunction::OnClose() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Respond(NoArguments());
}
static base::LazyInstance<BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI> >
g_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI>*
CefStreamsPrivateAPI::GetFactoryInstance() {
return g_factory.Pointer();
}
} // namespace extensions
// Copyright (c) 2012 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 CEF_LIBCEF_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_
#include <stdint.h>
#include <map>
#include <string>
#include "base/scoped_observer.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry_observer.h"
namespace content {
class BrowserContext;
class StreamHandle;
struct StreamInfo;
}
namespace extensions {
class ExtensionRegistry;
class CefStreamsPrivateAPI : public BrowserContextKeyedAPI,
public ExtensionRegistryObserver {
public:
// Convenience method to get the CefStreamsPrivateAPI for a BrowserContext.
static CefStreamsPrivateAPI* Get(content::BrowserContext* context);
explicit CefStreamsPrivateAPI(content::BrowserContext* context);
~CefStreamsPrivateAPI() override;
// Send the onExecuteMimeTypeHandler event to |extension_id|.
// |tab_id| is used to determine the tabId where the document is being
// opened. The data for the document will be readable from |stream|, and
// should be |expected_content_size| bytes long. If the viewer is being opened
// in a BrowserPlugin, specify a non-empty |view_id| of the plugin. |embedded|
// should be set to whether the document is embedded within another document.
void ExecuteMimeTypeHandler(const std::string& extension_id,
int tab_id,
std::unique_ptr<content::StreamInfo> stream,
const std::string& view_id,
int64_t expected_content_size,
bool embedded,
int render_process_id,
int render_frame_id);
void AbortStream(const std::string& extension_id,
const GURL& stream_url,
const base::Closure& callback);
// BrowserContextKeyedAPI implementation.
static BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI>*
GetFactoryInstance();
private:
friend class BrowserContextKeyedAPIFactory<CefStreamsPrivateAPI>;
typedef std::map<std::string,
std::map<GURL,
linked_ptr<content::StreamHandle> > > StreamMap;
// ExtensionRegistryObserver implementation.
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionInfo::Reason reason) override;
// BrowserContextKeyedAPI implementation.
static const char* service_name() {
return "CefStreamsPrivateAPI";
}
static const bool kServiceIsNULLWhileTesting = true;
static const bool kServiceRedirectedInIncognito = true;
content::BrowserContext* const browser_context_;
StreamMap streams_;
// Listen to extension unloaded notifications.
ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
extension_registry_observer_;
base::WeakPtrFactory<CefStreamsPrivateAPI> weak_ptr_factory_;
};
class CefStreamsPrivateAbortFunction : public UIThreadExtensionFunction {
public:
CefStreamsPrivateAbortFunction();
DECLARE_EXTENSION_FUNCTION("streamsPrivate.abort", STREAMSPRIVATE_ABORT)
protected:
~CefStreamsPrivateAbortFunction() override {}
// ExtensionFunction:
ExtensionFunction::ResponseAction Run() override;
private:
void OnClose();
std::string stream_url_;
};
// For compatibility with generated_api_registration.cc.
typedef CefStreamsPrivateAPI StreamsPrivateAPI;
typedef CefStreamsPrivateAbortFunction StreamsPrivateAbortFunction;
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_
// Copyright (c) 2012 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 "libcef/browser/extensions/api/tabs/tabs_api.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/request_context_impl.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/common/page_zoom.h"
#include "extensions/browser/extension_zoom_request_client.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
namespace cef {
namespace keys = extensions::tabs_constants;
namespace tabs = api::tabs;
namespace {
// Any out parameter (|browser|, |contents|, & |tab_index|) may be NULL and will
// not be set within the function.
// Based on ExtensionTabUtil::GetTabById().
bool GetTabById(int tab_id,
content::BrowserContext* browser_context,
bool include_incognito,
CefRefPtr<CefBrowserHostImpl>* browser,
content::WebContents** contents) {
if (tab_id == api::tabs::TAB_ID_NONE)
return false;
// As an extra security check make sure we're operating in the same
// BrowserContext.
Profile* profile = Profile::FromBrowserContext(browser_context);
Profile* incognito_profile =
include_incognito && profile->HasOffTheRecordProfile() ?
profile->GetOffTheRecordProfile() : NULL;
CefBrowserInfoManager::BrowserInfoList list;
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList(list);
for (auto browser_info : list) {
CefRefPtr<CefBrowserHostImpl> cef_browser = browser_info->browser();
if (!cef_browser)
continue;
CefRefPtr<CefRequestContext> request_context =
cef_browser->GetRequestContext();
if (!request_context)
continue;
CefRefPtr<CefRequestContextImpl> request_context_impl =
CefRequestContextImpl::GetForRequestContext(request_context);
if (!request_context_impl)
continue;
scoped_refptr<CefBrowserContext> browser_context =
request_context_impl->GetBrowserContext();
if (!browser_context)
continue;
if (browser_context == profile ||
browser_context == incognito_profile) {
content::WebContents* web_contents = cef_browser->web_contents();
if (SessionTabHelper::IdForTab(web_contents) == tab_id) {
if (browser)
*browser = cef_browser;
if (contents)
*contents = web_contents;
return true;
}
}
}
return false;
}
// |error_message| can optionally be passed in and will be set with an
// appropriate message if the tab cannot be found by id.
bool GetTabById(int tab_id,
content::BrowserContext* browser_context,
bool include_incognito,
CefRefPtr<CefBrowserHostImpl>* browser,
content::WebContents** contents,
std::string* error_message) {
if (GetTabById(tab_id, browser_context, include_incognito, browser,
contents)) {
return true;
}
if (error_message) {
*error_message = ErrorUtils::FormatErrorMessage(
keys::kTabNotFoundError, base::IntToString(tab_id));
}
return false;
}
void ZoomModeToZoomSettings(zoom::ZoomController::ZoomMode zoom_mode,
api::tabs::ZoomSettings* zoom_settings) {
DCHECK(zoom_settings);
switch (zoom_mode) {
case zoom::ZoomController::ZOOM_MODE_DEFAULT:
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN;
break;
case zoom::ZoomController::ZOOM_MODE_ISOLATED:
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
break;
case zoom::ZoomController::ZOOM_MODE_MANUAL:
zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_MANUAL;
zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
break;
case zoom::ZoomController::ZOOM_MODE_DISABLED: