diff options
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/proxy/callback_tracker.cc | 72 | ||||
-rw-r--r-- | ppapi/proxy/callback_tracker.h | 66 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 215 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.h | 187 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.cc | 63 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.h | 61 | ||||
-rw-r--r-- | ppapi/proxy/interface_id.h | 33 | ||||
-rw-r--r-- | ppapi/proxy/interface_proxy.cc | 36 | ||||
-rw-r--r-- | ppapi/proxy/interface_proxy.h | 77 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.cc | 88 | ||||
-rw-r--r-- | ppapi/proxy/plugin_dispatcher.h | 76 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource.cc | 17 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource.h | 64 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource_tracker.cc | 87 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource_tracker.h | 62 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.cc | 13 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.h | 22 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages_internal.h | 321 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_param_traits.cc | 190 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_param_traits.h | 86 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.cc | 457 |
21 files changed, 2293 insertions, 0 deletions
diff --git a/ppapi/proxy/callback_tracker.cc b/ppapi/proxy/callback_tracker.cc new file mode 100644 index 0000000..9806497 --- /dev/null +++ b/ppapi/proxy/callback_tracker.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2010 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/callback_tracker.h" + +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +struct CallbackData { + CallbackTracker* tracker; + uint32_t callback_id; +}; + +void CallbackProxy(void* user_data, int32_t result) { + CallbackData* data = static_cast<CallbackData*>(user_data); + data->tracker->SendExecuteSerializedCallback(data->callback_id, result); + delete data; +} + +} // namespace + +CallbackTracker::CallbackTracker(Dispatcher* dispatcher) + : dispatcher_(dispatcher), + next_callback_id_(1) { +} + +CallbackTracker::~CallbackTracker() { +} + +uint32_t CallbackTracker::SendCallback(PP_CompletionCallback callback) { + // Find the next callback ID we can use (being careful about wraparound). + while (callback_map_.find(next_callback_id_) != callback_map_.end()) + next_callback_id_++; + callback_map_[next_callback_id_] = callback; + return next_callback_id_++; +} + +PP_CompletionCallback CallbackTracker::ReceiveCallback( + uint32_t serialized_callback) { + CallbackData* data = new CallbackData; + data->tracker = this; + data->callback_id = serialized_callback; + return PP_MakeCompletionCallback(&CallbackProxy, data); +} + +void CallbackTracker::SendExecuteSerializedCallback( + uint32_t serialized_callback, + int32_t param) { + dispatcher_->Send(new PpapiMsg_ExecuteCallback(serialized_callback, param)); +} + +void CallbackTracker::ReceiveExecuteSerializedCallback( + uint32_t serialized_callback, + int32_t param) { + CallbackMap::iterator found = callback_map_.find(serialized_callback); + if (found == callback_map_.end()) { + NOTREACHED(); + return; + } + + PP_RunCompletionCallback(&found->second, param); + callback_map_.erase(found); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/callback_tracker.h b/ppapi/proxy/callback_tracker.h new file mode 100644 index 0000000..5f8233c1 --- /dev/null +++ b/ppapi/proxy/callback_tracker.h @@ -0,0 +1,66 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_CALLBACK_TRACKER_H_ +#define PPAPI_PROXY_CALLBACK_TRACKER_H_ + +#include <map> + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_stdint.h" + +namespace pp { +namespace proxy { + +class Dispatcher; + +// This object tracks cross-process callbacks. When the plugin sends a callback +// object to the renderer, we save the information and pass an identifier +// instead. +// +// On the renderer side, this identifier is converted to a new callback in that +// process. When executed, this new callback sends an IPC message containing the +// previous identifier back to the plugin. +// +// When we receive that message, ExecuteSerializedCallback converts the +// identifier back to the original callback information and runs the callback. +class CallbackTracker { + public: + CallbackTracker(Dispatcher* dispatcher); + ~CallbackTracker(); + + // Converts the given callback in the context of the plugin to a serialized + // ID. This will be passed to ReceiveCallback on the renderer side. + uint32_t SendCallback(PP_CompletionCallback callback); + + // Converts the given serialized callback ID to a new completion callback in + // the context of the current process. This callback actually will represent + // a proxy that will execute the callback in the plugin process. + PP_CompletionCallback ReceiveCallback(uint32_t serialized_callback); + + // Sends a request to the remote process to execute the given callback. + void SendExecuteSerializedCallback(uint32_t serialized_callback, + int32_t param); + + // Executes the given callback ID with the given result in the current + // process. This will also destroy the information associated with the + // callback and the serialized ID won't be valid any more. + void ReceiveExecuteSerializedCallback(uint32_t serialized_callback, + int32_t param); + + private: + // Pointer to the dispatcher that owns us. + Dispatcher* dispatcher_; + + int32_t next_callback_id_; + + // Maps callback IDs to the actual callback objects in the plugin process. + typedef std::map<int32_t, PP_CompletionCallback> CallbackMap; + CallbackMap callback_map_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_CALLBACK_TRACKER_H_ diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc new file mode 100644 index 0000000..e2c6f1e --- /dev/null +++ b/ppapi/proxy/dispatcher.cc @@ -0,0 +1,215 @@ +// Copyright (c) 2010 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/dispatcher.h" + +#include <string.h> // For memset. + +#include <map> + +#include "base/logging.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "ppapi/c/ppb_image_data.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/ppb_core_proxy.h" +#include "ppapi/proxy/ppb_graphics_2d_proxy.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppb_var_deprecated_proxy.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/ppp_instance_proxy.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace pp { +namespace proxy { + +Dispatcher::Dispatcher(GetInterfaceFunc local_get_interface) + : pp_module_(0), + disallow_trusted_interfaces_(true), + local_get_interface_(local_get_interface), + declared_supported_remote_interfaces_(false), + callback_tracker_(this) { + memset(id_to_proxy_, 0, + static_cast<int>(INTERFACE_ID_COUNT) * sizeof(InterfaceProxy*)); +} + +Dispatcher::~Dispatcher() { +} + +bool Dispatcher::InitWithChannel(MessageLoop* ipc_message_loop, + const std::string& channel_name, + bool is_client, + base::WaitableEvent* shutdown_event) { + IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT + : IPC::Channel::MODE_SERVER; + channel_.reset(new IPC::SyncChannel(channel_name, mode, this, NULL, + ipc_message_loop, false, shutdown_event)); + return true; +} + +void Dispatcher::OnMessageReceived(const IPC::Message& msg) { + // Control messages. + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + IPC_BEGIN_MESSAGE_MAP(Dispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_DeclareInterfaces, + OnMsgDeclareInterfaces) + IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) + IPC_MESSAGE_FORWARD(PpapiMsg_ExecuteCallback, &callback_tracker_, + CallbackTracker::ReceiveExecuteSerializedCallback) + IPC_END_MESSAGE_MAP() + return; + } + + // Interface-specific messages. + if (msg.routing_id() > 0 && msg.routing_id() < INTERFACE_ID_COUNT) { + InterfaceProxy* proxy = id_to_proxy_[msg.routing_id()]; + if (proxy) + proxy->OnMessageReceived(msg); + else + NOTREACHED(); + // TODO(brettw): kill the plugin if it starts sending invalid messages? + } +} + +void Dispatcher::SetSerializationRules( + VarSerializationRules* var_serialization_rules) { + serialization_rules_.reset(var_serialization_rules); +} + +void Dispatcher::InjectProxy(InterfaceID id, + const std::string& name, + InterfaceProxy* proxy) { + proxies_[name] = linked_ptr<InterfaceProxy>(proxy); + id_to_proxy_[id] = proxy; +} + +const void* Dispatcher::GetLocalInterface(const char* interface) { + return local_get_interface_(interface); +} + +const void* Dispatcher::GetProxiedInterface(const std::string& interface) { + // See if we already know about this interface and have created a host. + ProxyMap::const_iterator found = proxies_.find(interface); + if (found != proxies_.end()) + return found->second->GetSourceInterface(); + + // When the remote side has sent us a declared list of all interfaces it + // supports and we don't have it in our list, we know the requested interface + // doesn't exist and we can return failure. + if (declared_supported_remote_interfaces_) + return NULL; + + if (!RemoteSupportsTargetInterface(interface)) + return NULL; + + linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interface, NULL)); + if (!proxy.get()) + return NULL; // Don't know how to proxy this interface. + + // Save our proxy. + proxies_[interface] = proxy; + id_to_proxy_[proxy->GetInterfaceId()] = proxy.get(); + return proxy->GetSourceInterface(); +} + +bool Dispatcher::Send(IPC::Message* msg) { + return channel_->Send(msg); +} + +bool Dispatcher::RemoteSupportsTargetInterface(const std::string& interface) { + bool result = false; + Send(new PpapiMsg_SupportsInterface(interface, &result)); + return result; +} + +bool Dispatcher::IsInterfaceTrusted(const std::string& interface) { + // FIXME(brettw) + (void)interface; + return false; +} + +bool Dispatcher::SetupProxyForTargetInterface(const std::string& interface) { + // If we already have a proxy that knows about the locally-implemented + // interface, we know it's supported and don't need to re-query. + ProxyMap::const_iterator found = proxies_.find(interface); + if (found != proxies_.end()) + return true; + + if (disallow_trusted_interfaces_ && IsInterfaceTrusted(interface)) + return false; + + // Create the proxy if it doesn't exist and set the local interface on it. + // This also handles the case where possibly an interface could be supported + // by both the local and remote side. + const void* interface_functions = local_get_interface_(interface.c_str()); + if (!interface_functions) + return false; + InterfaceProxy* proxy = CreateProxyForInterface(interface, + interface_functions); + if (!proxy) + return false; + + proxies_[interface] = linked_ptr<InterfaceProxy>(proxy); + id_to_proxy_[proxy->GetInterfaceId()] = proxy; + return true; +} + +void Dispatcher::OnMsgSupportsInterface(const std::string& interface_name, + bool* result) { + *result = SetupProxyForTargetInterface(interface_name); +} + +void Dispatcher::OnMsgDeclareInterfaces( + const std::vector<std::string>& interfaces) { + // Make proxies for all the interfaces it supports that we also support. + for (size_t i = 0; i < interfaces.size(); i++) { + // Possibly the plugin could request an interface before the "declare" + // message is received, so we could already have an entry for this + // interface. In this case, we can just skip to the next one. + if (proxies_.find(interfaces[i]) != proxies_.end()) + continue; + + linked_ptr<InterfaceProxy> proxy(CreateProxyForInterface(interfaces[i], + NULL)); + if (!proxy.get()) { + // Since only the browser declares supported interfaces, we should never + // get one we don't support. + //NOTREACHED() << "Remote side declaring an unsupported proxy."; + continue; + } + proxies_[interfaces[i]] = proxy; + id_to_proxy_[proxy->GetInterfaceId()] = proxy.get(); + } +} + +InterfaceProxy* Dispatcher::CreateProxyForInterface( + const std::string& interface_name, + const void* interface_functions) { + if (interface_name == PPB_CORE_INTERFACE) + return new PPB_Core_Proxy(this, interface_functions); + if (interface_name == PPB_GRAPHICS_2D_INTERFACE) + return new PPB_Graphics2D_Proxy(this, interface_functions); + if (interface_name == PPB_IMAGEDATA_INTERFACE) + return new PPB_ImageData_Proxy(this, interface_functions); + if (interface_name == PPB_INSTANCE_INTERFACE) + return new PPB_Instance_Proxy(this, interface_functions); + if (interface_name == PPB_VAR_DEPRECATED_INTERFACE) + return new PPB_Var_Deprecated_Proxy(this, interface_functions); + if (interface_name == PPP_INSTANCE_INTERFACE) + return new PPP_Instance_Proxy(this, interface_functions); + + return NULL; +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h new file mode 100644 index 0000000..412b2d8 --- /dev/null +++ b/ppapi/proxy/dispatcher.h @@ -0,0 +1,187 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_DISPATCHER_H_ +#define PPAPI_PROXY_DISPATCHER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/linked_ptr.h" +#include "base/scoped_ptr.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/callback_tracker.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +class MessageLoop; +struct PPB_Var_Deprecated; + +namespace base { +class WaitableEvent; +} + +namespace IPC { +class SyncChannel; +} + +namespace pp { +namespace proxy { + +class InterfaceProxy; +class VarSerializationRules; + +// An interface proxy can represent either end of a cross-process interface +// call. The "source" side is where the call is invoked, and the "target" side +// is where the call ends up being executed. +// +// Plugin side | Browser side +// -------------------------------------|-------------------------------------- +// | +// "Source" | "Target" +// InterfaceProxy ----------------------> InterfaceProxy +// | +// | +// "Target" | "Source" +// InterfaceProxy <---------------------- InterfaceProxy +// | +class Dispatcher : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + typedef const void* (*GetInterfaceFunc)(const char*); + typedef const int32_t (*InitModuleFunc)(PP_Module, GetInterfaceFunc); + typedef const void (*ShutdownModuleFunc)(); + + ~Dispatcher(); + + bool InitWithChannel(MessageLoop* ipc_message_loop, + const std::string& channel_name, + bool is_client, + base::WaitableEvent* shutdown_event); + + // Returns true if the dispatcher is on the plugin side, or false if it's the + // browser side. + virtual bool IsPlugin() const = 0; + + VarSerializationRules* serialization_rules() const { + return serialization_rules_.get(); + } + PP_Module pp_module() const { + return pp_module_; + } + + // Wrapper for calling the local GetInterface function. + const void* GetLocalInterface(const char* interface); + + // Implements PPP_GetInterface and PPB_GetInterface on the "source" side. It + // will check if the remote side supports this interface as a target, and + // create a proxy if it does. A local implementation of that interface backed + // by the proxy will be returned on success. If the interface is unproxyable + // or not supported by the remote side, returns NULL. + const void* GetProxiedInterface(const std::string& interface); + + // Called if the remote side is declaring to us which interfaces it supports + // so we don't have to query for each one. We'll pre-create proxies for + // each of the given interfaces. + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // IPC::Channel::Listener implementation. + virtual void OnMessageReceived(const IPC::Message& msg); + + IPC::SyncChannel* channel() const { + return channel_.get(); + } + + CallbackTracker& callback_tracker() { + return callback_tracker_; + } + + protected: + Dispatcher(GetInterfaceFunc local_get_interface); + + // Setter for the derived classes to set the appropriate var serialization. + // Takes ownership of the given pointer, which must be on the heap. + void SetSerializationRules(VarSerializationRules* var_serialization_rules); + + void set_pp_module(PP_Module module) { + pp_module_ = module; + } + + // Allows the PluginDispatcher to add a magic proxy for PPP_Class, bypassing + // the normal "do you support this proxy" stuff and the big lookup of + // name to proxy object. Takes ownership of the pointer. + void InjectProxy(InterfaceID id, + const std::string& name, + InterfaceProxy* proxy); + + private: + typedef std::map< std::string, linked_ptr<InterfaceProxy> > ProxyMap; + + // Message handlers + void OnMsgSupportsInterface(const std::string& interface_name, bool* result); + void OnMsgDeclareInterfaces(const std::vector<std::string>& interfaces); + + // Allocates a new proxy on the heap corresponding to the given interface + // name, or returns NULL if that interface name isn't known proxyable. The + // caller owns the returned pointer. + // + // The interface_functions gives the pointer to the local interfece when this + // is a target proxy. When creating a source proxy, set this to NULL. + InterfaceProxy* CreateProxyForInterface( + const std::string& interface_name, + const void* interface_functions); + + // Returns true if the remote side supports the given interface as the + // target of an IPC call. + bool RemoteSupportsTargetInterface(const std::string& interface); + + // Sets up a proxy as the target for the given interface, if it is supported. + // Returns true if this process implements the given interface and it is + // proxyable. + bool SetupProxyForTargetInterface(const std::string& interface); + + bool IsInterfaceTrusted(const std::string& interface); + + // Set by the derived classed to indicate the module ID corresponding to + // this dispatcher. + PP_Module pp_module_; + + scoped_ptr<IPC::SyncChannel> channel_; + + bool disallow_trusted_interfaces_; + + GetInterfaceFunc local_get_interface_; + + ProxyMap proxies_; + InterfaceProxy* id_to_proxy_[INTERFACE_ID_COUNT]; + + // True if the remote side has declared which interfaces it supports in + // advance. When set, it means if we don't already have a source proxy for + // the requested interface, that the remote side doesn't support it and + // we don't need to query. + // + // This is just an optimization. The browser has a fixed set of interfaces + // it supports, and the many plugins will end up querying many of them. By + // having the browser just send all of those interfaces in one message, we + // can avoid a bunch of IPC chatter to set up each interface. + bool declared_supported_remote_interfaces_; + + CallbackTracker callback_tracker_; + + scoped_ptr<VarSerializationRules> serialization_rules_; + + DISALLOW_COPY_AND_ASSIGN(Dispatcher); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_DISPATCHER_H_ diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc new file mode 100644 index 0000000..bb70796 --- /dev/null +++ b/ppapi/proxy/host_dispatcher.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2010 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/host_dispatcher.h" + +#include <map> + +#include "base/logging.h" +#include "ppapi/proxy/host_var_serialization_rules.h" + +namespace pp { +namespace proxy { + +namespace { + +typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap; +InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; + +} // namespace + +HostDispatcher::HostDispatcher(const PPB_Var_Deprecated* var_interface, + PP_Module module, + GetInterfaceFunc local_get_interface) + : Dispatcher(local_get_interface) { + SetSerializationRules(new HostVarSerializationRules(var_interface, module)); +} + +HostDispatcher::~HostDispatcher() { +} + +// static +HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + return NULL; + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found == g_instance_to_dispatcher->end()) + return NULL; + return found->second; +} + +// static +void HostDispatcher::SetForInstance(PP_Instance instance, + HostDispatcher* dispatcher) { + if (!g_instance_to_dispatcher) + g_instance_to_dispatcher = new InstanceToDispatcherMap; + (*g_instance_to_dispatcher)[instance] = dispatcher; +} + +// static +void HostDispatcher::RemoveForInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + return; + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found != g_instance_to_dispatcher->end()) + g_instance_to_dispatcher->erase(found); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h new file mode 100644 index 0000000..94d45d2 --- /dev/null +++ b/ppapi/proxy/host_dispatcher.h @@ -0,0 +1,61 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_HOST_DISPATCHER_H_ +#define PPAPI_PROXY_HOST_DISPATCHER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/scoped_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +struct PPB_Var_Deprecated; + +namespace base { +class WaitableEvent; +} + +namespace IPC { +class SyncChannel; +} + +namespace pp { +namespace proxy { + +class InterfaceProxy; +class VarSerialization; + +class HostDispatcher : public Dispatcher { + public: + // Constructor for the renderer side. + // + // You must call Dispatcher::InitWithChannel after the constructor. + HostDispatcher(const PPB_Var_Deprecated* var_interface, + PP_Module module, + GetInterfaceFunc local_get_interface); + ~HostDispatcher(); + + // The host side maintains a mapping from PP_Instance to Dispatcher so + // that we can send the messages to the right channel. + static HostDispatcher* GetForInstance(PP_Instance instance); + static void SetForInstance(PP_Instance instance, + HostDispatcher* dispatcher); + static void RemoveForInstance(PP_Instance instance); + + // Dispatcher overrides. + virtual bool IsPlugin() const { return false; } + + private: + DISALLOW_COPY_AND_ASSIGN(HostDispatcher); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_HOST_DISPATCHER_H_ diff --git a/ppapi/proxy/interface_id.h b/ppapi/proxy/interface_id.h new file mode 100644 index 0000000..8f5ad9b --- /dev/null +++ b/ppapi/proxy/interface_id.h @@ -0,0 +1,33 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_INTERFACE_ID_H_ +#define PPAPI_PROXY_INTERFACE_ID_H_ + +namespace pp { +namespace proxy { + +// These numbers must be all small integers. They are used in a lookup table +// to route messages to the appropriate message handler. +enum InterfaceID { + // Zero is reserved for control messages. + INTERFACE_ID_PPB_CORE = 1, + INTERFACE_ID_PPB_GRAPHICS_2D, + INTERFACE_ID_PPB_IMAGE_DATA, + INTERFACE_ID_PPB_INSTANCE, + INTERFACE_ID_PPB_URL_LOADER, + INTERFACE_ID_PPB_VAR, + INTERFACE_ID_PPB_VAR_DEPRECATED, + + INTERFACE_ID_PPP_CLASS, + INTERFACE_ID_PPP_INSTANCE, + + // Must be last to indicate the number of interface IDs. + INTERFACE_ID_COUNT +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_INTERFACE_ID_H_ diff --git a/ppapi/proxy/interface_proxy.cc b/ppapi/proxy/interface_proxy.cc new file mode 100644 index 0000000..7561d5e --- /dev/null +++ b/ppapi/proxy/interface_proxy.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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/interface_proxy.h" + +#include "base/logging.h" +#include "ppapi/proxy/dispatcher.h" + +namespace pp { +namespace proxy { + +InterfaceProxy::InterfaceProxy(Dispatcher* dispatcher, + const void* target_interface) + : dispatcher_(dispatcher), + target_interface_(target_interface) { +} + +InterfaceProxy::~InterfaceProxy() { +} + +bool InterfaceProxy::Send(IPC::Message* msg) { + return dispatcher_->Send(msg); +} + +uint32 InterfaceProxy::SendCallback(PP_CompletionCallback callback) { + return dispatcher_->callback_tracker().SendCallback(callback); +} + +PP_CompletionCallback InterfaceProxy::ReceiveCallback( + uint32 serialized_callback) { + return dispatcher_->callback_tracker().ReceiveCallback(serialized_callback); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/interface_proxy.h b/ppapi/proxy/interface_proxy.h new file mode 100644 index 0000000..538ebf5 --- /dev/null +++ b/ppapi/proxy/interface_proxy.h @@ -0,0 +1,77 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_INTERFACE_PROXY_H_ +#define PPAPI_PROXY_INTERFACE_PROXY_H_ + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_id.h" + +namespace pp { +namespace proxy { + +class Dispatcher; + +class InterfaceProxy : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + // Creates the given interface associated with the given dispatcher. The + // dispatcher manages our lifetime. + // + // The target interface pointer, when non-NULL, indicates that this is a + // target proxy (see dispatcher.h for a definition). In this case, the proxy + // will interpret this pointer to the actual implementation of the interface + // in the local process. + // + // If the target interface is NULL, this proxy will be a "source" interface. + InterfaceProxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~InterfaceProxy(); + + // See dispatcher.h for definitions of source and target. + bool is_source_proxy() const { return !target_interface_; } + bool is_target_proxy() const { return !!target_interface_; } + + // When this proxy is the "target" of the IPC communication (see + // dispatcher.h), this target_interface pointer will indicate the local + // side's interface pointer. This contains the functions that actually + // implement the proxied interface. + // + // This will be NULL when this proxy is a source proxy. + const void* target_interface() const { return target_interface_; } + + Dispatcher* dispatcher() { return dispatcher_; } + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // Returns the local implementation of the interface that will proxy it to + // the remote side. This is used on the source side only (see dispatcher.h). + virtual const void* GetSourceInterface() const = 0; + + // Returns the interface ID associated with this proxy. Implemented by each + // derived class to identify itself. + virtual InterfaceID GetInterfaceId() const = 0; + + // Sub-classes must implement IPC::Channel::Listener which contains this: + //virtual void OnMessageReceived(const IPC::Message& msg); + + protected: + uint32 SendCallback(PP_CompletionCallback callback); + PP_CompletionCallback ReceiveCallback(uint32 serialized_callback); + + private: + Dispatcher* dispatcher_; + const void* target_interface_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_INTERFACE_PROXY_H_ + diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc new file mode 100644 index 0000000..1997dc4 --- /dev/null +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2010 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/plugin_dispatcher.h" + +#include <map> + +#include "base/logging.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_var_serialization_rules.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppp_class_proxy.h" + +namespace pp { +namespace proxy { + +namespace { + +PluginDispatcher* g_dispatcher = NULL; + +const void* GetInterfaceFromDispatcher(const char* interface) { + // TODO(brettw) need some kind of lock for multi-thread access. + return pp::proxy::PluginDispatcher::Get()->GetProxiedInterface(interface); +} + +} // namespace + +PluginDispatcher::PluginDispatcher(GetInterfaceFunc get_interface, + InitModuleFunc init_module, + ShutdownModuleFunc shutdown_module) + : Dispatcher(get_interface), + init_module_(init_module), + shutdown_module_(shutdown_module), + plugin_resource_tracker_(new PluginResourceTracker(this)), + plugin_var_tracker_(new PluginVarTracker(this)) { + SetSerializationRules( + new PluginVarSerializationRules(plugin_var_tracker_.get())); + + // As a plugin, we always support the PPP_Class interface. There's no + // GetInterface call or name for it, so we insert it into our table now. + InjectProxy(INTERFACE_ID_PPP_CLASS, "$Internal_PPP_Class", + new PPP_Class_Proxy(this)); +} + +PluginDispatcher::~PluginDispatcher() { + if (shutdown_module_) + shutdown_module_(); +} + +// static +PluginDispatcher* PluginDispatcher::Get() { + return g_dispatcher; +} + +// static +void PluginDispatcher::SetGlobal(PluginDispatcher* dispatcher) { + DCHECK(!dispatcher || !g_dispatcher); + g_dispatcher = dispatcher; +} + +void PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + // Handle some plugin-specific control messages. + IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnInitializeModule) + + // Forward all other control messages to the superclass. + IPC_MESSAGE_UNHANDLED(Dispatcher::OnMessageReceived(msg)) + IPC_END_MESSAGE_MAP() + return; + } + + // All non-control messages get handled by the superclass. + Dispatcher::OnMessageReceived(msg); +} + +void PluginDispatcher::OnInitializeModule(PP_Module pp_module, bool* result) { + set_pp_module(pp_module); + *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h new file mode 100644 index 0000000..0a97965 --- /dev/null +++ b/ppapi/proxy/plugin_dispatcher.h @@ -0,0 +1,76 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PLUGIN_DISPATCHER_H_ +#define PPAPI_PROXY_PLUGIN_DISPATCHER_H_ + +#include <string> + +#include "base/scoped_ptr.h" +#include "ppapi/proxy/callback_tracker.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +class MessageLoop; + +namespace base { +class WaitableEvent; +} + +namespace pp { +namespace proxy { + +class PluginDispatcher : public Dispatcher { + public: + // Constructor for the plugin side. The init and shutdown functions will be + // will be automatically called when requested by the renderer side. The + // module ID will be set upon receipt of the InitializeModule message. + // + // You must call Dispatcher::InitWithChannel after the constructor. + PluginDispatcher(GetInterfaceFunc get_interface, + InitModuleFunc init_module, + ShutdownModuleFunc shutdown_module); + ~PluginDispatcher(); + + // The plugin maintains a global Dispatcher pointer. There is only one since + // there is only one connection to the browser. Don't call this on the + // browser side, see GetForInstnace. + static PluginDispatcher* Get(); + static void SetGlobal(PluginDispatcher* dispatcher); + + // Dispatcher overrides. + virtual bool IsPlugin() const { return true; } + + // IPC::Channel::Listener implementation. + virtual void OnMessageReceived(const IPC::Message& msg); + + // Returns the resource tracker for the plugin. In the browser process this + // will return NULL. + PluginResourceTracker* plugin_resource_tracker() { + return plugin_resource_tracker_.get(); + } + + // Returns the var tracker for the plugin. In the browser process this + // will return NULL. + PluginVarTracker* plugin_var_tracker() { + return plugin_var_tracker_.get(); + } + + private: + void OnInitializeModule(PP_Module pp_module, bool* result); + + InitModuleFunc init_module_; + ShutdownModuleFunc shutdown_module_; + + scoped_ptr<PluginResourceTracker> plugin_resource_tracker_; + scoped_ptr<PluginVarTracker> plugin_var_tracker_; + + DISALLOW_COPY_AND_ASSIGN(PluginDispatcher); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_DISPATCHER_H_ diff --git a/ppapi/proxy/plugin_resource.cc b/ppapi/proxy/plugin_resource.cc new file mode 100644 index 0000000..b1a579e --- /dev/null +++ b/ppapi/proxy/plugin_resource.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2010 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/plugin_resource.h" + +namespace pp { +namespace proxy { + +PluginResource::PluginResource() { +} + +PluginResource::~PluginResource() { +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h new file mode 100644 index 0000000..9a70266 --- /dev/null +++ b/ppapi/proxy/plugin_resource.h @@ -0,0 +1,64 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PLUGIN_RESOURCE_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_H_ + +#include "base/basictypes.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" + +// If you inherit from resource, make sure you add the class name here. +#define FOR_ALL_RESOURCES(F) \ + F(Graphics2D) \ + F(ImageData) \ + F(URLLoader) + +namespace pp { +namespace proxy { + +// Forward declaration of Resource classes. +#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE; +FOR_ALL_RESOURCES(DECLARE_RESOURCE_CLASS) +#undef DECLARE_RESOURCE_CLASS + +class PluginResource { + public: + PluginResource(); + virtual ~PluginResource(); + + // Returns NULL if the resource is invalid or is a different type. + template<typename T> static T* GetAs(PP_Resource res) { + PluginResource* resource = + PluginDispatcher::Get()->plugin_resource_tracker()->GetResourceObject( + res); + return resource ? resource->Cast<T>() : NULL; + } + + template <typename T> T* Cast() { return NULL; } + + private: + // Type-specific getters for individual resource types. These will return + // NULL if the resource does not match the specified type. Used by the Cast() + // function. + #define DEFINE_TYPE_GETTER(RESOURCE) \ + virtual RESOURCE* As##RESOURCE() { return NULL; } + FOR_ALL_RESOURCES(DEFINE_TYPE_GETTER) + #undef DEFINE_TYPE_GETTER + + DISALLOW_COPY_AND_ASSIGN(PluginResource); +}; + +// Cast() specializations. +#define DEFINE_RESOURCE_CAST(Type) \ + template <> inline Type* PluginResource::Cast<Type>() { \ + return As##Type(); \ + } +FOR_ALL_RESOURCES(DEFINE_RESOURCE_CAST) +#undef DEFINE_RESOURCE_CAST + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_H_ diff --git a/ppapi/proxy/plugin_resource_tracker.cc b/ppapi/proxy/plugin_resource_tracker.cc new file mode 100644 index 0000000..a285311 --- /dev/null +++ b/ppapi/proxy/plugin_resource_tracker.cc @@ -0,0 +1,87 @@ +// Copyright (c) 2010 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/plugin_resource_tracker.h" + +#include "base/logging.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +namespace proxy { + +PluginResourceTracker::ResourceInfo::ResourceInfo() : ref_count(0) { +} + +PluginResourceTracker::ResourceInfo::ResourceInfo(int rc, + linked_ptr<PluginResource> r) + : ref_count(rc), + resource(r) { +} + +PluginResourceTracker::ResourceInfo::ResourceInfo(const ResourceInfo& other) + : ref_count(other.ref_count), + resource(other.resource) { +} + +PluginResourceTracker::ResourceInfo::~ResourceInfo() { +} + +PluginResourceTracker::ResourceInfo& +PluginResourceTracker::ResourceInfo::operator=( + const ResourceInfo& other) { + ref_count = other.ref_count; + resource = other.resource; + return *this; +} + +PluginResourceTracker::PluginResourceTracker(PluginDispatcher* dispatcher) + : dispatcher_(dispatcher) { +} + +PluginResourceTracker::~PluginResourceTracker() { +} + +PluginResource* PluginResourceTracker::GetResourceObject( + PP_Resource pp_resource) { + ResourceMap::iterator found = resource_map_.find(pp_resource); + if (found == resource_map_.end()) + return NULL; + return found->second.resource.get(); +} + +void PluginResourceTracker::AddResource(PP_Resource pp_resource, + linked_ptr<PluginResource> object) { + DCHECK(resource_map_.find(pp_resource) == resource_map_.end()); + resource_map_[pp_resource] = ResourceInfo(1, object); +} + +void PluginResourceTracker::AddRefResource(PP_Resource resource) { + resource_map_[resource].ref_count++; +} + +void PluginResourceTracker::ReleaseResource(PP_Resource resource) { + ReleasePluginResourceRef(resource, true); +} + +void PluginResourceTracker::ReleasePluginResourceRef( + const PP_Resource& resource, + bool notify_browser_on_release) { + ResourceMap::iterator found = resource_map_.find(resource); + if (found == resource_map_.end()) + return; + found->second.ref_count--; + if (found->second.ref_count == 0) { + if (notify_browser_on_release) { + dispatcher_->Send(new PpapiHostMsg_PPBCore_ReleaseResource( + INTERFACE_ID_PPB_CORE, resource)); + } + resource_map_.erase(found); + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_resource_tracker.h b/ppapi/proxy/plugin_resource_tracker.h new file mode 100644 index 0000000..a9ea963 --- /dev/null +++ b/ppapi/proxy/plugin_resource_tracker.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ + +#include <map> + +#include "base/linked_ptr.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" + +namespace pp { +namespace proxy { + +class PluginDispatcher; +class PluginResource; + +class PluginResourceTracker { + public: + PluginResourceTracker(PluginDispatcher* dispatcher); + ~PluginResourceTracker(); + + // Returns the object associated with the given resource ID, or NULL if + // there isn't one. + PluginResource* GetResourceObject(PP_Resource pp_resource); + + void AddResource(PP_Resource pp_resource, linked_ptr<PluginResource> object); + + void AddRefResource(PP_Resource resource); + void ReleaseResource(PP_Resource resource); + + private: + struct ResourceInfo { + ResourceInfo(); + ResourceInfo(int ref_count, linked_ptr<PluginResource> r); + ResourceInfo(const ResourceInfo& other); + ~ResourceInfo(); + + ResourceInfo& operator=(const ResourceInfo& other); + + int ref_count; + linked_ptr<PluginResource> resource; // May be NULL. + }; + + void ReleasePluginResourceRef(const PP_Resource& var, + bool notify_browser_on_release); + + // Pointer to the dispatcher that owns us. + PluginDispatcher* dispatcher_; + + typedef std::map<PP_Resource, ResourceInfo> ResourceMap; + ResourceMap resource_map_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ diff --git a/ppapi/proxy/ppapi_messages.cc b/ppapi/proxy/ppapi_messages.cc new file mode 100644 index 0000000..1cc617b --- /dev/null +++ b/ppapi/proxy/ppapi_messages.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2010 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/ppapi_messages.h" + +#include "base/file_path.h" +#include "ipc/ipc_channel_handle.h" +#include "ppapi/c/ppb_var.h" + +// This actually defines the implementations of all the IPC message functions. +#define MESSAGES_INTERNAL_IMPL_FILE "ppapi/proxy/ppapi_messages_internal.h" +#include "ipc/ipc_message_impl_macros.h" diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h new file mode 100644 index 0000000..89ba4e9 --- /dev/null +++ b/ppapi/proxy/ppapi_messages.h @@ -0,0 +1,22 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PPAPI_MESSAGES_H_ +#define PPAPI_PROXY_PPAPI_MESSAGES_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/ppapi_param_traits.h" + +#define MESSAGES_INTERNAL_FILE "ppapi/proxy/ppapi_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +#endif // PPAPI_PROXY_PPAPI_MESSAGES_H_ diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h new file mode 100644 index 0000000..f99f4cc --- /dev/null +++ b/ppapi/proxy/ppapi_messages_internal.h @@ -0,0 +1,321 @@ +// Copyright (c) 2010 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. + +// This header is meant to be included in multiple passes, hence no traditional +// header guard. It is included by backing_store_messages_internal.h +// See ipc_message_macros.h for explanation of the macros and passes. + +// This file needs to be included again, even though we're actually included +// from it via utility_messages.h. +#include "ipc/ipc_message_macros.h" + +// These are from the plugin to the renderer +IPC_BEGIN_MESSAGES(Ppapi) + // Loads the given plugin. + IPC_MESSAGE_CONTROL2(PpapiMsg_LoadPlugin, + FilePath /* path */, + int /* renderer_id */) + + IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_InitializeModule, + PP_Module /* module_id */, + bool /* result */) + + // Sent in both directions to see if the other side supports the given + // interface. + IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_SupportsInterface, + std::string /* interface_name */, + bool /* result */) + + // Way for the renderer to list all interfaces that is supports in advance to + // avoid extra IPC traffic. + IPC_MESSAGE_CONTROL1(PpapiMsg_DeclareInterfaces, + std::vector<std::string> /* interfaces */) + + IPC_MESSAGE_CONTROL2(PpapiMsg_ExecuteCallback, + uint32 /* serialized_callback */, + int32 /* param */) + + // PPP_Class. + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_HasProperty, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_HasMethod, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* method */, + pp::proxy::SerializedVar /* out_exception */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_GetProperty, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiMsg_PPPClass_EnumerateProperties, + int64 /* ppp_class */, + int64 /* object */, + std::vector<pp::proxy::SerializedVar> /* props */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED4_1(PpapiMsg_PPPClass_SetProperty, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* name */, + pp::proxy::SerializedVar /* value */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPClass_RemoveProperty, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED4_2(PpapiMsg_PPPClass_Call, + int64 /* ppp_class */, + int64 /* object */, + pp::proxy::SerializedVar /* method_name */, + std::vector<pp::proxy::SerializedVar> /* args */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiMsg_PPPClass_Construct, + int64 /* ppp_class */, + int64 /* object */, + std::vector<pp::proxy::SerializedVar> /* args */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_MESSAGE_ROUTED2(PpapiMsg_PPPClass_Deallocate, + int64 /* ppp_class */, + int64 /* object */) + + // PPP_Instance. + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPInstance_DidCreate, + PP_Instance /* instance */, + std::vector<std::string> /* argn */, + std::vector<std::string> /* argv */, + bool /* result */) + IPC_MESSAGE_ROUTED1(PpapiMsg_PPPInstance_DidDestroy, + PP_Instance /* instance */) + IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_DidChangeView, + PP_Instance /* instance */, + PP_Rect /* position */, + PP_Rect /* clip */) + IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInstance_DidChangeFocus, + PP_Instance /* instance */, + bool /* has_focus */) + IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleInputEvent, + PP_Instance /* instance */, + PP_InputEvent /* event */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleDocumentLoad, + PP_Instance /* instance */, + PP_Resource /* url_loader */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiMsg_PPPInstance_GetInstanceObject, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* result */) + + + // PPB_URLLoader + // (Messages from browser to plugin to notify it of changes in state.) + IPC_MESSAGE_ROUTED5(PpapiMsg_PPBURLLoader_UpdateProgress, + PP_Resource /* resource */, + int64 /* bytes_sent */, + int64 /* total_bytes_to_be_sent */, + int64 /* bytes_received */, + int64 /* total_bytes_to_be_received */) +IPC_END_MESSAGES(Ppapi) + +// ----------------------------------------------------------------------------- +// These are from the plugin to the renderer. +IPC_BEGIN_MESSAGES(PpapiHost) + // Reply to PpapiMsg_LoadPlugin. + IPC_MESSAGE_CONTROL1(PpapiHostMsg_PluginLoaded, + IPC::ChannelHandle /* handle */) + + // PPB_Core. + IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_AddRefResource, PP_Resource) + IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_ReleaseResource, PP_Resource) + IPC_SYNC_MESSAGE_ROUTED0_1(PpapiHostMsg_PPBCore_GetTime, + double /* return value -> time */) + IPC_SYNC_MESSAGE_ROUTED0_1(PpapiHostMsg_PPBCore_GetTimeTicks, + double /* return value -> time */) + IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBCore_CallOnMainThread, + int /* delay_in_msec */, + uint32_t /* serialized_callback */, + int32_t /* result */) + + // PPB_Graphics2D. + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBGraphics2D_Create, + PP_Module /* module */, + PP_Size /* size */, + bool /* is_always_opaque */, + PP_Resource /* result */) + IPC_MESSAGE_ROUTED5(PpapiHostMsg_PPBGraphics2D_PaintImageData, + PP_Resource /* graphics_2d */, + PP_Resource /* image_data */, + PP_Point /* top_left */, + bool /* src_rect_specified */, + PP_Rect /* src_rect */) + IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBGraphics2D_Scroll, + PP_Resource /* graphics_2d */, + bool /* clip_specified */, + PP_Rect /* clip */, + PP_Point /* amount */) + IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBGraphics2D_ReplaceContents, + PP_Resource /* graphics_2d */, + PP_Resource /* image_data */) + IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBGraphics2D_Flush, + PP_Resource /* graphics_2d */, + uint32_t /* serialized_callback */, + int32_t /* result */) + + // PPB_ImageData. + IPC_SYNC_MESSAGE_ROUTED0_1( + PpapiHostMsg_PPBImageData_GetNativeImageDataFormat, + int32 /* result_format */) + IPC_SYNC_MESSAGE_ROUTED1_1( + PpapiHostMsg_PPBImageData_IsImageDataFormatSupported, + int32 /* format */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED4_3(PpapiHostMsg_PPBImageData_Create, + PP_Module /* module */, + int32 /* format */, + PP_Size /* size */, + bool /* init_to_zero */, + PP_Resource /* result_resource */, + std::string /* image_data_desc */, + uint64_t /* result_shm_handle */) + + // PPB_Instance. + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetWindowObject, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_GetOwnerElementObject, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_BindGraphics, + PP_Instance /* instance */, + PP_Resource /* device */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_IsFullFrame, + PP_Instance /* instance */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBInstance_ExecuteScript, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* script */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + + // PPB_URLLoader. + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLLoader_Create, + PP_Instance /* instance */, + PP_Resource /* result */) + IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBURLLoader_Open, + PP_Resource /* loader */, + PP_Resource /*request_info */, + uint32_t /* serialized_callback */) + IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_FollowRedirect, + PP_Resource /* loader */, + uint32_t /* serialized_callback */) + IPC_SYNC_MESSAGE_ROUTED1_3(PpapiHostMsg_PPBURLLoader_GetUploadProgress, + PP_Resource /* loader */, + int64 /* bytes_sent */, + int64 /* total_bytes_to_be_sent */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED1_3(PpapiHostMsg_PPBURLLoader_GetDownloadProgress, + PP_Resource /* loader */, + int64 /* bytes_received */, + int64 /* total_bytes_to_be_received */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLLoader_GetResponseInfo, + PP_Resource /* loader */, + PP_Resource /* response_info_out */) + IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBURLLoader_ReadResponseBody, + PP_Resource /* loader */, + int32_t /* bytes_to_read */, + uint32_t /* serialized_callback */) + IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile, + PP_Resource /* loader */, + uint32_t /* serialized_callback */) + IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_Close, + PP_Resource /* loader */) + + // PPB_Var. + IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBVar_AddRefObject, + int64 /* object_id */) + IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBVar_ReleaseObject, + int64 /* object_id */) + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiHostMsg_PPBVar_ConvertType, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* var */, + int /* new_type */, + pp::proxy::SerializedVar /* exception */, + pp::proxy::SerializedVar /* result */) + IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBVar_DefineProperty, + pp::proxy::SerializedVar /* object */, + PP_ObjectProperty /* property */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasProperty, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasMethodDeprecated, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* method */, + pp::proxy::SerializedVar /* out_exception */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_GetProperty, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_DeleteProperty, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBVar_EnumerateProperties, + pp::proxy::SerializedVar /* object */, + std::vector<pp::proxy::SerializedVar> /* props */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVar_SetPropertyDeprecated, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* name */, + pp::proxy::SerializedVar /* value */, + pp::proxy::SerializedVar /* out_exception */) + IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBVar_IsCallable, + pp::proxy::SerializedVar /* object */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED4_2(PpapiHostMsg_PPBVar_Call, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* this_object */, + pp::proxy::SerializedVar /* method_name */, + std::vector<pp::proxy::SerializedVar> /* args */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED3_2(PpapiHostMsg_PPBVar_CallDeprecated, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* method_name */, + std::vector<pp::proxy::SerializedVar> /* args */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_Construct, + pp::proxy::SerializedVar /* object */, + std::vector<pp::proxy::SerializedVar> /* args */, + pp::proxy::SerializedVar /* out_exception */, + pp::proxy::SerializedVar /* result */) + IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, + pp::proxy::SerializedVar /* var */, + int64 /* object_class */, + int64 /* object-data */, + bool /* result */) + IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVar_CreateObjectDeprecated, + PP_Module /* module */, + int64 /* object_class */, + int64 /* object_data */, + pp::proxy::SerializedVar /* result */) + +IPC_END_MESSAGES(PpapiHost) + diff --git a/ppapi/proxy/ppapi_param_traits.cc b/ppapi/proxy/ppapi_param_traits.cc new file mode 100644 index 0000000..4bfe23c --- /dev/null +++ b/ppapi/proxy/ppapi_param_traits.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2010 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/ppapi_param_traits.h" + +#include <string.h> // For memcpy + +#include "ppapi/proxy/serialized_var.h" + +namespace IPC { + +// static +void ParamTraits<PP_InputEvent>::Write(Message* m, const param_type& p) { + // PP_InputEvent is just POD so we can just memcpy it. + m->WriteData(reinterpret_cast<const char*>(&p), sizeof(PP_InputEvent)); +} + +// static +bool ParamTraits<PP_InputEvent>::Read(const Message* m, + void** iter, + param_type* r) { + const char* data; + int data_size; + if (!m->ReadData(iter, &data, &data_size)) + return false; + memcpy(r, data, sizeof(PP_InputEvent)); + return true; +} + +// static +void ParamTraits<PP_InputEvent>::Log(const param_type& p, std::string* l) { +} + +// PP_ObjectProperty ----------------------------------------------------------- + +// static +void ParamTraits<PP_ObjectProperty>::Write(Message* m, const param_type& p) { + // FIXME(brettw); +} + +// static +bool ParamTraits<PP_ObjectProperty>::Read(const Message* m, + void** iter, + param_type* r) { + // FIXME(brettw); + return true; +} + +// static +void ParamTraits<PP_ObjectProperty>::Log(const param_type& p, std::string* l) { +} + +// PP_Point -------------------------------------------------------------------- + +// static +void ParamTraits<PP_Point>::Write(Message* m, const param_type& p) { + m->WriteInt(p.x); + m->WriteInt(p.y); +} + +// static +bool ParamTraits<PP_Point>::Read(const Message* m, void** iter, param_type* r) { + return m->ReadInt(iter, &r->x) && !m->ReadInt(iter, &r->y); +} + +// static +void ParamTraits<PP_Point>::Log(const param_type& p, std::string* l) { +} + +// PP_Rect --------------------------------------------------------------------- + +// static +void ParamTraits<PP_Rect>::Write(Message* m, const param_type& p) { + m->WriteInt(p.point.x); + m->WriteInt(p.point.y); + m->WriteInt(p.size.width); + m->WriteInt(p.size.height); +} + +// static +bool ParamTraits<PP_Rect>::Read(const Message* m, + void** iter, + param_type* r) { + if (!m->ReadInt(iter, &r->point.x) || + !m->ReadInt(iter, &r->point.y) || + !m->ReadInt(iter, &r->size.width) || + !m->ReadInt(iter, &r->size.height)) + return false; + return true; +} + +// static +void ParamTraits<PP_Rect>::Log(const param_type& p, std::string* l) { +} + +// PP_Size --------------------------------------------------------------------- + +// static +void ParamTraits<PP_Size>::Write(Message* m, const param_type& p) { + m->WriteInt(p.width); + m->WriteInt(p.height); +} + +// static +bool ParamTraits<PP_Size>::Read(const Message* m, void** iter, param_type* r) { + return m->ReadInt(iter, &r->width) && m->ReadInt(iter, &r->height); +} + +// static +void ParamTraits<PP_Size>::Log(const param_type& p, std::string* l) { +} + +// SerializedVar --------------------------------------------------------------- + +// static +void ParamTraits<pp::proxy::SerializedVar>::Write(Message* m, + const param_type& p) { + p.WriteToMessage(m); +} + +// static +bool ParamTraits<pp::proxy::SerializedVar>::Read(const Message* m, + void** iter, + param_type* r) { + return r->ReadFromMessage(m, iter); +} + +// static +void ParamTraits<pp::proxy::SerializedVar>::Log(const param_type& p, + std::string* l) { +} + +// std::vector<SerializedVar> -------------------------------------------------- + +void ParamTraits< std::vector<pp::proxy::SerializedVar> >::Write( + Message* m, + const param_type& p) { + WriteParam(m, static_cast<int>(p.size())); + for (size_t i = 0; i < p.size(); i++) + WriteParam(m, p[i]); +} + +// static +bool ParamTraits< std::vector<pp::proxy::SerializedVar> >::Read( + const Message* m, + void** iter, + param_type* r) { + // This part is just a copy of the the default ParamTraits vector Read(). + int size; + // ReadLength() checks for < 0 itself. + if (!m->ReadLength(iter, &size)) + return false; + // Resizing beforehand is not safe, see BUG 1006367 for details. + if (INT_MAX / sizeof(pp::proxy::SerializedVar) <= static_cast<size_t>(size)) + return false; + + // The default vector deserializer does resize here and then we deserialize + // into those allocated slots. However, the implementation of vector (at + // least in GCC's implementation), creates a new empty object using the + // default constructor, and then sets the rest of the items to that empty + // one using the copy constructor. + // + // Since we allocate the inner class when you call the default constructor + // and transfer the inner class when you do operator=, the entire vector + // will end up referring to the same inner class. Deserializing into this + // will just end up overwriting the same item over and over, since all the + // SerializedVars will refer to the same thing. + // + // The solution is to make a new SerializedVar for each deserialized item, + // and then add it to the vector one at a time. Our copies are efficient so + // this is no big deal. + r->reserve(size); + for (int i = 0; i < size; i++) { + pp::proxy::SerializedVar var; + if (!ReadParam(m, iter, &var)) + return false; + r->push_back(var); + } + return true; +} + +// static +void ParamTraits< std::vector<pp::proxy::SerializedVar> >::Log( + const param_type& p, + std::string* l) { +} + + +} // namespace IPC diff --git a/ppapi/proxy/ppapi_param_traits.h b/ppapi/proxy/ppapi_param_traits.h new file mode 100644 index 0000000..e8c17d8 --- /dev/null +++ b/ppapi/proxy/ppapi_param_traits.h @@ -0,0 +1,86 @@ +// Copyright (c) 2010 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. + +#ifndef PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ +#define PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ + +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_input_event.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/serialized_var.h" // TODO(brettw) eraseme. + +class PP_ObjectProperty; + +namespace pp { +namespace proxy { +class SerializedVar; +} +} + +namespace IPC { + +template<> +struct ParamTraits<PP_InputEvent> { + typedef PP_InputEvent param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct ParamTraits<PP_ObjectProperty> { + typedef PP_ObjectProperty param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct ParamTraits<PP_Point> { + typedef PP_Point param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct ParamTraits<PP_Rect> { + typedef PP_Rect param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct ParamTraits<PP_Size> { + typedef PP_Size param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +template<> +struct ParamTraits<pp::proxy::SerializedVar> { + typedef pp::proxy::SerializedVar param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +// We need a special implementation of sending a vector of SerializedVars +// because the behavior of vector doesn't always play nicely with our +// weird SerializedVar implementation (see "Read" in the .cc file). +template<> +struct ParamTraits< std::vector<pp::proxy::SerializedVar> > { + typedef std::vector<pp::proxy::SerializedVar> param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; + +} // namespace IPC + +#endif // PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc new file mode 100644 index 0000000..a76f219 --- /dev/null +++ b/ppapi/proxy/serialized_var.cc @@ -0,0 +1,457 @@ +// Copyright (c) 2010 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/serialized_var.h" + +#include "base/logging.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace pp { +namespace proxy { + +// SerializedVar::Inner -------------------------------------------------------- + +SerializedVar::Inner::Inner() + : serialization_rules_(NULL), + var_(PP_MakeUndefined()), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) + : serialization_rules_(serialization_rules), + var_(PP_MakeUndefined()), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules, + const PP_Var& var) + : serialization_rules_(serialization_rules), + var_(var), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::~Inner() { + switch (cleanup_mode_) { + case END_SEND_PASS_REF: + serialization_rules_->EndSendPassRef(var_); + break; + case END_RECEIVE_CALLER_OWNED: + serialization_rules_->EndReceiveCallerOwned(var_); + break; + default: + break; + } +} + +PP_Var SerializedVar::Inner::GetVar() const { + DCHECK(serialization_rules_); + + // If we're a string var, we should have already converted the string value + // to a var ID. + DCHECK(var_.type != PP_VARTYPE_STRING || var_.value.as_id != 0); + return var_; +} + +PP_Var SerializedVar::Inner::GetIncompleteVar() const { + DCHECK(serialization_rules_); + return var_; +} + +void SerializedVar::Inner::SetVar(PP_Var var) { + // Sanity check, when updating the var we should have received a + // serialization rules pointer already. + DCHECK(serialization_rules_); + var_ = var; +} + +const std::string& SerializedVar::Inner::GetString() const { + DCHECK(serialization_rules_); + return string_value_; +} + +std::string* SerializedVar::Inner::GetStringPtr() { + DCHECK(serialization_rules_); + return &string_value_; +} + +void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { + // When writing to the IPC messages, a serization rules handler should + // always have been set. + // + // When sending a message, it should be difficult to trigger this if you're + // using the SerializedVarSendInput class and giving a non-NULL dispatcher. + // Make sure you're using the proper "Send" helper class. + // + // It should be more common to see this when handling an incoming message + // that returns a var. This means the message handler didn't write to the + // output parameter, or possibly you used the wrong helper class + // (normally SerializedVarReturnValue). + DCHECK(serialization_rules_); + +#ifndef NDEBUG + // We should only be serializing something once. + DCHECK(!has_been_serialized_); + has_been_serialized_ = true; +#endif + + // If the var is not a string type, we should not have ended up with any + // string data. + DCHECK(var_.type == PP_VARTYPE_STRING || string_value_.empty()); + + m->WriteInt(static_cast<int>(var_.type)); + switch (var_.type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't need any data associated with them other than the type we + // just serialized. + break; + case PP_VARTYPE_BOOL: + m->WriteBool(var_.value.as_bool); + break; + case PP_VARTYPE_INT32: + m->WriteInt(var_.value.as_int); + break; + case PP_VARTYPE_DOUBLE: + IPC::ParamTraits<double>::Write(m, var_.value.as_double); + break; + case PP_VARTYPE_STRING: + // TODO(brettw) in the case of an invalid string ID, it would be nice + // to send something to the other side such that a 0 ID would be + // generated there. Then the function implementing the interface can + // handle the invalid string as if it was in process rather than seeing + // what looks like a valid empty string. + m->WriteString(string_value_); + break; + case PP_VARTYPE_OBJECT: + m->WriteInt64(var_.value.as_id); + break; + } +} + +bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, void** iter) { +#ifndef NDEBUG + // We should only deserialize something once or will end up with leaked + // references. + // + // One place this has happened in the past is using + // std::vector<SerializedVar>.resize(). If you're doing this manually instead + // of using the helper classes for handling in/out vectors of vars, be + // sure you use the same pattern as the SerializedVarVector classes. + DCHECK(!has_been_deserialized_); + has_been_deserialized_ = true; +#endif + + // When reading, the dispatcher should be set when we get a Deserialize + // call (which will supply a dispatcher). + int type; + if (!m->ReadInt(iter, &type)) + return false; + + bool success = false; + switch (type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't have any data associated with them other than the type we + // just serialized. + success = true; + break; + case PP_VARTYPE_BOOL: + success = m->ReadBool(iter, &var_.value.as_bool); + break; + case PP_VARTYPE_INT32: + success = m->ReadInt(iter, &var_.value.as_int); + break; + case PP_VARTYPE_DOUBLE: + success = IPC::ParamTraits<double>::Read(m, iter, &var_.value.as_double); + break; + case PP_VARTYPE_STRING: + success = m->ReadString(iter, &string_value_); + var_.value.as_id = 0; + break; + case PP_VARTYPE_OBJECT: + success = m->ReadInt64(iter, &var_.value.as_id); + break; + default: + // Leave success as false. + break; + } + + // All success cases get here. We avoid writing the type above so that the + // output param is untouched (defaults to VARTYPE_UNDEFINED) even in the + // failure case. + if (success) + var_.type = static_cast<PP_VarType>(type); + return success; +} + +// SerializedVar --------------------------------------------------------------- + +SerializedVar::SerializedVar() : inner_(new Inner) { +} + +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules) + : inner_(new Inner(serialization_rules)) { +} + +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules, + const PP_Var& var) + : inner_(new Inner(serialization_rules, var)) { +} + +SerializedVar::~SerializedVar() { +} + +// SerializedVarSendInput ------------------------------------------------------ + +SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher, + const PP_Var& var) + : SerializedVar(dispatcher->serialization_rules(), var) { + dispatcher->serialization_rules()->SendCallerOwned(var, GetStringPtr()); +} + +// static +void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, + const PP_Var* input, + size_t input_count, + std::vector<SerializedVar>* output) { + output->resize(input_count); + for (size_t i = 0; i < input_count; i++) { + (*output)[i] = SerializedVar(dispatcher->serialization_rules(), input[i]); + dispatcher->serialization_rules()->SendCallerOwned(input[i], + (*output)[i].GetStringPtr()); + } +} + +// ReceiveSerializedVarReturnValue --------------------------------------------- + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { +} + +PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { + set_serialization_rules(dispatcher->serialization_rules()); + SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(), + GetString())); + return GetVar(); +} + +// ReceiveSerializedException -------------------------------------------------- + +ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, + PP_Var* exception) + : SerializedVar(dispatcher->serialization_rules()), + exception_(exception) { +} + +ReceiveSerializedException::~ReceiveSerializedException() { + if (exception_) { + // When an output exception is specified, it will take ownership of the + // reference. + SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(), + GetString())); + *exception_ = GetVar(); + } else { + // When no output exception is specified, the browser thinks we have a ref + // to an object that we don't want (this will happen only in the plugin + // since the browser will always specify an out exception for the plugin to + // write into). + // + // Strings don't need this handling since we can just avoid creating a + // Var from the std::string in the first place. + if (GetVar().type == PP_VARTYPE_OBJECT) + serialization_rules()->ReleaseObjectRef(GetVar()); + } +} + +bool ReceiveSerializedException::IsThrown() const { + return exception_ && exception_->type != PP_VARTYPE_UNDEFINED; +} + +// ReceiveSerializedVarVectorOutParam ------------------------------------------ + +ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam( + Dispatcher* dispatcher, + uint32_t* output_count, + PP_Var** output) + : dispatcher_(dispatcher), + output_count_(output_count), + output_(output) { +} + +ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() { + *output_count_ = static_cast<uint32_t>(vector_.size()); + if (!vector_.size()) { + *output_ = NULL; + return; + } + + *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var))); + for (size_t i = 0; i < vector_.size(); i++) { + // Here we just mimic what happens when returning a value. + ReceiveSerializedVarReturnValue converted; + SerializedVar* serialized = &converted; + *serialized = vector_[i]; + (*output_)[i] = converted.Return(dispatcher_); + } +} + +std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() { + return &vector_; +} + +// SerializedVarReceiveInput --------------------------------------------------- + +SerializedVarReceiveInput::SerializedVarReceiveInput( + const SerializedVar& serialized) + : serialized_(serialized), + dispatcher_(NULL), + var_(PP_MakeUndefined()) { +} + +SerializedVarReceiveInput::~SerializedVarReceiveInput() { +} + +PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { + serialized_.set_serialization_rules(dispatcher->serialization_rules()); + + // Ensure that when the serialized var goes out of scope it cleans up the + // stuff we're making in BeginReceiveCallerOwned. + serialized_.set_cleanup_mode(SerializedVar::END_RECEIVE_CALLER_OWNED); + + serialized_.SetVar( + serialized_.serialization_rules()->BeginReceiveCallerOwned( + serialized_.GetIncompleteVar(), serialized_.GetStringPtr())); + return serialized_.GetVar(); +} + +// SerializedVarVectorReceiveInput --------------------------------------------- + +SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( + const std::vector<SerializedVar>& serialized) + : serialized_(serialized) { +} + +SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { + for (size_t i = 0; i < deserialized_.size(); i++) { + serialized_[i].serialization_rules()->EndReceiveCallerOwned( + deserialized_[i]); + } +} + +PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, + uint32_t* array_size) { + deserialized_.resize(serialized_.size()); + for (size_t i = 0; i < serialized_.size(); i++) { + // The vector must be able to clean themselves up after this call is + // torn down. + serialized_[i].set_serialization_rules(dispatcher->serialization_rules()); + + serialized_[i].SetVar( + serialized_[i].serialization_rules()->BeginReceiveCallerOwned( + serialized_[i].GetIncompleteVar(), serialized_[i].GetStringPtr())); + deserialized_[i] = serialized_[i].GetVar(); + } + + *array_size = static_cast<uint32_t>(serialized_.size()); + return deserialized_.size() > 0 ? &deserialized_[0] : NULL; +} + +// SerializedVarReturnValue ---------------------------------------------------- + +SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) + : serialized_(serialized) { +} + +void SerializedVarReturnValue::Return(Dispatcher* dispatcher, + const PP_Var& var) { + serialized_->set_serialization_rules(dispatcher->serialization_rules()); + serialized_->SetVar(var); + + // Var must clean up after our BeginSendPassRef call. + serialized_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); + + dispatcher->serialization_rules()->BeginSendPassRef( + serialized_->GetIncompleteVar(), serialized_->GetStringPtr()); +} + +// SerializedVarOutParam ------------------------------------------------------- + +SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) + : serialized_(serialized), + writable_var_(PP_MakeUndefined()) { +} + +SerializedVarOutParam::~SerializedVarOutParam() { + if (serialized_->serialization_rules()) { + // When unset, OutParam wasn't called. We'll just leave the var untouched + // in that case. + serialized_->SetVar(writable_var_); + serialized_->serialization_rules()->BeginSendPassRef( + writable_var_, serialized_->GetStringPtr()); + + // Normally the current object will be created on the stack to wrap a + // SerializedVar and won't have a scope around the actual IPC send. So we + // need to tell the SerializedVar to do the begin/end send pass ref calls. + serialized_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); + } +} + +PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { + serialized_->set_serialization_rules(dispatcher->serialization_rules()); + return &writable_var_; +} + +// SerializedVarVectorOutParam ------------------------------------------------- + +SerializedVarVectorOutParam::SerializedVarVectorOutParam( + std::vector<SerializedVar>* serialized) + : dispatcher_(NULL), + serialized_(serialized), + count_(0), + array_(NULL) { +} + +SerializedVarVectorOutParam::~SerializedVarVectorOutParam() { + DCHECK(dispatcher_); + + // Convert the array written by the pepper code to the serialized structure. + // Note we can't use resize here, we have to allocate a new SerializedVar + // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read. + serialized_->reserve(count_); + for (uint32_t i = 0; i < count_; i++) { + // Just mimic what we do for regular OutParams. + SerializedVar var; + SerializedVarOutParam out(&var); + *out.OutParam(dispatcher_) = array_[i]; + serialized_->push_back(var); + } + + // When returning arrays, the pepper code expects the caller to take + // ownership of the array. + free(array_); +} + +PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) { + DCHECK(!dispatcher_); // Should only be called once. + dispatcher_ = dispatcher; + return &array_; +} + +} // namespace proxy +} // namespace pp + |