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:
Marshall Greenblatt
2014-01-27 23:31:03 +00:00
parent 78bfefee5e
commit 0df95ca529
33 changed files with 6023 additions and 597 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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.