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:
chrome/test/ui
ppapi/tests
webkit/plugins/ppapi
@ -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);
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user