mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
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:
@ -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() {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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_
|
||||
|
@ -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);
|
||||
}
|
@ -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_
|
@ -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>();
|
||||
|
@ -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);
|
||||
|
46
libcef/browser/extensions/extension_background_host.cc
Normal file
46
libcef/browser/extensions/extension_background_host.cc
Normal 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
|
48
libcef/browser/extensions/extension_background_host.h
Normal file
48
libcef/browser/extensions/extension_background_host.h
Normal 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_
|
291
libcef/browser/extensions/extension_function_details.cc
Normal file
291
libcef/browser/extensions/extension_function_details.cc
Normal 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
|
114
libcef/browser/extensions/extension_function_details.h
Normal file
114
libcef/browser/extensions/extension_function_details.h
Normal 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_
|
63
libcef/browser/extensions/extension_host_delegate.cc
Normal file
63
libcef/browser/extensions/extension_host_delegate.cc
Normal 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
|
45
libcef/browser/extensions/extension_host_delegate.h
Normal file
45
libcef/browser/extensions/extension_host_delegate.h
Normal 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_
|
@ -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());
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
97
libcef/browser/extensions/extension_view_host.cc
Normal file
97
libcef/browser/extensions/extension_view_host.cc
Normal 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
|
64
libcef/browser/extensions/extension_view_host.h
Normal file
64
libcef/browser/extensions/extension_view_host.h
Normal 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_
|
@ -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() {}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user