- Move to a unified thread model for CEF based on the CEF2 implementation.

- Add the ability to post user-defined tasks for execution on CEF threads (issue #25).
- Update the CEF swap image.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@90 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2010-07-24 01:13:55 +00:00
parent 38ded6eec6
commit 7ffa037988
42 changed files with 1800 additions and 1034 deletions

19
cef.gyp
View File

@ -46,7 +46,6 @@
'tests/cefclient/scheme_test.h',
'tests/cefclient/string_util.cpp',
'tests/cefclient/string_util.h',
'tests/cefclient/thread_util.h',
'tests/cefclient/uiplugin.cpp',
'tests/cefclient/uiplugin.h',
'tests/cefclient/uiplugin_test.cpp',
@ -208,6 +207,8 @@
'libcef_dll/ctocpp/scheme_handler_ctocpp.h',
'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc',
'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h',
'libcef_dll/ctocpp/task_ctocpp.cc',
'libcef_dll/ctocpp/task_ctocpp.h',
'libcef_dll/ctocpp/v8handler_ctocpp.cc',
'libcef_dll/ctocpp/v8handler_ctocpp.h',
'libcef_dll/ctocpp/write_handler_ctocpp.cc',
@ -264,6 +265,8 @@
'libcef_dll/ctocpp/stream_reader_ctocpp.h',
'libcef_dll/ctocpp/stream_writer_ctocpp.cc',
'libcef_dll/ctocpp/stream_writer_ctocpp.h',
'libcef_dll/cpptoc/task_cpptoc.cc',
'libcef_dll/cpptoc/task_cpptoc.h',
'libcef_dll/ctocpp/v8value_ctocpp.cc',
'libcef_dll/ctocpp/v8value_ctocpp.h',
'libcef_dll/transfer_util.cpp',
@ -353,11 +356,21 @@
'libcef/browser_webview_delegate.cc',
'libcef/browser_webview_delegate.h',
'libcef/browser_webview_delegate_win.cc',
'libcef/cef_context.cc',
'libcef/cef_context.h',
'libcef/cef_process.cc',
'libcef/cef_process.h',
'libcef/cef_process_io_thread.cc',
'libcef/cef_process_io_thread.h',
'libcef/cef_process_sub_thread.cc',
'libcef/cef_process_sub_thread.h',
'libcef/cef_process_ui_thread.cc',
'libcef/cef_process_ui_thread.h',
'libcef/cef_string.c',
'libcef/cef_string_list.cc',
'libcef/cef_string_map.cc',
'libcef/context.cc',
'libcef/context.h',
'libcef/cef_thread.cc',
'libcef/cef_thread.h',
'libcef/printing/print_settings.cc',
'libcef/printing/print_settings.h',
'libcef/printing/win_printing_context.cc',

View File

@ -54,6 +54,7 @@ class CefSchemeHandler;
class CefSchemeHandlerFactory;
class CefStreamReader;
class CefStreamWriter;
class CefTask;
class CefV8Handler;
class CefV8Value;
@ -153,6 +154,29 @@ bool CefRegisterScheme(const std::wstring& scheme_name,
CefRefPtr<CefSchemeHandlerFactory> factory);
typedef cef_thread_id_t CefThreadId;
// CEF maintains multiple internal threads that are used for handling different
// types of tasks. The UI thread creates the browser window and is used for all
// interaction with the WebKit rendering engine and V8 JavaScript engine (The
// UI thread will be the same as the main application thread if CefInitialize()
// was called with a |multi_threaded_message_loop| value of false.) The IO
// thread is used for handling schema and network requests. The FILE thread is
// used for the application cache and other miscellaneous activities. This
// method will return true if called on the specified thread.
/*--cef()--*/
bool CefCurrentlyOn(CefThreadId threadId);
// Post a task for execution on the specified thread.
/*--cef()--*/
bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task);
// Post a task for delayed execution on the specified thread.
/*--cef()--*/
bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
long delay_ms);
// Interface defining the the reference count implementation methods. All
// framework classes must implement the CefBase class.
class CefBase
@ -285,6 +309,16 @@ inline bool operator!=(const CefRect& a, const CefRect& b)
return !(a == b);
}
// Implement this interface for task execution.
/*--cef(source=client)--*/
class CefTask : public CefBase
{
public:
// Method that will be executed. |threadId| is the thread executing the call.
/*--cef()--*/
virtual void Execute(CefThreadId threadId) =0;
};
// Class used to represent a browser window. All methods exposed by this class
// should be thread safe.

View File

@ -133,6 +133,24 @@ CEF_EXPORT int cef_register_extension(const wchar_t* extension_name,
CEF_EXPORT int cef_register_scheme(const wchar_t* scheme_name,
const wchar_t* host_name, struct _cef_scheme_handler_factory_t* factory);
// CEF maintains multiple internal threads that are used for handling different
// types of tasks. The UI thread creates the browser window and is used for all
// interaction with the WebKit rendering engine and V8 JavaScript engine (The UI
// thread will be the same as the main application thread if cef_initialize()
// was called with a |multi_threaded_message_loop| value of false (0).) The IO
// thread is used for handling schema and network requests. The FILE thread is
// used for the application cache and other miscellaneous activities. This
// function will return true (1) if called on the specified thread.
CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId);
// Post a task for execution on the specified thread.
CEF_EXPORT int cef_post_task(cef_thread_id_t threadId,
struct _cef_task_t* task);
// Post a task for delayed execution on the specified thread.
CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
struct _cef_task_t* task, long delay_ms);
typedef struct _cef_base_t
{
// Size of the data structure.
@ -157,6 +175,19 @@ typedef struct _cef_base_t
#define CEF_MEMBER_MISSING(s, f) (!CEF_MEMBER_EXISTS(s, f) || !((s)->f))
// Implement this structure for task execution.
typedef struct _cef_task_t
{
// Base structure.
cef_base_t base;
// Method that will be executed. |threadId| is the thread executing the call.
void (CEF_CALLBACK *execute)(struct _cef_task_t* self,
cef_thread_id_t threadId);
} cef_task_t;
// Structure used to represent a browser window. All functions exposed by this
// structure should be thread safe.
typedef struct _cef_browser_t

View File

@ -229,6 +229,14 @@ typedef struct _cef_rect_t
int height;
} cef_rect_t;
// Existing thread IDs.
enum cef_thread_id_t
{
TID_UI = 0,
TID_IO = 1,
TID_FILE = 2,
};
#ifdef __cplusplus
}
#endif

View File

@ -408,9 +408,6 @@ WebApplicationCacheHost* BrowserAppCacheSystem::CreateCacheHostForWebKit(
DCHECK(is_ui_thread());
// The IO thread needs to be running for this system to work.
BrowserResourceLoaderBridge::EnsureIOThread();
if (!is_initialized())
return NULL;
return new WebApplicationCacheHostImpl(client, backend_proxy_.get());

View File

@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "context.h"
#include "cef_context.h"
#include "browser_impl.h"
#include "browser_webkit_glue.h"
#include "request_impl.h"
@ -54,39 +54,38 @@ CefBrowserImpl::CefBrowserImpl(CefWindowInfo& windowInfo, bool popup,
void CefBrowserImpl::GoBack()
{
PostTask(FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleActionView, MENU_ID_NAV_BACK));
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleActionView, MENU_ID_NAV_BACK));
}
void CefBrowserImpl::GoForward()
{
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleActionView, MENU_ID_NAV_FORWARD));
}
void CefBrowserImpl::Reload()
{
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleActionView, MENU_ID_NAV_RELOAD));
}
void CefBrowserImpl::StopLoad()
{
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleActionView, MENU_ID_NAV_STOP));
}
void CefBrowserImpl::SetFocus(bool enable)
{
if (_Context->RunningOnUIThread())
if (CefThread::CurrentlyOn(CefThread::UI))
{
UIT_SetFocus(GetWebViewHost(), enable);
}
else
{
PostTask(FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_SetFocus,
GetWebViewHost(), enable));
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_SetFocus, GetWebViewHost(), enable));
}
}
@ -142,14 +141,14 @@ void CefBrowserImpl::Find(int identifier, const std::wstring& searchText,
options.findNext = findNext;
// Execute the request on the UI thread.
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_Find, identifier, searchText, options));
}
void CefBrowserImpl::StopFinding(bool clearSelection)
{
// Execute the request on the UI thread.
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_StopFinding, clearSelection));
}
@ -209,49 +208,49 @@ WebFrame* CefBrowserImpl::GetWebFrame(CefRefPtr<CefFrame> frame)
void CefBrowserImpl::Undo(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_UNDO, frame.get()));
}
void CefBrowserImpl::Redo(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_REDO, frame.get()));
}
void CefBrowserImpl::Cut(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_CUT, frame.get()));
}
void CefBrowserImpl::Copy(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_COPY, frame.get()));
}
void CefBrowserImpl::Paste(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_PASTE, frame.get()));
}
void CefBrowserImpl::Delete(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_DELETE, frame.get()));
}
void CefBrowserImpl::SelectAll(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_SELECTALL, frame.get()));
}
@ -259,14 +258,14 @@ void CefBrowserImpl::SelectAll(CefRefPtr<CefFrame> frame)
void CefBrowserImpl::Print(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_PRINT, frame.get()));
}
void CefBrowserImpl::ViewSource(CefRefPtr<CefFrame> frame)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_HandleAction, MENU_ID_VIEWSOURCE, frame.get()));
}
@ -276,7 +275,7 @@ void CefBrowserImpl::LoadRequest(CefRefPtr<CefFrame> frame,
DCHECK(request.get() != NULL);
frame->AddRef();
request->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_LoadURLForRequestRef, frame.get(), request.get()));
}
@ -284,7 +283,7 @@ void CefBrowserImpl::LoadURL(CefRefPtr<CefFrame> frame,
const std::wstring& url)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_LoadURL, frame.get(), url));
}
@ -293,7 +292,7 @@ void CefBrowserImpl::LoadString(CefRefPtr<CefFrame> frame,
const std::wstring& url)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_LoadHTML, frame.get(), string, url));
}
@ -304,7 +303,7 @@ void CefBrowserImpl::LoadStream(CefRefPtr<CefFrame> frame,
DCHECK(stream.get() != NULL);
frame->AddRef();
stream->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_LoadHTMLForStreamRef, frame.get(), stream.get(),
url));
}
@ -315,7 +314,7 @@ void CefBrowserImpl::ExecuteJavaScript(CefRefPtr<CefFrame> frame,
int startLine)
{
frame->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_ExecuteJavaScript, frame.get(), jsCode, scriptUrl,
startLine));
}
@ -351,7 +350,7 @@ bool CefBrowser::CreateBrowser(CefWindowInfo& windowInfo, bool popup,
CefRefPtr<CefBrowserImpl> browser(
new CefBrowserImpl(windowInfo, popup, handler));
PostTask(FROM_HERE, NewRunnableMethod(browser.get(),
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(browser.get(),
&CefBrowserImpl::UIT_CreateBrowser, newUrl));
return true;
}
@ -361,7 +360,7 @@ CefRefPtr<CefBrowser> CefBrowser::CreateBrowserSync(CefWindowInfo& windowInfo,
CefRefPtr<CefHandler> handler,
const std::wstring& url)
{
if(!_Context.get() || !_Context->RunningOnUIThread())
if(!_Context.get() || !CefThread::CurrentlyOn(CefThread::UI))
return NULL;
std::wstring newUrl = url;

View File

@ -7,11 +7,11 @@
#define _BROWSER_IMPL_H
#include "include/cef.h"
#include "context.h"
#include "webview_host.h"
#include "browser_webview_delegate.h"
#include "browser_navigation_controller.h"
#include "cef_thread.h"
#if defined(OS_WIN)
#include "printing/win_printing_context.h"
#endif

View File

@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "context.h"
#include "cef_context.h"
#include "browser_impl.h"
#include "browser_webkit_glue.h"
#include "stream_impl.h"
@ -111,7 +111,7 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle()
std::wstring CefBrowserImpl::GetSource(CefRefPtr<CefFrame> frame)
{
if(!_Context->RunningOnUIThread())
if(!CefThread::CurrentlyOn(CefThread::UI))
{
// We need to send the request to the UI thread and wait for the result
@ -125,7 +125,7 @@ std::wstring CefBrowserImpl::GetSource(CefRefPtr<CefFrame> frame)
// Request the data from the UI thread
frame->AddRef();
stream->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_GetDocumentStringNotify, frame.get(), stream.get(),
hEvent));
@ -150,7 +150,7 @@ std::wstring CefBrowserImpl::GetSource(CefRefPtr<CefFrame> frame)
std::wstring CefBrowserImpl::GetText(CefRefPtr<CefFrame> frame)
{
if(!_Context->RunningOnUIThread())
if(!CefThread::CurrentlyOn(CefThread::UI))
{
// We need to send the request to the UI thread and wait for the result
@ -164,7 +164,7 @@ std::wstring CefBrowserImpl::GetText(CefRefPtr<CefFrame> frame)
// Request the data from the UI thread
frame->AddRef();
stream->AddRef();
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_GetDocumentTextNotify, frame.get(), stream.get(),
hEvent));
@ -187,7 +187,7 @@ std::wstring CefBrowserImpl::GetText(CefRefPtr<CefFrame> frame)
bool CefBrowserImpl::CanGoBack()
{
if(!_Context->RunningOnUIThread())
if(!CefThread::CurrentlyOn(CefThread::UI))
{
// We need to send the request to the UI thread and wait for the result
@ -199,7 +199,7 @@ bool CefBrowserImpl::CanGoBack()
bool retVal = true;
// Request the data from the UI thread
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_CanGoBackNotify, &retVal, hEvent));
// Wait for the UI thread callback to tell us that the data is available
@ -217,7 +217,7 @@ bool CefBrowserImpl::CanGoBack()
bool CefBrowserImpl::CanGoForward()
{
if(!_Context->RunningOnUIThread())
if(!CefThread::CurrentlyOn(CefThread::UI))
{
// We need to send the request to the UI thread and wait for the result
@ -229,7 +229,7 @@ bool CefBrowserImpl::CanGoForward()
bool retVal = true;
// Request the data from the UI thread
PostTask(FROM_HERE, NewRunnableMethod(this,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(this,
&CefBrowserImpl::UIT_CanGoForwardNotify, &retVal, hEvent));
// Wait for the UI thread callback to tell us that the data is available
@ -254,7 +254,7 @@ void CefBrowserImpl::UIT_CreateBrowser(const std::wstring& url)
window_info_.m_windowName, window_info_.m_dwStyle,
window_info_.m_x, window_info_.m_y, window_info_.m_nWidth,
window_info_.m_nHeight, window_info_.m_hWndParent, window_info_.m_hMenu,
_Context->GetInstanceHandle(), NULL);
::GetModuleHandle(NULL), NULL);
DCHECK(window_info_.m_hWnd != NULL);
// Set window user data to this object for future reference from the window
@ -269,7 +269,7 @@ void CefBrowserImpl::UIT_CreateBrowser(const std::wstring& url)
// Create the webview host object
webviewhost_.reset(
WebViewHost::Create(window_info_.m_hWnd, delegate_.get(),
*_Context->GetWebPreferences()));
*_Context->web_preferences()));
delegate_->RegisterDragDrop();
// Size the web view window to the browser window

View File

@ -73,6 +73,13 @@ BrowserRequestContext::~BrowserRequestContext() {
delete static_cast<net::StaticCookiePolicy*>(cookie_policy_);
}
void BrowserRequestContext::SetAcceptAllCookies(bool accept_all_cookies) {
net::StaticCookiePolicy::Type policy_type = accept_all_cookies ?
net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES;
static_cast<net::StaticCookiePolicy*>(cookie_policy())->set_type(policy_type);
}
const std::string& BrowserRequestContext::GetUserAgent(
const GURL& url) const {
return webkit_glue::GetUserAgent(url);

View File

@ -16,6 +16,7 @@ class BrowserRequestContext : public URLRequestContext {
public:
// Use an in-memory cache
BrowserRequestContext();
~BrowserRequestContext();
// Use an on-disk cache at the specified location. Optionally, use the cache
// in playback or record mode.
@ -25,9 +26,9 @@ class BrowserRequestContext : public URLRequestContext {
virtual const std::string& GetUserAgent(const GURL& url) const;
private:
~BrowserRequestContext();
void SetAcceptAllCookies(bool accept_all_cookies);
private:
void Init(const FilePath& cache_path, net::HttpCache::Mode cache_mode,
bool no_proxy);
};

View File

@ -36,6 +36,9 @@
#include "browser_request_context.h"
#include "browser_socket_stream_bridge.h"
#include "browser_impl.h"
#include "cef_context.h"
#include "cef_process.h"
#include "cef_process_io_thread.h"
#include "request_impl.h"
#include "base/file_path.h"
@ -73,80 +76,6 @@ using net::StaticCookiePolicy;
namespace {
struct BrowserRequestContextParams {
BrowserRequestContextParams(
const FilePath& in_cache_path,
net::HttpCache::Mode in_cache_mode,
bool in_no_proxy)
: cache_path(in_cache_path),
cache_mode(in_cache_mode),
no_proxy(in_no_proxy),
accept_all_cookies(false) {}
FilePath cache_path;
net::HttpCache::Mode cache_mode;
bool no_proxy;
bool accept_all_cookies;
};
BrowserRequestContextParams* g_request_context_params = NULL;
URLRequestContext* g_request_context = NULL;
base::Thread* g_cache_thread = NULL;
//-----------------------------------------------------------------------------
class IOThread : public base::Thread {
public:
IOThread() : base::Thread("IOThread") {
}
~IOThread() {
// We cannot rely on our base class to stop the thread since we want our
// CleanUp function to run.
Stop();
}
virtual void Init() {
if (g_request_context_params) {
g_request_context = new BrowserRequestContext(
g_request_context_params->cache_path,
g_request_context_params->cache_mode,
g_request_context_params->no_proxy);
SetAcceptAllCookies(g_request_context_params->accept_all_cookies);
delete g_request_context_params;
g_request_context_params = NULL;
} else {
g_request_context = new BrowserRequestContext();
SetAcceptAllCookies(false);
}
g_request_context->AddRef();
BrowserAppCacheSystem::InitializeOnIOThread(g_request_context);
BrowserSocketStreamBridge::InitializeOnIOThread(g_request_context);
}
virtual void CleanUp() {
BrowserSocketStreamBridge::Cleanup();
if (g_request_context) {
g_request_context->Release();
g_request_context = NULL;
}
}
void SetAcceptAllCookies(bool accept_all_cookies) {
StaticCookiePolicy::Type policy_type = accept_all_cookies ?
StaticCookiePolicy::ALLOW_ALL_COOKIES :
StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES;
static_cast<StaticCookiePolicy*>(g_request_context->cookie_policy())->
set_type(policy_type);
}
};
IOThread* g_io_thread = NULL;
//-----------------------------------------------------------------------------
struct RequestParams {
std::string method;
GURL url;
@ -185,13 +114,13 @@ class RequestProxy : public URLRequest::Delegate,
owner_loop_ = MessageLoop::current();
// proxy over to the io thread
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
this, &RequestProxy::AsyncStart, params));
}
void Cancel() {
// proxy over to the io thread
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
this, &RequestProxy::AsyncCancel));
}
@ -200,8 +129,7 @@ class RequestProxy : public URLRequest::Delegate,
virtual ~RequestProxy() {
// If we have a request, then we'd better be on the io thread!
DCHECK(!request_.get() ||
MessageLoop::current() == g_io_thread->message_loop());
DCHECK(!request_.get() || CefThread::CurrentlyOn(CefThread::IO));
}
// --------------------------------------------------------------------------
@ -216,7 +144,7 @@ class RequestProxy : public URLRequest::Delegate,
if (peer_ && peer_->OnReceivedRedirect(new_url, info,
&has_new_first_party_for_cookies,
&new_first_party_for_cookies)) {
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
this, &RequestProxy::AsyncFollowDeferredRedirect,
has_new_first_party_for_cookies, new_first_party_for_cookies));
} else {
@ -245,7 +173,7 @@ class RequestProxy : public URLRequest::Delegate,
// peer could generate new requests in reponse to the received data, which
// when run on the io thread, could race against this function in doing
// another InvokeLater. See bug 769249.
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
this, &RequestProxy::AsyncReadData));
peer_->OnReceivedData(buf_copy.get(), bytes_read);
@ -349,7 +277,7 @@ class RequestProxy : public URLRequest::Delegate,
request_->SetExtraRequestHeaders(headers);
request_->set_load_flags(params->load_flags);
request_->set_upload(params->upload.get());
request_->set_context(g_request_context);
request_->set_context(_Context->request_context());
BrowserAppCacheSystem::SetExtraRequestInfo(
request_.get(), params->appcache_host_id, params->request_type);
@ -657,7 +585,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
if (proxy_) {
proxy_->DropPeer();
// Let the proxy die on the IO thread
g_io_thread->message_loop()->ReleaseSoon(FROM_HERE, proxy_);
CefThread::ReleaseSoon(CefThread::IO, FROM_HERE, proxy_);
}
}
@ -693,9 +621,6 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
virtual bool Start(Peer* peer) {
DCHECK(!proxy_);
if (!BrowserResourceLoaderBridge::EnsureIOThread())
return false;
proxy_ = new RequestProxy(browser_);
proxy_->AddRef();
@ -716,9 +641,6 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
virtual void SyncLoad(SyncLoadResponse* response) {
DCHECK(!proxy_);
if (!BrowserResourceLoaderBridge::EnsureIOThread())
return;
// this may change as the result of a redirect
response->url = params_->url;
@ -746,8 +668,8 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
class CookieSetter : public base::RefCountedThreadSafe<CookieSetter> {
public:
void Set(const GURL& url, const std::string& cookie) {
DCHECK(MessageLoop::current() == g_io_thread->message_loop());
g_request_context->cookie_store()->SetCookie(url, cookie);
REQUIRE_IOT();
_Context->request_context()->cookie_store()->SetCookie(url, cookie);
}
private:
@ -762,7 +684,7 @@ class CookieGetter : public base::RefCountedThreadSafe<CookieGetter> {
}
void Get(const GURL& url) {
result_ = g_request_context->cookie_store()->GetCookies(url);
result_ = _Context->request_context()->cookie_store()->GetCookies(url);
event_.Signal();
}
@ -798,11 +720,12 @@ ResourceLoaderBridge* ResourceLoaderBridge::Create(
// Issue the proxy resolve request on the io thread, and wait
// for the result.
bool FindProxyForUrl(const GURL& url, std::string* proxy_list) {
DCHECK(g_request_context);
DCHECK(_Context->request_context());
scoped_refptr<net::SyncProxyServiceHelper> sync_proxy_service(
new net::SyncProxyServiceHelper(g_io_thread->message_loop(),
g_request_context->proxy_service()));
new net::SyncProxyServiceHelper(
_Context->process()->io_thread()->message_loop(),
_Context->request_context()->proxy_service()));
net::ProxyInfo proxy_info;
int rv = sync_proxy_service->ResolveProxy(url, &proxy_info,
@ -818,53 +741,14 @@ bool FindProxyForUrl(const GURL& url, std::string* proxy_list) {
//-----------------------------------------------------------------------------
// static
void BrowserResourceLoaderBridge::Init(
const FilePath& cache_path,
net::HttpCache::Mode cache_mode,
bool no_proxy) {
// Make sure to stop any existing IO thread since it may be using the
// current request context.
Shutdown();
DCHECK(!g_request_context_params);
DCHECK(!g_request_context);
DCHECK(!g_io_thread);
g_request_context_params = new BrowserRequestContextParams(
cache_path, cache_mode, no_proxy);
}
// static
void BrowserResourceLoaderBridge::Shutdown() {
if (g_io_thread) {
delete g_io_thread;
g_io_thread = NULL;
DCHECK(g_cache_thread);
delete g_cache_thread;
g_cache_thread = NULL;
DCHECK(!g_request_context) << "should have been nulled by thread dtor";
} else {
delete g_request_context_params;
g_request_context_params = NULL;
}
}
// static
void BrowserResourceLoaderBridge::SetCookie(const GURL& url,
const GURL& first_party_for_cookies,
const std::string& cookie) {
// Proxy to IO thread to synchronize w/ network loading.
if (!EnsureIOThread()) {
NOTREACHED();
return;
}
scoped_refptr<CookieSetter> cookie_setter = new CookieSetter();
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
cookie_setter.get(), &CookieSetter::Set, url, cookie));
}
@ -873,61 +757,24 @@ std::string BrowserResourceLoaderBridge::GetCookies(
const GURL& url, const GURL& first_party_for_cookies) {
// Proxy to IO thread to synchronize w/ network loading
if (!EnsureIOThread()) {
NOTREACHED();
return std::string();
}
scoped_refptr<CookieGetter> getter = new CookieGetter();
g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
getter.get(), &CookieGetter::Get, url));
return getter->GetResult();
}
// static
bool BrowserResourceLoaderBridge::EnsureIOThread() {
if (g_io_thread)
return true;
#if defined(OS_WIN)
// Use NSS for SSL on Windows. TODO(wtc): this should eventually be hidden
// inside DefaultClientSocketFactory::CreateSSLClientSocket.
net::ClientSocketFactory::SetSSLClientSocketFactory(
net::SSLClientSocketNSSFactory);
#endif
#if defined(OS_MACOSX) || defined(OS_WIN)
// We want to be sure to init NSPR on the main thread.
base::EnsureNSPRInit();
#endif
// Create the cache thread. We want the cache thread to outlive the IO thread,
// so its lifetime is bonded to the IO thread lifetime.
DCHECK(!g_cache_thread);
g_cache_thread = new base::Thread("cache");
CHECK(g_cache_thread->StartWithOptions(
base::Thread::Options(MessageLoop::TYPE_IO, 0)));
g_io_thread = new IOThread();
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
return g_io_thread->StartWithOptions(options);
}
// static
void BrowserResourceLoaderBridge::SetAcceptAllCookies(bool accept_all_cookies) {
if (g_request_context_params) {
g_request_context_params->accept_all_cookies = accept_all_cookies;
DCHECK(!g_request_context);
DCHECK(!g_io_thread);
} else {
g_io_thread->SetAcceptAllCookies(accept_all_cookies);
}
// Proxy to IO thread to synchronize w/ network loading
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
_Context->request_context().get(),
&BrowserRequestContext::SetAcceptAllCookies, accept_all_cookies));
}
// static
//static
scoped_refptr<base::MessageLoopProxy>
BrowserResourceLoaderBridge::GetCacheThread() {
return g_cache_thread->message_loop_proxy();
return CefThread::GetMessageLoopProxyForThread(CefThread::FILE);
}

View File

@ -15,29 +15,14 @@ class GURL;
class BrowserResourceLoaderBridge {
public:
// Call this function to initialize the simple resource loader bridge.
// It is safe to call this function multiple times.
//
// NOTE: If this function is not called, then a default request context will
// be initialized lazily.
//
static void Init(const FilePath& cache_path,
net::HttpCache::Mode cache_mode,
bool no_proxy);
// Call this function to shutdown the simple resource loader bridge.
static void Shutdown();
// May only be called after Init.
static void SetCookie(const GURL& url,
const GURL& first_party_for_cookies,
const std::string& cookie);
static std::string GetCookies(const GURL& url,
const GURL& first_party_for_cookies);
static bool EnsureIOThread();
static void SetAcceptAllCookies(bool accept_all_cookies);
// This method should only be called after Init(), and before Shutdown().
static scoped_refptr<base::MessageLoopProxy> GetCacheThread();
};

View File

@ -11,7 +11,7 @@
#include "browser_appcache_system.h"
#include "browser_impl.h"
#include "browser_navigation_controller.h"
#include "context.h"
#include "cef_context.h"
#include "request_impl.h"
#include "v8_impl.h"
@ -126,13 +126,13 @@ int next_page_id_ = 1;
// WebViewDelegate -----------------------------------------------------------
void BrowserWebViewDelegate::SetUserStyleSheetEnabled(bool is_enabled) {
WebPreferences* prefs = _Context->GetWebPreferences();
WebPreferences* prefs = _Context->web_preferences();
prefs->user_style_sheet_enabled = is_enabled;
prefs->Apply(browser_->GetWebView());
}
void BrowserWebViewDelegate::SetUserStyleSheetLocation(const GURL& location) {
WebPreferences* prefs = _Context->GetWebPreferences();
WebPreferences* prefs = _Context->web_preferences();
prefs->user_style_sheet_enabled = true;
prefs->user_style_sheet_location = location;
prefs->Apply(browser_->GetWebView());

View File

@ -12,7 +12,7 @@
#include "browser_drop_delegate.h"
#include "browser_navigation_controller.h"
#include "browser_impl.h"
#include "context.h"
#include "cef_context.h"
#include <objidl.h>
#include <shlobj.h>

322
libcef/cef_context.cc Normal file
View File

@ -0,0 +1,322 @@
// Copyright (c) 2010 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 "cef_context.h"
#include "browser_impl.h"
#include "browser_webkit_glue.h"
#include "cef_thread.h"
#include "cef_process.h"
#include "../include/cef_nplugin.h"
#include "base/file_util.h"
#if defined(OS_MACOSX) || defined(OS_WIN)
#include "base/nss_util.h"
#endif
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/webpreferences.h"
// Global CefContext pointer
CefRefPtr<CefContext> _Context;
bool CefInitialize(bool multi_threaded_message_loop,
const std::wstring& cache_path)
{
// Return true if the context is already initialized
if(_Context.get())
return true;
// Create the new global context object
_Context = new CefContext();
// Initialize the global context
return _Context->Initialize(multi_threaded_message_loop, cache_path);
}
void CefShutdown()
{
// Verify that the context is already initialized
if(!_Context.get())
return;
// Shut down the global context
_Context->Shutdown();
// Delete the global context object
_Context = NULL;
}
void CefDoMessageLoopWork()
{
// Verify that the context is already initialized.
if(!_Context.get() || !_Context->process())
return;
if(!_Context->process()->CalledOnValidThread())
return;
_Context->process()->DoMessageLoopIteration();
}
static void UIT_RegisterPlugin(struct CefPluginInfo* plugin_info)
{
REQUIRE_UIT();
NPAPI::PluginVersionInfo info;
info.path = FilePath(plugin_info->unique_name);
info.product_name = plugin_info->display_name;
info.file_description = plugin_info->description;
info.file_version =plugin_info->version;
for(size_t i = 0; i < plugin_info->mime_types.size(); ++i) {
if(i > 0) {
info.mime_types += L"|";
info.file_extensions += L"|";
info.type_descriptions += L"|";
}
info.mime_types += plugin_info->mime_types[i].mime_type;
info.type_descriptions += plugin_info->mime_types[i].description;
for(size_t j = 0;
j < plugin_info->mime_types[i].file_extensions.size(); ++j) {
if(j > 0) {
info.file_extensions += L",";
}
info.file_extensions += plugin_info->mime_types[i].file_extensions[j];
}
}
info.entry_points.np_getentrypoints = plugin_info->np_getentrypoints;
info.entry_points.np_initialize = plugin_info->np_initialize;
info.entry_points.np_shutdown = plugin_info->np_shutdown;
NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
delete plugin_info;
}
bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info)
{
if(!_Context.get())
return false;
CefPluginInfo* pPluginInfo = new CefPluginInfo;
*pPluginInfo = plugin_info;
CefThread::PostTask(CefThread::UI, FROM_HERE,
NewRunnableFunction(UIT_RegisterPlugin, pPluginInfo));
return true;
}
static int GetThreadId(CefThreadId threadId)
{
switch(threadId) {
case TID_UI: return CefThread::UI;
case TID_IO: return CefThread::IO;
case TID_FILE: return CefThread::FILE;
};
NOTREACHED();
return -1;
}
bool CefCurrentlyOn(CefThreadId threadId)
{
int id = GetThreadId(threadId);
if(id < 0)
return false;
return CefThread::CurrentlyOn(static_cast<CefThread::ID>(id));
}
class CefTaskHelper : public base::RefCountedThreadSafe<CefTaskHelper>
{
public:
CefTaskHelper(CefRefPtr<CefTask> task) : task_(task) {}
void Execute(CefThreadId threadId) { task_->Execute(threadId); }
private:
CefRefPtr<CefTask> task_;
DISALLOW_COPY_AND_ASSIGN(CefTaskHelper);
};
bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task)
{
int id = GetThreadId(threadId);
if(id < 0)
return false;
scoped_refptr<CefTaskHelper> helper(new CefTaskHelper(task));
return CefThread::PostTask(static_cast<CefThread::ID>(id), FROM_HERE,
NewRunnableMethod(helper.get(), &CefTaskHelper::Execute, threadId));
}
bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
long delay_ms)
{
int id = GetThreadId(threadId);
if(id < 0)
return false;
scoped_refptr<CefTaskHelper> helper(new CefTaskHelper(task));
return CefThread::PostDelayedTask(static_cast<CefThread::ID>(id), FROM_HERE,
NewRunnableMethod(helper.get(), &CefTaskHelper::Execute, threadId),
delay_ms);
}
// CefContext
CefContext::CefContext() : process_(NULL), webprefs_(NULL)
{
}
CefContext::~CefContext()
{
// Just in case CefShutdown() isn't called
Shutdown();
}
bool CefContext::Initialize(bool multi_threaded_message_loop,
const std::wstring& cache_path)
{
cache_path_ = cache_path;
// Initialize web preferences
webprefs_ = new WebPreferences;
*webprefs_ = WebPreferences();
webprefs_->standard_font_family = L"Times";
webprefs_->fixed_font_family = L"Courier";
webprefs_->serif_font_family = L"Times";
webprefs_->sans_serif_font_family = L"Helvetica";
// These two fonts are picked from the intersection of
// Win XP font list and Vista font list :
// http://www.microsoft.com/typography/fonts/winxp.htm
// http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
// Some of them are installed only with CJK and complex script
// support enabled on Windows XP and are out of consideration here.
// (although we enabled both on our buildbots.)
// They (especially Impact for fantasy) are not typical cursive
// and fantasy fonts, but it should not matter for layout tests
// as long as they're available.
#if defined(OS_MACOSX)
webprefs_->cursive_font_family = L"Apple Chancery";
webprefs_->fantasy_font_family = L"Papyrus";
#else
webprefs_->cursive_font_family = L"Comic Sans MS";
webprefs_->fantasy_font_family = L"Impact";
#endif
webprefs_->default_encoding = "ISO-8859-1";
webprefs_->default_font_size = 16;
webprefs_->default_fixed_font_size = 13;
webprefs_->minimum_font_size = 1;
webprefs_->minimum_logical_font_size = 9;
webprefs_->javascript_can_open_windows_automatically = true;
webprefs_->dom_paste_enabled = true;
webprefs_->developer_extras_enabled = true;
webprefs_->site_specific_quirks_enabled = true;
webprefs_->shrinks_standalone_images_to_fit = false;
webprefs_->uses_universal_detector = false;
webprefs_->text_areas_are_resizable = true;
webprefs_->java_enabled = true;
webprefs_->allow_scripts_to_close_windows = false;
webprefs_->xss_auditor_enabled = false;
webprefs_->remote_fonts_enabled = true;
webprefs_->local_storage_enabled = true;
webprefs_->application_cache_enabled = true;
webprefs_->databases_enabled = true;
webprefs_->allow_file_access_from_file_urls = true;
#if defined(OS_MACOSX) || defined(OS_WIN)
// We want to be sure to init NSPR on the main thread.
base::EnsureNSPRInit();
#endif
process_ = new CefProcess(multi_threaded_message_loop);
process_->CreateChildThreads();
return true;
}
void CefContext::Shutdown()
{
// Remove all existing browsers.
//RemoveAllBrowsers();
// Deleting the process will destroy the child threads.
process_ = NULL;
}
bool CefContext::AddBrowser(CefRefPtr<CefBrowserImpl> browser)
{
bool found = false;
Lock();
// check that the browser isn't already in the list before adding
BrowserList::const_iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get() == browser.get()) {
found = true;
break;
}
}
if(!found)
{
browser->UIT_SetUniqueID(next_browser_id_++);
browserlist_.push_back(browser);
}
Unlock();
return !found;
}
bool CefContext::RemoveBrowser(CefRefPtr<CefBrowserImpl> browser)
{
bool deleted = false;
bool empty = false;
Lock();
BrowserList::iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get() == browser.get()) {
browserlist_.erase(it);
deleted = true;
break;
}
}
if (browserlist_.empty()) {
next_browser_id_ = 1;
empty = true;
}
Unlock();
if (empty) {
CefThread::PostTask(CefThread::UI, FROM_HERE,
NewRunnableFunction(webkit_glue::ClearCache));
}
return deleted;
}
CefRefPtr<CefBrowserImpl> CefContext::GetBrowserByID(int id)
{
CefRefPtr<CefBrowserImpl> browser;
Lock();
BrowserList::const_iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get()->UIT_GetUniqueID() == id) {
browser = it->get();
break;
}
}
Unlock();
return browser;
}

81
libcef/cef_context.h Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2010 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_CONTEXT_H
#define _CEF_CONTEXT_H
#include "../include/cef.h"
#include "browser_request_context.h"
#include "cef_process.h"
#include "cef_thread.h"
#include "base/at_exit.h"
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include <map>
class BrowserRequestContext;
class CefBrowserImpl;
struct WebPreferences;
class CefContext : public CefThreadSafeBase<CefBase>
{
public:
typedef std::list<CefRefPtr<CefBrowserImpl> > BrowserList;
CefContext();
~CefContext();
// These methods will be called on the main application thread.
bool Initialize(bool multi_threaded_message_loop,
const std::wstring& cache_path);
void Shutdown();
scoped_refptr<CefProcess> process() { return process_; }
bool AddBrowser(CefRefPtr<CefBrowserImpl> browser);
bool RemoveBrowser(CefRefPtr<CefBrowserImpl> browser);
CefRefPtr<CefBrowserImpl> GetBrowserByID(int id);
BrowserList* GetBrowserList() { return &browserlist_; }
// Retrieve the path at which cache data will be stored on disk. If empty,
// cache data will be stored in-memory.
const std::wstring& cache_path() { return cache_path_; }
WebPreferences* web_preferences()
{
REQUIRE_UIT();
return webprefs_;
}
// The BrowserRequestContext object is managed by CefProcessIOThread.
void set_request_context(BrowserRequestContext* request_context)
{ request_context_ = request_context; }
scoped_refptr<BrowserRequestContext> request_context()
{ return request_context_; }
private:
// Manages the various process threads.
scoped_refptr<CefProcess> process_;
// Initialize the AtExitManager on the main application thread to avoid
// asserts and possible memory leaks.
base::AtExitManager at_exit_manager_;
std::wstring cache_path_;
WebPreferences* webprefs_;
scoped_refptr<BrowserRequestContext> request_context_;
// Map of browsers that currently exist.
BrowserList browserlist_;
// Used for assigning unique IDs to browser instances.
int next_browser_id_;
};
// Global context object pointer
extern CefRefPtr<CefContext> _Context;
#endif // _CONTEXT_H

134
libcef/cef_process.cc Normal file
View File

@ -0,0 +1,134 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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 "cef_process.h"
#include "cef_process_io_thread.h"
#include "cef_process_sub_thread.h"
#include "cef_process_ui_thread.h"
#include "base/thread.h"
#include "base/waitable_event.h"
CefProcess* g_cef_process = NULL;
// Class used to process events on the current message loop.
class CefMessageLoopForUI : public MessageLoopForUI
{
typedef MessageLoopForUI inherited;
public:
CefMessageLoopForUI()
{
}
// Returns the MessageLoopForUI of the current thread.
static CefMessageLoopForUI* current() {
MessageLoop* loop = MessageLoop::current();
DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
return static_cast<CefMessageLoopForUI*>(loop);
}
virtual bool DoIdleWork() {
bool valueToRet = inherited::DoIdleWork();
pump_->Quit();
return valueToRet;
}
void DoMessageLoopIteration() {
Run(NULL);
}
private:
DISALLOW_COPY_AND_ASSIGN(CefMessageLoopForUI);
};
CefProcess::CefProcess(bool multi_threaded_message_loop)
: multi_threaded_message_loop_(multi_threaded_message_loop),
created_ui_thread_(false),
created_io_thread_(false),
created_file_thread_(false) {
g_cef_process = this;
}
CefProcess::~CefProcess() {
// Terminate the IO thread.
io_thread_.reset();
// Terminate the FILE thread.
file_thread_.reset();
if(!multi_threaded_message_loop_) {
// Must explicitly clean up the UI thread.
ui_thread_->CleanUp();
// Terminate the UI thread.
ui_thread_.reset();
// Terminate the message loop.
ui_message_loop_.reset();
}
g_cef_process = NULL;
}
void CefProcess::DoMessageLoopIteration() {
DCHECK(CalledOnValidThread() && ui_message_loop_.get() != NULL);
ui_message_loop_->DoMessageLoopIteration();
}
void CefProcess::CreateUIThread() {
DCHECK(!created_ui_thread_ && ui_thread_.get() == NULL);
created_ui_thread_ = true;
scoped_ptr<CefProcessUIThread> thread;
if(multi_threaded_message_loop_) {
// Create the message loop on a new thread.
thread.reset(new CefProcessUIThread());
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_UI;
if (!thread->StartWithOptions(options))
return;
} else {
// Create the message loop on the current (main application) thread.
ui_message_loop_.reset(new CefMessageLoopForUI());
thread.reset(
new CefProcessUIThread(ui_message_loop_.get()));
// Must explicitly initialize the UI thread.
thread->Init();
}
ui_thread_.swap(thread);
}
void CefProcess::CreateIOThread() {
DCHECK(!created_io_thread_ && io_thread_.get() == NULL);
created_io_thread_ = true;
scoped_ptr<CefProcessIOThread> thread(new CefProcessIOThread());
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
if (!thread->StartWithOptions(options))
return;
io_thread_.swap(thread);
}
void CefProcess::CreateFileThread() {
DCHECK(!created_file_thread_ && file_thread_.get() == NULL);
created_file_thread_ = true;
scoped_ptr<base::Thread> thread(new CefProcessSubThread(CefThread::FILE));
base::Thread::Options options;
#if defined(OS_WIN)
// On Windows, the FILE thread needs to be have a UI message loop which pumps
// messages in such a way that Google Update can communicate back to us.
options.message_loop_type = MessageLoop::TYPE_UI;
#else
options.message_loop_type = MessageLoop::TYPE_IO;
#endif
if (!thread->StartWithOptions(options))
return;
file_thread_.swap(thread);
}

117
libcef/cef_process.h Normal file
View File

@ -0,0 +1,117 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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.
// This interface is for managing the global services of the application. Each
// service is lazily created when requested the first time. The service getters
// will return NULL if the service is not available, so callers must check for
// this condition.
#ifndef _CEF_PROCESS_H
#define _CEF_PROCESS_H
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "ipc/ipc_message.h"
namespace base {
class Thread;
class WaitableEvent;
}
class CefProcessIOThread;
class CefProcessUIThread;
class CefMessageLoopForUI;
// NOT THREAD SAFE, call only from the main thread.
// These functions shouldn't return NULL unless otherwise noted.
class CefProcess : public base::RefCounted<CefProcess>, public NonThreadSafe {
public:
CefProcess(bool multi_threaded_message_loop);
virtual ~CefProcess();
// Creates key child threads. We need to do this explicitly since
// CefThread::PostTask silently deletes a posted task if the target message
// loop isn't created.
void CreateChildThreads() {
ui_thread();
// Create the FILE thread before the IO thread because IO thread
// initialization depends on existance of the FILE thread (for cache
// support, etc).
file_thread();
io_thread();
}
CefProcessUIThread* ui_thread() {
DCHECK(CalledOnValidThread());
if (!created_ui_thread_)
CreateUIThread();
return ui_thread_.get();
}
// Necessary to perform work on the UI thread if started without a multi
// threaded message loop.
void DoMessageLoopIteration();
// Returns the thread that we perform I/O coordination on (network requests,
// communication with renderers, etc.
// NOTE: You should ONLY use this to pass to IPC or other objects which must
// need a MessageLoop*. If you just want to post a task, use
// CefThread::PostTask (or other variants) as they take care of checking
// that a thread is still alive, race conditions, lifetime differences etc.
// If you still must use this, need to check the return value for NULL.
CefProcessIOThread* io_thread() {
DCHECK(CalledOnValidThread());
if (!created_io_thread_)
CreateIOThread();
return io_thread_.get();
}
// Returns the thread that we perform random file operations on. For code
// that wants to do I/O operations (not network requests or even file: URL
// requests), this is the thread to use to avoid blocking the UI thread.
// It might be nicer to have a thread pool for this kind of thing.
base::Thread* file_thread() {
DCHECK(CalledOnValidThread());
if (!created_file_thread_)
CreateFileThread();
return file_thread_.get();
}
#if defined(IPC_MESSAGE_LOG_ENABLED)
// Enable or disable IPC logging for the browser, all processes
// derived from ChildProcess (plugin etc), and all
// renderers.
void SetIPCLoggingEnabled(bool enable);
#endif
private:
void CreateUIThread();
void CreateIOThread();
void CreateFileThread();
bool multi_threaded_message_loop_;
bool created_ui_thread_;
scoped_ptr<CefProcessUIThread> ui_thread_;
scoped_ptr<CefMessageLoopForUI> ui_message_loop_;
bool created_io_thread_;
scoped_ptr<CefProcessIOThread> io_thread_;
bool created_file_thread_;
scoped_ptr<base::Thread> file_thread_;
DISALLOW_COPY_AND_ASSIGN(CefProcess);
};
extern CefProcess* g_cef_process;
#endif // _CEF_PROCESS_H

View File

@ -0,0 +1,60 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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 "cef_process_io_thread.h"
#include "cef_context.h"
#include "browser_appcache_system.h"
#include "browser_resource_loader_bridge.h"
#include "browser_socket_stream_bridge.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include <Objbase.h>
#endif
CefProcessIOThread::CefProcessIOThread()
: CefThread(CefThread::IO), request_context_(NULL) {}
CefProcessIOThread::CefProcessIOThread(MessageLoop* message_loop)
: CefThread(CefThread::IO, message_loop), request_context_(NULL) {}
CefProcessIOThread::~CefProcessIOThread() {
// We cannot rely on our base class to stop the thread since we want our
// CleanUp function to run.
Stop();
}
void CefProcessIOThread::Init() {
#if defined(OS_WIN)
// Initializes the COM library on the current thread.
CoInitialize(NULL);
#endif
request_context_ = new BrowserRequestContext(FilePath(_Context->cache_path()),
net::HttpCache::NORMAL, false);
_Context->set_request_context(request_context_);
BrowserAppCacheSystem::InitializeOnIOThread(request_context_);
BrowserSocketStreamBridge::InitializeOnIOThread(request_context_);
}
void CefProcessIOThread::CleanUp() {
// Flush any remaining messages. This ensures that any accumulated
// Task objects get destroyed before we exit, which avoids noise in
// purify leak-test results.
MessageLoop::current()->RunAllPending();
BrowserSocketStreamBridge::Cleanup();
_Context->set_request_context(NULL);
request_context_ = NULL;
#if defined(OS_WIN)
// Closes the COM library on the current thread. CoInitialize must
// be balanced by a corresponding call to CoUninitialize.
CoUninitialize();
#endif
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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_PROCESS_IO_THREAD
#define _CEF_PROCESS_IO_THREAD
#include "base/basictypes.h"
#include "cef_thread.h"
#include "browser_request_context.h"
// ----------------------------------------------------------------------------
// CefProcessIOThread
//
// This simple thread object is used for the specialized threads that the
// CefProcess spins up.
//
// Applications must initialize the COM library before they can call
// COM library functions other than CoGetMalloc and memory allocation
// functions, so this class initializes COM for those users.
class CefProcessIOThread : public CefThread {
public:
explicit CefProcessIOThread();
CefProcessIOThread(MessageLoop* message_loop);
virtual ~CefProcessIOThread();
virtual void Init();
virtual void CleanUp();
scoped_refptr<BrowserRequestContext> request_context()
{ return request_context_; }
private:
scoped_refptr<BrowserRequestContext> request_context_;
DISALLOW_COPY_AND_ASSIGN(CefProcessIOThread);
};
#endif // _CEF_PROCESS_UI_THREAD

View File

@ -0,0 +1,44 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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 "cef_process_sub_thread.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include <Objbase.h>
#endif
CefProcessSubThread::CefProcessSubThread(CefThread::ID identifier)
: CefThread(identifier) {}
CefProcessSubThread::CefProcessSubThread(CefThread::ID identifier,
MessageLoop* message_loop)
: CefThread(identifier, message_loop) {}
CefProcessSubThread::~CefProcessSubThread() {
// We cannot rely on our base class to stop the thread since we want our
// CleanUp function to run.
Stop();
}
void CefProcessSubThread::Init() {
#if defined(OS_WIN)
// Initializes the COM library on the current thread.
CoInitialize(NULL);
#endif
}
void CefProcessSubThread::CleanUp() {
// Flush any remaining messages. This ensures that any accumulated
// Task objects get destroyed before we exit, which avoids noise in
// purify leak-test results.
MessageLoop::current()->RunAllPending();
#if defined(OS_WIN)
// Closes the COM library on the current thread. CoInitialize must
// be balanced by a corresponding call to CoUninitialize.
CoUninitialize();
#endif
}

View File

@ -0,0 +1,35 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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_PROCESS_SUB_THREAD
#define _CEF_PROCESS_SUB_THREAD
#include "base/basictypes.h"
#include "cef_thread.h"
// ----------------------------------------------------------------------------
// CefProcessSubThread
//
// This simple thread object is used for the specialized threads that the
// CefProcess spins up.
//
// Applications must initialize the COM library before they can call
// COM library functions other than CoGetMalloc and memory allocation
// functions, so this class initializes COM for those users.
class CefProcessSubThread : public CefThread {
public:
explicit CefProcessSubThread(CefThread::ID identifier);
CefProcessSubThread(CefThread::ID identifier, MessageLoop* message_loop);
virtual ~CefProcessSubThread();
protected:
virtual void Init();
virtual void CleanUp();
private:
DISALLOW_COPY_AND_ASSIGN(CefProcessSubThread);
};
#endif // _CEF_PROCESS_SUB_THREAD

View File

@ -0,0 +1,153 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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 "cef_process_ui_thread.h"
#include "browser_impl.h"
#include "browser_resource_loader_bridge.h"
#include "browser_request_context.h"
#include "browser_webkit_glue.h"
#include "browser_webkit_init.h"
#include "cef_context.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/rand_util.h"
#include "base/stats_table.h"
#include "build/build_config.h"
#include "net/base/net_module.h"
#if defined(OS_WIN)
#include "net/socket/ssl_client_socket_nss_factory.h"
#endif
#include "webkit/extensions/v8/gc_extension.h"
#if defined(OS_WIN)
#include <commctrl.h>
#include <Objbase.h>
#endif
static const char* kStatsFilePrefix = "libcef_";
static int kStatsFileThreads = 20;
static int kStatsFileCounters = 200;
CefProcessUIThread::CefProcessUIThread()
: CefThread(CefThread::UI), statstable_(NULL), webkit_init_(NULL) {}
CefProcessUIThread::CefProcessUIThread(MessageLoop* message_loop)
: CefThread(CefThread::UI, message_loop), statstable_(NULL),
webkit_init_(NULL) {}
CefProcessUIThread::~CefProcessUIThread() {
// We cannot rely on our base class to stop the thread since we want our
// CleanUp function to run.
Stop();
}
void CefProcessUIThread::Init() {
#if defined(OS_WIN)
HRESULT res;
// Initialize common controls
res = CoInitialize(NULL);
DCHECK(SUCCEEDED(res));
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&InitCtrlEx);
// Start COM stuff
res = OleInitialize(NULL);
DCHECK(SUCCEEDED(res));
// Register the window class
WNDCLASSEX wcex = {
/* cbSize = */ sizeof(WNDCLASSEX),
/* style = */ CS_HREDRAW | CS_VREDRAW,
/* lpfnWndProc = */ CefBrowserImpl::WndProc,
/* cbClsExtra = */ 0,
/* cbWndExtra = */ 0,
/* hInstance = */ ::GetModuleHandle(NULL),
/* hIcon = */ NULL,
/* hCursor = */ LoadCursor(NULL, IDC_ARROW),
/* hbrBackground = */ 0,
/* lpszMenuName = */ NULL,
/* lpszClassName = */ CefBrowserImpl::GetWndClass(),
/* hIconSm = */ NULL,
};
RegisterClassEx(&wcex);
#endif
#ifndef _DEBUG
// Only log error messages and above in release build.
logging::SetMinLogLevel(logging::LOG_ERROR);
#endif
// Initialize the global CommandLine object.
CommandLine::Init(0, NULL);
// Initialize WebKit.
webkit_init_ = new BrowserWebKitInit();
// Initialize WebKit encodings
webkit_glue::InitializeTextEncoding();
// Load ICU data tables.
bool ret = icu_util::Initialize();
if(!ret) {
#if defined(OS_WIN)
MessageBox(NULL, L"Failed to load the required icudt38 library",
L"CEF Initialization Error", MB_ICONERROR | MB_OK);
#endif
return;
}
// Config the network module so it has access to a limited set of resources.
net::NetModule::SetResourceProvider(webkit_glue::NetResourceProvider);
// Load and initialize the stats table. Attempt to construct a somewhat
// unique name to isolate separate instances from each other.
statstable_ = new StatsTable(
kStatsFilePrefix + Uint64ToString(base::RandUint64()),
kStatsFileThreads,
kStatsFileCounters);
StatsTable::set_current(statstable_);
// CEF always exposes the GC.
webkit_glue::SetJavaScriptFlags(L"--expose-gc");
// Expose GCController to JavaScript.
WebKit::WebScriptController::registerExtension(
extensions_v8::GCExtension::Get());
#if defined(OS_WIN)
// Use NSS for SSL on Windows. TODO(wtc): this should eventually be hidden
// inside DefaultClientSocketFactory::CreateSSLClientSocket.
net::ClientSocketFactory::SetSSLClientSocketFactory(
net::SSLClientSocketNSSFactory);
#endif
}
void CefProcessUIThread::CleanUp() {
// Flush any remaining messages. This ensures that any accumulated
// Task objects get destroyed before we exit, which avoids noise in
// purify leak-test results.
MessageLoop::current()->RunAllPending();
// Tear down the shared StatsTable.
StatsTable::set_current(NULL);
delete statstable_;
statstable_ = NULL;
// Shut down WebKit.
delete webkit_init_;
webkit_init_ = NULL;
#if defined(OS_WIN)
// Uninitialize COM stuff
OleUninitialize();
// Closes the COM library on the current thread. CoInitialize must
// be balanced by a corresponding call to CoUninitialize.
CoUninitialize();
#endif
}

View File

@ -0,0 +1,42 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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_PROCESS_UI_THREAD
#define _CEF_PROCESS_UI_THREAD
#include "base/basictypes.h"
#include "cef_thread.h"
class BrowserWebKitInit;
class StatsTable;
// ----------------------------------------------------------------------------
// CefProcessUIThread
//
// This simple thread object is used for the specialized threads that the
// CefProcess spins up.
//
// Applications must initialize the COM library before they can call
// COM library functions other than CoGetMalloc and memory allocation
// functions, so this class initializes COM for those users.
class CefProcessUIThread : public CefThread {
public:
explicit CefProcessUIThread();
CefProcessUIThread(MessageLoop* message_loop);
virtual ~CefProcessUIThread();
virtual void Init();
virtual void CleanUp();
private:
StatsTable* statstable_;
// WebKit implementation class.
BrowserWebKitInit* webkit_init_;
DISALLOW_COPY_AND_ASSIGN(CefProcessUIThread);
};
#endif // _CEF_PROCESS_UI_THREAD

210
libcef/cef_thread.cc Normal file
View File

@ -0,0 +1,210 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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 "cef_thread.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
using base::MessageLoopProxy;
// Friendly names for the well-known threads.
static const char* cef_thread_names[CefThread::ID_COUNT] = {
"Cef_UIThread", // UI
"Cef_FileThread", // FILE
"Cef_IOThread", // IO
};
// An implementation of MessageLoopProxy to be used in conjunction
// with CefThread.
class CefThreadMessageLoopProxy : public MessageLoopProxy {
public:
explicit CefThreadMessageLoopProxy(CefThread::ID identifier)
: id_(identifier) {
}
// MessageLoopProxy implementation.
virtual bool PostTask(const tracked_objects::Location& from_here,
Task* task) {
return CefThread::PostTask(id_, from_here, task);
}
virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
Task* task, int64 delay_ms) {
return CefThread::PostDelayedTask(id_, from_here, task, delay_ms);
}
virtual bool PostNonNestableTask(const tracked_objects::Location& from_here,
Task* task) {
return CefThread::PostNonNestableTask(id_, from_here, task);
}
virtual bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms) {
return CefThread::PostNonNestableDelayedTask(id_, from_here, task,
delay_ms);
}
virtual bool BelongsToCurrentThread() {
return CefThread::CurrentlyOn(id_);
}
private:
CefThread::ID id_;
DISALLOW_COPY_AND_ASSIGN(CefThreadMessageLoopProxy);
};
Lock CefThread::lock_;
CefThread* CefThread::cef_threads_[ID_COUNT];
CefThread::CefThread(CefThread::ID identifier)
: Thread(cef_thread_names[identifier]),
identifier_(identifier) {
Initialize();
}
CefThread::CefThread(ID identifier, MessageLoop* message_loop)
: Thread(cef_thread_names[identifier]),
identifier_(identifier) {
message_loop->set_thread_name(cef_thread_names[identifier]);
set_message_loop(message_loop);
Initialize();
}
void CefThread::Initialize() {
AutoLock lock(lock_);
DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
DCHECK(cef_threads_[identifier_] == NULL);
cef_threads_[identifier_] = this;
}
CefThread::~CefThread() {
// Stop the thread here, instead of the parent's class destructor. This is so
// that if there are pending tasks that run, code that checks that it's on the
// correct CefThread succeeds.
Stop();
AutoLock lock(lock_);
cef_threads_[identifier_] = NULL;
#ifndef NDEBUG
// Double check that the threads are ordererd correctly in the enumeration.
for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
DCHECK(!cef_threads_[i]) <<
"Threads must be listed in the reverse order that they die";
}
#endif
}
// static
bool CefThread::IsWellKnownThread(ID identifier) {
AutoLock lock(lock_);
return (identifier >= 0 && identifier < ID_COUNT &&
cef_threads_[identifier]);
}
// static
bool CefThread::CurrentlyOn(ID identifier) {
AutoLock lock(lock_);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
return cef_threads_[identifier] &&
cef_threads_[identifier]->message_loop() == MessageLoop::current();
}
// static
bool CefThread::PostTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task) {
return PostTaskHelper(identifier, from_here, task, 0, true);
}
// static
bool CefThread::PostDelayedTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms) {
return PostTaskHelper(identifier, from_here, task, delay_ms, true);
}
// static
bool CefThread::PostNonNestableTask(
ID identifier,
const tracked_objects::Location& from_here,
Task* task) {
return PostTaskHelper(identifier, from_here, task, 0, false);
}
// static
bool CefThread::PostNonNestableDelayedTask(
ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms) {
return PostTaskHelper(identifier, from_here, task, delay_ms, false);
}
// static
bool CefThread::GetCurrentThreadIdentifier(ID* identifier) {
MessageLoop* cur_message_loop = MessageLoop::current();
for (int i = 0; i < ID_COUNT; ++i) {
if (cef_threads_[i] &&
cef_threads_[i]->message_loop() == cur_message_loop) {
*identifier = cef_threads_[i]->identifier_;
return true;
}
}
return false;
}
// static
scoped_refptr<MessageLoopProxy> CefThread::GetMessageLoopProxyForThread(
ID identifier) {
scoped_refptr<MessageLoopProxy> proxy =
new CefThreadMessageLoopProxy(identifier);
return proxy;
}
// static
bool CefThread::PostTaskHelper(
ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms,
bool nestable) {
DCHECK(identifier >= 0 && identifier < ID_COUNT);
// Optimization: to avoid unnecessary locks, we listed the ID enumeration in
// order of lifetime. So no need to lock if we know that the other thread
// outlives this one.
// Note: since the array is so small, ok to loop instead of creating a map,
// which would require a lock because std::map isn't thread safe, defeating
// the whole purpose of this optimization.
ID current_thread;
bool guaranteed_to_outlive_target_thread =
GetCurrentThreadIdentifier(&current_thread) &&
current_thread >= identifier;
if (!guaranteed_to_outlive_target_thread)
lock_.Acquire();
MessageLoop* message_loop = cef_threads_[identifier] ?
cef_threads_[identifier]->message_loop() : NULL;
if (message_loop) {
if (nestable) {
message_loop->PostDelayedTask(from_here, task, delay_ms);
} else {
message_loop->PostNonNestableDelayedTask(from_here, task, delay_ms);
}
} else {
delete task;
}
if (!guaranteed_to_outlive_target_thread)
lock_.Release();
return !!message_loop;
}

185
libcef/cef_thread.h Normal file
View File

@ -0,0 +1,185 @@
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2010 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_THREAD_H
#define _CEF_THREAD_H
#include "base/lock.h"
#include "base/task.h"
#include "base/thread.h"
namespace base {
class MessageLoopProxy;
}
///////////////////////////////////////////////////////////////////////////////
// CefThread
//
// This class represents a thread that is known by a browser-wide name. For
// example, there is one IO thread for the entire browser process, and various
// pieces of code find it useful to retrieve a pointer to the IO thread's
// Invoke a task by thread ID:
//
// CefThread::PostTask(CefThread::IO, FROM_HERE, task);
//
// The return value is false if the task couldn't be posted because the target
// thread doesn't exist. If this could lead to data loss, you need to check the
// result and restructure the code to ensure it doesn't occur.
//
// This class automatically handles the lifetime of different threads.
// It's always safe to call PostTask on any thread. If it's not yet created,
// the task is deleted. There are no race conditions. If the thread that the
// task is posted to is guaranteed to outlive the current thread, then no locks
// are used. You should never need to cache pointers to MessageLoops, since
// they're not thread safe.
class CefThread : public base::Thread {
public:
// An enumeration of the well-known threads.
// NOTE: threads must be listed in the order of their life-time, with each
// thread outliving every other thread below it.
enum ID {
// The main thread in the browser.
UI,
// This is the thread that interacts with the file system.
FILE,
// This is the thread that processes IPC and network messages.
IO,
// This identifier does not represent a thread. Instead it counts the
// number of well-known threads. Insert new well-known threads before this
// identifier.
ID_COUNT
};
// Construct a CefThread with the supplied identifier. It is an error
// to construct a CefThread that already exists.
explicit CefThread(ID identifier);
// Special constructor for the main (UI) thread and unittests. We use a dummy
// thread here since the main thread already exists.
CefThread(ID identifier, MessageLoop* message_loop);
virtual ~CefThread();
// These are the same methods in message_loop.h, but are guaranteed to either
// get posted to the MessageLoop if it's still alive, or be deleted otherwise.
// They return true if the thread existed and the task was posted. Note that
// even if the task is posted, there's no guarantee that it will run, since
// the target thread may already have a Quit message in its queue.
static bool PostTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task);
static bool PostDelayedTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms);
static bool PostNonNestableTask(ID identifier,
const tracked_objects::Location& from_here,
Task* task);
static bool PostNonNestableDelayedTask(
ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms);
template <class T>
static bool DeleteSoon(ID identifier,
const tracked_objects::Location& from_here,
T* object) {
return PostNonNestableTask(
identifier, from_here, new DeleteTask<T>(object));
}
template <class T>
static bool ReleaseSoon(ID identifier,
const tracked_objects::Location& from_here,
T* object) {
return PostNonNestableTask(
identifier, from_here, new ReleaseTask<T>(object));
}
// Callable on any thread. Returns whether the given ID corresponds to a well
// known thread.
static bool IsWellKnownThread(ID identifier);
// Callable on any thread. Returns whether you're currently on a particular
// thread.
static bool CurrentlyOn(ID identifier);
// If the current message loop is one of the known threads, returns true and
// sets identifier to its ID. Otherwise returns false.
static bool GetCurrentThreadIdentifier(ID* identifier);
// Callers can hold on to a refcounted MessageLoopProxy beyond the lifetime
// of the thread.
static scoped_refptr<base::MessageLoopProxy> GetMessageLoopProxyForThread(
ID identifier);
// Use these templates in conjuction with RefCountedThreadSafe when you want
// to ensure that an object is deleted on a specific thread. This is needed
// when an object can hop between threads (i.e. IO -> FILE -> IO), and thread
// switching delays can mean that the final IO tasks executes before the FILE
// task's stack unwinds. This would lead to the object destructing on the
// FILE thread, which often is not what you want (i.e. to unregister from
// NotificationService, to notify other objects on the creating thread etc).
template<ID thread>
struct DeleteOnThread {
template<typename T>
static void Destruct(T* x) {
if (CurrentlyOn(thread)) {
delete x;
} else {
DeleteSoon(thread, FROM_HERE, x);
}
}
};
// Sample usage:
// class Foo
// : public base::RefCountedThreadSafe<
// Foo, CefThread::DeleteOnIOThread> {
//
// ...
// private:
// friend class CefThread;
// friend class DeleteTask<Foo>;
//
// ~Foo();
struct DeleteOnUIThread : public DeleteOnThread<UI> { };
struct DeleteOnIOThread : public DeleteOnThread<IO> { };
struct DeleteOnFileThread : public DeleteOnThread<FILE> { };
private:
// Common initialization code for the constructors.
void Initialize();
static bool PostTaskHelper(
ID identifier,
const tracked_objects::Location& from_here,
Task* task,
int64 delay_ms,
bool nestable);
// The identifier of this thread. Only one thread can exist with a given
// identifier at a given time.
ID identifier_;
// This lock protects |cef_threads_|. Do not read or modify that array
// without holding this lock. Do not block while holding this lock.
static Lock lock_;
// An array of the CefThread objects. This array is protected by |lock_|.
// The threads are not owned by this array. Typically, the threads are owned
// on the UI thread by the g_browser_process object. CefThreads remove
// themselves from this array upon destruction.
static CefThread* cef_threads_[ID_COUNT];
};
#define REQUIRE_UIT() DCHECK(CefThread::CurrentlyOn(CefThread::UI))
#define REQUIRE_IOT() DCHECK(CefThread::CurrentlyOn(CefThread::IO))
#endif // _CEF_THREAD_H

View File

@ -1,593 +0,0 @@
// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 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 "context.h"
#include "browser_impl.h"
#include "browser_resource_loader_bridge.h"
#include "browser_request_context.h"
#include "browser_webkit_glue.h"
#include "browser_webkit_init.h"
#include "../include/cef_nplugin.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/resource_util.h"
#include "base/stats_table.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_module.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScriptController.h"
#include "webkit/extensions/v8/gc_extension.h"
#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_list.h"
#include <commctrl.h>
// Global CefContext pointer
CefRefPtr<CefContext> _Context;
static const char* kStatsFilePrefix = "libcef_";
static int kStatsFileThreads = 20;
static int kStatsFileCounters = 200;
// Class used to process events on the current message loop.
class CefMessageLoopForUI : public MessageLoopForUI
{
typedef MessageLoopForUI inherited;
public:
CefMessageLoopForUI()
{
}
virtual bool DoIdleWork() {
bool valueToRet = inherited::DoIdleWork();
pump_->Quit();
return valueToRet;
}
void DoMessageLoopIteration() {
Run(NULL);
}
};
bool CefInitialize(bool multi_threaded_message_loop,
const std::wstring& cache_path)
{
// Return true if the context is already initialized
if(_Context.get())
return true;
// Create the new global context object
_Context = new CefContext();
// Initialize the glboal context
return _Context->Initialize(multi_threaded_message_loop, cache_path);
}
void CefShutdown()
{
// Verify that the context is already initialized
if(!_Context.get())
return;
// Shut down the global context
_Context->Shutdown();
// Delete the global context object
_Context = NULL;
}
void CefDoMessageLoopWork()
{
if(!_Context->RunningOnUIThread())
return;
((CefMessageLoopForUI*)CefMessageLoopForUI::current())->DoMessageLoopIteration();
}
bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info)
{
if(!_Context.get())
return false;
CefPluginInfo* pPluginInfo = new CefPluginInfo;
*pPluginInfo = plugin_info;
PostTask(FROM_HERE, NewRunnableMethod(_Context.get(),
&CefContext::UIT_RegisterPlugin, pPluginInfo));
return true;
}
void CefContext::UIT_RegisterPlugin(struct CefPluginInfo* plugin_info)
{
REQUIRE_UIT();
NPAPI::PluginVersionInfo info;
info.path = FilePath(plugin_info->unique_name);
info.product_name = plugin_info->display_name;
info.file_description = plugin_info->description;
info.file_version =plugin_info->version;
for(size_t i = 0; i < plugin_info->mime_types.size(); ++i) {
if(i > 0) {
info.mime_types += L"|";
info.file_extensions += L"|";
info.type_descriptions += L"|";
}
info.mime_types += plugin_info->mime_types[i].mime_type;
info.type_descriptions += plugin_info->mime_types[i].description;
for(size_t j = 0;
j < plugin_info->mime_types[i].file_extensions.size(); ++j) {
if(j > 0) {
info.file_extensions += L",";
}
info.file_extensions += plugin_info->mime_types[i].file_extensions[j];
}
}
info.entry_points.np_getentrypoints = plugin_info->np_getentrypoints;
info.entry_points.np_initialize = plugin_info->np_initialize;
info.entry_points.np_shutdown = plugin_info->np_shutdown;
NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
delete plugin_info;
}
bool CefContext::DoInitialize()
{
HRESULT res;
// Initialize common controls
res = CoInitialize(NULL);
DCHECK(SUCCEEDED(res));
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&InitCtrlEx);
// Start COM stuff
res = OleInitialize(NULL);
DCHECK(SUCCEEDED(res));
// Initialize the global CommandLine object.
CommandLine::Init(0, NULL);
// Initialize WebKit.
webkit_init_ = new BrowserWebKitInit();
// Initialize WebKit encodings
webkit_glue::InitializeTextEncoding();
// Initializing with a default context, which means no on-disk cookie DB,
// and no support for directory listings.
//PathService::Get(base::DIR_EXE, &cache_path);
BrowserResourceLoaderBridge::Init(FilePath(cache_path_), net::HttpCache::NORMAL,
false);
// Load ICU data tables.
bool ret = icu_util::Initialize();
if(!ret) {
MessageBox(NULL, L"Failed to load the required icudt38 library",
L"CEF Initialization Error", MB_ICONERROR | MB_OK);
return false;
}
// Config the network module so it has access to a limited set of resources.
net::NetModule::SetResourceProvider(webkit_glue::NetResourceProvider);
// Load and initialize the stats table. Attempt to construct a somewhat
// unique name to isolate separate instances from each other.
statstable_ = new StatsTable(
kStatsFilePrefix + Uint64ToString(base::RandUint64()),
kStatsFileThreads,
kStatsFileCounters);
StatsTable::set_current(statstable_);
// CEF always exposes the GC.
webkit_glue::SetJavaScriptFlags(L"--expose-gc");
// Expose GCController to JavaScript.
WebKit::WebScriptController::registerExtension(
extensions_v8::GCExtension::Get());
return true;
}
void CefContext::DoUninitialize()
{
// Flush any remaining messages. This ensures that any accumulated
// Task objects get destroyed before we exit, which avoids noise in
// purify leak-test results.
MessageLoop::current()->RunAllPending();
BrowserResourceLoaderBridge::Shutdown();
// Tear down the shared StatsTable.
StatsTable::set_current(NULL);
delete statstable_;
statstable_ = NULL;
// Shut down WebKit.
delete webkit_init_;
webkit_init_ = NULL;
// Uninitialize COM stuff
OleUninitialize();
// Uninitialize common controls
CoUninitialize();
}
DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
{
CefContext *pContext = static_cast<CefContext*>(lpParam);
// AtExitManager is scoped to the UI thread.
base::AtExitManager at_exit_manager;
if (!pContext->DoInitialize())
return 1;
// Instantiate the message loop for this thread.
MessageLoopForUI main_message_loop;
pContext->SetMessageLoopForUI(&main_message_loop);
// Notify the context that initialization is complete so that the
// Initialize() function can return.
pContext->NotifyEvent();
// Execute the message loop that will run until a quit task is received.
MessageLoop::current()->Run();
pContext->DoUninitialize();
return 0;
}
CefContext::CefContext()
{
multi_threaded_message_loop_ = false;
hthreadui_ = NULL;
idthreadui_ = 0;
heventui_ = NULL;
messageloopui_ = NULL;
in_transition_ = false;
webprefs_ = NULL;
statstable_ = NULL;
at_exit_manager_ = NULL;
hinstance_ = ::GetModuleHandle(NULL);
next_browser_id_ = 1;
webkit_init_ = NULL;
}
CefContext::~CefContext()
{
// Just in case CefShutdown() isn't called
Shutdown();
if(!multi_threaded_message_loop_) {
if(messageloopui_)
delete messageloopui_;
if(at_exit_manager_)
delete at_exit_manager_;
}
}
bool CefContext::Initialize(bool multi_threaded_message_loop,
const std::wstring& cache_path)
{
bool initialized = false, intransition = false;
Lock();
// We only need to initialize if the UI thread is not currently running
if(!idthreadui_) {
// Only start the initialization if we're not currently in a transitional
// state
intransition = in_transition_;
if(!intransition) {
// We are now in a transitional state
in_transition_ = true;
cache_path_ = cache_path;
// Register the window class
WNDCLASSEX wcex = {
/* cbSize = */ sizeof(WNDCLASSEX),
/* style = */ CS_HREDRAW | CS_VREDRAW,
/* lpfnWndProc = */ CefBrowserImpl::WndProc,
/* cbClsExtra = */ 0,
/* cbWndExtra = */ 0,
/* hInstance = */ hinstance_,
/* hIcon = */ NULL,
/* hCursor = */ LoadCursor(NULL, IDC_ARROW),
/* hbrBackground = */ 0,
/* lpszMenuName = */ NULL,
/* lpszClassName = */ CefBrowserImpl::GetWndClass(),
/* hIconSm = */ NULL,
};
RegisterClassEx(&wcex);
#ifndef _DEBUG
// Only log error messages and above in release build.
logging::SetMinLogLevel(logging::LOG_ERROR);
#endif
// Initialize web preferences
webprefs_ = new WebPreferences;
*webprefs_ = WebPreferences();
webprefs_->standard_font_family = L"Times";
webprefs_->fixed_font_family = L"Courier";
webprefs_->serif_font_family = L"Times";
webprefs_->sans_serif_font_family = L"Helvetica";
// These two fonts are picked from the intersection of
// Win XP font list and Vista font list :
// http://www.microsoft.com/typography/fonts/winxp.htm
// http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
// Some of them are installed only with CJK and complex script
// support enabled on Windows XP and are out of consideration here.
// (although we enabled both on our buildbots.)
// They (especially Impact for fantasy) are not typical cursive
// and fantasy fonts, but it should not matter for layout tests
// as long as they're available.
#if defined(OS_MACOSX)
webprefs_->cursive_font_family = L"Apple Chancery";
webprefs_->fantasy_font_family = L"Papyrus";
#else
webprefs_->cursive_font_family = L"Comic Sans MS";
webprefs_->fantasy_font_family = L"Impact";
#endif
webprefs_->default_encoding = "ISO-8859-1";
webprefs_->default_font_size = 16;
webprefs_->default_fixed_font_size = 13;
webprefs_->minimum_font_size = 1;
webprefs_->minimum_logical_font_size = 9;
webprefs_->javascript_can_open_windows_automatically = true;
webprefs_->dom_paste_enabled = true;
webprefs_->developer_extras_enabled = true;
webprefs_->site_specific_quirks_enabled = true;
webprefs_->shrinks_standalone_images_to_fit = false;
webprefs_->uses_universal_detector = false;
webprefs_->text_areas_are_resizable = true;
webprefs_->java_enabled = true;
webprefs_->allow_scripts_to_close_windows = false;
webprefs_->xss_auditor_enabled = false;
webprefs_->remote_fonts_enabled = true;
webprefs_->local_storage_enabled = true;
webprefs_->application_cache_enabled = true;
webprefs_->databases_enabled = true;
webprefs_->allow_file_access_from_file_urls = true;
if (multi_threaded_message_loop) {
// Event that will be used to signal thread setup completion. Start
// in non-signaled mode so that the event will block.
heventui_ = CreateEvent(NULL, TRUE, FALSE, NULL);
DCHECK(heventui_ != NULL);
// Thread that hosts the UI loop
hthreadui_ = CreateThread(
NULL, 0, ThreadHandlerUI, this, 0, &idthreadui_);
DCHECK(hthreadui_ != NULL);
DCHECK(idthreadui_ != 0);
} else {
// AtExitManager is scoped to the context.
at_exit_manager_ = new base::AtExitManager;
if (!DoInitialize()) {
// TODO: Process initialization errors
}
// Message loop is scoped to the context.
SetMessageLoopForUI(new CefMessageLoopForUI());
idthreadui_ = GetCurrentThreadId();
DCHECK(idthreadui_ != 0);
}
initialized = true;
}
}
Unlock();
if(initialized) {
multi_threaded_message_loop_ = multi_threaded_message_loop;
if (multi_threaded_message_loop) {
// Wait for initial UI thread setup to complete
WaitForSingleObject(heventui_, INFINITE);
}
Lock();
// We have exited the transitional state
in_transition_ = false;
Unlock();
}
return intransition ? false : true;
}
void CefContext::Shutdown()
{
bool shutdown = false, intransition = false;
BrowserList browserlist;
Lock();
// We only need to shut down if the UI thread is currently running
if(idthreadui_) {
// Only start the shutdown if we're not currently in a transitional state
intransition = in_transition_;
if(!intransition) {
DCHECK(messageloopui_ != NULL);
// We are now in a transitional state
in_transition_ = true;
browserlist = browserlist_;
browserlist_.empty();
if(webprefs_) {
delete webprefs_;
webprefs_ = NULL;
}
// Post the quit message to the UI message loop
messageloopui_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
shutdown = true;
}
}
Unlock();
if(shutdown) {
if (browserlist.size() > 0) {
// Close any remaining browser windows
BrowserList::const_iterator it = browserlist.begin();
for (; it != browserlist.end(); ++it)
PostMessage((*it)->GetWindowHandle(), WM_CLOSE, 0, 0);
browserlist.empty();
}
if (hthreadui_) {
// Wait for the UI thread to exit
WaitForSingleObject(hthreadui_, INFINITE);
// Clean up thread and event handles
CloseHandle(hthreadui_);
CloseHandle(heventui_);
hthreadui_ = NULL;
heventui_ = NULL;
} else {
DoUninitialize();
}
Lock();
// Unregister the window class
UnregisterClass(CefBrowserImpl::GetWndClass(), hinstance_);
idthreadui_ = 0;
// We have exited the transitional state
in_transition_ = false;
Unlock();
}
}
bool CefContext::AddBrowser(CefRefPtr<CefBrowserImpl> browser)
{
bool found = false;
Lock();
// check that the browser isn't already in the list before adding
BrowserList::const_iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get() == browser.get()) {
found = true;
break;
}
}
if(!found)
{
browser->UIT_SetUniqueID(next_browser_id_++);
browserlist_.push_back(browser);
}
Unlock();
return !found;
}
void CefContext::UIT_ClearCache()
{
webkit_glue::ClearCache();
}
bool CefContext::RemoveBrowser(CefRefPtr<CefBrowserImpl> browser)
{
bool deleted = false;
bool empty = false;
Lock();
BrowserList::iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get() == browser.get()) {
browserlist_.erase(it);
deleted = true;
break;
}
}
if (browserlist_.empty()) {
next_browser_id_ = 1;
empty = true;
}
Unlock();
if (empty) {
PostTask(FROM_HERE, NewRunnableMethod(_Context.get(),
&CefContext::UIT_ClearCache));
}
return deleted;
}
CefRefPtr<CefBrowserImpl> CefContext::GetBrowserByID(int id)
{
CefRefPtr<CefBrowserImpl> browser;
Lock();
BrowserList::const_iterator it = browserlist_.begin();
for(; it != browserlist_.end(); ++it) {
if(it->get()->UIT_GetUniqueID() == id) {
browser = it->get();
break;
}
}
Unlock();
return browser;
}
void CefContext::SetMessageLoopForUI(MessageLoopForUI* loop)
{
Lock();
messageloopui_ = loop;
Unlock();
}
void CefContext::NotifyEvent()
{
Lock();
// Set the event state to signaled so that the waiting thread will be
// released.
if(heventui_)
SetEvent(heventui_);
Unlock();
}
void PostTask(const tracked_objects::Location& from_here, Task* task)
{
if(_Context.get()) {
_Context->Lock();
MessageLoopForUI *pMsgLoop = _Context->GetMessageLoopForUI();
if(pMsgLoop)
pMsgLoop->PostTask(from_here, task);
_Context->Unlock();
}
}

View File

@ -1,110 +0,0 @@
// Copyright (c) 2008 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 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 _CONTEXT_H
#define _CONTEXT_H
#include "../include/cef.h"
#include "base/at_exit.h"
#include "base/message_loop.h"
#include "base/stats_table.h"
#include "gfx/native_widget_types.h"
#include "webkit/glue/webpreferences.h"
class BrowserWebKitInit;
class CefBrowserImpl;
class CefContext : public CefThreadSafeBase<CefBase>
{
public:
typedef std::list<CefRefPtr<CefBrowserImpl> > BrowserList;
CefContext();
~CefContext();
bool Initialize(bool multi_threaded_message_loop,
const std::wstring& cache_path);
void Shutdown();
MessageLoopForUI* GetMessageLoopForUI() { return messageloopui_; }
HMODULE GetInstanceHandle() { return hinstance_; }
HANDLE GetUIThreadHandle() { return hthreadui_; }
DWORD GetUIThreadId() { return idthreadui_; }
WebPreferences* GetWebPreferences() { return webprefs_; }
// Retrieve the path at which cache data will be stored on disk. If empty,
// cache data will be stored in-memory.
std::wstring GetCachePath() { return cache_path_; }
bool AddBrowser(CefRefPtr<CefBrowserImpl> browser);
bool RemoveBrowser(CefRefPtr<CefBrowserImpl> browser);
CefRefPtr<CefBrowserImpl> GetBrowserByID(int id);
BrowserList* GetBrowserList() { return &browserlist_; }
// Returns true if the calling thread is the same as the UI thread
bool RunningOnUIThread() { return (GetCurrentThreadId() == idthreadui_); }
////////////////////////////////////////////////////////////
// ALL UIT_* METHODS MUST ONLY BE CALLED ON THE UI THREAD //
////////////////////////////////////////////////////////////
void UIT_RegisterPlugin(struct CefPluginInfo* plugin_info);
void UIT_UnregisterPlugin(struct CefPluginInfo* plugin_info);
void UIT_ClearCache();
bool DoWork();
bool DoDelayedWork();
bool DoIdleWork();
static bool ImplementsThreadSafeReferenceCounting() { return true; }
private:
void SetMessageLoopForUI(MessageLoopForUI* loop);
void NotifyEvent();
bool DoInitialize();
void DoUninitialize();
protected:
bool multi_threaded_message_loop_;
HMODULE hinstance_;
DWORD idthreadui_;
HANDLE hthreadui_;
HANDLE heventui_;
bool in_transition_;
BrowserList browserlist_;
WebPreferences* webprefs_;
StatsTable* statstable_;
std::wstring cache_path_;
// MessageLoopForUI will be scoped to the context when running in single
// threaded message loop mode.
MessageLoopForUI* messageloopui_;
// AtExitManager will be scoped to the context when running in single threaded
// message loop mode.
base::AtExitManager* at_exit_manager_;
// WebKit implementation class.
BrowserWebKitInit* webkit_init_;
// Used for assigning unique IDs to browser instances.
int next_browser_id_;
friend DWORD WINAPI ThreadHandlerUI(LPVOID lpParam);
};
// Post a task to the UI message loop
void PostTask(const tracked_objects::Location& from_here, Task* task);
// Global context object pointer
extern CefRefPtr<CefContext> _Context;
// Macro for requiring that a function be called on the UI thread
#define REQUIRE_UIT() DCHECK(_Context->RunningOnUIThread())
#endif // _CONTEXT_H

View File

@ -7,7 +7,6 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/worker_pool.h"
#include "googleurl/src/url_util.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
@ -19,7 +18,7 @@
#include "include/cef.h"
#include "tracker.h"
#include "context.h"
#include "cef_context.h"
#include "request_impl.h"
#include <map>
@ -68,8 +67,8 @@ public:
// Continue asynchronously.
DCHECK(!async_resolver_);
async_resolver_ = new AsyncResolver(this);
WorkerPool::PostTask(FROM_HERE, NewRunnableMethod(
async_resolver_.get(), &AsyncResolver::Resolve, url_), true);
CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod(
async_resolver_.get(), &AsyncResolver::Resolve, url_));
return;
}
@ -411,7 +410,7 @@ bool CefRegisterScheme(const std::wstring& scheme_name,
new SchemeRequestJobWrapper(WideToUTF8(scheme_name),
WideToUTF8(host_name), factory));
PostTask(FROM_HERE, NewRunnableMethod(wrapper.get(),
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(wrapper.get(),
&SchemeRequestJobWrapper::RegisterScheme));
return true;

View File

@ -3,7 +3,7 @@
// can be found in the LICENSE file.
#include "v8_impl.h"
#include "context.h"
#include "cef_context.h"
#include "tracker.h"
#include "base/lazy_instance.h"
#include "base/utf_string_conversions.h"
@ -156,7 +156,7 @@ bool CefRegisterExtension(const std::wstring& extension_name,
ExtensionWrapper* wrapper = new ExtensionWrapper(name->GetString(),
code->GetString(), handler.get());
PostTask(FROM_HERE, NewRunnableMethod(wrapper,
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(wrapper,
&ExtensionWrapper::UIT_RegisterExtension));
return true;
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
#include "libcef_dll/cpptoc/task_cpptoc.h"
// MEMBER FUNCTIONS - Body may be edited by hand.
void CEF_CALLBACK task_execute(struct _cef_task_t* self,
cef_thread_id_t threadId)
{
DCHECK(self);
if(!self)
return;
CefTaskCppToC::Get(self)->Execute(threadId);
}
// CONSTRUCTOR - Do not edit by hand.
CefTaskCppToC::CefTaskCppToC(CefTask* cls)
: CefCppToC<CefTaskCppToC, CefTask, cef_task_t>(cls)
{
struct_.struct_.execute = task_execute;
}
#ifdef _DEBUG
long CefCppToC<CefTaskCppToC, CefTask, cef_task_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,34 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _TASK_CPPTOC_H
#define _TASK_CPPTOC_H
#ifndef USING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed wrapper-side only")
#else // USING_CEF_SHARED
#include "include/cef.h"
#include "include/cef_capi.h"
#include "libcef_dll/cpptoc/cpptoc.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed wrapper-side only.
class CefTaskCppToC
: public CefCppToC<CefTaskCppToC, CefTask, cef_task_t>
{
public:
CefTaskCppToC(CefTask* cls);
virtual ~CefTaskCppToC() {}
};
#endif // USING_CEF_SHARED
#endif // _TASK_CPPTOC_H

View File

@ -0,0 +1,30 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing static and
// virtual method implementations. See the translator.README.txt file in the
// tools directory for more information.
//
#include "libcef_dll/ctocpp/task_ctocpp.h"
// VIRTUAL METHODS - Body may be edited by hand.
void CefTaskCToCpp::Execute(CefThreadId threadId)
{
if(CEF_MEMBER_MISSING(struct_, execute))
return;
struct_->execute(struct_, threadId);
}
#ifdef _DEBUG
long CefCToCpp<CefTaskCToCpp, CefTask, cef_task_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,39 @@
// Copyright (c) 2009 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.
//
// -------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _TASK_CTOCPP_H
#define _TASK_CTOCPP_H
#ifndef BUILDING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
#else // BUILDING_CEF_SHARED
#include "include/cef.h"
#include "include/cef_capi.h"
#include "libcef_dll/ctocpp/ctocpp.h"
// Wrap a C structure with a C++ class.
// This class may be instantiated and accessed DLL-side only.
class CefTaskCToCpp
: public CefCToCpp<CefTaskCToCpp, CefTask, cef_task_t>
{
public:
CefTaskCToCpp(cef_task_t* str)
: CefCToCpp<CefTaskCToCpp, CefTask, cef_task_t>(str) {}
virtual ~CefTaskCToCpp() {}
// CefTask methods
virtual void Execute(CefThreadId threadId);
};
#endif // BUILDING_CEF_SHARED
#endif // _TASK_CTOCPP_H

View File

@ -18,6 +18,7 @@
#include "ctocpp/read_handler_ctocpp.h"
#include "ctocpp/scheme_handler_ctocpp.h"
#include "ctocpp/scheme_handler_factory_ctocpp.h"
#include "ctocpp/task_ctocpp.h"
#include "ctocpp/v8handler_ctocpp.h"
#include "ctocpp/write_handler_ctocpp.h"
#include "base/string_util.h"
@ -133,3 +134,28 @@ CEF_EXPORT int cef_register_scheme(const wchar_t* scheme_name,
return CefRegisterScheme(nameStr, codeStr,
CefSchemeHandlerFactoryCToCpp::Wrap(factory));
}
CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId)
{
return CefCurrentlyOn(threadId);
}
CEF_EXPORT int cef_post_task(cef_thread_id_t threadId,
struct _cef_task_t* task)
{
DCHECK(task);
if(!task)
return 0;
return CefPostTask(threadId, CefTaskCToCpp::Wrap(task));
}
CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
struct _cef_task_t* task, long delay_ms)
{
DCHECK(task);
if(!task)
return 0;
return CefPostDelayedTask(threadId, CefTaskCToCpp::Wrap(task), delay_ms);
}

View File

@ -10,6 +10,7 @@
#include "libcef_dll/cpptoc/read_handler_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
#include "libcef_dll/cpptoc/task_cpptoc.h"
#include "libcef_dll/cpptoc/v8handler_cpptoc.h"
#include "libcef_dll/cpptoc/write_handler_cpptoc.h"
#include "libcef_dll/ctocpp/browser_ctocpp.h"
@ -111,3 +112,20 @@ bool CefRegisterScheme(const std::wstring& scheme_name,
return cef_register_scheme(scheme_name.c_str(), host_name.c_str(),
CefSchemeHandlerFactoryCppToC::Wrap(factory))?true:false;
}
bool CefCurrentlyOn(CefThreadId threadId)
{
return cef_currently_on(threadId)?true:false;
}
bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task)
{
return cef_post_task(threadId, CefTaskCppToC::Wrap(task))?true:false;
}
bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
long delay_ms)
{
return cef_post_delayed_task(threadId, CefTaskCppToC::Wrap(task), delay_ms)?
true:false;
}

View File

@ -9,7 +9,6 @@
#include "resource_util.h"
#include "scheme_test.h"
#include "string_util.h"
#include "thread_util.h"
#include "uiplugin_test.h"
#include <sstream>
#include <commdlg.h>
@ -376,12 +375,12 @@ public:
new ClientReadHandler(pBytes, dwSize));
mimeType = L"text/html";
}
} else if(wcsstr(url.c_str(), L"/logo.gif") != NULL) {
} else if(wcsstr(url.c_str(), L"/logo1w.png") != NULL) {
// Any time we find "logo.gif" in the URL substitute in our own image
if(LoadBinaryResource(IDS_LOGO, dwSize, pBytes)) {
resourceStream = CefStreamReader::CreateForHandler(
new ClientReadHandler(pBytes, dwSize));
mimeType = L"image/jpg";
mimeType = L"image/png";
}
} else if(wcsstr(url.c_str(), L"/logoball.png") != NULL) {
// Load the "logoball.png" image resource.
@ -563,7 +562,7 @@ public:
fclose(file);
if(first_message) {
// Show the message box on the UI thread.
// Show the message box on the main application thread.
PostMessage(m_MainHwnd, WM_COMMAND, ID_WARN_CONSOLEMESSAGE, 0);
}
}
@ -945,23 +944,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP
RunGetSourceTest(browser->GetMainFrame());
#else // !TEST_SINGLE_THREADED_MESSAGE_LOOP
// Execute the GetSource() call on a new worker thread to avoid
// blocking the UI thread when using a multi-threaded message loop
// Execute the GetSource() call on the FILE thread to avoid blocking
// the UI thread when using a multi-threaded message loop
// (issue #79).
class ExecHandler : public Thread::Handler
class ExecTask : public CefThreadSafeBase<CefTask>
{
public:
ExecHandler(CefRefPtr<CefFrame> frame) : m_Frame(frame) {}
virtual DWORD Run()
ExecTask(CefRefPtr<CefFrame> frame) : m_Frame(frame) {}
virtual void Execute(CefThreadId threadId)
{
RunGetSourceTest(m_Frame);
return 0;
}
virtual void Destroy() { delete this; }
private:
CefRefPtr<CefFrame> m_Frame;
};
Thread::Execute(new ExecHandler(browser->GetMainFrame()));
CefPostTask(TID_FILE, new ExecTask(browser->GetMainFrame()));
#endif // !TEST_SINGLE_THREADED_MESSAGE_LOOP
}
return 0;
@ -970,23 +967,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP
RunGetTextTest(browser->GetMainFrame());
#else // !TEST_SINGLE_THREADED_MESSAGE_LOOP
// Execute the GetText() call on a new worker thread to avoid
// blocking the UI thread when using a multi-threaded message loop
// Execute the GetText() call on the FILE thread to avoid blocking
// the UI thread when using a multi-threaded message loop
// (issue #79).
class ExecHandler : public Thread::Handler
class ExecTask : public CefThreadSafeBase<CefTask>
{
public:
ExecHandler(CefRefPtr<CefFrame> frame) : m_Frame(frame) {}
virtual DWORD Run()
ExecTask(CefRefPtr<CefFrame> frame) : m_Frame(frame) {}
virtual void Execute(CefThreadId threadId)
{
RunGetTextTest(m_Frame);
return 0;
}
virtual void Destroy() { delete this; }
private:
CefRefPtr<CefFrame> m_Frame;
};
Thread::Execute(new ExecHandler(browser->GetMainFrame()));
CefPostTask(TID_FILE, new ExecTask(browser->GetMainFrame()));
#endif // !TEST_SINGLE_THREADED_MESSAGE_LOOP
}
return 0;

View File

@ -28,7 +28,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// Binary
//
IDS_LOGO BINARY "res\logo.jpg"
IDS_LOGO BINARY "res\logo.png"
IDS_UIPLUGIN BINARY "res\uiplugin.html"
IDS_LOGOBALL BINARY "res\logoball.png"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,58 +0,0 @@
// Copyright (c) 2010 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.
#pragma once
#include <windows.h>
class Thread
{
public:
// Interface for thread execution.
class Handler
{
public:
virtual DWORD Run() =0;
virtual void Destroy() =0;
};
// Create and execute a new thread for the specified handler.
static HANDLE Execute(Handler* pHandler)
{
if (!pHandler)
return 0;
Thread* pThread = new Thread(pHandler);
return pThread->Execute();
}
private:
Thread(Handler* pHandler) : m_hThread(NULL), m_pHandler(pHandler) {}
~Thread()
{
if (m_hThread)
CloseHandle(m_hThread);
m_pHandler->Destroy();
}
HANDLE Execute()
{
m_hThread = CreateThread(NULL, 4096, ThreadHandler,
reinterpret_cast<LPVOID>(this), 0, NULL);
if (m_hThread == NULL) {
delete this;
return NULL;
}
return m_hThread;
}
static DWORD WINAPI ThreadHandler(LPVOID lpThreadParameter)
{
Thread* pThread = reinterpret_cast<Thread*>(lpThreadParameter);
DWORD ret = pThread->m_pHandler->Run();
delete pThread;
return ret;
}
Handler* m_pHandler;
HANDLE m_hThread;
};

View File

@ -1072,6 +1072,7 @@ class obj_analysis:
'bool' : 'int',
'CefWindowHandle' : 'cef_window_handle_t',
'CefRect' : 'cef_rect_t',
'CefThreadId' : 'cef_thread_id_t',
}
if value in simpletypes.keys():
return {