| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/bind.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "ppapi/shared_impl/ppapi_globals.h" | |
| 14 #include "ppapi/shared_impl/var.h" | |
| 15 #include "ppapi/shared_impl/var_tracker.h" | |
| 16 #include "third_party/WebKit/public/web/WebBindings.h" | |
| 17 #include "third_party/WebKit/public/web/WebDocument.h" | |
| 18 #include "third_party/WebKit/public/web/WebDOMMessageEvent.h" | |
| 19 #include "third_party/WebKit/public/web/WebElement.h" | |
| 20 #include "third_party/WebKit/public/web/WebFrame.h" | |
| 21 #include "third_party/WebKit/public/web/WebNode.h" | |
| 22 #include "third_party/WebKit/public/web/WebPluginContainer.h" | |
| 23 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" | |
| 24 #include "v8/include/v8.h" | |
| 25 #include "webkit/plugins/ppapi/host_array_buffer_var.h" | |
| 26 #include "webkit/plugins/ppapi/npapi_glue.h" | |
| 27 #include "webkit/plugins/ppapi/plugin_module.h" | |
| 28 #include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h" | |
| 29 #include "webkit/plugins/ppapi/v8_var_converter.h" | |
| 30 | |
| 31 using ppapi::ArrayBufferVar; | |
| 32 using ppapi::PpapiGlobals; | |
| 33 using ppapi::StringVar; | |
| 34 using WebKit::WebBindings; | |
| 35 using WebKit::WebElement; | |
| 36 using WebKit::WebDOMEvent; | |
| 37 using WebKit::WebDOMMessageEvent; | |
| 38 using WebKit::WebPluginContainer; | |
| 39 using WebKit::WebSerializedScriptValue; | |
| 40 | |
| 41 namespace webkit { | |
| 42 | |
| 43 namespace ppapi { | |
| 44 | |
| 45 namespace { | |
| 46 | |
| 47 const char kPostMessage[] = "postMessage"; | |
| 48 const char kV8ToVarConversionError[] = "Failed to convert a PostMessage " | |
| 49 "argument from a JavaScript value to a PP_Var. It may have cycles or be of " | |
| 50 "an unsupported type."; | |
| 51 const char kVarToV8ConversionError[] = "Failed to convert a PostMessage " | |
| 52 "argument from a PP_Var to a Javascript value. It may have cycles or be of " | |
| 53 "an unsupported type."; | |
| 54 | |
| 55 // Helper function to get the MessageChannel that is associated with an | |
| 56 // NPObject*. | |
| 57 MessageChannel* ToMessageChannel(NPObject* object) { | |
| 58 return static_cast<MessageChannel::MessageChannelNPObject*>(object)-> | |
| 59 message_channel.get(); | |
| 60 } | |
| 61 | |
| 62 NPObject* ToPassThroughObject(NPObject* object) { | |
| 63 MessageChannel* channel = ToMessageChannel(object); | |
| 64 return channel ? channel->passthrough_object() : NULL; | |
| 65 } | |
| 66 | |
| 67 // Helper function to determine if a given identifier is equal to kPostMessage. | |
| 68 bool IdentifierIsPostMessage(NPIdentifier identifier) { | |
| 69 return WebBindings::getStringIdentifier(kPostMessage) == identifier; | |
| 70 } | |
| 71 | |
| 72 bool NPVariantToPPVar(const NPVariant* variant, PP_Var* result) { | |
| 73 switch (variant->type) { | |
| 74 case NPVariantType_Void: | |
| 75 *result = PP_MakeUndefined(); | |
| 76 return true; | |
| 77 case NPVariantType_Null: | |
| 78 *result = PP_MakeNull(); | |
| 79 return true; | |
| 80 case NPVariantType_Bool: | |
| 81 *result = PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant))); | |
| 82 return true; | |
| 83 case NPVariantType_Int32: | |
| 84 *result = PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); | |
| 85 return true; | |
| 86 case NPVariantType_Double: | |
| 87 *result = PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); | |
| 88 return true; | |
| 89 case NPVariantType_String: | |
| 90 *result = StringVar::StringToPPVar( | |
| 91 NPVARIANT_TO_STRING(*variant).UTF8Characters, | |
| 92 NPVARIANT_TO_STRING(*variant).UTF8Length); | |
| 93 return true; | |
| 94 case NPVariantType_Object: { | |
| 95 // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it | |
| 96 // shouldn't result in a deep copy. | |
| 97 v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant); | |
| 98 if (!V8VarConverter::FromV8Value(v8_value, v8::Context::GetCurrent(), | |
| 99 result)) { | |
| 100 return false; | |
| 101 } | |
| 102 return true; | |
| 103 } | |
| 104 } | |
| 105 return false; | |
| 106 } | |
| 107 | |
| 108 // Copy a PP_Var in to a PP_Var that is appropriate for sending via postMessage. | |
| 109 // This currently just copies the value. For a string Var, the result is a | |
| 110 // PP_Var with the a copy of |var|'s string contents and a reference count of 1. | |
| 111 PP_Var CopyPPVar(const PP_Var& var) { | |
| 112 switch (var.type) { | |
| 113 case PP_VARTYPE_UNDEFINED: | |
| 114 case PP_VARTYPE_NULL: | |
| 115 case PP_VARTYPE_BOOL: | |
| 116 case PP_VARTYPE_INT32: | |
| 117 case PP_VARTYPE_DOUBLE: | |
| 118 return var; | |
| 119 case PP_VARTYPE_STRING: { | |
| 120 StringVar* string = StringVar::FromPPVar(var); | |
| 121 if (!string) | |
| 122 return PP_MakeUndefined(); | |
| 123 return StringVar::StringToPPVar(string->value()); | |
| 124 } | |
| 125 case PP_VARTYPE_ARRAY_BUFFER: { | |
| 126 ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var); | |
| 127 if (!buffer) | |
| 128 return PP_MakeUndefined(); | |
| 129 PP_Var new_buffer_var = PpapiGlobals::Get()->GetVarTracker()-> | |
| 130 MakeArrayBufferPPVar(buffer->ByteLength()); | |
| 131 DCHECK(new_buffer_var.type == PP_VARTYPE_ARRAY_BUFFER); | |
| 132 if (new_buffer_var.type != PP_VARTYPE_ARRAY_BUFFER) | |
| 133 return PP_MakeUndefined(); | |
| 134 ArrayBufferVar* new_buffer = ArrayBufferVar::FromPPVar(new_buffer_var); | |
| 135 DCHECK(new_buffer); | |
| 136 if (!new_buffer) | |
| 137 return PP_MakeUndefined(); | |
| 138 memcpy(new_buffer->Map(), buffer->Map(), buffer->ByteLength()); | |
| 139 return new_buffer_var; | |
| 140 } | |
| 141 case PP_VARTYPE_OBJECT: | |
| 142 case PP_VARTYPE_ARRAY: | |
| 143 case PP_VARTYPE_DICTIONARY: | |
| 144 // Objects/Arrays/Dictionaries not supported by PostMessage in-process. | |
| 145 NOTREACHED(); | |
| 146 return PP_MakeUndefined(); | |
| 147 } | |
| 148 NOTREACHED(); | |
| 149 return PP_MakeUndefined(); | |
| 150 } | |
| 151 | |
| 152 //------------------------------------------------------------------------------ | |
| 153 // Implementations of NPClass functions. These are here to: | |
| 154 // - Implement postMessage behavior. | |
| 155 // - Forward calls to the 'passthrough' object to allow backwards-compatibility | |
| 156 // with GetInstanceObject() objects. | |
| 157 //------------------------------------------------------------------------------ | |
| 158 NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) { | |
| 159 return new MessageChannel::MessageChannelNPObject; | |
| 160 } | |
| 161 | |
| 162 void MessageChannelDeallocate(NPObject* object) { | |
| 163 MessageChannel::MessageChannelNPObject* instance = | |
| 164 static_cast<MessageChannel::MessageChannelNPObject*>(object); | |
| 165 delete instance; | |
| 166 } | |
| 167 | |
| 168 bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) { | |
| 169 if (!np_obj) | |
| 170 return false; | |
| 171 | |
| 172 // We only handle a function called postMessage. | |
| 173 if (IdentifierIsPostMessage(name)) | |
| 174 return true; | |
| 175 | |
| 176 // Other method names we will pass to the passthrough object, if we have one. | |
| 177 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 178 if (passthrough) | |
| 179 return WebBindings::hasMethod(NULL, passthrough, name); | |
| 180 return false; | |
| 181 } | |
| 182 | |
| 183 bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name, | |
| 184 const NPVariant* args, uint32 arg_count, | |
| 185 NPVariant* result) { | |
| 186 if (!np_obj) | |
| 187 return false; | |
| 188 | |
| 189 // We only handle a function called postMessage. | |
| 190 if (IdentifierIsPostMessage(name) && (arg_count == 1)) { | |
| 191 MessageChannel* message_channel = ToMessageChannel(np_obj); | |
| 192 if (message_channel) { | |
| 193 PP_Var argument = PP_MakeUndefined(); | |
| 194 if (!NPVariantToPPVar(&args[0], &argument)) { | |
| 195 PpapiGlobals::Get()->LogWithSource( | |
| 196 message_channel->instance()->pp_instance(), | |
| 197 PP_LOGLEVEL_ERROR, std::string(), kV8ToVarConversionError); | |
| 198 return false; | |
| 199 } | |
| 200 message_channel->PostMessageToNative(argument); | |
| 201 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(argument); | |
| 202 return true; | |
| 203 } else { | |
| 204 return false; | |
| 205 } | |
| 206 } | |
| 207 // Other method calls we will pass to the passthrough object, if we have one. | |
| 208 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 209 if (passthrough) { | |
| 210 return WebBindings::invoke(NULL, passthrough, name, args, arg_count, | |
| 211 result); | |
| 212 } | |
| 213 return false; | |
| 214 } | |
| 215 | |
| 216 bool MessageChannelInvokeDefault(NPObject* np_obj, | |
| 217 const NPVariant* args, | |
| 218 uint32 arg_count, | |
| 219 NPVariant* result) { | |
| 220 if (!np_obj) | |
| 221 return false; | |
| 222 | |
| 223 // Invoke on the passthrough object, if we have one. | |
| 224 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 225 if (passthrough) { | |
| 226 return WebBindings::invokeDefault(NULL, passthrough, args, arg_count, | |
| 227 result); | |
| 228 } | |
| 229 return false; | |
| 230 } | |
| 231 | |
| 232 bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) { | |
| 233 if (!np_obj) | |
| 234 return false; | |
| 235 | |
| 236 // Invoke on the passthrough object, if we have one. | |
| 237 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 238 if (passthrough) | |
| 239 return WebBindings::hasProperty(NULL, passthrough, name); | |
| 240 return false; | |
| 241 } | |
| 242 | |
| 243 bool MessageChannelGetProperty(NPObject* np_obj, NPIdentifier name, | |
| 244 NPVariant* result) { | |
| 245 if (!np_obj) | |
| 246 return false; | |
| 247 | |
| 248 // Don't allow getting the postMessage function. | |
| 249 if (IdentifierIsPostMessage(name)) | |
| 250 return false; | |
| 251 | |
| 252 // Invoke on the passthrough object, if we have one. | |
| 253 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 254 if (passthrough) | |
| 255 return WebBindings::getProperty(NULL, passthrough, name, result); | |
| 256 return false; | |
| 257 } | |
| 258 | |
| 259 bool MessageChannelSetProperty(NPObject* np_obj, NPIdentifier name, | |
| 260 const NPVariant* variant) { | |
| 261 if (!np_obj) | |
| 262 return false; | |
| 263 | |
| 264 // Don't allow setting the postMessage function. | |
| 265 if (IdentifierIsPostMessage(name)) | |
| 266 return false; | |
| 267 | |
| 268 // Invoke on the passthrough object, if we have one. | |
| 269 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 270 if (passthrough) | |
| 271 return WebBindings::setProperty(NULL, passthrough, name, variant); | |
| 272 return false; | |
| 273 } | |
| 274 | |
| 275 bool MessageChannelEnumerate(NPObject *np_obj, NPIdentifier **value, | |
| 276 uint32_t *count) { | |
| 277 if (!np_obj) | |
| 278 return false; | |
| 279 | |
| 280 // Invoke on the passthrough object, if we have one, to enumerate its | |
| 281 // properties. | |
| 282 NPObject* passthrough = ToPassThroughObject(np_obj); | |
| 283 if (passthrough) { | |
| 284 bool success = WebBindings::enumerate(NULL, passthrough, value, count); | |
| 285 if (success) { | |
| 286 // Add postMessage to the list and return it. | |
| 287 if (std::numeric_limits<size_t>::max() / sizeof(NPIdentifier) <= | |
| 288 static_cast<size_t>(*count) + 1) // Else, "always false" x64 warning. | |
| 289 return false; | |
| 290 NPIdentifier* new_array = static_cast<NPIdentifier*>( | |
| 291 std::malloc(sizeof(NPIdentifier) * (*count + 1))); | |
| 292 std::memcpy(new_array, *value, sizeof(NPIdentifier)*(*count)); | |
| 293 new_array[*count] = WebBindings::getStringIdentifier(kPostMessage); | |
| 294 std::free(*value); | |
| 295 *value = new_array; | |
| 296 ++(*count); | |
| 297 return true; | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 // Otherwise, build an array that includes only postMessage. | |
| 302 *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier))); | |
| 303 (*value)[0] = WebBindings::getStringIdentifier(kPostMessage); | |
| 304 *count = 1; | |
| 305 return true; | |
| 306 } | |
| 307 | |
| 308 NPClass message_channel_class = { | |
| 309 NP_CLASS_STRUCT_VERSION, | |
| 310 &MessageChannelAllocate, | |
| 311 &MessageChannelDeallocate, | |
| 312 NULL, | |
| 313 &MessageChannelHasMethod, | |
| 314 &MessageChannelInvoke, | |
| 315 &MessageChannelInvokeDefault, | |
| 316 &MessageChannelHasProperty, | |
| 317 &MessageChannelGetProperty, | |
| 318 &MessageChannelSetProperty, | |
| 319 NULL, | |
| 320 &MessageChannelEnumerate, | |
| 321 }; | |
| 322 | |
| 323 } // namespace | |
| 324 | |
| 325 // MessageChannel -------------------------------------------------------------- | |
| 326 MessageChannel::MessageChannelNPObject::MessageChannelNPObject() { | |
| 327 } | |
| 328 | |
| 329 MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {} | |
| 330 | |
| 331 MessageChannel::MessageChannel(PluginInstanceImpl* instance) | |
| 332 : instance_(instance), | |
| 333 passthrough_object_(NULL), | |
| 334 np_object_(NULL), | |
| 335 weak_ptr_factory_(this), | |
| 336 early_message_queue_state_(QUEUE_MESSAGES) { | |
| 337 // Now create an NPObject for receiving calls to postMessage. This sets the | |
| 338 // reference count to 1. We release it in the destructor. | |
| 339 NPObject* obj = WebBindings::createObject(instance_->instanceNPP(), | |
| 340 &message_channel_class); | |
| 341 DCHECK(obj); | |
| 342 np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj); | |
| 343 np_object_->message_channel = weak_ptr_factory_.GetWeakPtr(); | |
| 344 } | |
| 345 | |
| 346 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { | |
| 347 v8::HandleScope scope; | |
| 348 | |
| 349 // Because V8 is probably not on the stack for Native->JS calls, we need to | |
| 350 // enter the appropriate context for the plugin. | |
| 351 WebPluginContainer* container = instance_->container(); | |
| 352 // It's possible that container() is NULL if the plugin has been removed from | |
| 353 // the DOM (but the PluginInstance is not destroyed yet). | |
| 354 if (!container) | |
| 355 return; | |
| 356 | |
| 357 v8::Local<v8::Context> context = | |
| 358 container->element().document().frame()->mainWorldScriptContext(); | |
| 359 // If the page is being destroyed, the context may be empty. | |
| 360 if (context.IsEmpty()) | |
| 361 return; | |
| 362 v8::Context::Scope context_scope(context); | |
| 363 | |
| 364 v8::Handle<v8::Value> v8_val; | |
| 365 if (!V8VarConverter::ToV8Value(message_data, context, &v8_val)) { | |
| 366 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), | |
| 367 PP_LOGLEVEL_ERROR, std::string(), kVarToV8ConversionError); | |
| 368 return; | |
| 369 } | |
| 370 | |
| 371 // This is for backward compatibility. It usually makes sense for us to return | |
| 372 // a string object rather than a string primitive because it allows multiple | |
| 373 // references to the same string (as with PP_Var strings). However, prior to | |
| 374 // implementing dictionary and array, vars we would return a string primitive | |
| 375 // here. Changing it to an object now will break existing code that uses | |
| 376 // strict comparisons for strings returned from PostMessage. e.g. x === "123" | |
| 377 // will no longer return true. So if the only value to return is a string | |
| 378 // object, just return the string primitive. | |
| 379 if (v8_val->IsStringObject()) | |
| 380 v8_val = v8_val->ToString(); | |
| 381 | |
| 382 WebSerializedScriptValue serialized_val = | |
| 383 WebSerializedScriptValue::serialize(v8_val); | |
| 384 | |
| 385 if (instance_->module()->IsProxied()) { | |
| 386 if (early_message_queue_state_ != SEND_DIRECTLY) { | |
| 387 // We can't just PostTask here; the messages would arrive out of | |
| 388 // order. Instead, we queue them up until we're ready to post | |
| 389 // them. | |
| 390 early_message_queue_.push_back(serialized_val); | |
| 391 } else { | |
| 392 // The proxy sent an asynchronous message, so the plugin is already | |
| 393 // unblocked. Therefore, there's no need to PostTask. | |
| 394 DCHECK(early_message_queue_.size() == 0); | |
| 395 PostMessageToJavaScriptImpl(serialized_val); | |
| 396 } | |
| 397 } else { | |
| 398 base::MessageLoop::current()->PostTask( | |
| 399 FROM_HERE, | |
| 400 base::Bind(&MessageChannel::PostMessageToJavaScriptImpl, | |
| 401 weak_ptr_factory_.GetWeakPtr(), | |
| 402 serialized_val)); | |
| 403 } | |
| 404 } | |
| 405 | |
| 406 void MessageChannel::StopQueueingJavaScriptMessages() { | |
| 407 // We PostTask here instead of draining the message queue directly | |
| 408 // since we haven't finished initializing the WebPluginImpl yet, so | |
| 409 // the plugin isn't available in the DOM. | |
| 410 early_message_queue_state_ = DRAIN_PENDING; | |
| 411 base::MessageLoop::current()->PostTask( | |
| 412 FROM_HERE, | |
| 413 base::Bind(&MessageChannel::DrainEarlyMessageQueue, | |
| 414 weak_ptr_factory_.GetWeakPtr())); | |
| 415 } | |
| 416 | |
| 417 void MessageChannel::QueueJavaScriptMessages() { | |
| 418 if (early_message_queue_state_ == DRAIN_PENDING) | |
| 419 early_message_queue_state_ = DRAIN_CANCELLED; | |
| 420 else | |
| 421 early_message_queue_state_ = QUEUE_MESSAGES; | |
| 422 } | |
| 423 | |
| 424 void MessageChannel::DrainEarlyMessageQueue() { | |
| 425 // Take a reference on the PluginInstance. This is because JavaScript code | |
| 426 // may delete the plugin, which would destroy the PluginInstance and its | |
| 427 // corresponding MessageChannel. | |
| 428 scoped_refptr<PluginInstanceImpl> instance_ref(instance_); | |
| 429 | |
| 430 if (early_message_queue_state_ == DRAIN_CANCELLED) { | |
| 431 early_message_queue_state_ = QUEUE_MESSAGES; | |
| 432 return; | |
| 433 } | |
| 434 DCHECK(early_message_queue_state_ == DRAIN_PENDING); | |
| 435 | |
| 436 while (!early_message_queue_.empty()) { | |
| 437 PostMessageToJavaScriptImpl(early_message_queue_.front()); | |
| 438 early_message_queue_.pop_front(); | |
| 439 } | |
| 440 early_message_queue_state_ = SEND_DIRECTLY; | |
| 441 } | |
| 442 | |
| 443 void MessageChannel::PostMessageToJavaScriptImpl( | |
| 444 const WebSerializedScriptValue& message_data) { | |
| 445 DCHECK(instance_); | |
| 446 | |
| 447 WebPluginContainer* container = instance_->container(); | |
| 448 // It's possible that container() is NULL if the plugin has been removed from | |
| 449 // the DOM (but the PluginInstance is not destroyed yet). | |
| 450 if (!container) | |
| 451 return; | |
| 452 | |
| 453 WebDOMEvent event = | |
| 454 container->element().document().createEvent("MessageEvent"); | |
| 455 WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>(); | |
| 456 msg_event.initMessageEvent("message", // type | |
| 457 false, // canBubble | |
| 458 false, // cancelable | |
| 459 message_data, // data | |
| 460 "", // origin [*] | |
| 461 NULL, // source [*] | |
| 462 ""); // lastEventId | |
| 463 // [*] Note that the |origin| is only specified for cross-document and server- | |
| 464 // sent messages, while |source| is only specified for cross-document | |
| 465 // messages: | |
| 466 // http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html | |
| 467 // This currently behaves like Web Workers. On Firefox, Chrome, and Safari | |
| 468 // at least, postMessage on Workers does not provide the origin or source. | |
| 469 // TODO(dmichael): Add origin if we change to a more iframe-like origin | |
| 470 // policy (see crbug.com/81537) | |
| 471 | |
| 472 container->element().dispatchEvent(msg_event); | |
| 473 } | |
| 474 | |
| 475 void MessageChannel::PostMessageToNative(PP_Var message_data) { | |
| 476 if (instance_->module()->IsProxied()) { | |
| 477 // In the proxied case, the copy will happen via serializiation, and the | |
| 478 // message is asynchronous. Therefore there's no need to copy the Var, nor | |
| 479 // to PostTask. | |
| 480 PostMessageToNativeImpl(message_data); | |
| 481 } else { | |
| 482 // Make a copy of the message data for the Task we will run. | |
| 483 PP_Var var_copy(CopyPPVar(message_data)); | |
| 484 | |
| 485 base::MessageLoop::current()->PostTask( | |
| 486 FROM_HERE, | |
| 487 base::Bind(&MessageChannel::PostMessageToNativeImpl, | |
| 488 weak_ptr_factory_.GetWeakPtr(), | |
| 489 var_copy)); | |
| 490 } | |
| 491 } | |
| 492 | |
| 493 void MessageChannel::PostMessageToNativeImpl(PP_Var message_data) { | |
| 494 instance_->HandleMessage(message_data); | |
| 495 } | |
| 496 | |
| 497 MessageChannel::~MessageChannel() { | |
| 498 WebBindings::releaseObject(np_object_); | |
| 499 if (passthrough_object_) | |
| 500 WebBindings::releaseObject(passthrough_object_); | |
| 501 } | |
| 502 | |
| 503 void MessageChannel::SetPassthroughObject(NPObject* passthrough) { | |
| 504 // Retain the passthrough object; We need to ensure it lives as long as this | |
| 505 // MessageChannel. | |
| 506 if (passthrough) | |
| 507 WebBindings::retainObject(passthrough); | |
| 508 | |
| 509 // If we had a passthrough set already, release it. Note that we retain the | |
| 510 // incoming passthrough object first, so that we behave correctly if anyone | |
| 511 // invokes: | |
| 512 // SetPassthroughObject(passthrough_object()); | |
| 513 if (passthrough_object_) | |
| 514 WebBindings::releaseObject(passthrough_object_); | |
| 515 | |
| 516 passthrough_object_ = passthrough; | |
| 517 } | |
| 518 | |
| 519 } // namespace ppapi | |
| 520 } // namespace webkit | |
| OLD | NEW |