| Index: content/renderer/pepper/message_channel.cc
|
| diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc
|
| index 81f49e998f8ba529e2b04012dd9b5e2e3edc9017..12d24baeda28d561f18ca7ce2ff2285f34b6b880 100644
|
| --- a/content/renderer/pepper/message_channel.cc
|
| +++ b/content/renderer/pepper/message_channel.cc
|
| @@ -31,6 +31,7 @@
|
|
|
| using ppapi::ArrayBufferVar;
|
| using ppapi::PpapiGlobals;
|
| +using ppapi::ScopedPPVar;
|
| using ppapi::StringVar;
|
| using blink::WebBindings;
|
| using blink::WebElement;
|
| @@ -65,56 +66,9 @@ NPObject* ToPassThroughObject(NPObject* object) {
|
| return channel ? channel->passthrough_object() : NULL;
|
| }
|
|
|
| -// Helper function to determine if a given identifier is equal to kPostMessage.
|
| -bool IdentifierIsPostMessage(NPIdentifier identifier) {
|
| - return WebBindings::getStringIdentifier(kPostMessage) == identifier;
|
| -}
|
| -
|
| -// Copy a PP_Var in to a PP_Var that is appropriate for sending via postMessage.
|
| -// This currently just copies the value. For a string Var, the result is a
|
| -// PP_Var with the a copy of |var|'s string contents and a reference count of 1.
|
| -PP_Var CopyPPVar(const PP_Var& var) {
|
| - switch (var.type) {
|
| - case PP_VARTYPE_UNDEFINED:
|
| - case PP_VARTYPE_NULL:
|
| - case PP_VARTYPE_BOOL:
|
| - case PP_VARTYPE_INT32:
|
| - case PP_VARTYPE_DOUBLE:
|
| - return var;
|
| - case PP_VARTYPE_STRING: {
|
| - StringVar* string = StringVar::FromPPVar(var);
|
| - if (!string)
|
| - return PP_MakeUndefined();
|
| - return StringVar::StringToPPVar(string->value());
|
| - }
|
| - case PP_VARTYPE_ARRAY_BUFFER: {
|
| - ArrayBufferVar* buffer = ArrayBufferVar::FromPPVar(var);
|
| - if (!buffer)
|
| - return PP_MakeUndefined();
|
| - PP_Var new_buffer_var =
|
| - PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
|
| - buffer->ByteLength());
|
| - DCHECK(new_buffer_var.type == PP_VARTYPE_ARRAY_BUFFER);
|
| - if (new_buffer_var.type != PP_VARTYPE_ARRAY_BUFFER)
|
| - return PP_MakeUndefined();
|
| - ArrayBufferVar* new_buffer = ArrayBufferVar::FromPPVar(new_buffer_var);
|
| - DCHECK(new_buffer);
|
| - if (!new_buffer)
|
| - return PP_MakeUndefined();
|
| - memcpy(new_buffer->Map(), buffer->Map(), buffer->ByteLength());
|
| - return new_buffer_var;
|
| - }
|
| - case PP_VARTYPE_OBJECT:
|
| - case PP_VARTYPE_ARRAY:
|
| - case PP_VARTYPE_DICTIONARY:
|
| - case PP_VARTYPE_RESOURCE:
|
| - // These types are not supported by PostMessage in-process. In some rare
|
| - // cases with the NaCl plugin, they may be sent but they will be dropped
|
| - // anyway (see crbug.com/318837 for details).
|
| - return PP_MakeUndefined();
|
| - }
|
| - NOTREACHED();
|
| - return PP_MakeUndefined();
|
| +// Return true iff |identifier| is equal to |string|.
|
| +bool IdentifierIs(NPIdentifier identifier, const char string[]) {
|
| + return WebBindings::getStringIdentifier(string) == identifier;
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
| @@ -137,8 +91,7 @@ bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
|
| if (!np_obj)
|
| return false;
|
|
|
| - // We only handle a function called postMessage.
|
| - if (IdentifierIsPostMessage(name))
|
| + if (IdentifierIs(name, kPostMessage))
|
| return true;
|
|
|
| // Other method names we will pass to the passthrough object, if we have one.
|
| @@ -156,15 +109,15 @@ bool MessageChannelInvoke(NPObject* np_obj,
|
| if (!np_obj)
|
| return false;
|
|
|
| - // We only handle a function called postMessage.
|
| - if (IdentifierIsPostMessage(name) && (arg_count == 1)) {
|
| - MessageChannel* message_channel = ToMessageChannel(np_obj);
|
| - if (message_channel) {
|
| - message_channel->NPVariantToPPVar(&args[0]);
|
| - return true;
|
| - } else {
|
| - return false;
|
| - }
|
| + MessageChannel* message_channel = ToMessageChannel(np_obj);
|
| + if (!message_channel)
|
| + return false;
|
| +
|
| + // Check to see if we should handle this function ourselves. We only handle
|
| + // kPostMessage.
|
| + if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) {
|
| + message_channel->PostMessageToNative(&args[0]);
|
| + return true;
|
| }
|
| // Other method calls we will pass to the passthrough object, if we have one.
|
| NPObject* passthrough = ToPassThroughObject(np_obj);
|
| @@ -215,7 +168,7 @@ bool MessageChannelGetProperty(NPObject* np_obj,
|
| return false;
|
|
|
| // Don't allow getting the postMessage function.
|
| - if (IdentifierIsPostMessage(name))
|
| + if (IdentifierIs(name, kPostMessage))
|
| return false;
|
|
|
| MessageChannel* message_channel = ToMessageChannel(np_obj);
|
| @@ -238,7 +191,7 @@ bool MessageChannelSetProperty(NPObject* np_obj,
|
| return false;
|
|
|
| // Don't allow setting the postMessage function.
|
| - if (IdentifierIsPostMessage(name))
|
| + if (IdentifierIs(name, kPostMessage))
|
| return false;
|
|
|
| // Invoke on the passthrough object, if we have one.
|
| @@ -294,12 +247,21 @@ NPClass message_channel_class = {
|
|
|
| // MessageChannel --------------------------------------------------------------
|
| struct MessageChannel::VarConversionResult {
|
| - VarConversionResult(const ppapi::ScopedPPVar& r, bool s)
|
| - : result(r), success(s), conversion_completed(true) {}
|
| - VarConversionResult() : success(false), conversion_completed(false) {}
|
| - ppapi::ScopedPPVar result;
|
| - bool success;
|
| - bool conversion_completed;
|
| + VarConversionResult() : success_(false), conversion_completed_(false) {}
|
| + void ConversionCompleted(const ScopedPPVar& var,
|
| + bool success) {
|
| + conversion_completed_ = true;
|
| + var_ = var;
|
| + success_ = success;
|
| + }
|
| + const ScopedPPVar& var() const { return var_; }
|
| + bool success() const { return success_; }
|
| + bool conversion_completed() const { return conversion_completed_; }
|
| +
|
| + private:
|
| + ScopedPPVar var_;
|
| + bool success_;
|
| + bool conversion_completed_;
|
| };
|
|
|
| MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {}
|
| @@ -321,61 +283,30 @@ MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
|
| np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
|
| }
|
|
|
| -void MessageChannel::NPVariantToPPVar(const NPVariant* variant) {
|
| - converted_var_queue_.push_back(VarConversionResult());
|
| - std::list<VarConversionResult>::iterator result_iterator =
|
| - --converted_var_queue_.end();
|
| - switch (variant->type) {
|
| - case NPVariantType_Void:
|
| - NPVariantToPPVarComplete(
|
| - result_iterator, ppapi::ScopedPPVar(PP_MakeUndefined()), true);
|
| - return;
|
| - case NPVariantType_Null:
|
| - NPVariantToPPVarComplete(
|
| - result_iterator, ppapi::ScopedPPVar(PP_MakeNull()), true);
|
| - return;
|
| - case NPVariantType_Bool:
|
| - NPVariantToPPVarComplete(result_iterator,
|
| - ppapi::ScopedPPVar(PP_MakeBool(PP_FromBool(
|
| - NPVARIANT_TO_BOOLEAN(*variant)))),
|
| - true);
|
| - return;
|
| - case NPVariantType_Int32:
|
| - NPVariantToPPVarComplete(
|
| - result_iterator,
|
| - ppapi::ScopedPPVar(PP_MakeInt32(NPVARIANT_TO_INT32(*variant))),
|
| - true);
|
| - return;
|
| - case NPVariantType_Double:
|
| - NPVariantToPPVarComplete(
|
| - result_iterator,
|
| - ppapi::ScopedPPVar(PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant))),
|
| - true);
|
| - return;
|
| - case NPVariantType_String:
|
| - NPVariantToPPVarComplete(
|
| - result_iterator,
|
| - ppapi::ScopedPPVar(ppapi::ScopedPPVar::PassRef(),
|
| - StringVar::StringToPPVar(
|
| - NPVARIANT_TO_STRING(*variant).UTF8Characters,
|
| - NPVARIANT_TO_STRING(*variant).UTF8Length)),
|
| - true);
|
| - return;
|
| - case NPVariantType_Object: {
|
| - // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
|
| - // shouldn't result in a deep copy.
|
| - v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
|
| - V8VarConverter(instance_->pp_instance())
|
| - .FromV8Value(v8_value,
|
| - v8::Isolate::GetCurrent()->GetCurrentContext(),
|
| - base::Bind(&MessageChannel::NPVariantToPPVarComplete,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - result_iterator));
|
| - return;
|
| - }
|
| +void MessageChannel::EnqueuePluginMessage(const NPVariant* variant) {
|
| + plugin_message_queue_.push_back(VarConversionResult());
|
| + if (variant->type == NPVariantType_Object) {
|
| + // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary,
|
| + // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var,
|
| + // which we don't support for Messaging.
|
| +
|
| + // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
|
| + // won't result in a deep copy.
|
| + v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
|
| + V8VarConverter v8_var_converter(instance_->pp_instance());
|
| + v8_var_converter.FromV8Value(
|
| + v8_value,
|
| + v8::Isolate::GetCurrent()->GetCurrentContext(),
|
| + base::Bind(&MessageChannel::FromV8ValueComplete,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + &plugin_message_queue_.back()));
|
| + } else {
|
| + plugin_message_queue_.back().ConversionCompleted(
|
| + ScopedPPVar(ScopedPPVar::PassRef(),
|
| + NPVariantToPPVar(instance(), variant)),
|
| + true);
|
| + DCHECK(plugin_message_queue_.back().var().get().type != PP_VARTYPE_OBJECT);
|
| }
|
| - NPVariantToPPVarComplete(
|
| - result_iterator, ppapi::ScopedPPVar(PP_MakeUndefined()), false);
|
| }
|
|
|
| void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
|
| @@ -409,82 +340,69 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
|
| WebSerializedScriptValue serialized_val =
|
| WebSerializedScriptValue::serialize(v8_val);
|
|
|
| - if (instance_->module()->IsProxied()) {
|
| - if (early_message_queue_state_ != SEND_DIRECTLY) {
|
| - // We can't just PostTask here; the messages would arrive out of
|
| - // order. Instead, we queue them up until we're ready to post
|
| - // them.
|
| - early_message_queue_.push_back(serialized_val);
|
| - } else {
|
| - // The proxy sent an asynchronous message, so the plugin is already
|
| - // unblocked. Therefore, there's no need to PostTask.
|
| - DCHECK(early_message_queue_.size() == 0);
|
| - PostMessageToJavaScriptImpl(serialized_val);
|
| - }
|
| + if (early_message_queue_state_ != SEND_DIRECTLY) {
|
| + // We can't just PostTask here; the messages would arrive out of
|
| + // order. Instead, we queue them up until we're ready to post
|
| + // them.
|
| + early_message_queue_.push_back(serialized_val);
|
| } else {
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&MessageChannel::PostMessageToJavaScriptImpl,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - serialized_val));
|
| + // The proxy sent an asynchronous message, so the plugin is already
|
| + // unblocked. Therefore, there's no need to PostTask.
|
| + DCHECK(early_message_queue_.empty());
|
| + PostMessageToJavaScriptImpl(serialized_val);
|
| }
|
| }
|
|
|
| -void MessageChannel::StopQueueingJavaScriptMessages() {
|
| +void MessageChannel::Start() {
|
| // We PostTask here instead of draining the message queue directly
|
| // since we haven't finished initializing the PepperWebPluginImpl yet, so
|
| // the plugin isn't available in the DOM.
|
| - early_message_queue_state_ = DRAIN_PENDING;
|
| base::MessageLoop::current()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&MessageChannel::DrainEarlyMessageQueue,
|
| weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| -void MessageChannel::QueueJavaScriptMessages() {
|
| - if (early_message_queue_state_ == DRAIN_PENDING)
|
| - early_message_queue_state_ = DRAIN_CANCELLED;
|
| - else
|
| - early_message_queue_state_ = QUEUE_MESSAGES;
|
| +void MessageChannel::FromV8ValueComplete(VarConversionResult* result_holder,
|
| + const ScopedPPVar& result,
|
| + bool success) {
|
| + result_holder->ConversionCompleted(result, success);
|
| + DrainCompletedPluginMessages();
|
| }
|
|
|
| -void MessageChannel::NPVariantToPPVarComplete(
|
| - const std::list<VarConversionResult>::iterator& result_iterator,
|
| - const ppapi::ScopedPPVar& result,
|
| - bool success) {
|
| - *result_iterator = VarConversionResult(result, success);
|
| - std::list<VarConversionResult>::iterator it = converted_var_queue_.begin();
|
| - while (it != converted_var_queue_.end() && it->conversion_completed) {
|
| - if (it->success) {
|
| - PostMessageToNative(it->result.get());
|
| +void MessageChannel::DrainCompletedPluginMessages() {
|
| + if (early_message_queue_state_ == QUEUE_MESSAGES)
|
| + return;
|
| +
|
| + while (!plugin_message_queue_.empty() &&
|
| + plugin_message_queue_.front().conversion_completed()) {
|
| + const VarConversionResult& front = plugin_message_queue_.front();
|
| + if (front.success()) {
|
| + instance_->HandleMessage(front.var());
|
| } else {
|
| PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(),
|
| PP_LOGLEVEL_ERROR,
|
| std::string(),
|
| kV8ToVarConversionError);
|
| }
|
| -
|
| - converted_var_queue_.erase(it++);
|
| + plugin_message_queue_.pop_front();
|
| }
|
| }
|
|
|
| void MessageChannel::DrainEarlyMessageQueue() {
|
| + DCHECK(early_message_queue_state_ == QUEUE_MESSAGES);
|
| +
|
| // Take a reference on the PluginInstance. This is because JavaScript code
|
| // may delete the plugin, which would destroy the PluginInstance and its
|
| // corresponding MessageChannel.
|
| scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_);
|
| -
|
| - if (early_message_queue_state_ == DRAIN_CANCELLED) {
|
| - early_message_queue_state_ = QUEUE_MESSAGES;
|
| - return;
|
| - }
|
| - DCHECK(early_message_queue_state_ == DRAIN_PENDING);
|
| -
|
| while (!early_message_queue_.empty()) {
|
| PostMessageToJavaScriptImpl(early_message_queue_.front());
|
| early_message_queue_.pop_front();
|
| }
|
| early_message_queue_state_ = SEND_DIRECTLY;
|
| +
|
| + DrainCompletedPluginMessages();
|
| }
|
|
|
| void MessageChannel::PostMessageToJavaScriptImpl(
|
| @@ -515,30 +433,12 @@ void MessageChannel::PostMessageToJavaScriptImpl(
|
| // at least, postMessage on Workers does not provide the origin or source.
|
| // TODO(dmichael): Add origin if we change to a more iframe-like origin
|
| // policy (see crbug.com/81537)
|
| -
|
| container->element().dispatchEvent(msg_event);
|
| }
|
|
|
| -void MessageChannel::PostMessageToNative(PP_Var message_data) {
|
| - if (instance_->module()->IsProxied()) {
|
| - // In the proxied case, the copy will happen via serializiation, and the
|
| - // message is asynchronous. Therefore there's no need to copy the Var, nor
|
| - // to PostTask.
|
| - PostMessageToNativeImpl(message_data);
|
| - } else {
|
| - // Make a copy of the message data for the Task we will run.
|
| - PP_Var var_copy(CopyPPVar(message_data));
|
| -
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&MessageChannel::PostMessageToNativeImpl,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - var_copy));
|
| - }
|
| -}
|
| -
|
| -void MessageChannel::PostMessageToNativeImpl(PP_Var message_data) {
|
| - instance_->HandleMessage(message_data);
|
| +void MessageChannel::PostMessageToNative(const NPVariant* message_data) {
|
| + EnqueuePluginMessage(message_data);
|
| + DrainCompletedPluginMessages();
|
| }
|
|
|
| MessageChannel::~MessageChannel() {
|
| @@ -565,7 +465,7 @@ void MessageChannel::SetPassthroughObject(NPObject* passthrough) {
|
|
|
| bool MessageChannel::GetReadOnlyProperty(NPIdentifier key,
|
| NPVariant* value) const {
|
| - std::map<NPIdentifier, ppapi::ScopedPPVar>::const_iterator it =
|
| + std::map<NPIdentifier, ScopedPPVar>::const_iterator it =
|
| internal_properties_.find(key);
|
| if (it != internal_properties_.end()) {
|
| if (value)
|
| @@ -576,7 +476,7 @@ bool MessageChannel::GetReadOnlyProperty(NPIdentifier key,
|
| }
|
|
|
| void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) {
|
| - internal_properties_[PPVarToNPIdentifier(key)] = ppapi::ScopedPPVar(value);
|
| + internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value);
|
| }
|
|
|
| } // namespace content
|
|
|