Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Unified Diff: webkit/plugins/ppapi/message_channel.cc

Issue 6538028: A proposal for an initial postMessage interface. This will allow JavaScript ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webkit/plugins/ppapi/message_channel.cc
===================================================================
--- webkit/plugins/ppapi/message_channel.cc (revision 0)
+++ webkit/plugins/ppapi/message_channel.cc (revision 0)
@@ -0,0 +1,343 @@
+// 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 <cstring>
+#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 determine if a given identifier is equal to kPostMessage.
+bool IdentifierIsPostMessage(NPIdentifier identifier) {
+ const NPUTF8* id_as_string = NULL;
+ int32_t int_value = 0;
+ bool is_string = false;
+ WebBindings::extractIdentifierData(identifier, id_as_string, int_value,
+ is_string);
+ if (is_string)
+ return (std::strcmp(id_as_string, kPostMessage) == 0);
+ return false;
+}
+
+// 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.
+ VOID_TO_NPVARIANT(*result);
+ DCHECK(false);
+ return false;
+ default:
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ return true;
+}
+
+// Helper function to get the MessageChannel that is associated with an
+// NPObject*.
+MessageChannel& ToMessageChannel(NPObject* object) {
+ return *(static_cast<MessageChannel::MessageChannelNPObject*>(object)->
+ message_channel);
+}
+
+//------------------------------------------------------------------------------
+// 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 (NULL == np_obj)
+ return false;
+
+ // We only handle a function called postMessage.
+ if (IdentifierIsPostMessage(name))
brettw 2011/03/16 21:34:11 Can't you just compare identifiers? I thought that
+ 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 (NULL == 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 (NULL == 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 (NULL == 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 (NULL == 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 (NULL == 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 (NULL == 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*>(
+ malloc(sizeof(NPIdentifier) * (*count + 1)));
+ std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count));
+ new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
+ 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) {
+ // Now create an NPObject for receiving calls to postMessage.
+ NPObject* obj = WebBindings::createObject(NULL, &message_channel_class);
+ DCHECK(obj != NULL);
+ np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
+ np_object_->message_channel = this;
+}
+
+void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
+ // 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 };
+ NPVariant invoke_onmessage_js_function;
+ VOID_TO_NPVARIANT(invoke_onmessage_js_function);
+ // 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,
+ &invoke_onmessage_js_function)) {
+ // If it fails, do nothing.
+ return;
+ }
+ DCHECK(NPVARIANT_IS_OBJECT(invoke_onmessage_js_function));
+ DCHECK(instance_ != NULL);
+
+ 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(invoke_onmessage_js_function),
+ npvariant_args,
+ sizeof(npvariant_args)/sizeof(*npvariant_args),
+ &result_var);
+ WebBindings::releaseVariantValue(&invoke_onmessage_js_function);
+}
+
+void MessageChannel::PostMessageToNative(PP_Var message_data) {
+ instance_->HandleMessage(message_data);
+}
+
+MessageChannel::~MessageChannel() {}
+
+} // namespace ppapi
+} // namespace webkit
+
Property changes on: webkit/plugins/ppapi/message_channel.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698