| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ppapi/proxy/ppp_class_proxy.h" |
| |
| #include "ppapi/c/dev/ppb_var_deprecated.h" |
| #include "ppapi/c/dev/ppp_class_deprecated.h" |
| #include "ppapi/c/pp_var.h" |
| #include "ppapi/proxy/dispatcher.h" |
| #include "ppapi/proxy/plugin_globals.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| #include "ppapi/proxy/serialized_var.h" |
| #include "ppapi/shared_impl/api_id.h" |
| #include "ppapi/shared_impl/proxy_lock.h" |
| |
| namespace ppapi { |
| namespace proxy { |
| |
| namespace { |
| |
| // PPP_Class in the browser implementation ------------------------------------- |
| |
| // Represents a plugin-implemented class in the browser process. This just |
| // stores the data necessary to call back the plugin. |
| struct ObjectProxy { |
| ObjectProxy(Dispatcher* d, int64_t p, int64_t ud) |
| : dispatcher(d), ppp_class(p), user_data(ud) {} |
| |
| Dispatcher* dispatcher; |
| int64_t ppp_class; |
| int64_t user_data; |
| }; |
| |
| ObjectProxy* ToObjectProxy(void* data) { |
| ObjectProxy* obj = reinterpret_cast<ObjectProxy*>(data); |
| if (!obj || !obj->dispatcher) |
| return NULL; |
| if (!obj->dispatcher->permissions().HasPermission(PERMISSION_FLASH)) |
| return NULL; |
| return obj; |
| } |
| |
| bool HasProperty(void* object, PP_Var name, PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return false; |
| |
| bool result = false; |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, name), &se, &result)); |
| return result; |
| } |
| |
| bool HasMethod(void* object, PP_Var name, PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return false; |
| |
| bool result = false; |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, name), &se, &result)); |
| return result; |
| } |
| |
| PP_Var GetProperty(void* object, |
| PP_Var name, |
| PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| ReceiveSerializedVarReturnValue result; |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, name), &se, &result)); |
| return result.Return(obj->dispatcher); |
| } |
| |
| void GetAllPropertyNames(void* object, |
| uint32_t* property_count, |
| PP_Var** properties, |
| PP_Var* exception) { |
| NOTIMPLEMENTED(); |
| // TODO(brettw) implement this. |
| } |
| |
| void SetProperty(void* object, |
| PP_Var name, |
| PP_Var value, |
| PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return; |
| |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, name), |
| SerializedVarSendInput(obj->dispatcher, value), &se)); |
| } |
| |
| void RemoveProperty(void* object, |
| PP_Var name, |
| PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return; |
| |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, name), &se)); |
| } |
| |
| PP_Var Call(void* object, |
| PP_Var method_name, |
| uint32_t argc, |
| PP_Var* argv, |
| PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedVarReturnValue result; |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| std::vector<SerializedVar> argv_vect; |
| SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, |
| &argv_vect); |
| |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_Call( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data, |
| SerializedVarSendInput(obj->dispatcher, method_name), argv_vect, |
| &se, &result)); |
| return result.Return(obj->dispatcher); |
| } |
| |
| PP_Var Construct(void* object, |
| uint32_t argc, |
| PP_Var* argv, |
| PP_Var* exception) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedVarReturnValue result; |
| ReceiveSerializedException se(obj->dispatcher, exception); |
| std::vector<SerializedVar> argv_vect; |
| SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc, |
| &argv_vect); |
| |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_Construct( |
| API_ID_PPP_CLASS, |
| obj->ppp_class, obj->user_data, argv_vect, &se, &result)); |
| return result.Return(obj->dispatcher); |
| } |
| |
| void Deallocate(void* object) { |
| ObjectProxy* obj = ToObjectProxy(object); |
| if (!obj) |
| return; |
| |
| obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate( |
| API_ID_PPP_CLASS, obj->ppp_class, obj->user_data)); |
| delete obj; |
| } |
| |
| const PPP_Class_Deprecated class_interface = { |
| &HasProperty, |
| &HasMethod, |
| &GetProperty, |
| &GetAllPropertyNames, |
| &SetProperty, |
| &RemoveProperty, |
| &Call, |
| &Construct, |
| &Deallocate |
| }; |
| |
| // Plugin helper functions ----------------------------------------------------- |
| |
| // Converts an int64_t object from IPC to a PPP_Class* for calling into the |
| // plugin's implementation. |
| const PPP_Class_Deprecated* ToPPPClass(int64_t value) { |
| return reinterpret_cast<const PPP_Class_Deprecated*>( |
| static_cast<intptr_t>(value)); |
| } |
| |
| // Converts an int64_t object from IPC to a void* for calling into the plugin's |
| // implementation as the user data. |
| void* ToUserData(int64_t value) { |
| return reinterpret_cast<void*>(static_cast<intptr_t>(value)); |
| } |
| |
| } // namespace |
| |
| // PPP_Class_Proxy ------------------------------------------------------------- |
| |
| PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher) |
| : InterfaceProxy(dispatcher) { |
| } |
| |
| PPP_Class_Proxy::~PPP_Class_Proxy() { |
| } |
| |
| // static |
| InterfaceProxy* PPP_Class_Proxy::Create(Dispatcher* dispatcher) { |
| return new PPP_Class_Proxy(dispatcher); |
| } |
| |
| // static |
| PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var, |
| Dispatcher* dispatcher, |
| PP_Instance instance_id, |
| int64_t ppp_class, |
| int64_t class_data) { |
| ObjectProxy* object_proxy = new ObjectProxy(dispatcher, |
| ppp_class, class_data); |
| return var->CreateObject(instance_id, &class_interface, object_proxy); |
| } |
| |
| // static |
| PP_Bool PPP_Class_Proxy::IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl, |
| const PP_Var& var, |
| int64_t ppp_class, |
| int64_t* ppp_class_data) { |
| void* proxied_object = NULL; |
| if (ppb_var_impl->IsInstanceOf(var, |
| &class_interface, |
| &proxied_object)) { |
| if (static_cast<ObjectProxy*>(proxied_object)->ppp_class == ppp_class) { |
| DCHECK(ppp_class_data); |
| *ppp_class_data = static_cast<ObjectProxy*>(proxied_object)->user_data; |
| return PP_TRUE; |
| } |
| } |
| return PP_FALSE; |
| } |
| |
| bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| if (!dispatcher()->IsPlugin()) |
| return false; // These messages are only valid from host->plugin. |
| |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(PPP_Class_Proxy, msg) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasProperty, |
| OnMsgHasProperty) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasMethod, |
| OnMsgHasMethod) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_GetProperty, |
| OnMsgGetProperty) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_EnumerateProperties, |
| OnMsgEnumerateProperties) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_SetProperty, |
| OnMsgSetProperty) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Call, |
| OnMsgCall) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Construct, |
| OnMsgConstruct) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Deallocate, |
| OnMsgDeallocate) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void PPP_Class_Proxy::OnMsgHasProperty(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput property, |
| SerializedVarOutParam exception, |
| bool* result) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty, |
| ToUserData(object), |
| property.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPP_Class_Proxy::OnMsgHasMethod(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput property, |
| SerializedVarOutParam exception, |
| bool* result) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod, |
| ToUserData(object), |
| property.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPP_Class_Proxy::OnMsgGetProperty(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput property, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| result.Return(dispatcher(), CallWhileUnlocked( |
| ToPPPClass(ppp_class)->GetProperty, |
| ToUserData(object), property.Get(dispatcher()), |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPP_Class_Proxy::OnMsgEnumerateProperties( |
| int64_t ppp_class, |
| int64_t object, |
| std::vector<SerializedVar>* props, |
| SerializedVarOutParam exception) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| NOTIMPLEMENTED(); |
| // TODO(brettw) implement this. |
| } |
| |
| void PPP_Class_Proxy::OnMsgSetProperty(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput property, |
| SerializedVarReceiveInput value, |
| SerializedVarOutParam exception) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty, |
| ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPP_Class_Proxy::OnMsgRemoveProperty(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput property, |
| SerializedVarOutParam exception) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty, |
| ToUserData(object), property.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPP_Class_Proxy::OnMsgCall(int64_t ppp_class, |
| int64_t object, |
| SerializedVarReceiveInput method_name, |
| SerializedVarVectorReceiveInput arg_vector, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| uint32_t arg_count = 0; |
| PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); |
| result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call, |
| ToUserData(object), method_name.Get(dispatcher()), |
| arg_count, args, exception.OutParam(dispatcher()))); |
| } |
| |
| void PPP_Class_Proxy::OnMsgConstruct(int64_t ppp_class, |
| int64_t object, |
| SerializedVarVectorReceiveInput arg_vector, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| if (!ValidateUserData(ppp_class, object, &exception)) |
| return; |
| uint32_t arg_count = 0; |
| PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); |
| result.Return(dispatcher(), CallWhileUnlocked( |
| ToPPPClass(ppp_class)->Construct, |
| ToUserData(object), arg_count, args, exception.OutParam(dispatcher()))); |
| } |
| |
| void PPP_Class_Proxy::OnMsgDeallocate(int64_t ppp_class, int64_t object) { |
| if (!ValidateUserData(ppp_class, object, NULL)) |
| return; |
| PluginGlobals::Get()->plugin_var_tracker()->PluginImplementedObjectDestroyed( |
| ToUserData(object)); |
| CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object)); |
| } |
| |
| bool PPP_Class_Proxy::ValidateUserData(int64_t ppp_class, |
| int64_t class_data, |
| SerializedVarOutParam* exception) { |
| if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall( |
| ToPPPClass(ppp_class), ToUserData(class_data))) { |
| // Set the exception. This is so the caller will know about the error and |
| // also that we won't assert that somebody forgot to call OutParam on the |
| // output parameter. Although this exception of "1" won't be very useful |
| // this shouldn't happen in normal usage, only when the renderer is being |
| // malicious. |
| if (exception) |
| *exception->OutParam(dispatcher()) = PP_MakeInt32(1); |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace proxy |
| } // namespace ppapi |