Commit b8737917 authored by dmichael's avatar dmichael Committed by Commit bot

PPAPI: Add C++ wrapper for MessageHandler stuff.

BUG=367896

Review URL: https://codereview.chromium.org/318763003

Cr-Commit-Position: refs/heads/master@{#295495}
parent 54f98657
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
'logging.h', 'logging.h',
'media_stream_audio_track.h', 'media_stream_audio_track.h',
'media_stream_video_track.h', 'media_stream_video_track.h',
'message_handler.h',
'message_loop.h', 'message_loop.h',
'module_embedder.h', 'module_embedder.h',
'module.h', 'module.h',
......
...@@ -32,7 +32,7 @@ interface PPP_MessageHandler { ...@@ -32,7 +32,7 @@ interface PPP_MessageHandler {
* @param[in] instance A <code>PP_Instance</code> identifying one instance * @param[in] instance A <code>PP_Instance</code> identifying one instance
* of a module. * of a module.
* @param[in] user_data is the same pointer which was provided by a call to * @param[in] user_data is the same pointer which was provided by a call to
* RegisterMessageHandler. * RegisterMessageHandler().
* @param[in] message A copy of the parameter that JavaScript provided to * @param[in] message A copy of the parameter that JavaScript provided to
* postMessage(). * postMessage().
*/ */
...@@ -43,14 +43,19 @@ interface PPP_MessageHandler { ...@@ -43,14 +43,19 @@ interface PPP_MessageHandler {
* Invoked as a result of JavaScript invoking postMessageAndAwaitResponse() * Invoked as a result of JavaScript invoking postMessageAndAwaitResponse()
* on the plugin's DOM element. * on the plugin's DOM element.
* *
* NOTE: JavaScript execution is blocked during the duration of this call.
* Hence, the plugin should respond as quickly as possible. For this reason,
* blocking completion callbacks are disallowed while handling a blocking
* message.
*
* @param[in] instance A <code>PP_Instance</code> identifying one instance * @param[in] instance A <code>PP_Instance</code> identifying one instance
* of a module. * of a module.
* @param[in] user_data is the same pointer which was provided by a call to * @param[in] user_data is the same pointer which was provided by a call to
* RegisterMessageHandler. * RegisterMessageHandler().
* @param[in] message is a copy of the parameter that JavaScript provided * @param[in] message is a copy of the parameter that JavaScript provided
* to postMessageAndAwaitResponse. * to postMessageAndAwaitResponse().
* @param[out] response will be copied to a JavaScript object which is * @param[out] response will be copied to a JavaScript object which is
* returned as the result of postMessageAndAwaitResponse to the invoking * returned as the result of postMessageAndAwaitResponse() to the invoking
JavaScript. JavaScript.
*/ */
void HandleBlockingMessage([in] PP_Instance instance, void HandleBlockingMessage([in] PP_Instance instance,
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
/* From ppp_message_handler.idl modified Wed Sep 10 17:04:21 2014. */ /* From ppp_message_handler.idl modified Wed Sep 17 16:54:35 2014. */
#ifndef PPAPI_C_PPP_MESSAGE_HANDLER_H_ #ifndef PPAPI_C_PPP_MESSAGE_HANDLER_H_
#define PPAPI_C_PPP_MESSAGE_HANDLER_H_ #define PPAPI_C_PPP_MESSAGE_HANDLER_H_
...@@ -44,7 +44,7 @@ struct PPP_MessageHandler_0_2 { /* dev */ ...@@ -44,7 +44,7 @@ struct PPP_MessageHandler_0_2 { /* dev */
* @param[in] instance A <code>PP_Instance</code> identifying one instance * @param[in] instance A <code>PP_Instance</code> identifying one instance
* of a module. * of a module.
* @param[in] user_data is the same pointer which was provided by a call to * @param[in] user_data is the same pointer which was provided by a call to
* RegisterMessageHandler. * RegisterMessageHandler().
* @param[in] message A copy of the parameter that JavaScript provided to * @param[in] message A copy of the parameter that JavaScript provided to
* postMessage(). * postMessage().
*/ */
...@@ -55,14 +55,19 @@ struct PPP_MessageHandler_0_2 { /* dev */ ...@@ -55,14 +55,19 @@ struct PPP_MessageHandler_0_2 { /* dev */
* Invoked as a result of JavaScript invoking postMessageAndAwaitResponse() * Invoked as a result of JavaScript invoking postMessageAndAwaitResponse()
* on the plugin's DOM element. * on the plugin's DOM element.
* *
* NOTE: JavaScript execution is blocked during the duration of this call.
* Hence, the plugin should respond as quickly as possible. For this reason,
* blocking completion callbacks are disallowed while handling a blocking
* message.
*
* @param[in] instance A <code>PP_Instance</code> identifying one instance * @param[in] instance A <code>PP_Instance</code> identifying one instance
* of a module. * of a module.
* @param[in] user_data is the same pointer which was provided by a call to * @param[in] user_data is the same pointer which was provided by a call to
* RegisterMessageHandler. * RegisterMessageHandler().
* @param[in] message is a copy of the parameter that JavaScript provided * @param[in] message is a copy of the parameter that JavaScript provided
* to postMessageAndAwaitResponse. * to postMessageAndAwaitResponse().
* @param[out] response will be copied to a JavaScript object which is * @param[out] response will be copied to a JavaScript object which is
* returned as the result of postMessageAndAwaitResponse to the invoking * returned as the result of postMessageAndAwaitResponse() to the invoking
* *
*/ */
void (*HandleBlockingMessage)(PP_Instance instance, void (*HandleBlockingMessage)(PP_Instance instance,
......
...@@ -9,12 +9,15 @@ ...@@ -9,12 +9,15 @@
#include "ppapi/c/ppb_input_event.h" #include "ppapi/c/ppb_input_event.h"
#include "ppapi/c/ppb_instance.h" #include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_messaging.h" #include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/ppp_message_handler.h"
#include "ppapi/cpp/compositor.h" #include "ppapi/cpp/compositor.h"
#include "ppapi/cpp/graphics_2d.h" #include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/graphics_3d.h" #include "ppapi/cpp/graphics_3d.h"
#include "ppapi/cpp/image_data.h" #include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/instance_handle.h" #include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/logging.h" #include "ppapi/cpp/logging.h"
#include "ppapi/cpp/message_handler.h"
#include "ppapi/cpp/message_loop.h"
#include "ppapi/cpp/module.h" #include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h" #include "ppapi/cpp/module_impl.h"
#include "ppapi/cpp/point.h" #include "ppapi/cpp/point.h"
...@@ -42,6 +45,38 @@ template <> const char* interface_name<PPB_Messaging_1_0>() { ...@@ -42,6 +45,38 @@ template <> const char* interface_name<PPB_Messaging_1_0>() {
return PPB_MESSAGING_INTERFACE_1_0; return PPB_MESSAGING_INTERFACE_1_0;
} }
template <> const char* interface_name<PPB_Messaging_1_2>() {
return PPB_MESSAGING_INTERFACE_1_2;
}
// PPP_MessageHandler implementation -------------------------------------------
void HandleMessage(PP_Instance pp_instance,
void* user_data,
const PP_Var* var) {
MessageHandler* message_handler = static_cast<MessageHandler*>(user_data);
message_handler->HandleMessage(InstanceHandle(pp_instance), Var(*var));
}
void HandleBlockingMessage(PP_Instance pp_instance,
void* user_data,
const PP_Var* var,
PP_Var* result) {
MessageHandler* message_handler = static_cast<MessageHandler*>(user_data);
pp::Var result_var =
message_handler->HandleBlockingMessage(InstanceHandle(pp_instance),
Var(*var));
*result = result_var.Detach();
}
void Destroy(PP_Instance pp_instance, void* user_data) {
MessageHandler* message_handler = static_cast<MessageHandler*>(user_data);
message_handler->WasUnregistered(InstanceHandle(pp_instance));
}
static PPP_MessageHandler_0_2 message_handler_if = {
&HandleMessage, &HandleBlockingMessage, &Destroy
};
} // namespace } // namespace
Instance::Instance(PP_Instance instance) : pp_instance_(instance) { Instance::Instance(PP_Instance instance) : pp_instance_(instance) {
...@@ -130,10 +165,30 @@ void Instance::ClearInputEventRequest(uint32_t event_classes) { ...@@ -130,10 +165,30 @@ void Instance::ClearInputEventRequest(uint32_t event_classes) {
} }
void Instance::PostMessage(const Var& message) { void Instance::PostMessage(const Var& message) {
if (!has_interface<PPB_Messaging_1_0>()) if (has_interface<PPB_Messaging_1_2>()) {
get_interface<PPB_Messaging_1_2>()->PostMessage(pp_instance(),
message.pp_var());
} else if (has_interface<PPB_Messaging_1_0>()) {
get_interface<PPB_Messaging_1_0>()->PostMessage(pp_instance(),
message.pp_var());
}
}
int32_t Instance::RegisterMessageHandler(MessageHandler* message_handler,
const MessageLoop& message_loop) {
if (!has_interface<PPB_Messaging_1_2>())
return PP_ERROR_NOTSUPPORTED;
return get_interface<PPB_Messaging_1_2>()->RegisterMessageHandler(
pp_instance(),
message_handler,
&message_handler_if,
message_loop.pp_resource());
}
void Instance::UnregisterMessageHandler() {
if (!has_interface<PPB_Messaging_1_2>())
return; return;
get_interface<PPB_Messaging_1_0>()->PostMessage(pp_instance(), get_interface<PPB_Messaging_1_2>()->UnregisterMessageHandler(pp_instance());
message.pp_var());
} }
void Instance::LogToConsole(PP_LogLevel level, const Var& value) { void Instance::LogToConsole(PP_LogLevel level, const Var& value) {
......
...@@ -33,6 +33,8 @@ class Graphics2D; ...@@ -33,6 +33,8 @@ class Graphics2D;
class Graphics3D; class Graphics3D;
class InputEvent; class InputEvent;
class InstanceHandle; class InstanceHandle;
class MessageHandler;
class MessageLoop;
class Rect; class Rect;
class URLLoader; class URLLoader;
class Var; class Var;
...@@ -495,6 +497,55 @@ class Instance { ...@@ -495,6 +497,55 @@ class Instance {
/// All var types are copied when passing them to JavaScript. /// All var types are copied when passing them to JavaScript.
void PostMessage(const Var& message); void PostMessage(const Var& message);
/// Dev-Channel Only
///
/// Registers a handler for receiving messages from JavaScript. If a handler
/// is registered this way, it will replace the Instance's HandleMessage
/// method, and all messages sent from JavaScript via postMessage and
/// postMessageAndAwaitResponse will be dispatched to
/// <code>message_handler</code>.
///
/// The function calls will be dispatched via <code>message_loop</code>. This
/// means that the functions will be invoked on the thread to which
/// <code>message_loop</code> is attached, when <code>message_loop</code> is
/// run. It is illegal to pass the main thread message loop;
/// RegisterMessageHandler will return PP_ERROR_WRONG_THREAD in that case.
/// If you quit <code>message_loop</code> before calling Unregister(),
/// the browser will not be able to call functions in the plugin's message
/// handler any more. That could mean missing some messages or could cause a
/// leak if you depend on Destroy() to free hander data. So you should,
/// whenever possible, Unregister() the handler prior to quitting its event
/// loop.
///
/// Attempting to register a message handler when one is already registered
/// will cause the current MessageHandler to be unregistered and replaced. In
/// that case, no messages will be sent to the "default" message handler
/// (pp::Instance::HandleMessage()). Messages will stop arriving at the prior
/// message handler and will begin to be dispatched at the new message
/// handler.
///
/// @param[in] message_handler The plugin-provided object for handling
/// messages. The instance does not take ownership of the pointer; it is up
/// to the plugin to ensure that |message_handler| lives until its
/// WasUnregistered() function is invoked.
/// @param[in] message_loop Represents the message loop on which
/// MessageHandler's functions should be invoked.
/// @return PP_OK on success, or an error from pp_errors.h.
int32_t RegisterMessageHandler(MessageHandler* message_handler,
const MessageLoop& message_loop);
/// Unregisters the current message handler for this instance if one is
/// registered. After this call, the message handler (if one was
/// registered) will have "WasUnregistered" called on it and will receive no
/// further messages. After that point, all messages sent from JavaScript
/// using postMessage() will be dispatched to pp::Instance::HandleMessage()
/// on the main thread. Attempts to call postMessageAndAwaitResponse() from
/// JavaScript after that point will fail.
///
/// Attempting to unregister a message handler when none is registered has no
/// effect.
void UnregisterMessageHandler();
/// @} /// @}
/// @{ /// @{
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PPAPI_CPP_MESSAGE_HANDLER_H_
#define PPAPI_CPP_MESSAGE_HANDLER_H_
namespace pp {
/// <code>MessageHandler</code> is an abstract base class that the plugin may
/// implement if it wants to receive messages from JavaScript on a background
/// thread when JavaScript invokes postMessage() or
/// postMessageAndAwaitResponse(). See pp::Instance::RegisterMessageHandler()
/// for usage.
class MessageHandler {
public:
virtual ~MessageHandler() {};
/// Invoked as a result of JavaScript invoking postMessage() on the plugin's
/// DOM element.
///
/// @param[in] instance An <code>InstanceHandle</code> identifying one
/// instance of a module.
/// @param[in] message_data A copy of the parameter that JavaScript provided
/// to postMessage().
virtual void HandleMessage(pp::InstanceHandle instance,
const Var& message_data) = 0;
/// Invoked as a result of JavaScript invoking postMessageAndAwaitResponse()
/// on the plugin's DOM element.
///
/// NOTE: JavaScript execution is blocked during the duration of this call.
/// Hence, the plugin should respond as quickly as possible. For this reason,
/// blocking completion callbacks are disallowed while handling a blocking
/// message.
///
/// @param[in] instance An <code>InstanceHandle</code> identifying one
/// instance of a module.
/// @param[in] message_data A copy of the parameter that JavaScript provided
/// to postMessage().
/// @return Returns a pp::Var that is then copied to a JavaScript object
/// which is returned as the result of JavaScript's call of
/// postMessageAndAwaitResponse().
virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance,
const Var& message_data) = 0;
/// Invoked when this MessageHandler is no longer needed. After this, no more
/// calls will be made to this object.
///
/// @param[in] instance An <code>InstanceHandle</code> identifying one
/// instance of a module.
virtual void WasUnregistered(pp::InstanceHandle instance) = 0;
};
} // namespace pp
#endif // PPAPI_CPP_MESSAGE_HANDLER_H_
...@@ -197,6 +197,7 @@ ...@@ -197,6 +197,7 @@
'cpp/media_stream_audio_track.h', 'cpp/media_stream_audio_track.h',
'cpp/media_stream_video_track.cc', 'cpp/media_stream_video_track.cc',
'cpp/media_stream_video_track.h', 'cpp/media_stream_video_track.h',
'cpp/message_handler.h',
'cpp/message_loop.cc', 'cpp/message_loop.cc',
'cpp/message_loop.h', 'cpp/message_loop.h',
'cpp/module.cc', 'cpp/module.cc',
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ppapi/cpp/file_ref.h" #include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/file_system.h" #include "ppapi/cpp/file_system.h"
#include "ppapi/cpp/instance.h" #include "ppapi/cpp/instance.h"
#include "ppapi/cpp/message_handler.h"
#include "ppapi/cpp/module_impl.h" #include "ppapi/cpp/module_impl.h"
#include "ppapi/cpp/var.h" #include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array.h" #include "ppapi/cpp/var_array.h"
...@@ -38,32 +39,22 @@ namespace { ...@@ -38,32 +39,22 @@ namespace {
// Created and destroyed on the main thread. All public methods should be called // Created and destroyed on the main thread. All public methods should be called
// on the main thread. Most data members are only accessed on the main thread. // on the main thread. Most data members are only accessed on the main thread.
// (Though it handles messages on the background thread). // (Though it handles messages on the background thread).
class EchoingMessageHandler { class EchoingMessageHandler : public pp::MessageHandler {
public: public:
explicit EchoingMessageHandler(PP_Instance instance, explicit EchoingMessageHandler(TestingInstance* instance,
const pp::MessageLoop& loop) const pp::MessageLoop& loop)
: pp_instance_(instance), : testing_instance_(instance),
message_handler_loop_(loop), message_handler_loop_(loop),
ppb_messaging_if_(static_cast<const PPB_Messaging_1_2*>(
pp::Module::Get()->GetBrowserInterface(
PPB_MESSAGING_INTERFACE_1_2))),
ppp_message_handler_if_(),
is_registered_(false), is_registered_(false),
test_finished_event_(instance), test_finished_event_(instance->pp_instance()),
destroy_event_(instance) { destroy_event_(instance->pp_instance()) {
AssertOnMainThread(); AssertOnMainThread();
ppp_message_handler_if_.HandleMessage = &HandleMessage;
ppp_message_handler_if_.HandleBlockingMessage = &HandleBlockingMessage;
ppp_message_handler_if_.Destroy = &Destroy;
} }
void Register() { void Register() {
AssertOnMainThread(); AssertOnMainThread();
assert(!is_registered_); assert(!is_registered_);
int32_t result = ppb_messaging_if_->RegisterMessageHandler( int32_t result =
pp_instance_, testing_instance_->RegisterMessageHandler(this, message_handler_loop_);
this,
&ppp_message_handler_if_,
message_handler_loop_.pp_resource());
if (result == PP_OK) { if (result == PP_OK) {
is_registered_ = true; is_registered_ = true;
} else { } else {
...@@ -78,7 +69,7 @@ class EchoingMessageHandler { ...@@ -78,7 +69,7 @@ class EchoingMessageHandler {
void Unregister() { void Unregister() {
AssertOnMainThread(); AssertOnMainThread();
assert(is_registered_); assert(is_registered_);
ppb_messaging_if_->UnregisterMessageHandler(pp_instance_); testing_instance_->UnregisterMessageHandler();
is_registered_ = false; is_registered_ = false;
} }
void WaitForTestFinishedMessage() { void WaitForTestFinishedMessage() {
...@@ -113,63 +104,42 @@ class EchoingMessageHandler { ...@@ -113,63 +104,42 @@ class EchoingMessageHandler {
errors_ += error; errors_ += error;
} }
} }
static void HandleMessage(PP_Instance instance, virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) {
void* user_data, if (pp::MessageLoop::GetCurrent() != message_handler_loop_)
const PP_Var* message_data) { AddError("HandleMessage was called on the wrong thread!");
EchoingMessageHandler* thiz = if (instance.pp_instance() != testing_instance_->pp_instance())
static_cast<EchoingMessageHandler*>(user_data); AddError("HandleMessage was passed the wrong instance!");
if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
thiz->AddError("HandleMessage was called on the wrong thread!");
if (instance != thiz->pp_instance_)
thiz->AddError("HandleMessage was passed the wrong instance!");
pp::Var var(*message_data);
if (var.is_string() && var.AsString() == "FINISHED_TEST") if (var.is_string() && var.AsString() == "FINISHED_TEST")
thiz->test_finished_event_.Signal(); test_finished_event_.Signal();
else else
thiz->ppb_messaging_if_->PostMessage(instance, *message_data); testing_instance_->PostMessage(var);
} }
static void HandleBlockingMessage(PP_Instance instance, virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance,
void* user_data, const pp::Var& var) {
const PP_Var* message_data, if (pp::MessageLoop::GetCurrent() != message_handler_loop_)
PP_Var* result) { AddError("HandleBlockingMessage was called on the wrong thread!");
EchoingMessageHandler* thiz = if (instance.pp_instance() != testing_instance_->pp_instance())
static_cast<EchoingMessageHandler*>(user_data); AddError("HandleBlockingMessage was passed the wrong instance!");
if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
thiz->AddError("HandleBlockingMessage was called on the wrong thread!");
if (instance != thiz->pp_instance_)
thiz->AddError("HandleBlockingMessage was passed the wrong instance!");
// The PP_Var we are passed is an in-parameter, so the browser is not return var;
// giving us a ref-count. The ref-count it has will be decremented after we
// return. But we need to add a ref when returning a PP_Var, to pass to the
// caller.
pp::Var take_ref(*message_data);
take_ref.Detach();
*result = *message_data;
} }
static void Destroy(PP_Instance instance, void* user_data) { virtual void WasUnregistered(pp::InstanceHandle instance) {
EchoingMessageHandler* thiz = if (pp::MessageLoop::GetCurrent() != message_handler_loop_)
static_cast<EchoingMessageHandler*>(user_data); AddError("Destroy was called on the wrong thread!");
if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_) if (instance.pp_instance() != testing_instance_->pp_instance())
thiz->AddError("Destroy was called on the wrong thread!"); AddError("Destroy was passed the wrong instance!");
if (instance != thiz->pp_instance_) destroy_event_.Signal();
thiz->AddError("Destroy was passed the wrong instance!");
thiz->destroy_event_.Signal();
} }
// These data members are initialized on the main thread, but don't change for // These data members are initialized on the main thread, but don't change for
// the life of the object, so are safe to access on the background thread, // the life of the object, so are safe to access on the background thread,
// because there will be a memory barrier before the the MessageHandler calls // because there will be a memory barrier before the the MessageHandler calls
// are invoked. // are invoked.
const PP_Instance pp_instance_; TestingInstance* const testing_instance_;
const pp::MessageLoop message_handler_loop_; const pp::MessageLoop message_handler_loop_;
const pp::MessageLoop main_loop_; const pp::MessageLoop main_loop_;
const PPB_Messaging_1_2* const ppb_messaging_if_;
// Spiritually, this member is const, but we can't initialize it in C++03,
// so it has to be non-const to be set in the constructor body.
PPP_MessageHandler_0_2 ppp_message_handler_if_;
// is_registered_ is only read/written on the main thread. // is_registered_ is only read/written on the main thread.
bool is_registered_; bool is_registered_;
...@@ -258,7 +228,7 @@ std::string TestMessageHandler::TestRegisterErrorConditions() { ...@@ -258,7 +228,7 @@ std::string TestMessageHandler::TestRegisterErrorConditions() {
} }
std::string TestMessageHandler::TestPostMessageAndAwaitResponse() { std::string TestMessageHandler::TestPostMessageAndAwaitResponse() {
EchoingMessageHandler handler(instance()->pp_instance(), EchoingMessageHandler handler(instance(),
handler_thread_.message_loop()); handler_thread_.message_loop());
handler.Register(); handler.Register();
std::string js_code("var plugin = document.getElementById('plugin');\n"); std::string js_code("var plugin = document.getElementById('plugin');\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment