mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Provide a generic JavaScript message router implementation (issue #1183).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1574 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
@@ -13,54 +13,43 @@ namespace binding_test {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kMessageName = "binding_test";
|
||||
const char kTestUrl[] = "http://tests/binding";
|
||||
const char kTestMessageName[] = "BindingTest";
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == kMessageName) {
|
||||
// Handle the message.
|
||||
std::string result;
|
||||
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
if (args->GetSize() > 0 && args->GetType(0) == VTYPE_STRING) {
|
||||
// Our result is a reverse of the original message.
|
||||
result = args->GetString(0);
|
||||
std::reverse(result.begin(), result.end());
|
||||
} else {
|
||||
result = "Invalid request";
|
||||
}
|
||||
|
||||
// Send the result back to the render process.
|
||||
CefRefPtr<CefProcessMessage> response =
|
||||
CefProcessMessage::Create(kMessageName);
|
||||
response->GetArgumentList()->SetString(0, result);
|
||||
browser->SendProcessMessage(PID_RENDERER, response);
|
||||
// Called due to cefQuery execution in binding.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name.find(kTestMessageName) == 0) {
|
||||
// Reverse the string and return.
|
||||
std::string result = message_name.substr(sizeof(kTestMessageName));
|
||||
std::reverse(result.begin(), result.end());
|
||||
callback->Success(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
} // namespace binding_test
|
||||
|
@@ -10,9 +10,8 @@
|
||||
|
||||
namespace binding_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
} // namespace binding_test
|
||||
|
||||
|
@@ -14,201 +14,21 @@
|
||||
#include "include/cef_v8.h"
|
||||
#include "util.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
// Forward declarations.
|
||||
void SetList(CefRefPtr<CefV8Value> source, CefRefPtr<CefListValue> target);
|
||||
void SetList(CefRefPtr<CefListValue> source, CefRefPtr<CefV8Value> target);
|
||||
|
||||
// Transfer a V8 value to a List index.
|
||||
void SetListValue(CefRefPtr<CefListValue> list, int index,
|
||||
CefRefPtr<CefV8Value> value) {
|
||||
if (value->IsArray()) {
|
||||
CefRefPtr<CefListValue> new_list = CefListValue::Create();
|
||||
SetList(value, new_list);
|
||||
list->SetList(index, new_list);
|
||||
} else if (value->IsString()) {
|
||||
list->SetString(index, value->GetStringValue());
|
||||
} else if (value->IsBool()) {
|
||||
list->SetBool(index, value->GetBoolValue());
|
||||
} else if (value->IsInt()) {
|
||||
list->SetInt(index, value->GetIntValue());
|
||||
} else if (value->IsDouble()) {
|
||||
list->SetDouble(index, value->GetDoubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer a V8 array to a List.
|
||||
void SetList(CefRefPtr<CefV8Value> source, CefRefPtr<CefListValue> target) {
|
||||
ASSERT(source->IsArray());
|
||||
|
||||
int arg_length = source->GetArrayLength();
|
||||
if (arg_length == 0)
|
||||
return;
|
||||
|
||||
// Start with null types in all spaces.
|
||||
target->SetSize(arg_length);
|
||||
|
||||
for (int i = 0; i < arg_length; ++i)
|
||||
SetListValue(target, i, source->GetValue(i));
|
||||
}
|
||||
|
||||
// Transfer a List value to a V8 array index.
|
||||
void SetListValue(CefRefPtr<CefV8Value> list, int index,
|
||||
CefRefPtr<CefListValue> value) {
|
||||
CefRefPtr<CefV8Value> new_value;
|
||||
|
||||
CefValueType type = value->GetType(index);
|
||||
switch (type) {
|
||||
case VTYPE_LIST: {
|
||||
CefRefPtr<CefListValue> list = value->GetList(index);
|
||||
new_value = CefV8Value::CreateArray(static_cast<int>(list->GetSize()));
|
||||
SetList(list, new_value);
|
||||
} break;
|
||||
case VTYPE_BOOL:
|
||||
new_value = CefV8Value::CreateBool(value->GetBool(index));
|
||||
break;
|
||||
case VTYPE_DOUBLE:
|
||||
new_value = CefV8Value::CreateDouble(value->GetDouble(index));
|
||||
break;
|
||||
case VTYPE_INT:
|
||||
new_value = CefV8Value::CreateInt(value->GetInt(index));
|
||||
break;
|
||||
case VTYPE_STRING:
|
||||
new_value = CefV8Value::CreateString(value->GetString(index));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_value.get()) {
|
||||
list->SetValue(index, new_value);
|
||||
} else {
|
||||
list->SetValue(index, CefV8Value::CreateNull());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer a List to a V8 array.
|
||||
void SetList(CefRefPtr<CefListValue> source, CefRefPtr<CefV8Value> target) {
|
||||
ASSERT(target->IsArray());
|
||||
|
||||
int arg_length = static_cast<int>(source->GetSize());
|
||||
if (arg_length == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < arg_length; ++i)
|
||||
SetListValue(target, i, source);
|
||||
}
|
||||
|
||||
|
||||
// Handles the native implementation for the client_app extension.
|
||||
class ClientAppExtensionHandler : public CefV8Handler {
|
||||
public:
|
||||
explicit ClientAppExtensionHandler(CefRefPtr<ClientApp> client_app)
|
||||
: client_app_(client_app) {
|
||||
}
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
bool handled = false;
|
||||
|
||||
if (name == "sendMessage") {
|
||||
// Send a message to the browser process.
|
||||
if ((arguments.size() == 1 || arguments.size() == 2) &&
|
||||
arguments[0]->IsString()) {
|
||||
CefRefPtr<CefBrowser> browser =
|
||||
CefV8Context::GetCurrentContext()->GetBrowser();
|
||||
ASSERT(browser.get());
|
||||
|
||||
CefString name = arguments[0]->GetStringValue();
|
||||
if (!name.empty()) {
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(name);
|
||||
|
||||
// Translate the arguments, if any.
|
||||
if (arguments.size() == 2 && arguments[1]->IsArray())
|
||||
SetList(arguments[1], message->GetArgumentList());
|
||||
|
||||
browser->SendProcessMessage(PID_BROWSER, message);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
} else if (name == "setMessageCallback") {
|
||||
// Set a message callback.
|
||||
if (arguments.size() == 2 && arguments[0]->IsString() &&
|
||||
arguments[1]->IsFunction()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
int browser_id = context->GetBrowser()->GetIdentifier();
|
||||
client_app_->SetMessageCallback(name, browser_id, context,
|
||||
arguments[1]);
|
||||
handled = true;
|
||||
}
|
||||
} else if (name == "removeMessageCallback") {
|
||||
// Remove a message callback.
|
||||
if (arguments.size() == 1 && arguments[0]->IsString()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
int browser_id = context->GetBrowser()->GetIdentifier();
|
||||
bool removed = client_app_->RemoveMessageCallback(name, browser_id);
|
||||
retval = CefV8Value::CreateBool(removed);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
exception = "Invalid method arguments";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<ClientApp> client_app_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientAppExtensionHandler);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
ClientApp::ClientApp() {
|
||||
CreateBrowserDelegates(browser_delegates_);
|
||||
CreateRenderDelegates(render_delegates_);
|
||||
}
|
||||
|
||||
void ClientApp::OnRegisterCustomSchemes(
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) {
|
||||
// Default schemes that support cookies.
|
||||
cookieable_schemes_.push_back("http");
|
||||
cookieable_schemes_.push_back("https");
|
||||
}
|
||||
|
||||
void ClientApp::SetMessageCallback(const std::string& message_name,
|
||||
int browser_id,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Value> function) {
|
||||
ASSERT(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
callback_map_.insert(
|
||||
std::make_pair(std::make_pair(message_name, browser_id),
|
||||
std::make_pair(context, function)));
|
||||
}
|
||||
|
||||
bool ClientApp::RemoveMessageCallback(const std::string& message_name,
|
||||
int browser_id) {
|
||||
ASSERT(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
CallbackMap::iterator it =
|
||||
callback_map_.find(std::make_pair(message_name, browser_id));
|
||||
if (it != callback_map_.end()) {
|
||||
callback_map_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RegisterCustomSchemes(registrar, cookieable_schemes_);
|
||||
}
|
||||
|
||||
void ClientApp::OnContextInitialized() {
|
||||
CreateBrowserDelegates(browser_delegates_);
|
||||
|
||||
// Register cookieable schemes with the global cookie manager.
|
||||
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager();
|
||||
ASSERT(manager.get());
|
||||
@@ -234,34 +54,14 @@ void ClientApp::OnRenderProcessThreadCreated(
|
||||
}
|
||||
|
||||
void ClientApp::OnRenderThreadCreated(CefRefPtr<CefListValue> extra_info) {
|
||||
CreateRenderDelegates(render_delegates_);
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnRenderThreadCreated(this, extra_info);
|
||||
}
|
||||
|
||||
void ClientApp::OnWebKitInitialized() {
|
||||
// Register the client_app extension.
|
||||
std::string app_code =
|
||||
"var app;"
|
||||
"if (!app)"
|
||||
" app = {};"
|
||||
"(function() {"
|
||||
" app.sendMessage = function(name, arguments) {"
|
||||
" native function sendMessage();"
|
||||
" return sendMessage(name, arguments);"
|
||||
" };"
|
||||
" app.setMessageCallback = function(name, callback) {"
|
||||
" native function setMessageCallback();"
|
||||
" return setMessageCallback(name, callback);"
|
||||
" };"
|
||||
" app.removeMessageCallback = function(name) {"
|
||||
" native function removeMessageCallback();"
|
||||
" return removeMessageCallback(name);"
|
||||
" };"
|
||||
"})();";
|
||||
CefRegisterExtension("v8/app", app_code,
|
||||
new ClientAppExtensionHandler(this));
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnWebKitInitialized(this);
|
||||
@@ -281,7 +81,6 @@ void ClientApp::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
CefRefPtr<CefLoadHandler> ClientApp::GetLoadHandler() {
|
||||
CefRefPtr<CefLoadHandler> load_handler;
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end() && !load_handler.get(); ++it)
|
||||
load_handler = (*it)->GetLoadHandler(this);
|
||||
@@ -319,18 +118,6 @@ void ClientApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnContextReleased(this, browser, frame, context);
|
||||
|
||||
// Remove any JavaScript callbacks registered for the context that has been
|
||||
// released.
|
||||
if (!callback_map_.empty()) {
|
||||
CallbackMap::iterator it = callback_map_.begin();
|
||||
for (; it != callback_map_.end();) {
|
||||
if (it->second.first->IsSame(context))
|
||||
callback_map_.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientApp::OnUncaughtException(CefRefPtr<CefBrowser> browser,
|
||||
@@ -367,47 +154,5 @@ bool ClientApp::OnProcessMessageReceived(
|
||||
message);
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return true;
|
||||
|
||||
// Execute the registered JavaScript callback if any.
|
||||
if (!callback_map_.empty()) {
|
||||
CefString message_name = message->GetName();
|
||||
CallbackMap::const_iterator it = callback_map_.find(
|
||||
std::make_pair(message_name.ToString(),
|
||||
browser->GetIdentifier()));
|
||||
if (it != callback_map_.end()) {
|
||||
// Keep a local reference to the objects. The callback may remove itself
|
||||
// from the callback map.
|
||||
CefRefPtr<CefV8Context> context = it->second.first;
|
||||
CefRefPtr<CefV8Value> callback = it->second.second;
|
||||
|
||||
// Enter the context.
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList arguments;
|
||||
|
||||
// First argument is the message name.
|
||||
arguments.push_back(CefV8Value::CreateString(message_name));
|
||||
|
||||
// Second argument is the list of message arguments.
|
||||
CefRefPtr<CefListValue> list = message->GetArgumentList();
|
||||
CefRefPtr<CefV8Value> args =
|
||||
CefV8Value::CreateArray(static_cast<int>(list->GetSize()));
|
||||
SetList(list, args);
|
||||
arguments.push_back(args);
|
||||
|
||||
// Execute the callback.
|
||||
CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments);
|
||||
if (retval.get()) {
|
||||
if (retval->IsBool())
|
||||
handled = retval->GetBoolValue();
|
||||
}
|
||||
|
||||
// Exit the context.
|
||||
context->Exit();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
@@ -103,22 +103,6 @@ class ClientApp : public CefApp,
|
||||
|
||||
ClientApp();
|
||||
|
||||
// Set a JavaScript callback for the specified |message_name| and |browser_id|
|
||||
// combination. Will automatically be removed when the associated context is
|
||||
// released. Callbacks can also be set in JavaScript using the
|
||||
// app.setMessageCallback function.
|
||||
void SetMessageCallback(const std::string& message_name,
|
||||
int browser_id,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Value> function);
|
||||
|
||||
// Removes the JavaScript callback for the specified |message_name| and
|
||||
// |browser_id| combination. Returns true if a callback was removed. Callbacks
|
||||
// can also be removed in JavaScript using the app.removeMessageCallback
|
||||
// function.
|
||||
bool RemoveMessageCallback(const std::string& message_name,
|
||||
int browser_id);
|
||||
|
||||
private:
|
||||
// Creates all of the BrowserDelegate objects. Implemented in
|
||||
// client_app_delegates.
|
||||
@@ -134,9 +118,7 @@ class ClientApp : public CefApp,
|
||||
|
||||
// CefApp methods.
|
||||
virtual void OnRegisterCustomSchemes(
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE {
|
||||
RegisterCustomSchemes(registrar, cookieable_schemes_);
|
||||
}
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE;
|
||||
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
|
||||
OVERRIDE { return this; }
|
||||
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
|
||||
@@ -181,19 +163,14 @@ class ClientApp : public CefApp,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
// Map of message callbacks.
|
||||
typedef std::map<std::pair<std::string, int>,
|
||||
std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >
|
||||
CallbackMap;
|
||||
CallbackMap callback_map_;
|
||||
|
||||
// Set of supported BrowserDelegates.
|
||||
// Set of supported BrowserDelegates. Only used in the browser process.
|
||||
BrowserDelegateSet browser_delegates_;
|
||||
|
||||
// Set of supported RenderDelegates.
|
||||
// Set of supported RenderDelegates. Only used in the renderer process.
|
||||
RenderDelegateSet render_delegates_;
|
||||
|
||||
// Schemes that will be registered with the global cookie manager.
|
||||
// Schemes that will be registered with the global cookie manager. Used in
|
||||
// both the browser and renderer process.
|
||||
std::vector<CefString> cookieable_schemes_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientApp);
|
||||
|
@@ -98,7 +98,15 @@ ClientHandler::ClientHandler()
|
||||
m_StopHwnd(NULL),
|
||||
m_ReloadHwnd(NULL),
|
||||
m_bFocusOnEditableField(false) {
|
||||
CreateProcessMessageDelegates(process_message_delegates_);
|
||||
// Create the browser-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
message_router_ = CefMessageRouterBrowserSide::Create(config);
|
||||
|
||||
// Register handlers with the router.
|
||||
CreateMessageHandlers(message_handler_set_);
|
||||
MessageHandlerSet::const_iterator it = message_handler_set_.begin();
|
||||
for (; it != message_handler_set_.end(); ++it)
|
||||
message_router_->AddHandler(*(it), false);
|
||||
|
||||
// Read command line settings.
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
@@ -120,6 +128,11 @@ bool ClientHandler::OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
if (message_router_->OnProcessMessageReceived(browser, source_process,
|
||||
message)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for messages from the client renderer.
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == client_renderer::kFocusedNodeChangedMessage) {
|
||||
@@ -131,16 +144,7 @@ bool ClientHandler::OnProcessMessageReceived(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
// Execute delegate callbacks.
|
||||
ProcessMessageDelegateSet::iterator it = process_message_delegates_.begin();
|
||||
for (; it != process_message_delegates_.end() && !handled; ++it) {
|
||||
handled = (*it)->OnProcessMessageReceived(this, browser, source_process,
|
||||
message);
|
||||
}
|
||||
|
||||
return handled;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforeContextMenu(
|
||||
@@ -343,6 +347,8 @@ bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
|
||||
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
message_router_->OnBeforeClose(browser);
|
||||
|
||||
if (m_BrowserId == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
m_Browser = NULL;
|
||||
@@ -363,7 +369,17 @@ void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
|
||||
if (--m_BrowserCount == 0) {
|
||||
// All browser windows have closed. Quit the application message loop.
|
||||
// All browser windows have closed.
|
||||
// Remove and delete message router handlers.
|
||||
MessageHandlerSet::const_iterator it = message_handler_set_.begin();
|
||||
for (; it != message_handler_set_.end(); ++it) {
|
||||
message_router_->RemoveHandler(*(it));
|
||||
delete *(it);
|
||||
}
|
||||
message_handler_set_.clear();
|
||||
message_router_ = NULL;
|
||||
|
||||
// Quit the application message loop.
|
||||
AppQuitMessageLoop();
|
||||
}
|
||||
}
|
||||
@@ -412,10 +428,18 @@ void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
|
||||
frame->LoadString(ss.str(), failedUrl);
|
||||
}
|
||||
|
||||
bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) {
|
||||
message_router_->OnBeforeBrowse(browser, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
std::string url = request->GetURL();
|
||||
if (url.find(kTestOrigin) == 0) {
|
||||
// Handle URLs in the test origin.
|
||||
@@ -469,6 +493,8 @@ void ClientHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) {
|
||||
message_router_->OnRenderProcessTerminated(browser);
|
||||
|
||||
// Load the startup URL if that's not the website that we terminated on.
|
||||
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
|
||||
std::string url = frame->GetURL();
|
||||
@@ -693,16 +719,15 @@ bool ClientHandler::Save(const std::string& path, const std::string& data) {
|
||||
}
|
||||
|
||||
// static
|
||||
void ClientHandler::CreateProcessMessageDelegates(
|
||||
ProcessMessageDelegateSet& delegates) {
|
||||
// Create the binding test delegates.
|
||||
binding_test::CreateProcessMessageDelegates(delegates);
|
||||
void ClientHandler::CreateMessageHandlers(MessageHandlerSet& handlers) {
|
||||
// Create the dialog test handlers.
|
||||
dialog_test::CreateMessageHandlers(handlers);
|
||||
|
||||
// Create the dialog test delegates.
|
||||
dialog_test::CreateProcessMessageDelegates(delegates);
|
||||
// Create the binding test handlers.
|
||||
binding_test::CreateMessageHandlers(handlers);
|
||||
|
||||
// Create the window test delegates.
|
||||
window_test::CreateProcessMessageDelegates(delegates);
|
||||
// Create the window test handlers.
|
||||
window_test::CreateMessageHandlers(handlers);
|
||||
}
|
||||
|
||||
void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include "include/cef_client.h"
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "cefclient/util.h"
|
||||
|
||||
|
||||
@@ -32,32 +33,14 @@ class ClientHandler : public CefClient,
|
||||
public CefRenderHandler,
|
||||
public CefRequestHandler {
|
||||
public:
|
||||
// Interface for process message delegates. Do not perform work in the
|
||||
// RenderDelegate constructor.
|
||||
class ProcessMessageDelegate : public virtual CefBase {
|
||||
public:
|
||||
// Called when a process message is received. Return true if the message was
|
||||
// handled and should not be passed on to other handlers.
|
||||
// ProcessMessageDelegates should check for unique message names to avoid
|
||||
// interfering with each other.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<CefRefPtr<ProcessMessageDelegate> >
|
||||
ProcessMessageDelegateSet;
|
||||
|
||||
// Interface implemented to handle off-screen rendering.
|
||||
class RenderHandler : public CefRenderHandler {
|
||||
public:
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) =0;
|
||||
};
|
||||
|
||||
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
|
||||
|
||||
ClientHandler();
|
||||
virtual ~ClientHandler();
|
||||
|
||||
@@ -174,6 +157,10 @@ class ClientHandler : public CefClient,
|
||||
const CefString& failedUrl) OVERRIDE;
|
||||
|
||||
// CefRequestHandler methods
|
||||
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) OVERRIDE;
|
||||
virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
@@ -264,9 +251,9 @@ class ClientHandler : public CefClient,
|
||||
void SetLoading(bool isLoading);
|
||||
void SetNavState(bool canGoBack, bool canGoForward);
|
||||
|
||||
// Create all of ProcessMessageDelegate objects.
|
||||
static void CreateProcessMessageDelegates(
|
||||
ProcessMessageDelegateSet& delegates);
|
||||
// Create all CefMessageRouterBrowserSide::Handler objects. They will be
|
||||
// deleted when the ClientHandler is destroyed.
|
||||
static void CreateMessageHandlers(MessageHandlerSet& handlers);
|
||||
|
||||
// Test context menu creation.
|
||||
void BuildTestMenu(CefRefPtr<CefMenuModel> model);
|
||||
@@ -317,15 +304,19 @@ class ClientHandler : public CefClient,
|
||||
// True if an editable field currently has focus.
|
||||
bool m_bFocusOnEditableField;
|
||||
|
||||
// Registered delegates.
|
||||
ProcessMessageDelegateSet process_message_delegates_;
|
||||
|
||||
// The startup URL.
|
||||
std::string m_StartupURL;
|
||||
|
||||
// True if mouse cursor change is disabled.
|
||||
bool m_bMouseCursorChangeDisabled;
|
||||
|
||||
// Handles the browser side of query routing. The renderer side is handled
|
||||
// in client_renderer.cpp.
|
||||
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
|
||||
|
||||
// Set of Handlers registered with the message router.
|
||||
MessageHandlerSet message_handler_set_;
|
||||
|
||||
// Number of currently existing browser windows. The application will exit
|
||||
// when the number of windows reaches 0.
|
||||
static int m_BrowserCount;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "include/cef_dom.h"
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "cefclient/util.h"
|
||||
|
||||
namespace client_renderer {
|
||||
@@ -22,6 +23,26 @@ class ClientRenderDelegate : public ClientApp::RenderDelegate {
|
||||
: last_node_is_editable_(false) {
|
||||
}
|
||||
|
||||
virtual void OnWebKitInitialized(CefRefPtr<ClientApp> app) OVERRIDE {
|
||||
// Create the renderer-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
}
|
||||
|
||||
virtual void OnContextCreated(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextCreated(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnContextReleased(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextReleased(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnFocusedNodeChanged(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
@@ -37,9 +58,21 @@ class ClientRenderDelegate : public ClientApp::RenderDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
private:
|
||||
bool last_node_is_editable_;
|
||||
|
||||
// Handles the renderer side of query routing.
|
||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientRenderDelegate);
|
||||
};
|
||||
|
||||
|
@@ -11,54 +11,54 @@ namespace dialog_test {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTestUrl = "http://tests/dialogs";
|
||||
const char* kFileOpenMessageName = "DialogTest.FileOpen";
|
||||
const char* kFileOpenMultipleMessageName = "DialogTest.FileOpenMultiple";
|
||||
const char* kFileSaveMessageName = "DialogTest.FileSave";
|
||||
const char kTestUrl[] = "http://tests/dialogs";
|
||||
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
|
||||
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
|
||||
const char kFileSaveMessageName[] = "DialogTest.FileSave";
|
||||
|
||||
class RunFileDialogCallback : public CefRunFileDialogCallback {
|
||||
// Callback executed when the file dialog is dismissed.
|
||||
class DialogCallback : public CefRunFileDialogCallback {
|
||||
public:
|
||||
explicit RunFileDialogCallback(const std::string& message_name)
|
||||
: message_name_(message_name) {
|
||||
explicit DialogCallback(
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback)
|
||||
: router_callback_(router_callback) {
|
||||
}
|
||||
|
||||
virtual void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
const std::vector<CefString>& file_paths) OVERRIDE {
|
||||
// Send a message back to the render process with the same name and the list
|
||||
// of file paths.
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(message_name_);
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
CefRefPtr<CefListValue> val = CefListValue::Create();
|
||||
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i)
|
||||
val->SetString(i, file_paths[i]);
|
||||
args->SetList(0, val);
|
||||
// Send a message back to the render process with the list of file paths.
|
||||
std::string response;
|
||||
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
|
||||
if (!response.empty())
|
||||
response += "|"; // Use a delimiter disallowed in file paths.
|
||||
response += file_paths[i];
|
||||
}
|
||||
|
||||
// This will result in a call to the callback registered via JavaScript in
|
||||
// dialogs.html.
|
||||
browser_host->GetBrowser()->SendProcessMessage(PID_RENDERER, message);
|
||||
router_callback_->Success(response);
|
||||
router_callback_ = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string message_name_;
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(RunFileDialogCallback);
|
||||
IMPLEMENT_REFCOUNTING(DialogCallback);
|
||||
};
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string url = browser->GetMainFrame()->GetURL();
|
||||
// Called due to cefQuery execution in dialogs.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
@@ -68,35 +68,31 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
file_types.push_back(".log");
|
||||
file_types.push_back(".patch");
|
||||
|
||||
std::string message_name = message->GetName();
|
||||
CefRefPtr<DialogCallback> dialog_callback(new DialogCallback(callback));
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name == kFileOpenMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN, "My Open Dialog",
|
||||
"test.txt", file_types, new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
} else if (message_name == kFileOpenMultipleMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN_MULTIPLE,
|
||||
"My Open Multiple Dialog", CefString(), file_types,
|
||||
new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
dialog_callback.get());
|
||||
} else if (message_name == kFileSaveMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_SAVE, "My Save Dialog",
|
||||
"test.txt", file_types, new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
} else {
|
||||
ASSERT(false); // Not reached.
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
} // namespace dialog_test
|
||||
|
@@ -10,9 +10,8 @@
|
||||
|
||||
namespace dialog_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
/// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
} // namespace dialog_test
|
||||
|
||||
|
@@ -3,15 +3,16 @@
|
||||
<title>Binding Test</title>
|
||||
<script language="JavaScript">
|
||||
|
||||
// Register the callback for messages from the browser process.
|
||||
app.setMessageCallback('binding_test', function(name, args) {
|
||||
document.getElementById('result').value = "Response: "+args[0];
|
||||
});
|
||||
|
||||
// Send a message to the browser process.
|
||||
// Send a query to the browser process.
|
||||
function sendMessage() {
|
||||
var msg = document.getElementById("message").value;
|
||||
app.sendMessage('binding_test', [msg]);
|
||||
// Results in a call to the OnQuery method in binding_test.cpp
|
||||
window.cefQuery({
|
||||
request: 'BindingTest:' + document.getElementById("message").value,
|
||||
onSuccess: function(response) {
|
||||
document.getElementById('result').value = 'Response: '+response;
|
||||
},
|
||||
onFailure: function(error_code, error_message) {}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@@ -35,14 +35,14 @@ function show_file_dialog(element, test) {
|
||||
var message = 'DialogTest.' + test;
|
||||
var target = document.getElementById(element);
|
||||
|
||||
// Register for the callback from OnFileDialogDismissed in dialog_test.cpp.
|
||||
app.setMessageCallback(message, function(msg, paths) {
|
||||
target.innerText = paths.join();
|
||||
app.removeMessageCallback(message);
|
||||
// Results in a call to the OnQuery method in dialog_test.cpp
|
||||
window.cefQuery({
|
||||
request: message,
|
||||
onSuccess: function(response) {
|
||||
target.innerText = response;
|
||||
},
|
||||
onFailure: function(error_code, error_message) {}
|
||||
});
|
||||
|
||||
// This will result in a call to OnProcessMessageReceived in dialog_test.cpp.
|
||||
app.sendMessage(message);
|
||||
}
|
||||
|
||||
window.addEventListener('load', setup, false);
|
||||
|
@@ -8,10 +8,6 @@
|
||||
#LI11select {width: 75px;}
|
||||
</style>
|
||||
<script>
|
||||
function sendBrowserMessage(paramString) {
|
||||
app.sendMessage("osrtest", [paramString]);
|
||||
}
|
||||
|
||||
function getElement(id) { return document.getElementById(id); }
|
||||
function makeH1Red() { getElement('LI00').style.color='red'; }
|
||||
function makeH1Black() { getElement('LI00').style.color='black'; }
|
||||
@@ -22,12 +18,13 @@
|
||||
}
|
||||
|
||||
function onEventTest(event) {
|
||||
var param = event.type;
|
||||
var param = 'osr' + event.type;
|
||||
|
||||
if (event.type == "click")
|
||||
param += event.button;
|
||||
|
||||
sendBrowserMessage(param);
|
||||
// Results in a call to the OnQuery method in os_rendering_unittest.cc.
|
||||
window.testQuery({request: param});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@@ -3,8 +3,12 @@
|
||||
<title>Window Test</title>
|
||||
<script>
|
||||
function send_message(test, params) {
|
||||
// This will result in a call to OnProcessMessageReceived in window_test.cpp.
|
||||
app.sendMessage('WindowTest.' + test, params);
|
||||
var message = 'WindowTest.' + test;
|
||||
if (typeof params != 'undefined')
|
||||
message += ':' + params;
|
||||
|
||||
// Results in a call to the OnQuery method in window_test.cpp.
|
||||
window.cefQuery({'request' : message});
|
||||
}
|
||||
|
||||
function minimize() {
|
||||
@@ -28,7 +32,7 @@ function position() {
|
||||
if (isNaN(x) || isNaN(y) || isNaN(width) || isNaN(height))
|
||||
alert('Please specify a valid numeric value.');
|
||||
else
|
||||
send_message('Position', [x, y, width, height]);
|
||||
send_message('Position', x + ',' + y + ',' + width + ',' + height);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
@@ -5,7 +5,9 @@
|
||||
#include "cefclient/window_test.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||
|
||||
@@ -13,56 +15,66 @@ namespace window_test {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kMessagePositionName = "WindowTest.Position";
|
||||
const char* kMessageMinimizeName = "WindowTest.Minimize";
|
||||
const char* kMessageMaximizeName = "WindowTest.Maximize";
|
||||
const char* kMessageRestoreName = "WindowTest.Restore";
|
||||
const char kTestUrl[] = "http://tests/window";
|
||||
const char kMessagePositionName[] = "WindowTest.Position";
|
||||
const char kMessageMinimizeName[] = "WindowTest.Minimize";
|
||||
const char kMessageMaximizeName[] = "WindowTest.Maximize";
|
||||
const char kMessageRestoreName[] = "WindowTest.Restore";
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == kMessagePositionName) {
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
if (args->GetSize() >= 4) {
|
||||
int x = args->GetInt(0);
|
||||
int y = args->GetInt(1);
|
||||
int width = args->GetInt(2);
|
||||
int height = args->GetInt(3);
|
||||
SetPos(browser->GetHost()->GetWindowHandle(), x, y, width, height);
|
||||
// Called due to cefBroadcast execution in window.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name.find(kMessagePositionName) == 0) {
|
||||
// Parse the comma-delimited list of integer values.
|
||||
std::vector<int> vec;
|
||||
const std::string& vals =
|
||||
message_name.substr(sizeof(kMessagePositionName));
|
||||
std::stringstream ss(vals);
|
||||
int i;
|
||||
while (ss >> i) {
|
||||
vec.push_back(i);
|
||||
if (ss.peek() == ',')
|
||||
ss.ignore();
|
||||
}
|
||||
|
||||
if (vec.size() == 4) {
|
||||
SetPos(browser->GetHost()->GetWindowHandle(),
|
||||
vec[0], vec[1], vec[2], vec[3]);
|
||||
}
|
||||
return true;
|
||||
} else if (message_name == kMessageMinimizeName) {
|
||||
Minimize(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else if (message_name == kMessageMaximizeName) {
|
||||
Maximize(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else if (message_name == kMessageRestoreName) {
|
||||
Restore(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else {
|
||||
ASSERT(false); // Not reached.
|
||||
}
|
||||
|
||||
return false;
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
void ModifyBounds(const CefRect& display, CefRect& window) {
|
||||
|
@@ -10,9 +10,8 @@
|
||||
|
||||
namespace window_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
/// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
// Fit |window| inside |display|. Coordinates are relative to the upper-left
|
||||
// corner of the display.
|
||||
|
718
tests/unittests/browser_info_map_unittest.cc
Normal file
718
tests/unittests/browser_info_map_unittest.cc
Normal file
@@ -0,0 +1,718 @@
|
||||
// Copyright (c) 2014 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 <list>
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "libcef_dll/wrapper/cef_browser_info_map.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct MyObject {
|
||||
MyObject(int val = 0) : member(val) {}
|
||||
int member;
|
||||
};
|
||||
|
||||
int g_destruct_ct = 0;
|
||||
|
||||
struct MyObjectTraits {
|
||||
static void Destruct(MyObject info) {
|
||||
g_destruct_ct++;
|
||||
}
|
||||
};
|
||||
|
||||
typedef CefBrowserInfoMap<int, MyObject, MyObjectTraits> MyObjectMap;
|
||||
|
||||
class MyVisitor : public MyObjectMap::Visitor {
|
||||
public:
|
||||
MyVisitor(bool remove = false,
|
||||
int remove_browser_id = 0,
|
||||
InfoIdType remove_info_id = 0)
|
||||
: remove_(remove),
|
||||
remove_browser_id_(remove_browser_id),
|
||||
remove_info_id_(remove_info_id) {}
|
||||
|
||||
virtual bool OnNextInfo(int browser_id,
|
||||
InfoIdType info_id,
|
||||
InfoObjectType info,
|
||||
bool* remove) OVERRIDE {
|
||||
Info info_rec;
|
||||
info_rec.browser_id = browser_id;
|
||||
info_rec.info_id = info_id;
|
||||
info_rec.info = info;
|
||||
info_list_.push_back(info_rec);
|
||||
|
||||
// Based on test configuration remove no objects, all objects, or only the
|
||||
// specified object.
|
||||
*remove = remove_ || (browser_id == remove_browser_id_ &&
|
||||
info_id == remove_info_id_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the specified info was passed to OnNextInfo. Removes the
|
||||
// record if found.
|
||||
bool Exists(int browser_id,
|
||||
InfoIdType info_id,
|
||||
InfoObjectType info) {
|
||||
InfoList::iterator it = info_list_.begin();
|
||||
for (; it != info_list_.end(); ++it) {
|
||||
const Info& found_info = *it;
|
||||
if (browser_id == found_info.browser_id &&
|
||||
info_id == found_info.info_id &&
|
||||
info.member == found_info.info.member) {
|
||||
info_list_.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t info_size() const { return info_list_.size(); }
|
||||
|
||||
private:
|
||||
bool remove_;
|
||||
int remove_browser_id_;
|
||||
InfoIdType remove_info_id_;
|
||||
|
||||
struct Info {
|
||||
int browser_id;
|
||||
InfoIdType info_id;
|
||||
InfoObjectType info;
|
||||
};
|
||||
|
||||
// Track calls to OnNextInfo.
|
||||
typedef std::list<Info> InfoList;
|
||||
InfoList info_list_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BrowserInfoMapTest, AddSingleBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId = 1;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId, 1, obj1);
|
||||
EXPECT_EQ(1U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId, 2, obj2);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId, 3, obj3);
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(3U, map.size(kBrowserId));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId);
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId));
|
||||
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, AddMultipleBrowsers) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
EXPECT_EQ(1U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId1);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId2);
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindSingleBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId = 1;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
// obj1 not added yet.
|
||||
MyObject nf1 = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId, 1, obj1);
|
||||
|
||||
// obj1 should exist.
|
||||
MyObject f1 = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
|
||||
// obj2 not added yet.
|
||||
MyObject nf2 = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId, 2, obj2);
|
||||
|
||||
// obj2 should exist.
|
||||
MyObject f2 = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
|
||||
// find obj1 again.
|
||||
MyObject f1b = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1b.member);
|
||||
|
||||
// find obj2 again.
|
||||
MyObject f2b = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2b.member);
|
||||
|
||||
// doesn't exist.
|
||||
MyObject nf3 = map.Find(kBrowserId, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
MyObject nf4 = map.Find(10, 1, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
MyObject nf5 = map.Find(10, 3, NULL);
|
||||
EXPECT_EQ(0, nf5.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindMultipleBrowsers) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
// obj1 not added yet.
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
// obj1 should exist.
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
|
||||
// obj2 not added yet.
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
// obj2 should exist.
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
|
||||
// obj3 not added yet.
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
// obj3 should exist.
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
|
||||
// obj4 not added yet.
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
// obj4 should exist.
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
// obj1-3 should exist.
|
||||
MyObject f1b = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1b.member);
|
||||
MyObject f2b = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2b.member);
|
||||
MyObject f3b = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3b.member);
|
||||
|
||||
// wrong browser
|
||||
MyObject nf5 = map.Find(kBrowserId1, 4, NULL);
|
||||
EXPECT_EQ(0, nf5.member);
|
||||
MyObject nf6 = map.Find(kBrowserId2, 1, NULL);
|
||||
EXPECT_EQ(0, nf6.member);
|
||||
|
||||
// deosn't exist
|
||||
MyObject nf7 = map.Find(kBrowserId2, 5, NULL);
|
||||
EXPECT_EQ(0, nf7.member);
|
||||
MyObject nf8 = map.Find(8, 1, NULL);
|
||||
EXPECT_EQ(0, nf8.member);
|
||||
MyObject nf9 = map.Find(8, 10, NULL);
|
||||
EXPECT_EQ(0, nf9.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, Find) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit the single object
|
||||
MyVisitor visitor;
|
||||
map.Find(kBrowserId2, 4, &visitor);
|
||||
EXPECT_EQ(1U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAndRemove) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit and remove the single object.
|
||||
MyVisitor visitor(true);
|
||||
map.Find(kBrowserId1, 2, &visitor);
|
||||
EXPECT_EQ(1U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// visited object shouldn't exist
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, nf1.member);
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, nf3.member);
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, nf4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAll) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects
|
||||
MyVisitor visitor;
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit browser2 objects
|
||||
MyVisitor visitor;
|
||||
map.FindAll(kBrowserId2, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveAll) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects
|
||||
MyVisitor visitor(true);
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveOne) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects and remove one
|
||||
MyVisitor visitor(false, kBrowserId2, 3);
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
// removed object shouldn't exist
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveAllByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit browser1 objects
|
||||
MyVisitor visitor(true);
|
||||
map.FindAll(kBrowserId1, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// browser1 objects shouldn't exist
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
// browser 2 objects should exist
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 2 objects
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveOneByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit browser2 objects and remove one
|
||||
MyVisitor visitor(false, kBrowserId2, 4);
|
||||
map.FindAll(kBrowserId2, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
// removed object shouldn't exist
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class MyHeapObject {
|
||||
public:
|
||||
MyHeapObject(int* destroy_ct) : destroy_ct_(destroy_ct) {}
|
||||
~MyHeapObject() {
|
||||
(*destroy_ct_)++;
|
||||
}
|
||||
|
||||
private:
|
||||
int* destroy_ct_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BrowserInfoMapTest, DefaultTraits) {
|
||||
CefBrowserInfoMap<int, MyHeapObject*> map;
|
||||
|
||||
int destroy_ct = 0;
|
||||
map.Add(1, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(1, 2, new MyHeapObject(&destroy_ct));
|
||||
map.Add(2, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(2, 2, new MyHeapObject(&destroy_ct));
|
||||
map.Add(3, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(3, 2, new MyHeapObject(&destroy_ct));
|
||||
|
||||
EXPECT_EQ(6U, map.size());
|
||||
|
||||
map.clear(1);
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2, destroy_ct);
|
||||
|
||||
map.clear();
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(6, destroy_ct);
|
||||
}
|
@@ -21,6 +21,16 @@ void ClientApp::CreateBrowserDelegates(BrowserDelegateSet& delegates) {
|
||||
|
||||
// static
|
||||
void ClientApp::CreateRenderDelegates(RenderDelegateSet& delegates) {
|
||||
// Bring in the routing test handler delegate.
|
||||
extern void CreateRoutingTestHandlerDelegate(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
CreateRoutingTestHandlerDelegate(delegates);
|
||||
|
||||
// Bring in the message router tests.
|
||||
extern void CreateMessageRouterRendererTests(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
CreateMessageRouterRendererTests(delegates);
|
||||
|
||||
// Bring in the process message tests.
|
||||
extern void CreateProcessMessageRendererTests(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "include/cef_runnable.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "tests/unittests/routing_test_handler.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
@@ -13,7 +13,7 @@ const char kUnloadDialogText[] = "Are you sure?";
|
||||
const char kUnloadMsg[] = "LifeSpanTestHandler.Unload";
|
||||
|
||||
// Browser side.
|
||||
class LifeSpanTestHandler : public TestHandler {
|
||||
class LifeSpanTestHandler : public RoutingTestHandler {
|
||||
public:
|
||||
struct Settings {
|
||||
Settings()
|
||||
@@ -35,9 +35,9 @@ class LifeSpanTestHandler : public TestHandler {
|
||||
virtual void RunTest() OVERRIDE {
|
||||
// Add the resources that we will navigate to/from.
|
||||
std::string page = "<html><script>";
|
||||
|
||||
page += "window.onunload = function() { app.sendMessage('" +
|
||||
std::string(kUnloadMsg) + "'); };";
|
||||
|
||||
page += "window.onunload = function() { window.testQuery({request:'" +
|
||||
std::string(kUnloadMsg) + "'}); };";
|
||||
|
||||
if (settings_.add_onunload_handler) {
|
||||
page += "window.onbeforeunload = function() { return '" +
|
||||
@@ -53,7 +53,7 @@ class LifeSpanTestHandler : public TestHandler {
|
||||
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
got_after_created_.yes();
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
RoutingTestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
@@ -78,7 +78,7 @@ class LifeSpanTestHandler : public TestHandler {
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
}
|
||||
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
RoutingTestHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
virtual bool OnBeforeUnloadDialog(
|
||||
@@ -116,18 +116,18 @@ class LifeSpanTestHandler : public TestHandler {
|
||||
browser->GetHost()->CloseBrowser(settings_.force_close);
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
const std::string& message_name = message->GetName();
|
||||
if (message_name == kUnloadMsg) {
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
if (request.ToString() == kUnloadMsg) {
|
||||
if (!executing_delay_close_)
|
||||
got_unload_message_.yes();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
TrackCallback got_after_created_;
|
||||
|
2810
tests/unittests/message_router_unittest.cc
Normal file
2810
tests/unittests/message_router_unittest.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "tests/cefclient/client_app.h"
|
||||
#include "tests/cefclient/resource_util.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "tests/unittests/routing_test_handler.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
@@ -190,7 +190,7 @@ enum OSRTestType {
|
||||
};
|
||||
|
||||
// Used in the browser process.
|
||||
class OSRTestHandler : public TestHandler,
|
||||
class OSRTestHandler : public RoutingTestHandler,
|
||||
public CefRenderHandler,
|
||||
public CefContextMenuHandler {
|
||||
public:
|
||||
@@ -224,7 +224,7 @@ class OSRTestHandler : public TestHandler,
|
||||
EXPECT_TRUE(browser->GetHost()->IsWindowRenderingDisabled());
|
||||
DestroySucceededTestSoon();
|
||||
}
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
RoutingTestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
@@ -247,37 +247,33 @@ class OSRTestHandler : public TestHandler,
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
EXPECT_TRUE(browser.get());
|
||||
EXPECT_EQ(PID_RENDERER, source_process);
|
||||
EXPECT_TRUE(message.get());
|
||||
EXPECT_TRUE(message->IsReadOnly());
|
||||
|
||||
if (!started())
|
||||
return false;
|
||||
|
||||
const CefString kMessageName = "osrtest";
|
||||
EXPECT_EQ(kMessageName, message->GetName());
|
||||
|
||||
CefString stringParam = message->GetArgumentList()->GetString(0);
|
||||
const std::string& messageStr = request;
|
||||
switch(test_type_) {
|
||||
case OSR_TEST_FOCUS:
|
||||
EXPECT_EQ(stringParam, std::string("focus"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrfocus");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_CLICK_LEFT:
|
||||
EXPECT_EQ(stringParam, std::string("click0"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrclick0");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_CLICK_MIDDLE:
|
||||
EXPECT_EQ(stringParam, std::string("click1"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrclick1");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_MOUSE_MOVE:
|
||||
EXPECT_EQ(stringParam, std::string("mousemove"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrmousemove");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
default:
|
||||
@@ -285,6 +281,7 @@ class OSRTestHandler : public TestHandler,
|
||||
break;
|
||||
}
|
||||
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -12,11 +12,8 @@
|
||||
namespace {
|
||||
|
||||
// Unique values for the SendRecv test.
|
||||
const char* kSendRecvUrlNative =
|
||||
"http://tests/ProcessMessageTest.SendRecv/Native";
|
||||
const char* kSendRecvUrlJavaScript =
|
||||
"http://tests/ProcessMessageTest.SendRecv/JavaScript";
|
||||
const char* kSendRecvMsg = "ProcessMessageTest.SendRecv";
|
||||
const char kSendRecvUrl[] = "http://tests/ProcessMessageTest.SendRecv";
|
||||
const char kSendRecvMsg[] = "ProcessMessageTest.SendRecv";
|
||||
|
||||
// Creates a test message.
|
||||
CefRefPtr<CefProcessMessage> CreateTestMessage() {
|
||||
@@ -55,7 +52,7 @@ class SendRecvRendererTest : public ClientApp::RenderDelegate {
|
||||
EXPECT_TRUE(message.get());
|
||||
|
||||
std::string url = browser->GetMainFrame()->GetURL();
|
||||
if (url == kSendRecvUrlNative) {
|
||||
if (url == kSendRecvUrl) {
|
||||
// Echo the message back to the sender natively.
|
||||
EXPECT_TRUE(browser->SendProcessMessage(PID_BROWSER, message));
|
||||
return true;
|
||||
@@ -72,33 +69,14 @@ class SendRecvRendererTest : public ClientApp::RenderDelegate {
|
||||
// Browser side.
|
||||
class SendRecvTestHandler : public TestHandler {
|
||||
public:
|
||||
explicit SendRecvTestHandler(bool native)
|
||||
: native_(native) {
|
||||
SendRecvTestHandler() {
|
||||
}
|
||||
|
||||
virtual void RunTest() OVERRIDE {
|
||||
message_ = CreateTestMessage();
|
||||
|
||||
if (native_) {
|
||||
// Native test.
|
||||
AddResource(kSendRecvUrlNative, "<html><body>TEST NATIVE</body></html>",
|
||||
"text/html");
|
||||
CreateBrowser(kSendRecvUrlNative);
|
||||
} else {
|
||||
// JavaScript test.
|
||||
std::string content =
|
||||
"<html><head>\n"
|
||||
"<script>\n"
|
||||
"function cb(name, args) {\n"
|
||||
" app.sendMessage(name, args);\n"
|
||||
"}\n"
|
||||
"app.setMessageCallback('"+std::string(kSendRecvMsg)+"', cb);\n"
|
||||
"</script>\n"
|
||||
"<body>TEST JAVASCRIPT</body>\n"
|
||||
"</head></html>";
|
||||
AddResource(kSendRecvUrlJavaScript, content, "text/html");
|
||||
CreateBrowser(kSendRecvUrlJavaScript);
|
||||
}
|
||||
AddResource(kSendRecvUrl, "<html><body>TEST</body></html>", "text/html");
|
||||
CreateBrowser(kSendRecvUrl);
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
@@ -128,30 +106,21 @@ class SendRecvTestHandler : public TestHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool native_;
|
||||
CefRefPtr<CefProcessMessage> message_;
|
||||
TrackCallback got_message_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Verify native send and recieve
|
||||
TEST(ProcessMessageTest, SendRecvNative) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(true);
|
||||
// Verify send and recieve.
|
||||
TEST(ProcessMessageTest, SendRecv) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler();
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_message_);
|
||||
}
|
||||
|
||||
// Verify JavaScript send and recieve
|
||||
TEST(ProcessMessageTest, SendRecvJavaScript) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(false);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_message_);
|
||||
}
|
||||
|
||||
// Verify create
|
||||
// Verify create.
|
||||
TEST(ProcessMessageTest, Create) {
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(kSendRecvMsg);
|
||||
@@ -167,7 +136,7 @@ TEST(ProcessMessageTest, Create) {
|
||||
EXPECT_FALSE(args->IsReadOnly());
|
||||
}
|
||||
|
||||
// Verify copy
|
||||
// Verify copy.
|
||||
TEST(ProcessMessageTest, Copy) {
|
||||
CefRefPtr<CefProcessMessage> message = CreateTestMessage();
|
||||
CefRefPtr<CefProcessMessage> message2 = message->Copy();
|
||||
|
104
tests/unittests/routing_test_handler.cc
Normal file
104
tests/unittests/routing_test_handler.cc
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2014 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 "tests/unittests/routing_test_handler.h"
|
||||
#include "tests/cefclient/client_app.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void SetRouterConfig(CefMessageRouterConfig& config) {
|
||||
config.js_query_function = "testQuery";
|
||||
config.js_cancel_function = "testQueryCancel";
|
||||
}
|
||||
|
||||
// Handle the renderer side of the routing implementation.
|
||||
class RoutingRenderDelegate : public ClientApp::RenderDelegate {
|
||||
public:
|
||||
RoutingRenderDelegate() {}
|
||||
|
||||
virtual void OnWebKitInitialized(CefRefPtr<ClientApp> app) OVERRIDE {
|
||||
// Create the renderer-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
SetRouterConfig(config);
|
||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
}
|
||||
|
||||
virtual void OnContextCreated(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextCreated(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnContextReleased(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextReleased(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(RoutingRenderDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
RoutingTestHandler::RoutingTestHandler() {
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
if (!message_router_) {
|
||||
// Create the browser-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
SetRouterConfig(config);
|
||||
message_router_ = CefMessageRouterBrowserSide::Create(config);
|
||||
message_router_->AddHandler(this, false);
|
||||
}
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
message_router_->OnBeforeClose(browser);
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnRenderProcessTerminated(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) {
|
||||
message_router_->OnRenderProcessTerminated(browser);
|
||||
}
|
||||
|
||||
bool RoutingTestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) {
|
||||
message_router_->OnBeforeBrowse(browser, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RoutingTestHandler::OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
// Entry point for creating the test delegate.
|
||||
// Called from client_app_delegates.cc.
|
||||
void CreateRoutingTestHandlerDelegate(
|
||||
ClientApp::RenderDelegateSet& delegates) {
|
||||
delegates.insert(new RoutingRenderDelegate);
|
||||
}
|
44
tests/unittests/routing_test_handler.h
Normal file
44
tests/unittests/routing_test_handler.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2014 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_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
||||
#define CEF_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
|
||||
// Extends TestHandler to provide message routing functionality. The
|
||||
// RoutingTestHandler implementation must be called from subclass
|
||||
// overrides unless otherwise indicated.
|
||||
class RoutingTestHandler :
|
||||
public TestHandler,
|
||||
public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
RoutingTestHandler();
|
||||
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual void OnRenderProcessTerminated(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) OVERRIDE;
|
||||
|
||||
// Only call this method if the navigation isn't canceled.
|
||||
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) OVERRIDE;
|
||||
|
||||
// Returns true if the router handled the navigation.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
private:
|
||||
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
|
||||
};
|
||||
|
||||
|
||||
#endif // CEF_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
@@ -3,7 +3,6 @@
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "base/logging.h"
|
||||
#include "include/cef_command_line.h"
|
||||
#include "include/cef_runnable.h"
|
||||
#include "include/cef_stream.h"
|
||||
@@ -47,16 +46,16 @@ void TestHandler::CompletionState::WaitForTests() {
|
||||
|
||||
TestHandler::Collection::Collection(CompletionState* completion_state)
|
||||
: completion_state_(completion_state) {
|
||||
DCHECK(completion_state_);
|
||||
EXPECT_TRUE(completion_state_);
|
||||
}
|
||||
|
||||
void TestHandler::Collection::AddTestHandler(TestHandler* test_handler) {
|
||||
DCHECK_EQ(test_handler->completion_state_, completion_state_);
|
||||
EXPECT_EQ(test_handler->completion_state_, completion_state_);
|
||||
handler_list_.push_back(test_handler);
|
||||
}
|
||||
|
||||
void TestHandler::Collection::ExecuteTests() {
|
||||
DCHECK_GT(handler_list_.size(), 0UL);
|
||||
EXPECT_GT(handler_list_.size(), 0UL);
|
||||
|
||||
TestHandlerList::const_iterator it;
|
||||
|
||||
@@ -79,7 +78,8 @@ void TestHandler::Collection::ExecuteTests() {
|
||||
int TestHandler::browser_count_ = 0;
|
||||
|
||||
TestHandler::TestHandler(CompletionState* completion_state)
|
||||
: browser_id_(0) {
|
||||
: first_browser_id_(0),
|
||||
signal_completion_when_all_browsers_close_(true) {
|
||||
if (completion_state) {
|
||||
completion_state_ = completion_state;
|
||||
completion_state_owned_ = false;
|
||||
@@ -90,31 +90,48 @@ TestHandler::TestHandler(CompletionState* completion_state)
|
||||
}
|
||||
|
||||
TestHandler::~TestHandler() {
|
||||
EXPECT_TRUE(browser_map_.empty());
|
||||
|
||||
if (completion_state_owned_)
|
||||
delete completion_state_;
|
||||
}
|
||||
|
||||
void TestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
browser_count_++;
|
||||
|
||||
AutoLock lock_scope(this);
|
||||
if (!browser->IsPopup()) {
|
||||
// Keep the main child window, but not popup windows
|
||||
browser_ = browser;
|
||||
browser_id_ = browser->GetIdentifier();
|
||||
// Keep non-popup browsers.
|
||||
const int browser_id = browser->GetIdentifier();
|
||||
EXPECT_EQ(browser_map_.find(browser_id), browser_map_.end());
|
||||
if (browser_map_.empty()) {
|
||||
first_browser_id_ = browser_id;
|
||||
first_browser_ = browser;
|
||||
}
|
||||
browser_map_.insert(std::make_pair(browser_id, browser));
|
||||
}
|
||||
}
|
||||
|
||||
void TestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
{
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
browser_ = NULL;
|
||||
browser_id_ = 0;
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
if (!browser->IsPopup()) {
|
||||
// Free the browser pointer so that the browser can be destroyed.
|
||||
const int browser_id = browser->GetIdentifier();
|
||||
BrowserMap::iterator it = browser_map_.find(browser_id);
|
||||
EXPECT_NE(it, browser_map_.end());
|
||||
browser_map_.erase(it);
|
||||
|
||||
if (browser_id == first_browser_id_) {
|
||||
first_browser_id_ = 0;
|
||||
first_browser_ = NULL;
|
||||
}
|
||||
|
||||
if (browser_map_.empty() &&
|
||||
signal_completion_when_all_browsers_close_) {
|
||||
// Signal that the test is now complete.
|
||||
completion_state_->TestComplete();
|
||||
TestComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +142,7 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
AutoLock lock_scope(this);
|
||||
EXPECT_IO_THREAD();
|
||||
|
||||
if (resource_map_.size() > 0) {
|
||||
CefString url = request->GetURL();
|
||||
@@ -150,8 +167,22 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> TestHandler::GetBrowser() {
|
||||
return first_browser_;
|
||||
}
|
||||
|
||||
int TestHandler::GetBrowserId() {
|
||||
return first_browser_id_;
|
||||
}
|
||||
|
||||
void TestHandler::GetAllBrowsers(BrowserMap* map) {
|
||||
EXPECT_UI_THREAD();
|
||||
EXPECT_TRUE(map);
|
||||
*map = browser_map_;
|
||||
}
|
||||
|
||||
void TestHandler::ExecuteTest() {
|
||||
DCHECK_EQ(completion_state_->total(), 1);
|
||||
EXPECT_EQ(completion_state_->total(), 1);
|
||||
|
||||
// Run the test
|
||||
RunTest();
|
||||
@@ -166,9 +197,21 @@ void TestHandler::SetupComplete() {
|
||||
}
|
||||
|
||||
void TestHandler::DestroyTest() {
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ != 0)
|
||||
browser_->GetHost()->CloseBrowser(false);
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, NewCefRunnableMethod(this, &TestHandler::DestroyTest));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!browser_map_.empty()) {
|
||||
// Use a copy of the map since the original may be modified while we're
|
||||
// iterating.
|
||||
BrowserMap browser_map = browser_map_;
|
||||
|
||||
// Tell all non-popup browsers to close.
|
||||
BrowserMap::const_iterator it = browser_map.begin();
|
||||
for (; it != browser_map.end(); ++it)
|
||||
it->second->GetHost()->CloseBrowser(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TestHandler::CreateBrowser(
|
||||
@@ -187,6 +230,13 @@ void TestHandler::CreateBrowser(
|
||||
void TestHandler::AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mimeType) {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
NewCefRunnableMethod(this, &TestHandler::AddResource, url, content,
|
||||
mimeType));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore the query component, if any.
|
||||
std::string urlStr = url;
|
||||
size_t idx = urlStr.find('?');
|
||||
@@ -198,9 +248,25 @@ void TestHandler::AddResource(const std::string& url,
|
||||
}
|
||||
|
||||
void TestHandler::ClearResources() {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
NewCefRunnableMethod(this, &TestHandler::ClearResources));
|
||||
return;
|
||||
}
|
||||
|
||||
resource_map_.clear();
|
||||
}
|
||||
|
||||
void TestHandler::TestComplete() {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, NewCefRunnableMethod(this, &TestHandler::TestComplete));
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(browser_map_.empty());
|
||||
completion_state_->TestComplete();
|
||||
}
|
||||
|
||||
|
||||
// global functions
|
||||
|
||||
|
@@ -94,6 +94,8 @@ class TestHandler : public CefClient,
|
||||
TestHandlerList handler_list_;
|
||||
};
|
||||
|
||||
typedef std::map<int, CefRefPtr<CefBrowser> > BrowserMap;
|
||||
|
||||
// The |completion_state| object if specified must outlive this class.
|
||||
explicit TestHandler(CompletionState* completion_state = NULL);
|
||||
virtual ~TestHandler();
|
||||
@@ -149,8 +151,13 @@ class TestHandler : public CefClient,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) OVERRIDE;
|
||||
|
||||
CefRefPtr<CefBrowser> GetBrowser() { return browser_; }
|
||||
int GetBrowserId() { return browser_id_; }
|
||||
// These methods should only be used if at most one non-popup browser exists.
|
||||
CefRefPtr<CefBrowser> GetBrowser();
|
||||
int GetBrowserId();
|
||||
|
||||
// Copies the map of all the currently existing browsers into |map|. Must be
|
||||
// called on the UI thread.
|
||||
void GetAllBrowsers(BrowserMap* map);
|
||||
|
||||
// Called by the test function to execute the test. This method blocks until
|
||||
// the test is complete. Do not reference the object after this method
|
||||
@@ -166,8 +173,11 @@ class TestHandler : public CefClient,
|
||||
// Collection.
|
||||
virtual void SetupComplete();
|
||||
|
||||
// Destroy the browser window. Once the window is destroyed test completion
|
||||
// will be signaled.
|
||||
// Close any existing non-popup browsers. Test completion will be signaled
|
||||
// once all the browsers have closed if
|
||||
// |signal_completion_when_all_browsers_close_| is true (default value).
|
||||
// If no browsers exist then this method will do nothing and
|
||||
// TestComplete() must be called manually.
|
||||
virtual void DestroyTest();
|
||||
|
||||
void CreateBrowser(const CefString& url,
|
||||
@@ -178,26 +188,44 @@ class TestHandler : public CefClient,
|
||||
const std::string& mimeType);
|
||||
void ClearResources();
|
||||
|
||||
void SetSignalCompletionWhenAllBrowsersClose(bool val) {
|
||||
signal_completion_when_all_browsers_close_ = val;
|
||||
}
|
||||
bool SignalCompletionWhenAllBrowsersClose() const {
|
||||
return signal_completion_when_all_browsers_close_;
|
||||
}
|
||||
|
||||
// Signal that the test is complete. This will be called automatically when
|
||||
// all existing non-popup browsers are closed if
|
||||
// |signal_completion_when_all_browsers_close_| is true (default value). It
|
||||
// is an error to call this method before all browsers have closed.
|
||||
void TestComplete();
|
||||
|
||||
private:
|
||||
// The child browser window
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
||||
// The browser window identifier
|
||||
int browser_id_;
|
||||
|
||||
// Used to notify when the test is complete
|
||||
// Used to notify when the test is complete. Can be accessed on any thread.
|
||||
CompletionState* completion_state_;
|
||||
bool completion_state_owned_;
|
||||
|
||||
// Map of resources that can be automatically loaded
|
||||
// Map browser ID to browser object for non-popup browsers. Only accessed on
|
||||
// the UI thread.
|
||||
BrowserMap browser_map_;
|
||||
|
||||
// Values for the first created browser. Modified on the UI thread but can be
|
||||
// accessed on any thread.
|
||||
int first_browser_id_;
|
||||
CefRefPtr<CefBrowser> first_browser_;
|
||||
|
||||
// Map of resources that can be automatically loaded. Only accessed on the
|
||||
// IO thread.
|
||||
typedef std::map<std::string, std::pair<std::string, std::string> >
|
||||
ResourceMap;
|
||||
ResourceMap resource_map_;
|
||||
|
||||
// If true test completion will be signaled when all browsers have closed.
|
||||
bool signal_completion_when_all_browsers_close_;
|
||||
|
||||
// Include the default reference counting implementation.
|
||||
IMPLEMENT_REFCOUNTING(TestHandler);
|
||||
// Include the default locking implementation.
|
||||
IMPLEMENT_LOCKING(TestHandler);
|
||||
|
||||
// Used to track the number of currently existing browser windows.
|
||||
static int browser_count_;
|
||||
@@ -215,4 +243,8 @@ void WaitForThread(CefRefPtr<CefTaskRunner> task_runner);
|
||||
// Returns true if the currently running test has failed.
|
||||
bool TestFailed();
|
||||
|
||||
#define EXPECT_UI_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
#define EXPECT_IO_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
#define EXPECT_RENDERER_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
#endif // CEF_TESTS_UNITTESTS_TEST_HANDLER_H_
|
||||
|
Reference in New Issue
Block a user