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