Commit b7a56d93 authored by Marshall Greenblatt's avatar Marshall Greenblatt

Add PDF extension support (issue #1565)

parent aefb5ccc
......@@ -289,6 +289,7 @@ if(OS_LINUX)
cef.pak
cef_100_percent.pak
cef_200_percent.pak
cef_extensions.pak
devtools_resources.pak
icudtl.dat
locales
......@@ -457,6 +458,7 @@ if(OS_WINDOWS)
cef.pak
cef_100_percent.pak
cef_200_percent.pak
cef_extensions.pak
devtools_resources.pak
icudtl.dat
locales
......
This diff is collapsed.
......@@ -214,6 +214,8 @@
'tests/cefclient/resources/logo.png',
'tests/cefclient/resources/osr_test.html',
'tests/cefclient/resources/other_tests.html',
'tests/cefclient/resources/pdf.html',
'tests/cefclient/resources/pdf.pdf',
'tests/cefclient/resources/performance.html',
'tests/cefclient/resources/performance2.html',
'tests/cefclient/resources/transparency.html',
......
......@@ -4,6 +4,8 @@
#include "libcef/browser/browser_context.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/common/extensions/extensions_util.h"
#include "base/logging.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
......@@ -15,16 +17,7 @@ base::AtomicRefCount CefBrowserContext::DebugObjCt = 0;
#endif
CefBrowserContext::CefBrowserContext()
: resource_context_(new CefResourceContext) {
BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
this);
// Spell checking support and possibly other subsystems retrieve the
// PrefService associated with a BrowserContext via UserPrefs::Get().
PrefService* pref_service = CefContentBrowserClient::Get()->pref_service();
DCHECK(pref_service);
user_prefs::UserPrefs::Set(this, pref_service);
: extension_system_(NULL) {
#ifndef NDEBUG
base::AtomicRefCountInc(&DebugObjCt);
#endif
......@@ -47,6 +40,33 @@ CefBrowserContext::~CefBrowserContext() {
#endif
}
void CefBrowserContext::Initialize() {
const bool extensions_enabled = extensions::ExtensionsEnabled();
if (extensions_enabled) {
// Create the custom ExtensionSystem first because other KeyedServices
// depend on it.
extension_system_ = static_cast<extensions::CefExtensionSystem*>(
extensions::ExtensionSystem::Get(this));
extension_system_->InitForRegularProfile(true);
}
resource_context_.reset(new CefResourceContext(
IsOffTheRecord(),
extensions_enabled ? extension_system_->info_map() : NULL));
BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
this);
// Spell checking support and possibly other subsystems retrieve the
// PrefService associated with a BrowserContext via UserPrefs::Get().
PrefService* pref_service = CefContentBrowserClient::Get()->pref_service();
DCHECK(pref_service);
user_prefs::UserPrefs::Set(this, pref_service);
if (extensions_enabled)
extension_system_->Init();
}
content::ResourceContext* CefBrowserContext::GetResourceContext() {
return resource_context_.get();
}
......@@ -104,6 +104,10 @@
// CefURLRequestContextGetter* destruction.
*/
namespace extensions {
class CefExtensionSystem;
}
// Main entry point for configuring behavior on a per-browser basis. An instance
// of this class is passed to WebContents::Create in CefBrowserHostImpl::
// CreateInternal. Only accessed on the UI thread unless otherwise indicated.
......@@ -114,13 +118,12 @@ class CefBrowserContext
public:
CefBrowserContext();
// Must be called immediately after this object is created.
virtual void Initialize();
// BrowserContext methods.
content::ResourceContext* GetResourceContext() override;
// Returns true if this is a CefBrowserContextProxy object. Safe to call from
// any thread.
virtual bool IsProxy() const = 0;
// Returns the settings associated with this object. Safe to call from any
// thread.
virtual const CefRequestContextSettings& GetSettings() const = 0;
......@@ -140,7 +143,10 @@ class CefBrowserContext
content::URLRequestInterceptorScopedVector request_interceptors) = 0;
CefResourceContext* resource_context() const {
return resource_context_.get();
return resource_context_.get();
}
extensions::CefExtensionSystem* extension_system() const {
return extension_system_;
}
#ifndef NDEBUG
......@@ -159,6 +165,9 @@ class CefBrowserContext
scoped_ptr<CefResourceContext> resource_context_;
// Owned by the KeyedService system.
extensions::CefExtensionSystem* extension_system_;
DISALLOW_COPY_AND_ASSIGN(CefBrowserContext);
};
......
......@@ -6,18 +6,21 @@
#include <map>
#include "libcef/browser/browser_context_proxy.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/context.h"
#include "libcef/browser/download_manager_delegate.h"
#include "libcef/browser/permission_manager.h"
#include "libcef/browser/ssl_host_state_delegate.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/extensions/extensions_util.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/net/proxy_service_factory.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
......@@ -27,43 +30,89 @@ using content::BrowserThread;
namespace {
// Manages the global mapping of cache path to Impl instance.
// Manages the global list of Impl instances.
class ImplManager {
public:
typedef std::vector<CefBrowserContextImpl*> Vector;
ImplManager() {}
~ImplManager() {
DCHECK(all_.empty());
DCHECK(map_.empty());
}
CefBrowserContextImpl* GetImpl(const base::FilePath& path) {
void AddImpl(CefBrowserContextImpl* impl) {
CEF_REQUIRE_UIT();
DCHECK(!path.empty());
PathMap::const_iterator it = map_.find(path);
if (it != map_.end())
return it->second;
DCHECK(!IsValidImpl(impl));
all_.push_back(impl);
}
void RemoveImpl(CefBrowserContextImpl* impl, const base::FilePath& path) {
CEF_REQUIRE_UIT();
Vector::iterator it = GetImplPos(impl);
DCHECK(it != all_.end());
all_.erase(it);
if (!path.empty()) {
PathMap::iterator it = map_.find(path);
DCHECK(it != map_.end());
if (it != map_.end())
map_.erase(it);
}
}
bool IsValidImpl(const CefBrowserContextImpl* impl) {
CEF_REQUIRE_UIT();
return GetImplPos(impl) != all_.end();
}
CefBrowserContextImpl* GetImplForContext(
const content::BrowserContext* context) {
CEF_REQUIRE_UIT();
Vector::iterator it = all_.begin();
for (; it != all_.end(); ++it) {
if (*it == context || (*it)->HasProxy(context))
return *it;
}
return NULL;
}
void AddImpl(const base::FilePath& path, CefBrowserContextImpl* impl) {
void SetImplPath(CefBrowserContextImpl* impl, const base::FilePath& path) {
CEF_REQUIRE_UIT();
DCHECK(!path.empty());
DCHECK(GetImpl(path) == NULL);
DCHECK(IsValidImpl(impl));
DCHECK(GetImplForPath(path) == NULL);
map_.insert(std::make_pair(path, impl));
}
void RemoveImpl(const base::FilePath& path) {
CefBrowserContextImpl* GetImplForPath(const base::FilePath& path) {
CEF_REQUIRE_UIT();
DCHECK(!path.empty());
PathMap::iterator it = map_.find(path);
DCHECK(it != map_.end());
PathMap::const_iterator it = map_.find(path);
if (it != map_.end())
map_.erase(it);
return it->second;
return NULL;
}
const Vector GetAllImpl() const { return all_; }
private:
Vector::iterator GetImplPos(const CefBrowserContextImpl* impl) {
Vector::iterator it = all_.begin();
for (; it != all_.end(); ++it) {
if (*it == impl)
return it;
}
return all_.end();
}
typedef std::map<base::FilePath, CefBrowserContextImpl*> PathMap;
PathMap map_;
Vector all_;
DISALLOW_COPY_AND_ASSIGN(ImplManager);
};
......@@ -74,6 +123,7 @@ base::LazyInstance<ImplManager> g_manager = LAZY_INSTANCE_INITIALIZER;
CefBrowserContextImpl::CefBrowserContextImpl(
const CefRequestContextSettings& settings)
: settings_(settings) {
g_manager.Get().AddImpl(this);
}
CefBrowserContextImpl::~CefBrowserContextImpl() {
......@@ -84,8 +134,7 @@ CefBrowserContextImpl::~CefBrowserContextImpl() {
if (download_manager_delegate_.get())
download_manager_delegate_.reset(NULL);
if (!cache_path_.empty())
g_manager.Get().RemoveImpl(cache_path_);
g_manager.Get().RemoveImpl(this, cache_path_);
}
void CefBrowserContextImpl::Initialize() {
......@@ -102,7 +151,7 @@ void CefBrowserContextImpl::Initialize() {
}
if (!cache_path_.empty())
g_manager.Get().AddImpl(cache_path_, this);
g_manager.Get().SetImplPath(this, cache_path_);
if (settings_.accept_language_list.length == 0) {
// Use the global language list setting.
......@@ -110,6 +159,8 @@ void CefBrowserContextImpl::Initialize() {
CefString(&CefContext::Get()->settings().accept_language_list);
}
CefBrowserContext::Initialize();
// Initialize proxy configuration tracker.
pref_proxy_config_tracker_.reset(
ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
......@@ -123,10 +174,52 @@ void CefBrowserContextImpl::Initialize() {
DCHECK(url_request_getter_.get());
}
void CefBrowserContextImpl::AddProxy(const CefBrowserContextProxy* proxy) {
CEF_REQUIRE_UIT();
DCHECK(!HasProxy(proxy));
proxy_list_.push_back(proxy);
}
void CefBrowserContextImpl::RemoveProxy(const CefBrowserContextProxy* proxy) {
CEF_REQUIRE_UIT();
bool found = false;
ProxyList::iterator it = proxy_list_.begin();
for (; it != proxy_list_.end(); ++it) {
if (*it == proxy) {
proxy_list_.erase(it);
found = true;
break;
}
}
DCHECK(found);
}
bool CefBrowserContextImpl::HasProxy(
const content::BrowserContext* context) const {
CEF_REQUIRE_UIT();
ProxyList::const_iterator it = proxy_list_.begin();
for (; it != proxy_list_.end(); ++it) {
if (*it == context)
return true;
}
return false;
}
// static
scoped_refptr<CefBrowserContextImpl> CefBrowserContextImpl::GetForCachePath(
const base::FilePath& cache_path) {
return g_manager.Get().GetImpl(cache_path);
return g_manager.Get().GetImplForPath(cache_path);
}
// static
CefRefPtr<CefBrowserContextImpl> CefBrowserContextImpl::GetForContext(
content::BrowserContext* context) {
return g_manager.Get().GetImplForContext(context);
}
// static
std::vector<CefBrowserContextImpl*> CefBrowserContextImpl::GetAll() {
return g_manager.Get().GetAllImpl();
}
base::FilePath CefBrowserContextImpl::GetPath() const {
......@@ -181,7 +274,8 @@ net::URLRequestContextGetter*
}
content::BrowserPluginGuestManager* CefBrowserContextImpl::GetGuestManager() {
return NULL;
DCHECK(extensions::ExtensionsEnabled());
return guest_view::GuestViewManager::FromBrowserContext(this);
}
storage::SpecialStoragePolicy*
......@@ -207,10 +301,6 @@ content::PermissionManager* CefBrowserContextImpl::GetPermissionManager() {
return permission_manager_.get();
}
bool CefBrowserContextImpl::IsProxy() const {
return false;
}
const CefRequestContextSettings& CefBrowserContextImpl::GetSettings() const {
return settings_;
}
......
......@@ -20,6 +20,7 @@ class DownloadManagerDelegate;
class SpeechRecognitionPreferences;
}
class CefBrowserContextProxy;
class CefDownloadManagerDelegate;
class CefSSLHostStateDelegate;
......@@ -36,8 +37,20 @@ class CefBrowserContextImpl : public CefBrowserContext {
static scoped_refptr<CefBrowserContextImpl> GetForCachePath(
const base::FilePath& cache_path);
// Returns the underlying CefBrowserContextImpl if any.
static CefRefPtr<CefBrowserContextImpl> GetForContext(
content::BrowserContext* context);
// Returns all existing CefBrowserContextImpl.
static std::vector<CefBrowserContextImpl*> GetAll();
// Must be called immediately after this object is created.
void Initialize();
void Initialize() override;
// Track associated proxy objects.
void AddProxy(const CefBrowserContextProxy* proxy);
void RemoveProxy(const CefBrowserContextProxy* proxy);
bool HasProxy(const content::BrowserContext* context) const;
// BrowserContext methods.
base::FilePath GetPath() const override;
......@@ -62,7 +75,6 @@ class CefBrowserContextImpl : public CefBrowserContext {
content::PermissionManager* GetPermissionManager() override;
// CefBrowserContext methods.
bool IsProxy() const override;
const CefRequestContextSettings& GetSettings() const override;
CefRefPtr<CefRequestContextHandler> GetHandler() const override;
net::URLRequestContextGetter* CreateRequestContext(
......@@ -93,6 +105,10 @@ class CefBrowserContextImpl : public CefBrowserContext {
CefRequestContextSettings settings_;
base::FilePath cache_path_;
// Not owned by this class.
typedef std::vector<const CefBrowserContextProxy*> ProxyList;
ProxyList proxy_list_;
scoped_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
scoped_ptr<CefDownloadManagerDelegate> download_manager_delegate_;
......
......@@ -19,9 +19,11 @@ CefBrowserContextProxy::CefBrowserContextProxy(
parent_(parent) {
DCHECK(handler_.get());
DCHECK(parent_.get());
parent_->AddProxy(this);
}
CefBrowserContextProxy::~CefBrowserContextProxy() {
parent_->RemoveProxy(this);
}
base::FilePath CefBrowserContextProxy::GetPath() const {
......@@ -99,10 +101,6 @@ content::PermissionManager* CefBrowserContextProxy::GetPermissionManager() {
return parent_->GetPermissionManager();
}
bool CefBrowserContextProxy::IsProxy() const {
return true;
}
const CefRequestContextSettings& CefBrowserContextProxy::GetSettings() const {
return parent_->GetSettings();
}
......
......@@ -52,7 +52,6 @@ class CefBrowserContextProxy : public CefBrowserContext {
content::PermissionManager* GetPermissionManager() override;
// CefBrowserContext methods.
bool IsProxy() const override;
const CefRequestContextSettings& GetSettings() const override;
CefRefPtr<CefRequestContextHandler> GetHandler() const override;
net::URLRequestContextGetter* CreateRequestContext(
......
......@@ -16,6 +16,7 @@
#include "libcef/browser/context.h"
#include "libcef/browser/devtools_delegate.h"
#include "libcef/browser/devtools_frontend.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/navigate_params.h"
#include "libcef/browser/navigation_entry_impl.h"
......@@ -28,6 +29,7 @@
#include "libcef/common/cef_messages.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/drag_data_impl.h"
#include "libcef/common/extensions/extensions_util.h"
#include "libcef/common/http_header_utils.h"
#include "libcef/common/main_delegate.h"
#include "libcef/common/process_message_impl.h"
......@@ -73,6 +75,63 @@
namespace {
// Manages the global list of Impl instances.
class ImplManager {
public:
typedef std::vector<CefBrowserHostImpl*> Vector;
ImplManager() {}
~ImplManager() {
DCHECK(all_.empty());
}
void AddImpl(CefBrowserHostImpl* impl) {
CEF_REQUIRE_UIT();
DCHECK(!IsValidImpl(impl));
all_.push_back(impl);
}
void RemoveImpl(CefBrowserHostImpl* impl) {
CEF_REQUIRE_UIT();
Vector::iterator it = GetImplPos(impl);
DCHECK(it != all_.end());
all_.erase(it);
}
bool IsValidImpl(const CefBrowserHostImpl* impl) {
CEF_REQUIRE_UIT();
return GetImplPos(impl) != all_.end();
}
CefBrowserHostImpl* GetImplForWebContents(
const content::WebContents* web_contents) {
CEF_REQUIRE_UIT();
Vector::const_iterator it = all_.begin();
for (; it != all_.end(); ++it) {
if ((*it)->web_contents() == web_contents)
return *it;
}
return NULL;
}
private:
Vector::iterator GetImplPos(const CefBrowserHostImpl* impl) {
Vector::iterator it = all_.begin();
for (; it != all_.end(); ++it) {
if (*it == impl)
return it;
}
return all_.end();
}
Vector all_;
DISALLOW_COPY_AND_ASSIGN(ImplManager);
};
base::LazyInstance<ImplManager> g_manager = LAZY_INSTANCE_INITIALIZER;
class CreateBrowserHelper {
public:
CreateBrowserHelper(const CefWindowInfo& windowInfo,
......@@ -520,7 +579,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForHost(
content::WebContents* web_contents =
content::WebContents::FromRenderViewHost(host);
if (web_contents)
return static_cast<CefBrowserHostImpl*>(web_contents->GetDelegate());
return GetBrowserForContents(web_contents);
return NULL;
}
......@@ -533,21 +592,20 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForHost(
content::WebContents::FromRenderFrameHost(
const_cast<content::RenderFrameHost*>(host));
if (web_contents)
return static_cast<CefBrowserHostImpl*>(web_contents->GetDelegate());
return GetBrowserForContents(web_contents);
return NULL;
}
// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForContents(
content::WebContents* contents) {
const content::WebContents* contents) {
DCHECK(contents);
CEF_REQUIRE_UIT();
return static_cast<CefBrowserHostImpl*>(contents->GetDelegate());
return g_manager.Get().GetImplForWebContents(contents);
}
// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForRequest(
net::URLRequest* request) {
const net::URLRequest* request) {
DCHECK(request);
CEF_REQUIRE_IOT();
int render_process_id = -1;
......@@ -584,7 +642,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForView(
render_routing_id);
if (info.get()) {
CefRefPtr<CefBrowserHostImpl> browser = info->browser();
if (!browser.get()) {
if (!browser.get() && !info->is_mime_handler_view()) {
LOG(WARNING) << "Found browser id " << info->browser_id() <<
" but no browser object matching view process id " <<
render_process_id << " and routing id " <<
......@@ -617,7 +675,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForFrame(
render_routing_id);
if (info.get()) {
CefRefPtr<CefBrowserHostImpl> browser = info->browser();
if (!browser.get()) {
if (!browser.get() && !info->is_mime_handler_view()) {
LOG(WARNING) << "Found browser id " << info->browser_id() <<
" but no browser object matching frame process id " <<
render_process_id << " and routing id " <<
......@@ -836,10 +894,11 @@ void CefBrowserHostImpl::StartDownload(const CefString& url) {
void CefBrowserHostImpl::Print() {
if (CEF_CURRENTLY_ON_UIT()) {
if (!web_contents_)
content::WebContents* actionable_contents = GetActionableWebContents();
if (!actionable_contents)
return;
printing::PrintViewManager::FromWebContents(
web_contents_.get())->PrintNow();
actionable_contents)->PrintNow();
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::Print, this));
......@@ -850,7 +909,8 @@ void CefBrowserHostImpl::PrintToPDF(const CefString& path,
const CefPdfPrintSettings& settings,
CefRefPtr<CefPdfPrintCallback> callback) {
if (CEF_CURRENTLY_ON_UIT()) {
if (!web_contents_)
content::WebContents* actionable_contents = GetActionableWebContents();
if (!actionable_contents)
return;
printing::PrintViewManager::PdfPrintCallback pdf_callback;
......@@ -858,7 +918,7 @@ void CefBrowserHostImpl::PrintToPDF(const CefString& path,
pdf_callback = base::Bind(&CefPdfPrintCallback::OnPdfPrintFinished,
callback.get(), path);
}
printing::PrintViewManager::FromWebContents(web_contents_.get())->
printing::PrintViewManager::FromWebContents(actionable_contents)->
PrintToPDF(base::FilePath(path), settings, pdf_callback);
} else {
CEF_POST_TASK(CEF_UIT,
......@@ -1538,6 +1598,8 @@ void CefBrowserHostImpl::DestroyBrowser() {
queued_messages_.pop();
}
g_manager.Get().RemoveImpl(this);
registrar_.reset(NULL);
response_manager_.reset(NULL);
content::WebContentsObserver::Observe(NULL);
......@@ -2265,9 +2327,17 @@ bool CefBrowserHostImpl::TakeFocus(content::WebContents* source,
bool CefBrowserHostImpl::HandleContextMenu(
const content::ContextMenuParams& params) {
if (!menu_creator_.get())
menu_creator_.reset(new CefMenuCreator(this));
return menu_creator_->CreateContextMenu(params);
return HandleContextMenu(web_contents(), params);
}
content::WebContents* CefBrowserHostImpl::GetActionableWebContents() {
if (web_contents() && extensions::ExtensionsEnabled()) {
content::WebContents* guest_contents =
extensions::GetGuestForOwnerContents(web_contents());
if (guest_contents)
return guest_contents;
}
return web_contents();
}
bool CefBrowserHostImpl::PreHandleKeyboardEvent(
......@@ -2451,6 +2521,14 @@ void CefBrowserHostImpl::RunFileChooser(
web_contents, params.mode));
}
bool CefBrowserHostImpl::HandleContextMenu(
content::WebContents* web_contents,
const content::ContextMenuParams& params) {