blob: 1850dc0fd46e76c1526367288ff07f1f5da20266 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ppapi/proxy/ppb_var_deprecated_proxy.h"
#include <stdlib.h> // For malloc
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "ppapi/c/dev/ppb_var_deprecated.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb_core.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/plugin_var_tracker.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppp_class_proxy.h"
#include "ppapi/proxy/serialized_var.h"
#include "ppapi/shared_impl/var.h"
namespace ppapi {
namespace proxy {
namespace {
// Used to do get the set-up information for calling a var object. If the
// exception is set, returns NULL. Otherwise, computes the dispatcher for the
// given var object. If the var is not a valid object, returns NULL and sets
// the exception.
PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object,
PP_Var* exception) {
// If an exception is already set, we don't need to do anything, just return
// an error to the caller.
if (exception && exception->type != PP_VARTYPE_UNDEFINED)
return NULL;
if (object.type == PP_VARTYPE_OBJECT) {
// Get the dispatcher for the object.
PluginDispatcher* dispatcher = PluginResourceTracker::GetInstance()->
var_tracker().DispatcherForPluginObject(object);
if (dispatcher)
return dispatcher;
}
// The object is invalid. This means we can't figure out which dispatcher
// to use, which is OK because the call will fail anyway. Set the exception.
if (exception) {
*exception = StringVar::StringToPPVar(0,
std::string("Attempting to use an invalid object"));
}
return NULL;
}
// PPP_Var_Deprecated plugin ---------------------------------------------------
void AddRefVar(PP_Var var) {
PluginResourceTracker::GetInstance()->var_tracker().AddRefVar(var);
}
void ReleaseVar(PP_Var var) {
PluginResourceTracker::GetInstance()->var_tracker().ReleaseVar(var);
}
PP_Var VarFromUtf8(PP_Module module, const char* data, uint32_t len) {
return StringVar::StringToPPVar(module, data, len);
}
const char* VarToUtf8(PP_Var var, uint32_t* len) {
StringVar* str = StringVar::FromPPVar(var);
if (str) {
*len = static_cast<uint32_t>(str->value().size());
return str->value().c_str();
}
*len = 0;
return NULL;
}
bool HasProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher)
return false;
ReceiveSerializedException se(dispatcher, exception);
PP_Bool result = PP_FALSE;
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
SerializedVarSendInput(dispatcher, name), &se, &result));
}
return PP_ToBool(result);
}
bool HasMethod(PP_Var var,
PP_Var name,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher)
return false;
ReceiveSerializedException se(dispatcher, exception);
PP_Bool result = PP_FALSE;
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
SerializedVarSendInput(dispatcher, name), &se, &result));
}
return PP_ToBool(result);
}
PP_Var GetProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher)
return PP_MakeUndefined();
ReceiveSerializedException se(dispatcher, exception);
ReceiveSerializedVarReturnValue result;
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
SerializedVarSendInput(dispatcher, name), &se, &result));
}
return result.Return(dispatcher);
}
void EnumerateProperties(PP_Var var,
uint32_t* property_count,
PP_Var** properties,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher) {
*property_count = 0;
*properties = NULL;
return;
}
ReceiveSerializedVarVectorOutParam out_vector(dispatcher,
property_count, properties);
ReceiveSerializedException se(dispatcher, exception);
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
out_vector.OutParam(), &se));
}
}
void SetProperty(PP_Var var,
PP_Var name,
PP_Var value,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher)
return;
ReceiveSerializedException se(dispatcher, exception);
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
SerializedVarSendInput(dispatcher, name),
SerializedVarSendInput(dispatcher, value), &se));
}
}
void RemoveProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
if (!dispatcher)
return;
ReceiveSerializedException se(dispatcher, exception);
PP_Bool result = PP_FALSE;
if (!se.IsThrown()) {
dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, var),
SerializedVarSendInput(dispatcher, name), &se, &result));
}
}
PP_Var Call(PP_Var object,
PP_Var method_name,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
if (!dispatcher)
return PP_MakeUndefined();
ReceiveSerializedVarReturnValue result;
ReceiveSerializedException se(dispatcher, exception);
if (!se.IsThrown()) {
std::vector<SerializedVar> argv_vect;
SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect);
dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, object),
SerializedVarSendInput(dispatcher, method_name), argv_vect,
&se, &result));
}
return result.Return(dispatcher);
}
PP_Var Construct(PP_Var object,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
if (!dispatcher)
return PP_MakeUndefined();
ReceiveSerializedVarReturnValue result;
ReceiveSerializedException se(dispatcher, exception);
if (!se.IsThrown()) {
std::vector<SerializedVar> argv_vect;
SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect);
dispatcher->Send(new PpapiHostMsg_PPBVar_Construct(
INTERFACE_ID_PPB_VAR_DEPRECATED,
SerializedVarSendInput(dispatcher, object),
argv_vect, &se, &result));
}
return result.Return(dispatcher);
}
bool IsInstanceOf(PP_Var var,
const PPP_Class_Deprecated* ppp_class,
void** ppp_class_data) {
Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL);
if (!dispatcher)
return false;
PP_Bool result = PP_FALSE;
int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class));
int64 class_data_int = 0;
dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated(
INTERFACE_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var),
class_int, &class_data_int, &result));
*ppp_class_data =
reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int));
return PP_ToBool(result);
}
PP_Var CreateObject(PP_Instance instance,
const PPP_Class_Deprecated* ppp_class,
void* ppp_class_data) {
Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
if (!dispatcher)
return PP_MakeUndefined();
ReceiveSerializedVarReturnValue result;
int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class));
int64 data_int =
static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class_data));
dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated(
INTERFACE_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int,
&result));
return result.Return(dispatcher);
}
const PPB_Var_Deprecated var_deprecated_interface = {
&AddRefVar,
&ReleaseVar,
&VarFromUtf8,
&VarToUtf8,
&HasProperty,
&HasMethod,
&GetProperty,
&EnumerateProperties,
&SetProperty,
&RemoveProperty,
&Call,
&Construct,
&IsInstanceOf,
&CreateObject
};
InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) {
return new PPB_Var_Deprecated_Proxy(dispatcher );
}
} // namespace
PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy(
Dispatcher* dispatcher)
: InterfaceProxy(dispatcher),
task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
ppb_var_impl_(NULL) {
if (!dispatcher->IsPlugin()) {
ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>(
dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE));
}
}
PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
}
// static
const InterfaceProxy::Info* PPB_Var_Deprecated_Proxy::GetInfo() {
static const Info info = {
&var_deprecated_interface,
PPB_VAR_DEPRECATED_INTERFACE,
INTERFACE_ID_PPB_VAR_DEPRECATED,
false,
&CreateVarDeprecatedProxy,
};
return &info;
}
bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) {
// Prevent the dispatcher from going away during a call to Call or other
// function that could mutate the DOM. This must happen OUTSIDE of
// the message handlers since the SerializedVars use the dispatcher upon
// return of the function (converting the SerializedVarReturnValue/OutParam
// to a SerializedVar in the destructor).
ScopedModuleReference death_grip(dispatcher());
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty,
OnMsgHasProperty)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated,
OnMsgHasMethodDeprecated)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty,
OnMsgGetProperty)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty,
OnMsgDeleteProperty)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties,
OnMsgEnumerateProperties)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated,
OnMsgSetPropertyDeprecated)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated,
OnMsgCallDeprecated)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct,
OnMsgConstruct)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated,
OnMsgIsInstanceOfDeprecated)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated,
OnMsgCreateObjectDeprecated)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
// TODO(brettw) handle bad messages!
return handled;
}
void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id,
int* /* unused */) {
PP_Var var;
var.type = PP_VARTYPE_OBJECT;
var.value.as_id = object_id;
ppb_var_impl_->AddRef(var);
}
void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) {
// Ok, so this is super subtle.
// When the browser side sends a sync IPC message that returns a var, and the
// plugin wants to give ownership of that var to the browser, dropping all
// references, it may call ReleaseObject right after returning the result.
// However, the IPC system doesn't enforce strict ordering of messages in that
// case, where a message that is set to unblock (e.g. a sync message, or in
// our case all messages coming from the plugin) that is sent *after* the
// result may be dispatched on the browser side *before* the sync send
// returned (see ipc_sync_channel.cc). In this case, that means it could
// release the object before it is AddRef'ed on the browser side.
// To work around this, we post a task here, that will not execute before
// control goes back to the main message loop, that will ensure the sync send
// has returned and the browser side can take its reference before we Release.
// Note: if the instance is gone by the time the task is executed, then it
// will Release the objects itself and this Release will be a NOOP (aside of a
// spurious warning).
// TODO(piman): See if we can fix the IPC code to enforce strict ordering, and
// then remove this.
MessageLoop::current()->PostNonNestableTask(FROM_HERE,
task_factory_.NewRunnableMethod(
&PPB_Var_Deprecated_Proxy::DoReleaseObject, object_id));
}
void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
SerializedVarReceiveInput var,
SerializedVarReceiveInput name,
SerializedVarOutParam exception,
PP_Bool* result) {
SetAllowPluginReentrancy();
*result = PP_FromBool(ppb_var_impl_->HasProperty(
var.Get(dispatcher()),
name.Get(dispatcher()),
exception.OutParam(dispatcher())));
}
void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
SerializedVarReceiveInput var,
SerializedVarReceiveInput name,
SerializedVarOutParam exception,
PP_Bool* result) {
SetAllowPluginReentrancy();
*result = PP_FromBool(ppb_var_impl_->HasMethod(
var.Get(dispatcher()),
name.Get(dispatcher()),
exception.OutParam(dispatcher())));
}
void PPB_Var_Deprecated_Proxy::OnMsgGetProperty(
SerializedVarReceiveInput var,
SerializedVarReceiveInput name,
SerializedVarOutParam exception,
SerializedVarReturnValue result) {
SetAllowPluginReentrancy();
result.Return(dispatcher(), ppb_var_impl_->GetProperty(
var.Get(dispatcher()), name.Get(dispatcher()),
exception.OutParam(dispatcher())));
}
void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties(
SerializedVarReceiveInput var,
SerializedVarVectorOutParam props,
SerializedVarOutParam exception) {
SetAllowPluginReentrancy();
ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()),
props.CountOutParam(), props.ArrayOutParam(dispatcher()),
exception.OutParam(dispatcher()));
}
void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated(
SerializedVarReceiveInput var,
SerializedVarReceiveInput name,
SerializedVarReceiveInput value,
SerializedVarOutParam exception) {
SetAllowPluginReentrancy();
ppb_var_impl_->SetProperty(var.Get(dispatcher()),
name.Get(dispatcher()),
value.Get(dispatcher()),
exception.OutParam(dispatcher()));
}
void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
SerializedVarReceiveInput var,
SerializedVarReceiveInput name,
SerializedVarOutParam exception,
PP_Bool* result) {
SetAllowPluginReentrancy();
ppb_var_impl_->RemoveProperty(var.Get(dispatcher()),
name.Get(dispatcher()),
exception.OutParam(dispatcher()));
// This deprecated function doesn't actually return a value, but we re-use
// the message from the non-deprecated interface with the return value.
*result = PP_TRUE;
}
void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated(
SerializedVarReceiveInput object,
SerializedVarReceiveInput method_name,
SerializedVarVectorReceiveInput arg_vector,
SerializedVarOutParam exception,
SerializedVarReturnValue result) {
SetAllowPluginReentrancy();
uint32_t arg_count = 0;
PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
result.Return(dispatcher(), ppb_var_impl_->Call(
object.Get(dispatcher()),
method_name.Get(dispatcher()),
arg_count, args,
exception.OutParam(dispatcher())));
}
void PPB_Var_Deprecated_Proxy::OnMsgConstruct(
SerializedVarReceiveInput var,
SerializedVarVectorReceiveInput arg_vector,
SerializedVarOutParam exception,
SerializedVarReturnValue result) {
SetAllowPluginReentrancy();
uint32_t arg_count = 0;
PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
result.Return(dispatcher(), ppb_var_impl_->Construct(
var.Get(dispatcher()), arg_count, args,
exception.OutParam(dispatcher())));
}
void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
SerializedVarReceiveInput var,
int64 ppp_class,
int64* ppp_class_data,
PP_Bool* result) {
// TODO(brettw) write this.
}
void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
PP_Instance instance,
int64 ppp_class,
int64 class_data,
SerializedVarReturnValue result) {
SetAllowPluginReentrancy();
result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
ppb_var_impl_, dispatcher(), instance, ppp_class, class_data));
}
void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
if (dispatcher()->IsPlugin())
NOTREACHED();
else
static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy();
}
void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) {
PP_Var var;
var.type = PP_VARTYPE_OBJECT;
var.value.as_id = object_id;
ppb_var_impl_->Release(var);
}
} // namespace proxy
} // namespace ppapi