Add support for loading extensions (issue #1947)

- Add CefRequestContext::LoadExtension, CefExtension, CefExtensionHandler and
  related methods/interfaces.
- Add chrome://extensions-support that lists supported Chrome APIs.
- Add CefBrowserHost::SetAutoResizeEnabled and CefDisplayHandler::OnAutoResize
  to support browser resize based on preferred web contents size.
- views: Add support for custom CefMenuButton popups.
- cefclient: Run with `--load-extension=set_page_color` command-line flag for
  an extension loading example. Add `--use-views` on Windows and Linux for an
  even better example.
This commit is contained in:
Marshall Greenblatt
2017-08-03 18:55:19 -04:00
parent 5b12134a45
commit 9cff99dc4e
178 changed files with 10360 additions and 650 deletions

View File

@ -14,6 +14,7 @@
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "extensions/browser/process_manager.h"
CefBrowserContext::CefBrowserContext(bool is_proxy)
: is_proxy_(is_proxy), extension_system_(NULL) {}
@ -49,6 +50,11 @@ void CefBrowserContext::Initialize() {
extension_system_->InitForRegularProfile(true);
}
resource_context_->set_extensions_info_map(extension_system_->info_map());
// Make sure the ProcessManager is created so that it receives extension
// load notifications. This is necessary for the proper initialization of
// background/event pages.
extensions::ProcessManager::Get(this);
}
}

View File

@ -329,6 +329,11 @@ void CefBrowserContextImpl::AddCefRequestContext(
void CefBrowserContextImpl::RemoveCefRequestContext(
CefRequestContextImpl* context) {
CEF_REQUIRE_UIT();
if (extensions::ExtensionsEnabled()) {
extension_system()->OnRequestContextDeleted(context);
}
request_context_set_.erase(context);
// Delete ourselves when the reference count reaches zero.
@ -382,7 +387,9 @@ CefBrowserContextImpl::CreateZoomLevelDelegate(
}
bool CefBrowserContextImpl::IsOffTheRecord() const {
return cache_path_.empty();
// CEF contexts are never flagged as off-the-record. It causes problems
// for the extension system.
return false;
}
content::DownloadManagerDelegate*

View File

@ -18,6 +18,10 @@
#include "libcef/browser/devtools_frontend.h"
#include "libcef/browser/devtools_manager_delegate.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/extensions/extension_background_host.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/extensions/extension_view_host.h"
#include "libcef/browser/extensions/extension_web_contents_observer.h"
#include "libcef/browser/image_impl.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/navigate_params.h"
@ -35,11 +39,11 @@
#include "libcef/common/main_delegate.h"
#include "libcef/common/process_message_impl.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/values_impl.h"
#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"
@ -66,6 +70,7 @@
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/favicon_url.h"
#include "extensions/browser/process_manager.h"
#include "net/base/net_errors.h"
#include "third_party/WebKit/public/web/WebFindOptions.h"
#include "ui/events/base_event_utils.h"
@ -259,7 +264,7 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
CefBrowserHostImpl::CreateParams create_params;
create_params.window_info.reset(new CefWindowInfo(windowInfo));
create_params.client = client;
create_params.url = url;
create_params.url = GURL(url.ToString());
create_params.settings = settings;
create_params.request_context = request_context;
@ -303,7 +308,40 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
create_params.request_context = request_context_impl.get();
}
content::WebContents::CreateParams wc_create_params(browser_context);
CefRefPtr<CefExtension> cef_extension;
scoped_refptr<content::SiteInstance> site_instance;
if (extensions::ExtensionsEnabled() && !create_params.url.is_empty()) {
if (!create_params.extension) {
// We might be loading an extension app view where the extension URL is
// provided by the client.
create_params.extension =
extensions::GetExtensionForUrl(browser_context, create_params.url);
}
if (create_params.extension) {
cef_extension = browser_context->extension_system()->GetExtension(
create_params.extension->id());
DCHECK(cef_extension);
if (create_params.extension_host_type == extensions::VIEW_TYPE_INVALID) {
// Default to dialog behavior.
create_params.extension_host_type =
extensions::VIEW_TYPE_EXTENSION_DIALOG;
}
// Extension resources will fail to load if we don't use a SiteInstance
// associated with the extension.
// (CefContentBrowserClient::SiteInstanceGotProcess won't find the
// extension to register with InfoMap, and AllowExtensionResourceLoad in
// ExtensionProtocolHandler::MaybeCreateJob will return false resulting in
// ERR_BLOCKED_BY_CLIENT).
site_instance = extensions::ProcessManager::Get(browser_context)
->GetSiteInstanceForURL(create_params.url);
DCHECK(site_instance);
}
}
content::WebContents::CreateParams wc_create_params(browser_context,
site_instance);
if (platform_delegate->IsWindowless()) {
// Create the OSR view for the WebContents.
@ -318,12 +356,21 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
CefRefPtr<CefBrowserHostImpl> browser = CefBrowserHostImpl::CreateInternal(
create_params.settings, create_params.client, web_contents, info,
create_params.devtools_opener, is_devtools_popup,
create_params.request_context, std::move(platform_delegate));
if (browser.get() && !create_params.url.empty()) {
browser->LoadURL(CefFrameHostImpl::kMainFrameId, create_params.url,
create_params.request_context, std::move(platform_delegate),
cef_extension);
if (!browser)
return nullptr;
if (create_params.extension) {
browser->CreateExtensionHost(create_params.extension, browser_context,
web_contents, create_params.url,
create_params.extension_host_type);
} else if (!create_params.url.is_empty()) {
browser->LoadURL(CefFrameHostImpl::kMainFrameId, create_params.url.spec(),
content::Referrer(), ui::PAGE_TRANSITION_TYPED,
std::string());
}
return browser.get();
}
@ -336,7 +383,8 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
CefRefPtr<CefBrowserHostImpl> opener,
bool is_devtools_popup,
CefRefPtr<CefRequestContext> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate) {
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension) {
CEF_REQUIRE_UIT();
DCHECK(web_contents);
DCHECK(browser_info);
@ -363,7 +411,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
CefRefPtr<CefBrowserHostImpl> browser = new CefBrowserHostImpl(
settings, client, web_contents, browser_info, opener, request_context,
std::move(platform_delegate));
std::move(platform_delegate), extension);
if (!browser->CreateHostWindow())
return nullptr;
@ -947,6 +995,35 @@ void CefBrowserHostImpl::SetAccessibilityState(
web_contents_impl->SetAccessibilityMode(accMode);
}
void CefBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
const CefSize& min_size,
const CefSize& max_size) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::Bind(&CefBrowserHostImpl::SetAutoResizeEnabled,
this, enabled, min_size, max_size));
return;
}
if (!web_contents() || !web_contents()->GetRenderViewHost())
return;
if (enabled) {
web_contents()->GetRenderViewHost()->EnableAutoResize(
gfx::Size(min_size.width, min_size.height),
gfx::Size(max_size.width, max_size.height));
} else {
web_contents()->GetRenderViewHost()->DisableAutoResize(gfx::Size());
}
}
CefRefPtr<CefExtension> CefBrowserHostImpl::GetExtension() {
return extension_;
}
bool CefBrowserHostImpl::IsBackgroundHost() {
return is_background_host_;
}
void CefBrowserHostImpl::SetMouseCursorChangeDisabled(bool disabled) {
base::AutoLock lock_scope(state_lock_);
mouse_cursor_change_disabled_ = disabled;
@ -1446,6 +1523,7 @@ void CefBrowserHostImpl::DestroyBrowser() {
javascript_dialog_manager_->Destroy();
if (menu_manager_.get())
menu_manager_->Destroy();
DestroyExtensionHost();
// Notify any observers that may have state associated with this browser.
for (auto& observer : observers_)
@ -1783,6 +1861,13 @@ int CefBrowserHostImpl::browser_id() const {
return browser_info_->browser_id();
}
content::BrowserContext* CefBrowserHostImpl::GetBrowserContext() {
CEF_REQUIRE_UIT();
if (web_contents_)
return web_contents_->GetBrowserContext();
return nullptr;
}
void CefBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
if (CEF_CURRENTLY_ON_UIT()) {
// SetFocus() might be called while inside the OnSetFocus() callback. If so,
@ -2098,6 +2183,26 @@ content::WebContents* CefBrowserHostImpl::OpenURLFromTab(
return nullptr;
}
bool CefBrowserHostImpl::ShouldTransferNavigation(
bool is_main_frame_navigation) {
if (extension_host_) {
return extension_host_->ShouldTransferNavigation(is_main_frame_navigation);
}
return true;
}
void CefBrowserHostImpl::AddNewContents(content::WebContents* source,
content::WebContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
if (extension_host_) {
extension_host_->AddNewContents(source, new_contents, disposition,
initial_rect, user_gesture, was_blocked);
}
}
void CefBrowserHostImpl::LoadingStateChanged(content::WebContents* source,
bool to_different_document) {
int current_index =
@ -2274,6 +2379,14 @@ void CefBrowserHostImpl::HandleKeyboardEvent(
platform_delegate_->HandleKeyboardEvent(event);
}
bool CefBrowserHostImpl::PreHandleGestureEvent(
content::WebContents* source,
const blink::WebGestureEvent& event) {
if (extension_host_)
return extension_host_->PreHandleGestureEvent(source, event);
return false;
}
bool CefBrowserHostImpl::CanDragEnter(content::WebContents* source,
const content::DropData& data,
blink::WebDragOperationsMask mask) {
@ -2334,7 +2447,8 @@ void CefBrowserHostImpl::WebContentsCreated(
CefRefPtr<CefBrowserHostImpl> browser = CefBrowserHostImpl::CreateInternal(
settings, client, new_contents, info, opener, false,
browser_context->GetCefRequestContext(), std::move(platform_delegate));
browser_context->GetCefRequestContext(), std::move(platform_delegate),
nullptr);
}
void CefBrowserHostImpl::DidNavigateMainFramePostCommit(
@ -2379,6 +2493,21 @@ void CefBrowserHostImpl::UpdatePreferredSize(content::WebContents* source,
#endif
}
void CefBrowserHostImpl::ResizeDueToAutoResize(content::WebContents* source,
const gfx::Size& new_size) {
CEF_REQUIRE_UIT();
if (client_) {
CefRefPtr<CefDisplayHandler> handler = client_->GetDisplayHandler();
if (handler && handler->OnAutoResize(
this, CefSize(new_size.width(), new_size.height()))) {
return;
}
}
UpdatePreferredSize(source, new_size);
}
void CefBrowserHostImpl::RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
@ -2444,6 +2573,12 @@ bool CefBrowserHostImpl::CheckMediaAccessPermission(
return command_line->HasSwitch(switches::kEnableMediaStream);
}
bool CefBrowserHostImpl::IsNeverVisible(content::WebContents* web_contents) {
if (extension_host_)
return extension_host_->IsNeverVisible(web_contents);
return false;
}
// content::WebContentsObserver methods.
// -----------------------------------------------------------------------------
@ -2924,7 +3059,8 @@ CefBrowserHostImpl::CefBrowserHostImpl(
scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate)
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension)
: content::WebContentsObserver(web_contents),
settings_(settings),
client_(client),
@ -2949,7 +3085,8 @@ CefBrowserHostImpl::CefBrowserHostImpl(
is_in_onsetfocus_(false),
focus_on_editable_field_(false),
mouse_cursor_change_disabled_(false),
devtools_frontend_(NULL) {
devtools_frontend_(NULL),
extension_(extension) {
if (opener.get() && !platform_delegate_->IsViewsHosted()) {
// GetOpenerWindowHandle() only returns a value for non-views-hosted
// popup browsers.
@ -2986,8 +3123,10 @@ CefBrowserHostImpl::CefBrowserHostImpl(
printing::CefPrintViewManager::CreateForWebContents(web_contents_.get());
if (extensions::ExtensionsEnabled()) {
extensions::CefExtensionWebContentsObserver::CreateForWebContents(
web_contents_.get());
// Used by the tabs extension API.
SessionTabHelper::CreateForWebContents(web_contents_.get());
zoom::ZoomController::CreateForWebContents(web_contents_.get());
}
@ -3009,6 +3148,63 @@ bool CefBrowserHostImpl::CreateHostWindow() {
return success;
}
void CefBrowserHostImpl::CreateExtensionHost(
const extensions::Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
extensions::ViewType host_type) {
DCHECK(!extension_host_);
// Use the *Impl context because ProcessManager expects it for notification
// registration.
CefBrowserContextImpl* impl_context =
CefBrowserContextImpl::GetForContext(browser_context);
if (host_type == extensions::VIEW_TYPE_EXTENSION_DIALOG ||
host_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
// Create an extension host that we own.
extension_host_ = new extensions::CefExtensionViewHost(
this, extension, impl_context, host_contents, url, host_type);
// Trigger load of the extension URL.
extension_host_->CreateRenderViewSoon();
} else if (host_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
is_background_host_ = true;
// Create an extension host that will be owned by ProcessManager.
extension_host_ = new extensions::CefExtensionBackgroundHost(
this, base::BindOnce(&CefBrowserHostImpl::OnExtensionHostDeleted, this),
extension, impl_context, host_contents, url, host_type);
// Load will be triggered by ProcessManager::CreateBackgroundHost.
} else {
NOTREACHED() << " Unsupported extension host type: " << host_type;
}
}
void CefBrowserHostImpl::DestroyExtensionHost() {
if (!extension_host_)
return;
if (extension_host_->extension_host_type() ==
extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
DCHECK(is_background_host_);
// Close notification for background pages arrives via CloseContents.
// The extension host will be deleted by
// ProcessManager::CloseBackgroundHost and OnExtensionHostDeleted will be
// called to notify us.
extension_host_->Close();
} else {
DCHECK(!is_background_host_);
// We own the extension host and must delete it.
delete extension_host_;
extension_host_ = nullptr;
}
}
void CefBrowserHostImpl::OnExtensionHostDeleted() {
DCHECK(is_background_host_);
DCHECK(extension_host_);
extension_host_ = nullptr;
}
CefRefPtr<CefFrame> CefBrowserHostImpl::GetOrCreateFrame(
int64 frame_id,
int64 parent_frame_id,

View File

@ -31,12 +31,18 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/common/view_type.h"
namespace content {
struct DragEventSourceInfo;
class RenderWidgetHostImpl;
} // namespace content
namespace extensions {
class Extension;
class ExtensionHost;
} // namespace extensions
namespace net {
class URLRequest;
}
@ -111,8 +117,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Client implementation. May be nullptr.
CefRefPtr<CefClient> client;
// Initial URL to load. May be empty.
CefString url;
// Initial URL to load. May be empty. If this is a valid extension URL then
// the browser will be created as an app view extension host.
GURL url;
// Browser settings.
CefBrowserSettings settings;
@ -124,6 +131,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Request context to use when creating the browser. If nullptr the global
// request context will be used.
CefRefPtr<CefRequestContext> request_context;
// Used when explicitly creating the browser as an extension host via
// ProcessManager::CreateBackgroundHost.
const extensions::Extension* extension = nullptr;
extensions::ViewType extension_host_type = extensions::VIEW_TYPE_INVALID;
};
// Create a new CefBrowserHostImpl instance.
@ -234,6 +246,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
void DragSourceEndedAt(int x, int y, DragOperationsMask op) override;
CefRefPtr<CefNavigationEntry> GetVisibleNavigationEntry() override;
void SetAccessibilityState(cef_state_t accessibility_state) override;
void SetAutoResizeEnabled(bool enabled,
const CefSize& min_size,
const CefSize& max_size) override;
CefRefPtr<CefExtension> GetExtension() override;
bool IsBackgroundHost() override;
// CefBrowser methods.
CefRefPtr<CefBrowserHost> GetHost() override;
@ -352,6 +369,10 @@ class CefBrowserHostImpl : public CefBrowserHost,
scoped_refptr<CefBrowserInfo> browser_info() const { return browser_info_; }
int browser_id() const;
// Accessors that must be called on the UI thread.
content::BrowserContext* GetBrowserContext();
extensions::ExtensionHost* extension_host() const { return extension_host_; }
void OnSetFocus(cef_focus_source_t source);
// Run the file chooser dialog specified by |params|. Only a single dialog may
@ -382,6 +403,13 @@ class CefBrowserHostImpl : public CefBrowserHost,
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) override;
bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
void AddNewContents(content::WebContents* source,
content::WebContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) override;
void LoadingStateChanged(content::WebContents* source,
bool to_different_document) override;
void CloseContents(content::WebContents* source) override;
@ -402,6 +430,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
void HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
bool PreHandleGestureEvent(content::WebContents* source,
const blink::WebGestureEvent& event) override;
bool CanDragEnter(content::WebContents* source,
const content::DropData& data,
blink::WebDragOperationsMask operations_allowed) override;
@ -440,6 +470,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
bool final_update) override;
void UpdatePreferredSize(content::WebContents* source,
const gfx::Size& pref_size) override;
void ResizeDueToAutoResize(content::WebContents* source,
const gfx::Size& new_size) override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
@ -447,6 +479,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
bool CheckMediaAccessPermission(content::WebContents* web_contents,
const GURL& security_origin,
content::MediaStreamType type) override;
bool IsNeverVisible(content::WebContents* web_contents) override;
// content::WebContentsObserver methods.
using content::WebContentsObserver::BeforeUnloadFired;
@ -504,7 +537,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefRefPtr<CefBrowserHostImpl> opener,
bool is_devtools_popup,
CefRefPtr<CefRequestContext> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate);
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension);
// content::WebContentsObserver::OnMessageReceived() message handlers.
void OnFrameIdentified(int64 frame_id,
@ -533,11 +567,21 @@ class CefBrowserHostImpl : public CefBrowserHost,
scoped_refptr<CefBrowserInfo> browser_info,
CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate);
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
CefRefPtr<CefExtension> extension);
// Give the platform delegate an opportunity to create the host window.
bool CreateHostWindow();
// Create/delete the host for extensions.
void CreateExtensionHost(const extensions::Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
extensions::ViewType host_type);
void DestroyExtensionHost();
void OnExtensionHostDeleted();
// Updates and returns an existing frame or creates a new frame. Pass
// CefFrameHostImpl::kUnspecifiedFrameId for |parent_frame_id| if unknown.
CefRefPtr<CefFrame> GetOrCreateFrame(int64 frame_id,
@ -649,6 +693,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Used to provide unique incremental IDs for each find request.
int find_request_id_counter_ = 0;
// Used when the browser is hosting an extension.
extensions::ExtensionHost* extension_host_ = nullptr;
CefRefPtr<CefExtension> extension_;
bool is_background_host_ = false;
IMPLEMENT_REFCOUNTING(CefBrowserHostImpl);
DISALLOW_COPY_AND_ASSIGN(CefBrowserHostImpl);
};

View File

@ -210,6 +210,9 @@ void CefBrowserMainParts::PostMainMessageLoopRun() {
// NOTE: Destroy objects in reverse order of creation.
CefDevToolsManagerDelegate::StopHttpHandler();
// There should be no additional references to the global CefRequestContext
// during shutdown. Did you forget to release a CefBrowser reference?
DCHECK(global_request_context_->HasOneRef());
global_request_context_ = NULL;
if (extensions::ExtensionsEnabled()) {

View File

@ -11,6 +11,8 @@
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "libcef/browser/extensions/browser_platform_delegate_background.h"
#if defined(OS_WIN)
#include "libcef/browser/native/browser_platform_delegate_native_win.h"
#include "libcef/browser/osr/browser_platform_delegate_osr_win.h"
@ -78,6 +80,13 @@ std::unique_ptr<CefBrowserPlatformDelegate> CefBrowserPlatformDelegate::Create(
if (is_windowless)
return CreateOSRDelegate(std::move(native_delegate));
return std::move(native_delegate);
} else if (create_params.extension_host_type ==
extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
// Creating a background extension host without a window.
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate =
CreateNativeDelegate(CefWindowInfo(), background_color);
return base::MakeUnique<CefBrowserPlatformDelegateBackground>(
std::move(native_delegate));
}
#if defined(USE_AURA)
else {

View File

@ -7,7 +7,7 @@
#include <algorithm>
#include <utility>
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_context_impl.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_info_manager.h"
@ -574,6 +574,10 @@ void CefContentBrowserClient::SiteInstanceDeleting(
if (!extensions::ExtensionsBrowserClient::Get())
return;
// May be NULL during shutdown.
if (!site_instance->HasProcess())
return;
// If this isn't an extension renderer there's nothing to do.
const extensions::Extension* extension = GetExtension(site_instance);
if (!extension)
@ -625,6 +629,13 @@ CefContentBrowserClient::GetExtraServiceManifests() {
});
}
bool CefContentBrowserClient::IsSameBrowserContext(
content::BrowserContext* context1,
content::BrowserContext* context2) {
return CefBrowserContextImpl::GetForContext(context1) ==
CefBrowserContextImpl::GetForContext(context2);
}
void CefContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int child_process_id) {
@ -731,8 +742,9 @@ void CefContentBrowserClient::GetQuotaSettings(
content::BrowserContext* context,
content::StoragePartition* partition,
storage::OptionalQuotaSettingsCallback callback) {
storage::GetNominalDynamicSettings(
partition->GetPath(), context->IsOffTheRecord(), std::move(callback));
const base::FilePath& cache_path = partition->GetPath();
storage::GetNominalDynamicSettings(cache_path, !cache_path.empty(),
std::move(callback));
}
content::MediaObserver* CefContentBrowserClient::GetMediaObserver() {
@ -1015,6 +1027,8 @@ const extensions::Extension* CefContentBrowserClient::GetExtension(
content::SiteInstance* site_instance) {
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext());
if (!registry)
return nullptr;
return registry->enabled_extensions().GetExtensionOrAppByURL(
site_instance->GetSiteURL());
}

View File

@ -53,6 +53,8 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
std::unique_ptr<base::Value> GetServiceManifestOverlay(
base::StringPiece name) override;
std::vector<ServiceManifestInfo> GetExtraServiceManifests() override;
bool IsSameBrowserContext(content::BrowserContext* context1,
content::BrowserContext* context2) override;
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override;

View File

@ -0,0 +1,114 @@
// Copyright (c) 2017 The Chromium Embedded Framework 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/extension_impl.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/request_context_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/values_impl.h"
#include "extensions/common/extension.h"
CefExtensionImpl::CefExtensionImpl(const extensions::Extension* extension,
CefRequestContext* loader_context,
CefRefPtr<CefExtensionHandler> handler)
: id_(extension->id()),
path_(extension->path().value()),
manifest_(
new CefDictionaryValueImpl(extension->manifest()->value()->DeepCopy(),
true,
true)),
loader_context_(loader_context),
handler_(handler) {}
CefString CefExtensionImpl::GetIdentifier() {
return id_;
}
CefString CefExtensionImpl::GetPath() {
return path_;
}
CefRefPtr<CefDictionaryValue> CefExtensionImpl::GetManifest() {
return manifest_;
}
bool CefExtensionImpl::IsSame(CefRefPtr<CefExtension> that) {
CefExtensionImpl* that_impl = static_cast<CefExtensionImpl*>(that.get());
if (!that_impl)
return false;
// Maybe the same object.
if (this == that_impl)
return true;
return id_ == that_impl->id_ && path_ == that_impl->path_ &&
loader_context_ == that_impl->loader_context_;
}
CefRefPtr<CefExtensionHandler> CefExtensionImpl::GetHandler() {
return handler_;
}
CefRefPtr<CefRequestContext> CefExtensionImpl::GetLoaderContext() {
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return nullptr;
}
return loader_context_;
}
bool CefExtensionImpl::IsLoaded() {
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return false;
}
return !unloaded_;
}
void CefExtensionImpl::Unload() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefExtensionImpl::Unload, this));
return;
}
// Will be NULL for internal extensions. They can't be unloaded.
if (!loader_context_)
return;
if (unloaded_)
return;
// CefExtensionHandler callbacks triggered by UnloadExtension may check this
// flag, so set it here.
unloaded_ = true;
const bool result = static_cast<CefRequestContextImpl*>(loader_context_)
->GetBrowserContext()
->extension_system()
->UnloadExtension(id_);
ALLOW_UNUSED_LOCAL(result);
DCHECK(result);
}
void CefExtensionImpl::OnExtensionLoaded() {
CEF_REQUIRE_UIT();
if (handler_)
handler_->OnExtensionLoaded(this);
}
void CefExtensionImpl::OnExtensionUnloaded() {
CEF_REQUIRE_UIT();
// Should not be called for internal extensions.
DCHECK(loader_context_);
unloaded_ = true;
loader_context_ = nullptr;
if (handler_)
handler_->OnExtensionUnloaded(this);
}

View File

@ -0,0 +1,58 @@
// Copyright (c) 2017 The Chromium Embedded Framework 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_EXTENSION_IMPL_H_
#define CEF_LIBCEF_BROWSER_EXTENSION_IMPL_H_
#pragma once
#include <memory>
#include "include/cef_extension.h"
#include "include/cef_extension_handler.h"
#include "include/cef_request_context.h"
namespace extensions {
class Extension;
};
// CefNavigationEntry implementation
class CefExtensionImpl : public CefExtension {
public:
CefExtensionImpl(const extensions::Extension* extension,
CefRequestContext* loader_context,
CefRefPtr<CefExtensionHandler> handler);
// CefExtension methods.
CefString GetIdentifier() override;
CefString GetPath() override;
CefRefPtr<CefDictionaryValue> GetManifest() override;
bool IsSame(CefRefPtr<CefExtension> that) override;
CefRefPtr<CefExtensionHandler> GetHandler() override;
CefRefPtr<CefRequestContext> GetLoaderContext() override;
bool IsLoaded() override;
void Unload() override;
void OnExtensionLoaded();
void OnExtensionUnloaded();
// Use this instead of the GetLoaderContext version during
// CefRequestContext destruction.
CefRequestContext* loader_context() const { return loader_context_; }
private:
CefString id_;
CefString path_;
CefRefPtr<CefDictionaryValue> manifest_;
CefRequestContext* loader_context_;
CefRefPtr<CefExtensionHandler> handler_;
// Only accessed on the UI thread.
bool unloaded_ = false;
IMPLEMENT_REFCOUNTING(CefExtensionImpl);
DISALLOW_COPY_AND_ASSIGN(CefExtensionImpl);
};
#endif // CEF_LIBCEF_BROWSER_EXTENSION_IMPL_H_

View File

@ -1,21 +1,20 @@
// 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.
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// 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 "libcef/browser/extensions/extension_web_contents_observer.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/browser/render_frame_host.h"
#include "content/public/common/page_zoom.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_zoom_request_client.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
@ -24,83 +23,12 @@ namespace cef {
namespace keys = extensions::tabs_constants;
namespace tabs = api::tabs;
using api::extension_types::InjectDetails;
namespace {
const char kNotImplementedError[] = "Not implemented";
// 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::GetOrCreateForRequestContext(request_context);
if (!request_context_impl)
continue;
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);
@ -130,18 +58,172 @@ ExtensionFunction::ResponseAction TabsGetFunction::Run() {
return RespondNow(Error(kNotImplementedError));
}
content::WebContents* ZoomAPIFunction::GetWebContents(int tab_id) {
content::WebContents* web_contents = NULL;
if (tab_id != -1) {
// We assume this call leaves web_contents unchanged if it is unsuccessful.
GetTabById(tab_id, context_, include_incognito(),
NULL /* ignore CefBrowserHostImpl* output */, &web_contents,
&error_);
} else {
// Use the sender as the default.
web_contents = GetSenderWebContents();
ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
: cef_details_(this), execute_tab_id_(-1) {}
ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
bool ExecuteCodeInTabFunction::HasPermission() {
if (Init() == SUCCESS &&
// TODO(devlin/lazyboy): Consider removing the following check as it isn't
// doing anything. The fallback to ExtensionFunction::HasPermission()
// below dictates what this function returns.
extension_->permissions_data()->HasAPIPermissionForTab(
execute_tab_id_, APIPermission::kTab)) {
return true;
}
return web_contents;
return ExtensionFunction::HasPermission();
}
ExecuteCodeFunction::InitResult ExecuteCodeInTabFunction::Init() {
if (init_result_)
return init_result_.value();
// |tab_id| is optional so it's ok if it's not there.
int tab_id = -1;
if (args_->GetInteger(0, &tab_id) && tab_id < 0)
return set_init_result(VALIDATION_FAILURE);
// |details| are not optional.
base::DictionaryValue* details_value = NULL;
if (!args_->GetDictionary(1, &details_value))
return set_init_result(VALIDATION_FAILURE);
std::unique_ptr<InjectDetails> details(new InjectDetails());
if (!InjectDetails::Populate(*details_value, details.get()))
return set_init_result(VALIDATION_FAILURE);
// Find a browser that we can access, or fail with error.
std::string error;
CefRefPtr<CefBrowserHostImpl> browser =
cef_details_.GetBrowserForTabIdFirstTime(tab_id, &error);
if (!browser)
return set_init_result_error(error);
execute_tab_id_ = browser->GetIdentifier();
details_ = std::move(details);
set_host_id(HostID(HostID::EXTENSIONS, extension()->id()));
return set_init_result(SUCCESS);
}
bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
CHECK_GE(execute_tab_id_, 0);
CefRefPtr<CefBrowserHostImpl> browser =
cef_details_.GetBrowserForTabIdAgain(execute_tab_id_, &error_);
if (!browser)
return false;
int frame_id = details_->frame_id ? *details_->frame_id
: ExtensionApiFrameIdMap::kTopFrameId;
content::RenderFrameHost* rfh =
ExtensionApiFrameIdMap::GetRenderFrameHostById(browser->web_contents(),
frame_id);
if (!rfh) {
error_ = ErrorUtils::FormatErrorMessage(keys::kFrameNotFoundError,
base::IntToString(frame_id),
base::IntToString(execute_tab_id_));
return false;
}
// Content scripts declared in manifest.json can access frames at about:-URLs
// if the extension has permission to access the frame's origin, so also allow
// programmatic content scripts at about:-URLs for allowed origins.
GURL effective_document_url(rfh->GetLastCommittedURL());
bool is_about_url = effective_document_url.SchemeIs(url::kAboutScheme);
if (is_about_url && details_->match_about_blank &&
*details_->match_about_blank) {
effective_document_url = GURL(rfh->GetLastCommittedOrigin().Serialize());
}
if (!effective_document_url.is_valid()) {
// Unknown URL, e.g. because no load was committed yet. Allow for now, the
// renderer will check again and fail the injection if needed.
return true;
}
// NOTE: This can give the wrong answer due to race conditions, but it is OK,
// we check again in the renderer.
if (!extension()->permissions_data()->CanAccessPage(
extension(), effective_document_url, execute_tab_id_, &error_)) {
if (is_about_url &&
extension()->permissions_data()->active_permissions().HasAPIPermission(
APIPermission::kTab)) {
error_ = ErrorUtils::FormatErrorMessage(
manifest_errors::kCannotAccessAboutUrl,
rfh->GetLastCommittedURL().spec(),
rfh->GetLastCommittedOrigin().Serialize());
}
return false;
}
return true;
}
ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor() {
CHECK_GE(execute_tab_id_, 0);
CefRefPtr<CefBrowserHostImpl> browser =
cef_details_.GetBrowserForTabIdAgain(execute_tab_id_, &error_);
if (!browser)
return nullptr;
return CefExtensionWebContentsObserver::FromWebContents(
browser->web_contents())
->script_executor();
}
bool ExecuteCodeInTabFunction::IsWebView() const {
return false;
}
const GURL& ExecuteCodeInTabFunction::GetWebViewSrc() const {
return GURL::EmptyGURL();
}
bool ExecuteCodeInTabFunction::LoadFile(const std::string& file) {
if (cef_details_.LoadFile(
file, base::BindOnce(&ExecuteCodeInTabFunction::LoadFileComplete,
this, file))) {
return true;
}
// Default handling.
return ExecuteCodeFunction::LoadFile(file);
}
void ExecuteCodeInTabFunction::LoadFileComplete(
const std::string& file,
std::unique_ptr<std::string> data) {
DidLoadAndLocalizeFile(file, !!data.get(), std::move(data));
}
bool TabsExecuteScriptFunction::ShouldInsertCSS() const {
return false;
}
void TabsExecuteScriptFunction::OnExecuteCodeFinished(
const std::string& error,
const GURL& on_url,
const base::ListValue& result) {
if (error.empty())
SetResult(result.CreateDeepCopy());
ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_url, result);
}
bool TabsInsertCSSFunction::ShouldInsertCSS() const {
return true;
}
ZoomAPIFunction::ZoomAPIFunction() : cef_details_(this) {}
content::WebContents* ZoomAPIFunction::GetWebContents(int tab_id) {
// Find a browser that we can access, or set |error_| and return nullptr.
CefRefPtr<CefBrowserHostImpl> browser =
cef_details_.GetBrowserForTabIdFirstTime(tab_id, &error_);
if (!browser)
return nullptr;
return browser->web_contents();
}
bool TabsSetZoomFunction::RunAsync() {

View File

@ -5,7 +5,10 @@
#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
#include "libcef/browser/extensions/extension_function_details.h"
#include "chrome/common/extensions/api/tabs.h"
#include "extensions/browser/api/execute_code_function.h"
#include "extensions/browser/extension_function.h"
// The contents of this file are extracted from
@ -26,17 +29,72 @@ class TabsGetFunction : public UIThreadExtensionFunction {
DECLARE_EXTENSION_FUNCTION("tabs.get", TABS_GET)
};
// Implement API call tabs.executeScript and tabs.insertCSS.
class ExecuteCodeInTabFunction : public ExecuteCodeFunction {
public:
ExecuteCodeInTabFunction();
protected:
~ExecuteCodeInTabFunction() override;
// ExtensionFunction:
bool HasPermission() override;
// Initializes |execute_tab_id_| and |details_|.
InitResult Init() override;
bool CanExecuteScriptOnPage() override;
ScriptExecutor* GetScriptExecutor() override;
bool IsWebView() const override;
const GURL& GetWebViewSrc() const override;
bool LoadFile(const std::string& file) override;
private:
const CefExtensionFunctionDetails cef_details_;
void LoadFileComplete(const std::string& file,
std::unique_ptr<std::string> data);
// Id of tab which executes code.
int execute_tab_id_;
};
class TabsExecuteScriptFunction : public ExecuteCodeInTabFunction {
protected:
bool ShouldInsertCSS() const override;
private:
~TabsExecuteScriptFunction() override {}
void OnExecuteCodeFinished(const std::string& error,
const GURL& on_url,
const base::ListValue& script_result) override;
DECLARE_EXTENSION_FUNCTION("tabs.executeScript", TABS_EXECUTESCRIPT)
};
class TabsInsertCSSFunction : public ExecuteCodeInTabFunction {
private:
~TabsInsertCSSFunction() override {}
bool ShouldInsertCSS() const override;
DECLARE_EXTENSION_FUNCTION("tabs.insertCSS", TABS_INSERTCSS)
};
class ZoomAPIFunction : public AsyncExtensionFunction {
public:
ZoomAPIFunction();
protected:
~ZoomAPIFunction() override {}
// Gets the WebContents for |tab_id| if it is specified. Otherwise get the
// WebContents for the active tab in the current window. Calling this function
// may set error_.
//
// TODO(...) many other tabs API functions use similar behavior. There should
// be a way to share this implementation somehow.
content::WebContents* GetWebContents(int tab_id);
private:
const CefExtensionFunctionDetails cef_details_;
};
class TabsSetZoomFunction : public ZoomAPIFunction {

View File

@ -4,6 +4,7 @@
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/browser_context_impl.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/extensions/extensions_util.h"
@ -13,6 +14,7 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "extensions/browser/extension_registry.h"
namespace extensions {
@ -130,4 +132,45 @@ CefRefPtr<CefBrowserHostImpl> GetOwnerBrowserForHost(
return browser;
}
CefRefPtr<CefBrowserHostImpl> GetBrowserForTabId(
int tab_id,
content::BrowserContext* browser_context) {
CEF_REQUIRE_UIT();
DCHECK(browser_context);
if (tab_id == -1 || !browser_context)
return nullptr;
CefBrowserContextImpl* browser_context_impl =
CefBrowserContextImpl::GetForContext(browser_context);
CefBrowserInfoManager::BrowserInfoList list;
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList(list);
for (auto browser_info : list) {
CefRefPtr<CefBrowserHostImpl> current_browser = browser_info->browser();
if (current_browser && current_browser->GetIdentifier() == tab_id) {
// Make sure we're operating in the same BrowserContextImpl.
if (CefBrowserContextImpl::GetForContext(
current_browser->GetBrowserContext()) == browser_context_impl) {
return current_browser;
} else {
LOG(WARNING) << "Browser with tabId " << tab_id
<< " cannot be accessed because is uses a different "
"CefRequestContext";
break;
}
}
}
return nullptr;
}
const Extension* GetExtensionForUrl(content::BrowserContext* browser_context,
const GURL& url) {
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
if (!registry)
return nullptr;
std::string extension_id = url.host();
return registry->enabled_extensions().GetByID(extension_id);
}
} // namespace extensions

View File

@ -9,13 +9,18 @@
#include "libcef/browser/browser_host_impl.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
class RenderViewHost;
class WebContents;
}
} // namespace content
namespace extensions {
class Extension;
// Returns the full-page guest WebContents for the specified |owner|, if any.
content::WebContents* GetFullPageGuestForOwnerContents(
content::WebContents* owner);
@ -47,6 +52,18 @@ CefRefPtr<CefBrowserHostImpl> GetOwnerBrowserForHost(
content::RenderFrameHost* host,
bool* is_guest_view);
// Returns the browser matching |tab_id| and |browser_context|. Returns false if
// |tab_id| is -1 or a matching browser cannot be found within
// |browser_context|. Similar in concept to ExtensionTabUtil::GetTabById.
CefRefPtr<CefBrowserHostImpl> GetBrowserForTabId(
int tab_id,
content::BrowserContext* browser_context);
// Returns the extension associated with |url| in |profile|. Returns nullptr
// if the extension does not exist.
const Extension* GetExtensionForUrl(content::BrowserContext* browser_context,
const GURL& url);
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_BROWSER_EXTENSIONS_UTIL_H_

View File

@ -0,0 +1,153 @@
// Copyright 2017 The Chromium Embedded Framework 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/browser_platform_delegate_background.h"
#include <utility>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/thread_util.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
CefBrowserPlatformDelegateBackground::CefBrowserPlatformDelegateBackground(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: native_delegate_(std::move(native_delegate)) {
native_delegate_->set_windowless_handler(this);
}
bool CefBrowserPlatformDelegateBackground::CreateHostWindow() {
// Nothing to do here.
return true;
}
void CefBrowserPlatformDelegateBackground::CloseHostWindow() {
// No host window, so continue browser destruction now. Do it asynchronously
// so the call stack has a chance to unwind.
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::WindowDestroyed, browser_));
}
CefWindowHandle CefBrowserPlatformDelegateBackground::GetHostWindowHandle()
const {
return kNullWindowHandle;
}
SkColor CefBrowserPlatformDelegateBackground::GetBackgroundColor() const {
return native_delegate_->GetBackgroundColor();
}
void CefBrowserPlatformDelegateBackground::WasResized() {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendKeyEvent(
const content::NativeWebKeyboardEvent& event) {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendMouseEvent(
const blink::WebMouseEvent& event) {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendMouseWheelEvent(
const blink::WebMouseWheelEvent& event) {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::SendFocusEvent(bool setFocus) {
// Nothing to do here.
}
gfx::Point CefBrowserPlatformDelegateBackground::GetScreenPoint(
const gfx::Point& view_pt) const {
// Nothing to do here.
return view_pt;
}
void CefBrowserPlatformDelegateBackground::ViewText(const std::string& text) {
native_delegate_->ViewText(text);
}
void CefBrowserPlatformDelegateBackground::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// Nothing to do here.
}
void CefBrowserPlatformDelegateBackground::HandleExternalProtocol(
const GURL& url) {
native_delegate_->HandleExternalProtocol(url);
}
void CefBrowserPlatformDelegateBackground::TranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const {
native_delegate_->TranslateKeyEvent(result, key_event);
}
void CefBrowserPlatformDelegateBackground::TranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp,
int clickCount) const {
native_delegate_->TranslateClickEvent(result, mouse_event, type, mouseUp,
clickCount);
}
void CefBrowserPlatformDelegateBackground::TranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const {
native_delegate_->TranslateMoveEvent(result, mouse_event, mouseLeave);
}
void CefBrowserPlatformDelegateBackground::TranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX,
int deltaY) const {
native_delegate_->TranslateWheelEvent(result, mouse_event, deltaX, deltaY);
}
CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
return native_delegate_->GetEventHandle(event);
}
std::unique_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateBackground::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
std::unique_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateBackground::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();
}
std::unique_ptr<CefMenuRunner>
CefBrowserPlatformDelegateBackground::CreateMenuRunner() {
// No default menu implementation for background browsers.
return nullptr;
}
bool CefBrowserPlatformDelegateBackground::IsWindowless() const {
return false;
}
bool CefBrowserPlatformDelegateBackground::IsViewsHosted() const {
return false;
}
CefWindowHandle CefBrowserPlatformDelegateBackground::GetParentWindowHandle()
const {
return GetHostWindowHandle();
}
gfx::Point CefBrowserPlatformDelegateBackground::GetParentScreenPoint(
const gfx::Point& view) const {
return GetScreenPoint(view);
}

View File

@ -0,0 +1,66 @@
// Copyright 2017 The Chromium Embedded Framework 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_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_
#define CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/native/browser_platform_delegate_native.h"
// Implementation of browser functionality for background script hosts.
class CefBrowserPlatformDelegateBackground
: public CefBrowserPlatformDelegate,
public CefBrowserPlatformDelegateNative::WindowlessHandler {
public:
// Platform-specific behaviors will be delegated to |native_delegate|.
CefBrowserPlatformDelegateBackground(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate);
// CefBrowserPlatformDelegate methods:
bool CreateHostWindow() override;
void CloseHostWindow() override;
CefWindowHandle GetHostWindowHandle() const override;
SkColor GetBackgroundColor() const override;
void WasResized() override;
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;
void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void HandleExternalProtocol(const GURL& url) override;
void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const override;
void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp,
int clickCount) const override;
void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const override;
void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX,
int deltaY) const override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
std::unique_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
override;
std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
bool IsWindowless() const override;
bool IsViewsHosted() const override;
// CefBrowserPlatformDelegateNative::WindowlessHandler methods:
CefWindowHandle GetParentWindowHandle() const override;
gfx::Point GetParentScreenPoint(const gfx::Point& view) const override;
private:
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
};
#endif // CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_

View File

@ -22,23 +22,29 @@ namespace cefimpl = extensions::cef;
#define EXTENSION_FUNCTION_NAME(classname) classname::function_name()
// Maintain the same order as https://developer.chrome.com/extensions/api_index
// so chrome://extensions-support looks nice.
const char* const kSupportedAPIs[] = {
"resourcesPrivate",
EXTENSION_FUNCTION_NAME(ResourcesPrivateGetStringsFunction),
"streamsPrivate",
EXTENSION_FUNCTION_NAME(StreamsPrivateAbortFunction),
"tabs",
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsExecuteScriptFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsInsertCSSFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomSettingsFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomSettingsFunction),
nullptr, // Indicates end of array.
};
// Only add APIs to this list that have been tested in CEF.
// static
bool ChromeFunctionRegistry::IsSupported(const std::string& name) {
static const char* const supported_apis[] = {
"resourcesPrivate",
EXTENSION_FUNCTION_NAME(ResourcesPrivateGetStringsFunction),
"streamsPrivate",
EXTENSION_FUNCTION_NAME(StreamsPrivateAbortFunction),
"tabs",
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomSettingsFunction),
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomSettingsFunction),
};
for (size_t i = 0; i < arraysize(supported_apis); ++i) {
if (name == supported_apis[i])
for (size_t i = 0; kSupportedAPIs[i] != nullptr; ++i) {
if (name == kSupportedAPIs[i])
return true;
}
return false;
@ -49,6 +55,8 @@ bool ChromeFunctionRegistry::IsSupported(const std::string& name) {
void ChromeFunctionRegistry::RegisterAll(ExtensionFunctionRegistry* registry) {
registry->RegisterFunction<ResourcesPrivateGetStringsFunction>();
registry->RegisterFunction<StreamsPrivateAbortFunction>();
registry->RegisterFunction<cefimpl::TabsExecuteScriptFunction>();
registry->RegisterFunction<cefimpl::TabsInsertCSSFunction>();
registry->RegisterFunction<cefimpl::TabsGetFunction>();
registry->RegisterFunction<cefimpl::TabsSetZoomFunction>();
registry->RegisterFunction<cefimpl::TabsGetZoomFunction>();

View File

@ -13,6 +13,9 @@ namespace extensions {
namespace api {
namespace cef {
// Array of currently supported APIs.
extern const char* const kSupportedAPIs[];
class ChromeFunctionRegistry {
public:
static bool IsSupported(const std::string& name);

View File

@ -0,0 +1,46 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2013 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/extension_background_host.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/extensions/extension_host_delegate.h"
#include "base/callback.h"
namespace extensions {
CefExtensionBackgroundHost::CefExtensionBackgroundHost(
CefBrowserHostImpl* browser,
base::OnceClosure deleted_callback,
const Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
ViewType host_type)
: ExtensionHost(new CefExtensionHostDelegate(browser),
extension,
browser_context,
host_contents,
url,
host_type),
deleted_callback_(std::move(deleted_callback)) {
DCHECK(!deleted_callback_.is_null());
// Only used for background pages.
DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
}
CefExtensionBackgroundHost::~CefExtensionBackgroundHost() {
std::move(deleted_callback_).Run();
}
bool CefExtensionBackgroundHost::ShouldTransferNavigation(
bool is_main_frame_navigation) {
// Block navigations that cause the main frame to navigate to non-extension
// content (i.e. to web content).
return !is_main_frame_navigation;
}
} // namespace extensions

View File

@ -0,0 +1,48 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2013 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_EXTENSION_BACKGROUND_HOST_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_BACKGROUND_HOST_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "extensions/browser/extension_host.h"
class CefBrowserHostImpl;
namespace content {
class WebContents;
} // namespace content
namespace extensions {
// The ExtensionHost for a background page. This is a thin wrapper around the
// ExtensionHost base class to support CEF-specific constructor. Object lifespan
// is managed by ProcessManager.
class CefExtensionBackgroundHost : public ExtensionHost {
public:
CefExtensionBackgroundHost(CefBrowserHostImpl* browser,
base::OnceClosure deleted_callback,
const Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
ViewType host_type);
~CefExtensionBackgroundHost() override;
// content::WebContentsDelegate methods:
bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
private:
// Callback that will be executed on host deletion.
base::OnceClosure deleted_callback_;
DISALLOW_COPY_AND_ASSIGN(CefExtensionBackgroundHost);
};
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_BACKGROUND_HOST_H_

View File

@ -0,0 +1,291 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2014 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/extension_function_details.h"
#include "libcef/browser/browser_context_impl.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/thread_util.h"
#include "base/task_scheduler/post_task.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_dispatcher.h"
#include "extensions/common/error_utils.h"
using content::WebContents;
using content::RenderViewHost;
namespace extensions {
namespace keys = extensions::tabs_constants;
namespace {
class CefGetExtensionLoadFileCallbackImpl
: public CefGetExtensionResourceCallback {
public:
CefGetExtensionLoadFileCallbackImpl(
const std::string& file,
CefExtensionFunctionDetails::LoadFileCallback callback)
: file_(file), callback_(std::move(callback)) {}
~CefGetExtensionLoadFileCallbackImpl() {
if (!callback_.is_null()) {
// The callback is still pending. Cancel it now.
if (CEF_CURRENTLY_ON_UIT()) {
RunNow(file_, std::move(callback_), nullptr);
} else {
CEF_POST_TASK(
CEF_UIT,
base::BindOnce(&CefGetExtensionLoadFileCallbackImpl::RunNow, file_,
base::Passed(std::move(callback_)), nullptr));
}
}
}
void Continue(CefRefPtr<CefStreamReader> stream) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
// Always continue asynchronously.
CEF_POST_TASK(
CEF_UIT,
base::BindOnce(&CefGetExtensionLoadFileCallbackImpl::RunNow, file_,
base::Passed(std::move(callback_)), stream));
}
} else {
CEF_POST_TASK(CEF_UIT, base::BindOnce(
&CefGetExtensionLoadFileCallbackImpl::Continue,
this, stream));
}
}
void Cancel() override { Continue(nullptr); }
void Disconnect() { callback_.Reset(); }
private:
static void RunNow(const std::string& file,
CefExtensionFunctionDetails::LoadFileCallback callback,
CefRefPtr<CefStreamReader> stream) {
CEF_REQUIRE_UIT();
if (!stream) {
std::move(callback).Run(nullptr);
return;
}
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(LoadFileFromStream, file, stream), std::move(callback));
}
static std::unique_ptr<std::string> LoadFileFromStream(
const std::string& file,
CefRefPtr<CefStreamReader> stream) {
base::ThreadRestrictions::AssertIOAllowed();
// Move to the end of the stream.
stream->Seek(0, SEEK_END);
const int64 size = stream->Tell();
if (size == 0) {
LOG(WARNING) << "Extension resource " << file << " is empty.";
return nullptr;
}
std::unique_ptr<std::string> result(new std::string());
result->resize(size);
// Move to the beginning of the stream.
stream->Seek(0, SEEK_SET);
// Read all stream contents into the string.
int64 read, offset = 0;
do {
read =
static_cast<int>(stream->Read(&(*result)[offset], 1, size - offset));
offset += read;
} while (read > 0 && offset < size);
if (offset != size) {
LOG(WARNING) << "Extension resource " << file << " read failed; expected "
<< size << ", got " << offset << " bytes.";
return nullptr;
}
return result;
}
const std::string file_;
CefExtensionFunctionDetails::LoadFileCallback callback_;
IMPLEMENT_REFCOUNTING(CefGetExtensionLoadFileCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefGetExtensionLoadFileCallbackImpl);
};
} // namespace
CefExtensionFunctionDetails::CefExtensionFunctionDetails(
UIThreadExtensionFunction* function)
: function_(function) {}
CefExtensionFunctionDetails::~CefExtensionFunctionDetails() {}
Profile* CefExtensionFunctionDetails::GetProfile() const {
return Profile::FromBrowserContext(function_->browser_context());
}
CefRefPtr<CefBrowserHostImpl> CefExtensionFunctionDetails::GetSenderBrowser()
const {
content::WebContents* web_contents = function_->GetSenderWebContents();
if (web_contents)
return CefBrowserHostImpl::GetBrowserForContents(web_contents);
return nullptr;
}
CefRefPtr<CefBrowserHostImpl> CefExtensionFunctionDetails::GetCurrentBrowser()
const {
// Start with the browser hosting the extension.
CefRefPtr<CefBrowserHostImpl> browser = GetSenderBrowser();
if (browser && browser->client()) {
CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
if (handler) {
// Give the handler an opportunity to specify a different browser.
CefRefPtr<CefBrowser> active_browser = handler->GetActiveBrowser(
GetCefExtension(), browser.get(), function_->include_incognito());
if (active_browser && active_browser != browser) {
CefRefPtr<CefBrowserHostImpl> active_browser_impl =
static_cast<CefBrowserHostImpl*>(active_browser.get());
// Make sure we're operating in the same BrowserContextImpl.
if (CefBrowserContextImpl::GetForContext(
browser->GetBrowserContext()) ==
CefBrowserContextImpl::GetForContext(
active_browser_impl->GetBrowserContext())) {
browser = active_browser_impl;
} else {
LOG(WARNING) << "Browser with tabId "
<< active_browser->GetIdentifier()
<< " cannot be accessed because is uses a different "
"CefRequestContext";
}
}
}
}
// May be null during startup/shutdown.
return browser;
}
bool CefExtensionFunctionDetails::CanAccessBrowser(
CefRefPtr<CefBrowserHostImpl> target) const {
DCHECK(target);
// Start with the browser hosting the extension.
CefRefPtr<CefBrowserHostImpl> browser = GetSenderBrowser();
if (browser == target) {
// A sender can always access itself.
return true;
}
if (browser && browser->client()) {
CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
if (handler) {
return handler->CanAccessBrowser(GetCefExtension(), browser.get(),
function_->include_incognito(), target);
}
}
// Default to allowing access.
return true;
}
CefRefPtr<CefBrowserHostImpl>
CefExtensionFunctionDetails::GetBrowserForTabIdFirstTime(
int tab_id,
std::string* error_message) const {
DCHECK_GE(tab_id, -1);
DCHECK(!get_browser_called_first_time_);
get_browser_called_first_time_ = true;
CefRefPtr<CefBrowserHostImpl> browser;
if (tab_id != -1) {
// May be an invalid tabId or in the wrong BrowserContext.
browser = GetBrowserForTabId(tab_id, function_->browser_context());
if (!browser || !browser->web_contents() || !CanAccessBrowser(browser)) {
if (error_message) {
*error_message = ErrorUtils::FormatErrorMessage(
keys::kTabNotFoundError, base::IntToString(tab_id));
}
return nullptr;
}
} else {
// May return NULL during shutdown.
browser = GetCurrentBrowser();
if (!browser || !browser->web_contents()) {
if (error_message) {
*error_message = keys::kNoCurrentWindowError;
}
return nullptr;
}
}
return browser;
}
CefRefPtr<CefBrowserHostImpl>
CefExtensionFunctionDetails::GetBrowserForTabIdAgain(
int tab_id,
std::string* error_message) const {
DCHECK_GE(tab_id, 0);
DCHECK(get_browser_called_first_time_);
// May return NULL during shutdown.
CefRefPtr<CefBrowserHostImpl> browser =
GetBrowserForTabId(tab_id, function_->browser_context());
if (!browser || !browser->web_contents()) {
if (error_message) {
*error_message = ErrorUtils::FormatErrorMessage(
keys::kTabNotFoundError, base::IntToString(tab_id));
}
}
return browser;
}
bool CefExtensionFunctionDetails::LoadFile(const std::string& file,
LoadFileCallback callback) const {
// Start with the browser hosting the extension.
CefRefPtr<CefBrowserHostImpl> browser = GetSenderBrowser();
if (browser && browser->client()) {
CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
if (handler) {
CefRefPtr<CefGetExtensionLoadFileCallbackImpl> cef_callback(
new CefGetExtensionLoadFileCallbackImpl(file, std::move(callback)));
if (handler->GetExtensionResource(GetCefExtension(), browser.get(), file,
cef_callback)) {
return true;
}
cef_callback->Disconnect();
}
}
return false;
}
CefRefPtr<CefExtension> CefExtensionFunctionDetails::GetCefExtension() const {
if (!cef_extension_) {
cef_extension_ =
static_cast<CefBrowserContext*>(function_->browser_context())
->extension_system()
->GetExtension(function_->extension_id());
DCHECK(cef_extension_);
}
return cef_extension_;
}
} // namespace extensions

View File

@ -0,0 +1,114 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2014 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_EXTENSION_FUNCTION_DETAILS_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DETAILS_H_
#include "libcef/browser/browser_host_impl.h"
#include "include/cef_extension.h"
#include "base/callback_forward.h"
#include "base/macros.h"
#include "ui/gfx/native_widget_types.h"
class Profile;
class UIThreadExtensionFunction;
namespace content {
class WebContents;
}
namespace extensions {
// Provides CEF-specific details to UIThreadExtensionFunction implementations.
// Based on chrome/browser/extensions/chrome_extension_function_details.h.
class CefExtensionFunctionDetails {
public:
// Constructs a new ChromeExtensionFunctionDetails instance for |function|.
// This instance does not own |function| and must outlive it.
explicit CefExtensionFunctionDetails(UIThreadExtensionFunction* function);
~CefExtensionFunctionDetails();
Profile* GetProfile() const;
// Get the "sender" browser that is hosting the extension. May return NULL
// during startup/shutdown.
CefRefPtr<CefBrowserHostImpl> GetSenderBrowser() const;
// Get the "current" browser that will be acted on by this extension function,
// if any. When mapping from a tabId use the GetBrowserForTabId* methods
// instead of calling this method directly.
//
// Many extension APIs operate relative to the browser that the calling code
// is running inside of. For example, popups and tabs all have a containing
// browser, but background pages and notification bubbles do not. Other APIs,
// like chrome.tabs.*, can act on either a specific browser (specified via the
// tabId parameter) or should allow the client to determine the most
// appropriate browser (for example, the browser that representing the
// foreground window).
//
// Incognito browsers should not be considered unless the calling extension
// has incognito access enabled. CEF does not internally enforce incognito
// status so we pass this flag to client callbacks for consideration.
//
// This method can return NULL if there is no matching browser, which can
// happen if only incognito windows are open, or early in startup or shutdown
// shutdown when there are no active windows.
CefRefPtr<CefBrowserHostImpl> GetCurrentBrowser() const;
// Returns true if the sender browser can access |target|. When mapping from a
// tabId use the GetBrowserForTabId* methods instead of calling this method
// directly.
bool CanAccessBrowser(CefRefPtr<CefBrowserHostImpl> target) const;
// Returns the browser matching |tab_id| or NULL if the browser cannot be
// found or does not have a WebContents. If |tab_id| is -1 the "current"
// browser will be returned. |error_message| can optionally be passed in and
// will be set with an appropriate message on error. This method should only
// be called one time per extension function and will check all necessary
// client permissions.
CefRefPtr<CefBrowserHostImpl> GetBrowserForTabIdFirstTime(
int tab_id,
std::string* error_message) const;
// Returns the browser matching |tab_id| or NULL if the browser cannot be
// found or does not have a WebContents. |tab_id| must be >= 0.
// |error_message| can optionally be passed in and will be set with an
// appropriate message on error. This method should be called only after
// GetBrowserForTabIdFirstTime() has succeeded for the same |tab_id|.
CefRefPtr<CefBrowserHostImpl> GetBrowserForTabIdAgain(
int tab_id,
std::string* error_message) const;
// Give the client a chance to handle |file|. |callback| will be executed
// once the file contents have been loaded. Returns false if the file is
// unhandled.
using LoadFileCallback =
base::OnceCallback<void(std::unique_ptr<std::string>)>;
bool LoadFile(const std::string& file, LoadFileCallback callback) const;
// Returns a pointer to the associated UIThreadExtensionFunction
UIThreadExtensionFunction* function() { return function_; }
const UIThreadExtensionFunction* function() const { return function_; }
protected:
CefRefPtr<CefExtension> GetCefExtension() const;
private:
// The function for which these details have been created. Must outlive the
// CefExtensionFunctionDetails instance.
UIThreadExtensionFunction* function_;
mutable CefRefPtr<CefExtension> cef_extension_;
// Verifies correct usage of GetBrowserForTabId* methods.
mutable bool get_browser_called_first_time_ = false;
DISALLOW_COPY_AND_ASSIGN(CefExtensionFunctionDetails);
};
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DETAILS_H_

View File

@ -0,0 +1,63 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2014 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/extension_host_delegate.h"
#include "libcef/browser/extensions/extensions_browser_client.h"
#include "base/logging.h"
namespace extensions {
CefExtensionHostDelegate::CefExtensionHostDelegate(
CefBrowserHostImpl* browser) {}
CefExtensionHostDelegate::~CefExtensionHostDelegate() {}
void CefExtensionHostDelegate::OnExtensionHostCreated(
content::WebContents* web_contents) {}
void CefExtensionHostDelegate::OnRenderViewCreatedForBackgroundPage(
ExtensionHost* host) {}
content::JavaScriptDialogManager*
CefExtensionHostDelegate::GetJavaScriptDialogManager() {
// Never routed here from CefBrowserHostImpl.
NOTREACHED();
return NULL;
}
void CefExtensionHostDelegate::CreateTab(content::WebContents* web_contents,
const std::string& extension_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture) {
// TODO(cef): Add support for extensions opening popup windows.
NOTIMPLEMENTED();
}
void CefExtensionHostDelegate::ProcessMediaAccessRequest(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
const Extension* extension) {
// Never routed here from CefBrowserHostImpl.
NOTREACHED();
}
bool CefExtensionHostDelegate::CheckMediaAccessPermission(
content::WebContents* web_contents,
const GURL& security_origin,
content::MediaStreamType type,
const Extension* extension) {
// Never routed here from CefBrowserHostImpl.
NOTREACHED();
return false;
}
ExtensionHostQueue* CefExtensionHostDelegate::GetExtensionHostQueue() const {
return CefExtensionsBrowserClient::Get()->GetExtensionHostQueue();
}
} // namespace extensions

View File

@ -0,0 +1,45 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2014 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 LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_
#define LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_
#include "base/macros.h"
#include "extensions/browser/extension_host_delegate.h"
class CefBrowserHostImpl;
namespace extensions {
class CefExtensionHostDelegate : public ExtensionHostDelegate {
public:
explicit CefExtensionHostDelegate(CefBrowserHostImpl* browser);
~CefExtensionHostDelegate() override;
// ExtensionHostDelegate implementation.
void OnExtensionHostCreated(content::WebContents* web_contents) override;
void OnRenderViewCreatedForBackgroundPage(ExtensionHost* host) override;
content::JavaScriptDialogManager* GetJavaScriptDialogManager() override;
void CreateTab(content::WebContents* web_contents,
const std::string& extension_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture) override;
void ProcessMediaAccessRequest(content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
const Extension* extension) override;
bool CheckMediaAccessPermission(content::WebContents* web_contents,
const GURL& security_origin,
content::MediaStreamType type,
const Extension* extension) override;
ExtensionHostQueue* GetExtensionHostQueue() const override;
private:
DISALLOW_COPY_AND_ASSIGN(CefExtensionHostDelegate);
};
} // namespace extensions
#endif // LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_

View File

@ -7,7 +7,9 @@
#include <string>
#include "libcef/browser/extension_impl.h"
#include "libcef/browser/extensions/pdf_extension_util.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/extensions/extensions_util.h"
#include "base/command_line.h"
@ -17,6 +19,7 @@
#include "base/path_service.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/common/chrome_paths.h"
#include "components/crx_file/id_util.h"
@ -53,18 +56,9 @@ namespace extensions {
namespace {
std::string GenerateId(const base::DictionaryValue* manifest,
const base::FilePath& path) {
std::string raw_key;
std::string id_input;
CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key));
CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input));
std::string id = crx_file::id_util::GenerateId(id_input);
return id;
}
// Implementation based on ComponentLoader::ParseManifest.
base::DictionaryValue* ParseManifest(const std::string& manifest_contents) {
std::unique_ptr<base::DictionaryValue> ParseManifest(
const std::string& manifest_contents) {
JSONStringValueDeserializer deserializer(manifest_contents);
std::unique_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL));
@ -73,7 +67,81 @@ base::DictionaryValue* ParseManifest(const std::string& manifest_contents) {
return NULL;
}
// Transfer ownership to the caller.
return static_cast<base::DictionaryValue*>(manifest.release());
return base::WrapUnique(
static_cast<base::DictionaryValue*>(manifest.release()));
}
void ExecuteLoadFailure(CefRefPtr<CefExtensionHandler> handler,
cef_errorcode_t result) {
if (!handler)
return;
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(ExecuteLoadFailure, handler, result));
return;
}
handler->OnExtensionLoadFailed(result);
}
void LoadExtensionOnUIThread(base::WeakPtr<CefExtensionSystem> context,
std::unique_ptr<base::DictionaryValue> manifest,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(LoadExtensionOnUIThread, context,
base::Passed(std::move(manifest)),
root_directory, internal,
loader_context, handler));
return;
}
if (context) {
context->LoadExtension(std::move(manifest), root_directory, internal,
loader_context, handler);
}
}
void LoadExtensionWithManifest(base::WeakPtr<CefExtensionSystem> context,
const std::string& manifest_contents,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
base::ThreadRestrictions::AssertIOAllowed();
std::unique_ptr<base::DictionaryValue> manifest =
ParseManifest(manifest_contents);
if (!manifest) {
LOG(WARNING) << "Failed to parse extension manifest";
ExecuteLoadFailure(handler, ERR_INVALID_ARGUMENT);
return;
}
LoadExtensionOnUIThread(context, std::move(manifest), root_directory,
internal, loader_context, handler);
}
void LoadExtensionFromDisk(base::WeakPtr<CefExtensionSystem> context,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
base::ThreadRestrictions::AssertIOAllowed();
base::FilePath manifest_path = root_directory.AppendASCII("manifest.json");
std::string manifest_contents;
if (!base::ReadFileToString(manifest_path, &manifest_contents)) {
LOG(WARNING) << "Failed to read extension manifest from "
<< manifest_path.MaybeAsASCII();
ExecuteLoadFailure(handler, ERR_FILE_NOT_FOUND);
return;
}
LoadExtensionWithManifest(context, manifest_contents, root_directory,
internal, loader_context, handler);
}
} // namespace
@ -110,7 +178,7 @@ void CefExtensionSystem::Init() {
content::Source<BrowserContext>(browser_context_),
content::NotificationService::NoDetails());
// Add the built-in PDF extension. PDF loading works as follows:
// Add the internal PDF extension. PDF loading works as follows:
// 1. PDF PPAPI plugin is registered to handle kPDFPluginOutOfProcessMimeType
// in libcef/common/content_client.cc ComputeBuiltInPlugins.
// 2. PDF extension is registered and associated with the "application/pdf"
@ -153,40 +221,139 @@ void CefExtensionSystem::Init() {
// CefExtensionWebContentsObserver::RenderViewCreated in the browser
// process.
if (PdfExtensionEnabled()) {
AddExtension(pdf_extension_util::GetManifest(),
base::FilePath(FILE_PATH_LITERAL("pdf")));
LoadExtension(pdf_extension_util::GetManifest(),
base::FilePath(FILE_PATH_LITERAL("pdf")), true /* internal */,
nullptr, nullptr);
}
initialized_ = true;
}
// Implementation based on ComponentLoader::Add.
const Extension* CefExtensionSystem::AddExtension(
void CefExtensionSystem::LoadExtension(
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
CEF_REQUIRE_UIT();
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(LoadExtensionFromDisk, weak_ptr_factory_.GetWeakPtr(),
root_directory, internal, loader_context, handler));
}
void CefExtensionSystem::LoadExtension(
const std::string& manifest_contents,
const base::FilePath& root_directory) {
base::DictionaryValue* manifest = ParseManifest(manifest_contents);
if (!manifest)
return NULL;
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
CEF_REQUIRE_UIT();
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(LoadExtensionWithManifest, weak_ptr_factory_.GetWeakPtr(),
manifest_contents, root_directory, internal,
loader_context, handler));
}
ComponentExtensionInfo info(manifest, root_directory);
const Extension* extension = LoadExtension(info);
delete manifest;
// Implementation based on ComponentLoader::Add.
void CefExtensionSystem::LoadExtension(
std::unique_ptr<base::DictionaryValue> manifest,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
CEF_REQUIRE_UIT();
return extension;
// Internal extensions don't have a loader context. External extensions should.
#if DCHECK_IS_ON()
if (internal) {
DCHECK(!loader_context);
} else {
DCHECK(loader_context);
}
#endif
ComponentExtensionInfo info(manifest.get(), root_directory, internal);
const Extension* extension = LoadExtension(info, loader_context, handler);
if (!extension)
ExecuteLoadFailure(handler, ERR_FAILED);
}
// Implementation based on ExtensionService::RemoveComponentExtension.
void CefExtensionSystem::RemoveExtension(const std::string& extension_id) {
bool CefExtensionSystem::UnloadExtension(const std::string& extension_id) {
CEF_REQUIRE_UIT();
ExtensionMap::iterator it = extension_map_.find(extension_id);
if (it == extension_map_.end()) {
// No CEF representation so we've already unloaded it.
return false;
}
CefRefPtr<CefExtensionImpl> cef_extension =
static_cast<CefExtensionImpl*>(it->second.get());
// Erase first so that callbacks can't retrieve the unloaded extension.
extension_map_.erase(it);
cef_extension->OnExtensionUnloaded();
scoped_refptr<const Extension> extension(
registry_->enabled_extensions().GetByID(extension_id));
registry_->GetInstalledExtension(extension_id));
UnloadExtension(extension_id, UnloadedExtensionReason::UNINSTALL);
if (extension.get()) {
registry_->TriggerOnUninstalled(
extension.get(), extensions::UNINSTALL_REASON_COMPONENT_REMOVED);
}
return true;
}
void CefExtensionSystem::Shutdown() {}
bool CefExtensionSystem::HasExtension(const std::string& extension_id) const {
return !!GetExtension(extension_id);
}
CefRefPtr<CefExtension> CefExtensionSystem::GetExtension(
const std::string& extension_id) const {
CEF_REQUIRE_UIT();
ExtensionMap::const_iterator it = extension_map_.find(extension_id);
if (it != extension_map_.end())
return it->second;
return nullptr;
}
CefExtensionSystem::ExtensionMap CefExtensionSystem::GetExtensions() const {
CEF_REQUIRE_UIT();
return extension_map_;
}
void CefExtensionSystem::OnRequestContextDeleted(CefRequestContext* context) {
CEF_REQUIRE_UIT();
DCHECK(context);
// Make a copy of the map because UnloadExtension will modify it.
// Don't add any references to |context|.
ExtensionMap map = extension_map_;
ExtensionMap::const_iterator it = map.begin();
for (; it != map.end(); ++it) {
CefRefPtr<CefExtensionImpl> cef_extension =
static_cast<CefExtensionImpl*>(it->second.get());
if (cef_extension->loader_context() == context)
UnloadExtension(it->first);
}
}
void CefExtensionSystem::Shutdown() {
CEF_REQUIRE_UIT();
// Only internal extensions should exist at this point.
#if DCHECK_IS_ON()
ExtensionMap::iterator it = extension_map_.begin();
for (; it != extension_map_.end(); ++it) {
CefRefPtr<CefExtensionImpl> cef_extension =
static_cast<CefExtensionImpl*>(it->second.get());
DCHECK(!cef_extension->loader_context());
}
#endif
extension_map_.clear();
}
void CefExtensionSystem::InitForRegularProfile(bool extensions_enabled) {
DCHECK(!initialized_);
@ -289,15 +456,15 @@ void CefExtensionSystem::InstallUpdate(const std::string& extension_id,
CefExtensionSystem::ComponentExtensionInfo::ComponentExtensionInfo(
const base::DictionaryValue* manifest,
const base::FilePath& directory)
: manifest(manifest), root_directory(directory) {
const base::FilePath& directory,
bool internal)
: manifest(manifest), root_directory(directory), internal(internal) {
if (!root_directory.IsAbsolute()) {
// This path structure is required by
// url_request_util::MaybeCreateURLRequestResourceBundleJob.
CHECK(PathService::Get(chrome::DIR_RESOURCES, &root_directory));
root_directory = root_directory.Append(directory);
}
extension_id = GenerateId(manifest, root_directory);
}
// Implementation based on ComponentLoader::CreateExtension.
@ -306,24 +473,45 @@ scoped_refptr<const Extension> CefExtensionSystem::CreateExtension(
std::string* utf8_error) {
// TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
// our component extensions to the new manifest version.
int flags = Extension::REQUIRE_KEY;
return Extension::Create(info.root_directory, Manifest::COMPONENT,
*info.manifest, flags, utf8_error);
int flags = 0;
if (info.internal) {
// Internal extensions must have kPublicKey in the manifest.
flags |= Extension::REQUIRE_KEY;
}
return Extension::Create(
info.root_directory,
info.internal ? Manifest::COMPONENT : Manifest::COMMAND_LINE,
*info.manifest, flags, utf8_error);
}
// Implementation based on ComponentLoader::Load and
// ExtensionService::AddExtension.
const Extension* CefExtensionSystem::LoadExtension(
const ComponentExtensionInfo& info) {
const ComponentExtensionInfo& info,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler) {
std::string error;
scoped_refptr<const Extension> extension(CreateExtension(info, &error));
if (!extension.get()) {
LOG(ERROR) << error;
return NULL;
return nullptr;
}
CHECK_EQ(info.extension_id, extension->id()) << extension->name();
if (registry_->GetInstalledExtension(extension->id())) {
LOG(ERROR) << "Extension with id " << extension->id()
<< "is already installed";
return nullptr;
}
CefRefPtr<CefExtensionImpl> cef_extension =
new CefExtensionImpl(extension.get(), loader_context.get(), handler);
// Insert first so that callbacks can retrieve the loaded extension.
extension_map_.insert(std::make_pair(extension->id(), cef_extension));
cef_extension->OnExtensionLoaded();
// This may trigger additional callbacks.
registry_->AddEnabled(extension.get());
NotifyExtensionLoaded(extension.get());

View File

@ -6,7 +6,11 @@
#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_H_
#include <vector>
#include <map>
#include <memory>
#include "include/cef_extension_handler.h"
#include "include/cef_request_context.h"
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
@ -16,8 +20,9 @@
class BrowserContextKeyedServiceFactory;
namespace base {
class DictionaryValue;
class FilePath;
}
} // namespace base
namespace content {
class BrowserContext;
@ -41,13 +46,43 @@ class CefExtensionSystem : public ExtensionSystem {
// Initializes the extension system.
void Init();
// Add an extension. Returns the new Extension object on success or NULL on
// failure.
const Extension* AddExtension(const std::string& manifest_contents,
const base::FilePath& root_directory);
// Load an extension. For internal (built-in) extensions set |internal| to
// true and |loader_context| and |handler| to NULL. For external extensions
// set |internal| to false and |loader_context| must be the request context
// that loaded the extension. |handler| is optional for internal extensions
// and, if specified, will receive extension-related callbacks.
void LoadExtension(const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler);
void LoadExtension(const std::string& manifest_contents,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler);
void LoadExtension(std::unique_ptr<base::DictionaryValue> manifest,
const base::FilePath& root_directory,
bool internal,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler);
// Remove an extension.
void RemoveExtension(const std::string& extension_id);
// Unload the external extension identified by |extension_id|.
bool UnloadExtension(const std::string& extension_id);
// Returns true if an extension matching |extension_id| is loaded.
bool HasExtension(const std::string& extension_id) const;
// Returns the loaded extention matching |extension_id| or NULL if not found.
CefRefPtr<CefExtension> GetExtension(const std::string& extension_id) const;
using ExtensionMap = std::map<std::string, CefRefPtr<CefExtension>>;
// Returns the map of all loaded extensions.
ExtensionMap GetExtensions() const;
// Called when a request context is deleted. Unregisters any external
// extensions that were registered with this context.
void OnRequestContextDeleted(CefRequestContext* context);
// KeyedService implementation:
void Shutdown() override;
@ -84,7 +119,8 @@ class CefExtensionSystem : public ExtensionSystem {
// Information about a registered component extension.
struct ComponentExtensionInfo {
ComponentExtensionInfo(const base::DictionaryValue* manifest,
const base::FilePath& root_directory);
const base::FilePath& root_directory,
bool internal);
// The parsed contents of the extensions's manifest file.
const base::DictionaryValue* manifest;
@ -92,8 +128,8 @@ class CefExtensionSystem : public ExtensionSystem {
// Directory where the extension is stored.
base::FilePath root_directory;
// The component extension's ID.
std::string extension_id;
// True if the extension is an internal (built-in) component.
bool internal;
};
scoped_refptr<const Extension> CreateExtension(
@ -101,7 +137,9 @@ class CefExtensionSystem : public ExtensionSystem {
std::string* utf8_error);
// Loads a registered component extension.
const Extension* LoadExtension(const ComponentExtensionInfo& info);
const Extension* LoadExtension(const ComponentExtensionInfo& info,
CefRefPtr<CefRequestContext> loader_context,
CefRefPtr<CefExtensionHandler> handler);
// Unload the specified extension.
void UnloadExtension(const std::string& extension_id,
@ -141,6 +179,9 @@ class CefExtensionSystem : public ExtensionSystem {
// ExtensionSystem, and thus us.
extensions::RendererStartupHelper* renderer_helper_;
// Map of extension ID to CEF extension object.
ExtensionMap extension_map_;
// Must be the last member.
base::WeakPtrFactory<CefExtensionSystem> weak_ptr_factory_;

View File

@ -0,0 +1,97 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2013 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/extension_view_host.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/extensions/extension_host_delegate.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/notification_types.h"
#include "extensions/browser/runtime_data.h"
#include "third_party/WebKit/public/platform/WebGestureEvent.h"
using content::NativeWebKeyboardEvent;
using content::OpenURLParams;
using content::WebContents;
using content::WebContentsObserver;
namespace extensions {
CefExtensionViewHost::CefExtensionViewHost(
CefBrowserHostImpl* browser,
const Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
ViewType host_type)
: ExtensionHost(new CefExtensionHostDelegate(browser),
extension,
browser_context,
host_contents,
url,
host_type) {
// Only used for dialogs and popups.
DCHECK(host_type == VIEW_TYPE_EXTENSION_DIALOG ||
host_type == VIEW_TYPE_EXTENSION_POPUP);
}
CefExtensionViewHost::~CefExtensionViewHost() {}
void CefExtensionViewHost::OnDidStopFirstLoad() {
// Nothing to do here, but don't call the base class method.
}
void CefExtensionViewHost::LoadInitialURL() {
if (!ExtensionSystem::Get(browser_context())
->runtime_data()
->IsBackgroundPageReady(extension())) {
// Make sure the background page loads before any others.
registrar_.Add(this,
extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
content::Source<Extension>(extension()));
return;
}
ExtensionHost::LoadInitialURL();
}
bool CefExtensionViewHost::IsBackgroundPage() const {
return false;
}
bool CefExtensionViewHost::ShouldTransferNavigation(
bool is_main_frame_navigation) {
// Block navigations that cause the main frame to navigate to non-extension
// content (i.e. to web content).
return !is_main_frame_navigation;
}
bool CefExtensionViewHost::PreHandleGestureEvent(
content::WebContents* source,
const blink::WebGestureEvent& event) {
// Disable pinch zooming.
return blink::WebInputEvent::IsPinchGestureEventType(event.GetType());
}
WebContents* CefExtensionViewHost::GetVisibleWebContents() const {
if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP)
return host_contents();
return nullptr;
}
void CefExtensionViewHost::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(type, extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY);
DCHECK(ExtensionSystem::Get(browser_context())
->runtime_data()
->IsBackgroundPageReady(extension()));
LoadInitialURL();
}
} // namespace extensions

View File

@ -0,0 +1,64 @@
// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
// 2013 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_EXTENSION_VIEW_HOST_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_
#include <memory>
#include "base/macros.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "extensions/browser/extension_host.h"
class CefBrowserHostImpl;
namespace content {
class WebContents;
} // namespace content
namespace extensions {
// The ExtensionHost for an extension that backs a view in the browser UI. For
// example, this could be an extension popup or dialog, but not a background
// page. Object lifespan is managed by CefBrowserHostImpl. Based on
// chrome/browser/extensions/extension_view_host.h.
class CefExtensionViewHost : public ExtensionHost,
public content::NotificationObserver {
public:
CefExtensionViewHost(CefBrowserHostImpl* browser,
const Extension* extension,
content::BrowserContext* browser_context,
content::WebContents* host_contents,
const GURL& url,
ViewType host_type);
~CefExtensionViewHost() override;
// ExtensionHost methods:
void OnDidStopFirstLoad() override;
void LoadInitialURL() override;
bool IsBackgroundPage() const override;
// content::WebContentsDelegate methods:
bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
bool PreHandleGestureEvent(content::WebContents* source,
const blink::WebGestureEvent& event) override;
// extensions::ExtensionFunctionDispatcher::Delegate methods:
content::WebContents* GetVisibleWebContents() const override;
// content::NotificationObserver methods:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
private:
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(CefExtensionViewHost);
};
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_

View File

@ -15,7 +15,9 @@ namespace extensions {
CefExtensionWebContentsObserver::CefExtensionWebContentsObserver(
content::WebContents* web_contents)
: ExtensionWebContentsObserver(web_contents) {}
: ExtensionWebContentsObserver(web_contents),
script_executor_(
new ScriptExecutor(web_contents, &script_execution_observers_)) {}
CefExtensionWebContentsObserver::~CefExtensionWebContentsObserver() {}

View File

@ -5,8 +5,13 @@
#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
#include <memory>
#include "base/observer_list.h"
#include "content/public/browser/web_contents_user_data.h"
#include "extensions/browser/extension_web_contents_observer.h"
#include "extensions/browser/script_execution_observer.h"
#include "extensions/browser/script_executor.h"
namespace extensions {
@ -17,6 +22,8 @@ class CefExtensionWebContentsObserver
public:
~CefExtensionWebContentsObserver() override;
ScriptExecutor* script_executor() { return script_executor_.get(); }
private:
friend class content::WebContentsUserData<CefExtensionWebContentsObserver>;
@ -25,6 +32,12 @@ class CefExtensionWebContentsObserver
// content::WebContentsObserver overrides.
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
// Our content script observers. Declare at top so that it will outlive all
// other members, since they might add themselves as observers.
base::ObserverList<ScriptExecutionObserver> script_execution_observers_;
std::unique_ptr<ScriptExecutor> script_executor_;
DISALLOW_COPY_AND_ASSIGN(CefExtensionWebContentsObserver);
};

View File

@ -13,7 +13,6 @@
#include "libcef/browser/printing/print_view_manager.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
#include "components/pdf/browser/pdf_web_contents_helper.h"
#include "components/zoom/zoom_controller.h"
@ -64,7 +63,6 @@ void CefExtensionsAPIClient::AttachWebContentsHelpers(
new CefPDFWebContentsHelperClient()));
// Used by the tabs extension API.
SessionTabHelper::CreateForWebContents(web_contents);
zoom::ZoomController::CreateForWebContents(web_contents);
}

View File

@ -8,17 +8,19 @@
#include <utility>
#include "libcef/browser/browser_context_impl.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/extensions/chrome_api_registration.h"
#include "libcef/browser/extensions/component_extension_resource_manager.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/extensions/extension_system_factory.h"
#include "libcef/browser/extensions/extension_web_contents_observer.h"
#include "libcef/browser/extensions/extensions_api_client.h"
#include "libcef/browser/request_context_impl.h"
//#include "cef/libcef/browser/extensions/api/generated_api_registration.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/chrome_url_request_util.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
@ -30,6 +32,7 @@
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_host_delegate.h"
#include "extensions/browser/mojo/service_registration.h"
#include "extensions/browser/serial_extension_host_queue.h"
#include "extensions/browser/url_request_util.h"
#include "extensions/common/constants.h"
@ -44,6 +47,12 @@ CefExtensionsBrowserClient::CefExtensionsBrowserClient()
CefExtensionsBrowserClient::~CefExtensionsBrowserClient() {}
// static
CefExtensionsBrowserClient* CefExtensionsBrowserClient::Get() {
return static_cast<CefExtensionsBrowserClient*>(
ExtensionsBrowserClient::Get());
}
bool CefExtensionsBrowserClient::IsShuttingDown() {
return false;
}
@ -62,24 +71,28 @@ bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first,
BrowserContext* second) {
// Returns true if |first| and |second| share the same underlying
// CefBrowserContextImpl.
return CefBrowserContextImpl::GetForContext(first) ==
CefBrowserContextImpl::GetForContext(second);
return GetCefImplContext(first) == GetCefImplContext(second);
}
bool CefExtensionsBrowserClient::HasOffTheRecordContext(
BrowserContext* context) {
// CEF doesn't use incognito contexts.
return false;
}
BrowserContext* CefExtensionsBrowserClient::GetOffTheRecordContext(
BrowserContext* context) {
// TODO(extensions): Do we need to support this?
return NULL;
}
BrowserContext* CefExtensionsBrowserClient::GetOriginalContext(
BrowserContext* context) {
return chrome::GetBrowserContextRedirectedInIncognito(context);
return GetCefImplContext(context);
}
BrowserContext* CefExtensionsBrowserClient::GetCefImplContext(
BrowserContext* context) {
return CefBrowserContextImpl::GetForContext(context);
}
bool CefExtensionsBrowserClient::IsGuestSession(BrowserContext* context) const {
@ -148,11 +161,68 @@ ProcessManagerDelegate* CefExtensionsBrowserClient::GetProcessManagerDelegate()
std::unique_ptr<ExtensionHostDelegate>
CefExtensionsBrowserClient::CreateExtensionHostDelegate() {
// TODO(extensions): Implement to support Apps.
// CEF does not use the ExtensionHost constructor that calls this method.
NOTREACHED();
return std::unique_ptr<ExtensionHostDelegate>();
}
bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost(
const Extension* extension,
content::BrowserContext* browser_context,
const GURL& url,
ExtensionHost** host) {
// The BrowserContext referenced by ProcessManager should always be an *Impl.
DCHECK(!static_cast<CefBrowserContext*>(browser_context)->is_proxy());
CefBrowserContextImpl* browser_context_impl =
CefBrowserContextImpl::GetForContext(browser_context);
// A CEF representation should always exist.
CefRefPtr<CefExtension> cef_extension =
browser_context_impl->extension_system()->GetExtension(extension->id());
DCHECK(cef_extension);
if (!cef_extension) {
// Cancel the background host creation.
return true;
}
// Always use the same request context that the extension was registered with.
// May represent an *Impl or *Proxy BrowserContext.
// GetLoaderContext() will return NULL for internal extensions.
CefRefPtr<CefRequestContext> request_context =
cef_extension->GetLoaderContext();
if (!request_context) {
// Cancel the background host creation.
return true;
}
CefBrowserHostImpl::CreateParams create_params;
create_params.url = url;
create_params.request_context = request_context;
CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler();
if (handler.get() && handler->OnBeforeBackgroundBrowser(
cef_extension, url.spec(), create_params.client,
create_params.settings)) {
// Cancel the background host creation.
return true;
}
// This triggers creation of the background host.
create_params.extension = extension;
create_params.extension_host_type =
extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE;
// Browser creation may fail under certain rare circumstances. Fail the
// background host creation in that case.
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::Create(create_params);
if (browser) {
*host = browser->extension_host();
DCHECK(*host);
}
return true;
}
bool CefExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) {
// TODO(jamescook): We might want to tell extensions when app_shell updates.
return false;
@ -250,9 +320,10 @@ bool CefExtensionsBrowserClient::IsLockScreenContext(
return false;
}
void CefExtensionsBrowserClient::SetAPIClientForTest(
ExtensionsAPIClient* api_client) {
api_client_.reset(api_client);
ExtensionHostQueue* CefExtensionsBrowserClient::GetExtensionHostQueue() {
if (!extension_host_queue_)
extension_host_queue_.reset(new SerialExtensionHostQueue);
return extension_host_queue_.get();
}
} // namespace extensions

View File

@ -11,6 +11,7 @@
namespace extensions {
class ExtensionHostQueue;
class ExtensionsAPIClient;
// An ExtensionsBrowserClient that supports a single content::BrowserContent
@ -20,6 +21,9 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
CefExtensionsBrowserClient();
~CefExtensionsBrowserClient() override;
// Returns the singleton CefExtensionsBrowserClient instance.
static CefExtensionsBrowserClient* Get();
// ExtensionsBrowserClient overrides:
bool IsShuttingDown() override;
bool AreExtensionsDisabled(const base::CommandLine& command_line,
@ -32,6 +36,8 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
content::BrowserContext* context) override;
content::BrowserContext* GetOriginalContext(
content::BrowserContext* context) override;
content::BrowserContext* GetCefImplContext(
content::BrowserContext* context) override;
bool IsGuestSession(content::BrowserContext* context) const override;
bool IsExtensionIncognitoEnabled(
const std::string& extension_id,
@ -56,6 +62,10 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
std::vector<ExtensionPrefsObserver*>* observers) const override;
ProcessManagerDelegate* GetProcessManagerDelegate() const override;
std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override;
bool CreateBackgroundExtensionHost(const Extension* extension,
content::BrowserContext* browser_context,
const GURL& url,
ExtensionHost** host) override;
bool DidVersionUpdate(content::BrowserContext* context) override;
void PermitExternalProtocolHandler() override;
bool IsRunningInForcedAppMode() override;
@ -82,8 +92,7 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
KioskDelegate* GetKioskDelegate() override;
bool IsLockScreenContext(content::BrowserContext* context) override;
// Sets the API client.
void SetAPIClientForTest(ExtensionsAPIClient* api_client);
ExtensionHostQueue* GetExtensionHostQueue();
private:
// Support for extension APIs.
@ -92,6 +101,9 @@ class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
// Resource manager used to supply resources from pak files.
std::unique_ptr<ComponentExtensionResourceManager> resource_manager_;
// Used to create deferred RenderViews for extensions.
std::unique_ptr<ExtensionHostQueue> extension_host_queue_;
DISALLOW_COPY_AND_ASSIGN(CefExtensionsBrowserClient);
};

View File

@ -94,7 +94,6 @@ CefMenuManager::CefMenuManager(CefBrowserHostImpl* browser,
custom_menu_callback_(NULL),
weak_ptr_factory_(this) {
DCHECK(web_contents());
DCHECK(runner_.get());
model_ = new CefMenuModelImpl(this, nullptr, false);
}
@ -106,7 +105,8 @@ CefMenuManager::~CefMenuManager() {
void CefMenuManager::Destroy() {
CancelContextMenu();
runner_.reset(NULL);
if (runner_)
runner_.reset(NULL);
}
bool CefMenuManager::IsShowingContextMenu() {
@ -184,7 +184,7 @@ bool CefMenuManager::CreateContextMenu(
}
}
if (custom_menu)
if (custom_menu || !runner_)
return true;
return runner_->RunContextMenu(browser_, model_.get(), params_);
}
@ -193,7 +193,7 @@ void CefMenuManager::CancelContextMenu() {
if (IsShowingContextMenu()) {
if (custom_menu_callback_)
custom_menu_callback_->Cancel();
else
else if (runner_)
runner_->CancelContextMenu();
}
}
@ -268,6 +268,8 @@ void CefMenuManager::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
bool CefMenuManager::FormatLabel(CefRefPtr<CefMenuModelImpl> source,
base::string16& label) {
if (!runner_)
return false;
return runner_->FormatLabel(label);
}

View File

@ -276,8 +276,9 @@ void CefBrowserPlatformDelegateNativeWin::SizeTo(int width, int height) {
// based on the current style.
AdjustWindowRectEx(&rect, style, has_menu, ex_style);
// Size the window.
SetWindowPos(window, NULL, 0, 0, rect.right, rect.bottom,
// Size the window. The left/top values may be negative.
SetWindowPos(window, NULL, 0, 0, rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}

View File

@ -12,6 +12,7 @@
#include "include/cef_version.h"
#include "include/cef_web_plugin.h"
#include "libcef/browser/extensions/chrome_api_registration.h"
#include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/net/internal_scheme_handler.h"
#include "libcef/browser/net/url_request_manager.h"
@ -41,12 +42,15 @@
#include "net/url_request/url_request.h"
#include "v8/include/v8.h"
using extensions::api::cef::kSupportedAPIs;
namespace scheme {
const char kChromeURL[] = "chrome://";
namespace {
const char kChromeUIExtensionsSupportHost[] = "extensions-support";
const char kChromeUILicenseHost[] = "license";
const char kChromeUIWebUIHostsHost[] = "webui-hosts";
@ -83,6 +87,7 @@ const char* kUnlistedHosts[] = {
enum ChromeHostId {
CHROME_UNKNOWN = 0,
CHROME_EXTENSIONS_SUPPORT,
CHROME_LICENSE,
CHROME_VERSION,
CHROME_WEBUI_HOSTS,
@ -93,6 +98,7 @@ const struct {
const char* host;
ChromeHostId host_id;
} kAllowedCefHosts[] = {
{kChromeUIExtensionsSupportHost, CHROME_EXTENSIONS_SUPPORT},
{kChromeUILicenseHost, CHROME_LICENSE},
{chrome::kChromeUIVersionHost, CHROME_VERSION},
{kChromeUIWebUIHostsHost, CHROME_WEBUI_HOSTS},
@ -510,6 +516,9 @@ class Delegate : public InternalHandlerDelegate {
ChromeHostId host_id = GetChromeHostId(url.host());
switch (host_id) {
case CHROME_EXTENSIONS_SUPPORT:
handled = OnExtensionsSupport(action);
break;
case CHROME_LICENSE:
handled = OnLicense(action);
break;
@ -535,6 +544,61 @@ class Delegate : public InternalHandlerDelegate {
return handled;
}
bool OnExtensionsSupport(Action* action) {
static const char kDevURL[] = "https://developer.chrome.com/extensions/";
std::string html =
"<html>\n<head><title>Extensions Support</title></head>\n"
"<body bgcolor=\"white\"><h3>Supported Chrome Extensions "
"APIs</h3>\nFollow <a "
"href=\"https://bitbucket.org/chromiumembedded/cef/issues/1947\" "
"target=\"new\">issue #1947</a> for development progress.\n<ul>\n";
bool has_top_level_name = false;
for (size_t i = 0; kSupportedAPIs[i] != nullptr; ++i) {
const std::string& api_name = kSupportedAPIs[i];
if (api_name.find("Private") != std::string::npos) {
// Don't list private APIs.
continue;
}
const size_t dot_pos = api_name.find('.');
if (dot_pos == std::string::npos) {
if (has_top_level_name) {
// End the previous top-level API entry.
html += "</ul></li>\n";
} else {
has_top_level_name = true;
}
// Start a new top-level API entry.
html += "<li><a href=\"" + std::string(kDevURL) + api_name +
"\" target=\"new\">" + api_name + "</a><ul>\n";
} else {
// Function name.
const std::string& group_name = api_name.substr(0, dot_pos);
const std::string& function_name = api_name.substr(dot_pos + 1);
html += "\t<li><a href=\"" + std::string(kDevURL) + group_name +
"#method-" + function_name + "\" target=\"new\">" + api_name +
"</a></li>\n";
}
}
if (has_top_level_name) {
// End the last top-level API entry.
html += "</ul></li>\n";
}
html += "</ul>\n</body>\n</html>";
action->mime_type = "text/html";
action->stream = CefStreamReader::CreateForData(
const_cast<char*>(html.c_str()), html.length());
action->stream_size = html.length();
return true;
}
bool OnLicense(Action* action) {
base::StringPiece piece = CefContentClient::Get()->GetDataResource(
IDR_CEF_LICENSE_TXT, ui::SCALE_FACTOR_NONE);

View File

@ -6,6 +6,7 @@
#define CEF_LIBCEF_BROWSER_NET_URL_REQUEST_CONTEXT_GETTER_PROXY_H_
#pragma once
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "libcef/browser/net/url_request_context_getter.h"
#include "libcef/browser/net/url_request_context_getter_impl.h"

View File

@ -6,6 +6,7 @@
#define CEF_LIBCEF_BROWSER_NET_URL_REQUEST_CONTEXT_PROXY_H_
#pragma once
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "libcef/browser/net/url_request_context.h"

View File

@ -38,6 +38,9 @@ bool CefGetPath(PathKey key, CefString& path) {
case PK_USER_DATA:
pref_key = chrome::DIR_USER_DATA;
break;
case PK_DIR_RESOURCES:
pref_key = chrome::DIR_RESOURCES;
break;
default:
NOTREACHED() << "invalid argument";
return false;

View File

@ -8,7 +8,9 @@
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/context.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/extensions/extensions_util.h"
#include "libcef/common/values_impl.h"
#include "base/atomic_sequence_num.h"
@ -132,6 +134,8 @@ CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
// CefRequestContextImpl
CefRequestContextImpl::~CefRequestContextImpl() {
CEF_REQUIRE_UIT();
// Delete the proxy first because it also references |browser_context_impl_|.
if (browser_context_proxy_)
browser_context_proxy_.reset(nullptr);
@ -501,6 +505,80 @@ cef_errorcode_t CefRequestContextImpl::ResolveHostCached(
return static_cast<cef_errorcode_t>(retval);
}
void CefRequestContextImpl::LoadExtension(
const CefString& root_directory,
CefRefPtr<CefDictionaryValue> manifest,
CefRefPtr<CefExtensionHandler> handler) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefRequestContextImpl::LoadExtension, this,
root_directory, manifest, handler));
return;
}
if (!extensions::ExtensionsEnabled()) {
if (handler)
handler->OnExtensionLoadFailed(ERR_ABORTED);
return;
}
if (manifest && manifest->GetSize() > 0) {
CefDictionaryValueImpl* value_impl =
static_cast<CefDictionaryValueImpl*>(manifest.get());
GetBrowserContext()->extension_system()->LoadExtension(
base::WrapUnique(value_impl->CopyValue()), root_directory,
false /* builtin */, this, handler);
} else {
GetBrowserContext()->extension_system()->LoadExtension(
root_directory, false /* builtin */, this, handler);
}
}
bool CefRequestContextImpl::DidLoadExtension(const CefString& extension_id) {
CefRefPtr<CefExtension> extension = GetExtension(extension_id);
// GetLoaderContext() will return NULL for internal extensions.
return extension && IsSame(extension->GetLoaderContext());
}
bool CefRequestContextImpl::HasExtension(const CefString& extension_id) {
return !!GetExtension(extension_id);
}
bool CefRequestContextImpl::GetExtensions(
std::vector<CefString>& extension_ids) {
extension_ids.clear();
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return false;
}
if (!extensions::ExtensionsEnabled())
return false;
extensions::CefExtensionSystem::ExtensionMap extension_map =
GetBrowserContext()->extension_system()->GetExtensions();
extensions::CefExtensionSystem::ExtensionMap::const_iterator it =
extension_map.begin();
for (; it != extension_map.end(); ++it)
extension_ids.push_back(it->second->GetIdentifier());
return true;
}
CefRefPtr<CefExtension> CefRequestContextImpl::GetExtension(
const CefString& extension_id) {
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return nullptr;
}
if (!extensions::ExtensionsEnabled())
return nullptr;
return GetBrowserContext()->extension_system()->GetExtension(extension_id);
}
// static
CefRefPtr<CefRequestContextImpl>
CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) {
@ -581,9 +659,13 @@ void CefRequestContextImpl::Initialize() {
// IsSharedWith().
config_.other = NULL;
}
if (config_.handler)
config_.handler->OnRequestContextInitialized(this);
}
void CefRequestContextImpl::EnsureBrowserContext() {
CEF_REQUIRE_UIT();
if (!browser_context())
Initialize();
DCHECK(browser_context());

View File

@ -80,6 +80,13 @@ class CefRequestContextImpl : public CefRequestContext {
cef_errorcode_t ResolveHostCached(
const CefString& origin,
std::vector<CefString>& resolved_ips) override;
void LoadExtension(const CefString& root_directory,
CefRefPtr<CefDictionaryValue> manifest,
CefRefPtr<CefExtensionHandler> handler) override;
bool DidLoadExtension(const CefString& extension_id) override;
bool HasExtension(const CefString& extension_id) override;
bool GetExtensions(std::vector<CefString>& extension_ids) override;
CefRefPtr<CefExtension> GetExtension(const CefString& extension_id) override;
const CefRequestContextSettings& settings() const { return config_.settings; }

View File

@ -6,6 +6,7 @@
#define CEF_LIBCEF_BROWSER_RESOURCE_CONTEXT_H_
#pragma once
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "base/files/file_path.h"

View File

@ -174,7 +174,7 @@ void CefBrowserViewImpl::SetPendingBrowserCreateParams(
DCHECK(!pending_browser_create_params_);
pending_browser_create_params_.reset(new CefBrowserHostImpl::CreateParams());
pending_browser_create_params_->client = client;
pending_browser_create_params_->url = url;
pending_browser_create_params_->url = GURL(url.ToString());
pending_browser_create_params_->settings = settings;
pending_browser_create_params_->request_context = request_context;
}

View File

@ -49,8 +49,25 @@ CEF_BUTTON_IMPL_T class CefButtonImpl : public CEF_VIEW_IMPL_D {
CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetState(cef_button_state_t state) {
CEF_REQUIRE_VALID_RETURN_VOID();
ParentClass::root_view()->SetState(
static_cast<views::Button::ButtonState>(state));
views::Button::ButtonState old_state = ParentClass::root_view()->state();
views::Button::ButtonState new_state =
static_cast<views::Button::ButtonState>(state);
if (ParentClass::root_view()->ink_drop_mode() !=
views::CustomButton::InkDropMode::OFF &&
!ParentClass::root_view()->IsFocusable()) {
// Ink drop state does not get set properly on state change when the button
// is non-focusable.
views::InkDropState ink_state = views::InkDropState::HIDDEN;
if (new_state == views::Button::STATE_PRESSED) {
ink_state = views::InkDropState::ACTIVATED;
} else if (old_state == views::Button::STATE_PRESSED) {
ink_state = views::InkDropState::DEACTIVATED;
}
ParentClass::root_view()->AnimateInkDrop(ink_state, nullptr);
}
ParentClass::root_view()->SetState(new_state);
}
CEF_BUTTON_IMPL_T cef_button_state_t CEF_BUTTON_IMPL_D::GetState() {

View File

@ -56,12 +56,16 @@ CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::StateChanged(
CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::ButtonPressed(
views::Button* sender,
const ui::Event& event) {
// Callback may trigger new animation state.
if (ParentClass::cef_delegate())
ParentClass::cef_delegate()->OnButtonPressed(GetCefButton());
if (ParentClass::ink_drop_mode() != views::CustomButton::InkDropMode::OFF &&
!ParentClass::IsFocusable()) {
// When ink drop is enabled for non-focusable buttons the ink drop state
// does not get reset properly on click, so we do it here explicitly.
!ParentClass::IsFocusable() &&
ParentClass::state() != views::CustomButton::STATE_PRESSED) {
// Ink drop state does not get reset properly on click when the button is
// non-focusable. Reset the ink drop state here if the state has not been
// explicitly set to pressed by the OnButtonPressed callback calling
// SetState (which also sets the ink drop state).
ParentClass::AnimateInkDrop(views::InkDropState::HIDDEN,
ui::LocatedEvent::FromIfValid(&event));
}

View File

@ -4,9 +4,27 @@
#include "libcef/browser/views/menu_button_view.h"
#include "libcef/browser/thread_util.h"
#include "ui/gfx/canvas.h"
#include "ui/views/controls/menu/menu_config.h"
namespace {
class ButtonPressedLock : public CefMenuButtonPressedLock {
public:
explicit ButtonPressedLock(views::MenuButton* menu_button)
: pressed_lock_(menu_button) {}
private:
views::MenuButton::PressedLock pressed_lock_;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ButtonPressedLock);
DISALLOW_COPY_AND_ASSIGN(ButtonPressedLock);
};
} // namespace
CefMenuButtonView::CefMenuButtonView(CefMenuButtonDelegate* cef_delegate)
: ParentClass(cef_delegate) {
DCHECK(cef_delegate);
@ -36,5 +54,6 @@ void CefMenuButtonView::OnMenuButtonClicked(views::MenuButton* source,
const gfx::Point& point,
const ui::Event* event) {
cef_delegate()->OnMenuButtonPressed(GetCefMenuButton(),
CefPoint(point.x(), point.y()));
CefPoint(point.x(), point.y()),
new ButtonPressedLock(source));
}

View File

@ -122,6 +122,8 @@ class CefWindowImpl
cef_menu_anchor_position_t anchor_position);
void MenuClosed();
views::Widget* widget() const { return widget_; }
private:
// Create a new implementation object.
// Always call Initialize() after creation.

View File

@ -5,6 +5,7 @@
#include "libcef/browser/views/window_view.h"
#include "libcef/browser/image_impl.h"
#include "libcef/browser/views/window_impl.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/window.h"
@ -249,9 +250,29 @@ void CefWindowView::CreateWidget() {
views::Widget::InitParams params;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
bool can_activate = true;
if (cef_delegate())
is_frameless_ = cef_delegate()->IsFrameless(GetCefWindow());
if (cef_delegate()) {
CefRefPtr<CefWindow> cef_window = GetCefWindow();
is_frameless_ = cef_delegate()->IsFrameless(cef_window);
bool is_menu = false;
bool can_activate_menu = true;
CefRefPtr<CefWindow> parent_window = cef_delegate()->GetParentWindow(
cef_window, &is_menu, &can_activate_menu);
if (parent_window && !parent_window->IsSame(cef_window)) {
CefWindowImpl* parent_window_impl =
static_cast<CefWindowImpl*>(parent_window.get());
params.parent = view_util::GetNativeWindow(parent_window_impl->widget());
if (is_menu) {
// Don't clip the window to parent bounds.
params.type = views::Widget::InitParams::TYPE_MENU;
can_activate = can_activate_menu;
if (can_activate_menu)
params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
}
}
}
#if defined(OS_WIN)
if (is_frameless_) {
@ -267,8 +288,11 @@ void CefWindowView::CreateWidget() {
DCHECK_EQ(widget, GetWidget());
// |widget| must be top-level for focus handling to work correctly.
DCHECK(widget->is_top_level());
// |widget| must be activatable for focus handling to work correctly.
DCHECK(widget->widget_delegate()->CanActivate());
if (can_activate) {
// |widget| must be activatable for focus handling to work correctly.
DCHECK(widget->widget_delegate()->CanActivate());
}
#if defined(OS_LINUX)
if (is_frameless_) {