diff options
author | dmichael <dmichael@chromium.org> | 2014-09-18 11:00:29 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-18 18:00:46 +0000 |
commit | b8737917043275c52ae682cddc6604c495d2e73f (patch) | |
tree | e9e333fe6377a717160e4cf52b15393c85e07db6 /ppapi | |
parent | 54f98657d48d67fdb4d0097e7a9f906cc52f9378 (diff) | |
download | chromium_src-b8737917043275c52ae682cddc6604c495d2e73f.zip chromium_src-b8737917043275c52ae682cddc6604c495d2e73f.tar.gz chromium_src-b8737917043275c52ae682cddc6604c495d2e73f.tar.bz2 |
PPAPI: Add C++ wrapper for MessageHandler stuff.
BUG=367896
Review URL: https://codereview.chromium.org/318763003
Cr-Commit-Position: refs/heads/master@{#295495}
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/api/ppp_message_handler.idl | 13 | ||||
-rw-r--r-- | ppapi/c/ppp_message_handler.h | 15 | ||||
-rw-r--r-- | ppapi/cpp/instance.cc | 61 | ||||
-rw-r--r-- | ppapi/cpp/instance.h | 51 | ||||
-rw-r--r-- | ppapi/cpp/message_handler.h | 57 | ||||
-rw-r--r-- | ppapi/ppapi_sources.gypi | 1 | ||||
-rw-r--r-- | ppapi/tests/test_message_handler.cc | 92 |
7 files changed, 217 insertions, 73 deletions
diff --git a/ppapi/api/ppp_message_handler.idl b/ppapi/api/ppp_message_handler.idl index e898f0b..7d76040 100644 --- a/ppapi/api/ppp_message_handler.idl +++ b/ppapi/api/ppp_message_handler.idl @@ -32,7 +32,7 @@ interface PPP_MessageHandler { * @param[in] instance A <code>PP_Instance</code> identifying one instance * of a module. * @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 * postMessage(). */ @@ -43,14 +43,19 @@ interface PPP_MessageHandler { * 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 A <code>PP_Instance</code> identifying one instance * of a module. * @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 - * to postMessageAndAwaitResponse. + * to postMessageAndAwaitResponse(). * @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. */ void HandleBlockingMessage([in] PP_Instance instance, diff --git a/ppapi/c/ppp_message_handler.h b/ppapi/c/ppp_message_handler.h index 2b1a0db..b73ecb7 100644 --- a/ppapi/c/ppp_message_handler.h +++ b/ppapi/c/ppp_message_handler.h @@ -3,7 +3,7 @@ * 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_ #define PPAPI_C_PPP_MESSAGE_HANDLER_H_ @@ -44,7 +44,7 @@ struct PPP_MessageHandler_0_2 { /* dev */ * @param[in] instance A <code>PP_Instance</code> identifying one instance * of a module. * @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 * postMessage(). */ @@ -55,14 +55,19 @@ struct PPP_MessageHandler_0_2 { /* dev */ * 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 A <code>PP_Instance</code> identifying one instance * of a module. * @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 - * to postMessageAndAwaitResponse. + * to postMessageAndAwaitResponse(). * @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, diff --git a/ppapi/cpp/instance.cc b/ppapi/cpp/instance.cc index a5be2b9..74b9321 100644 --- a/ppapi/cpp/instance.cc +++ b/ppapi/cpp/instance.cc @@ -9,12 +9,15 @@ #include "ppapi/c/ppb_input_event.h" #include "ppapi/c/ppb_instance.h" #include "ppapi/c/ppb_messaging.h" +#include "ppapi/c/ppp_message_handler.h" #include "ppapi/cpp/compositor.h" #include "ppapi/cpp/graphics_2d.h" #include "ppapi/cpp/graphics_3d.h" #include "ppapi/cpp/image_data.h" #include "ppapi/cpp/instance_handle.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_impl.h" #include "ppapi/cpp/point.h" @@ -42,6 +45,38 @@ template <> const char* interface_name<PPB_Messaging_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 Instance::Instance(PP_Instance instance) : pp_instance_(instance) { @@ -130,10 +165,30 @@ void Instance::ClearInputEventRequest(uint32_t event_classes) { } 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; - get_interface<PPB_Messaging_1_0>()->PostMessage(pp_instance(), - message.pp_var()); + get_interface<PPB_Messaging_1_2>()->UnregisterMessageHandler(pp_instance()); } void Instance::LogToConsole(PP_LogLevel level, const Var& value) { diff --git a/ppapi/cpp/instance.h b/ppapi/cpp/instance.h index af024db..9bc16fb 100644 --- a/ppapi/cpp/instance.h +++ b/ppapi/cpp/instance.h @@ -33,6 +33,8 @@ class Graphics2D; class Graphics3D; class InputEvent; class InstanceHandle; +class MessageHandler; +class MessageLoop; class Rect; class URLLoader; class Var; @@ -495,6 +497,55 @@ class Instance { /// All var types are copied when passing them to JavaScript. 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(); + /// @} /// @{ diff --git a/ppapi/cpp/message_handler.h b/ppapi/cpp/message_handler.h new file mode 100644 index 0000000..0bb6ad8 --- /dev/null +++ b/ppapi/cpp/message_handler.h @@ -0,0 +1,57 @@ +// 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_ diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index 10f2d16..105ae4f 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -197,6 +197,7 @@ 'cpp/media_stream_audio_track.h', 'cpp/media_stream_video_track.cc', 'cpp/media_stream_video_track.h', + 'cpp/message_handler.h', 'cpp/message_loop.cc', 'cpp/message_loop.h', 'cpp/module.cc', diff --git a/ppapi/tests/test_message_handler.cc b/ppapi/tests/test_message_handler.cc index 5b59f7d..c5c8354 100644 --- a/ppapi/tests/test_message_handler.cc +++ b/ppapi/tests/test_message_handler.cc @@ -17,6 +17,7 @@ #include "ppapi/cpp/file_ref.h" #include "ppapi/cpp/file_system.h" #include "ppapi/cpp/instance.h" +#include "ppapi/cpp/message_handler.h" #include "ppapi/cpp/module_impl.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/var_array.h" @@ -38,32 +39,22 @@ namespace { // 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. // (Though it handles messages on the background thread). -class EchoingMessageHandler { +class EchoingMessageHandler : public pp::MessageHandler { public: - explicit EchoingMessageHandler(PP_Instance instance, + explicit EchoingMessageHandler(TestingInstance* instance, const pp::MessageLoop& loop) - : pp_instance_(instance), + : testing_instance_(instance), 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), - test_finished_event_(instance), - destroy_event_(instance) { + test_finished_event_(instance->pp_instance()), + destroy_event_(instance->pp_instance()) { AssertOnMainThread(); - ppp_message_handler_if_.HandleMessage = &HandleMessage; - ppp_message_handler_if_.HandleBlockingMessage = &HandleBlockingMessage; - ppp_message_handler_if_.Destroy = &Destroy; } void Register() { AssertOnMainThread(); assert(!is_registered_); - int32_t result = ppb_messaging_if_->RegisterMessageHandler( - pp_instance_, - this, - &ppp_message_handler_if_, - message_handler_loop_.pp_resource()); + int32_t result = + testing_instance_->RegisterMessageHandler(this, message_handler_loop_); if (result == PP_OK) { is_registered_ = true; } else { @@ -78,7 +69,7 @@ class EchoingMessageHandler { void Unregister() { AssertOnMainThread(); assert(is_registered_); - ppb_messaging_if_->UnregisterMessageHandler(pp_instance_); + testing_instance_->UnregisterMessageHandler(); is_registered_ = false; } void WaitForTestFinishedMessage() { @@ -113,63 +104,42 @@ class EchoingMessageHandler { errors_ += error; } } - static void HandleMessage(PP_Instance instance, - void* user_data, - const PP_Var* message_data) { - EchoingMessageHandler* thiz = - static_cast<EchoingMessageHandler*>(user_data); - 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); + virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { + if (pp::MessageLoop::GetCurrent() != message_handler_loop_) + AddError("HandleMessage was called on the wrong thread!"); + if (instance.pp_instance() != testing_instance_->pp_instance()) + AddError("HandleMessage was passed the wrong instance!"); if (var.is_string() && var.AsString() == "FINISHED_TEST") - thiz->test_finished_event_.Signal(); + test_finished_event_.Signal(); else - thiz->ppb_messaging_if_->PostMessage(instance, *message_data); + testing_instance_->PostMessage(var); } - static void HandleBlockingMessage(PP_Instance instance, - void* user_data, - const PP_Var* message_data, - PP_Var* result) { - EchoingMessageHandler* thiz = - static_cast<EchoingMessageHandler*>(user_data); - 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!"); + virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, + const pp::Var& var) { + if (pp::MessageLoop::GetCurrent() != message_handler_loop_) + AddError("HandleBlockingMessage was called on the wrong thread!"); + if (instance.pp_instance() != testing_instance_->pp_instance()) + AddError("HandleBlockingMessage was passed the wrong instance!"); - // The PP_Var we are passed is an in-parameter, so the browser is not - // 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; + return var; } - static void Destroy(PP_Instance instance, void* user_data) { - EchoingMessageHandler* thiz = - static_cast<EchoingMessageHandler*>(user_data); - if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_) - thiz->AddError("Destroy was called on the wrong thread!"); - if (instance != thiz->pp_instance_) - thiz->AddError("Destroy was passed the wrong instance!"); - thiz->destroy_event_.Signal(); + virtual void WasUnregistered(pp::InstanceHandle instance) { + if (pp::MessageLoop::GetCurrent() != message_handler_loop_) + AddError("Destroy was called on the wrong thread!"); + if (instance.pp_instance() != testing_instance_->pp_instance()) + AddError("Destroy was passed the wrong instance!"); + destroy_event_.Signal(); } // 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, // because there will be a memory barrier before the the MessageHandler calls // are invoked. - const PP_Instance pp_instance_; + TestingInstance* const testing_instance_; const pp::MessageLoop message_handler_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. bool is_registered_; @@ -258,7 +228,7 @@ std::string TestMessageHandler::TestRegisterErrorConditions() { } std::string TestMessageHandler::TestPostMessageAndAwaitResponse() { - EchoingMessageHandler handler(instance()->pp_instance(), + EchoingMessageHandler handler(instance(), handler_thread_.message_loop()); handler.Register(); std::string js_code("var plugin = document.getElementById('plugin');\n"); |