summaryrefslogtreecommitdiffstats
path: root/webkit/plugins/ppapi
diff options
context:
space:
mode:
authordmichael@google.com <dmichael@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-23 21:07:15 +0000
committerdmichael@google.com <dmichael@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-23 21:07:15 +0000
commit9888f134c655a95c5922c980eb59d3337341d653 (patch)
tree8ec7b6849cd94196df9bf3ee7810f6a838242e8d /webkit/plugins/ppapi
parent2752bf6a3120e172d216ab7bde42222a3ae4b5cb (diff)
downloadchromium_src-9888f134c655a95c5922c980eb59d3337341d653.zip
chromium_src-9888f134c655a95c5922c980eb59d3337341d653.tar.gz
chromium_src-9888f134c655a95c5922c980eb59d3337341d653.tar.bz2
A proposal and implementation for an initial postMessage interface. These interfaces will allow JavaScript to send data asynchronously to a module instance, and the module instance to asynchronously send data to a JavaScript message handler.
Note, I did something differently from other per-instance interfaces. While the C interface has 'PPB_Messaging' and 'PPP_Messaging' separate from the Instance interfaces, I stuck the per-instance messaging in to pp::Instance. It seems more intuitive to me, and doesn't have the drawbacks of having too many functions in the C layer instance interfaces. Happy to back off of that position, but it's worth a shot. Overview: From JavaScript, you can invoke 'postMessage' on the embedded module. That results in a call to 'PPP_Messaging::HandleMessage'. From Native Code, you can invoke 'PPB_Messaging::PostMessage', which results in a call to an 'onmessage' function on the DOM element for the module instance in the JavaScript code (if one has been registered). Please see the included example or the examples in the comments of PPB_Messaging and PPP_Messaging. Restrictions: - This implementation is synchronous. A later CL will make it asynchronous. - This implementation supports only intrinsic values and strings (all types that PP_Var supports except for objects). Object & array support will come later. - This implementation only allows for 1 channel per instance. You can not expose other 'channels' or 'ports'. Future CLs will add support for MessagePorts. BUG=None TEST=test_post_message.h/.cc (This CL replaces http://codereview.chromium.org/6538028/ ) Review URL: http://codereview.chromium.org/6716005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79178 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins/ppapi')
-rw-r--r--webkit/plugins/ppapi/message_channel.cc350
-rw-r--r--webkit/plugins/ppapi/message_channel.h93
-rw-r--r--webkit/plugins/ppapi/plugin_module.cc3
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.cc50
-rw-r--r--webkit/plugins/ppapi/ppapi_plugin_instance.h19
-rw-r--r--webkit/plugins/ppapi/ppapi_webplugin_impl.cc12
6 files changed, 522 insertions, 5 deletions
diff --git a/webkit/plugins/ppapi/message_channel.cc b/webkit/plugins/ppapi/message_channel.cc
new file mode 100644
index 0000000..9fdadca
--- /dev/null
+++ b/webkit/plugins/ppapi/message_channel.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/plugins/ppapi/message_channel.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "base/logging.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
+#include "webkit/plugins/ppapi/npapi_glue.h"
+#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
+#include "webkit/plugins/ppapi/var.h"
+
+using WebKit::WebBindings;
+
+namespace webkit {
+
+namespace ppapi {
+
+namespace {
+
+const char kPostMessage[] = "postMessage";
+
+// Helper function to get the MessageChannel that is associated with an
+// NPObject*.
+MessageChannel& ToMessageChannel(NPObject* object) {
+ return *(static_cast<MessageChannel::MessageChannelNPObject*>(object)->
+ message_channel);
+}
+
+// Helper function to determine if a given identifier is equal to kPostMessage.
+bool IdentifierIsPostMessage(NPIdentifier identifier) {
+ return WebBindings::getStringIdentifier(kPostMessage) == identifier;
+}
+
+// Converts the given PP_Var to an NPVariant, returning true on success.
+// False means that the given variant is invalid. In this case, the result
+// NPVariant will be set to a void one.
+//
+// The contents of the PP_Var will NOT be copied, so you need to ensure that
+// the PP_Var remains valid while the resultant NPVariant is in use.
+//
+// Note: This is largely copied from var.cc so that we don't depend on code
+// which will be removed. TODO(dmichael) remove this comment when var
+// is removed.
+bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
+ switch (var.type) {
+ case PP_VARTYPE_UNDEFINED:
+ VOID_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_NULL:
+ NULL_TO_NPVARIANT(*result);
+ break;
+ case PP_VARTYPE_BOOL:
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
+ break;
+ case PP_VARTYPE_INT32:
+ INT32_TO_NPVARIANT(var.value.as_int, *result);
+ break;
+ case PP_VARTYPE_DOUBLE:
+ DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
+ break;
+ case PP_VARTYPE_STRING: {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+ if (!string) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ const std::string& value = string->value();
+ STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
+ break;
+ }
+ case PP_VARTYPE_OBJECT:
+ // Objects are not currently supported.
+ DCHECK(false);
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ default:
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// Implementations of NPClass functions. These are here to:
+// - Implement postMessage behavior.
+// - Forward calls to the 'passthrough' object to allow backwards-compatibility
+// with GetInstanceObject() objects.
+//------------------------------------------------------------------------------
+NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) {
+ return new MessageChannel::MessageChannelNPObject;
+}
+
+void MessageChannelDeallocate(NPObject* object) {
+ MessageChannel::MessageChannelNPObject* instance =
+ static_cast<MessageChannel::MessageChannelNPObject*>(object);
+ delete instance;
+}
+
+bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ // We only handle a function called postMessage.
+ if (IdentifierIsPostMessage(name))
+ return true;
+
+ // Other method names we will pass to the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough)
+ return WebBindings::hasMethod(NULL, passthrough, name);
+ return false;
+}
+
+bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* args, uint32 arg_count,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // We only handle a function called postMessage.
+ if (IdentifierIsPostMessage(name) && (arg_count == 1)) {
+ MessageChannel& message_channel(ToMessageChannel(np_obj));
+ PP_Var argument(Var::NPVariantToPPVar(message_channel.instance(),
+ &args[0]));
+ message_channel.PostMessageToNative(argument);
+ return true;
+ }
+ // Other method calls we will pass to the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough) {
+ return WebBindings::invoke(NULL, passthrough, name, args, arg_count,
+ result);
+ }
+ return false;
+}
+
+bool MessageChannelInvokeDefault(NPObject* np_obj,
+ const NPVariant* args,
+ uint32 arg_count,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough) {
+ return WebBindings::invokeDefault(NULL, passthrough, args, arg_count,
+ result);
+ }
+ return false;
+}
+
+bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough)
+ return WebBindings::hasProperty(NULL, passthrough, name);
+ return false;
+}
+
+bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name,
+ NPVariant* result) {
+ if (!np_obj)
+ return false;
+
+ // Don't allow getting the postMessage function.
+ if (IdentifierIsPostMessage(name))
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough)
+ return WebBindings::getProperty(NULL, passthrough, name, result);
+ return false;
+}
+
+bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name,
+ const NPVariant* variant) {
+ if (!np_obj)
+ return false;
+
+ // Don't allow setting the postMessage function.
+ if (IdentifierIsPostMessage(name))
+ return false;
+
+ // Invoke on the passthrough object, if we have one.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough)
+ return WebBindings::setProperty(NULL, passthrough, name, variant);
+ return false;
+}
+
+bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value,
+ uint32_t *count) {
+ if (!np_obj)
+ return false;
+
+ // Invoke on the passthrough object, if we have one, to enumerate its
+ // properties.
+ NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object();
+ if (passthrough) {
+ bool success = WebBindings::enumerate(NULL, passthrough, value, count);
+ if (success) {
+ // Add postMessage to the list and return it.
+ NPIdentifier* new_array = static_cast<NPIdentifier*>(
+ std::malloc(sizeof(NPIdentifier) * (*count + 1)));
+ std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count));
+ new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
+ std::free(*value);
+ *value = new_array;
+ ++(*count);
+ return true;
+ }
+ }
+
+ // Otherwise, build an array that includes only postMessage.
+ *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier)));
+ (*value)[0] = WebBindings::getStringIdentifier(kPostMessage);
+ *count = 1;
+ return true;
+}
+
+NPClass message_channel_class = {
+ NP_CLASS_STRUCT_VERSION,
+ &MessageChannelAllocate,
+ &MessageChannelDeallocate,
+ NULL,
+ &MessageChannelHasMethod,
+ &MessageChannelInvoke,
+ &MessageChannelInvokeDefault,
+ &MessageChannelHasProperty,
+ &MessageChannelGetProperty,
+ &MessageChannelSetProperty,
+ NULL,
+ &MessageChannelEnumerate,
+};
+
+} // namespace
+
+// MessageChannel --------------------------------------------------------------
+MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {}
+
+MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
+
+MessageChannel::MessageChannel(PluginInstance* instance)
+ : instance_(instance),
+ passthrough_object_(NULL),
+ np_object_(NULL) {
+ VOID_TO_NPVARIANT(onmessage_invoker_);
+
+ // Now create an NPObject for receiving calls to postMessage.
+ NPObject* obj = WebBindings::createObject(NULL, &message_channel_class);
+ DCHECK(obj);
+ np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
+ np_object_->message_channel = this;
+}
+
+bool MessageChannel::EvaluateOnMessageInvoker() {
+ // If we've already evaluated the function, just return.
+ if (NPVARIANT_IS_OBJECT(onmessage_invoker_))
+ return true;
+
+ // This is the javascript code that we invoke. It checks to see if onmessage
+ // exists, and if so, it invokes it.
+ const char invoke_onmessage_js[] =
+ "(function(module_instance, message_data) {"
+ " if (module_instance &&" // Only invoke if the instance is valid and
+ " module_instance.onmessage &&" // has a function named onmessage.
+ " typeof(module_instance.onmessage) == 'function') {"
+ " var message_event = document.createEvent('MessageEvent');"
+ " message_event.initMessageEvent('message'," // type
+ " false," // canBubble
+ " false," // cancelable
+ " message_data," // data
+ " ''," // origin
+ " ''," // lastEventId
+ " module_instance," // source
+ " []);" // ports
+ " module_instance.onmessage(message_event);"
+ " }"
+ "})";
+ NPString function_string = { invoke_onmessage_js,
+ sizeof(invoke_onmessage_js)-1 };
+ // Get the current frame to pass to the evaluate function.
+ WebKit::WebFrame* frame =
+ instance_->container()->element().document().frame();
+ // Evaluate the function and obtain an NPVariant pointing to it.
+ if (!WebBindings::evaluate(NULL, frame->windowObject(), &function_string,
+ &onmessage_invoker_)) {
+ // If it fails, do nothing.
+ return false;
+ }
+ DCHECK(NPVARIANT_IS_OBJECT(onmessage_invoker_));
+ return true;
+}
+
+void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
+ // Make sure we have our function for invoking a JavaScript onmessage
+ // function.
+ bool success = EvaluateOnMessageInvoker();
+ DCHECK(success);
+ if (!success)
+ return;
+
+ DCHECK(instance_);
+
+ NPVariant result_var;
+ VOID_TO_NPVARIANT(result_var);
+ NPVariant npvariant_args[2];
+ OBJECT_TO_NPVARIANT(instance_->container()->scriptableObjectForElement(),
+ npvariant_args[0]);
+ // Convert message to an NPVariant without copying. Note this means that
+ // in-process plugins will not copy the data, so isn't really following the
+ // postMessage spec in spirit. Copying is handled in the proxy, and we don't
+ // want to re-copy unnecessarily.
+ //
+ // TODO(dmichael): We need to do structured clone eventually to copy a object
+ // structure. The details and PPAPI changes for this are TBD.
+ if (!PPVarToNPVariantNoCopy(message_data, &npvariant_args[1]))
+ return;
+
+ WebBindings::invokeDefault(NULL,
+ NPVARIANT_TO_OBJECT(onmessage_invoker_),
+ npvariant_args,
+ sizeof(npvariant_args)/sizeof(*npvariant_args),
+ &result_var);
+}
+
+void MessageChannel::PostMessageToNative(PP_Var message_data) {
+ instance_->HandleMessage(message_data);
+}
+
+MessageChannel::~MessageChannel() {
+ WebBindings::releaseVariantValue(&onmessage_invoker_);
+}
+
+} // namespace ppapi
+} // namespace webkit
+
diff --git a/webkit/plugins/ppapi/message_channel.h b/webkit/plugins/ppapi/message_channel.h
new file mode 100644
index 0000000..7d8b6f2
--- /dev/null
+++ b/webkit/plugins/ppapi/message_channel.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2011 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 WEBKIT_PLUGINS_PPAPI_MESSAGE_CHANNEL_H_
+#define WEBKIT_PLUGINS_PPAPI_MESSAGE_CHANNEL_H_
+
+#include "third_party/npapi/bindings/npruntime.h"
+#include "webkit/plugins/ppapi/resource.h"
+
+struct PP_Var;
+
+namespace webkit {
+namespace ppapi {
+
+class PluginInstance;
+
+// MessageChannel implements bidirectional postMessage functionality, allowing
+// calls from JavaScript to plugins and vice-versa. See
+// PPB_Instance::PostMessage and PPP_Instance::HandleMessage for more
+// information.
+//
+// Currently, only 1 MessageChannel can exist, to implement postMessage
+// functionality for the instance interfaces. In the future, when we create a
+// MessagePort type in PPAPI, those may be implemented here as well with some
+// refactoring.
+// - Separate message ports won't require the passthrough object.
+// - The message target won't be limited to instance, and should support
+// either plugin-provided or JS objects.
+// TODO(dmichael): Add support for separate MessagePorts.
+class MessageChannel {
+ public:
+ // MessageChannelNPObject is a simple struct that adds a pointer back to a
+ // MessageChannel instance. This way, we can use an NPObject to allow
+ // JavaScript interactions without forcing MessageChannel to inherit from
+ // NPObject.
+ struct MessageChannelNPObject : public NPObject {
+ MessageChannelNPObject();
+ ~MessageChannelNPObject();
+
+ MessageChannel* message_channel;
+ };
+
+ explicit MessageChannel(PluginInstance* instance);
+ ~MessageChannel();
+
+ void PostMessageToJavaScript(PP_Var message_data);
+ void PostMessageToNative(PP_Var message_data);
+
+ // Return the NPObject* to which we should forward any calls which aren't
+ // related to postMessage. Note that this can be NULL; it only gets set if
+ // there is a scriptable 'InstanceObject' associated with this channel's
+ // instance.
+ NPObject* passthrough_object() {
+ return passthrough_object_;
+ }
+ void set_passthrough_object(NPObject* passthrough) {
+ passthrough_object_ = passthrough;
+ }
+
+ NPObject* np_object() { return np_object_; }
+
+ PluginInstance* instance() {
+ return instance_;
+ }
+
+ private:
+ PluginInstance* instance_;
+
+ // We pass all non-postMessage calls through to the passthrough_object_.
+ // This way, a plugin can use PPB_Class or PPP_Class_Deprecated and also
+ // postMessage. This is necessary to support backwards-compatibility, and
+ // also trusted plugins for which we will continue to support synchronous
+ // scripting.
+ NPObject* passthrough_object_;
+
+ // The NPObject we use to expose postMessage to JavaScript.
+ MessageChannelNPObject* np_object_;
+
+ // An NPVariant referring to the JavaScript function we use to send a message
+ // to a JavaScript target.
+ NPVariant onmessage_invoker_;
+
+ bool EvaluateOnMessageInvoker();
+
+ DISALLOW_COPY_AND_ASSIGN(MessageChannel);
+};
+
+} // namespace ppapi
+} // namespace webkit
+
+#endif // WEBKIT_PLUGINS_PPAPI_MESSAGE_CHANNEL_H_
+
diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc
index f945934..0f5059a 100644
--- a/webkit/plugins/ppapi/plugin_module.cc
+++ b/webkit/plugins/ppapi/plugin_module.cc
@@ -27,6 +27,7 @@
#include "ppapi/c/dev/ppb_fullscreen_dev.h"
#include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h"
#include "ppapi/c/dev/ppb_graphics_3d_dev.h"
+#include "ppapi/c/dev/ppb_messaging_dev.h"
#include "ppapi/c/dev/ppb_opengles_dev.h"
#include "ppapi/c/dev/ppb_scrollbar_dev.h"
#include "ppapi/c/dev/ppb_testing_dev.h"
@@ -272,6 +273,8 @@ const void* GetInterface(const char* name) {
return PPB_ImageData_Impl::GetTrustedInterface();
if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0)
return PluginInstance::GetInterface();
+ if (strcmp(name, PPB_MESSAGING_DEV_INTERFACE) == 0)
+ return PluginInstance::GetMessagingInterface();
if (strcmp(name, PPB_PDF_INTERFACE) == 0)
return PPB_PDF_Impl::GetInterface();
if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
index ecfcba7..97526e9 100644
--- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc
+++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
@@ -11,8 +11,10 @@
#include "base/utf_string_conversions.h"
#include "ppapi/c/dev/ppb_find_dev.h"
#include "ppapi/c/dev/ppb_fullscreen_dev.h"
+#include "ppapi/c/dev/ppb_messaging_dev.h"
#include "ppapi/c/dev/ppb_zoom_dev.h"
#include "ppapi/c/dev/ppp_find_dev.h"
+#include "ppapi/c/dev/ppp_messaging_dev.h"
#include "ppapi/c/dev/ppp_selection_dev.h"
#include "ppapi/c/dev/ppp_zoom_dev.h"
#include "ppapi/c/pp_input_event.h"
@@ -42,6 +44,7 @@
#include "webkit/plugins/ppapi/common.h"
#include "webkit/plugins/ppapi/event_conversion.h"
#include "webkit/plugins/ppapi/fullscreen_container.h"
+#include "webkit/plugins/ppapi/message_channel.h"
#include "webkit/plugins/ppapi/plugin_delegate.h"
#include "webkit/plugins/ppapi/plugin_module.h"
#include "webkit/plugins/ppapi/plugin_object.h"
@@ -100,7 +103,8 @@ typedef bool (*RenderPDFPageToDCProc)(
namespace {
#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
- COMPILE_ASSERT(int(WebCursorInfo::webkit_name) == int(np_name), \
+ COMPILE_ASSERT(static_cast<int>(WebCursorInfo::webkit_name) \
+ == static_cast<int>(np_name), \
mismatching_enums)
COMPILE_ASSERT_MATCHING_ENUM(TypePointer, PP_CURSORTYPE_POINTER);
@@ -262,13 +266,23 @@ PP_Bool GetScreenSize(PP_Instance instance_id, PP_Size* size) {
return PP_TRUE;
}
-
const PPB_Fullscreen_Dev ppb_fullscreen = {
&IsFullscreen,
&SetFullscreen,
&GetScreenSize
};
+void PostMessage(PP_Instance instance_id, PP_Var message) {
+ PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
+ if (!instance)
+ return;
+ instance->PostMessage(message);
+}
+
+const PPB_Messaging_Dev ppb_messaging = {
+ &PostMessage
+};
+
void ZoomChanged(PP_Instance instance_id, double factor) {
PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
if (!instance)
@@ -326,9 +340,11 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
has_content_area_focus_(false),
find_identifier_(-1),
plugin_find_interface_(NULL),
+ plugin_messaging_interface_(NULL),
plugin_pdf_interface_(NULL),
plugin_selection_interface_(NULL),
plugin_zoom_interface_(NULL),
+ checked_for_plugin_messaging_interface_(false),
#if defined(OS_LINUX)
canvas_(NULL),
#endif // defined(OS_LINUX)
@@ -337,6 +353,7 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
always_on_top_(false),
fullscreen_container_(NULL),
fullscreen_(false),
+ message_channel_(NULL),
sad_plugin_(NULL) {
pp_instance_ = ResourceTracker::Get()->AddInstance(this);
@@ -344,6 +361,7 @@ PluginInstance::PluginInstance(PluginDelegate* delegate,
DCHECK(delegate);
module_->InstanceCreated(this);
delegate_->InstanceCreated(this);
+ message_channel_.reset(new MessageChannel(this));
}
PluginInstance::~PluginInstance() {
@@ -383,6 +401,11 @@ const PPB_Fullscreen_Dev* PluginInstance::GetFullscreenInterface() {
}
// static
+const PPB_Messaging_Dev* PluginInstance::GetMessagingInterface() {
+ return &ppb_messaging;
+}
+
+// static
const PPB_Zoom_Dev* PluginInstance::GetZoomInterface() {
return &ppb_zoom;
}
@@ -643,6 +666,10 @@ PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) {
return ret;
}
+void PluginInstance::PostMessage(PP_Var message) {
+ message_channel_->PostMessageToJavaScript(message);
+}
+
void PluginInstance::Delete() {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PluginInstance> ref(this);
@@ -702,6 +729,14 @@ bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event,
return rv;
}
+void PluginInstance::HandleMessage(PP_Var message) {
+ // Keep a reference on the stack. See NOTE above.
+ scoped_refptr<PluginInstance> ref(this);
+ if (!LoadMessagingInterface())
+ return;
+ plugin_messaging_interface_->HandleMessage(pp_instance(), message);
+}
+
PP_Var PluginInstance::GetInstanceObject() {
return instance_interface_->GetInstanceObject(pp_instance());
}
@@ -878,6 +913,17 @@ bool PluginInstance::LoadFindInterface() {
return !!plugin_find_interface_;
}
+bool PluginInstance::LoadMessagingInterface() {
+ if (!checked_for_plugin_messaging_interface_) {
+ checked_for_plugin_messaging_interface_ = true;
+ plugin_messaging_interface_ =
+ reinterpret_cast<const PPP_Messaging_Dev*>(module_->GetPluginInterface(
+ PPP_MESSAGING_DEV_INTERFACE));
+ }
+
+ return !!plugin_messaging_interface_;
+}
+
bool PluginInstance::LoadPdfInterface() {
if (!plugin_pdf_interface_) {
plugin_pdf_interface_ =
diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h
index 7cb6187..176dbe7 100644
--- a/webkit/plugins/ppapi/ppapi_plugin_instance.h
+++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h
@@ -29,9 +29,11 @@ struct PP_Var;
struct PPB_Instance;
struct PPB_Find_Dev;
struct PPB_Fullscreen_Dev;
+struct PPB_Messaging_Dev;
struct PPB_Zoom_Dev;
struct PPP_Find_Dev;
struct PPP_Instance;
+struct PPP_Messaging_Dev;
struct PPP_Pdf;
struct PPP_Selection_Dev;
struct PPP_Zoom_Dev;
@@ -53,6 +55,7 @@ namespace webkit {
namespace ppapi {
class FullscreenContainer;
+class MessageChannel;
class ObjectVar;
class PluginDelegate;
class PluginModule;
@@ -80,10 +83,12 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// exposed to the plugin.
static const PPB_Find_Dev* GetFindInterface();
static const PPB_Fullscreen_Dev* GetFullscreenInterface();
+ static const PPB_Messaging_Dev* GetMessagingInterface();
static const PPB_Zoom_Dev* GetZoomInterface();
PluginDelegate* delegate() const { return delegate_; }
PluginModule* module() const { return module_.get(); }
+ MessageChannel& message_channel() { return *message_channel_; }
WebKit::WebPluginContainer* container() const { return container_; }
@@ -214,6 +219,10 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// Implementation of PPB_Flash.
bool NavigateToURL(const char* url, const char* target);
+ // Implementation of PPB_Messaging and PPP_Messaging.
+ void PostMessage(PP_Var message);
+ void HandleMessage(PP_Var message);
+
PluginDelegate::PlatformContext3D* CreateContext3D();
// Tracks all live ObjectVar. This is so we can map between PluginModule +
@@ -234,6 +243,7 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
private:
bool LoadFindInterface();
+ bool LoadMessagingInterface();
bool LoadPdfInterface();
bool LoadSelectionInterface();
bool LoadZoomInterface();
@@ -319,10 +329,15 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// The plugin-provided interfaces.
const PPP_Find_Dev* plugin_find_interface_;
+ const PPP_Messaging_Dev* plugin_messaging_interface_;
const PPP_Pdf* plugin_pdf_interface_;
const PPP_Selection_Dev* plugin_selection_interface_;
const PPP_Zoom_Dev* plugin_zoom_interface_;
+ // A flag to indicate whether we have asked this plugin instance for its
+ // messaging interface, so that we can ask only once.
+ bool checked_for_plugin_messaging_interface_;
+
// This is only valid between a successful PrintBegin call and a PrintEnd
// call.
PP_PrintSettings_Dev current_print_settings_;
@@ -367,6 +382,10 @@ class PluginInstance : public base::RefCounted<PluginInstance> {
// True if we are in fullscreen mode. Note: it is false during the transition.
bool fullscreen_;
+ // The MessageChannel used to implement bidirectional postMessage for the
+ // instance.
+ scoped_ptr<MessageChannel> message_channel_;
+
// Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
SkBitmap* sad_plugin_;
diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc
index 2c8c2af..8e61354 100644
--- a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc
+++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc
@@ -12,6 +12,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+#include "webkit/plugins/ppapi/message_channel.h"
#include "webkit/plugins/ppapi/plugin_module.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
#include "webkit/plugins/ppapi/ppb_url_loader_impl.h"
@@ -90,9 +91,14 @@ void WebPluginImpl::destroy() {
NPObject* WebPluginImpl::scriptableObject() {
scoped_refptr<ObjectVar> object(
ObjectVar::FromPPVar(instance_->GetInstanceObject()));
- if (object)
- return object->np_object();
- return NULL;
+ // If there's an InstanceObject, tell the Instance's MessageChannel to pass
+ // any non-postMessage calls to it.
+ if (object) {
+ instance_->message_channel().set_passthrough_object(
+ object->np_object());
+ }
+ // And return the instance's MessageChannel.
+ return instance_->message_channel().np_object();
}
void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {