0

Make PPAPI PostMessage behave asynchronously.

Add PostMessage test to ppapi_uitest.cc.

BUG=None
TEST=test_post_message.cc
Review URL: http://codereview.chromium.org/6745015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79497 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
dmichael@google.com
2011-03-26 20:56:35 +00:00
parent 3aded7fb5d
commit f1ced92024
4 changed files with 91 additions and 15 deletions

@ -154,6 +154,10 @@ TEST_F(PPAPITest, Var) {
RunTest("Var");
}
TEST_F(PPAPITest, PostMessage) {
RunTest("PostMessage");
}
TEST_F(PPAPITest, FileIO) {
RunTestViaHTTP("FileIO");
}

@ -51,6 +51,7 @@ void TestPostMessage::RunTest() {
void TestPostMessage::HandleMessage(const pp::Var& message_data) {
message_data_.push_back(message_data);
testing_interface_->QuitMessageLoop(instance_->pp_instance());
}
bool TestPostMessage::MakeOnMessageEcho(const std::string& expression) {
@ -74,20 +75,26 @@ std::string TestPostMessage::TestSendingData() {
// the data back to us, and we check that they match.
message_data_.clear();
instance_->PostMessage(pp::Var(kTestString));
// Note that the trusted in-process version is completely synchronous, so we
// do not need to use 'RunMessageLoop' to wait.
// PostMessage is asynchronous, so we should not receive a response yet.
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_string());
ASSERT_EQ(message_data_.back().AsString(), kTestString);
message_data_.clear();
instance_->PostMessage(pp::Var(kTestBool));
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_bool());
ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_number());
ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(),
@ -95,17 +102,23 @@ std::string TestPostMessage::TestSendingData() {
message_data_.clear();
instance_->PostMessage(pp::Var(kTestDouble));
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_number());
ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
message_data_.clear();
instance_->PostMessage(pp::Var());
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_undefined());
message_data_.clear();
instance_->PostMessage(pp::Var(pp::Var::Null()));
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_null());
@ -121,6 +134,8 @@ std::string TestPostMessage::TestMessageEvent() {
ASSERT_TRUE(MakeOnMessageEcho("typeof(message_event)"));
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_string());
ASSERT_EQ(message_data_.back().AsString(), "object");
@ -136,8 +151,8 @@ std::string TestPostMessage::TestMessageEvent() {
ASSERT_TRUE(success);
message_data_.clear();
instance_->PostMessage(pp::Var(kTestInt));
// Note that the trusted in-process version is completely synchronous, so we
// do not need to use 'RunMessageLoop' to wait.
ASSERT_EQ(message_data_.size(), 0);
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 1);
ASSERT_TRUE(message_data_.back().is_bool());
ASSERT_TRUE(message_data_.back().AsBool());
@ -159,6 +174,7 @@ std::string TestPostMessage::TestNoHandler() {
// don't crash).
message_data_.clear();
instance_->PostMessage(pp::Var());
testing_interface_->RunMessageLoop(instance_->pp_instance());
ASSERT_EQ(message_data_.size(), 0);
PASS();

@ -8,6 +8,7 @@
#include <string>
#include "base/logging.h"
#include "base/message_loop.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"
@ -78,7 +79,7 @@ bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
}
case PP_VARTYPE_OBJECT:
// Objects are not currently supported.
DCHECK(false);
NOTIMPLEMENTED();
VOID_TO_NPVARIANT(*result);
return false;
default:
@ -88,6 +89,27 @@ bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
return true;
}
// 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.
//
// TODO(dmichael): We need to do structured clone eventually to copy a object
// structure. The details and PPAPI changes for this are TBD.
PP_Var CopyPPVar(const PP_Var& var) {
if (var.type == PP_VARTYPE_OBJECT) {
// Objects are not currently supported.
NOTIMPLEMENTED();
return PP_MakeUndefined();
} else if (var.type == PP_VARTYPE_STRING) {
scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
if (!string)
return PP_MakeUndefined();
return StringVar::StringToPPVar(string->module(), string->value());
} else {
return var;
}
}
//------------------------------------------------------------------------------
// Implementations of NPClass functions. These are here to:
// - Implement postMessage behavior.
@ -256,7 +278,8 @@ MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
MessageChannel::MessageChannel(PluginInstance* instance)
: instance_(instance),
passthrough_object_(NULL),
np_object_(NULL) {
np_object_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
VOID_TO_NPVARIANT(onmessage_invoker_);
// Now create an NPObject for receiving calls to postMessage.
@ -306,8 +329,18 @@ bool MessageChannel::EvaluateOnMessageInvoker() {
}
void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
// Make sure we have our function for invoking a JavaScript onmessage
// function.
// Make a copy of the message data for the Task we will run.
PP_Var var_copy(CopyPPVar(message_data));
MessageLoop::current()->PostTask(
FROM_HERE,
method_factory_.NewRunnableMethod(
&MessageChannel::PostMessageToJavaScriptImpl,
var_copy));
}
void MessageChannel::PostMessageToJavaScriptImpl(PP_Var message_data) {
// Make sure we have our function for invoking onmessage on JavaScript.
bool success = EvaluateOnMessageInvoker();
DCHECK(success);
if (!success)
@ -320,13 +353,8 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
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.
// Convert message to an NPVariant without copying. At this point, the data
// has already been copied.
if (!PPVarToNPVariantNoCopy(message_data, &npvariant_args[1]))
return;
@ -338,6 +366,16 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
}
void MessageChannel::PostMessageToNative(PP_Var message_data) {
// Make a copy of the message data for the Task we will run.
PP_Var var_copy(CopyPPVar(message_data));
MessageLoop::current()->PostTask(FROM_HERE,
method_factory_.NewRunnableMethod(
&MessageChannel::PostMessageToNativeImpl,
var_copy));
}
void MessageChannel::PostMessageToNativeImpl(PP_Var message_data) {
instance_->HandleMessage(message_data);
}

@ -5,6 +5,7 @@
#ifndef WEBKIT_PLUGINS_PPAPI_MESSAGE_CHANNEL_H_
#define WEBKIT_PLUGINS_PPAPI_MESSAGE_CHANNEL_H_
#include "base/task.h"
#include "third_party/npapi/bindings/npruntime.h"
#include "webkit/plugins/ppapi/resource.h"
@ -44,7 +45,11 @@ class MessageChannel {
explicit MessageChannel(PluginInstance* instance);
~MessageChannel();
// Post a message to the onmessage handler for this channel's instance
// asynchronously.
void PostMessageToJavaScript(PP_Var message_data);
// Post a message to the PPP_Instance HandleMessage function for this
// channel's instance.
void PostMessageToNative(PP_Var message_data);
// Return the NPObject* to which we should forward any calls which aren't
@ -81,8 +86,21 @@ class MessageChannel {
// to a JavaScript target.
NPVariant onmessage_invoker_;
// Evaluates the JavaScript code for onmessage_invoker_ and makes
// it a callable NPVariant for that function. Returns true on success, false
// otherwise.
bool EvaluateOnMessageInvoker();
// Post a message to the onmessage handler for this channel's instance
// synchronously. This is used by PostMessageToJavaScript.
void PostMessageToJavaScriptImpl(PP_Var message_data);
// Post a message to the PPP_Instance HandleMessage function for this
// channel's instance. This is used by PostMessageToNative.
void PostMessageToNativeImpl(PP_Var message_data);
// Ensure pending tasks will not fire after this object is destroyed.
ScopedRunnableMethodFactory<MessageChannel> method_factory_;
DISALLOW_COPY_AND_ASSIGN(MessageChannel);
};