| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "webkit/plugins/ppapi/message_channel.h" | 
|  | 6 | 
|  | 7 #include <cstdlib> | 
|  | 8 #include <cstring> | 
|  | 9 #include <string> | 
|  | 10 | 
|  | 11 #include "base/logging.h" | 
|  | 12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | 
|  | 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 
|  | 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" | 
|  | 15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 
|  | 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" | 
|  | 17 #include "webkit/plugins/ppapi/npapi_glue.h" | 
|  | 18 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 
|  | 19 #include "webkit/plugins/ppapi/var.h" | 
|  | 20 | 
|  | 21 using WebKit::WebBindings; | 
|  | 22 | 
|  | 23 namespace webkit { | 
|  | 24 namespace ppapi { | 
|  | 25 | 
|  | 26 namespace { | 
|  | 27 | 
|  | 28 const char kPostMessage[] = "postMessage"; | 
|  | 29 | 
|  | 30 // Helper function to determine if a given identifier is equal to kPostMessage. | 
|  | 31 bool IdentifierIsPostMessage(NPIdentifier identifier) { | 
|  | 32   const NPUTF8* id_as_string = NULL; | 
|  | 33   int32_t int_value = 0; | 
|  | 34   bool is_string = false; | 
|  | 35   WebBindings::extractIdentifierData(identifier, id_as_string, int_value, | 
|  | 36                                      is_string); | 
|  | 37   if (is_string) | 
|  | 38     return (std::strcmp(id_as_string, kPostMessage) == 0); | 
|  | 39   return false; | 
|  | 40 } | 
|  | 41 | 
|  | 42 // Converts the given PP_Var to an NPVariant, returning true on success. | 
|  | 43 // False means that the given variant is invalid. In this case, the result | 
|  | 44 // NPVariant will be set to a void one. | 
|  | 45 // | 
|  | 46 // The contents of the PP_Var will NOT be copied, so you need to ensure that | 
|  | 47 // the PP_Var remains valid while the resultant NPVariant is in use. | 
|  | 48 // | 
|  | 49 // | 
|  | 50 // Note:  This is largely copied from var.cc so that we don't depend on code | 
|  | 51 //        which will be removed.  TODO(dmichael) remove this comment when var | 
|  | 52 //        is removed. | 
|  | 53 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) { | 
|  | 54   switch (var.type) { | 
|  | 55     case PP_VARTYPE_UNDEFINED: | 
|  | 56       VOID_TO_NPVARIANT(*result); | 
|  | 57       break; | 
|  | 58     case PP_VARTYPE_NULL: | 
|  | 59       NULL_TO_NPVARIANT(*result); | 
|  | 60       break; | 
|  | 61     case PP_VARTYPE_BOOL: | 
|  | 62       BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); | 
|  | 63       break; | 
|  | 64     case PP_VARTYPE_INT32: | 
|  | 65       INT32_TO_NPVARIANT(var.value.as_int, *result); | 
|  | 66       break; | 
|  | 67     case PP_VARTYPE_DOUBLE: | 
|  | 68       DOUBLE_TO_NPVARIANT(var.value.as_double, *result); | 
|  | 69       break; | 
|  | 70     case PP_VARTYPE_STRING: { | 
|  | 71       scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); | 
|  | 72       if (!string) { | 
|  | 73         VOID_TO_NPVARIANT(*result); | 
|  | 74         return false; | 
|  | 75       } | 
|  | 76       const std::string& value = string->value(); | 
|  | 77       STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result); | 
|  | 78       break; | 
|  | 79     } | 
|  | 80     case PP_VARTYPE_OBJECT: | 
|  | 81       // Objects are not currently supported. | 
|  | 82       VOID_TO_NPVARIANT(*result); | 
|  | 83       DCHECK(false); | 
|  | 84       return false; | 
|  | 85     default: | 
|  | 86       VOID_TO_NPVARIANT(*result); | 
|  | 87       return false; | 
|  | 88   } | 
|  | 89   return true; | 
|  | 90 } | 
|  | 91 | 
|  | 92 // Helper function to get the MessageChannel that is associated with an | 
|  | 93 // NPObject*. | 
|  | 94 MessageChannel& ToMessageChannel(NPObject* object) { | 
|  | 95   return *(static_cast<MessageChannel::MessageChannelNPObject*>(object)-> | 
|  | 96       message_channel); | 
|  | 97 } | 
|  | 98 | 
|  | 99 //------------------------------------------------------------------------------ | 
|  | 100 // Implementations of NPClass functions.  These are here to: | 
|  | 101 // - Implement postMessage behavior. | 
|  | 102 // - Forward calls to the 'passthrough' object to allow backwards-compatibility | 
|  | 103 //   with GetInstanceObject() objects. | 
|  | 104 //------------------------------------------------------------------------------ | 
|  | 105 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) { | 
|  | 106   return new MessageChannel::MessageChannelNPObject; | 
|  | 107 } | 
|  | 108 | 
|  | 109 void MessageChannelDeallocate(NPObject* object) { | 
|  | 110   MessageChannel::MessageChannelNPObject* instance = | 
|  | 111       static_cast<MessageChannel::MessageChannelNPObject*>(object); | 
|  | 112   delete instance; | 
|  | 113 } | 
|  | 114 | 
|  | 115 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) { | 
|  | 116   if (NULL == np_obj) | 
|  | 117     return false; | 
|  | 118 | 
|  | 119   // We only handle a function called postMessage. | 
|  | 120   if (IdentifierIsPostMessage(name)) | 
|  | 121     return true; | 
|  | 122 | 
|  | 123   // Other method names we will pass to the passthrough object, if we have one. | 
|  | 124   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 125   if (passthrough) { | 
|  | 126     return WebBindings::hasMethod(NULL, passthrough, name); | 
|  | 127   } | 
|  | 128   return false; | 
|  | 129 } | 
|  | 130 | 
|  | 131 bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name, | 
|  | 132                           const NPVariant* args, uint32 arg_count, | 
|  | 133                           NPVariant* result) { | 
|  | 134   if (NULL == np_obj) | 
|  | 135     return false; | 
|  | 136 | 
|  | 137   // We only handle a function called postMessage. | 
|  | 138   if (IdentifierIsPostMessage(name) && (arg_count == 1)) { | 
|  | 139     MessageChannel& message_channel(ToMessageChannel(np_obj)); | 
|  | 140     PP_Var argument(Var::NPVariantToPPVar(message_channel.instance(), | 
|  | 141                                           &args[0])); | 
|  | 142     message_channel.PostMessageToNative(argument); | 
|  | 143     return true; | 
|  | 144   } | 
|  | 145   // Other method calls we will pass to the passthrough object, if we have one. | 
|  | 146   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 147   if (passthrough) { | 
|  | 148     return WebBindings::invoke(NULL, passthrough, name, args, arg_count, | 
|  | 149                                result); | 
|  | 150   } | 
|  | 151   return false; | 
|  | 152 } | 
|  | 153 | 
|  | 154 bool MessageChannelInvokeDefault(NPObject* np_obj, | 
|  | 155                                  const NPVariant* args, | 
|  | 156                                  uint32 arg_count, | 
|  | 157                                  NPVariant* result) { | 
|  | 158   if (NULL == np_obj) | 
|  | 159     return false; | 
|  | 160 | 
|  | 161   // Invoke on the passthrough object, if we have one. | 
|  | 162   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 163   if (passthrough) { | 
|  | 164     return WebBindings::invokeDefault(NULL, passthrough, args, arg_count, | 
|  | 165                                       result); | 
|  | 166   } | 
|  | 167   return false; | 
|  | 168 } | 
|  | 169 | 
|  | 170 bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) { | 
|  | 171   if (NULL == np_obj) | 
|  | 172     return false; | 
|  | 173 | 
|  | 174   // Invoke on the passthrough object, if we have one. | 
|  | 175   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 176   if (passthrough) { | 
|  | 177     return WebBindings::hasProperty(NULL, passthrough, name); | 
|  | 178   } | 
|  | 179   return false; | 
|  | 180 } | 
|  | 181 | 
|  | 182 bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name, | 
|  | 183                                NPVariant* result) { | 
|  | 184   if (NULL == np_obj) return false; | 
|  | 185 | 
|  | 186   // Don't allow getting the postMessage function. | 
|  | 187   if (IdentifierIsPostMessage(name)) | 
|  | 188     return false; | 
|  | 189 | 
|  | 190   // Invoke on the passthrough object, if we have one. | 
|  | 191   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 192   if (passthrough) { | 
|  | 193     return WebBindings::getProperty(NULL, passthrough, name, result); | 
|  | 194   } | 
|  | 195   return false; | 
|  | 196 } | 
|  | 197 | 
|  | 198 bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name, | 
|  | 199                                const NPVariant* variant) { | 
|  | 200   if (NULL == np_obj) return false; | 
|  | 201 | 
|  | 202   // Don't allow setting the postMessage function. | 
|  | 203   if (IdentifierIsPostMessage(name)) | 
|  | 204     return false; | 
|  | 205 | 
|  | 206   // Invoke on the passthrough object, if we have one. | 
|  | 207   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 208   if (passthrough) { | 
|  | 209     return WebBindings::setProperty(NULL, passthrough, name, variant); | 
|  | 210   } | 
|  | 211   return false; | 
|  | 212 } | 
|  | 213 | 
|  | 214 bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value, | 
|  | 215                              uint32_t *count) { | 
|  | 216   if (NULL == np_obj) return false; | 
|  | 217 | 
|  | 218   // Invoke on the passthrough object, if we have one, to enumerate its | 
|  | 219   // properties. | 
|  | 220   NPObject* passthrough = ToMessageChannel(np_obj).passthrough_object(); | 
|  | 221   if (passthrough) { | 
|  | 222     bool success = WebBindings::enumerate(NULL, passthrough, value, count); | 
|  | 223     if (success) { | 
|  | 224       // add postMessage to the list and return it. | 
|  | 225       NPIdentifier* new_array = static_cast<NPIdentifier*>( | 
|  | 226           malloc(sizeof(NPIdentifier) * (*count + 1))); | 
|  | 227       std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count)); | 
|  | 228       new_array[*count] = WebBindings::getStringIdentifier(kPostMessage); | 
|  | 229       free(*value); | 
|  | 230       *value = new_array; | 
|  | 231       ++(*count); | 
|  | 232       return true; | 
|  | 233     } | 
|  | 234   } | 
|  | 235 | 
|  | 236   // Otherwise, build an array that includes only postMessage. | 
|  | 237   *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier))); | 
|  | 238   (*value)[0] = WebBindings::getStringIdentifier(kPostMessage); | 
|  | 239   *count = 1; | 
|  | 240   return true; | 
|  | 241 } | 
|  | 242 | 
|  | 243 NPClass message_channel_class = { | 
|  | 244   NP_CLASS_STRUCT_VERSION, | 
|  | 245   &MessageChannelAllocate, | 
|  | 246   &MessageChannelDeallocate, | 
|  | 247   NULL, | 
|  | 248   &MessageChannelHasMethod, | 
|  | 249   &MessageChannelInvoke, | 
|  | 250   &MessageChannelInvokeDefault, | 
|  | 251   &MessageChannelHasProperty, | 
|  | 252   &MessageChannelGetProperty, | 
|  | 253   &MessageChannelSetProperty, | 
|  | 254   NULL, | 
|  | 255   &MessageChannelEnumerate, | 
|  | 256 }; | 
|  | 257 }  // namespace | 
|  | 258 | 
|  | 259 // MessageChannel -------------------------------------------------------------- | 
|  | 260 MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {} | 
|  | 261 | 
|  | 262 MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {} | 
|  | 263 | 
|  | 264 MessageChannel::MessageChannel(PluginInstance* instance) | 
|  | 265     : instance_(instance), | 
|  | 266       passthrough_object_(NULL), | 
|  | 267       np_object_(NULL) { | 
|  | 268   // Now create an NPObject for receiving calls to postMessage. | 
|  | 269   NPObject* obj = WebBindings::createObject(NULL, &message_channel_class); | 
|  | 270   DCHECK(obj != NULL); | 
|  | 271   np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj); | 
|  | 272   np_object_->message_channel = this; | 
|  | 273 } | 
|  | 274 | 
|  | 275 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { | 
|  | 276   // This is the javascript code that we invoke.  It checks to see if onmessage | 
|  | 277   // exists, and if so, it invokes it. | 
|  | 278   const char invoke_onmessage_js[] = | 
|  | 279       "(function(module_instance, message_data) {" | 
|  | 280       "  if (module_instance &&"  // Only invoke if the instance is valid and | 
|  | 281       "      module_instance.onmessage &&"  // has a function named onmessage. | 
|  | 282       "      typeof(module_instance.onmessage) == 'function') {" | 
|  | 283       "    var message_event = document.createEvent('MessageEvent');" | 
|  | 284       "    message_event.initMessageEvent('message',"  // type | 
|  | 285       "                                   false,"  // canBubble | 
|  | 286       "                                   false,"  // cancelable | 
|  | 287       "                                   message_data,"  // data | 
|  | 288       "                                   '',"  // origin | 
|  | 289       "                                   '',"  // lastEventId | 
|  | 290       "                                   module_instance,"  // source | 
|  | 291       "                                   []);"  // ports | 
|  | 292       "    module_instance.onmessage(message_event);" | 
|  | 293       "  }" | 
|  | 294       "})"; | 
|  | 295 | 
|  | 296   NPString function_string = { invoke_onmessage_js, | 
|  | 297                                sizeof(invoke_onmessage_js)-1 }; | 
|  | 298   NPVariant invoke_onmessage_js_function; | 
|  | 299   VOID_TO_NPVARIANT(invoke_onmessage_js_function); | 
|  | 300   // Get the current frame to pass to the evaluate function. | 
|  | 301   WebKit::WebFrame* frame = | 
|  | 302       instance_->container()->element().document().frame(); | 
|  | 303   // Evaluate the function and obtain an NPVariant pointing to it. | 
|  | 304   if (!WebBindings::evaluate(NULL, frame->windowObject(), &function_string, | 
|  | 305                              &invoke_onmessage_js_function)) { | 
|  | 306     // If it fails, do nothing. | 
|  | 307     return; | 
|  | 308   } | 
|  | 309   DCHECK(NPVARIANT_IS_OBJECT(invoke_onmessage_js_function)); | 
|  | 310   DCHECK(instance_ != NULL); | 
|  | 311 | 
|  | 312   NPVariant result_var; | 
|  | 313   VOID_TO_NPVARIANT(result_var); | 
|  | 314   NPVariant npvariant_args[2]; | 
|  | 315   OBJECT_TO_NPVARIANT(instance_->container()->scriptableObjectForElement(), | 
|  | 316                       npvariant_args[0]); | 
|  | 317   // Convert message to an NPVariant without copying.  Note this means that | 
|  | 318   // in-process plugins will not copy the data, so isn't really following the | 
|  | 319   // postMessage spec in spirit.  Copying is handled in the proxy, and we don't | 
|  | 320   // want to re-copy unnecessarily. | 
|  | 321   // | 
|  | 322   // TODO(dmichael):  We need to do structured clone eventually to copy a object | 
|  | 323   // structure.  The details and PPAPI changes for this are TBD. | 
|  | 324   if (!PPVarToNPVariantNoCopy(message_data, &npvariant_args[1])) { | 
|  | 325     return; | 
|  | 326   } | 
|  | 327   WebBindings::invokeDefault(NULL, | 
|  | 328                              NPVARIANT_TO_OBJECT(invoke_onmessage_js_function), | 
|  | 329                              npvariant_args, | 
|  | 330                              sizeof(npvariant_args)/sizeof(*npvariant_args), | 
|  | 331                              &result_var); | 
|  | 332   WebBindings::releaseVariantValue(&invoke_onmessage_js_function); | 
|  | 333 } | 
|  | 334 | 
|  | 335 void MessageChannel::PostMessageToNative(PP_Var message_data) { | 
|  | 336   instance_->HandleMessage(message_data); | 
|  | 337 } | 
|  | 338 | 
|  | 339 MessageChannel::~MessageChannel() {} | 
|  | 340 | 
|  | 341 }  // namespace ppapi | 
|  | 342 }  // namespace webkit | 
|  | 343 | 
| OLD | NEW | 
|---|