diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 16:14:55 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-19 16:14:55 +0000 |
commit | 1e78967ed2f1937b3809c19d91e7dd62d756d307 (patch) | |
tree | 054c19343eaced71ac5edf8d5425e83fb878ca0d /ppapi/proxy | |
parent | 5d4451ebf298d9d71f716cc0135f465cec41fcd0 (diff) | |
parent | cd18d6f39a965004529d5800a7067a3d3b29a2ba (diff) | |
download | chromium_src-1e78967ed2f1937b3809c19d91e7dd62d756d307.zip chromium_src-1e78967ed2f1937b3809c19d91e7dd62d756d307.tar.gz chromium_src-1e78967ed2f1937b3809c19d91e7dd62d756d307.tar.bz2 |
FileManagerDialogTest.SelectFileAndCancel flaky.
BUG=89733
TBR=robertshield@chromium.org
TEST=browser_tests
Review URL: http://codereview.chromium.org/7447001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93027 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/proxy')
138 files changed, 21522 insertions, 0 deletions
diff --git a/ppapi/proxy/DEPS b/ppapi/proxy/DEPS new file mode 100644 index 0000000..a159be3 --- /dev/null +++ b/ppapi/proxy/DEPS @@ -0,0 +1,15 @@ +include_rules = [ + "+base", + "+ipc", + "+gpu", + "+skia", + "+ui/gfx/surface", + + # We don't want the proxy to depend on the C++ layer, which is appropriate + # for plugins only. However, the completion callback factory is a very useful + # tool that we would otherwise have to duplicate, and has no other + # dependencies, so we allow that. + "-ppapi/cpp", + "+ppapi/cpp/completion_callback.h" +] + diff --git a/ppapi/proxy/OWNERS b/ppapi/proxy/OWNERS new file mode 100644 index 0000000..86dac7d --- /dev/null +++ b/ppapi/proxy/OWNERS @@ -0,0 +1,2 @@ +piman@chromium.org +viettrungluu@chromium.org diff --git a/ppapi/proxy/broker_dispatcher.cc b/ppapi/proxy/broker_dispatcher.cc new file mode 100644 index 0000000..087e9fc --- /dev/null +++ b/ppapi/proxy/broker_dispatcher.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/broker_dispatcher.h" + +#include "base/sync_socket.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +int32_t PlatformFileToInt(base::PlatformFile handle) { +#if defined(OS_WIN) + return static_cast<int32_t>(reinterpret_cast<intptr_t>(handle)); +#elif defined(OS_POSIX) + return handle; +#else + #error Not implemented. +#endif +} + +} // namespace + +BrokerDispatcher::BrokerDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance) + : ProxyChannel(remote_process_handle), + connect_instance_(connect_instance) { +} + +BrokerDispatcher::~BrokerDispatcher() { +} + +bool BrokerDispatcher::InitBrokerWithChannel( + ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + return ProxyChannel::InitWithChannel(delegate, channel_handle, is_client); +} + +bool BrokerDispatcher::OnMessageReceived(const IPC::Message& msg) { + // Control messages. + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(BrokerDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_ConnectToPlugin, OnMsgConnectToPlugin) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } + return false; +} + +// Transfers ownership of the handle to the broker module. +void BrokerDispatcher::OnMsgConnectToPlugin( + PP_Instance instance, + IPC::PlatformFileForTransit handle) { + int32_t result = PP_OK; + if (handle == IPC::InvalidPlatformFileForTransit()) { + result = PP_ERROR_FAILED; + } else { + base::SyncSocket::Handle socket_handle = + IPC::PlatformFileForTransitToPlatformFile(handle); + + if (connect_instance_) { + result = connect_instance_(instance, PlatformFileToInt(socket_handle)); + } else { + result = PP_ERROR_FAILED; + // Close the handle since there is no other owner. + // The easiest way to clean it up is to just put it in an object + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket(socket_handle); + } + } + + // TODO(ddorwin): Report result via IPC. +} + +BrokerHostDispatcher::BrokerHostDispatcher( + base::ProcessHandle remote_process_handle) + : BrokerDispatcher(remote_process_handle, NULL) { +} + +void BrokerHostDispatcher::OnChannelError() { + BrokerDispatcher::OnChannelError(); // Stop using the channel. + + // Tell the host about the crash so it can clean up and display notification. + // TODO(ddorwin): Add BrokerCrashed() to PPB_Proxy_Private and call it. + // ppb_proxy_->BrokerCrashed(pp_module()); +} + +BrokerSideDispatcher::BrokerSideDispatcher( + base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance) + : BrokerDispatcher(remote_process_handle, connect_instance) { +} + +void BrokerSideDispatcher::OnChannelError() { + BrokerDispatcher::OnChannelError(); + + // The renderer has crashed or exited. This channel and all instances + // associated with it are no longer valid. + // TODO(ddorwin): This causes the broker process to exit, which may not be + // desirable in some use cases. + delete this; +} + + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/broker_dispatcher.h b/ppapi/proxy/broker_dispatcher.h new file mode 100644 index 0000000..399bb87 --- /dev/null +++ b/ppapi/proxy/broker_dispatcher.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_BROKER_DISPATCHER_H_ +#define PPAPI_PROXY_BROKER_DISPATCHER_H_ + +#include "ppapi/c/trusted/ppp_broker.h" +#include "ppapi/proxy/proxy_channel.h" + +namespace pp { +namespace proxy { + +class BrokerDispatcher : public ProxyChannel { + public: + virtual ~BrokerDispatcher(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitBrokerWithChannel(ProxyChannel::Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + // IPC::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + protected: + // You must call InitBrokerWithChannel after the constructor. + BrokerDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance); + + void OnMsgConnectToPlugin(PP_Instance instance, + IPC::PlatformFileForTransit handle); + + PP_ConnectInstance_Func connect_instance_; + + private: + DISALLOW_COPY_AND_ASSIGN(BrokerDispatcher); +}; + +// The dispatcher for the browser side of the broker channel. +class BrokerHostDispatcher : public BrokerDispatcher { + public: + BrokerHostDispatcher(base::ProcessHandle remote_process_handle); + + // IPC::Channel::Listener implementation. + virtual void OnChannelError(); +}; + +// The dispatcher for the broker side of the broker channel. +class BrokerSideDispatcher : public BrokerDispatcher { + public: + BrokerSideDispatcher(base::ProcessHandle remote_process_handle, + PP_ConnectInstance_Func connect_instance); + + // IPC::Channel::Listener implementation. + virtual void OnChannelError(); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_BROKER_DISPATCHER_H_ 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..69e16ac --- /dev/null +++ b/ppapi/proxy/dispatcher.cc @@ -0,0 +1,272 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/dispatcher.h" + +#include <string.h> // For memset. + +#include <map> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/dev/ppb_context_3d_dev.h" +#include "ppapi/c/dev/ppb_crypto_dev.h" +#include "ppapi/c/dev/ppb_cursor_control_dev.h" +#include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/dev/ppb_opengles_dev.h" +#include "ppapi/c/dev/ppb_surface_3d_dev.h" +#include "ppapi/c/dev/ppb_testing_dev.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppb_audio_config.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/ppb_url_loader.h" +#include "ppapi/c/ppb_url_request_info.h" +#include "ppapi/c/ppb_url_response_info.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/c/private/ppb_flash_clipboard.h" +#include "ppapi/c/private/ppb_flash_file.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/c/private/ppb_flash_net_connector.h" +#include "ppapi/c/private/ppb_flash_tcp_socket.h" +#include "ppapi/c/private/ppb_pdf.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_audio_config_proxy.h" +#include "ppapi/proxy/ppb_audio_proxy.h" +#include "ppapi/proxy/ppb_broker_proxy.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/ppb_char_set_proxy.h" +#include "ppapi/proxy/ppb_console_proxy.h" +#include "ppapi/proxy/ppb_context_3d_proxy.h" +#include "ppapi/proxy/ppb_core_proxy.h" +#include "ppapi/proxy/ppb_crypto_proxy.h" +#include "ppapi/proxy/ppb_cursor_control_proxy.h" +#include "ppapi/proxy/ppb_file_chooser_proxy.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/ppb_file_system_proxy.h" +#include "ppapi/proxy/ppb_flash_clipboard_proxy.h" +#include "ppapi/proxy/ppb_flash_file_proxy.h" +#include "ppapi/proxy/ppb_flash_proxy.h" +#include "ppapi/proxy/ppb_flash_menu_proxy.h" +#include "ppapi/proxy/ppb_flash_net_connector_proxy.h" +#include "ppapi/proxy/ppb_flash_tcp_socket_proxy.h" +#include "ppapi/proxy/ppb_font_proxy.h" +#include "ppapi/proxy/ppb_graphics_2d_proxy.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/ppb_input_event_proxy.h" +#include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppb_memory_proxy.h" +#include "ppapi/proxy/ppb_opengles2_proxy.h" +#include "ppapi/proxy/ppb_pdf_proxy.h" +#include "ppapi/proxy/ppb_surface_3d_proxy.h" +#include "ppapi/proxy/ppb_testing_proxy.h" +#include "ppapi/proxy/ppb_url_loader_proxy.h" +#include "ppapi/proxy/ppb_url_request_info_proxy.h" +#include "ppapi/proxy/ppb_url_response_info_proxy.h" +#include "ppapi/proxy/ppb_url_util_proxy.h" +#include "ppapi/proxy/ppb_var_deprecated_proxy.h" +#include "ppapi/proxy/ppb_var_proxy.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/ppp_graphics_3d_proxy.h" +#include "ppapi/proxy/ppp_input_event_proxy.h" +#include "ppapi/proxy/ppp_instance_private_proxy.h" +#include "ppapi/proxy/ppp_instance_proxy.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace pp { +namespace proxy { + +namespace { + +struct InterfaceList { + InterfaceList(); + + static InterfaceList* GetInstance(); + + void AddPPP(const InterfaceProxy::Info* info); + void AddPPB(const InterfaceProxy::Info* info); + + typedef std::map<std::string, const InterfaceProxy::Info*> NameToInfo; + NameToInfo name_to_plugin_info_; + NameToInfo name_to_browser_info_; + + // Note that there can be multiple interface names mapping to the same ID. + // In this case, the ID will map to one of them. This is temporary while + // we're converting to the thunk system, when that is complete, we need to + // have a better way of handling multiple interface implemented by one + // proxy object. + const InterfaceProxy::Info* id_to_browser_info_[INTERFACE_ID_COUNT]; +}; + +InterfaceList::InterfaceList() { + memset(id_to_browser_info_, 0, sizeof(id_to_browser_info_)); + + // PPB (browser) interfaces. + AddPPB(PPB_AudioConfig_Proxy::GetInfo()); + AddPPB(PPB_Audio_Proxy::GetInfo()); + AddPPB(PPB_Broker_Proxy::GetInfo()); + AddPPB(PPB_Buffer_Proxy::GetInfo()); + AddPPB(PPB_CharSet_Proxy::GetInfo()); + AddPPB(PPB_Console_Proxy::GetInfo()); + AddPPB(PPB_Context3D_Proxy::GetInfo()); + AddPPB(PPB_Context3D_Proxy::GetTextureMappingInfo()); + AddPPB(PPB_Core_Proxy::GetInfo()); + AddPPB(PPB_Crypto_Proxy::GetInfo()); + AddPPB(PPB_CursorControl_Proxy::GetInfo()); + AddPPB(PPB_FileChooser_Proxy::GetInfo()); + AddPPB(PPB_FileRef_Proxy::GetInfo()); + AddPPB(PPB_FileSystem_Proxy::GetInfo()); + AddPPB(PPB_Flash_Clipboard_Proxy::GetInfo()); + AddPPB(PPB_Flash_File_FileRef_Proxy::GetInfo()); + AddPPB(PPB_Flash_File_ModuleLocal_Proxy::GetInfo()); + AddPPB(PPB_Flash_Proxy::GetInfo()); + AddPPB(PPB_Flash_Menu_Proxy::GetInfo()); + AddPPB(PPB_Flash_TCPSocket_Proxy::GetInfo()); + AddPPB(PPB_Font_Proxy::GetInfo()); + AddPPB(PPB_Graphics2D_Proxy::GetInfo()); + AddPPB(PPB_ImageData_Proxy::GetInfo()); + AddPPB(PPB_InputEvent_Proxy::GetInfo()); + AddPPB(PPB_Instance_Proxy::GetInfo0_5()); + AddPPB(PPB_Instance_Proxy::GetInfo1_0()); + AddPPB(PPB_Instance_Proxy::GetInfoFullscreen()); + AddPPB(PPB_Instance_Proxy::GetInfoMessaging()); + AddPPB(PPB_Instance_Proxy::GetInfoPrivate()); + AddPPB(PPB_Memory_Proxy::GetInfo()); + AddPPB(PPB_OpenGLES2_Proxy::GetInfo()); + AddPPB(PPB_PDF_Proxy::GetInfo()); + AddPPB(PPB_Surface3D_Proxy::GetInfo()); + AddPPB(PPB_Testing_Proxy::GetInfo()); + AddPPB(PPB_URLLoader_Proxy::GetInfo()); + AddPPB(PPB_URLLoader_Proxy::GetTrustedInfo()); + AddPPB(PPB_URLRequestInfo_Proxy::GetInfo()); + AddPPB(PPB_URLResponseInfo_Proxy::GetInfo()); + AddPPB(PPB_URLUtil_Proxy::GetInfo()); + AddPPB(PPB_Var_Deprecated_Proxy::GetInfo()); + AddPPB(PPB_Var_Proxy::GetInfo()); + +#ifdef ENABLE_FLAPPER_HACKS + AddPPB(PPB_Flash_NetConnector_Proxy::GetInfo()); +#endif + + // PPP (plugin) interfaces. + AddPPP(PPP_Graphics3D_Proxy::GetInfo()); + AddPPP(PPP_InputEvent_Proxy::GetInfo()); + AddPPP(PPP_Instance_Private_Proxy::GetInfo()); + AddPPP(PPP_Instance_Proxy::GetInfo0_5()); +} + +void InterfaceList::AddPPP(const InterfaceProxy::Info* info) { + DCHECK(name_to_plugin_info_.find(info->name) == + name_to_plugin_info_.end()); + DCHECK(info->id >= INTERFACE_ID_NONE && info->id < INTERFACE_ID_COUNT); + + name_to_plugin_info_[info->name] = info; +} + +void InterfaceList::AddPPB(const InterfaceProxy::Info* info) { + DCHECK(name_to_browser_info_.find(info->name) == + name_to_browser_info_.end()); + DCHECK(info->id >= INTERFACE_ID_NONE && info->id < INTERFACE_ID_COUNT); + DCHECK(info->id == INTERFACE_ID_NONE || + id_to_browser_info_[info->id] == NULL); + + name_to_browser_info_[std::string(info->name)] = info; + if (info->id != INTERFACE_ID_NONE) + id_to_browser_info_[info->id] = info; +} + +// static +InterfaceList* InterfaceList::GetInstance() { + return Singleton<InterfaceList>::get(); +} + +} // namespace + +Dispatcher::Dispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc local_get_interface) + : ProxyChannel(remote_process_handle), + disallow_trusted_interfaces_(false), // TODO(brettw) make this settable. + local_get_interface_(local_get_interface), + callback_tracker_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +Dispatcher::~Dispatcher() { +} + +bool Dispatcher::OnMessageReceived(const IPC::Message& msg) { + // Control messages. + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(Dispatcher, msg) + IPC_MESSAGE_FORWARD(PpapiMsg_ExecuteCallback, &callback_tracker_, + CallbackTracker::ReceiveExecuteSerializedCallback) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } + return false; +} + +// static +const InterfaceProxy::Info* Dispatcher::GetPPBInterfaceInfo( + const std::string& name) { + const InterfaceList* list = InterfaceList::GetInstance(); + InterfaceList::NameToInfo::const_iterator found = + list->name_to_browser_info_.find(name); + if (found == list->name_to_browser_info_.end()) + return NULL; + return found->second; +} + +// static +const InterfaceProxy::Info* Dispatcher::GetPPBInterfaceInfo(InterfaceID id) { + if (id <= 0 || id >= INTERFACE_ID_COUNT) + return NULL; + const InterfaceList* list = InterfaceList::GetInstance(); + return list->id_to_browser_info_[id]; +} + +// static +const InterfaceProxy::Info* Dispatcher::GetPPPInterfaceInfo( + const std::string& name) { + const InterfaceList* list = InterfaceList::GetInstance(); + InterfaceList::NameToInfo::const_iterator found = + list->name_to_plugin_info_.find(name); + if (found == list->name_to_plugin_info_.end()) + return NULL; + return found->second; +} + +void Dispatcher::SetSerializationRules( + VarSerializationRules* var_serialization_rules) { + serialization_rules_.reset(var_serialization_rules); +} + +const void* Dispatcher::GetLocalInterface(const char* interface_name) { + return local_get_interface_(interface_name); +} + +base::MessageLoopProxy* Dispatcher::GetIPCMessageLoop() { + return delegate()->GetIPCMessageLoop(); +} + +void Dispatcher::AddIOThreadMessageFilter( + IPC::ChannelProxy::MessageFilter* filter) { + channel()->AddFilter(filter); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/dispatcher.h b/ppapi/proxy/dispatcher.h new file mode 100644 index 0000000..348c91c --- /dev/null +++ b/ppapi/proxy/dispatcher.h @@ -0,0 +1,124 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_DISPATCHER_H_ +#define PPAPI_PROXY_DISPATCHER_H_ + +#include <set> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/tracked_objects.h" +#include "ipc/ipc_channel_proxy.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/callback_tracker.h" +#include "ppapi/proxy/proxy_channel.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +namespace ppapi { +class WebKitForwarding; +} + +namespace pp { +namespace proxy { + +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 ProxyChannel { + public: + typedef const void* (*GetInterfaceFunc)(const char*); + typedef int32_t (*InitModuleFunc)(PP_Module, GetInterfaceFunc); + + virtual ~Dispatcher(); + + // 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(); + } + + // Wrapper for calling the local GetInterface function. + const void* GetLocalInterface(const char* interface_name); + + // Returns the pointer to the IO thread for processing IPC messages. + // TODO(brettw) remove this. It's a hack to support the Flash + // ModuleLocalThreadAdapter. When the thread stuff is sorted out, this + // implementation detail should be hidden. + base::MessageLoopProxy* GetIPCMessageLoop(); + + // Adds the given filter to the IO thread. Takes ownership of the pointer. + // TODO(brettw) remove this. It's a hack to support the Flash + // ModuleLocalThreadAdapter. When the thread stuff is sorted out, this + // implementation detail should be hidden. + void AddIOThreadMessageFilter(IPC::ChannelProxy::MessageFilter* filter); + + // TODO(brettw): What is this comment referring to? + // 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::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + CallbackTracker& callback_tracker() { + return callback_tracker_; + } + + // Retrieves the information associated with the given interface, identified + // either by name or ID. Each function searches either PPP or PPB interfaces. + static const InterfaceProxy::Info* GetPPBInterfaceInfo( + const std::string& name); + static const InterfaceProxy::Info* GetPPBInterfaceInfo( + InterfaceID id); + static const InterfaceProxy::Info* GetPPPInterfaceInfo( + const std::string& name); + + protected: + Dispatcher(base::ProcessHandle remote_process_handle, + 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); + + bool disallow_trusted_interfaces() const { + return disallow_trusted_interfaces_; + } + + private: + bool disallow_trusted_interfaces_; + + GetInterfaceFunc local_get_interface_; + + 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/enter_proxy.h b/ppapi/proxy/enter_proxy.h new file mode 100644 index 0000000..6e52705 --- /dev/null +++ b/ppapi/proxy/enter_proxy.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_ENTER_PROXY_H_ +#define PPAPI_PROXY_ENTER_PROXY_H_ + +#include "base/logging.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/thunk/enter.h" + +namespace pp { +namespace proxy { + +// Wrapper around EnterResourceNoLock that takes a host resource. This is used +// when handling messages in the plugin from the host and we need to convert to +// an object in the plugin side corresponding to that. +// +// This never locks since we assume the host Resource is coming from IPC, and +// never logs errors since we assume the host is doing reasonable things. +template<typename ResourceT> +class EnterPluginFromHostResource + : public ::ppapi::thunk::EnterResourceNoLock<ResourceT> { + public: + EnterPluginFromHostResource(const HostResource& host_resource) + : ::ppapi::thunk::EnterResourceNoLock<ResourceT>( + PluginResourceTracker::GetInstance()->PluginResourceForHostResource( + host_resource), + false) { + // Validate that we're in the plugin rather than the host. Otherwise this + // object will do the wrong thing. In the plugin, the instance should have + // a corresponding plugin dispatcher (assuming the resource is valid). + DCHECK(this->failed() || + PluginDispatcher::GetForInstance(host_resource.instance())); + } +}; + +template<typename ResourceT> +class EnterHostFromHostResource + : public ::ppapi::thunk::EnterResourceNoLock<ResourceT> { + public: + EnterHostFromHostResource(const HostResource& host_resource) + : ::ppapi::thunk::EnterResourceNoLock<ResourceT>( + host_resource.host_resource(), false) { + // Validate that we're in the host rather than the plugin. Otherwise this + // object will do the wrong thing. In the host, the instance should have + // a corresponding host disptacher (assuming the resource is valid). + DCHECK(this->failed() || + HostDispatcher::GetForInstance(host_resource.instance())); + } +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_ENTER_PROXY_H_ diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc new file mode 100644 index 0000000..1137a54 --- /dev/null +++ b/ppapi/proxy/host_dispatcher.cc @@ -0,0 +1,274 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/host_dispatcher.h" + +#include <map> + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/proxy/host_var_serialization_rules.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/resource_creation_proxy.h" + +namespace pp { +namespace proxy { + +namespace { + +typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap; +InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; + +typedef std::map<PP_Module, HostDispatcher*> ModuleToDispatcherMap; +ModuleToDispatcherMap* g_module_to_dispatcher = NULL; + +PP_Bool ReserveInstanceID(PP_Module module, PP_Instance instance) { + // Default to returning true (usable) failure. Otherwise, if there's some + // kind of communication error or the plugin just crashed, we'll get into an + // infinite loop generating new instnace IDs since we think they're all in + // use. + ModuleToDispatcherMap::const_iterator found = + g_module_to_dispatcher->find(module); + if (found == g_module_to_dispatcher->end()) { + NOTREACHED(); + return PP_TRUE; + } + + bool usable = true; + if (!found->second->Send(new PpapiMsg_ReserveInstanceId(instance, &usable))) + return PP_TRUE; + return PP_FromBool(usable); +} + +// Saves the state of the given bool and puts it back when it goes out of +// scope. +class BoolRestorer { + public: + BoolRestorer(bool* var) : var_(var), old_value_(*var) { + } + ~BoolRestorer() { + *var_ = old_value_; + } + private: + bool* var_; + bool old_value_; +}; + +} // namespace + +HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle, + PP_Module module, + GetInterfaceFunc local_get_interface) + : Dispatcher(remote_process_handle, local_get_interface), + pp_module_(module), + ppb_proxy_(NULL), + allow_plugin_reentrancy_(false) { + if (!g_module_to_dispatcher) + g_module_to_dispatcher = new ModuleToDispatcherMap; + (*g_module_to_dispatcher)[pp_module_] = this; + + const PPB_Var_Deprecated* var_interface = + static_cast<const PPB_Var_Deprecated*>( + local_get_interface(PPB_VAR_DEPRECATED_INTERFACE)); + SetSerializationRules(new HostVarSerializationRules(var_interface, module)); + + // TODO(brettw): It might be more testable to inject the PPB_Proxy_Private + // instead of requesting it from GetLocalInterface. + ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>( + GetLocalInterface(PPB_PROXY_PRIVATE_INTERFACE)); + DCHECK(ppb_proxy_) << "The proxy interface should always be supported."; + + ppb_proxy_->SetReserveInstanceIDCallback(pp_module_, &ReserveInstanceID); +} + +HostDispatcher::~HostDispatcher() { + g_module_to_dispatcher->erase(pp_module_); +} + +bool HostDispatcher::InitHostWithChannel( + Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client, + const ppapi::Preferences& preferences) { + if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) + return false; + Send(new PpapiMsg_SetPreferences(preferences)); + return true; +} + +// 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); +} + +bool HostDispatcher::IsPlugin() const { + return false; +} + +bool HostDispatcher::Send(IPC::Message* msg) { + TRACE_EVENT2("ppapi proxy", "HostDispatcher::Send", + "Class", IPC_MESSAGE_ID_CLASS(msg->type()), + "Line", IPC_MESSAGE_ID_LINE(msg->type())); + // Normal sync messages are set to unblock, which would normally cause the + // plugin to be reentered to process them. We only want to do this when we + // know the plugin is in a state to accept reentrancy. Since the plugin side + // never clears this flag on messages it sends, we can't get deadlock, but we + // may still get reentrancy in the host as a result. + if (!allow_plugin_reentrancy_) + msg->set_unblock(false); + return Dispatcher::Send(msg); +} + +bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { + TRACE_EVENT2("ppapi proxy", "HostDispatcher::OnMessageReceived", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + // We only want to allow reentrancy when the most recent message from the + // plugin was a scripting message. We save the old state of the flag on the + // stack in case we're (we are the host) being reentered ourselves. The flag + // is set to false here for all messages, and then the scripting API will + // explicitly set it to true during processing of those messages that can be + // reentered. + BoolRestorer restorer(&allow_plugin_reentrancy_); + allow_plugin_reentrancy_ = false; + + // Handle common control messages. + if (Dispatcher::OnMessageReceived(msg)) + return true; + + if (msg.routing_id() <= 0 || msg.routing_id() >= INTERFACE_ID_COUNT) { + NOTREACHED(); + // TODO(brettw): kill the plugin if it starts sending invalid messages? + return true; + } + + // New-style function proxies. + // TODO(brettw) this is hacked in for the routing for the types we've + // implemented in this style so far. When everything is implemented in this + // style, this function should be cleaned up. + if (msg.routing_id() == INTERFACE_ID_RESOURCE_CREATION) { + ResourceCreationProxy proxy(this); + return proxy.OnMessageReceived(msg); + } + + InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); + if (!proxy) { + // Autocreate any proxy objects to handle requests from the plugin. Since + // we always support all known PPB_* interfaces (modulo the trusted bit), + // there's very little checking necessary. + const InterfaceProxy::Info* info = GetPPBInterfaceInfo( + static_cast<InterfaceID>(msg.routing_id())); + if (!info || + (info->is_trusted && disallow_trusted_interfaces())) + return true; + proxy = CreatePPBInterfaceProxy(info); + } + + return proxy->OnMessageReceived(msg); +} + +void HostDispatcher::OnChannelError() { + Dispatcher::OnChannelError(); // Stop using the channel. + + // Tell the host about the crash so it can clean up and display notification. + ppb_proxy_->PluginCrashed(pp_module()); +} + +const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { + // First see if we even have a proxy for this interface. + const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface); + if (!info) + return NULL; + + PluginIFSupportedMap::iterator iter(plugin_if_supported_.find(interface)); + if (iter == plugin_if_supported_.end()) { + // Need to query. Cache the result so we only do this once. + bool supported = false; + Send(new PpapiMsg_SupportsInterface(interface, &supported)); + std::pair<PluginIFSupportedMap::iterator, bool> iter_success_pair; + iter_success_pair = plugin_if_supported_.insert( + PluginIFSupportedMap::value_type(interface, supported)); + iter = iter_success_pair.first; + } + if (iter->second) + return info->interface_ptr; + return NULL; +} + +InterfaceProxy* HostDispatcher::GetOrCreatePPBInterfaceProxy( + InterfaceID id) { + InterfaceProxy* proxy = target_proxies_[id].get(); + if (!proxy) { + const InterfaceProxy::Info* info = GetPPBInterfaceInfo(id); + if (!info) + return NULL; + + // Sanity check. This function won't normally be called for trusted + // interfaces, but in case somebody does this, we don't want to then give + // the plugin the ability to call that trusted interface (since the + // checking occurs at proxy-creation time). + if (info->is_trusted && disallow_trusted_interfaces()) + return NULL; + + proxy = CreatePPBInterfaceProxy(info); + } + return proxy; +} + +InterfaceProxy* HostDispatcher::CreatePPBInterfaceProxy( + const InterfaceProxy::Info* info) { + const void* local_interface = GetLocalInterface(info->name); + if (!local_interface) { + // This should always succeed since the browser should support the stuff + // the proxy does. If this happens, something is out of sync. + NOTREACHED(); + return NULL; + } + + InterfaceProxy* proxy = info->create_proxy(this, local_interface); + target_proxies_[info->id].reset(proxy); + return proxy; +} + +// ScopedModuleReference ------------------------------------------------------- + +ScopedModuleReference::ScopedModuleReference(Dispatcher* dispatcher) { + DCHECK(!dispatcher->IsPlugin()); + dispatcher_ = static_cast<HostDispatcher*>(dispatcher); + dispatcher_->ppb_proxy()->AddRefModule(dispatcher_->pp_module()); +} + +ScopedModuleReference::~ScopedModuleReference() { + dispatcher_->ppb_proxy()->ReleaseModule(dispatcher_->pp_module()); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h new file mode 100644 index 0000000..e3d9001 --- /dev/null +++ b/ppapi/proxy/host_dispatcher.h @@ -0,0 +1,161 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_HOST_DISPATCHER_H_ +#define PPAPI_PROXY_HOST_DISPATCHER_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "base/process.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/shared_impl/function_group_base.h" + +struct PPB_Proxy_Private; +struct PPB_Var_Deprecated; + +namespace base { +class WaitableEvent; +} + +namespace IPC { +class SyncChannel; +} + +namespace ppapi { +struct Preferences; +} + +namespace pp { +namespace proxy { + +class InterfaceProxy; +class VarSerialization; + +class HostDispatcher : public Dispatcher { + public: + // Constructor for the renderer side. + // + // You must call InitHostWithChannel after the constructor. + HostDispatcher(base::ProcessHandle host_process_handle, + PP_Module module, + GetInterfaceFunc local_get_interface); + ~HostDispatcher(); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitHostWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client, + const ppapi::Preferences& preferences); + + // 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); + + // Returns the host's notion of our PP_Module. This will be different than + // the plugin's notion of its PP_Module because the plugin process may be + // used by multiple renderer processes. + // + // Use this value instead of a value from the plugin whenever talking to the + // host. + PP_Module pp_module() const { return pp_module_; } + + // Dispatcher overrides. + virtual bool IsPlugin() const; + virtual bool Send(IPC::Message* msg); + + // IPC::Channel::Listener. + virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); + + // Proxied version of calling GetInterface on the plugin. This will check + // if the plugin supports the given interface (with caching) and returns the + // pointer to the proxied interface if it is supported. Returns NULL if the + // given interface isn't supported by the plugin or the proxy. + const void* GetProxiedInterface(const std::string& interface); + + // Returns the proxy object associated with the given interface ID, creating + // it if necessary. This is used in cases where a proxy needs to access code + // in the proxy for another interface. It's assumed that the interface always + // exists, so this is only used for browser proxies. + // + // Will return NULL if an interface isn't supported. + InterfaceProxy* GetOrCreatePPBInterfaceProxy(InterfaceID id); + + // See the value below. Call this when processing a scripting message from + // the plugin that can be reentered. + void set_allow_plugin_reentrancy() { + allow_plugin_reentrancy_ = true; + } + + // Returns the proxy interface for talking to the implementation. + const PPB_Proxy_Private* ppb_proxy() const { return ppb_proxy_; } + + private: + friend class HostDispatcherTest; + + // Makes an instance of the given PPB interface proxy, storing it in the + // target_proxies_ array. An proxy for this interface must not exist yet. + InterfaceProxy* CreatePPBInterfaceProxy(const InterfaceProxy::Info* info); + + PP_Module pp_module_; + + typedef std::map<std::string, bool> PluginIFSupportedMap; + // Maps interface name to whether that interface is supported. If an interface + // name is not in the map, that implies that we haven't queried for it yet. + std::map<std::string, bool> plugin_if_supported_; + + // All target proxies currently created. These are ones that receive + // messages. They are created on demand when we receive messages. + scoped_ptr<InterfaceProxy> target_proxies_[INTERFACE_ID_COUNT]; + + // Function proxies created for "new-style" FunctionGroups. + // TODO(brettw) this is in progress. It should be merged with the target + // proxies so there is one list to consult. + scoped_ptr< ::ppapi::FunctionGroupBase > + function_proxies_[INTERFACE_ID_COUNT]; + + // Guaranteed non-NULL. + const PPB_Proxy_Private* ppb_proxy_; + + // Set to true when the plugin is in a state that it can be reentered by a + // sync message from the host. We allow reentrancy only when we're processing + // a sync message from the renderer that is a scripting command. When the + // plugin is in this state, it needs to accept reentrancy since scripting may + // ultimately call back into the plugin. + bool allow_plugin_reentrancy_; + + DISALLOW_COPY_AND_ASSIGN(HostDispatcher); +}; + +// Create this object on the stack to prevent the module (and hence the +// dispatcher) from being deleted out from under you. This is necessary when +// calling some scripting functions that may delete the plugin. +// +// This may only be called in the host. The parameter is a plain Dispatcher +// since that's what most callers have. +class ScopedModuleReference { + public: + ScopedModuleReference(Dispatcher* dispatcher); + ~ScopedModuleReference(); + + private: + HostDispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ScopedModuleReference); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_HOST_DISPATCHER_H_ diff --git a/ppapi/proxy/host_dispatcher_unittest.cc b/ppapi/proxy/host_dispatcher_unittest.cc new file mode 100644 index 0000000..b2caa1a --- /dev/null +++ b/ppapi/proxy/host_dispatcher_unittest.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/scoped_ptr.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace pp { +namespace proxy { + +class HostDispatcherTest : public HostProxyTest { + public: + HostDispatcherTest() {} + + bool HasTargetProxy(InterfaceID id) { + return !!host_dispatcher()->target_proxies_[id].get(); + } +}; + +// TODO(brettw): Make and register an implementation of TrackerBase for this +// test. Possibly fix other failures too, once that's resolved. +TEST_F(HostDispatcherTest, FAILS_PPBCreation) { + RegisterTestInterface(PPB_AUDIO_INTERFACE, + reinterpret_cast<void*>(0xdeadbeef)); + + // Sending a PPB message out of the blue should create a target proxy for + // that interface in the plugin. + EXPECT_FALSE(HasTargetProxy(INTERFACE_ID_PPB_AUDIO)); + PpapiMsg_PPBAudio_NotifyAudioStreamCreated audio_msg( + INTERFACE_ID_PPB_AUDIO, HostResource(), 0, + IPC::PlatformFileForTransit(), base::SharedMemoryHandle(), 0); + host_dispatcher()->OnMessageReceived(audio_msg); + EXPECT_TRUE(HasTargetProxy(INTERFACE_ID_PPB_AUDIO)); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/host_resource.h b/ppapi/proxy/host_resource.h new file mode 100644 index 0000000..fe1abb2 --- /dev/null +++ b/ppapi/proxy/host_resource.h @@ -0,0 +1,70 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_HOST_RESOURCE_H_ +#define PPAPI_PROXY_HOST_RESOURCE_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" + +namespace pp { +namespace proxy { + +// Represents a PP_Resource sent over the wire. This just wraps a PP_Resource. +// The point is to prevent mistakes where the wrong resource value is sent. +// Resource values are remapped in the plugin so that it can talk to multiple +// hosts. If all values were PP_Resource, it would be easy to forget to do +// this tranformation. +// +// All HostResources respresent IDs valid in the host. +class HostResource { + public: + HostResource() : instance_(0), host_resource_(0) { + } + + bool is_null() const { + return !host_resource_; + } + + // Some resources are plugin-side only and don't have a corresponding + // resource in the host. Yet these resources still need an instance to be + // associated with. This function creates a HostResource with the given + // instances and a 0 host resource ID for these cases. + static HostResource MakeInstanceOnly(PP_Instance instance) { + HostResource resource; + resource.SetHostResource(instance, 0); + return resource; + } + + // Sets and retrieves the internal PP_Resource which is valid for the host + // (a.k.a. renderer, as opposed to the plugin) process. + // + // DO NOT CALL THESE FUNCTIONS IN THE PLUGIN SIDE OF THE PROXY. The values + // will be invalid. See the class comment above. + void SetHostResource(PP_Instance instance, PP_Resource resource) { + instance_ = instance; + host_resource_ = resource; + } + PP_Resource host_resource() const { + return host_resource_; + } + + PP_Instance instance() const { return instance_; } + + // This object is used in maps so we need to provide this sorting operator. + bool operator<(const HostResource& other) const { + if (instance_ != other.instance_) + return instance_ < other.instance_; + return host_resource_ < other.host_resource_; + } + + private: + PP_Instance instance_; + PP_Resource host_resource_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_HOST_RESOURCE_H_ diff --git a/ppapi/proxy/host_var_serialization_rules.cc b/ppapi/proxy/host_var_serialization_rules.cc new file mode 100644 index 0000000..2a1d0ee --- /dev/null +++ b/ppapi/proxy/host_var_serialization_rules.cc @@ -0,0 +1,96 @@ +// 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_var_serialization_rules.h" + +#include "base/logging.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" + +namespace pp { +namespace proxy { + +HostVarSerializationRules::HostVarSerializationRules( + const PPB_Var_Deprecated* var_interface, + PP_Module pp_module) + : var_interface_(var_interface), + pp_module_(pp_module) { +} + +HostVarSerializationRules::~HostVarSerializationRules() { +} + +PP_Var HostVarSerializationRules::SendCallerOwned(const PP_Var& var, + std::string* str_val) { + if (var.type == PP_VARTYPE_STRING) + VarToString(var, str_val); + return var; +} + +PP_Var HostVarSerializationRules::BeginReceiveCallerOwned( + const PP_Var& var, + const std::string* str_val, + Dispatcher* /* dispatcher */) { + if (var.type == PP_VARTYPE_STRING) { + // Convert the string to the context of the current process. + return var_interface_->VarFromUtf8(pp_module_, str_val->c_str(), + static_cast<uint32_t>(str_val->size())); + } + return var; +} + +void HostVarSerializationRules::EndReceiveCallerOwned(const PP_Var& var) { + if (var.type == PP_VARTYPE_STRING) { + // Destroy the string BeginReceiveCallerOwned created above. + var_interface_->Release(var); + } +} + +PP_Var HostVarSerializationRules::ReceivePassRef(const PP_Var& var, + const std::string& str_val, + Dispatcher* /* dispatcher */) { + if (var.type == PP_VARTYPE_STRING) { + // Convert the string to the context of the current process. + return var_interface_->VarFromUtf8(pp_module_, str_val.c_str(), + static_cast<uint32_t>(str_val.size())); + } + + // See PluginVarSerialization::BeginSendPassRef for an example. + if (var.type == PP_VARTYPE_OBJECT) + var_interface_->AddRef(var); + return var; +} + +PP_Var HostVarSerializationRules::BeginSendPassRef(const PP_Var& var, + std::string* str_val) { + // See PluginVarSerialization::ReceivePassRef for an example. We don't need + // to do anything here other than convert the string. + if (var.type == PP_VARTYPE_STRING) + VarToString(var, str_val); + return var; +} + +void HostVarSerializationRules::EndSendPassRef(const PP_Var& /* var */, + Dispatcher* /* dispatcher */) { + // See PluginVarSerialization::ReceivePassRef for an example. We don't need + // to do anything here. +} + +void HostVarSerializationRules::VarToString(const PP_Var& var, + std::string* str) { + DCHECK(var.type == PP_VARTYPE_STRING); + + // This could be optimized to avoid an extra string copy by going to a lower + // level of the browser's implementation of strings where we already have + // a std::string. + uint32_t len = 0; + const char* data = var_interface_->VarToUtf8(var, &len); + str->assign(data, len); +} + +void HostVarSerializationRules::ReleaseObjectRef(const PP_Var& var) { + var_interface_->Release(var); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/host_var_serialization_rules.h b/ppapi/proxy/host_var_serialization_rules.h new file mode 100644 index 0000000..4fd39be --- /dev/null +++ b/ppapi/proxy/host_var_serialization_rules.h @@ -0,0 +1,53 @@ +// 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_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_HOST_VAR_SERIALIZATION_RULES_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/var_serialization_rules.h" + +struct PPB_Var_Deprecated; + +namespace pp { +namespace proxy { + +class VarTracker; + +// Implementation of the VarSerializationRules interface for the host side. +class HostVarSerializationRules : public VarSerializationRules { + public: + HostVarSerializationRules(const PPB_Var_Deprecated* var_interface, + PP_Module pp_module); + ~HostVarSerializationRules(); + + // VarSerialization implementation. + virtual PP_Var SendCallerOwned(const PP_Var& var, std::string* str_val); + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var, + const std::string* str_val, + Dispatcher* dispatcher); + virtual void EndReceiveCallerOwned(const PP_Var& var); + virtual PP_Var ReceivePassRef(const PP_Var& var, + const std::string& str_val, + Dispatcher* dispatcher); + virtual PP_Var BeginSendPassRef(const PP_Var& var, std::string* str_val); + virtual void EndSendPassRef(const PP_Var& var, Dispatcher* dispatcher); + virtual void ReleaseObjectRef(const PP_Var& var); + + private: + // Converts the given var (which must be a VARTYPE_STRING) to the given + // string object. + void VarToString(const PP_Var& var, std::string* str); + + const PPB_Var_Deprecated* var_interface_; + PP_Module pp_module_; + + DISALLOW_COPY_AND_ASSIGN(HostVarSerializationRules); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_HOST_VAR_SERIALIZATION_RULES_H_ diff --git a/ppapi/proxy/interface_id.h b/ppapi/proxy/interface_id.h new file mode 100644 index 0000000..26ef71f6a --- /dev/null +++ b/ppapi/proxy/interface_id.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#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_NONE = 0, + INTERFACE_ID_PPB_AUDIO = 1, + INTERFACE_ID_PPB_AUDIO_CONFIG, + INTERFACE_ID_PPB_BROKER, + INTERFACE_ID_PPB_BUFFER, + INTERFACE_ID_PPB_CHAR_SET, + INTERFACE_ID_PPB_CONSOLE, + INTERFACE_ID_PPB_CONTEXT_3D, + INTERFACE_ID_PPB_CORE, + INTERFACE_ID_PPB_CRYPTO, + INTERFACE_ID_PPB_CURSORCONTROL, + INTERFACE_ID_PPB_FILE_CHOOSER, + INTERFACE_ID_PPB_FILE_REF, + INTERFACE_ID_PPB_FILE_SYSTEM, + INTERFACE_ID_PPB_FIND, + INTERFACE_ID_PPB_FLASH, + INTERFACE_ID_PPB_FLASH_CLIPBOARD, + INTERFACE_ID_PPB_FLASH_FILE_FILEREF, + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + INTERFACE_ID_PPB_FLASH_MENU, + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, + INTERFACE_ID_PPB_FLASH_TCPSOCKET, + INTERFACE_ID_PPB_FONT, + INTERFACE_ID_PPB_GRAPHICS_2D, + INTERFACE_ID_PPB_IMAGE_DATA, + INTERFACE_ID_PPB_INSTANCE, + INTERFACE_ID_PPB_INSTANCE_PRIVATE, + INTERFACE_ID_PPB_MEMORY, + INTERFACE_ID_PPB_OPENGLES2, + INTERFACE_ID_PPB_PDF, + INTERFACE_ID_PPB_SURFACE_3D, + INTERFACE_ID_PPB_TESTING, + INTERFACE_ID_PPB_URL_LOADER, + INTERFACE_ID_PPB_URL_REQUEST_INFO, + INTERFACE_ID_PPB_URL_RESPONSE_INFO, + INTERFACE_ID_PPB_URL_UTIL, + INTERFACE_ID_PPB_VAR, + INTERFACE_ID_PPB_VAR_DEPRECATED, + INTERFACE_ID_PPB_VIDEO_DECODER_DEV, + + INTERFACE_ID_PPP_CLASS, + INTERFACE_ID_PPP_GRAPHICS_3D_DEV, + INTERFACE_ID_PPP_INPUT_EVENT, + INTERFACE_ID_PPP_INSTANCE, + INTERFACE_ID_PPP_INSTANCE_PRIVATE, + INTERFACE_ID_PPP_VIDEO_DECODER_DEV, + + INTERFACE_ID_RESOURCE_CREATION, + + // 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..3b16f9e --- /dev/null +++ b/ppapi/proxy/interface_proxy.h @@ -0,0 +1,79 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#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: + // Factory function type for interfaces. Ownership of the returned pointer + // is transferred to the caller. + typedef InterfaceProxy* (*Factory)(Dispatcher* dispatcher, + const void* target_interface); + + // Information about the interface. Each interface has a static function to + // return its info, which allows either construction on the target side, and + // getting the proxied interface on the source side (see dispatcher.h for + // terminology). + struct Info { + const void* interface_ptr; + + const char* name; + InterfaceID id; + + bool is_trusted; + + InterfaceProxy::Factory create_proxy; + }; + + virtual ~InterfaceProxy(); + + // The actual implementation of the given interface in the current process. + const void* target_interface() const { return target_interface_; } + + Dispatcher* dispatcher() const { return dispatcher_; } + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // Sub-classes must implement IPC::Channel::Listener which contains this: + //virtual bool OnMessageReceived(const IPC::Message& msg); + + protected: + // 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. + InterfaceProxy(Dispatcher* dispatcher, const void* target_interface); + + 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/mock_resource.cc b/ppapi/proxy/mock_resource.cc new file mode 100644 index 0000000..21e5381 --- /dev/null +++ b/ppapi/proxy/mock_resource.cc @@ -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. + +#include "ppapi/proxy/mock_resource.h" + +namespace pp { +namespace proxy { + +MockResource::MockResource(const HostResource& resource) + : PluginResource(resource) { +} + +MockResource::~MockResource() { +} + +MockResource* MockResource::AsMockResource() { + return this; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/mock_resource.h b/ppapi/proxy/mock_resource.h new file mode 100644 index 0000000..7e38be1 --- /dev/null +++ b/ppapi/proxy/mock_resource.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_MOCK_RESOURCE_H_ +#define PPAPI_PROXY_MOCK_RESOURCE_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/plugin_resource.h" + +namespace pp { +namespace proxy { + +class MockResource : public PluginResource { + public: + MockResource(const HostResource& resource); + virtual ~MockResource(); + + // Resource overrides. + virtual MockResource* AsMockResource(); + + private: + DISALLOW_COPY_AND_ASSIGN(MockResource); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_MOCK_RESOURCE_H_ diff --git a/ppapi/proxy/plugin_dispatcher.cc b/ppapi/proxy/plugin_dispatcher.cc new file mode 100644 index 0000000..53dab26 --- /dev/null +++ b/ppapi/proxy/plugin_dispatcher.cc @@ -0,0 +1,312 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_dispatcher.h" + +#include <map> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_channel.h" +#include "base/debug/trace_event.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_message_filter.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_serialization_rules.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_char_set_proxy.h" +#include "ppapi/proxy/ppb_cursor_control_proxy.h" +#include "ppapi/proxy/ppb_font_proxy.h" +#include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/resource_creation_proxy.h" +#include "ppapi/shared_impl/tracker_base.h" + +#if defined(OS_POSIX) +#include "base/eintr_wrapper.h" +#include "ipc/ipc_channel_posix.h" +#endif + +namespace pp { +namespace proxy { + +namespace { + +typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; +InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; + +} // namespace + +PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc get_interface) + : Dispatcher(remote_process_handle, get_interface), + plugin_delegate_(NULL), + received_preferences_(false), + plugin_dispatcher_id_(0) { + SetSerializationRules(new PluginVarSerializationRules); + + // 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. + target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this)); + + ::ppapi::TrackerBase::Init( + &PluginResourceTracker::GetTrackerBaseInstance); +} + +PluginDispatcher::~PluginDispatcher() { + if (plugin_delegate_) + plugin_delegate_->Unregister(plugin_dispatcher_id_); +} + +// static +PluginDispatcher* PluginDispatcher::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 +const void* PluginDispatcher::GetInterfaceFromDispatcher( + const char* interface) { + // All interfaces the plugin requests of the browser are "PPB". + const InterfaceProxy::Info* info = GetPPBInterfaceInfo(interface); + if (!info) + return NULL; + return info->interface_ptr; +} + +bool PluginDispatcher::InitPluginWithChannel( + PluginDelegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) + return false; + plugin_delegate_ = delegate; + plugin_dispatcher_id_ = plugin_delegate_->Register(this); + + // The message filter will intercept and process certain messages directly + // on the I/O thread. + channel()->AddFilter( + new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet())); + return true; +} + +bool PluginDispatcher::IsPlugin() const { + return true; +} + +bool PluginDispatcher::Send(IPC::Message* msg) { + DCHECK(MessageLoop::current()); + TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send", + "Class", IPC_MESSAGE_ID_CLASS(msg->type()), + "Line", IPC_MESSAGE_ID_LINE(msg->type())); + // We always want plugin->renderer messages to arrive in-order. If some sync + // and some async messages are send in response to a synchronous + // renderer->plugin call, the sync reply will be processed before the async + // reply, and everything will be confused. + // + // Allowing all async messages to unblock the renderer means more reentrancy + // there but gives correct ordering. + msg->set_unblock(true); + return Dispatcher::Send(msg); +} + +bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { + TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", + "Class", IPC_MESSAGE_ID_CLASS(msg.type()), + "Line", IPC_MESSAGE_ID_LINE(msg.type())); + // Handle common control messages. + if (Dispatcher::OnMessageReceived(msg)) + return true; + + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + // Handle some plugin-specific control messages. + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) + IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) + IPC_END_MESSAGE_MAP() + return handled; + } + + if (msg.routing_id() <= 0 || msg.routing_id() >= INTERFACE_ID_COUNT) { + // Host is sending us garbage. Since it's supposed to be trusted, this + // isn't supposed to happen. Crash here in all builds in case the renderer + // is compromised. + CHECK(false); + return true; + } + + // There are two cases: + // + // * The first case is that the host is calling a PPP interface. It will + // always do a check for the interface before sending messages, and this + // will create the necessary interface proxy at that time. So when we + // actually receive a message, we know such a proxy will exist. + // + // * The second case is that the host is sending a response to the plugin + // side of a PPB interface (some, like the URL loader, have complex + // response messages). Since the host is trusted and not supposed to be + // doing silly things, we can just create a PPB proxy project on demand the + // first time it's needed. + + InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); + if (!proxy) { + // Handle the first time the host calls a PPB reply interface by + // autocreating it. + const InterfaceProxy::Info* info = GetPPBInterfaceInfo( + static_cast<InterfaceID>(msg.routing_id())); + if (!info) { + NOTREACHED(); + return true; + } + proxy = info->create_proxy(this, NULL); + target_proxies_[info->id].reset(proxy); + } + + return proxy->OnMessageReceived(msg); +} + +void PluginDispatcher::OnChannelError() { + Dispatcher::OnChannelError(); + + // The renderer has crashed or exited. This channel and all instances + // associated with it are no longer valid. + ForceFreeAllInstances(); + // TODO(brettw) free resources too! + delete this; +} + +void PluginDispatcher::DidCreateInstance(PP_Instance instance) { + if (!g_instance_to_dispatcher) + g_instance_to_dispatcher = new InstanceToDispatcherMap; + (*g_instance_to_dispatcher)[instance] = this; + + instance_map_[instance] = InstanceData(); +} + +void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { + InstanceDataMap::iterator it = instance_map_.find(instance); + if (it != instance_map_.end()) + instance_map_.erase(it); + + if (g_instance_to_dispatcher) { + InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( + instance); + if (found != g_instance_to_dispatcher->end()) { + DCHECK(found->second == this); + g_instance_to_dispatcher->erase(found); + } else { + NOTREACHED(); + } + } +} + +InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { + InstanceDataMap::iterator it = instance_map_.find(instance); + return (it == instance_map_.end()) ? NULL : &it->second; +} + +void PluginDispatcher::PostToWebKitThread( + const tracked_objects::Location& from_here, + const base::Closure& task) { + return plugin_delegate_->PostToWebKitThread(from_here, task); +} + +bool PluginDispatcher::SendToBrowser(IPC::Message* msg) { + return plugin_delegate_->SendToBrowser(msg); +} + +ppapi::WebKitForwarding* PluginDispatcher::GetWebKitForwarding() { + return plugin_delegate_->GetWebKitForwarding(); +} + +::ppapi::FunctionGroupBase* PluginDispatcher::GetFunctionAPI( + pp::proxy::InterfaceID id) { + scoped_ptr< ::ppapi::FunctionGroupBase >& proxy = function_proxies_[id]; + + if (proxy.get()) + return proxy.get(); + + if (id == INTERFACE_ID_PPB_CHAR_SET) + proxy.reset(new PPB_CharSet_Proxy(this, NULL)); + else if(id == INTERFACE_ID_PPB_CURSORCONTROL) + proxy.reset(new PPB_CursorControl_Proxy(this, NULL)); + else if (id == INTERFACE_ID_PPB_FONT) + proxy.reset(new PPB_Font_Proxy(this, NULL)); + else if (id == INTERFACE_ID_PPB_INSTANCE) + proxy.reset(new PPB_Instance_Proxy(this, NULL)); + else if (id == INTERFACE_ID_RESOURCE_CREATION) + proxy.reset(new ResourceCreationProxy(this)); + + return proxy.get(); +} + +void PluginDispatcher::ForceFreeAllInstances() { + if (!g_instance_to_dispatcher) + return; + + // Iterating will remove each item from the map, so we need to make a copy + // to avoid things changing out from under is. + InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; + for (InstanceToDispatcherMap::iterator i = temp_map.begin(); + i != temp_map.end(); ++i) { + if (i->second == this) { + // Synthesize an "instance destroyed" message, this will notify the + // plugin and also remove it from our list of tracked plugins. + PpapiMsg_PPPInstance_DidDestroy msg(INTERFACE_ID_PPP_INSTANCE, i->first); + OnMessageReceived(msg); + delete msg.GetReplyDeserializer(); + } + } +} + +void PluginDispatcher::OnMsgSupportsInterface( + const std::string& interface_name, + bool* result) { + *result = false; + + // Setup a proxy for receiving the messages from this interface. + const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); + if (!info) + return; // Interface not supported by proxy. + + // Check for a cached result. + if (target_proxies_[info->id].get()) { + *result = true; + return; + } + + // Query the plugin & cache the result. + const void* interface_functions = GetLocalInterface(interface_name.c_str()); + if (!interface_functions) + return; + target_proxies_[info->id].reset( + info->create_proxy(this, interface_functions)); + *result = true; +} + +void PluginDispatcher::OnMsgSetPreferences(const ::ppapi::Preferences& prefs) { + // The renderer may send us preferences more than once (currently this + // happens every time a new plugin instance is created). Since we don't have + // a way to signal to the plugin that the preferences have changed, changing + // the default fonts and such in the middle of a running plugin could be + // confusing to it. As a result, we never allow the preferences to be changed + // once they're set. The user will have to restart to get new font prefs + // propogated to plugins. + if (!received_preferences_) { + received_preferences_ = true; + preferences_ = prefs; + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_dispatcher.h b/ppapi/proxy/plugin_dispatcher.h new file mode 100644 index 0000000..ae6da60 --- /dev/null +++ b/ppapi/proxy/plugin_dispatcher.h @@ -0,0 +1,174 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PLUGIN_DISPATCHER_H_ +#define PPAPI_PROXY_PLUGIN_DISPATCHER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/memory/scoped_ptr.h" +#include "base/process.h" +#include "build/build_config.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/shared_impl/ppapi_preferences.h" + +class MessageLoop; + +namespace base { +class WaitableEvent; +} + +namespace ppapi { +struct Preferences; +} + +namespace pp { +namespace proxy { + +// Used to keep track of per-instance data. +struct InstanceData { + InstanceData() : fullscreen(PP_FALSE) {} + PP_Rect position; + PP_Bool fullscreen; +}; + +class PluginDispatcher : public Dispatcher { + public: + class PluginDelegate : public ProxyChannel::Delegate { + public: + // Returns the set used for globally uniquifying PP_Instances. This same + // set must be returned for all channels. + // + // DEREFERENCE ONLY ON THE I/O THREAD. + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() = 0; + + // Returns the WebKit forwarding object used to make calls into WebKit. + // Necessary only on the plugin side. + virtual ppapi::WebKitForwarding* GetWebKitForwarding() = 0; + + // Posts the given task to the WebKit thread associated with this plugin + // process. The WebKit thread should be lazily created if it does not + // exist yet. + virtual void PostToWebKitThread(const tracked_objects::Location& from_here, + const base::Closure& task) = 0; + + // Sends the given message to the browser. Identical semantics to + // IPC::Message::Sender interface. + virtual bool SendToBrowser(IPC::Message* msg) = 0; + + // Registers the plugin dispatcher and returns an ID. + // Plugin dispatcher IDs will be used to dispatch messages from the browser. + // Each call to Register() has to be matched with a call to Unregister(). + virtual uint32 Register(PluginDispatcher* plugin_dispatcher) = 0; + virtual void Unregister(uint32 plugin_dispatcher_id) = 0; + }; + + // 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 InitPluginWithChannel after the constructor. + PluginDispatcher(base::ProcessHandle remote_process_handle, + GetInterfaceFunc get_interface); + virtual ~PluginDispatcher(); + + // The plugin side maintains a mapping from PP_Instance to Dispatcher so + // that we can send the messages to the right channel if there are multiple + // renderers sharing the same plugin. This mapping is maintained by + // DidCreateInstance/DidDestroyInstance. + static PluginDispatcher* GetForInstance(PP_Instance instance); + + static const void* GetInterfaceFromDispatcher(const char* interface); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + bool InitPluginWithChannel(PluginDelegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + // Dispatcher overrides. + virtual bool IsPlugin() const; + virtual bool Send(IPC::Message* msg); + + // IPC::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); + + // Keeps track of which dispatcher to use for each instance, active instances + // and tracks associated data like the current size. + void DidCreateInstance(PP_Instance instance); + void DidDestroyInstance(PP_Instance instance); + + // Gets the data for an existing instance, or NULL if the instance id doesn't + // correspond to a known instance. + InstanceData* GetInstanceData(PP_Instance instance); + + // Posts the given task to the WebKit thread. + void PostToWebKitThread(const tracked_objects::Location& from_here, + const base::Closure& task); + + // Calls the PluginDelegate.SendToBrowser function. + bool SendToBrowser(IPC::Message* msg); + + // Returns the WebKitForwarding object used to forward events to WebKit. + ppapi::WebKitForwarding* GetWebKitForwarding(); + + // Returns the Preferences. + const ppapi::Preferences& preferences() const { return preferences_; } + + // Returns the "new-style" function API for the given interface ID, creating + // it if necessary. + // TODO(brettw) this is in progress. It should be merged with the target + // proxies so there is one list to consult. + ppapi::FunctionGroupBase* GetFunctionAPI( + pp::proxy::InterfaceID id); + + uint32 plugin_dispatcher_id() const { return plugin_dispatcher_id_; } + + private: + friend class PluginDispatcherTest; + + // Notifies all live instances that they're now closed. This is used when + // a renderer crashes or some other error is received. + void ForceFreeAllInstances(); + + // IPC message handlers. + void OnMsgSupportsInterface(const std::string& interface_name, bool* result); + void OnMsgSetPreferences(const ::ppapi::Preferences& prefs); + + PluginDelegate* plugin_delegate_; + + // All target proxies currently created. These are ones that receive + // messages. + scoped_ptr<InterfaceProxy> target_proxies_[INTERFACE_ID_COUNT]; + + // Function proxies created for "new-style" FunctionGroups. + // TODO(brettw) this is in progress. It should be merged with the target + // proxies so there is one list to consult. + scoped_ptr< ::ppapi::FunctionGroupBase > + function_proxies_[INTERFACE_ID_COUNT]; + + typedef base::hash_map<PP_Instance, InstanceData> InstanceDataMap; + InstanceDataMap instance_map_; + + // The preferences sent from the host. We only want to set this once, which + // is what the received_preferences_ indicates. See OnMsgSetPreferences. + bool received_preferences_; + ppapi::Preferences preferences_; + + uint32 plugin_dispatcher_id_; + + DISALLOW_COPY_AND_ASSIGN(PluginDispatcher); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_DISPATCHER_H_ diff --git a/ppapi/proxy/plugin_dispatcher_unittest.cc b/ppapi/proxy/plugin_dispatcher_unittest.cc new file mode 100644 index 0000000..f3e8da5 --- /dev/null +++ b/ppapi/proxy/plugin_dispatcher_unittest.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/scoped_ptr.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace pp { +namespace proxy { + +namespace { + +bool received_create = false; + +// Implement PPB_Audio since it's a relatively simple PPB interface and +// includes bidirectional communication. +PP_Resource Create(PP_Instance instance, PP_Resource config, + PPB_Audio_Callback audio_callback, void* user_data) { + received_create = true; + return 0; +} +PP_Bool IsAudio(PP_Resource resource) { + return PP_FALSE; +} +PP_Resource GetCurrentConfig(PP_Resource audio) { + return 0; +} +PP_Bool StartPlayback(PP_Resource audio) { + return PP_FALSE; +} +PP_Bool StopPlayback(PP_Resource audio) { + return PP_FALSE; +} + +PPB_Audio dummy_audio_interface = { + &Create, + &IsAudio, + &GetCurrentConfig, + &StartPlayback, + &StopPlayback +}; + +PPP_Instance dummy_ppp_instance_interface = {}; + +} // namespace + +class PluginDispatcherTest : public PluginProxyTest { + public: + PluginDispatcherTest() {} + + bool HasTargetProxy(InterfaceID id) { + return !!plugin_dispatcher()->target_proxies_[id].get(); + } +}; + +TEST_F(PluginDispatcherTest, SupportsInterface) { + RegisterTestInterface(PPB_AUDIO_INTERFACE, &dummy_audio_interface); + RegisterTestInterface(PPP_INSTANCE_INTERFACE, &dummy_ppp_instance_interface); + + // Sending a request for a random interface should fail. + EXPECT_FALSE(SupportsInterface("Random interface")); + + // Sending a request for a PPB interface should fail even though we've + // registered it as existing in the GetInterface function (the plugin proxy + // should only respond to PPP interfaces when asked if it supports them). + EXPECT_FALSE(SupportsInterface(PPB_AUDIO_INTERFACE)); + + // Sending a request for a supported PPP interface should succeed. + EXPECT_TRUE(SupportsInterface(PPP_INSTANCE_INTERFACE)); +} + +TEST_F(PluginDispatcherTest, PPBCreation) { + // Sending a PPB message out of the blue should create a target proxy for + // that interface in the plugin. + EXPECT_FALSE(HasTargetProxy(INTERFACE_ID_PPB_AUDIO)); + PpapiMsg_PPBAudio_NotifyAudioStreamCreated audio_msg( + INTERFACE_ID_PPB_AUDIO, HostResource(), 0, + IPC::PlatformFileForTransit(), base::SharedMemoryHandle(), 0); + plugin_dispatcher()->OnMessageReceived(audio_msg); + EXPECT_TRUE(HasTargetProxy(INTERFACE_ID_PPB_AUDIO)); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/plugin_message_filter.cc b/ppapi/proxy/plugin_message_filter.cc new file mode 100644 index 0000000..9df2208 --- /dev/null +++ b/ppapi/proxy/plugin_message_filter.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_message_filter.h" + +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +PluginMessageFilter::PluginMessageFilter( + std::set<PP_Instance>* seen_instance_ids) + : seen_instance_ids_(seen_instance_ids), + channel_(NULL) { +} + +PluginMessageFilter::~PluginMessageFilter() { +} + +void PluginMessageFilter::OnFilterAdded(IPC::Channel* channel) { + channel_ = channel; +} + +void PluginMessageFilter::OnFilterRemoved() { + channel_ = NULL; +} + +bool PluginMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginMessageFilter, message) + IPC_MESSAGE_HANDLER(PpapiMsg_ReserveInstanceId, OnMsgReserveInstanceId) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +bool PluginMessageFilter::Send(IPC::Message* msg) { + if (channel_) + return channel_->Send(msg); + delete msg; + return false; +} + +void PluginMessageFilter::OnMsgReserveInstanceId(PP_Instance instance, + bool* usable) { + // See the message definition for how this works. + if (seen_instance_ids_->find(instance) != seen_instance_ids_->end()) { + // Instance ID already seen, reject it. + *usable = false; + return; + } + + // This instance ID is new so we can return that it's usable and mark it as + // used for future reference. + seen_instance_ids_->insert(instance); + *usable = true; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_message_filter.h b/ppapi/proxy/plugin_message_filter.h new file mode 100644 index 0000000..fa3b2f4 --- /dev/null +++ b/ppapi/proxy/plugin_message_filter.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ +#define PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ + +#include <set> + +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_message.h" +#include "ppapi/c/pp_instance.h" + +namespace pp { +namespace proxy { + +// Listens for messages on the I/O thread of the plugin and handles some of +// them to avoid needing to block on the plugin. +// +// There is one instance of this class for each renderer channel (same as for +// the PluginDispatchers). +class PluginMessageFilter : public IPC::ChannelProxy::MessageFilter, + public IPC::Message::Sender { + public: + // The input is a pointer to a set that will be used to uniquify PP_Instances + // across all renderer channels. The same pointer should be passed to each + // MessageFilter to ensure uniqueness, and the value should outlive this + // class. + PluginMessageFilter(std::set<PP_Instance>* seen_instance_ids); + virtual ~PluginMessageFilter(); + + // MessageFilter implementation. + virtual void OnFilterAdded(IPC::Channel* channel); + virtual void OnFilterRemoved(); + virtual bool OnMessageReceived(const IPC::Message& message); + + // Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + private: + void OnMsgReserveInstanceId(PP_Instance instance, bool* usable); + + // All instance IDs every queried by any renderer on this plugin. This is + // used to make sure that new instance IDs are unique. This is a non-owning + // pointer, it will be managed by the later that creates this class. + std::set<PP_Instance>* seen_instance_ids_; + + // The IPC channel to the renderer. May be NULL if we're not currently + // attached as a filter. + IPC::Channel* channel_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_MESSAGE_FILTER_H_ diff --git a/ppapi/proxy/plugin_resource.cc b/ppapi/proxy/plugin_resource.cc new file mode 100644 index 0000000..d25dde1 --- /dev/null +++ b/ppapi/proxy/plugin_resource.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_resource.h" + +namespace pp { +namespace proxy { + +PluginResource::PluginResource(const HostResource& resource) + : host_resource_(resource) { +} + +PluginResource::~PluginResource() { +} + +#define DEFINE_TYPE_GETTER(RESOURCE) \ + RESOURCE* PluginResource::As##RESOURCE() { return NULL; } +FOR_ALL_PLUGIN_RESOURCES(DEFINE_TYPE_GETTER) +#undef DEFINE_TYPE_GETTER + +PluginDispatcher* PluginResource::GetDispatcher() { + PluginDispatcher* disp = PluginDispatcher::GetForInstance(instance()); + CHECK(disp); + return disp; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h new file mode 100644 index 0000000..eff74b4 --- /dev/null +++ b/ppapi/proxy/plugin_resource.h @@ -0,0 +1,97 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PLUGIN_RESOURCE_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/shared_impl/resource_object_base.h" + +// If you inherit from resource, make sure you add the class name here. +#define FOR_ALL_PLUGIN_RESOURCES(F) \ + F(Audio) \ + F(AudioConfig) \ + F(Broker) \ + F(Buffer) \ + F(Context3D) \ + F(FileChooser) \ + F(FileRef) \ + F(FileSystem) \ + F(FlashMenu) \ + F(FlashNetConnector) \ + F(Font) \ + F(Graphics2D) \ + F(ImageData) \ + F(MockResource) \ + F(PrivateFontFile) \ + F(Surface3D) \ + F(URLLoader) \ + F(URLRequestInfo)\ + F(URLResponseInfo) + +namespace pp { +namespace proxy { + +// Forward declaration of Resource classes. +#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE; +FOR_ALL_PLUGIN_RESOURCES(DECLARE_RESOURCE_CLASS) +#undef DECLARE_RESOURCE_CLASS + +class PluginResource : public ::ppapi::ResourceObjectBase { + public: + PluginResource(const HostResource& resource); + 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 = + PluginResourceTracker::GetInstance()->GetResourceObject(res); + return resource ? resource->Cast<T>() : NULL; + } + + template <typename T> T* Cast() { return NULL; } + + PP_Instance instance() const { return host_resource_.instance(); } + + // Returns the host resource ID for sending to the host process. + const HostResource& host_resource() const { + return host_resource_; + } + + PluginDispatcher* GetDispatcher(); + + 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(); + FOR_ALL_PLUGIN_RESOURCES(DEFINE_TYPE_GETTER) + #undef DEFINE_TYPE_GETTER + + // The resource ID in the host that this object corresponds to. Inside the + // plugin we'll remap the resource IDs so we can have many host processes + // each independently generating resources (which may conflict) but the IDs + // in the plugin will all be unique. + HostResource host_resource_; + + DISALLOW_COPY_AND_ASSIGN(PluginResource); +}; + +// Cast() specializations. +#define DEFINE_RESOURCE_CAST(Type) \ + template <> inline Type* PluginResource::Cast<Type>() { \ + return As##Type(); \ + } +FOR_ALL_PLUGIN_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..e1726cf --- /dev/null +++ b/ppapi/proxy/plugin_resource_tracker.cc @@ -0,0 +1,183 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_resource_tracker.h" + +#include "base/logging.h" +#include "base/memory/singleton.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" +#include "ppapi/shared_impl/tracker_base.h" + +namespace pp { +namespace proxy { + +namespace { + +// When non-NULL, this object overrides the ResourceTrackerSingleton. +PluginResourceTracker* g_resource_tracker_override = NULL; + +::ppapi::TrackerBase* GetTrackerBase() { + return PluginResourceTracker::GetInstance(); +} + +} // namespace + +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) { + // Wire up the new shared resource tracker base to use our implementation. + ::ppapi::TrackerBase::Init(&GetTrackerBase); +} + +PluginResourceTracker::ResourceInfo::~ResourceInfo() { +} + +PluginResourceTracker::ResourceInfo& +PluginResourceTracker::ResourceInfo::operator=( + const ResourceInfo& other) { + ref_count = other.ref_count; + resource = other.resource; + return *this; +} + +// Start counting resources at a high number to avoid collisions with vars (to +// help debugging). +PluginResourceTracker::PluginResourceTracker() + : last_resource_id_(0x00100000) { +} + +PluginResourceTracker::~PluginResourceTracker() { +} + +// static +void PluginResourceTracker::SetInstanceForTest(PluginResourceTracker* tracker) { + g_resource_tracker_override = tracker; +} + +// static +PluginResourceTracker* PluginResourceTracker::GetInstance() { + if (g_resource_tracker_override) + return g_resource_tracker_override; + return Singleton<PluginResourceTracker>::get(); +} + +// static +::ppapi::TrackerBase* +PluginResourceTracker::GetTrackerBaseInstance() { + return GetInstance(); +} + +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(); +} + +PP_Resource PluginResourceTracker::AddResource( + linked_ptr<PluginResource> object) { + PP_Resource plugin_resource = ++last_resource_id_; + DCHECK(resource_map_.find(plugin_resource) == resource_map_.end()); + resource_map_[plugin_resource] = ResourceInfo(1, object); + if (!object->host_resource().is_null()) { + // The host resource ID will be 0 for resources that only exist in the + // plugin process. Don't add those to the list. + host_resource_map_[object->host_resource()] = plugin_resource; + } + return plugin_resource; +} + +void PluginResourceTracker::AddRefResource(PP_Resource resource) { + ResourceMap::iterator found = resource_map_.find(resource); + if (found == resource_map_.end()) { + NOTREACHED(); + return; + } + found->second.ref_count++; +} + +void PluginResourceTracker::ReleaseResource(PP_Resource resource) { + ReleasePluginResourceRef(resource, true); +} + +PP_Resource PluginResourceTracker::PluginResourceForHostResource( + const HostResource& resource) const { + HostResourceMap::const_iterator found = host_resource_map_.find(resource); + if (found == host_resource_map_.end()) + return 0; + return found->second; +} + +::ppapi::ResourceObjectBase* PluginResourceTracker::GetResourceAPI( + PP_Resource res) { + ResourceMap::iterator found = resource_map_.find(res); + if (found == resource_map_.end()) + return NULL; + return found->second.resource.get(); +} + +::ppapi::FunctionGroupBase* PluginResourceTracker::GetFunctionAPI( + PP_Instance inst, + pp::proxy::InterfaceID id) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(inst); + if (dispatcher) + return dispatcher->GetFunctionAPI(id); + return NULL; +} + +PP_Instance PluginResourceTracker::GetInstanceForResource( + PP_Resource resource) { + ResourceMap::iterator found = resource_map_.find(resource); + if (found == resource_map_.end()) + return 0; + return found->second.resource->instance(); +} + +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) { + // Keep a reference while removing in case the destructor ends up + // re-entering. That way, when the destructor is called, it's out of the + // maps. + linked_ptr<PluginResource> plugin_resource = found->second.resource; + PluginDispatcher* dispatcher = + PluginDispatcher::GetForInstance(plugin_resource->instance()); + HostResource host_resource = plugin_resource->host_resource(); + if (!host_resource.is_null()) + host_resource_map_.erase(host_resource); + resource_map_.erase(found); + plugin_resource.reset(); + + // dispatcher can be NULL if the plugin held on to a resource after the + // instance was destroyed. In that case the browser-side resource has + // already been freed correctly on the browser side. The host_resource + // will be NULL for proxy-only resources, which we obviously don't need to + // tell the host about. + if (notify_browser_on_release && dispatcher && !host_resource.is_null()) { + dispatcher->Send(new PpapiHostMsg_PPBCore_ReleaseResource( + INTERFACE_ID_PPB_CORE, host_resource)); + } + } +} + +} // 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..83b7840 --- /dev/null +++ b/ppapi/proxy/plugin_resource_tracker.h @@ -0,0 +1,107 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ +#define PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ + +#include <map> +#include <utility> + +#include "base/compiler_specific.h" +#include "base/memory/linked_ptr.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/shared_impl/tracker_base.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace pp { +namespace proxy { + +class PluginDispatcher; +class PluginResource; + +class PluginResourceTracker : public ::ppapi::TrackerBase { + public: + // Called by tests that want to specify a specific ResourceTracker. This + // allows them to use a unique one each time and avoids singletons sticking + // around across tests. + static void SetInstanceForTest(PluginResourceTracker* tracker); + + // Returns the global singleton resource tracker for the plugin. + static PluginResourceTracker* GetInstance(); + static ::ppapi::TrackerBase* GetTrackerBaseInstance(); + + // Returns the object associated with the given resource ID, or NULL if + // there isn't one. + PluginResource* GetResourceObject(PP_Resource pp_resource); + + // Adds the given resource object to the tracked list, and returns the + // plugin-local PP_Resource ID that identifies the resource. Note that this + // PP_Resource is not valid to send to the host, use + // PluginResource.host_resource() to get that. + PP_Resource AddResource(linked_ptr<PluginResource> object); + + void AddRefResource(PP_Resource resource); + void ReleaseResource(PP_Resource resource); + + // Given a host resource, maps it to an existing plugin resource ID if it + // exists, or returns 0 on failure. + PP_Resource PluginResourceForHostResource( + const HostResource& resource) const; + + // TrackerBase. + virtual ::ppapi::ResourceObjectBase* GetResourceAPI( + PP_Resource res) OVERRIDE; + virtual ::ppapi::FunctionGroupBase* GetFunctionAPI( + PP_Instance inst, + pp::proxy::InterfaceID id) OVERRIDE; + virtual PP_Instance GetInstanceForResource(PP_Resource resource) OVERRIDE; + + private: + friend struct DefaultSingletonTraits<PluginResourceTracker>; + friend class PluginResourceTrackerTest; + friend class PluginProxyTestHarness; + + PluginResourceTracker(); + virtual ~PluginResourceTracker(); + + 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); + + // Map of plugin resource IDs to the information tracking that resource. + typedef std::map<PP_Resource, ResourceInfo> ResourceMap; + ResourceMap resource_map_; + + // Map of host instance/resource pairs to a plugin resource ID. + typedef std::map<HostResource, PP_Resource> HostResourceMap; + HostResourceMap host_resource_map_; + + // Tracks the last ID we've sent out as a plugin resource so we don't send + // duplicates. + PP_Resource last_resource_id_; + + DISALLOW_COPY_AND_ASSIGN(PluginResourceTracker); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_RESOURCE_TRACKER_H_ diff --git a/ppapi/proxy/plugin_resource_tracker_unittest.cc b/ppapi/proxy/plugin_resource_tracker_unittest.cc new file mode 100644 index 0000000..5a317128 --- /dev/null +++ b/ppapi/proxy/plugin_resource_tracker_unittest.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/scoped_ptr.h" +#include "base/process.h" +#include "ppapi/proxy/mock_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace pp { +namespace proxy { + +namespace { + +// Object so we know when a resource has been released. +class TrackedMockResource : public MockResource { + public: + TrackedMockResource(const HostResource& serialized) + : MockResource(serialized) { + tracked_alive_count++; + } + ~TrackedMockResource() { + tracked_alive_count--; + } + + static int tracked_alive_count; +}; + +int TrackedMockResource::tracked_alive_count = 0; + +} // namespace + +class PluginResourceTrackerTest : public PluginProxyTest { + public: + PluginResourceTrackerTest() {} + ~PluginResourceTrackerTest() {} + + PluginResourceTracker& tracker() { return tracker_; } + + private: + PluginResourceTracker tracker_; +}; + +TEST_F(PluginResourceTrackerTest, PluginResourceForHostResource) { + PP_Resource host_resource = 0x5678; + + HostResource serialized; + serialized.SetHostResource(pp_instance(), host_resource); + + // When we haven't added an object, the return value should be 0. + EXPECT_EQ(0, tracker().PluginResourceForHostResource(serialized)); + + EXPECT_EQ(0, TrackedMockResource::tracked_alive_count); + TrackedMockResource* object = new TrackedMockResource(serialized); + EXPECT_EQ(1, TrackedMockResource::tracked_alive_count); + PP_Resource plugin_resource = + tracker().AddResource(linked_ptr<PluginResource>(object)); + + // Now that the object has been added, the return value should be the plugin + // resource ID we already got. + EXPECT_EQ(plugin_resource, + tracker().PluginResourceForHostResource(serialized)); + + // Releasing the resource should have freed it. + tracker().ReleaseResource(plugin_resource); + EXPECT_EQ(0, TrackedMockResource::tracked_alive_count); + EXPECT_EQ(0, tracker().PluginResourceForHostResource(serialized)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_var_serialization_rules.cc b/ppapi/proxy/plugin_var_serialization_rules.cc new file mode 100644 index 0000000..8ba5574 --- /dev/null +++ b/ppapi/proxy/plugin_var_serialization_rules.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_var_serialization_rules.h" + +#include "base/logging.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +namespace pp { +namespace proxy { + +PluginVarSerializationRules::PluginVarSerializationRules() + : var_tracker_(PluginVarTracker::GetInstance()) { +} + +PluginVarSerializationRules::~PluginVarSerializationRules() { +} + +PP_Var PluginVarSerializationRules::SendCallerOwned(const PP_Var& var, + std::string* str_val) { + // Objects need special translations to get the IDs valid in the host. + if (var.type == PP_VARTYPE_OBJECT) + return var_tracker_->GetHostObject(var); + + // Retrieve the string to use for IPC. + if (var.type == PP_VARTYPE_STRING) { + const std::string* var_string = var_tracker_->GetExistingString(var); + if (var_string) + *str_val = *var_string; + else + NOTREACHED() << "Trying to send unknown string over IPC."; + } + return var; +} + +PP_Var PluginVarSerializationRules::BeginReceiveCallerOwned( + const PP_Var& var, + const std::string* str_val, + Dispatcher* dispatcher) { + if (var.type == PP_VARTYPE_STRING) { + // Convert the string to the context of the current process. + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = var_tracker_->MakeString(*str_val); + return ret; + } + + if (var.type == PP_VARTYPE_OBJECT) { + DCHECK(dispatcher->IsPlugin()); + return var_tracker_->TrackObjectWithNoReference( + var, static_cast<PluginDispatcher*>(dispatcher)); + } + + return var; +} + +void PluginVarSerializationRules::EndReceiveCallerOwned(const PP_Var& var) { + if (var.type == PP_VARTYPE_STRING) { + // Destroy the string BeginReceiveCallerOwned created above. + var_tracker_->Release(var); + } else if (var.type == PP_VARTYPE_OBJECT) { + var_tracker_->StopTrackingObjectWithNoReference(var); + } +} + +PP_Var PluginVarSerializationRules::ReceivePassRef(const PP_Var& var, + const std::string& str_val, + Dispatcher* dispatcher) { + if (var.type == PP_VARTYPE_STRING) { + // Convert the string to the context of the current process. + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = var_tracker_->MakeString(str_val); + return ret; + } + + // Overview of sending an object with "pass ref" from the browser to the + // plugin: + // Example 1 Example 2 + // Plugin Browser Plugin Browser + // Before send 3 2 0 1 + // Browser calls BeginSendPassRef 3 2 0 1 + // Plugin calls ReceivePassRef 4 1 1 1 + // Browser calls EndSendPassRef 4 1 1 1 + // + // In example 1 before the send, the plugin has 3 refs which are represented + // as one ref in the browser (since the plugin only tells the browser when + // it's refcount goes from 1 -> 0). The initial state is that the browser + // plugin code started to return a value, which means it gets another ref + // on behalf of the caller. This needs to be transferred to the plugin and + // folded in to its set of refs it maintains (with one ref representing all + // fo them in the browser). + if (var.type == PP_VARTYPE_OBJECT) { + DCHECK(dispatcher->IsPlugin()); + return var_tracker_->ReceiveObjectPassRef( + var, static_cast<PluginDispatcher*>(dispatcher)); + } + + // Other types are unchanged. + return var; +} + +PP_Var PluginVarSerializationRules::BeginSendPassRef(const PP_Var& var, + std::string* str_val) { + // Overview of sending an object with "pass ref" from the plugin to the + // browser: + // Example 1 Example 2 + // Plugin Browser Plugin Browser + // Before send 3 1 1 1 + // Plugin calls BeginSendPassRef 3 1 1 1 + // Browser calls ReceivePassRef 3 2 1 2 + // Plugin calls EndSendPassRef 2 2 0 1 + // + // The plugin maintains one ref count in the browser on behalf of the + // entire ref count in the plugin. When the plugin refcount goes to 0, it + // will call the browser to deref the object. This is why in example 2 + // transferring the object ref to the browser involves no net change in the + // browser's refcount. + + // Objects need special translations to get the IDs valid in the host. + if (var.type == PP_VARTYPE_OBJECT) + return var_tracker_->GetHostObject(var); + + if (var.type == PP_VARTYPE_STRING) { + const std::string* var_string = var_tracker_->GetExistingString(var); + if (var_string) + *str_val = *var_string; + else + NOTREACHED() << "Trying to send unknown string over IPC."; + } + return var; +} + +void PluginVarSerializationRules::EndSendPassRef(const PP_Var& var, + Dispatcher* dispatcher) { + // See BeginSendPassRef for an example of why we release our ref here. + // The var we have in our inner class has been converted to a host object + // by BeginSendPassRef. This means it's not a normal var valid in the plugin, + // so we need to use the special ReleaseHostObject. + if (var.type == PP_VARTYPE_OBJECT) { + var_tracker_->ReleaseHostObject( + static_cast<PluginDispatcher*>(dispatcher), var); + } +} + +void PluginVarSerializationRules::ReleaseObjectRef(const PP_Var& var) { + var_tracker_->Release(var); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_var_serialization_rules.h b/ppapi/proxy/plugin_var_serialization_rules.h new file mode 100644 index 0000000..e073602 --- /dev/null +++ b/ppapi/proxy/plugin_var_serialization_rules.h @@ -0,0 +1,46 @@ +// 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_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_PLUGIN_VAR_SERIALIZATION_RULES_H_ + +#include "base/basictypes.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace pp { +namespace proxy { + +class PluginVarTracker; + +// Implementation of the VarSerialization interface for the plugin. +class PluginVarSerializationRules : public VarSerializationRules { + public: + // This class will use the given non-owning pointer to the var tracker to + // handle object refcounting and string conversion. + PluginVarSerializationRules(); + ~PluginVarSerializationRules(); + + // VarSerialization implementation. + virtual PP_Var SendCallerOwned(const PP_Var& var, std::string* str_val); + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var, + const std::string* str_val, + Dispatcher* dispatcher); + virtual void EndReceiveCallerOwned(const PP_Var& var); + virtual PP_Var ReceivePassRef(const PP_Var& var, + const std::string& str_val, + Dispatcher* dispatcher); + virtual PP_Var BeginSendPassRef(const PP_Var& var, std::string* str_val); + virtual void EndSendPassRef(const PP_Var& var, Dispatcher* dispatcher); + virtual void ReleaseObjectRef(const PP_Var& var); + + private: + PluginVarTracker* var_tracker_; + + DISALLOW_COPY_AND_ASSIGN(PluginVarSerializationRules); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_VAR_SERIALIZATION_RULES_H_ diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc new file mode 100644 index 0000000..5734f96 --- /dev/null +++ b/ppapi/proxy/plugin_var_tracker.cc @@ -0,0 +1,336 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/plugin_var_tracker.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/interface_id.h" + +namespace pp { +namespace proxy { + +namespace { + +// When non-NULL, this object overrides the VarTrackerSingleton. +PluginVarTracker* var_tracker_override = NULL; + +} // namespace + +PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, VarID i) + : dispatcher(d), + host_object_id(i) { +} + +bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { + if (dispatcher < other.dispatcher) + return true; + if (other.dispatcher < dispatcher) + return false; + return host_object_id < other.host_object_id; +} + +PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) + : host_var(host_var), + ref_count(0), + track_with_no_reference_count(0) { +} + +PluginVarTracker::PluginVarTracker() : last_plugin_var_id_(0) { +} + +PluginVarTracker::~PluginVarTracker() { +} + +// static +void PluginVarTracker::SetInstanceForTest(PluginVarTracker* tracker) { + var_tracker_override = tracker; +} + +// static +PluginVarTracker* PluginVarTracker::GetInstance() { + if (var_tracker_override) + return var_tracker_override; + return Singleton<PluginVarTracker>::get(); +} + +PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) { + return MakeString(str.c_str(), str.length()); +} + +PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str, + uint32_t len) { + std::pair<VarIDStringMap::iterator, bool> + iter_success_pair(var_id_to_string_.end(), false); + VarID new_id(0); + RefCountedStringPtr str_ptr(new RefCountedString(str, len)); + // Pick new IDs until one is successfully inserted. This loop is very unlikely + // to ever run a 2nd time, since we have ~2^63 possible IDs to exhaust. + while (!iter_success_pair.second) { + new_id = GetNewVarID(); + iter_success_pair = + var_id_to_string_.insert(VarIDStringMap::value_type(new_id, str_ptr)); + } + iter_success_pair.first->second->AddRef(); + return new_id; +} + +const std::string* PluginVarTracker::GetExistingString( + const PP_Var& var) const { + if (var.type != PP_VARTYPE_STRING) + return NULL; + VarIDStringMap::const_iterator found = + var_id_to_string_.find(var.value.as_id); + if (found != var_id_to_string_.end()) + return &found->second->value(); + return NULL; +} + +void PluginVarTracker::AddRef(const PP_Var& var) { + if (var.type == PP_VARTYPE_STRING) { + VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); + if (found == var_id_to_string_.end()) { + NOTREACHED() << "Requesting to addref an unknown string."; + return; + } + found->second->AddRef(); + } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { + PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); + if (found == plugin_var_info_.end()) { + NOTREACHED() << "Requesting to addref an unknown object."; + return; + } + + PluginVarInfo& info = found->second; + if (info.ref_count == 0) { + // Got an AddRef for an object we have no existing reference for. + // We need to tell the browser we've taken a ref. This comes up when the + // browser passes an object as an input param and holds a ref for us. + // This must be a sync message since otherwise the "addref" will actually + // occur after the return to the browser of the sync function that + // presumably sent the object. + SendAddRefObjectMsg(info.host_var); + } + info.ref_count++; + } +} + +void PluginVarTracker::Release(const PP_Var& var) { + if (var.type == PP_VARTYPE_STRING) { + VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); + if (found == var_id_to_string_.end()) { + NOTREACHED() << "Requesting to release an unknown string."; + return; + } + found->second->Release(); + // If there is only 1 reference left, it's the map's reference. Erase it + // from the map, which will delete the string. + if (found->second->HasOneRef()) + var_id_to_string_.erase(found); + } else if (var.type == PP_VARTYPE_OBJECT) { + PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); + if (found == plugin_var_info_.end()) { + NOTREACHED() << "Requesting to release an unknown object."; + return; + } + + PluginVarInfo& info = found->second; + if (info.ref_count == 0) { + NOTREACHED() << "Releasing an object with zero ref."; + return; + } + + info.ref_count--; + if (info.ref_count == 0) + SendReleaseObjectMsg(info.host_var); + DeletePluginVarInfoIfNecessary(found); + } +} + +PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var, + PluginDispatcher* dispatcher) { + DCHECK(var.type == PP_VARTYPE_OBJECT); + + // Find the plugin info. + PluginVarInfoMap::iterator found = + FindOrMakePluginVarFromHostVar(var, dispatcher); + if (found == plugin_var_info_.end()) { + // The above code should have always made an entry in the map. + NOTREACHED(); + return PP_MakeUndefined(); + } + + // Fix up the references. The host (renderer) just sent us a ref. The + // renderer has addrefed the var in its tracker for us since it's returning + // it. + PluginVarInfo& info = found->second; + if (info.ref_count == 0) { + // We don't have a reference to this already, then we just add it to our + // tracker and use that one ref. + info.ref_count = 1; + } else { + // We already have a reference to it, that means the renderer now has two + // references on our behalf. We want to transfer that extra reference to + // our list. This means we addref in the plugin, and release the extra one + // in the renderer. + SendReleaseObjectMsg(info.host_var); + info.ref_count++; + } + + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = found->first; + return ret; +} + +PP_Var PluginVarTracker::TrackObjectWithNoReference( + const PP_Var& host_var, + PluginDispatcher* dispatcher) { + DCHECK(host_var.type == PP_VARTYPE_OBJECT); + + PluginVarInfoMap::iterator found = + FindOrMakePluginVarFromHostVar(host_var, dispatcher); + if (found == plugin_var_info_.end()) { + // The above code should have always made an entry in the map. + NOTREACHED(); + return PP_MakeUndefined(); + } + + found->second.track_with_no_reference_count++; + + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = found->first; + return ret; +} + +void PluginVarTracker::StopTrackingObjectWithNoReference( + const PP_Var& plugin_var) { + DCHECK(plugin_var.type == PP_VARTYPE_OBJECT); + PluginVarInfoMap::iterator found = plugin_var_info_.find( + plugin_var.value.as_id); + if (found == plugin_var_info_.end()) { + NOTREACHED(); + return; + } + + found->second.track_with_no_reference_count--; + DeletePluginVarInfoIfNecessary(found); +} + +PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const { + DCHECK(plugin_object.type == PP_VARTYPE_OBJECT); + PluginVarInfoMap::const_iterator found = plugin_var_info_.find( + plugin_object.value.as_id); + if (found == plugin_var_info_.end()) { + NOTREACHED(); + return PP_MakeUndefined(); + } + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = found->second.host_var.host_object_id; + return ret; +} + +PluginDispatcher* PluginVarTracker::DispatcherForPluginObject( + const PP_Var& plugin_object) const { + DCHECK(plugin_object.type == PP_VARTYPE_OBJECT); + PluginVarInfoMap::const_iterator found = plugin_var_info_.find( + plugin_object.value.as_id); + if (found != plugin_var_info_.end()) + return found->second.host_var.dispatcher; + return NULL; +} + +void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, + const PP_Var& host_object) { + // Convert the host object to a normal var valid in the plugin. + DCHECK(host_object.type == PP_VARTYPE_OBJECT); + HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find( + HostVar(dispatcher, host_object.value.as_id)); + if (found == host_var_to_plugin_var_.end()) { + NOTREACHED(); + return; + } + + // Now just release the object like normal. + PP_Var plugin_object; + plugin_object.type = PP_VARTYPE_OBJECT; + plugin_object.value.as_id = found->second; + Release(plugin_object); +} + +int PluginVarTracker::GetRefCountForObject(const PP_Var& plugin_object) { + PluginVarInfoMap::iterator found = plugin_var_info_.find( + plugin_object.value.as_id); + if (found == plugin_var_info_.end()) + return -1; + return found->second.ref_count; +} + +int PluginVarTracker::GetTrackedWithNoReferenceCountForObject( + const PP_Var& plugin_object) { + PluginVarInfoMap::iterator found = plugin_var_info_.find( + plugin_object.value.as_id); + if (found == plugin_var_info_.end()) + return -1; + return found->second.track_with_no_reference_count; +} + +void PluginVarTracker::SendAddRefObjectMsg(const HostVar& host_var) { + int unused; + host_var.dispatcher->Send(new PpapiHostMsg_PPBVar_AddRefObject( + INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id, &unused)); +} + +void PluginVarTracker::SendReleaseObjectMsg(const HostVar& host_var) { + host_var.dispatcher->Send(new PpapiHostMsg_PPBVar_ReleaseObject( + INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id)); +} + +PluginVarTracker::PluginVarInfoMap::iterator +PluginVarTracker::FindOrMakePluginVarFromHostVar(const PP_Var& var, + PluginDispatcher* dispatcher) { + DCHECK(var.type == PP_VARTYPE_OBJECT); + HostVar host_var(dispatcher, var.value.as_id); + + HostVarToPluginVarMap::iterator found = + host_var_to_plugin_var_.find(host_var); + if (found != host_var_to_plugin_var_.end()) { + PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second); + DCHECK(ret != plugin_var_info_.end()); + return ret; // Already know about this var return the ID. + } + + // Make a new var, adding references to both maps. + VarID new_plugin_var_id = GetNewVarID(); + host_var_to_plugin_var_[host_var] = new_plugin_var_id; + return plugin_var_info_.insert( + std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first; +} + +void PluginVarTracker::DeletePluginVarInfoIfNecessary( + PluginVarInfoMap::iterator iter) { + if (iter->second.ref_count != 0 || + iter->second.track_with_no_reference_count != 0) + return; // Object still alive. + + // Object ref counts are all zero, delete from both maps. + DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) != + host_var_to_plugin_var_.end()); + host_var_to_plugin_var_.erase(iter->second.host_var); + plugin_var_info_.erase(iter); +} + +PluginVarTracker::VarID PluginVarTracker::GetNewVarID() { + if (last_plugin_var_id_ == std::numeric_limits<VarID>::max()) + last_plugin_var_id_ = 0; + return ++last_plugin_var_id_; +} + +} // namesace proxy +} // namespace pp diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h new file mode 100644 index 0000000..748ec2d --- /dev/null +++ b/ppapi/proxy/plugin_var_tracker.h @@ -0,0 +1,196 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ +#define PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ + +#include <map> +#include <string> + +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" + +struct PPB_Var; + +template<typename T> struct DefaultSingletonTraits; + +namespace pp { +namespace proxy { + +class PluginDispatcher; + +// Tracks live strings and objects in the plugin process. +// +// This object maintains its own object IDs that are used by the plugin. These +// IDs can be mapped to the renderer that created them, and that renderer's ID. +// This way, we can maintain multiple renderers each giving us objects, and the +// plugin can work with them using a uniform set of unique IDs. +// +// We maintain our own reference count for objects. a single ref in the +// renderer process whenever we have a nonzero refcount in the plugin process. +// This allows AddRef and Release to not initiate too much IPC chat. +// +// In addition to the local reference count, we also maintain "tracked objects" +// which are objects that the plugin is aware of, but doesn't hold a reference +// to. This will happen when the plugin is passed an object as an argument from +// the host (renderer) but where a reference is not passed. +class PluginVarTracker { + public: + typedef int64_t VarID; + + // Called by tests that want to specify a specific VarTracker. This allows + // them to use a unique one each time and avoids singletons sticking around + // across tests. + static void SetInstanceForTest(PluginVarTracker* tracker); + + // Returns the global var tracker for the plugin object. + static PluginVarTracker* GetInstance(); + + // Allocates a string and returns the ID of it. The refcount will be 1. + VarID MakeString(const std::string& str); + VarID MakeString(const char* str, uint32_t len); + + // Returns a pointer to the given string if it exists, or NULL if the var + // isn't a string var. + const std::string* GetExistingString(const PP_Var& plugin_var) const; + + void AddRef(const PP_Var& plugin_var); + void Release(const PP_Var& plugin_var); + + // Manages tracking for receiving a VARTYPE_OBJECT from the remote side + // (either the plugin or the renderer) that has already had its reference + // count incremented on behalf of the caller. + PP_Var ReceiveObjectPassRef(const PP_Var& var, PluginDispatcher* dispatcher); + + PP_Var TrackObjectWithNoReference(const PP_Var& host_var, + PluginDispatcher* dispatcher); + void StopTrackingObjectWithNoReference(const PP_Var& plugin_var); + + // Returns the host var for the corresponding plugin object var. The object + // should be a VARTYPE_OBJECT + PP_Var GetHostObject(const PP_Var& plugin_object) const; + + PluginDispatcher* DispatcherForPluginObject( + const PP_Var& plugin_object) const; + + // Like Release() but the var is identified by its host object ID (as + // returned by GetHostObject). + void ReleaseHostObject(PluginDispatcher* dispatcher, + const PP_Var& host_object); + + // Retrieves the internal reference counts for testing. Returns 0 if we + // know about the object but the corresponding value is 0, or -1 if the + // given object ID isn't in our map. + int GetRefCountForObject(const PP_Var& plugin_object); + int GetTrackedWithNoReferenceCountForObject(const PP_Var& plugin_object); + + private: + friend struct DefaultSingletonTraits<PluginVarTracker>; + friend class PluginProxyTestHarness; + + class RefCountedString : public base::RefCounted<RefCountedString> { + public: + RefCountedString() { + } + RefCountedString(const std::string& str) : value_(str) { + } + RefCountedString(const char* data, size_t len) + : value_(data, len) { + } + + const std::string& value() const { return value_; } + + private: + std::string value_; + + // Ensure only base::RefCounted can delete a RefCountedString. + friend void base::RefCounted<RefCountedString>::Release() const; + virtual ~RefCountedString() {} + }; + typedef scoped_refptr<RefCountedString> RefCountedStringPtr; + + // Represents a var as received from the host. + struct HostVar { + HostVar(PluginDispatcher* d, int64_t i); + + bool operator<(const HostVar& other) const; + + // The dispatcher that sent us this object. This is used so we know how to + // send back requests on this object. + PluginDispatcher* dispatcher; + + // The object ID that the host generated to identify the object. This is + // unique only within that host: different hosts could give us different + // objects with the same ID. + VarID host_object_id; + }; + + // The information associated with a var object in the plugin. + struct PluginVarInfo { + PluginVarInfo(const HostVar& host_var); + + // Maps back to the original var in the host. + HostVar host_var; + + // Explicit reference count. This value is affected by the renderer calling + // AddRef and Release. A nonzero value here is represented by a single + // reference in the host on our behalf (this reduces IPC traffic). + int32_t ref_count; + + // Tracked object count (see class comment above). + // + // "TrackObjectWithNoReference" might be called recursively in rare cases. + // For example, say the host calls a plugin function with an object as an + // argument, and in response, the plugin calls a host function that then + // calls another (or the same) plugin function with the same object. + // + // This value tracks the number of calls to TrackObjectWithNoReference so + // we know when we can stop tracking this object. + int32_t track_with_no_reference_count; + }; + + typedef std::map<int64_t, PluginVarInfo> PluginVarInfoMap; + + PluginVarTracker(); + ~PluginVarTracker(); + + // Sends an addref or release message to the browser for the given object ID. + void SendAddRefObjectMsg(const HostVar& host_var); + void SendReleaseObjectMsg(const HostVar& host_var); + + PluginVarInfoMap::iterator FindOrMakePluginVarFromHostVar( + const PP_Var& var, + PluginDispatcher* dispatcher); + + // Checks the reference counds of the given plugin var info and removes the + // tracking information if necessary. We're done with the object when its + // explicit reference count and its "tracked with no reference" count both + // reach zero. + void DeletePluginVarInfoIfNecessary(PluginVarInfoMap::iterator iter); + + // Tracks all information about plugin vars. + PluginVarInfoMap plugin_var_info_; + + // Maps host vars to plugin vars. This allows us to know if we've previously + // seen a host var and re-use the information. + typedef std::map<HostVar, VarID> HostVarToPluginVarMap; + HostVarToPluginVarMap host_var_to_plugin_var_; + + // Maps plugin var IDs to ref counted strings. + typedef std::map<VarID, RefCountedStringPtr> VarIDStringMap; + VarIDStringMap var_id_to_string_; + + // The last plugin PP_Var ID we've handed out. This must be unique for the + // process. + VarID last_plugin_var_id_; + + // Get a new Var ID and increment last_plugin_var_id_. + VarID GetNewVarID(); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ diff --git a/ppapi/proxy/plugin_var_tracker_unittest.cc b/ppapi/proxy/plugin_var_tracker_unittest.cc new file mode 100644 index 0000000..08fba9b --- /dev/null +++ b/ppapi/proxy/plugin_var_tracker_unittest.cc @@ -0,0 +1,189 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ipc/ipc_test_sink.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Var MakeObject(PluginVarTracker::VarID object_id) { + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = object_id; + return ret; +} + +// Creates a PP_Var from the given string ID. +PP_Var MakeString(PluginVarTracker::VarID string_id) { + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = string_id; + return ret; +} + +} // namespace + +class PluginVarTrackerTest : public PluginProxyTest { + public: + PluginVarTrackerTest() {} + + protected: + // Asserts that there is a unique "release object" IPC message in the test + // sink. This will return the var ID from the message or -1 if none found. + PluginVarTracker::VarID GetObjectIDForUniqueReleaseObject() { + const IPC::Message* release_msg = sink().GetUniqueMessageMatching( + PpapiHostMsg_PPBVar_ReleaseObject::ID); + if (!release_msg) + return -1; + + Tuple1<int64> id; + PpapiHostMsg_PPBVar_ReleaseObject::Read(release_msg, &id); + return id.a; + } +}; + +TEST_F(PluginVarTrackerTest, Strings) { + std::string str("Hello"); + PluginVarTracker::VarID str_id1 = var_tracker().MakeString(str); + EXPECT_NE(0, str_id1); + + PluginVarTracker::VarID str_id2 = var_tracker().MakeString( + str.c_str(), static_cast<uint32_t>(str.size())); + EXPECT_NE(0, str_id2); + + // Make sure the strings come out the other end. + const std::string* result = + var_tracker().GetExistingString(MakeString(str_id1)); + EXPECT_EQ(str, *result); + result = var_tracker().GetExistingString(MakeString(str_id2)); + EXPECT_EQ(str, *result); +} + +TEST_F(PluginVarTrackerTest, GetHostObject) { + PP_Var host_object = MakeObject(12345); + + // Round-trip through the tracker to make sure the host object comes out the + // other end. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + PP_Var host_object2 = var_tracker().GetHostObject(plugin_object); + EXPECT_EQ(PP_VARTYPE_OBJECT, host_object2.type); + EXPECT_EQ(host_object.value.as_id, host_object2.value.as_id); + + var_tracker().Release(plugin_object); +} + +TEST_F(PluginVarTrackerTest, ReceiveObjectPassRef) { + PP_Var host_object = MakeObject(12345); + + // Receive the object, we should have one ref and no messages. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(0u, sink().message_count()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // Receive the same object again, we should get the same plugin ID out. + PP_Var plugin_object2 = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_object.value.as_id, plugin_object2.value.as_id); + EXPECT_EQ(2, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_object)); + + // It should have sent one message to decerment the refcount in the host. + // This is because it only maintains one host refcount for all references + // in the plugin, but the host just sent the second one. + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + sink().ClearMessages(); + + // Release the object, one ref at a time. The second release should free + // the tracking data and send a release message to the browser. + var_tracker().Release(plugin_object); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + var_tracker().Release(plugin_object); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +// Tests freeing objects that have both refcounts and "tracked with no ref". +TEST_F(PluginVarTrackerTest, FreeTrackedAndReferencedObject) { + PP_Var host_object = MakeObject(12345); + + // Phase one: First receive via a "pass ref", then a tracked with no ref. + PP_Var plugin_var = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the refcount, this should release the object to the browser but + // maintain the tracked object. + var_tracker().Release(plugin_var); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1u, sink().message_count()); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); + + // Now free via the tracked object, this should free it. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var)); + + // Phase two: Receive via a tracked, then get an addref. + sink().ClearMessages(); + plugin_var = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + plugin_var2 = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Free via the tracked object, this should have no effect. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(0, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + EXPECT_EQ(0u, sink().message_count()); + + // Now free via the refcount, this should delete it. + var_tracker().Release(plugin_var); + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(host_object.value.as_id, GetObjectIDForUniqueReleaseObject()); +} + +TEST_F(PluginVarTrackerTest, RecursiveTrackWithNoRef) { + PP_Var host_object = MakeObject(12345); + + // Receive a tracked object twice. + PP_Var plugin_var = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + PP_Var plugin_var2 = var_tracker().TrackObjectWithNoReference( + host_object, plugin_dispatcher()); + EXPECT_EQ(plugin_var.value.as_id, plugin_var2.value.as_id); + EXPECT_EQ(0, var_tracker().GetRefCountForObject(plugin_var)); + EXPECT_EQ(2, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + + // Now release those tracked items, the reference should be freed. + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); + var_tracker().StopTrackingObjectWithNoReference(plugin_var); + EXPECT_EQ(-1, + var_tracker().GetTrackedWithNoReferenceCountForObject(plugin_var)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppapi_messages.cc b/ppapi/proxy/ppapi_messages.cc new file mode 100644 index 0000000..5cee1c7 --- /dev/null +++ b/ppapi/proxy/ppapi_messages.cc @@ -0,0 +1,34 @@ +// 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. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "ppapi/proxy/ppapi_messages.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "ppapi/proxy/ppapi_messages.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "ppapi/proxy/ppapi_messages.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "ppapi/proxy/ppapi_messages.h" +} // namespace IPC + diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h new file mode 100644 index 0000000..c516514 --- /dev/null +++ b/ppapi/proxy/ppapi_messages.h @@ -0,0 +1,858 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Multiply-included message header, no traditional include guard. +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/process.h" +#include "base/shared_memory.h" +#include "base/string16.h" +#include "base/sync_socket.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/ipc/gpu_command_buffer_traits.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/private/ppb_flash_tcp_socket.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/serialized_flash_menu.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/input_event_impl.h" +#include "ppapi/shared_impl/ppapi_preferences.h" + +#define IPC_MESSAGE_START PpapiMsgStart + +IPC_ENUM_TRAITS(PP_InputEvent_Type) +IPC_ENUM_TRAITS(PP_InputEvent_MouseButton) + +IPC_STRUCT_TRAITS_BEGIN(PP_Point) + IPC_STRUCT_TRAITS_MEMBER(x) + IPC_STRUCT_TRAITS_MEMBER(y) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_FloatPoint) + IPC_STRUCT_TRAITS_MEMBER(x) + IPC_STRUCT_TRAITS_MEMBER(y) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_Size) + IPC_STRUCT_TRAITS_MEMBER(height) + IPC_STRUCT_TRAITS_MEMBER(width) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PP_Rect) + IPC_STRUCT_TRAITS_MEMBER(point) + IPC_STRUCT_TRAITS_MEMBER(size) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(::ppapi::Preferences) + IPC_STRUCT_TRAITS_MEMBER(standard_font_family) + IPC_STRUCT_TRAITS_MEMBER(fixed_font_family) + IPC_STRUCT_TRAITS_MEMBER(serif_font_family) + IPC_STRUCT_TRAITS_MEMBER(sans_serif_font_family) + IPC_STRUCT_TRAITS_MEMBER(default_font_size) + IPC_STRUCT_TRAITS_MEMBER(default_fixed_font_size) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(::ppapi::InputEventData) + IPC_STRUCT_TRAITS_MEMBER(is_filtered) + IPC_STRUCT_TRAITS_MEMBER(event_type) + IPC_STRUCT_TRAITS_MEMBER(event_time_stamp) + IPC_STRUCT_TRAITS_MEMBER(event_modifiers) + IPC_STRUCT_TRAITS_MEMBER(mouse_button) + IPC_STRUCT_TRAITS_MEMBER(mouse_position) + IPC_STRUCT_TRAITS_MEMBER(mouse_click_count) + IPC_STRUCT_TRAITS_MEMBER(wheel_delta) + IPC_STRUCT_TRAITS_MEMBER(wheel_ticks) + IPC_STRUCT_TRAITS_MEMBER(wheel_scroll_by_page) + IPC_STRUCT_TRAITS_MEMBER(key_code) + IPC_STRUCT_TRAITS_MEMBER(character_text) +IPC_STRUCT_TRAITS_END() + +// These are from the browser to the plugin. +// Loads the given plugin. +IPC_MESSAGE_CONTROL1(PpapiMsg_LoadPlugin, FilePath /* path */) + +// Creates a channel to talk to a renderer. The plugin will respond with +// PpapiHostMsg_ChannelCreated. +IPC_MESSAGE_CONTROL2(PpapiMsg_CreateChannel, + base::ProcessHandle /* host_process_handle */, + int /* renderer_id */) + +// Each plugin may be referenced by multiple renderers. We need the instance +// IDs to be unique within a plugin, despite coming from different renderers, +// and unique within a renderer, despite going to different plugins. This means +// that neither the renderer nor the plugin can generate instance IDs without +// consulting the other. +// +// We resolve this by having the renderer generate a unique instance ID inside +// its process. It then asks the plugin to reserve that ID by sending this sync +// message. If the plugin has not yet seen this ID, it will remember it as used +// (to prevent a race condition if another renderer tries to then use the same +// instance), and set usable as true. +// +// If the plugin has already seen the instance ID, it will set usable as false +// and the renderer must retry a new instance ID. +IPC_SYNC_MESSAGE_CONTROL1_1(PpapiMsg_ReserveInstanceId, + PP_Instance /* instance */, + bool /* usable */) + +// Passes the WebKit preferences to the plugin. +IPC_MESSAGE_CONTROL1(PpapiMsg_SetPreferences, + ::ppapi::Preferences) + +// Network state notification from the browser for implementing +// PPP_NetworkState_Dev. +IPC_MESSAGE_CONTROL1(PpapiMsg_SetNetworkState, + bool /* online */) + +// 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 */) + +IPC_MESSAGE_CONTROL2(PpapiMsg_ExecuteCallback, + uint32 /* serialized_callback */, + int32 /* param */) + +// Broker Process. + +IPC_SYNC_MESSAGE_CONTROL2_0(PpapiMsg_ConnectToPlugin, + PP_Instance /* instance */, + IPC::PlatformFileForTransit /* handle */) + +// PPB_Audio. + +// Notifies the result of the audio stream create call. This is called in +// both error cases and in the normal success case. These cases are +// differentiated by the result code, which is one of the standard PPAPI +// result codes. +// +// The handler of this message should always close all of the handles passed +// in, since some could be valid even in the error case. +IPC_MESSAGE_ROUTED5(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + pp::proxy::HostResource /* audio_id */, + int32_t /* result_code (will be != PP_OK on failure) */, + IPC::PlatformFileForTransit /* socket_handle */, + base::SharedMemoryHandle /* handle */, + int32_t /* length */) + +// PPB_Broker. +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPBBroker_ConnectComplete, + pp::proxy::HostResource /* broker */, + IPC::PlatformFileForTransit /* handle */, + int32_t /* result */) + +// PPB_FileChooser. +IPC_MESSAGE_ROUTED3( + PpapiMsg_PPBFileChooser_ChooseComplete, + pp::proxy::HostResource /* chooser */, + int32_t /* result_code (will be != PP_OK on failure */, + std::vector<pp::proxy::PPBFileRef_CreateInfo> /* chosen_files */) + +// PPB_FileSystem. +IPC_MESSAGE_ROUTED2( + PpapiMsg_PPBFileSystem_OpenComplete, + pp::proxy::HostResource /* filesystem */, + int32_t /* result */) + +// PPB_Flash_NetConnector. +IPC_MESSAGE_ROUTED5(PpapiMsg_PPBFlashNetConnector_ConnectACK, + pp::proxy::HostResource /* net_connector */, + int32_t /* result */, + IPC::PlatformFileForTransit /* handle */, + std::string /* local_addr_as_string */, + std::string /* remote_addr_as_string */) + +// PPB_Flash_TCPSocket. +IPC_MESSAGE_ROUTED5(PpapiMsg_PPBFlashTCPSocket_ConnectACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + bool /* succeeded */, + PP_Flash_NetAddress /* local_addr */, + PP_Flash_NetAddress /* remote_addr */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBFlashTCPSocket_ReadACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + bool /* succeeded */, + std::string /* data */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBFlashTCPSocket_WriteACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */, + bool /* succeeded */, + int32_t /* bytes_written */) + +// PPB_Graphics2D. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics2D_FlushACK, + pp::proxy::HostResource /* graphics_2d */, + int32_t /* pp_error */) + +// PPB_Surface3D. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPBSurface3D_SwapBuffersACK, + pp::proxy::HostResource /* surface_3d */, + int32_t /* pp_error */) + +// 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_Graphics3D_Dev. +IPC_MESSAGE_ROUTED1(PpapiMsg_PPPGraphics3D_ContextLost, + PP_Instance /* instance */) + +// PPP_InputEvent. +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInputEvent_HandleInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* data */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInputEvent_HandleFilteredInputEvent, + PP_Instance /* instance */, + ppapi::InputEventData /* data */, + PP_Bool /* result */) + +// PPP_Instance. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiMsg_PPPInstance_DidCreate, + PP_Instance /* instance */, + std::vector<std::string> /* argn */, + std::vector<std::string> /* argv */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiMsg_PPPInstance_DidDestroy, + PP_Instance /* instance */) +IPC_MESSAGE_ROUTED4(PpapiMsg_PPPInstance_DidChangeView, + PP_Instance /* instance */, + PP_Rect /* position */, + PP_Rect /* clip */, + PP_Bool /* fullscreen */) +IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInstance_DidChangeFocus, + PP_Instance /* instance */, + PP_Bool /* has_focus */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleInputEvent, + PP_Instance /* instance */, + PP_InputEvent /* event */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleDocumentLoad, + PP_Instance /* instance */, + pp::proxy::HostResource /* url_loader */, + PP_Bool /* result */) + +// PPP_Instance_Private. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiMsg_PPPInstancePrivate_GetInstanceObject, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* result */) + +// PPB_URLLoader +// (Messages from browser to plugin to notify it of changes in state.) +IPC_MESSAGE_ROUTED1(PpapiMsg_PPBURLLoader_UpdateProgress, + pp::proxy::PPBURLLoader_UpdateProgress_Params /* params */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack, + pp::proxy::HostResource /* loader */, + int32 /* result */, + std::string /* data */) + +// ----------------------------------------------------------------------------- +// These are from the plugin to the renderer. + +// Reply to PpapiMsg_CreateChannel. The handle will be NULL if the channel +// could not be established. This could be because the IPC could not be created +// for some weird reason, but more likely that the plugin failed to load or +// initialize properly. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_ChannelCreated, + IPC::ChannelHandle /* handle */) + +// PPB_Audio. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBAudio_Create, + PP_Instance /* instance_id */, + int32_t /* sample_rate */, + uint32_t /* sample_frame_count */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBAudio_StartOrStop, + pp::proxy::HostResource /* audio_id */, + bool /* play */) + +// PPB_Broker. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBBroker_Create, + PP_Instance /* instance */, + pp::proxy::HostResource /* result_resource */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBBroker_Connect, + pp::proxy::HostResource /* broker */) + +// PPB_Buffer. +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBBuffer_Create, + PP_Instance /* instance */, + uint32_t /* size */, + pp::proxy::HostResource /* result_resource */, + base::SharedMemoryHandle /* result_shm_handle */) + +// PPB_Console. +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBConsole_Log, + PP_Instance /* instance */, + int /* log_level */, + pp::proxy::SerializedVar /* value */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBConsole_LogWithSource, + PP_Instance /* instance */, + int /* log_level */, + pp::proxy::SerializedVar /* soruce */, + pp::proxy::SerializedVar /* value */) + +// PPB_Context3D. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBContext3D_Create, + PP_Instance /* instance */, + int32_t /* config */, + std::vector<int32_t> /* attrib_list */, + pp::proxy::HostResource /* result */) + +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBContext3D_BindSurfaces, + pp::proxy::HostResource /* context */, + pp::proxy::HostResource /* draw */, + pp::proxy::HostResource /* read */, + int32_t /* result */) + +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBContext3D_Initialize, + pp::proxy::HostResource /* context */, + int32 /* size */, + base::SharedMemoryHandle /* ring_buffer */) + +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBContext3D_GetState, + pp::proxy::HostResource /* context */, + gpu::CommandBuffer::State /* state */) + +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBContext3D_Flush, + pp::proxy::HostResource /* context */, + int32 /* put_offset */, + int32 /* last_known_get */, + gpu::CommandBuffer::State /* state */) + +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBContext3D_AsyncFlush, + pp::proxy::HostResource /* context */, + int32 /* put_offset */) + +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBContext3D_CreateTransferBuffer, + pp::proxy::HostResource /* context */, + int32 /* size */, + int32 /* id */) + +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBContext3D_DestroyTransferBuffer, + pp::proxy::HostResource /* context */, + int32 /* id */) + +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBContext3D_GetTransferBuffer, + pp::proxy::HostResource /* context */, + int32 /* id */, + base::SharedMemoryHandle /* transfer_buffer */, + uint32 /* size */) + +// PPB_Core. +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_AddRefResource, + pp::proxy::HostResource) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBCore_ReleaseResource, + pp::proxy::HostResource) + +// PPB_CharSet. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBCharSet_GetDefaultCharSet, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* result */) + +// PPB_CursorControl. +IPC_SYNC_MESSAGE_ROUTED4_1(PpapiHostMsg_PPBCursorControl_SetCursor, + PP_Instance /* instance */, + int32_t /* type */, + pp::proxy::HostResource /* custom_image */, + PP_Point /* hot_spot */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBCursorControl_LockCursor, + PP_Instance /* instance */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBCursorControl_UnlockCursor, + PP_Instance /* instance */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBCursorControl_HasCursorLock, + PP_Instance /* instance */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBCursorControl_CanLockCursor, + PP_Instance /* instance */, + PP_Bool /* result */) + +// PPB_FileChooser. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFileChooser_Create, + PP_Instance /* instance */, + int /* mode */, + std::string /* accept_mime_types */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBFileChooser_Show, + pp::proxy::HostResource /* file_chooser */) + + +// PPB_FileRef. +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFileRef_Create, + pp::proxy::HostResource /* file_system */, + std::string /* path */, + pp::proxy::PPBFileRef_CreateInfo /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFileRef_GetParent, + pp::proxy::HostResource /* file_ref */, + pp::proxy::PPBFileRef_CreateInfo /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFileRef_MakeDirectory, + pp::proxy::HostResource /* file_ref */, + PP_Bool /* make_ancestors */, + uint32_t /* serialized_callback */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBFileRef_Touch, + pp::proxy::HostResource /* file_ref */, + PP_Time /* last_access */, + PP_Time /* last_modified */, + uint32_t /* serialized_callback */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFileRef_Delete, + pp::proxy::HostResource /* file_ref */, + uint32_t /* serialized_callback */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFileRef_Rename, + pp::proxy::HostResource /* file_ref */, + pp::proxy::HostResource /* new_file_ref */, + uint32_t /* serialized_callback */) + +// PPB_FileSystem. +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFileSystem_Create, + PP_Instance /* instance */, + int /* type */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFileSystem_Open, + pp::proxy::HostResource /* result */, + int64_t /* expected_size */) + +// PPB_Flash. +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop, + PP_Instance /* instance */, + PP_Bool /* on_top */) +// This has to be synchronous becuase the caller may want to composite on +// top of the resulting text after the call is complete. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFlash_DrawGlyphs, + pp::proxy::PPBFlash_DrawGlyphs_Params /* params */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFlash_GetProxyForURL, + PP_Instance /* instance */, + std::string /* url */, + pp::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFlash_Navigate, + pp::proxy::HostResource /* request_info */, + std::string /* target */, + bool /* from_user_action */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBFlash_RunMessageLoop, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBFlash_QuitMessageLoop, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFlash_GetLocalTimeZoneOffset, + PP_Instance /* instance */, + PP_Time /* t */, + double /* offset */) + +// PPB_Flash_Clipboard. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFlashClipboard_IsFormatAvailable, + PP_Instance /* instance */, + int /* clipboard_type */, + int /* format */, + bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFlashClipboard_ReadPlainText, + PP_Instance /* instance */, + int /* clipboard_type */, + pp::proxy::SerializedVar /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFlashClipboard_WritePlainText, + PP_Instance /* instance */, + int /* clipboard_type */, + pp::proxy::SerializedVar /* text */) + +// PPB_Flash_File_FileRef. +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBFlashFile_FileRef_OpenFile, + pp::proxy::HostResource /* file_ref */, + int32_t /* mode */, + IPC::PlatformFileForTransit /* file_handle */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBFlashFile_FileRef_QueryFile, + pp::proxy::HostResource /* file_ref */, + PP_FileInfo /* info */, + int32_t /* result */) + +// PPB_Flash_File_ModuleLocal. +IPC_SYNC_MESSAGE_ROUTED3_2(PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile, + PP_Instance /* instance */, + std::string /* path */, + int32_t /* mode */, + IPC::PlatformFileForTransit /* file_handle */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile, + PP_Instance /* instance */, + std::string /* path_from */, + std::string /* path_to */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED3_1( + PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir, + PP_Instance /* instance */, + std::string /* path */, + PP_Bool /* recursive */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir, + PP_Instance /* instance */, + std::string /* path */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile, + PP_Instance /* instance */, + std::string /* path */, + PP_FileInfo /* info */, + int32_t /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2( + PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents, + PP_Instance /* instance */, + std::string /* path */, + std::vector<pp::proxy::SerializedDirEntry> /* entries */, + int32_t /* result */) + +// PPB_Flash_Menu +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBFlashMenu_Create, + PP_Instance /* instance */, + pp::proxy::SerializedFlashMenu /* menu_data */, + pp::proxy::HostResource /* result */) +IPC_SYNC_MESSAGE_ROUTED2_0(PpapiHostMsg_PPBFlashMenu_Show, + pp::proxy::HostResource /* menu */, + PP_Point /* location */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPBFlashMenu_ShowACK, + pp::proxy::HostResource /* menu */, + int32_t /* selected_id */, + int32_t /* result */) + +// PPB_Flash_NetConnector. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBFlashNetConnector_Create, + PP_Instance /* instance_id */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBFlashNetConnector_ConnectTcp, + pp::proxy::HostResource /* connector */, + std::string /* host */, + uint16_t /* port */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFlashNetConnector_ConnectTcpAddress, + pp::proxy::HostResource /* connector */, + std::string /* net_address_as_string */) + +// PPB_Flash_TCPSocket. +IPC_SYNC_MESSAGE_CONTROL2_1(PpapiHostMsg_PPBFlashTCPSocket_Create, + int32 /* routing_id */, + uint32 /* plugin_dispatcher_id */, + uint32 /* socket_id */) +IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBFlashTCPSocket_Connect, + uint32 /* socket_id */, + std::string /* host */, + uint16_t /* port */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBFlashTCPSocket_ConnectWithNetAddress, + uint32 /* socket_id */, + PP_Flash_NetAddress /* net_addr */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBFlashTCPSocket_Read, + uint32 /* socket_id */, + int32_t /* bytes_to_read */) +IPC_MESSAGE_CONTROL2(PpapiHostMsg_PPBFlashTCPSocket_Write, + uint32 /* socket_id */, + std::string /* data */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBFlashTCPSocket_Disconnect, + uint32 /* socket_id */) + +// PPB_Font. +IPC_SYNC_MESSAGE_CONTROL0_1(PpapiHostMsg_PPBFont_GetFontFamilies, + std::string /* result */) + +// PPB_Graphics2D. +IPC_MESSAGE_ROUTED5(PpapiHostMsg_PPBGraphics2D_PaintImageData, + pp::proxy::HostResource /* graphics_2d */, + pp::proxy::HostResource /* image_data */, + PP_Point /* top_left */, + bool /* src_rect_specified */, + PP_Rect /* src_rect */) +IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBGraphics2D_Scroll, + pp::proxy::HostResource /* graphics_2d */, + bool /* clip_specified */, + PP_Rect /* clip */, + PP_Point /* amount */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBGraphics2D_ReplaceContents, + pp::proxy::HostResource /* graphics_2d */, + pp::proxy::HostResource /* image_data */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBGraphics2D_Flush, + pp::proxy::HostResource /* graphics_2d */) + +// 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::proxy::HostResource /* device */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBInstance_IsFullFrame, + PP_Instance /* instance */, + PP_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 */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBInstance_SetFullscreen, + PP_Instance /* instance */, + PP_Bool /* fullscreen */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_2(PpapiHostMsg_PPBInstance_GetScreenSize, + PP_Instance /* instance */, + PP_Bool /* result */, + PP_Size /* size */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBInstance_RequestInputEvents, + PP_Instance /* instance */, + bool /* is_filtering */, + uint32_t /* event_classes */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_ClearInputEvents, + PP_Instance /* instance */, + uint32_t /* event_classes */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBInstance_PostMessage, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* message */) + +IPC_SYNC_MESSAGE_ROUTED3_1( + PpapiHostMsg_PPBPDF_GetFontFileWithFallback, + PP_Instance /* instance */, + pp::proxy::SerializedFontDescription /* description */, + int32_t /* charset */, + pp::proxy::HostResource /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1( + PpapiHostMsg_PPBPDF_GetFontTableForPrivateFontFile, + pp::proxy::HostResource /* font_file */, + uint32_t /* table */, + std::string /* result */) + +// PPB_Surface3D. +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBSurface3D_Create, + PP_Instance /* instance */, + int32_t /* config */, + std::vector<int32_t> /* attrib_list */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBSurface3D_SwapBuffers, + pp::proxy::HostResource /* surface_3d */) + +// PPB_Testing. +IPC_SYNC_MESSAGE_ROUTED3_1( + PpapiHostMsg_PPBTesting_ReadImageData, + pp::proxy::HostResource /* device_context_2d */, + pp::proxy::HostResource /* image */, + PP_Point /* top_left */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBTesting_RunMessageLoop, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED1_0(PpapiHostMsg_PPBTesting_QuitMessageLoop, + PP_Instance /* instance */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, + PP_Instance /* instance */, + uint32 /* result */) + +// PPB_URLLoader. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLLoader_Create, + PP_Instance /* instance */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBURLLoader_Open, + pp::proxy::HostResource /* loader */, + pp::proxy::HostResource /*request_info */, + uint32_t /* serialized_callback */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_FollowRedirect, + pp::proxy::HostResource /* loader */, + uint32_t /* serialized_callback */) +IPC_SYNC_MESSAGE_ROUTED1_1( + PpapiHostMsg_PPBURLLoader_GetResponseInfo, + pp::proxy::HostResource /* loader */, + pp::proxy::HostResource /* response_info_out */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_ReadResponseBody, + pp::proxy::HostResource /* loader */, + int32_t /* bytes_to_read */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile, + pp::proxy::HostResource /* loader */, + uint32_t /* serialized_callback */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_Close, + pp::proxy::HostResource /* loader */) +IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess, + pp::proxy::HostResource /* loader */) + +// PPB_URLRequestInfo. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLRequestInfo_Create, + PP_Instance /* instance */, + pp::proxy::HostResource /* result */) +IPC_MESSAGE_ROUTED3(PpapiHostMsg_PPBURLRequestInfo_SetProperty, + pp::proxy::HostResource /* request */, + int32_t /* property */, + pp::proxy::SerializedVar /* value */) +IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLRequestInfo_AppendDataToBody, + pp::proxy::HostResource /* request */, + std::string /* data */) +IPC_MESSAGE_ROUTED5(PpapiHostMsg_PPBURLRequestInfo_AppendFileToBody, + pp::proxy::HostResource /* request */, + pp::proxy::HostResource /* file_ref */, + int64_t /* start_offset */, + int64_t /* number_of_bytes */, + double /* expected_last_modified_time */) + +// PPB_URLResponseInfo. +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBURLResponseInfo_GetProperty, + pp::proxy::HostResource /* response */, + int32_t /* property */, + pp::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLResponseInfo_GetBodyAsFileRef, + pp::proxy::HostResource /* response */, + pp::proxy::PPBFileRef_CreateInfo /* result */) + +// PPB_URLUtil. +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBURLUtil_ResolveRelativeToDocument, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* relative */, + pp::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBURLUtil_DocumentCanRequest, + PP_Instance /* instance */, + pp::proxy::SerializedVar /* relative */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_1(PpapiHostMsg_PPBURLUtil_DocumentCanAccessDocument, + PP_Instance /* active */, + PP_Instance /* target */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLUtil_GetDocumentURL, + PP_Instance /* active */, + pp::proxy::SerializedVar /* result */) +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLUtil_GetPluginInstanceURL, + PP_Instance /* active */, + pp::proxy::SerializedVar /* result */) + +// PPB_Var. +IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBVar_AddRefObject, + int64 /* object_id */, + int /* unused - need a return value for sync msgs */) +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_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasProperty, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* property */, + pp::proxy::SerializedVar /* out_exception */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBVar_HasMethodDeprecated, + pp::proxy::SerializedVar /* object */, + pp::proxy::SerializedVar /* method */, + pp::proxy::SerializedVar /* out_exception */, + PP_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 */, + PP_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_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 */, + PP_Bool /* result */) +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBVar_CreateObjectDeprecated, + PP_Instance /* instance */, + int64 /* object_class */, + int64 /* object_data */, + pp::proxy::SerializedVar /* result */) + +IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_ResourceCreation_Graphics2D, + PP_Instance /* instance */, + PP_Size /* size */, + PP_Bool /* is_always_opaque */, + pp::proxy::HostResource /* result */) +IPC_SYNC_MESSAGE_ROUTED4_3(PpapiHostMsg_ResourceCreation_ImageData, + PP_Instance /* instance */, + int32 /* format */, + PP_Size /* size */, + PP_Bool /* init_to_zero */, + pp::proxy::HostResource /* result_resource */, + std::string /* image_data_desc */, + pp::proxy::ImageHandle /* result */) diff --git a/ppapi/proxy/ppapi_param_traits.cc b/ppapi/proxy/ppapi_param_traits.cc new file mode 100644 index 0000000..87c253b --- /dev/null +++ b/ppapi/proxy/ppapi_param_traits.cc @@ -0,0 +1,510 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppapi_param_traits.h" + +#include <string.h> // For memcpy + +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_flash_tcp_socket.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/proxy/serialized_flash_menu.h" + +namespace IPC { + +namespace { + +// Deserializes a vector from IPC. This special version must be used instead +// of the default IPC version when the vector contains a SerializedVar, either +// directly or indirectly (i.e. a vector of objects that have a SerializedVar +// inside them). +// +// The default vector deserializer does resize 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 object for each deserialized item, and then +// add it to the vector one at a time. +template<typename T> +bool ReadVectorWithoutCopy(const Message* m, + void** iter, + std::vector<T>* output) { + // 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(T) <= static_cast<size_t>(size)) + return false; + + output->reserve(size); + for (int i = 0; i < size; i++) { + T cur; + if (!ReadParam(m, iter, &cur)) + return false; + output->push_back(cur); + } + return true; +} + +// This serializes the vector of items to the IPC message in exactly the same +// way as the "regular" IPC vector serializer does. But having the code here +// saves us from having to copy this code into all ParamTraits that use the +// ReadVectorWithoutCopy function for deserializing. +template<typename T> +void WriteVectorWithoutCopy(Message* m, const std::vector<T>& p) { + WriteParam(m, static_cast<int>(p.size())); + for (size_t i = 0; i < p.size(); i++) + WriteParam(m, p[i]); +} + +} // namespace + +// PP_Bool --------------------------------------------------------------------- + +// static +void ParamTraits<PP_Bool>::Write(Message* m, const param_type& p) { + ParamTraits<bool>::Write(m, PP_ToBool(p)); +} + +// static +bool ParamTraits<PP_Bool>::Read(const Message* m, void** iter, param_type* r) { + // We specifically want to be strict here about what types of input we accept, + // which ParamTraits<bool> does for us. We don't want to deserialize "2" into + // a PP_Bool, for example. + bool result = false; + if (!ParamTraits<bool>::Read(m, iter, &result)) + return false; + *r = PP_FromBool(result); + return true; +} + +// static +void ParamTraits<PP_Bool>::Log(const param_type& p, std::string* l) { +} + +// PP_FileInfo ------------------------------------------------------------- + +// static +void ParamTraits<PP_FileInfo>::Write(Message* m, const param_type& p) { + ParamTraits<int64_t>::Write(m, p.size); + ParamTraits<int>::Write(m, static_cast<int>(p.type)); + ParamTraits<int>::Write(m, static_cast<int>(p.system_type)); + ParamTraits<double>::Write(m, p.creation_time); + ParamTraits<double>::Write(m, p.last_access_time); + ParamTraits<double>::Write(m, p.last_modified_time); +} + +// static +bool ParamTraits<PP_FileInfo>::Read(const Message* m, void** iter, + param_type* r) { + int type, system_type; + if (!ParamTraits<int64_t>::Read(m, iter, &r->size) || + !ParamTraits<int>::Read(m, iter, &type) || + !ParamTraits<int>::Read(m, iter, &system_type) || + !ParamTraits<double>::Read(m, iter, &r->creation_time) || + !ParamTraits<double>::Read(m, iter, &r->last_access_time) || + !ParamTraits<double>::Read(m, iter, &r->last_modified_time)) + return false; + if (type != PP_FILETYPE_REGULAR && + type != PP_FILETYPE_DIRECTORY && + type != PP_FILETYPE_OTHER) + return false; + r->type = static_cast<PP_FileType>(type); + if (system_type != PP_FILESYSTEMTYPE_EXTERNAL && + system_type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && + system_type != PP_FILESYSTEMTYPE_LOCALTEMPORARY) + return false; + r->system_type = static_cast<PP_FileSystemType>(system_type); + return true; +} + +// static +void ParamTraits<PP_FileInfo>::Log(const param_type& p, std::string* l) { +} + +// PP_Flash_NetAddress --------------------------------------------------------- + +// static +void ParamTraits<PP_Flash_NetAddress>::Write(Message* m, const param_type& p) { + WriteParam(m, p.size); + m->WriteBytes(p.data, static_cast<int>(p.size)); +} + +// static +bool ParamTraits<PP_Flash_NetAddress>::Read(const Message* m, + void** iter, + param_type* p) { + uint16 size; + if (!ReadParam(m, iter, &size)) + return false; + if (size > sizeof(p->data)) + return false; + p->size = size; + + const char* data; + if (!m->ReadBytes(iter, &data, size)) + return false; + memcpy(p->data, data, size); + return true; +} + +// static +void ParamTraits<PP_Flash_NetAddress>::Log(const param_type& p, + std::string* l) { + l->append("<PP_Flash_NetAddress ("); + LogParam(p.size, l); + l->append(" bytes)>"); +} + +// PP_InputEvent --------------------------------------------------------------- + +// 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) { +} + +// PPBFlash_DrawGlyphs_Params -------------------------------------------------- + +// static +void ParamTraits<pp::proxy::PPBFlash_DrawGlyphs_Params>::Write( + Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance); + ParamTraits<pp::proxy::HostResource>::Write(m, p.image_data); + ParamTraits<pp::proxy::SerializedFontDescription>::Write(m, p.font_desc); + ParamTraits<uint32_t>::Write(m, p.color); + ParamTraits<PP_Point>::Write(m, p.position); + ParamTraits<PP_Rect>::Write(m, p.clip); + ParamTraits<float>::Write(m, p.transformation[0][0]); + ParamTraits<float>::Write(m, p.transformation[0][1]); + ParamTraits<float>::Write(m, p.transformation[0][2]); + ParamTraits<float>::Write(m, p.transformation[1][0]); + ParamTraits<float>::Write(m, p.transformation[1][1]); + ParamTraits<float>::Write(m, p.transformation[1][2]); + ParamTraits<float>::Write(m, p.transformation[2][0]); + ParamTraits<float>::Write(m, p.transformation[2][1]); + ParamTraits<float>::Write(m, p.transformation[2][2]); + ParamTraits<std::vector<uint16_t> >::Write(m, p.glyph_indices); + ParamTraits<std::vector<PP_Point> >::Write(m, p.glyph_advances); +} + +// static +bool ParamTraits<pp::proxy::PPBFlash_DrawGlyphs_Params>::Read( + const Message* m, + void** iter, + param_type* r) { + return + ParamTraits<PP_Instance>::Read(m, iter, &r->instance) && + ParamTraits<pp::proxy::HostResource>::Read(m, iter, + &r->image_data) && + ParamTraits<pp::proxy::SerializedFontDescription>::Read(m, iter, + &r->font_desc) && + ParamTraits<uint32_t>::Read(m, iter, &r->color) && + ParamTraits<PP_Point>::Read(m, iter, &r->position) && + ParamTraits<PP_Rect>::Read(m, iter, &r->clip) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[0][2]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[1][2]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][0]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][1]) && + ParamTraits<float>::Read(m, iter, &r->transformation[2][2]) && + ParamTraits<std::vector<uint16_t> >::Read(m, iter, &r->glyph_indices) && + ParamTraits<std::vector<PP_Point> >::Read(m, iter, &r->glyph_advances) && + r->glyph_indices.size() == r->glyph_advances.size(); +} + +// static +void ParamTraits<pp::proxy::PPBFlash_DrawGlyphs_Params>::Log( + const param_type& p, + std::string* l) { +} + +// PPBFileRef_CreateInfo ------------------------------------------------------- + +// static +void ParamTraits<pp::proxy::PPBFileRef_CreateInfo>::Write( + Message* m, + const param_type& p) { + ParamTraits<pp::proxy::HostResource>::Write(m, p.resource); + ParamTraits<int>::Write(m, p.file_system_type); + ParamTraits<pp::proxy::SerializedVar>::Write(m, p.path); + ParamTraits<pp::proxy::SerializedVar>::Write(m, p.name); +} + +// static +bool ParamTraits<pp::proxy::PPBFileRef_CreateInfo>::Read(const Message* m, + void** iter, + param_type* r) { + return + ParamTraits<pp::proxy::HostResource>::Read(m, iter, &r->resource) && + ParamTraits<int>::Read(m, iter, &r->file_system_type) && + ParamTraits<pp::proxy::SerializedVar>::Read(m, iter, &r->path) && + ParamTraits<pp::proxy::SerializedVar>::Read(m, iter, &r->name); +} + +// static +void ParamTraits<pp::proxy::PPBFileRef_CreateInfo>::Log( + const param_type& p, + std::string* l) { +} + +// PPBURLLoader_UpdateProgress_Params ------------------------------------------ + +// static +void ParamTraits<pp::proxy::PPBURLLoader_UpdateProgress_Params>::Write( + Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance); + ParamTraits<pp::proxy::HostResource>::Write(m, p.resource); + ParamTraits<int64_t>::Write(m, p.bytes_sent); + ParamTraits<int64_t>::Write(m, p.total_bytes_to_be_sent); + ParamTraits<int64_t>::Write(m, p.bytes_received); + ParamTraits<int64_t>::Write(m, p.total_bytes_to_be_received); +} + +// static +bool ParamTraits<pp::proxy::PPBURLLoader_UpdateProgress_Params>::Read( + const Message* m, + void** iter, + param_type* r) { + return + ParamTraits<PP_Instance>::Read(m, iter, &r->instance) && + ParamTraits<pp::proxy::HostResource>::Read(m, iter, &r->resource) && + ParamTraits<int64_t>::Read(m, iter, &r->bytes_sent) && + ParamTraits<int64_t>::Read(m, iter, &r->total_bytes_to_be_sent) && + ParamTraits<int64_t>::Read(m, iter, &r->bytes_received) && + ParamTraits<int64_t>::Read(m, iter, &r->total_bytes_to_be_received); +} + +// static +void ParamTraits<pp::proxy::PPBURLLoader_UpdateProgress_Params>::Log( + const param_type& p, + std::string* l) { +} + +// SerializedDirEntry ---------------------------------------------------------- + +// static +void ParamTraits<pp::proxy::SerializedDirEntry>::Write(Message* m, + const param_type& p) { + ParamTraits<std::string>::Write(m, p.name); + ParamTraits<bool>::Write(m, p.is_dir); +} + +// static +bool ParamTraits<pp::proxy::SerializedDirEntry>::Read(const Message* m, + void** iter, + param_type* r) { + return ParamTraits<std::string>::Read(m, iter, &r->name) && + ParamTraits<bool>::Read(m, iter, &r->is_dir); +} + +// static +void ParamTraits<pp::proxy::SerializedDirEntry>::Log(const param_type& p, + std::string* l) { +} + +// pp::proxy::SerializedFontDescription ---------------------------------------- + +// static +void ParamTraits<pp::proxy::SerializedFontDescription>::Write( + Message* m, + const param_type& p) { + ParamTraits<pp::proxy::SerializedVar>::Write(m, p.face); + ParamTraits<int32_t>::Write(m, p.family); + ParamTraits<uint32_t>::Write(m, p.size); + ParamTraits<int32_t>::Write(m, p.weight); + ParamTraits<PP_Bool>::Write(m, p.italic); + ParamTraits<PP_Bool>::Write(m, p.small_caps); + ParamTraits<int32_t>::Write(m, p.letter_spacing); + ParamTraits<int32_t>::Write(m, p.word_spacing); +} + +// static +bool ParamTraits<pp::proxy::SerializedFontDescription>::Read( + const Message* m, + void** iter, + param_type* r) { + return + ParamTraits<pp::proxy::SerializedVar>::Read(m, iter, &r->face) && + ParamTraits<int32_t>::Read(m, iter, &r->family) && + ParamTraits<uint32_t>::Read(m, iter, &r->size) && + ParamTraits<int32_t>::Read(m, iter, &r->weight) && + ParamTraits<PP_Bool>::Read(m, iter, &r->italic) && + ParamTraits<PP_Bool>::Read(m, iter, &r->small_caps) && + ParamTraits<int32_t>::Read(m, iter, &r->letter_spacing) && + ParamTraits<int32_t>::Read(m, iter, &r->word_spacing); +} + +// static +void ParamTraits<pp::proxy::SerializedFontDescription>::Log( + const param_type& p, + std::string* l) { +} + +// HostResource ---------------------------------------------------------- + +// static +void ParamTraits<pp::proxy::HostResource>::Write(Message* m, + const param_type& p) { + ParamTraits<PP_Instance>::Write(m, p.instance()); + ParamTraits<PP_Resource>::Write(m, p.host_resource()); +} + +// static +bool ParamTraits<pp::proxy::HostResource>::Read(const Message* m, + void** iter, + param_type* r) { + PP_Instance instance; + PP_Resource resource; + if (!ParamTraits<PP_Instance>::Read(m, iter, &instance) || + !ParamTraits<PP_Resource>::Read(m, iter, &resource)) + return false; + r->SetHostResource(instance, resource); + return true; +} + +// static +void ParamTraits<pp::proxy::HostResource>::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) { + WriteVectorWithoutCopy(m, p); +} + +// static +bool ParamTraits< std::vector<pp::proxy::SerializedVar> >::Read( + const Message* m, + void** iter, + param_type* r) { + return ReadVectorWithoutCopy(m, iter, r); +} + +// static +void ParamTraits< std::vector<pp::proxy::SerializedVar> >::Log( + const param_type& p, + std::string* l) { +} + +// std::vector<PPBFileRef_CreateInfo> ------------------------------------------ + +void ParamTraits< std::vector<pp::proxy::PPBFileRef_CreateInfo> >::Write( + Message* m, + const param_type& p) { + WriteVectorWithoutCopy(m, p); +} + +// static +bool ParamTraits< std::vector<pp::proxy::PPBFileRef_CreateInfo> >::Read( + const Message* m, + void** iter, + param_type* r) { + return ReadVectorWithoutCopy(m, iter, r); +} + +// static +void ParamTraits< std::vector<pp::proxy::PPBFileRef_CreateInfo> >::Log( + const param_type& p, + std::string* l) { +} + +// SerializedFlashMenu --------------------------------------------------------- + +// static +void ParamTraits<pp::proxy::SerializedFlashMenu>::Write(Message* m, + const param_type& p) { + p.WriteToMessage(m); +} + +// static +bool ParamTraits<pp::proxy::SerializedFlashMenu>::Read(const Message* m, + void** iter, + param_type* r) { + return r->ReadFromMessage(m, iter); +} + +// static +void ParamTraits<pp::proxy::SerializedFlashMenu>::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..0db47cd --- /dev/null +++ b/ppapi/proxy/ppapi_param_traits.h @@ -0,0 +1,162 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ +#define PPAPI_PROXY_PPAPI_PARAM_TRAITS_H_ + +#include <string> +#include <vector> + +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.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" + +struct PP_FileInfo; +struct PP_ObjectProperty; +struct PP_Flash_Menu; +struct PP_Flash_NetAddress; + +namespace pp { +namespace proxy { + +class HostResource; +struct PPBFileRef_CreateInfo; +struct PPBFlash_DrawGlyphs_Params; +struct PPBURLLoader_UpdateProgress_Params; +struct SerializedDirEntry; +struct SerializedFontDescription; +class SerializedFlashMenu; +class SerializedVar; + +} // namespace proxy +} // namespace pp + +namespace IPC { + +template<> +struct ParamTraits<PP_Bool> { + typedef PP_Bool 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_FileInfo> { + typedef PP_FileInfo 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_Flash_NetAddress> { + typedef PP_Flash_NetAddress param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + +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::proxy::PPBFlash_DrawGlyphs_Params> { + typedef pp::proxy::PPBFlash_DrawGlyphs_Params 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::PPBFileRef_CreateInfo> { + typedef pp::proxy::PPBFileRef_CreateInfo 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::PPBURLLoader_UpdateProgress_Params> { + typedef pp::proxy::PPBURLLoader_UpdateProgress_Params 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::SerializedDirEntry> { + typedef pp::proxy::SerializedDirEntry 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::SerializedFontDescription> { + typedef pp::proxy::SerializedFontDescription 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::HostResource> { + typedef pp::proxy::HostResource 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); +}; + +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); +}; + +template<> +struct ParamTraits< std::vector<pp::proxy::PPBFileRef_CreateInfo> > { + typedef std::vector<pp::proxy::PPBFileRef_CreateInfo> 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::SerializedFlashMenu> { + typedef pp::proxy::SerializedFlashMenu 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/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc new file mode 100644 index 0000000..c8bb7eb --- /dev/null +++ b/ppapi/proxy/ppapi_proxy_test.cc @@ -0,0 +1,376 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppapi_proxy_test.h" + +#include "base/message_loop_proxy.h" +#include "base/observer_list.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_preferences.cc" + +namespace pp { +namespace proxy { + +namespace { +// HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback +// do-nothing implementation. +void PluginCrashed(PP_Module module) { + NOTREACHED(); +}; + +PP_Instance GetInstanceForResource(PP_Resource resource) { + // If a test relies on this, we need to implement it. + NOTREACHED(); + return 0; +} + +void SetReserveInstanceIDCallback(PP_Module module, + PP_Bool (*is_seen)(PP_Module, PP_Instance)) { + // This function gets called in HostDispatcher's constructor. We simply don't + // worry about Instance uniqueness in tests, so we can ignore the call. +} + +int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) { + NOTREACHED(); + return 0; +} + +void AddRefModule(PP_Module module) {} +void ReleaseModule(PP_Module module) {} + +PPB_Proxy_Private ppb_proxy_private = { PluginCrashed, + GetInstanceForResource, + SetReserveInstanceIDCallback, + GetURLLoaderBufferedBytes, + AddRefModule, + ReleaseModule }; + +// We allow multiple harnesses at a time to respond to 'GetInterface' calls. +// We assume that only 1 harness's GetInterface function will ever support a +// given interface name. In practice, there will either be only 1 GetInterface +// handler (for PluginProxyTest or HostProxyTest), or there will be only 2 +// GetInterface handlers (for TwoWayTest). In the latter case, one handler is +// for the PluginProxyTestHarness and should only respond for PPP interfaces, +// and the other handler is for the HostProxyTestHarness which should only +// ever respond for PPB interfaces. +ObserverList<ProxyTestHarnessBase> get_interface_handlers_; + +const void* MockGetInterface(const char* name) { + ObserverList<ProxyTestHarnessBase>::Iterator it = + get_interface_handlers_; + while (ProxyTestHarnessBase* observer = it.GetNext()) { + const void* interface = observer->GetInterface(name); + if (interface) + return interface; + } + if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0) + return &ppb_proxy_private; + return NULL; +} + +void SetUpRemoteHarness(ProxyTestHarnessBase* harness, + const IPC::ChannelHandle& handle, + base::MessageLoopProxy* ipc_message_loop_proxy, + base::WaitableEvent* shutdown_event, + base::WaitableEvent* harness_set_up) { + harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy, + shutdown_event, false); + harness_set_up->Signal(); +} + +void TearDownRemoteHarness(ProxyTestHarnessBase* harness, + base::WaitableEvent* harness_torn_down) { + harness->TearDownHarness(); + harness_torn_down->Signal(); +} + +} // namespace + +// ProxyTestHarnessBase -------------------------------------------------------- + +ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765), + pp_instance_(0x12345) { + get_interface_handlers_.AddObserver(this); +} + +ProxyTestHarnessBase::~ProxyTestHarnessBase() { + get_interface_handlers_.RemoveObserver(this); +} + +const void* ProxyTestHarnessBase::GetInterface(const char* name) { + return registered_interfaces_[name]; +} + +void ProxyTestHarnessBase::RegisterTestInterface(const char* name, + const void* interface) { + registered_interfaces_[name] = interface; +} + +bool ProxyTestHarnessBase::SupportsInterface(const char* name) { + sink().ClearMessages(); + + // IPC doesn't actually write to this when we send a message manually + // not actually using IPC. + bool unused_result = false; + PpapiMsg_SupportsInterface msg(name, &unused_result); + GetDispatcher()->OnMessageReceived(msg); + + const IPC::Message* reply_msg = + sink().GetUniqueMessageMatching(IPC_REPLY_ID); + EXPECT_TRUE(reply_msg); + if (!reply_msg) + return false; + + TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data; + EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam( + reply_msg, &reply_data)); + + sink().ClearMessages(); + return reply_data.a; +} + +// PluginProxyTestHarness ------------------------------------------------------ + +PluginProxyTestHarness::PluginProxyTestHarness() { +} + +PluginProxyTestHarness::~PluginProxyTestHarness() { +} + +Dispatcher* PluginProxyTestHarness::GetDispatcher() { + return plugin_dispatcher_.get(); +} + +void PluginProxyTestHarness::SetUpHarness() { + // These must be first since the dispatcher set-up uses them. + PluginResourceTracker::SetInstanceForTest(&resource_tracker_); + PluginVarTracker::SetInstanceForTest(&var_tracker_); + + plugin_dispatcher_.reset(new PluginDispatcher( + base::Process::Current().handle(), + &MockGetInterface)); + plugin_dispatcher_->InitWithTestSink(&sink()); + plugin_dispatcher_->DidCreateInstance(pp_instance()); +} + +void PluginProxyTestHarness::SetUpHarnessWithChannel( + const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) { + // These must be first since the dispatcher set-up uses them. + PluginResourceTracker::SetInstanceForTest(&resource_tracker_); + PluginVarTracker::SetInstanceForTest(&var_tracker_); + plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event); + + plugin_dispatcher_.reset(new PluginDispatcher( + base::Process::Current().handle(), + &MockGetInterface)); + plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_, + channel_handle, + is_client); + plugin_dispatcher_->DidCreateInstance(pp_instance()); +} + +void PluginProxyTestHarness::TearDownHarness() { + plugin_dispatcher_->DidDestroyInstance(pp_instance()); + plugin_dispatcher_.reset(); + + PluginVarTracker::SetInstanceForTest(NULL); + PluginResourceTracker::SetInstanceForTest(NULL); +} + +base::MessageLoopProxy* +PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() { + return ipc_message_loop_; +} + +base::WaitableEvent* +PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() { + return shutdown_event_; +} + +std::set<PP_Instance>* +PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() { + return &instance_id_set_; +} + +ppapi::WebKitForwarding* +PluginProxyTestHarness::PluginDelegateMock::GetWebKitForwarding() { + NOTREACHED(); + return NULL; +} + +void PluginProxyTestHarness::PluginDelegateMock::PostToWebKitThread( + const tracked_objects::Location& from_here, const base::Closure& task) { + NOTREACHED(); +} + +bool PluginProxyTestHarness::PluginDelegateMock::SendToBrowser( + IPC::Message* msg) { + NOTREACHED(); + return false; +} + +uint32 PluginProxyTestHarness::PluginDelegateMock::Register( + PluginDispatcher* plugin_dispatcher) { + return 0; +} + +void PluginProxyTestHarness::PluginDelegateMock::Unregister( + uint32 plugin_dispatcher_id) { +} + +// PluginProxyTest ------------------------------------------------------------- + +PluginProxyTest::PluginProxyTest() { +} + +PluginProxyTest::~PluginProxyTest() { +} + +void PluginProxyTest::SetUp() { + SetUpHarness(); +} + +void PluginProxyTest::TearDown() { + TearDownHarness(); +} + +// HostProxyTestHarness -------------------------------------------------------- + +HostProxyTestHarness::HostProxyTestHarness() { +} + +HostProxyTestHarness::~HostProxyTestHarness() { +} + +Dispatcher* HostProxyTestHarness::GetDispatcher() { + return host_dispatcher_.get(); +} + +void HostProxyTestHarness::SetUpHarness() { + host_dispatcher_.reset(new HostDispatcher( + base::Process::Current().handle(), + pp_module(), + &MockGetInterface)); + host_dispatcher_->InitWithTestSink(&sink()); + HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get()); +} + +void HostProxyTestHarness::SetUpHarnessWithChannel( + const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) { + delegate_mock_.Init(ipc_message_loop, shutdown_event); + host_dispatcher_.reset(new HostDispatcher( + base::Process::Current().handle(), + pp_module(), + &MockGetInterface)); + ppapi::Preferences preferences; + host_dispatcher_->InitHostWithChannel(&delegate_mock_, channel_handle, + is_client, preferences); + HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get()); +} + +void HostProxyTestHarness::TearDownHarness() { + HostDispatcher::RemoveForInstance(pp_instance()); + host_dispatcher_.reset(); +} + +base::MessageLoopProxy* +HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() { + return ipc_message_loop_; +} + +base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() { + return shutdown_event_; +} + + +// HostProxyTest --------------------------------------------------------------- + +HostProxyTest::HostProxyTest() { +} + +HostProxyTest::~HostProxyTest() { +} + +void HostProxyTest::SetUp() { + SetUpHarness(); +} + +void HostProxyTest::TearDown() { + TearDownHarness(); +} + +// TwoWayTest --------------------------------------------------------------- + +TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode) + : test_mode_(test_mode), + io_thread_("TwoWayTest_IOThread"), + plugin_thread_("TwoWayTest_PluginThread"), + remote_harness_(NULL), + local_harness_(NULL), + channel_created_(true, false), + shutdown_event_(true, false) { + if (test_mode == TEST_PPP_INTERFACE) { + remote_harness_ = &plugin_; + local_harness_ = &host_; + } else { + remote_harness_ = &host_; + local_harness_ = &plugin_; + } +} + +TwoWayTest::~TwoWayTest() { + shutdown_event_.Signal(); +} + +void TwoWayTest::SetUp() { + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + plugin_thread_.Start(); + + IPC::ChannelHandle handle; + handle.name = "TwoWayTestChannel"; + + base::WaitableEvent remote_harness_set_up(true, false); + plugin_thread_.message_loop_proxy()->PostTask( + FROM_HERE, + NewRunnableFunction(&SetUpRemoteHarness, + remote_harness_, + handle, + io_thread_.message_loop_proxy(), + &shutdown_event_, + &remote_harness_set_up)); + remote_harness_set_up.Wait(); + local_harness_->SetUpHarnessWithChannel(handle, + io_thread_.message_loop_proxy(), + &shutdown_event_, + true); // is_client +} + +void TwoWayTest::TearDown() { + base::WaitableEvent remote_harness_torn_down(true, false); + plugin_thread_.message_loop_proxy()->PostTask( + FROM_HERE, + NewRunnableFunction(&TearDownRemoteHarness, + remote_harness_, + &remote_harness_torn_down)); + remote_harness_torn_down.Wait(); + + local_harness_->TearDownHarness(); + + io_thread_.Stop(); +} + + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppapi_proxy_test.h b/ppapi/proxy/ppapi_proxy_test.h new file mode 100644 index 0000000..775b75c --- /dev/null +++ b/ppapi/proxy/ppapi_proxy_test.h @@ -0,0 +1,243 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> +#include <string> + +#include "base/message_loop.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "ipc/ipc_test_sink.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace pp { +namespace proxy { + +// Base class for plugin and host test harnesses. Tests will not use this +// directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest. +class ProxyTestHarnessBase { + public: + ProxyTestHarnessBase(); + virtual ~ProxyTestHarnessBase(); + + PP_Module pp_module() const { return pp_module_; } + PP_Instance pp_instance() const { return pp_instance_; } + IPC::TestSink& sink() { return sink_; } + + // Returns either the plugin or host dispatcher, depending on the test. + virtual Dispatcher* GetDispatcher() = 0; + + // Set up the harness using an IPC::TestSink to capture messages. + virtual void SetUpHarness() = 0; + + // Set up the harness using a real IPC channel. + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client) = 0; + + virtual void TearDownHarness() = 0; + + // Implementation of GetInterface for the dispatcher. This will + // return NULL for all interfaces unless one is registered by calling + // RegisterTestInterface(); + const void* GetInterface(const char* name); + + // Allows the test to specify an interface implementation for a given + // interface name. This will be returned when any of the proxy logic + // requests a local interface. + void RegisterTestInterface(const char* name, const void* interface); + + // Sends a "supports interface" message to the current dispatcher and returns + // true if it's supported. This is just for the convenience of tests. + bool SupportsInterface(const char* name); + + private: + // Destination for IPC messages sent by the test. + IPC::TestSink sink_; + + // The module and instance ID associated with the plugin dispatcher. + PP_Module pp_module_; + PP_Instance pp_instance_; + + // Stores the data for GetInterface/RegisterTestInterface. + std::map<std::string, const void*> registered_interfaces_; +}; + +// Test harness for the plugin side of the proxy. +class PluginProxyTestHarness : public ProxyTestHarnessBase { + public: + PluginProxyTestHarness(); + virtual ~PluginProxyTestHarness(); + + PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); } + PluginResourceTracker& resource_tracker() { return resource_tracker_; } + PluginVarTracker& var_tracker() { return var_tracker_; } + + // ProxyTestHarnessBase implementation. + virtual Dispatcher* GetDispatcher(); + virtual void SetUpHarness(); + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client); + virtual void TearDownHarness(); + + class PluginDelegateMock : public PluginDispatcher::PluginDelegate { + public: + PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {} + virtual ~PluginDelegateMock() {} + + void Init(base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event) { + ipc_message_loop_ = ipc_message_loop; + shutdown_event_ = shutdown_event; + } + + // ProxyChannel::Delegate implementation. + virtual base::MessageLoopProxy* GetIPCMessageLoop(); + virtual base::WaitableEvent* GetShutdownEvent(); + + // PluginDispatcher::PluginDelegate implementation. + virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet(); + virtual ppapi::WebKitForwarding* GetWebKitForwarding(); + virtual void PostToWebKitThread(const tracked_objects::Location& from_here, + const base::Closure& task); + virtual bool SendToBrowser(IPC::Message* msg); + virtual uint32 Register(PluginDispatcher* plugin_dispatcher); + virtual void Unregister(uint32 plugin_dispatcher_id); + + private: + base::MessageLoopProxy* ipc_message_loop_; // Weak + base::WaitableEvent* shutdown_event_; // Weak + std::set<PP_Instance> instance_id_set_; + + DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock); + }; + + private: + PluginResourceTracker resource_tracker_; + PluginVarTracker var_tracker_; + scoped_ptr<PluginDispatcher> plugin_dispatcher_; + PluginDelegateMock plugin_delegate_mock_; +}; + +class PluginProxyTest : public PluginProxyTestHarness, public testing::Test { + public: + PluginProxyTest(); + virtual ~PluginProxyTest(); + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + private: + MessageLoop message_loop_; +}; + +class HostProxyTestHarness : public ProxyTestHarnessBase { + public: + HostProxyTestHarness(); + virtual ~HostProxyTestHarness(); + + HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); } + + // ProxyTestBase implementation. + virtual Dispatcher* GetDispatcher(); + virtual void SetUpHarness(); + virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle, + base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event, + bool is_client); + virtual void TearDownHarness(); + + class DelegateMock : public ProxyChannel::Delegate { + public: + DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) { + } + virtual ~DelegateMock() {} + + void Init(base::MessageLoopProxy* ipc_message_loop, + base::WaitableEvent* shutdown_event) { + ipc_message_loop_ = ipc_message_loop; + shutdown_event_ = shutdown_event; + } + + // ProxyChannel::Delegate implementation. + virtual base::MessageLoopProxy* GetIPCMessageLoop(); + virtual base::WaitableEvent* GetShutdownEvent(); + + private: + base::MessageLoopProxy* ipc_message_loop_; // Weak + base::WaitableEvent* shutdown_event_; // Weak + + DISALLOW_COPY_AND_ASSIGN(DelegateMock); + }; + + private: + scoped_ptr<HostDispatcher> host_dispatcher_; + DelegateMock delegate_mock_; +}; + +class HostProxyTest : public HostProxyTestHarness, public testing::Test { + public: + HostProxyTest(); + virtual ~HostProxyTest(); + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + private: + MessageLoop message_loop_; +}; + +// Use this base class to test both sides of a proxy. +class TwoWayTest : public testing::Test { + public: + enum TwoWayTestMode { + TEST_PPP_INTERFACE, + TEST_PPB_INTERFACE + }; + TwoWayTest(TwoWayTestMode test_mode); + virtual ~TwoWayTest(); + + HostProxyTestHarness& host() { return host_; } + PluginProxyTestHarness& plugin() { return plugin_; } + PP_Module pp_module() const { return host_.pp_module(); } + PP_Instance pp_instance() const { return host_.pp_instance(); } + TwoWayTestMode test_mode() { return test_mode_; } + + // testing::Test implementation. + virtual void SetUp(); + virtual void TearDown(); + + private: + TwoWayTestMode test_mode_; + HostProxyTestHarness host_; + PluginProxyTestHarness plugin_; + // In order to use sync IPC, we need to have an IO thread. + base::Thread io_thread_; + // The plugin side of the proxy runs on its own thread. + base::Thread plugin_thread_; + // The message loop for the main (host) thread. + MessageLoop message_loop_; + + // Aliases for the host and plugin harnesses; if we're testing a PPP + // interface, remote_harness will point to plugin_, and local_harness + // will point to host_. This makes it convenient when we're starting and + // stopping the harnesses. + ProxyTestHarnessBase* remote_harness_; + ProxyTestHarnessBase* local_harness_; + + base::WaitableEvent channel_created_; + base::WaitableEvent shutdown_event_; +}; + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_audio_config_proxy.cc b/ppapi/proxy/ppb_audio_config_proxy.cc new file mode 100644 index 0000000..e8eb056 --- /dev/null +++ b/ppapi/proxy/ppb_audio_config_proxy.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_audio_config_proxy.h" + +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/audio_config_impl.h" +#include "ppapi/thunk/thunk.h" + +namespace pp { +namespace proxy { + +// The implementation is actually in AudioConfigImpl. +class AudioConfig : public PluginResource, + public ppapi::AudioConfigImpl { + public: + // Note that you must call Init (on AudioConfigImpl) before using this class. + AudioConfig(const HostResource& resource); + virtual ~AudioConfig(); + + // ResourceObjectBase overrides. + virtual ::ppapi::thunk::PPB_AudioConfig_API* AsPPB_AudioConfig_API() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(AudioConfig); +}; + +AudioConfig::AudioConfig(const HostResource& resource) + : PluginResource(resource) { +} + +AudioConfig::~AudioConfig() { +} + +::ppapi::thunk::PPB_AudioConfig_API* AudioConfig::AsPPB_AudioConfig_API() { + return this; +} + +namespace { + +InterfaceProxy* CreateAudioConfigProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_AudioConfig_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_AudioConfig_Proxy::PPB_AudioConfig_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_AudioConfig_Proxy::~PPB_AudioConfig_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_AudioConfig_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_AudioConfig_Thunk(), + PPB_AUDIO_CONFIG_INTERFACE, + INTERFACE_ID_PPB_AUDIO_CONFIG, + false, + &CreateAudioConfigProxy, + }; + return &info; +} + +// static +PP_Resource PPB_AudioConfig_Proxy::CreateProxyResource( + PP_Instance instance, + PP_AudioSampleRate sample_rate, + uint32_t sample_frame_count) { + linked_ptr<AudioConfig> object(new AudioConfig( + HostResource::MakeInstanceOnly(instance))); + if (!object->Init(sample_rate, sample_frame_count)) + return 0; + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_AudioConfig_Proxy::OnMessageReceived(const IPC::Message& msg) { + // There are no IPC messages for this interface. + NOTREACHED(); + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_audio_config_proxy.h b/ppapi/proxy/ppb_audio_config_proxy.h new file mode 100644 index 0000000..e8a12e8 --- /dev/null +++ b/ppapi/proxy/ppb_audio_config_proxy.h @@ -0,0 +1,42 @@ +// 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_PPB_AUDIO_CONFIG_PROXY_H_ +#define PPAPI_PROXY_PPB_AUDIO_CONFIG_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_AudioConfig; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_AudioConfig_Proxy : public InterfaceProxy { + public: + PPB_AudioConfig_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_AudioConfig_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + PP_AudioSampleRate sample_rate, + uint32_t sample_frame_count); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_AudioConfig_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_AUDIO_CONFIG_PROXY_H_ diff --git a/ppapi/proxy/ppb_audio_proxy.cc b/ppapi/proxy/ppb_audio_proxy.cc new file mode 100644 index 0000000..76f3046 --- /dev/null +++ b/ppapi/proxy/ppb_audio_proxy.cc @@ -0,0 +1,318 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_audio_proxy.h" + +#include "base/threading/simple_thread.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/c/trusted/ppb_audio_trusted.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/audio_impl.h" +#include "ppapi/thunk/ppb_audio_config_api.h" +#include "ppapi/thunk/ppb_audio_trusted_api.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ::ppapi::thunk::PPB_Audio_API; + +namespace pp { +namespace proxy { + +class Audio : public PluginResource, public ppapi::AudioImpl { + public: + Audio(const HostResource& audio_id, + PP_Resource config_id, + PPB_Audio_Callback callback, + void* user_data); + virtual ~Audio(); + + // ResourceObjectBase overrides. + virtual PPB_Audio_API* AsPPB_Audio_API(); + + // PPB_Audio_API implementation. + virtual PP_Resource GetCurrentConfig() OVERRIDE; + virtual PP_Bool StartPlayback() OVERRIDE; + virtual PP_Bool StopPlayback() OVERRIDE; + + private: + // Owning reference to the current config object. This isn't actually used, + // we just dish it out as requested by the plugin. + PP_Resource config_; + + DISALLOW_COPY_AND_ASSIGN(Audio); +}; + +Audio::Audio(const HostResource& audio_id, + PP_Resource config_id, + PPB_Audio_Callback callback, + void* user_data) + : PluginResource(audio_id), + config_(config_id) { + SetCallback(callback, user_data); + PluginResourceTracker::GetInstance()->AddRefResource(config_); +} + +Audio::~Audio() { + PluginResourceTracker::GetInstance()->ReleaseResource(config_); +} + +PPB_Audio_API* Audio::AsPPB_Audio_API() { + return this; +} + +PP_Resource Audio::GetCurrentConfig() { + // AddRef for the caller. + PluginResourceTracker::GetInstance()->AddRefResource(config_); + return config_; +} + +PP_Bool Audio::StartPlayback() { + if (playing()) + return PP_TRUE; + SetStartPlaybackState(); + PluginDispatcher::GetForInstance(instance())->Send( + new PpapiHostMsg_PPBAudio_StartOrStop( + INTERFACE_ID_PPB_AUDIO, host_resource(), true)); + return PP_TRUE; +} + +PP_Bool Audio::StopPlayback() { + if (!playing()) + return PP_TRUE; + PluginDispatcher::GetForInstance(instance())->Send( + new PpapiHostMsg_PPBAudio_StartOrStop( + INTERFACE_ID_PPB_AUDIO, host_resource(), false)); + SetStopPlaybackState(); + return PP_TRUE; +} + +namespace { + +InterfaceProxy* CreateAudioProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Audio_Proxy(dispatcher, target_interface); +} + +base::PlatformFile IntToPlatformFile(int32_t handle) { + // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle, + // those casts are ugly. +#if defined(OS_WIN) + return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); +#elif defined(OS_POSIX) + return handle; +#else + #error Not implemented. +#endif +} + +} // namespace + +PPB_Audio_Proxy::PPB_Audio_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Audio_Proxy::~PPB_Audio_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Audio_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_Audio_Thunk(), + PPB_AUDIO_INTERFACE, + INTERFACE_ID_PPB_AUDIO, + false, + &CreateAudioProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Audio_Proxy::CreateProxyResource( + PP_Instance instance_id, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return 0; + + ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioConfig_API> + config(config_id, true); + if (config.failed()) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBAudio_Create( + INTERFACE_ID_PPB_AUDIO, instance_id, + config.object()->GetSampleRate(), config.object()->GetSampleFrameCount(), + &result)); + if (result.is_null()) + return 0; + + linked_ptr<Audio> object(new Audio(result, config_id, + audio_callback, user_data)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_Audio_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Audio_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBAudio_StartOrStop, + OnMsgStartOrStop) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, + OnMsgNotifyAudioStreamCreated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Audio_Proxy::OnMsgCreate(PP_Instance instance_id, + int32_t sample_rate, + uint32_t sample_frame_count, + HostResource* result) { + ::ppapi::thunk::EnterFunction< ::ppapi::thunk::ResourceCreationAPI> + resource_creation(instance_id, true); + if (resource_creation.failed()) + return; + + // Make the resource and get the API pointer to its trusted interface. + result->SetHostResource( + instance_id, + resource_creation.functions()->CreateAudioTrusted(instance_id)); + if (result->is_null()) + return; + ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioTrusted_API> + trusted_audio(result->host_resource(), false); + if (trusted_audio.failed()) + return; + + // Make an audio config object. + PP_Resource audio_config_res = + resource_creation.functions()->CreateAudioConfig( + instance_id, static_cast<PP_AudioSampleRate>(sample_rate), + sample_frame_count); + if (!audio_config_res) + return; + + // Initiate opening the audio object. + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Audio_Proxy::AudioChannelConnected, *result); + int32_t open_error = trusted_audio.object()->OpenTrusted( + audio_config_res, callback.pp_completion_callback()); + if (open_error != PP_OK_COMPLETIONPENDING) + callback.Run(open_error); + + // Clean up the temporary audio config resource we made. + const PPB_Core* core = static_cast<const PPB_Core*>( + dispatcher()->GetLocalInterface(PPB_CORE_INTERFACE)); + core->ReleaseResource(audio_config_res); +} + +void PPB_Audio_Proxy::OnMsgStartOrStop(const HostResource& audio_id, + bool play) { + if (play) + ppb_audio_target()->StartPlayback(audio_id.host_resource()); + else + ppb_audio_target()->StopPlayback(audio_id.host_resource()); +} + +// Processed in the plugin (message from host). +void PPB_Audio_Proxy::OnMsgNotifyAudioStreamCreated( + const HostResource& audio_id, + int32_t result_code, + IPC::PlatformFileForTransit socket_handle, + base::SharedMemoryHandle handle, + uint32_t length) { + EnterPluginFromHostResource<PPB_Audio_API> enter(audio_id); + if (enter.failed() || result_code != PP_OK) { + // The caller may still have given us these handles in the failure case. + // The easiest way to clean these up is to just put them in the objects + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + base::SharedMemory temp_mem(handle, false); + } else { + static_cast<Audio*>(enter.object())->SetStreamInfo( + handle, length, + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + } +} + +void PPB_Audio_Proxy::AudioChannelConnected( + int32_t result, + const HostResource& resource) { + IPC::PlatformFileForTransit socket_handle = + IPC::InvalidPlatformFileForTransit(); + base::SharedMemoryHandle shared_memory = IPC::InvalidPlatformFileForTransit(); + uint32_t shared_memory_length = 0; + + int32_t result_code = result; + if (result_code == PP_OK) { + result_code = GetAudioConnectedHandles(resource, &socket_handle, + &shared_memory, + &shared_memory_length); + } + + // Send all the values, even on error. This simplifies some of our cleanup + // code since the handles will be in the other process and could be + // inconvenient to clean up. Our IPC code will automatically handle this for + // us, as long as the remote side always closes the handles it receives + // (in OnMsgNotifyAudioStreamCreated), even in the failure case. + dispatcher()->Send(new PpapiMsg_PPBAudio_NotifyAudioStreamCreated( + INTERFACE_ID_PPB_AUDIO, resource, result_code, socket_handle, + shared_memory, shared_memory_length)); +} + +int32_t PPB_Audio_Proxy::GetAudioConnectedHandles( + const HostResource& resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length) { + // Get the trusted audio interface which will give us the handles. + ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_AudioTrusted_API> + trusted_audio(resource.host_resource(), false); + if (trusted_audio.failed()) + return PP_ERROR_NOINTERFACE; + + // Get the socket handle for signaling. + int32_t socket_handle; + int32_t result = trusted_audio.object()->GetSyncSocket(&socket_handle); + if (result != PP_OK) + return result; + + // socket_handle doesn't belong to us: don't close it. + *foreign_socket_handle = dispatcher()->ShareHandleWithRemote( + IntToPlatformFile(socket_handle), false); + if (*foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) + return PP_ERROR_FAILED; + + // Get the shared memory for the buffer. + int shared_memory_handle; + result = trusted_audio.object()->GetSharedMemory(&shared_memory_handle, + shared_memory_length); + if (result != PP_OK) + return result; + + // shared_memory_handle doesn't belong to us: don't close it. + *foreign_shared_memory_handle = dispatcher()->ShareHandleWithRemote( + IntToPlatformFile(shared_memory_handle), false); + if (*foreign_shared_memory_handle == IPC::InvalidPlatformFileForTransit()) + return PP_ERROR_FAILED; + + return PP_OK; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_audio_proxy.h b/ppapi/proxy/ppb_audio_proxy.h new file mode 100644 index 0000000..e39a82d --- /dev/null +++ b/ppapi/proxy/ppb_audio_proxy.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_AUDIO_PROXY_H_ +#define PPAPI_PROXY_PPB_AUDIO_PROXY_H_ + +#include <utility> + +#include "base/basictypes.h" +#include "base/shared_memory.h" +#include "base/sync_socket.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_audio.h" +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_Audio; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_Audio_Proxy : public InterfaceProxy { + public: + PPB_Audio_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Audio_Proxy(); + + static const Info* GetInfo(); + + // Creates an Audio object in the plugin process. + static PP_Resource CreateProxyResource(PP_Instance instance_id, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data); + + + const PPB_Audio* ppb_audio_target() const { + return static_cast<const PPB_Audio*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Plugin->renderer message handlers. + void OnMsgCreate(PP_Instance instance_id, + int32_t sample_rate, + uint32_t sample_frame_count, + HostResource* result); + void OnMsgStartOrStop(const HostResource& audio_id, bool play); + + // Renderer->plugin message handlers. + void OnMsgNotifyAudioStreamCreated(const HostResource& audio_id, + int32_t result_code, + IPC::PlatformFileForTransit socket_handle, + base::SharedMemoryHandle handle, + uint32_t length); + + void AudioChannelConnected(int32_t result, + const HostResource& resource); + + // In the renderer, this is called in response to a stream created message. + // It will retrieve the shared memory and socket handles and place them into + // the given out params. The return value is a PPAPI error code. + // + // The input arguments should be initialized to 0 or -1, depending on the + // platform's default invalid handle values. On error, some of these + // arguments may be written to, and others may be untouched, depending on + // where the error occurred. + int32_t GetAudioConnectedHandles( + const HostResource& resource, + IPC::PlatformFileForTransit* foreign_socket_handle, + base::SharedMemoryHandle* foreign_shared_memory_handle, + uint32_t* shared_memory_length); + + CompletionCallbackFactory<PPB_Audio_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_AUDIO_PROXY_H_ diff --git a/ppapi/proxy/ppb_broker_proxy.cc b/ppapi/proxy/ppb_broker_proxy.cc new file mode 100644 index 0000000..37f8ba0 --- /dev/null +++ b/ppapi/proxy/ppb_broker_proxy.cc @@ -0,0 +1,281 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_broker_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/trusted/ppb_broker_trusted.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/ppb_broker_api.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/thunk.h" + +namespace pp { +namespace proxy { + +namespace { + +base::PlatformFile IntToPlatformFile(int32_t handle) { +#if defined(OS_WIN) + return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); +#elif defined(OS_POSIX) + return handle; +#else + #error Not implemented. +#endif +} + +int32_t PlatformFileToInt(base::PlatformFile handle) { +#if defined(OS_WIN) + return static_cast<int32_t>(reinterpret_cast<intptr_t>(handle)); +#elif defined(OS_POSIX) + return handle; +#else + #error Not implemented. +#endif +} + +InterfaceProxy* CreateBrokerProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Broker_Proxy(dispatcher, target_interface); +} + +} // namespace + +class Broker : public ppapi::thunk::PPB_Broker_API, + public PluginResource { + public: + explicit Broker(const HostResource& resource); + virtual ~Broker(); + + // ResourceObjectBase overries. + virtual ppapi::thunk::PPB_Broker_API* AsPPB_Broker_API() OVERRIDE; + + // PPB_Broker_API implementation. + virtual int32_t Connect(PP_CompletionCallback connect_callback) OVERRIDE; + virtual int32_t GetHandle(int32_t* handle) OVERRIDE; + + // Called by the proxy when the host side has completed the request. + void ConnectComplete(IPC::PlatformFileForTransit socket_handle, + int32_t result); + + private: + bool called_connect_; + PP_CompletionCallback current_connect_callback_; + + // The plugin module owns the handle. + // The host side transfers ownership of the handle to the plugin side when it + // sends the IPC. This member holds the handle value for the plugin module + // to read, but the plugin side of the proxy never takes ownership. + base::SyncSocket::Handle socket_handle_; + + DISALLOW_COPY_AND_ASSIGN(Broker); +}; + +Broker::Broker(const HostResource& resource) + : PluginResource(resource), + called_connect_(false), + current_connect_callback_(PP_MakeCompletionCallback(NULL, NULL)), + socket_handle_(base::kInvalidPlatformFileValue) { +} + +Broker::~Broker() { + // Ensure the callback is always fired. + if (current_connect_callback_.func) { + // TODO(brettw) the callbacks at this level should be refactored with a + // more automatic tracking system like we have in the renderer. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( + current_connect_callback_.func, current_connect_callback_.user_data, + static_cast<int32_t>(PP_ERROR_ABORTED))); + } + + socket_handle_ = base::kInvalidPlatformFileValue; +} + +ppapi::thunk::PPB_Broker_API* Broker::AsPPB_Broker_API() { + return this; +} + +int32_t Broker::Connect(PP_CompletionCallback connect_callback) { + if (!connect_callback.func) { + // Synchronous calls are not supported. + return PP_ERROR_BADARGUMENT; + } + + if (current_connect_callback_.func) + return PP_ERROR_INPROGRESS; + else if (called_connect_) + return PP_ERROR_FAILED; + + current_connect_callback_ = connect_callback; + called_connect_ = true; + + bool success = GetDispatcher()->Send(new PpapiHostMsg_PPBBroker_Connect( + INTERFACE_ID_PPB_BROKER, host_resource())); + return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED; +} + +int32_t Broker::GetHandle(int32_t* handle) { + if (socket_handle_ == base::kInvalidPlatformFileValue) + return PP_ERROR_FAILED; + *handle = PlatformFileToInt(socket_handle_); + return PP_OK; +} + +void Broker::ConnectComplete(IPC::PlatformFileForTransit socket_handle, + int32_t result) { + if (result == PP_OK) { + DCHECK(socket_handle_ == base::kInvalidPlatformFileValue); + socket_handle_ = IPC::PlatformFileForTransitToPlatformFile(socket_handle); + } else { + // The caller may still have given us a handle in the failure case. + // The easiest way to clean it up is to just put it in an object + // and then close them. This failure case is not performance critical. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + } + + if (!current_connect_callback_.func) { + // The handle might leak if the plugin never calls GetHandle(). + return; + } + + PP_RunAndClearCompletionCallback(¤t_connect_callback_, result); +} + +PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) , + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)){ +} + +PPB_Broker_Proxy::~PPB_Broker_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Broker_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_Broker_Thunk(), + PPB_BROKER_TRUSTED_INTERFACE, + INTERFACE_ID_PPB_BROKER, + true, + &CreateBrokerProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Broker_Proxy::CreateProxyResource(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBBroker_Create( + INTERFACE_ID_PPB_BROKER, instance, &result)); + if (result.is_null()) + return 0; + + linked_ptr<Broker> object(new Broker(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete, + OnMsgConnectComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance, + HostResource* result_resource) { + result_resource->SetHostResource( + instance, + ppb_broker_target()->CreateTrusted(instance)); +} + +void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) { + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Broker_Proxy::ConnectCompleteInHost, broker); + + int32_t result = ppb_broker_target()->Connect( + broker.host_resource(), + callback.pp_completion_callback()); + if (result != PP_OK_COMPLETIONPENDING) + callback.Run(result); +} + +// Called in the plugin to handle the connect callback. +// The proxy owns the handle and transfers it to the Broker. At that point, +// the plugin owns the handle and is responsible for closing it. +// The caller guarantees that socket_handle is not valid if result is not PP_OK. +void PPB_Broker_Proxy::OnMsgConnectComplete( + const HostResource& resource, + IPC::PlatformFileForTransit socket_handle, + int32_t result) { + DCHECK(result == PP_OK || + socket_handle == IPC::InvalidPlatformFileForTransit()); + + EnterPluginFromHostResource<ppapi::thunk::PPB_Broker_API> enter(resource); + if (enter.failed()) { + // As in Broker::ConnectComplete, we need to close the resource on error. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(socket_handle)); + } else { + static_cast<Broker*>(enter.object())->ConnectComplete(socket_handle, + result); + } +} + +// Callback on the host side. +// Transfers ownership of the handle to the plugin side. This function must +// either successfully call the callback or close the handle. +void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result, + const HostResource& broker) { + IPC::PlatformFileForTransit foreign_socket_handle = + IPC::InvalidPlatformFileForTransit(); + if (result == PP_OK) { + int32_t socket_handle = PlatformFileToInt(base::kInvalidPlatformFileValue); + result = ppb_broker_target()->GetHandle(broker.host_resource(), + &socket_handle); + DCHECK(result == PP_OK || + socket_handle == PlatformFileToInt(base::kInvalidPlatformFileValue)); + + if (result == PP_OK) { + foreign_socket_handle = + dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle), + true); + if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) { + result = PP_ERROR_FAILED; + // Assume the local handle was closed even if the foreign handle could + // not be created. + } + } + } + DCHECK(result == PP_OK || + foreign_socket_handle == IPC::InvalidPlatformFileForTransit()); + + bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete( + INTERFACE_ID_PPB_BROKER, broker, foreign_socket_handle, result)); + + if (!success || result != PP_OK) { + // The plugin did not receive the handle, so it must be closed. + // The easiest way to clean it up is to just put it in an object + // and then close it. This failure case is not performance critical. + // The handle could still leak if Send succeeded but the IPC later failed. + base::SyncSocket temp_socket( + IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle)); + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_broker_proxy.h b/ppapi/proxy/ppb_broker_proxy.h new file mode 100644 index 0000000..efa9a98 --- /dev/null +++ b/ppapi/proxy/ppb_broker_proxy.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_BROKER_PROXY_H_ +#define PPAPI_PPB_BROKER_PROXY_H_ + +#include "base/sync_socket.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + + +struct PPB_BrokerTrusted; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_Broker_Proxy : public InterfaceProxy { + public: + PPB_Broker_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Broker_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + const PPB_BrokerTrusted* ppb_broker_target() const { + return static_cast<const PPB_BrokerTrusted*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, HostResource* result_resource); + void OnMsgConnect(const HostResource& broker); + void OnMsgConnectComplete(const HostResource& broker, + IPC::PlatformFileForTransit foreign_socket_handle, + int32_t result); + + void ConnectCompleteInHost(int32_t result, const HostResource& host_resource); + + CompletionCallbackFactory<PPB_Broker_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_BROKER_PROXY_H_ diff --git a/ppapi/proxy/ppb_buffer_proxy.cc b/ppapi/proxy/ppb_buffer_proxy.cc new file mode 100644 index 0000000..2e2ee90 --- /dev/null +++ b/ppapi/proxy/ppb_buffer_proxy.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_buffer_proxy.h" + +#include <vector> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_buffer_api.h" +#include "ppapi/thunk/ppb_buffer_trusted_api.h" +#include "ppapi/thunk/thunk.h" + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateBufferProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Buffer_Proxy(dispatcher, target_interface); +} + +} // namespace + +class Buffer : public ppapi::thunk::PPB_Buffer_API, + public PluginResource { + public: + Buffer(const HostResource& resource, + const base::SharedMemoryHandle& shm_handle, + uint32_t size); + virtual ~Buffer(); + + // Resource overrides. + virtual Buffer* AsBuffer() OVERRIDE; + + // ResourceObjectBase overrides. + virtual ppapi::thunk::PPB_Buffer_API* AsPPB_Buffer_API() OVERRIDE; + + // PPB_Buffer_API implementation. + virtual PP_Bool Describe(uint32_t* size_in_bytes) OVERRIDE; + virtual PP_Bool IsMapped() OVERRIDE; + virtual void* Map() OVERRIDE; + virtual void Unmap() OVERRIDE; + + private: + base::SharedMemory shm_; + uint32_t size_; + void* mapped_data_; + int map_count_; + + DISALLOW_COPY_AND_ASSIGN(Buffer); +}; + +Buffer::Buffer(const HostResource& resource, + const base::SharedMemoryHandle& shm_handle, + uint32_t size) + : PluginResource(resource), + shm_(shm_handle, false), + size_(size), + mapped_data_(NULL), + map_count_(0) { +} + +Buffer::~Buffer() { + Unmap(); +} + +Buffer* Buffer::AsBuffer() { + return this; +} + +ppapi::thunk::PPB_Buffer_API* Buffer::AsPPB_Buffer_API() { + return this; +} + +PP_Bool Buffer::Describe(uint32_t* size_in_bytes) { + *size_in_bytes = size_; + return PP_TRUE; +} + +PP_Bool Buffer::IsMapped() { + return PP_FromBool(!!mapped_data_); +} + +void* Buffer::Map() { + if (map_count_++ == 0) + shm_.Map(size_); + return shm_.memory(); +} + +void Buffer::Unmap() { + if (--map_count_ == 0) + shm_.Unmap(); +} + +PPB_Buffer_Proxy::PPB_Buffer_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Buffer_Proxy::~PPB_Buffer_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Buffer_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_Buffer_Thunk(), + PPB_BUFFER_DEV_INTERFACE, + INTERFACE_ID_PPB_BUFFER, + false, + &CreateBufferProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Buffer_Proxy::CreateProxyResource(PP_Instance instance, + uint32_t size) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + base::SharedMemoryHandle shm_handle = base::SharedMemory::NULLHandle(); + dispatcher->Send(new PpapiHostMsg_PPBBuffer_Create( + INTERFACE_ID_PPB_BUFFER, instance, size, + &result, &shm_handle)); + if (result.is_null() || !base::SharedMemory::IsHandleValid(shm_handle)) + return 0; + + linked_ptr<Buffer> object(new Buffer(result, shm_handle, size)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_Buffer_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Buffer_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBuffer_Create, OnMsgCreate) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Buffer_Proxy::OnMsgCreate( + PP_Instance instance, + uint32_t size, + HostResource* result_resource, + base::SharedMemoryHandle* result_shm_handle) { + // Overwritten below on success. + *result_shm_handle = base::SharedMemory::NULLHandle(); + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + PP_Resource local_buffer_resource = + ppb_buffer_target()->Create(instance, size); + if (local_buffer_resource == 0) + return; + ::ppapi::thunk::EnterResourceNoLock< ::ppapi::thunk::PPB_BufferTrusted_API> + trusted_buffer(local_buffer_resource, false); + if (trusted_buffer.failed()) + return; + int local_fd; + if (trusted_buffer.object()->GetSharedMemory(&local_fd) != PP_OK) + return; + + result_resource->SetHostResource(instance, local_buffer_resource); + + // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle, + // those casts are ugly. + base::PlatformFile platform_file = +#if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd)); +#elif defined(OS_POSIX) + local_fd; +#else + #error Not implemented. +#endif + *result_shm_handle = dispatcher->ShareHandleWithRemote(platform_file, false); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_buffer_proxy.h b/ppapi/proxy/ppb_buffer_proxy.h new file mode 100644 index 0000000..6002950 --- /dev/null +++ b/ppapi/proxy/ppb_buffer_proxy.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_BUFFER_PROXY_H_ +#define PPAPI_PPB_BUFFER_PROXY_H_ + +#include "base/shared_memory.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Buffer_Dev; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_Buffer_Proxy : public InterfaceProxy { + public: + PPB_Buffer_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Buffer_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + uint32_t size); + + const PPB_Buffer_Dev* ppb_buffer_target() const { + return static_cast<const PPB_Buffer_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, + uint32_t size, + HostResource* result_resource, + base::SharedMemoryHandle* result_shm_handle); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_BUFFER_PROXY_H_ diff --git a/ppapi/proxy/ppb_char_set_proxy.cc b/ppapi/proxy/ppb_char_set_proxy.cc new file mode 100644 index 0000000..4701ded --- /dev/null +++ b/ppapi/proxy/ppb_char_set_proxy.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_char_set_proxy.h" + +#include "base/basictypes.h" +#include "ppapi/c/dev/ppb_char_set_dev.h" +#include "ppapi/c/dev/ppb_memory_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/char_set_impl.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/thunk.h" + +namespace pp { +namespace proxy { + +namespace { + +const PPB_Memory_Dev* GetMemoryDevInterface() { + return static_cast<const PPB_Memory_Dev*>( + PluginDispatcher::GetInterfaceFromDispatcher(PPB_MEMORY_DEV_INTERFACE)); +} + +InterfaceProxy* CreateCharSetProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_CharSet_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_CharSet_Proxy::PPB_CharSet_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_CharSet_Proxy::~PPB_CharSet_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_CharSet_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_CharSet_Thunk(), + PPB_CHAR_SET_DEV_INTERFACE, + INTERFACE_ID_PPB_CHAR_SET, + false, + &CreateCharSetProxy, + }; + return &info; +} + +ppapi::thunk::PPB_CharSet_FunctionAPI* +PPB_CharSet_Proxy::AsPPB_CharSet_FunctionAPI() { + return this; +} + +char* PPB_CharSet_Proxy::UTF16ToCharSet( + PP_Instance instance, + const uint16_t* utf16, uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { + return ppapi::CharSetImpl::UTF16ToCharSet( + GetMemoryDevInterface(), utf16, utf16_len, output_char_set, on_error, + output_length); +} + +uint16_t* PPB_CharSet_Proxy::CharSetToUTF16( + PP_Instance instance, + const char* input, uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) { + return ppapi::CharSetImpl::CharSetToUTF16( + GetMemoryDevInterface(), input, input_len, input_char_set, on_error, + output_length); +} + +PP_Var PPB_CharSet_Proxy::GetDefaultCharSet(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBCharSet_GetDefaultCharSet( + INTERFACE_ID_PPB_CHAR_SET, instance, &result)); + return result.Return(dispatcher); +} + +bool PPB_CharSet_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_CharSet_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCharSet_GetDefaultCharSet, + OnMsgGetDefaultCharSet) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_CharSet_Proxy::OnMsgGetDefaultCharSet( + PP_Instance instance, + SerializedVarReturnValue result) { + ppapi::thunk::EnterFunctionNoLock<ppapi::thunk::PPB_CharSet_FunctionAPI> + enter(instance, true); + if (enter.succeeded()) + result.Return(dispatcher(), enter.functions()->GetDefaultCharSet(instance)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_char_set_proxy.h b/ppapi/proxy/ppb_char_set_proxy.h new file mode 100644 index 0000000..0f70ab5 --- /dev/null +++ b/ppapi/proxy/ppb_char_set_proxy.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_PPB_CHAR_SET_PROXY_H_ +#define PPAPI_PROXY_PPB_CHAR_SET_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/thunk/ppb_char_set_api.h" + +struct PPB_CharSet_Dev; +struct PPB_Core; + +namespace pp { +namespace proxy { + +class SerializedVarReturnValue; + +class PPB_CharSet_Proxy : public ppapi::FunctionGroupBase, + public ppapi::thunk::PPB_CharSet_FunctionAPI, + public InterfaceProxy { + public: + PPB_CharSet_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_CharSet_Proxy(); + + static const Info* GetInfo(); + + // FunctionGroupBase overrides. + virtual ppapi::thunk::PPB_CharSet_FunctionAPI* AsPPB_CharSet_FunctionAPI() + OVERRIDE; + + // PPB_CharSet_FunctionAPI implementation. + virtual char* UTF16ToCharSet(PP_Instance instance, + const uint16_t* utf16, uint32_t utf16_len, + const char* output_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) OVERRIDE; + virtual uint16_t* CharSetToUTF16(PP_Instance instance, + const char* input, uint32_t input_len, + const char* input_char_set, + PP_CharSet_ConversionError on_error, + uint32_t* output_length) OVERRIDE; + virtual PP_Var GetDefaultCharSet(PP_Instance instance) OVERRIDE; + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + void OnMsgGetDefaultCharSet(PP_Instance instance, + SerializedVarReturnValue result); + + DISALLOW_COPY_AND_ASSIGN(PPB_CharSet_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_CHAR_SET_PROXY_H_ diff --git a/ppapi/proxy/ppb_console_proxy.cc b/ppapi/proxy/ppb_console_proxy.cc new file mode 100644 index 0000000..a04aacc --- /dev/null +++ b/ppapi/proxy/ppb_console_proxy.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_console_proxy.h" + +#include "ppapi/c/dev/ppb_console_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +void Log(PP_Instance instance, PP_LogLevel_Dev level, PP_Var value) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + dispatcher->Send(new PpapiHostMsg_PPBConsole_Log( + INTERFACE_ID_PPB_CONSOLE, instance, static_cast<int>(level), + SerializedVarSendInput(dispatcher, value))); +} + +void LogWithSource(PP_Instance instance, + PP_LogLevel_Dev level, + const PP_Var source, + const PP_Var value) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + dispatcher->Send(new PpapiHostMsg_PPBConsole_LogWithSource( + INTERFACE_ID_PPB_CONSOLE, instance, static_cast<int>(level), + SerializedVarSendInput(dispatcher, source), + SerializedVarSendInput(dispatcher, value))); +} + +const PPB_Console_Dev console_interface = { + &Log, + &LogWithSource +}; + +InterfaceProxy* CreateConsoleProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Console_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Console_Proxy::PPB_Console_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Console_Proxy::~PPB_Console_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Console_Proxy::GetInfo() { + static const Info info = { + &console_interface, + PPB_CONSOLE_DEV_INTERFACE, + INTERFACE_ID_PPB_CONSOLE, + false, + &CreateConsoleProxy, + }; + return &info; +} + +bool PPB_Console_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Console_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBConsole_Log, + OnMsgLog) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBConsole_LogWithSource, + OnMsgLogWithSource) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Console_Proxy::OnMsgLog(PP_Instance instance, + int log_level, + SerializedVarReceiveInput value) { + ppb_console_target()->Log(instance, + static_cast<PP_LogLevel_Dev>(log_level), + value.Get(dispatcher())); +} + +void PPB_Console_Proxy::OnMsgLogWithSource(PP_Instance instance, + int log_level, + SerializedVarReceiveInput source, + SerializedVarReceiveInput value) { + ppb_console_target()->LogWithSource( + instance, + static_cast<PP_LogLevel_Dev>(log_level), + source.Get(dispatcher()), + value.Get(dispatcher())); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/ppb_console_proxy.h b/ppapi/proxy/ppb_console_proxy.h new file mode 100644 index 0000000..af1c9e0 --- /dev/null +++ b/ppapi/proxy/ppb_console_proxy.h @@ -0,0 +1,48 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_CONSOLE_PROXY_H_ +#define PPAPI_PROXY_PPB_CONSOLE_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/serialized_var.h" + +struct PPB_Console_Dev; + +namespace pp { +namespace proxy { + +class PPB_Console_Proxy : public InterfaceProxy { + public: + PPB_Console_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Console_Proxy(); + + static const Info* GetInfo(); + + const PPB_Console_Dev* ppb_console_target() const { + return static_cast<const PPB_Console_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgLog(PP_Instance instance, + int log_level, + SerializedVarReceiveInput value); + void OnMsgLogWithSource(PP_Instance instance, + int log_level, + SerializedVarReceiveInput source, + SerializedVarReceiveInput value); + + DISALLOW_COPY_AND_ASSIGN(PPB_Console_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_CONSOLE_PROXY_H_ diff --git a/ppapi/proxy/ppb_context_3d_proxy.cc b/ppapi/proxy/ppb_context_3d_proxy.cc new file mode 100644 index 0000000..ff2fe93 --- /dev/null +++ b/ppapi/proxy/ppb_context_3d_proxy.cc @@ -0,0 +1,719 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_context_3d_proxy.h" + +#include "base/hash_tables.h" +#include "gpu/command_buffer/client/gles2_cmd_helper.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_context_3d_dev.h" +#include "ppapi/c/dev/ppb_context_3d_trusted_dev.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_surface_3d_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Context3D_API; +using ppapi::thunk::PPB_Surface3D_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +base::SharedMemoryHandle TransportSHMHandleFromInt(Dispatcher* dispatcher, + int shm_handle) { + // TODO(piman): Change trusted interface to return a PP_FileHandle, those + // casts are ugly. + base::PlatformFile source = +#if defined(OS_WIN) + reinterpret_cast<HANDLE>(static_cast<intptr_t>(shm_handle)); +#elif defined(OS_POSIX) + shm_handle; +#else + #error Not implemented. +#endif + // Don't close the handle, it doesn't belong to us. + return dispatcher->ShareHandleWithRemote(source, false); +} + +PP_Context3DTrustedState GetErrorState() { + PP_Context3DTrustedState error_state = { 0 }; + error_state.error = kGenericError; + return error_state; +} + +gpu::CommandBuffer::State GPUStateFromPPState( + const PP_Context3DTrustedState& s) { + gpu::CommandBuffer::State state; + state.num_entries = s.num_entries; + state.get_offset = s.get_offset; + state.put_offset = s.put_offset; + state.token = s.token; + state.error = static_cast<gpu::error::Error>(s.error); + state.generation = s.generation; + return state; +} + +// Size of the transfer buffer. +const int32 kCommandBufferSize = 1024 * 1024; +const int32 kTransferBufferSize = 1024 * 1024; + +InterfaceProxy* CreateContext3DProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Context3D_Proxy(dispatcher, target_interface); +} + +} // namespace + +class PepperCommandBuffer : public gpu::CommandBuffer { + public: + PepperCommandBuffer(const HostResource& resource, + PluginDispatcher* dispatcher); + virtual ~PepperCommandBuffer(); + + // CommandBuffer implementation: + virtual bool Initialize(int32 size); + virtual bool Initialize(base::SharedMemory* buffer, int32 size); + virtual gpu::Buffer GetRingBuffer(); + virtual State GetState(); + virtual void Flush(int32 put_offset); + virtual State FlushSync(int32 put_offset, int32 last_known_get); + virtual void SetGetOffset(int32 get_offset); + virtual int32 CreateTransferBuffer(size_t size, int32 id_request); + virtual int32 RegisterTransferBuffer(base::SharedMemory* shared_memory, + size_t size, + int32 id_request); + virtual void DestroyTransferBuffer(int32 id); + virtual gpu::Buffer GetTransferBuffer(int32 handle); + virtual void SetToken(int32 token); + virtual void SetParseError(gpu::error::Error error); + virtual void SetContextLostReason(gpu::error::ContextLostReason reason); + + private: + bool Send(IPC::Message* msg); + void UpdateState(const gpu::CommandBuffer::State& state); + + int32 num_entries_; + scoped_ptr<base::SharedMemory> ring_buffer_; + + typedef base::hash_map<int32, gpu::Buffer> TransferBufferMap; + TransferBufferMap transfer_buffers_; + + State last_state_; + + HostResource resource_; + PluginDispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(PepperCommandBuffer); +}; + +PepperCommandBuffer::PepperCommandBuffer( + const HostResource& resource, + PluginDispatcher* dispatcher) + : num_entries_(0), + resource_(resource), + dispatcher_(dispatcher) { +} + +PepperCommandBuffer::~PepperCommandBuffer() { + // Delete all the locally cached shared memory objects, closing the handle + // in this process. + for (TransferBufferMap::iterator it = transfer_buffers_.begin(); + it != transfer_buffers_.end(); + ++it) { + delete it->second.shared_memory; + it->second.shared_memory = NULL; + } +} + +bool PepperCommandBuffer::Initialize(int32 size) { + DCHECK(!ring_buffer_.get()); + + // Initialize the service. Assuming we are sandboxed, the GPU + // process is responsible for duplicating the handle. This might not be true + // for NaCl. + base::SharedMemoryHandle handle; + if (Send(new PpapiHostMsg_PPBContext3D_Initialize( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &handle)) && + base::SharedMemory::IsHandleValid(handle)) { + ring_buffer_.reset(new base::SharedMemory(handle, false)); + if (ring_buffer_->Map(size)) { + num_entries_ = size / sizeof(gpu::CommandBufferEntry); + return true; + } + + ring_buffer_.reset(); + } + + return false; +} + +bool PepperCommandBuffer::Initialize(base::SharedMemory* buffer, int32 size) { + // Not implemented in proxy. + NOTREACHED(); + return false; +} + +gpu::Buffer PepperCommandBuffer::GetRingBuffer() { + // Return locally cached ring buffer. + gpu::Buffer buffer; + buffer.ptr = ring_buffer_->memory(); + buffer.size = num_entries_ * sizeof(gpu::CommandBufferEntry); + buffer.shared_memory = ring_buffer_.get(); + return buffer; +} + +gpu::CommandBuffer::State PepperCommandBuffer::GetState() { + // Send will flag state with lost context if IPC fails. + if (last_state_.error == gpu::error::kNoError) { + gpu::CommandBuffer::State state; + if (Send(new PpapiHostMsg_PPBContext3D_GetState( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, &state))) + UpdateState(state); + } + + return last_state_; +} + +void PepperCommandBuffer::Flush(int32 put_offset) { + if (last_state_.error != gpu::error::kNoError) + return; + + IPC::Message* message = new PpapiHostMsg_PPBContext3D_AsyncFlush( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset); + + // Do not let a synchronous flush hold up this message. If this handler is + // deferred until after the synchronous flush completes, it will overwrite the + // cached last_state_ with out-of-date data. + message->set_unblock(true); + Send(message); +} + +gpu::CommandBuffer::State PepperCommandBuffer::FlushSync( + int32 put_offset, int32 last_known_get) { + if (last_known_get == last_state_.get_offset) { + // Send will flag state with lost context if IPC fails. + if (last_state_.error == gpu::error::kNoError) { + gpu::CommandBuffer::State state; + if (Send(new PpapiHostMsg_PPBContext3D_Flush( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, put_offset, + last_known_get, &state))) + UpdateState(state); + } + } else { + Flush(put_offset); + } + + return last_state_; +} + +void PepperCommandBuffer::SetGetOffset(int32 get_offset) { + // Not implemented in proxy. + NOTREACHED(); +} + +int32 PepperCommandBuffer::CreateTransferBuffer(size_t size, int32 id_request) { + if (last_state_.error == gpu::error::kNoError) { + int32 id; + if (Send(new PpapiHostMsg_PPBContext3D_CreateTransferBuffer( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, size, &id))) { + return id; + } + } + + return -1; +} + +int32 PepperCommandBuffer::RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size, + int32 id_request) { + // Not implemented in proxy. + NOTREACHED(); + return -1; +} + +void PepperCommandBuffer::DestroyTransferBuffer(int32 id) { + if (last_state_.error != gpu::error::kNoError) + return; + + // Remove the transfer buffer from the client side4 cache. + TransferBufferMap::iterator it = transfer_buffers_.find(id); + DCHECK(it != transfer_buffers_.end()); + + // Delete the shared memory object, closing the handle in this process. + delete it->second.shared_memory; + + transfer_buffers_.erase(it); + + Send(new PpapiHostMsg_PPBContext3D_DestroyTransferBuffer( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, id)); +} + +gpu::Buffer PepperCommandBuffer::GetTransferBuffer(int32 id) { + if (last_state_.error != gpu::error::kNoError) + return gpu::Buffer(); + + // Check local cache to see if there is already a client side shared memory + // object for this id. + TransferBufferMap::iterator it = transfer_buffers_.find(id); + if (it != transfer_buffers_.end()) { + return it->second; + } + + // Assuming we are in the renderer process, the service is responsible for + // duplicating the handle. This might not be true for NaCl. + base::SharedMemoryHandle handle; + uint32 size; + if (!Send(new PpapiHostMsg_PPBContext3D_GetTransferBuffer( + INTERFACE_ID_PPB_CONTEXT_3D, resource_, id, &handle, &size))) { + return gpu::Buffer(); + } + + // Cache the transfer buffer shared memory object client side. + scoped_ptr<base::SharedMemory> shared_memory( + new base::SharedMemory(handle, false)); + + // Map the shared memory on demand. + if (!shared_memory->memory()) { + if (!shared_memory->Map(size)) { + return gpu::Buffer(); + } + } + + gpu::Buffer buffer; + buffer.ptr = shared_memory->memory(); + buffer.size = size; + buffer.shared_memory = shared_memory.release(); + transfer_buffers_[id] = buffer; + + return buffer; +} + +void PepperCommandBuffer::SetToken(int32 token) { + NOTREACHED(); +} + +void PepperCommandBuffer::SetParseError(gpu::error::Error error) { + NOTREACHED(); +} + +void PepperCommandBuffer::SetContextLostReason( + gpu::error::ContextLostReason reason) { + NOTREACHED(); +} + +bool PepperCommandBuffer::Send(IPC::Message* msg) { + DCHECK(last_state_.error == gpu::error::kNoError); + + if (dispatcher_->Send(msg)) + return true; + + last_state_.error = gpu::error::kLostContext; + return false; +} + +void PepperCommandBuffer::UpdateState(const gpu::CommandBuffer::State& state) { + // Handle wraparound. It works as long as we don't have more than 2B state + // updates in flight across which reordering occurs. + if (state.generation - last_state_.generation < 0x80000000U) + last_state_ = state; +} + +// Context3D ------------------------------------------------------------------- + +Context3D::Context3D(const HostResource& resource) + : PluginResource(resource), + draw_(NULL), + read_(NULL), + transfer_buffer_id_(0) { +} + +Context3D::~Context3D() { + if (draw_) + draw_->set_context(NULL); +} + +PPB_Context3D_API* Context3D::AsPPB_Context3D_API() { + return this; +} + +bool Context3D::CreateImplementation() { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance()); + if (!dispatcher) + return false; + + command_buffer_.reset(new PepperCommandBuffer(host_resource(), dispatcher)); + + if (!command_buffer_->Initialize(kCommandBufferSize)) + return false; + + helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer_.get())); + if (!helper_->Initialize(kCommandBufferSize)) + return false; + + transfer_buffer_id_ = + command_buffer_->CreateTransferBuffer(kTransferBufferSize, -1); + if (transfer_buffer_id_ < 0) + return false; + + gpu::Buffer transfer_buffer = + command_buffer_->GetTransferBuffer(transfer_buffer_id_); + if (!transfer_buffer.ptr) + return false; + + gles2_impl_.reset(new gpu::gles2::GLES2Implementation( + helper_.get(), + transfer_buffer.size, + transfer_buffer.ptr, + transfer_buffer_id_, + false)); + + return true; +} + +int32_t Context3D::GetAttrib(int32_t attribute, int32_t* value) { + // TODO(alokp): Implement me. + return 0; +} + +int32_t Context3D::BindSurfaces(PP_Resource pp_draw, PP_Resource pp_read) { + // TODO(alokp): Support separate draw-read surfaces. + DCHECK_EQ(pp_draw, pp_read); + if (pp_draw != pp_read) + return PP_GRAPHICS3DERROR_BAD_MATCH; + + EnterResourceNoLock<PPB_Surface3D_API> enter_draw(pp_draw, false); + EnterResourceNoLock<PPB_Surface3D_API> enter_read(pp_read, false); + Surface3D* draw_surface = enter_draw.succeeded() ? + static_cast<Surface3D*>(enter_draw.object()) : NULL; + Surface3D* read_surface = enter_read.succeeded() ? + static_cast<Surface3D*>(enter_read.object()) : NULL; + + if (pp_draw && !draw_surface) + return PP_ERROR_BADRESOURCE; + if (pp_read && !read_surface) + return PP_ERROR_BADRESOURCE; + HostResource host_draw = + draw_surface ? draw_surface->host_resource() : HostResource(); + HostResource host_read = + read_surface ? read_surface->host_resource() : HostResource(); + + int32_t result; + GetDispatcher()->Send(new PpapiHostMsg_PPBContext3D_BindSurfaces( + INTERFACE_ID_PPB_CONTEXT_3D, + host_resource(), host_draw, host_read, &result)); + if (result != PP_OK) + return result; + + if (draw_surface != draw_) { + if (draw_) + draw_->set_context(NULL); + if (draw_surface) { + draw_surface->set_context(this); + // Resize the backing texture to the size of the instance when it is + // bound. + // TODO(alokp): This should be the responsibility of plugins. + InstanceData* data = GetDispatcher()->GetInstanceData(instance()); + gles2_impl()->ResizeCHROMIUM(data->position.size.width, + data->position.size.height); + } + draw_ = draw_surface; + } + read_ = read_surface; + return PP_OK; +} + +int32_t Context3D::GetBoundSurfaces(PP_Resource* draw, PP_Resource* read) { + *draw = draw_ ? draw_->resource() : 0; + *read = read_ ? read_->resource() : 0; + return PP_OK; +} + +PP_Bool Context3D::InitializeTrusted(int32_t size) { + // Trusted interface not implemented in the proxy. + return PP_FALSE; +} + +PP_Bool Context3D::GetRingBuffer(int* shm_handle, + uint32_t* shm_size) { + // Trusted interface not implemented in the proxy. + return PP_FALSE; +} + +PP_Context3DTrustedState Context3D::GetState() { + // Trusted interface not implemented in the proxy. + return GetErrorState(); +} + +PP_Bool Context3D::Flush(int32_t put_offset) { + // Trusted interface not implemented in the proxy. + return PP_FALSE; +} + +PP_Context3DTrustedState Context3D::FlushSync(int32_t put_offset) { + // Trusted interface not implemented in the proxy. + return GetErrorState(); +} + +int32_t Context3D::CreateTransferBuffer(uint32_t size) { + // Trusted interface not implemented in the proxy. + return 0; +} + +PP_Bool Context3D::DestroyTransferBuffer(int32_t id) { + // Trusted interface not implemented in the proxy. + return PP_FALSE; +} + +PP_Bool Context3D::GetTransferBuffer(int32_t id, + int* shm_handle, + uint32_t* shm_size) { + // Trusted interface not implemented in the proxy. + return PP_FALSE; +} + +PP_Context3DTrustedState Context3D::FlushSyncFast(int32_t put_offset, + int32_t last_known_get) { + // Trusted interface not implemented in the proxy. + return GetErrorState(); +} + +void* Context3D::MapTexSubImage2DCHROMIUM(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLenum access) { + return gles2_impl_->MapTexSubImage2DCHROMIUM( + target, level, xoffset, yoffset, width, height, format, type, access); +} + +void Context3D::UnmapTexSubImage2DCHROMIUM(const void* mem) { + gles2_impl_->UnmapTexSubImage2DCHROMIUM(mem); +} + +// PPB_Context3D_Proxy --------------------------------------------------------- + +PPB_Context3D_Proxy::PPB_Context3D_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Context3D_Proxy::~PPB_Context3D_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Context3D_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_Context3D_Thunk(), + PPB_CONTEXT_3D_DEV_INTERFACE, + INTERFACE_ID_PPB_CONTEXT_3D, + false, + &CreateContext3DProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_Context3D_Proxy::GetTextureMappingInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_GLESChromiumTextureMapping_Thunk(), + PPB_GLES_CHROMIUM_TEXTURE_MAPPING_DEV_INTERFACE, + INTERFACE_ID_NONE, // CONTEXT_3D is the canonical one. + false, + &CreateContext3DProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Context3D_Proxy::Create(PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + // TODO(alokp): Support shared context. + DCHECK_EQ(0, share_context); + if (share_context != 0) + return 0; + + std::vector<int32_t> attribs; + if (attrib_list) { + for (const int32_t* attr = attrib_list; attr; ++attr) + attribs.push_back(*attr); + } else { + attribs.push_back(0); + } + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBContext3D_Create( + INTERFACE_ID_PPB_CONTEXT_3D, instance, config, attribs, &result)); + + if (result.is_null()) + return 0; + linked_ptr<Context3D> context_3d(new Context3D(result)); + if (!context_3d->CreateImplementation()) + return 0; + return PluginResourceTracker::GetInstance()->AddResource(context_3d); +} + +bool PPB_Context3D_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Context3D_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_BindSurfaces, + OnMsgBindSurfaces) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Initialize, + OnMsgInitialize) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetState, + OnMsgGetState) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_Flush, + OnMsgFlush) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_AsyncFlush, + OnMsgAsyncFlush) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_CreateTransferBuffer, + OnMsgCreateTransferBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_DestroyTransferBuffer, + OnMsgDestroyTransferBuffer) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBContext3D_GetTransferBuffer, + OnMsgGetTransferBuffer) + IPC_MESSAGE_UNHANDLED(handled = false) + + IPC_END_MESSAGE_MAP() + // FIXME(brettw) handle bad messages! + return handled; +} + +void PPB_Context3D_Proxy::OnMsgCreate(PP_Instance instance, + PP_Config3D_Dev config, + const std::vector<int32_t>& attribs, + HostResource* result) { + if (attribs.empty() || attribs.back() != 0) + return; // Bad message. + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource( + instance, + enter.functions()->CreateContext3DRaw(instance, config, 0, + &attribs.front())); + } +} + +void PPB_Context3D_Proxy::OnMsgBindSurfaces(const HostResource& context, + const HostResource& draw, + const HostResource& read, + int32_t* result) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.succeeded()) { + *result = enter.object()->BindSurfaces(draw.host_resource(), + read.host_resource()); + } else { + *result = PP_ERROR_BADRESOURCE; + } +} + +void PPB_Context3D_Proxy::OnMsgInitialize( + const HostResource& context, + int32 size, + base::SharedMemoryHandle* ring_buffer) { + *ring_buffer = base::SharedMemory::NULLHandle(); + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.failed()) + return; + + if (!enter.object()->InitializeTrusted(size)) + return; + + int shm_handle; + uint32_t shm_size; + if (!enter.object()->GetRingBuffer(&shm_handle, &shm_size)) + return; + *ring_buffer = TransportSHMHandleFromInt(dispatcher(), shm_handle); +} + +void PPB_Context3D_Proxy::OnMsgGetState(const HostResource& context, + gpu::CommandBuffer::State* state) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.failed()) + return; + PP_Context3DTrustedState pp_state = enter.object()->GetState(); + *state = GPUStateFromPPState(pp_state); +} + +void PPB_Context3D_Proxy::OnMsgFlush(const HostResource& context, + int32 put_offset, + int32 last_known_get, + gpu::CommandBuffer::State* state) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.failed()) + return; + PP_Context3DTrustedState pp_state = enter.object()->FlushSyncFast( + put_offset, last_known_get); + *state = GPUStateFromPPState(pp_state); +} + +void PPB_Context3D_Proxy::OnMsgAsyncFlush(const HostResource& context, + int32 put_offset) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.succeeded()) + enter.object()->Flush(put_offset); +} + +void PPB_Context3D_Proxy::OnMsgCreateTransferBuffer( + const HostResource& context, + int32 size, + int32* id) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.succeeded()) + *id = enter.object()->CreateTransferBuffer(size); + else + *id = 0; +} + +void PPB_Context3D_Proxy::OnMsgDestroyTransferBuffer( + const HostResource& context, + int32 id) { + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + if (enter.succeeded()) + enter.object()->DestroyTransferBuffer(id); +} + +void PPB_Context3D_Proxy::OnMsgGetTransferBuffer( + const HostResource& context, + int32 id, + base::SharedMemoryHandle* transfer_buffer, + uint32* size) { + *transfer_buffer = base::SharedMemory::NULLHandle(); + *size = 0; + + EnterHostFromHostResource<PPB_Context3D_API> enter(context); + int shm_handle = 0; + uint32_t shm_size = 0; + if (enter.succeeded() && + enter.object()->GetTransferBuffer(id, &shm_handle, &shm_size)) { + *transfer_buffer = TransportSHMHandleFromInt(dispatcher(), shm_handle); + *size = shm_size; + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_context_3d_proxy.h b/ppapi/proxy/ppb_context_3d_proxy.h new file mode 100644 index 0000000..991b7a2 --- /dev/null +++ b/ppapi/proxy/ppb_context_3d_proxy.h @@ -0,0 +1,144 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_CONTEXT_3D_PROXY_H_ +#define PPAPI_PROXY_PPB_CONTEXT_3D_PROXY_H_ + +#include <vector> + +#include "base/shared_memory.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "ppapi/c/dev/pp_graphics_3d_dev.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" +#include "ppapi/thunk/ppb_context_3d_api.h" + +struct PPB_Context3D_Dev; +struct PPB_Context3DTrusted_Dev; + +namespace gpu { +class CommandBuffer; + +namespace gles2 { +class GLES2CmdHelper; +class GLES2Implementation; +} // namespace gles2 + +} // namespace gpu + +namespace pp { +namespace proxy { + +class Surface3D; + +class Context3D : public PluginResource, + public ppapi::thunk::PPB_Context3D_API { + public: + explicit Context3D(const HostResource& resource); + virtual ~Context3D(); + + // ResourceObjectBase overrides. + virtual ::ppapi::thunk::PPB_Context3D_API* AsPPB_Context3D_API() OVERRIDE; + + gpu::gles2::GLES2Implementation* gles2_impl() const { + return gles2_impl_.get(); + } + + // PPB_Context3D_API implementation. + virtual int32_t GetAttrib(int32_t attribute, int32_t* value) OVERRIDE; + virtual int32_t BindSurfaces(PP_Resource draw, PP_Resource read) OVERRIDE; + virtual int32_t GetBoundSurfaces(PP_Resource* draw, + PP_Resource* read) OVERRIDE; + virtual PP_Bool InitializeTrusted(int32_t size) OVERRIDE; + virtual PP_Bool GetRingBuffer(int* shm_handle, + uint32_t* shm_size) OVERRIDE; + virtual PP_Context3DTrustedState GetState() OVERRIDE; + virtual PP_Bool Flush(int32_t put_offset) OVERRIDE; + virtual PP_Context3DTrustedState FlushSync(int32_t put_offset) OVERRIDE; + virtual int32_t CreateTransferBuffer(uint32_t size) OVERRIDE; + virtual PP_Bool DestroyTransferBuffer(int32_t id) OVERRIDE; + virtual PP_Bool GetTransferBuffer(int32_t id, + int* shm_handle, + uint32_t* shm_size) OVERRIDE; + virtual PP_Context3DTrustedState FlushSyncFast( + int32_t put_offset, + int32_t last_known_get) OVERRIDE; + virtual void* MapTexSubImage2DCHROMIUM(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLenum access) OVERRIDE; + virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) OVERRIDE; + + bool CreateImplementation(); + + private: + Surface3D* draw_; + Surface3D* read_; + + scoped_ptr<gpu::CommandBuffer> command_buffer_; + scoped_ptr<gpu::gles2::GLES2CmdHelper> helper_; + int32 transfer_buffer_id_; + scoped_ptr<gpu::gles2::GLES2Implementation> gles2_impl_; + + DISALLOW_COPY_AND_ASSIGN(Context3D); +}; + +class PPB_Context3D_Proxy : public InterfaceProxy { + public: + PPB_Context3D_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Context3D_Proxy(); + + static const Info* GetInfo(); + static const Info* GetTextureMappingInfo(); + + static PP_Resource Create(PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + void OnMsgCreate(PP_Instance instance, + PP_Config3D_Dev config, + const std::vector<int32_t>& attribs, + HostResource* result); + void OnMsgBindSurfaces(const HostResource& context, + const HostResource& draw, + const HostResource& read, + int32_t* result); + void OnMsgInitialize(const HostResource& context, + int32 size, + base::SharedMemoryHandle* ring_buffer); + void OnMsgGetState(const HostResource& context, + gpu::CommandBuffer::State* state); + void OnMsgFlush(const HostResource& context, + int32 put_offset, + int32 last_known_get, + gpu::CommandBuffer::State* state); + void OnMsgAsyncFlush(const HostResource& context, + int32 put_offset); + void OnMsgCreateTransferBuffer(const HostResource& context, + int32 size, + int32* id); + void OnMsgDestroyTransferBuffer(const HostResource& context, + int32 id); + void OnMsgGetTransferBuffer(const HostResource& context, + int32 id, + base::SharedMemoryHandle* transfer_buffer, + uint32* size); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_CONTEXT_3D_PROXY_H_ diff --git a/ppapi/proxy/ppb_core_proxy.cc b/ppapi/proxy/ppb_core_proxy.cc new file mode 100644 index 0000000..06d5974 --- /dev/null +++ b/ppapi/proxy/ppb_core_proxy.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_core_proxy.h" + +#include <stdlib.h> // For malloc + +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/time.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/time_conversion.h" + +using ppapi::TimeToPPTime; +using ppapi::TimeTicksToPPTimeTicks; + +namespace pp { +namespace proxy { + +namespace { + +base::MessageLoopProxy* GetMainThreadMessageLoop() { + static scoped_refptr<base::MessageLoopProxy> proxy( + base::MessageLoopProxy::CreateForCurrentThread()); + return proxy.get(); +} + +void AddRefResource(PP_Resource resource) { + PluginResourceTracker::GetInstance()->AddRefResource(resource); +} + +void ReleaseResource(PP_Resource resource) { + PluginResourceTracker::GetInstance()->ReleaseResource(resource); +} + +void* MemAlloc(uint32_t num_bytes) { + return malloc(num_bytes); +} + +void MemFree(void* ptr) { + free(ptr); +} + +double GetTime() { + return TimeToPPTime(base::Time::Now()); +} + +double GetTimeTicks() { + return TimeTicksToPPTimeTicks(base::TimeTicks::Now()); +} + +void CallbackWrapper(PP_CompletionCallback callback, int32_t result) { + TRACE_EVENT2("ppapi proxy", "CallOnMainThread callback", + "Func", reinterpret_cast<void*>(callback.func), + "UserData", callback.user_data); + PP_RunCompletionCallback(&callback, result); +} + +void CallOnMainThread(int delay_in_ms, + PP_CompletionCallback callback, + int32_t result) { + GetMainThreadMessageLoop()->PostDelayedTask( + FROM_HERE, + NewRunnableFunction(&CallbackWrapper, callback, result), + delay_in_ms); +} + +PP_Bool IsMainThread() { + return PP_FromBool(GetMainThreadMessageLoop()->BelongsToCurrentThread()); +} + +const PPB_Core core_interface = { + &AddRefResource, + &ReleaseResource, + &GetTime, + &GetTimeTicks, + &CallOnMainThread, + &IsMainThread +}; + +InterfaceProxy* CreateCoreProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Core_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Core_Proxy::PPB_Core_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Core_Proxy::~PPB_Core_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Core_Proxy::GetInfo() { + static const Info info = { + &core_interface, + PPB_CORE_INTERFACE, + INTERFACE_ID_PPB_CORE, + false, + &CreateCoreProxy, + }; + return &info; +} + +bool PPB_Core_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Core_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCore_AddRefResource, + OnMsgAddRefResource) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCore_ReleaseResource, + OnMsgReleaseResource) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Core_Proxy::OnMsgAddRefResource(HostResource resource) { + ppb_core_target()->AddRefResource(resource.host_resource()); +} + +void PPB_Core_Proxy::OnMsgReleaseResource(HostResource resource) { + ppb_core_target()->ReleaseResource(resource.host_resource()); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_core_proxy.h b/ppapi/proxy/ppb_core_proxy.h new file mode 100644 index 0000000..6ad8b31 --- /dev/null +++ b/ppapi/proxy/ppb_core_proxy.h @@ -0,0 +1,42 @@ +// 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_PPB_CORE_PROXY_H_ +#define PPAPI_PPB_CORE_PROXY_H_ + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Core; + +namespace pp { +namespace proxy { + +class PPB_Core_Proxy : public InterfaceProxy { + public: + PPB_Core_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Core_Proxy(); + + static const Info* GetInfo(); + + const PPB_Core* ppb_core_target() const { + return reinterpret_cast<const PPB_Core*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgAddRefResource(HostResource resource); + void OnMsgReleaseResource(HostResource resource); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_CORE_PROXY_H_ diff --git a/ppapi/proxy/ppb_crypto_proxy.cc b/ppapi/proxy/ppb_crypto_proxy.cc new file mode 100644 index 0000000..d900800 --- /dev/null +++ b/ppapi/proxy/ppb_crypto_proxy.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_crypto_proxy.h" + +#include "ppapi/c/dev/ppb_crypto_dev.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/shared_impl/crypto_impl.h" + +namespace pp { +namespace proxy { + +namespace { + +const PPB_Crypto_Dev crypto_interface = { + &ppapi::CryptoImpl::GetRandomBytes +}; + +InterfaceProxy* CreateCryptoProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Crypto_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Crypto_Proxy::PPB_Crypto_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { + NOTREACHED(); // See comment in the header file. +} + +PPB_Crypto_Proxy::~PPB_Crypto_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Crypto_Proxy::GetInfo() { + static const Info info = { + &crypto_interface, + PPB_CRYPTO_DEV_INTERFACE, + INTERFACE_ID_PPB_CRYPTO, + false, + &CreateCryptoProxy, + }; + return &info; +} + +bool PPB_Crypto_Proxy::OnMessageReceived(const IPC::Message& msg) { + NOTREACHED(); + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_crypto_proxy.h b/ppapi/proxy/ppb_crypto_proxy.h new file mode 100644 index 0000000..e801892 --- /dev/null +++ b/ppapi/proxy/ppb_crypto_proxy.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_CRYPTO_PROXY_H_ +#define PPAPI_PROXY_PPB_CRYPTO_PROXY_H_ + +#include "ppapi/proxy/interface_proxy.h" + +namespace pp { +namespace proxy { + +class PPB_Crypto_Proxy : public InterfaceProxy { + public: + // This class should not normally be instantiated since there's only one + // function that's implemented entirely within the plugin. However, we need + // to support this so the machinery for automatically handling interfaces + // works. As a result, this constructor will assert if it's actually used. + PPB_Crypto_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Crypto_Proxy(); + + static const Info* GetInfo(); + + private: + virtual bool OnMessageReceived(const IPC::Message& msg); + + DISALLOW_COPY_AND_ASSIGN(PPB_Crypto_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_CRYPTO_PROXY_H_ diff --git a/ppapi/proxy/ppb_cursor_control_proxy.cc b/ppapi/proxy/ppb_cursor_control_proxy.cc new file mode 100644 index 0000000..993efe8 --- /dev/null +++ b/ppapi/proxy/ppb_cursor_control_proxy.cc @@ -0,0 +1,171 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_cursor_control_proxy.h" + +#include "ppapi/c/dev/pp_cursor_type_dev.h" +#include "ppapi/c/dev/ppb_cursor_control_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_CursorControl_FunctionAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateCursorControlProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_CursorControl_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_CursorControl_Proxy::PPB_CursorControl_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_CursorControl_Proxy::~PPB_CursorControl_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_CursorControl_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_CursorControl_Thunk(), + PPB_CURSOR_CONTROL_DEV_INTERFACE, + INTERFACE_ID_PPB_CURSORCONTROL, + false, + &CreateCursorControlProxy, + }; + return &info; +} + +ppapi::thunk::PPB_CursorControl_FunctionAPI* +PPB_CursorControl_Proxy::AsPPB_CursorControl_FunctionAPI() { + return this; +} + +PP_Bool PPB_CursorControl_Proxy::SetCursor(PP_Instance instance, + PP_CursorType_Dev type, + PP_Resource custom_image_id, + const PP_Point* hot_spot) { + // It's legal for the image ID to be null if the type is not custom. + HostResource cursor_image_resource; + if (type == PP_CURSORTYPE_CUSTOM) { + PluginResource* cursor_image = PluginResourceTracker::GetInstance()-> + GetResourceObject(custom_image_id); + if (!cursor_image || cursor_image->instance() != instance) + return PP_FALSE; + cursor_image_resource = cursor_image->host_resource(); + } else { + if (custom_image_id) + return PP_FALSE; // Image specified for a predefined type. + } + + PP_Bool result = PP_FALSE; + PP_Point empty_point = { 0, 0 }; + dispatcher()->Send(new PpapiHostMsg_PPBCursorControl_SetCursor( + INTERFACE_ID_PPB_CURSORCONTROL, + instance, static_cast<int32_t>(type), cursor_image_resource, + hot_spot ? *hot_spot : empty_point, &result)); + return result; +} + +PP_Bool PPB_CursorControl_Proxy::LockCursor(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBCursorControl_LockCursor( + INTERFACE_ID_PPB_CURSORCONTROL, instance, &result)); + return result; +} + +PP_Bool PPB_CursorControl_Proxy::UnlockCursor(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBCursorControl_UnlockCursor( + INTERFACE_ID_PPB_CURSORCONTROL, instance, &result)); + return result; +} + +PP_Bool PPB_CursorControl_Proxy::HasCursorLock(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBCursorControl_HasCursorLock( + INTERFACE_ID_PPB_CURSORCONTROL, instance, &result)); + return result; +} + +PP_Bool PPB_CursorControl_Proxy::CanLockCursor(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBCursorControl_CanLockCursor( + INTERFACE_ID_PPB_CURSORCONTROL, instance, &result)); + return result; +} + +bool PPB_CursorControl_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_CursorControl_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCursorControl_SetCursor, + OnMsgSetCursor) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCursorControl_LockCursor, + OnMsgLockCursor) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCursorControl_UnlockCursor, + OnMsgUnlockCursor) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCursorControl_HasCursorLock, + OnMsgHasCursorLock) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBCursorControl_CanLockCursor, + OnMsgCanLockCursor) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw): handle bad messages! + return handled; +} + +void PPB_CursorControl_Proxy::OnMsgSetCursor(PP_Instance instance, + int32_t type, + HostResource custom_image, + const PP_Point& hot_spot, + PP_Bool* result) { + EnterFunctionNoLock<PPB_CursorControl_FunctionAPI> enter(instance, true); + if (enter.succeeded()) { + *result = enter.functions()->SetCursor( + instance, static_cast<PP_CursorType_Dev>(type), + custom_image.host_resource(), &hot_spot); + } +} + +void PPB_CursorControl_Proxy::OnMsgLockCursor(PP_Instance instance, + PP_Bool* result) { + EnterFunctionNoLock<PPB_CursorControl_FunctionAPI> enter(instance, true); + if (enter.succeeded()) + *result = enter.functions()->LockCursor(instance); +} + +void PPB_CursorControl_Proxy::OnMsgUnlockCursor(PP_Instance instance, + PP_Bool* result) { + EnterFunctionNoLock<PPB_CursorControl_FunctionAPI> enter(instance, true); + if (enter.succeeded()) + *result = enter.functions()->UnlockCursor(instance); +} + +void PPB_CursorControl_Proxy::OnMsgHasCursorLock(PP_Instance instance, + PP_Bool* result) { + EnterFunctionNoLock<PPB_CursorControl_FunctionAPI> enter(instance, true); + if (enter.succeeded()) + *result = enter.functions()->HasCursorLock(instance); +} + +void PPB_CursorControl_Proxy::OnMsgCanLockCursor(PP_Instance instance, + PP_Bool* result) { + EnterFunctionNoLock<PPB_CursorControl_FunctionAPI> enter(instance, true); + if (enter.succeeded()) + *result = enter.functions()->CanLockCursor(instance); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_cursor_control_proxy.h b/ppapi/proxy/ppb_cursor_control_proxy.h new file mode 100644 index 0000000..8657dc9 --- /dev/null +++ b/ppapi/proxy/ppb_cursor_control_proxy.h @@ -0,0 +1,70 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_CURSOR_CONTROL_PROXY_H_ +#define PPAPI_PPB_CURSOR_CONTROL_PROXY_H_ + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/thunk/ppb_cursor_control_api.h" + +struct PPB_CursorControl_Dev; + +namespace pp { +namespace proxy { + +class PPB_CursorControl_Proxy + : public ppapi::FunctionGroupBase, + public ppapi::thunk::PPB_CursorControl_FunctionAPI, + public InterfaceProxy { + public: + PPB_CursorControl_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_CursorControl_Proxy(); + + static const Info* GetInfo(); + + // FunctionGroupBase overrides. + ppapi::thunk::PPB_CursorControl_FunctionAPI* AsPPB_CursorControl_FunctionAPI() + OVERRIDE; + + // PPB_CursorControl_FunctionAPI implementation. + virtual PP_Bool SetCursor(PP_Instance instance, + PP_CursorType_Dev type, + PP_Resource custom_image_id, + const PP_Point* hot_spot) OVERRIDE; + virtual PP_Bool LockCursor(PP_Instance instance) OVERRIDE; + virtual PP_Bool UnlockCursor(PP_Instance instance) OVERRIDE; + virtual PP_Bool HasCursorLock(PP_Instance instance) OVERRIDE; + virtual PP_Bool CanLockCursor(PP_Instance instance) OVERRIDE; + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + // Message handlers. + void OnMsgSetCursor(PP_Instance instance, + int32_t type, + HostResource custom_image, + const PP_Point& hot_spot, + PP_Bool* result); + void OnMsgLockCursor(PP_Instance instance, + PP_Bool* result); + void OnMsgUnlockCursor(PP_Instance instance, + PP_Bool* result); + void OnMsgHasCursorLock(PP_Instance instance, + PP_Bool* result); + void OnMsgCanLockCursor(PP_Instance instance, + PP_Bool* result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_CURSOR_CONTROL_PROXY_H_ diff --git a/ppapi/proxy/ppb_file_chooser_proxy.cc b/ppapi/proxy/ppb_file_chooser_proxy.cc new file mode 100644 index 0000000..cda175f --- /dev/null +++ b/ppapi/proxy/ppb_file_chooser_proxy.cc @@ -0,0 +1,243 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_file_chooser_proxy.h" + +#include <queue> + +#include "ppapi/c/dev/ppb_file_chooser_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/thunk.h" + +using ::ppapi::thunk::PPB_FileChooser_API; + +namespace pp { +namespace proxy { + +class FileChooser : public PluginResource, + public PPB_FileChooser_API { + public: + FileChooser(const HostResource& resource); + virtual ~FileChooser(); + + // ResourceObjectBase overrides. + virtual PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; + + // PPB_FileChooser_API implementation. + virtual int32_t Show(PP_CompletionCallback callback) OVERRIDE; + virtual PP_Resource GetNextChosenFile() OVERRIDE; + + // Handles the choose complete notification from the host. + void ChooseComplete( + int32_t result_code, + const std::vector<PPBFileRef_CreateInfo>& chosen_files); + + private: + PP_CompletionCallback current_show_callback_; + + // All files returned by the current show callback that haven't yet been + // given to the plugin. The plugin will repeatedly call us to get the next + // file, and we'll vend those out of this queue, removing them when ownership + // has transferred to the plugin. + std::queue<PP_Resource> file_queue_; + + DISALLOW_COPY_AND_ASSIGN(FileChooser); +}; + +FileChooser::FileChooser(const HostResource& resource) + : PluginResource(resource), + current_show_callback_(PP_MakeCompletionCallback(NULL, NULL)) { +} + +FileChooser::~FileChooser() { + // Always need to fire completion callbacks to prevent a leak in the plugin. + if (current_show_callback_.func) { + // TODO(brettw) the callbacks at this level should be refactored with a + // more automatic tracking system like we have in the renderer. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( + current_show_callback_.func, current_show_callback_.user_data, + static_cast<int32_t>(PP_ERROR_ABORTED))); + } + + // Any existing files we haven't transferred ownership to the plugin need + // to be freed. + PluginResourceTracker* tracker = PluginResourceTracker::GetInstance(); + while (!file_queue_.empty()) { + tracker->ReleaseResource(file_queue_.front()); + file_queue_.pop(); + } +} + +PPB_FileChooser_API* FileChooser::AsPPB_FileChooser_API() { + return this; +} + +int32_t FileChooser::Show(PP_CompletionCallback callback) { + if (current_show_callback_.func) + return PP_ERROR_INPROGRESS; // Can't show more than once. + + current_show_callback_ = callback; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileChooser_Show( + INTERFACE_ID_PPB_FILE_CHOOSER, host_resource())); + return PP_OK_COMPLETIONPENDING; +} + +PP_Resource FileChooser::GetNextChosenFile() { + if (file_queue_.empty()) + return 0; + + // Return the next resource in the queue. These resource have already been + // addrefed (they're currently owned by the FileChooser) and returning them + // transfers ownership of that reference to the plugin. + PP_Resource next = file_queue_.front(); + file_queue_.pop(); + return next; +} + +void FileChooser::ChooseComplete( + int32_t result_code, + const std::vector<PPBFileRef_CreateInfo>& chosen_files) { + // Convert each of the passed in file infos to resources. These will be owned + // by the FileChooser object until they're passed to the plugin. + DCHECK(file_queue_.empty()); + for (size_t i = 0; i < chosen_files.size(); i++) + file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); + + // Notify the plugin of the new data. + PP_RunAndClearCompletionCallback(¤t_show_callback_, result_code); + // DANGER: May delete |this|! +} + +namespace { + +InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_FileChooser_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() { +} + +const InterfaceProxy::Info* PPB_FileChooser_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_FileChooser_Thunk(), + PPB_FILECHOOSER_DEV_INTERFACE, + INTERFACE_ID_PPB_FILE_CHOOSER, + false, + &CreateFileChooserProxy, + }; + return &info; +} + +// static +PP_Resource PPB_FileChooser_Proxy::CreateProxyResource( + PP_Instance instance, + const PP_FileChooserOptions_Dev* options) { + Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create( + INTERFACE_ID_PPB_FILE_CHOOSER, instance, + options->mode, + options->accept_mime_types ? options->accept_mime_types : std::string(), + &result)); + + if (result.is_null()) + return 0; + linked_ptr<FileChooser> object(new FileChooser(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg) + // Plugin -> host messages. + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow) + + // Host -> plugin messages. + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete, + OnMsgChooseComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_FileChooser_Proxy::OnMsgCreate(PP_Instance instance, + int mode, + const std::string& accept_mime_types, + HostResource* result) { + PP_FileChooserOptions_Dev options; + options.mode = static_cast<PP_FileChooserMode_Dev>(mode); + options.accept_mime_types = accept_mime_types.c_str(); + result->SetHostResource( + instance, ppb_file_chooser_target()->Create(instance, &options)); +} + +void PPB_FileChooser_Proxy::OnMsgShow(const HostResource& chooser) { + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_FileChooser_Proxy::OnShowCallback, chooser); + + int32_t result = ppb_file_chooser_target()->Show( + chooser.host_resource(), callback.pp_completion_callback()); + if (result != PP_OK_COMPLETIONPENDING) + callback.Run(result); +} + +void PPB_FileChooser_Proxy::OnMsgChooseComplete( + const HostResource& chooser, + int32_t result_code, + const std::vector<PPBFileRef_CreateInfo>& chosen_files) { + EnterPluginFromHostResource<PPB_FileChooser_API> enter(chooser); + if (enter.succeeded()) { + static_cast<FileChooser*>(enter.object())->ChooseComplete( + result_code, chosen_files); + } +} + +void PPB_FileChooser_Proxy::OnShowCallback(int32_t result, + const HostResource& chooser) { + std::vector<PPBFileRef_CreateInfo> files; + if (result == PP_OK) { + // Jump through some hoops to get the FileRef proxy. Since we know we're + // in the host at this point, we can ask the host dispatcher for it. + DCHECK(!dispatcher()->IsPlugin()); + HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher()); + PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>( + host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF)); + + // Convert the returned files to the serialized info. + while (PP_Resource cur_file_resource = + ppb_file_chooser_target()->GetNextChosenFile( + chooser.host_resource())) { + PPBFileRef_CreateInfo cur_create_info; + file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info); + files.push_back(cur_create_info); + } + } + + dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete( + INTERFACE_ID_PPB_FILE_CHOOSER, chooser, result, files)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_file_chooser_proxy.h b/ppapi/proxy/ppb_file_chooser_proxy.h new file mode 100644 index 0000000..4b83e950 --- /dev/null +++ b/ppapi/proxy/ppb_file_chooser_proxy.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FILE_CHOOSER_PROXY_H_ +#define PPAPI_PROXY_PPB_FILE_CHOOSER_PROXY_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" +#include "ppapi/thunk/ppb_file_chooser_api.h" + +struct PPB_FileChooser_Dev; + +namespace pp { +namespace proxy { + +class HostResource; +struct PPBFileRef_CreateInfo; + +class PPB_FileChooser_Proxy : public InterfaceProxy { + public: + PPB_FileChooser_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_FileChooser_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource( + PP_Instance instance, + const PP_FileChooserOptions_Dev* options); + + const PPB_FileChooser_Dev* ppb_file_chooser_target() const { + return static_cast<const PPB_FileChooser_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Plugin -> host message handlers. + void OnMsgCreate(PP_Instance instance, + int mode, + const std::string& accept_mime_types, + pp::proxy::HostResource* result); + void OnMsgShow(const pp::proxy::HostResource& chooser); + + // Host -> plugin message handlers. + void OnMsgChooseComplete( + const pp::proxy::HostResource& chooser, + int32_t result_code, + const std::vector<PPBFileRef_CreateInfo>& chosen_files); + + // Called when the show is complete in the host. This will notify the plugin + // via IPC and OnMsgChooseComplete will be called there. + void OnShowCallback(int32_t result, const HostResource& chooser); + + CompletionCallbackFactory<PPB_FileChooser_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileChooser_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FILE_CHOOSER_PROXY_H_ diff --git a/ppapi/proxy/ppb_file_ref_proxy.cc b/ppapi/proxy/ppb_file_ref_proxy.cc new file mode 100644 index 0000000..de91996 --- /dev/null +++ b/ppapi/proxy/ppb_file_ref_proxy.cc @@ -0,0 +1,303 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_file_ref_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_ref.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/ppb_file_ref_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_FileRef_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateFileRefProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_FileRef_Proxy(dispatcher, target_interface); +} + +} // namespace + +class FileRef : public PluginResource, public PPB_FileRef_API { + public: + explicit FileRef(const PPBFileRef_CreateInfo& info); + virtual ~FileRef(); + + // ResourceObjectBase overrides. + virtual PPB_FileRef_API* AsPPB_FileRef_API() OVERRIDE; + + // PPB_FileRef_API implementation. + virtual PP_FileSystemType GetFileSystemType() const OVERRIDE; + virtual PP_Var GetName() const OVERRIDE; + virtual PP_Var GetPath() const OVERRIDE; + virtual PP_Resource GetParent() OVERRIDE; + virtual int32_t MakeDirectory(PP_Bool make_ancestors, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Rename(PP_Resource new_file_ref, + PP_CompletionCallback callback) OVERRIDE; + + private: + PP_FileSystemType file_system_type_; + PP_Var path_; + PP_Var name_; + + DISALLOW_COPY_AND_ASSIGN(FileRef); +}; + +FileRef::FileRef(const PPBFileRef_CreateInfo& info) + : PluginResource(info.resource) { + Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance()); + + file_system_type_ = static_cast<PP_FileSystemType>(info.file_system_type); + + name_ = ReceiveSerializedVarReturnValue(info.name).Return(dispatcher); + path_ = ReceiveSerializedVarReturnValue(info.path).Return(dispatcher); +} + +FileRef::~FileRef() { + PluginVarTracker::GetInstance()->Release(path_); + PluginVarTracker::GetInstance()->Release(name_); +} + +PPB_FileRef_API* FileRef::AsPPB_FileRef_API() { + return this; +} + +PP_FileSystemType FileRef::GetFileSystemType() const { + return file_system_type_; +} + +PP_Var FileRef::GetName() const { + PluginVarTracker::GetInstance()->AddRef(name_); + return name_; +} + +PP_Var FileRef::GetPath() const { + PluginVarTracker::GetInstance()->AddRef(path_); + return path_; +} + +PP_Resource FileRef::GetParent() { + PPBFileRef_CreateInfo create_info; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( + INTERFACE_ID_PPB_FILE_REF, host_resource(), &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, + PP_CompletionCallback callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( + INTERFACE_ID_PPB_FILE_REF, host_resource(), make_ancestors, + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( + INTERFACE_ID_PPB_FILE_REF, host_resource(), + last_access_time, last_modified_time, + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Delete(PP_CompletionCallback callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( + INTERFACE_ID_PPB_FILE_REF, host_resource(), + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileRef::Rename(PP_Resource new_file_ref, + PP_CompletionCallback callback) { + PluginResource* new_file_ref_object = + PluginResourceTracker::GetInstance()->GetResourceObject(new_file_ref); + if (!new_file_ref_object || + new_file_ref_object->host_resource().instance() != instance()) + return PP_ERROR_BADRESOURCE; + + GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( + INTERFACE_ID_PPB_FILE_REF, host_resource(), + new_file_ref_object->host_resource(), + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { +} + +const InterfaceProxy::Info* PPB_FileRef_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_FileRef_Thunk(), + PPB_FILEREF_INTERFACE, + INTERFACE_ID_PPB_FILE_REF, + false, + &CreateFileRefProxy, + }; + return &info; +} + +// static +PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Resource file_system, + const char* path) { + PluginResource* file_system_object = + PluginResourceTracker::GetInstance()->GetResourceObject(file_system); + if (!file_system_object) + return 0; + + PPBFileRef_CreateInfo create_info; + file_system_object->GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Create( + INTERFACE_ID_PPB_FILE_REF, file_system_object->host_resource(), + path, &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +bool PPB_FileRef_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_FileRef_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_GetParent, OnMsgGetParent) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_MakeDirectory, + OnMsgMakeDirectory) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Touch, OnMsgTouch) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Delete, OnMsgDelete) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileRef_Rename, OnMsgRename) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_FileRef_Proxy::SerializeFileRef(PP_Resource file_ref, + PPBFileRef_CreateInfo* result) { + EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, false); + if (enter.failed()) { + NOTREACHED(); + return; + } + + // We need the instance out of the resource for serializing back to the + // plugin. This code can only run in the host. + if (dispatcher()->IsPlugin()) { + NOTREACHED(); + return; + } + HostDispatcher* host_dispatcher = static_cast<HostDispatcher*>(dispatcher()); + PP_Instance instance = + host_dispatcher->ppb_proxy()->GetInstanceForResource(file_ref); + + result->resource.SetHostResource(instance, file_ref); + result->file_system_type = + static_cast<int>(enter.object()->GetFileSystemType()); + result->path = SerializedVarReturnValue::Convert(dispatcher(), + enter.object()->GetPath()); + result->name = SerializedVarReturnValue::Convert(dispatcher(), + enter.object()->GetName()); +} + +// static +PP_Resource PPB_FileRef_Proxy::DeserializeFileRef( + const PPBFileRef_CreateInfo& serialized) { + if (serialized.resource.is_null()) + return 0; // Resource invalid. + + linked_ptr<FileRef> object(new FileRef(serialized)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +void PPB_FileRef_Proxy::OnMsgCreate(const HostResource& file_system, + const std::string& path, + PPBFileRef_CreateInfo* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(file_system.instance(), true); + if (enter.failed()) + return; + PP_Resource resource = enter.functions()->CreateFileRef( + file_system.host_resource(), path.c_str()); + if (!resource) + return; // CreateInfo default constructor initializes to 0. + SerializeFileRef(resource, result); +} + +void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, + PPBFileRef_CreateInfo* result) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.succeeded()) + SerializeFileRef(enter.object()->GetParent(), result); +} + +void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, + PP_Bool make_ancestors, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.failed()) + return; + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = enter.object()->MakeDirectory(make_ancestors, callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, + PP_Time last_access, + PP_Time last_modified, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.failed()) + return; + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = enter.object()->Touch(last_access, last_modified, callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); + if (enter.failed()) + return; + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = enter.object()->Delete(callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, + const HostResource& new_file_ref, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_FileRef_API> enter(file_ref); + if (enter.failed()) + return; + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = enter.object()->Rename(new_file_ref.host_resource(), + callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_file_ref_proxy.h b/ppapi/proxy/ppb_file_ref_proxy.h new file mode 100644 index 0000000..076bea2 --- /dev/null +++ b/ppapi/proxy/ppb_file_ref_proxy.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ +#define PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_FileRef_Dev; + +namespace pp { +namespace proxy { + +class HostResource; +struct PPBFileRef_CreateInfo; + +class PPB_FileRef_Proxy : public InterfaceProxy { + public: + PPB_FileRef_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_FileRef_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Resource file_system, + const char* path); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Takes a resource in the host and converts it into a serialized file ref + // "create info" for reconstitution in the plugin. This struct contains all + // the necessary information about the file ref. + // + // This function is not static because it needs access to the particular + // dispatcher and host interface. + // + // Various PPAPI functions return file refs from various interfaces, so this + // function is public so anybody can send a file ref. + void SerializeFileRef(PP_Resource file_ref, + PPBFileRef_CreateInfo* result); + + // Creates a plugin resource from the given CreateInfo sent from the host. + // The value will be the result of calling SerializeFileRef on the host. + // This represents passing the resource ownership to the plugin. This + // function also checks the validity of the result and returns 0 on failure. + // + // Various PPAPI functions return file refs from various interfaces, so this + // function is public so anybody can receive a file ref. + static PP_Resource DeserializeFileRef( + const PPBFileRef_CreateInfo& serialized); + + private: + // Message handlers. + void OnMsgCreate(const HostResource& file_system, + const std::string& path, + PPBFileRef_CreateInfo* result); + void OnMsgGetParent(const HostResource& host_resource, + PPBFileRef_CreateInfo* result); + void OnMsgMakeDirectory(const HostResource& host_resource, + PP_Bool make_ancestors, + uint32_t serialized_callback); + void OnMsgTouch(const HostResource& host_resource, + PP_Time last_access, + PP_Time last_modified, + uint32_t serialized_callback); + void OnMsgDelete(const HostResource& host_resource, + uint32_t serialized_callback); + void OnMsgRename(const HostResource& file_ref, + const HostResource& new_file_ref, + uint32_t serialized_callback); + + DISALLOW_COPY_AND_ASSIGN(PPB_FileRef_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FILE_REF_PROXY_H_ diff --git a/ppapi/proxy/ppb_file_system_proxy.cc b/ppapi/proxy/ppb_file_system_proxy.cc new file mode 100644 index 0000000..1edf5d7 --- /dev/null +++ b/ppapi/proxy/ppb_file_system_proxy.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_file_system_proxy.h" + +#include "base/message_loop.h" +#include "base/task.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_system.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_system_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_FileSystem_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateFileSystemProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_FileSystem_Proxy(dispatcher, target_interface); +} + +} // namespace + +// This object maintains most of the state of the ref in the plugin for fast +// querying. It's all set in the constructor from the "create info" sent from +// the host. +class FileSystem : public PluginResource, public PPB_FileSystem_API { + public: + FileSystem(const HostResource& host_resource, PP_FileSystemType type); + virtual ~FileSystem(); + + // ResourceObjectBase override. + virtual PPB_FileSystem_API* AsPPB_FileSystem_API() OVERRIDE; + + // PPB_FileSystem_APi implementation. + virtual int32_t Open(int64_t expected_size, + PP_CompletionCallback callback) OVERRIDE; + virtual PP_FileSystemType GetType() OVERRIDE; + + // Called when the host has responded to our open request. + void OpenComplete(int32_t result); + + private: + PP_FileSystemType type_; + bool called_open_; + PP_CompletionCallback current_open_callback_; + + DISALLOW_COPY_AND_ASSIGN(FileSystem); +}; + +FileSystem::FileSystem(const HostResource& host_resource, + PP_FileSystemType type) + : PluginResource(host_resource), + type_(type), + called_open_(false), + current_open_callback_(PP_MakeCompletionCallback(NULL, NULL)) { +} + +// TODO(brettw) this logic is duplicated with some other resource objects +// like FileChooser. It would be nice to look at all of the different resources +// that need callback tracking and design something that they can all re-use. +FileSystem::~FileSystem() { + // Ensure the callback is always fired. + if (current_open_callback_.func) { + // TODO(brettw) the callbacks at this level should be refactored with a + // more automatic tracking system like we have in the renderer. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( + current_open_callback_.func, current_open_callback_.user_data, + static_cast<int32_t>(PP_ERROR_ABORTED))); + } +} + +PPB_FileSystem_API* FileSystem::AsPPB_FileSystem_API() { + return this; +} + +int32_t FileSystem::Open(int64_t expected_size, + PP_CompletionCallback callback) { + if (current_open_callback_.func) + return PP_ERROR_INPROGRESS; + if (called_open_) + return PP_ERROR_FAILED; + + current_open_callback_ = callback; + called_open_ = true; + GetDispatcher()->Send(new PpapiHostMsg_PPBFileSystem_Open( + INTERFACE_ID_PPB_FILE_SYSTEM, host_resource(), expected_size)); + return PP_OK_COMPLETIONPENDING; +} + +PP_FileSystemType FileSystem::GetType() { + return type_; +} + +void FileSystem::OpenComplete(int32_t result) { + PP_RunAndClearCompletionCallback(¤t_open_callback_, result); +} + +PPB_FileSystem_Proxy::PPB_FileSystem_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_FileSystem_Proxy::~PPB_FileSystem_Proxy() { +} + +const InterfaceProxy::Info* PPB_FileSystem_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_FileSystem_Thunk(), + PPB_FILESYSTEM_INTERFACE, + INTERFACE_ID_PPB_FILE_SYSTEM, + false, + &CreateFileSystemProxy, + }; + return &info; +} + +// static +PP_Resource PPB_FileSystem_Proxy::CreateProxyResource( + PP_Instance instance, + PP_FileSystemType type) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBFileSystem_Create( + INTERFACE_ID_PPB_FILE_SYSTEM, instance, type, &result)); + if (result.is_null()) + return 0; + + linked_ptr<FileSystem> object(new FileSystem(result, type)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_FileSystem_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_FileSystem_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileSystem_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileSystem_Open, OnMsgOpen) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileSystem_OpenComplete, OnMsgOpenComplete) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_FileSystem_Proxy::OnMsgCreate(PP_Instance instance, + int type, + HostResource* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.failed()) + return; + PP_Resource resource = enter.functions()->CreateFileSystem( + instance, static_cast<PP_FileSystemType>(type)); + if (!resource) + return; // CreateInfo default constructor initializes to 0. + result->SetHostResource(instance, resource); +} + +void PPB_FileSystem_Proxy::OnMsgOpen(const HostResource& host_resource, + int64_t expected_size) { + EnterHostFromHostResource<PPB_FileSystem_API> enter(host_resource); + if (enter.failed()) + return; + + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_FileSystem_Proxy::OpenCompleteInHost, host_resource); + int32_t result = enter.object()->Open(expected_size, + callback.pp_completion_callback()); + if (result != PP_OK_COMPLETIONPENDING) + callback.Run(result); +} + +// Called in the plugin to handle the open callback. +void PPB_FileSystem_Proxy::OnMsgOpenComplete(const HostResource& host_resource, + int32_t result) { + EnterPluginFromHostResource<PPB_FileSystem_API> enter(host_resource); + if (enter.succeeded()) + static_cast<FileSystem*>(enter.object())->OpenComplete(result); +} + +void PPB_FileSystem_Proxy::OpenCompleteInHost( + int32_t result, + const HostResource& host_resource) { + dispatcher()->Send(new PpapiMsg_PPBFileSystem_OpenComplete( + INTERFACE_ID_PPB_FILE_SYSTEM, host_resource, result)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_file_system_proxy.h b/ppapi/proxy/ppb_file_system_proxy.h new file mode 100644 index 0000000..dcf94b3 --- /dev/null +++ b/ppapi/proxy/ppb_file_system_proxy.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FILE_SYSTEM_PROXY_H_ +#define PPAPI_PROXY_PPB_FILE_SYSTEM_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/c/ppb_file_system.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_FileSystem_Dev; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_FileSystem_Proxy : public InterfaceProxy { + public: + PPB_FileSystem_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_FileSystem_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + PP_FileSystemType type); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, + int type, + HostResource* result); + void OnMsgOpen(const HostResource& filesystem, + int64_t expected_size); + + void OnMsgOpenComplete(const HostResource& filesystem, + int32_t result); + + void OpenCompleteInHost(int32_t result, const HostResource& host_resource); + + CompletionCallbackFactory<PPB_FileSystem_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileSystem_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FILE_SYSTEM_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_clipboard_proxy.cc b/ppapi/proxy/ppb_flash_clipboard_proxy.cc new file mode 100644 index 0000000..8dc98ff --- /dev/null +++ b/ppapi/proxy/ppb_flash_clipboard_proxy.cc @@ -0,0 +1,165 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_clipboard_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash_clipboard.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +namespace proxy { + +namespace { + +bool IsValidClipboardType(PP_Flash_Clipboard_Type clipboard_type) { + return clipboard_type == PP_FLASH_CLIPBOARD_TYPE_STANDARD || + clipboard_type == PP_FLASH_CLIPBOARD_TYPE_SELECTION || + clipboard_type == PP_FLASH_CLIPBOARD_TYPE_DRAG; +} + +bool IsValidClipboardFormat(PP_Flash_Clipboard_Format format) { + // Purposely excludes |PP_FLASH_CLIPBOARD_FORMAT_INVALID|. + return format == PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT || + format == PP_FLASH_CLIPBOARD_FORMAT_HTML; +} + +PP_Bool IsFormatAvailable(PP_Instance instance_id, + PP_Flash_Clipboard_Type clipboard_type, + PP_Flash_Clipboard_Format format) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return PP_FALSE; + + if (!IsValidClipboardType(clipboard_type) || !IsValidClipboardFormat(format)) + return PP_FALSE; + + bool result = false; + dispatcher->Send(new PpapiHostMsg_PPBFlashClipboard_IsFormatAvailable( + INTERFACE_ID_PPB_FLASH_CLIPBOARD, + instance_id, + static_cast<int>(clipboard_type), + static_cast<int>(format), + &result)); + return PP_FromBool(result); +} + +PP_Var ReadPlainText(PP_Instance instance_id, + PP_Flash_Clipboard_Type clipboard_type) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return PP_MakeUndefined(); + + if (!IsValidClipboardType(clipboard_type)) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBFlashClipboard_ReadPlainText( + INTERFACE_ID_PPB_FLASH_CLIPBOARD, instance_id, + static_cast<int>(clipboard_type), &result)); + return result.Return(dispatcher); +} + +int32_t WritePlainText(PP_Instance instance_id, + PP_Flash_Clipboard_Type clipboard_type, + PP_Var text) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + if (!IsValidClipboardType(clipboard_type)) + return PP_ERROR_BADARGUMENT; + + dispatcher->Send(new PpapiHostMsg_PPBFlashClipboard_WritePlainText( + INTERFACE_ID_PPB_FLASH_CLIPBOARD, + instance_id, + static_cast<int>(clipboard_type), + SerializedVarSendInput(dispatcher, text))); + // Assume success, since it allows us to avoid a sync IPC. + return PP_OK; +} + +const PPB_Flash_Clipboard flash_clipboard_interface = { + &IsFormatAvailable, + &ReadPlainText, + &WritePlainText +}; + +InterfaceProxy* CreateFlashClipboardProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_Clipboard_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_Clipboard_Proxy::PPB_Flash_Clipboard_Proxy( + Dispatcher* dispatcher, const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Flash_Clipboard_Proxy::~PPB_Flash_Clipboard_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_Clipboard_Proxy::GetInfo() { + static const Info info = { + &flash_clipboard_interface, + PPB_FLASH_CLIPBOARD_INTERFACE, + INTERFACE_ID_PPB_FLASH_CLIPBOARD, + false, + &CreateFlashClipboardProxy + }; + return &info; +} + +bool PPB_Flash_Clipboard_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_Clipboard_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashClipboard_IsFormatAvailable, + OnMsgIsFormatAvailable) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashClipboard_ReadPlainText, + OnMsgReadPlainText) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashClipboard_WritePlainText, + OnMsgWritePlainText) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Flash_Clipboard_Proxy::OnMsgIsFormatAvailable( + PP_Instance instance_id, + int clipboard_type, + int format, + bool* result) { + *result = PP_ToBool(ppb_flash_clipboard_target()->IsFormatAvailable( + instance_id, + static_cast<PP_Flash_Clipboard_Type>(clipboard_type), + static_cast<PP_Flash_Clipboard_Format>(format))); +} + +void PPB_Flash_Clipboard_Proxy::OnMsgReadPlainText( + PP_Instance instance_id, + int clipboard_type, + SerializedVarReturnValue result) { + result.Return(dispatcher(), + ppb_flash_clipboard_target()->ReadPlainText( + instance_id, + static_cast<PP_Flash_Clipboard_Type>(clipboard_type))); +} + +void PPB_Flash_Clipboard_Proxy::OnMsgWritePlainText( + PP_Instance instance_id, + int clipboard_type, + SerializedVarReceiveInput text) { + int32_t result = ppb_flash_clipboard_target()->WritePlainText( + instance_id, + static_cast<PP_Flash_Clipboard_Type>(clipboard_type), + text.Get(dispatcher())); + LOG_IF(WARNING, result != PP_OK) << "Write to clipboard failed unexpectedly."; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_clipboard_proxy.h b/ppapi/proxy/ppb_flash_clipboard_proxy.h new file mode 100644 index 0000000..6d9604f --- /dev/null +++ b/ppapi/proxy/ppb_flash_clipboard_proxy.h @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FLASH_CLIPBOARD_PROXY_H_ +#define PPAPI_PROXY_PPB_FLASH_CLIPBOARD_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Flash_Clipboard; + +namespace pp { +namespace proxy { + +class SerializedVarReceiveInput; +class SerializedVarReturnValue; + +class PPB_Flash_Clipboard_Proxy : public InterfaceProxy { + public: + PPB_Flash_Clipboard_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Flash_Clipboard_Proxy(); + + static const Info* GetInfo(); + + const PPB_Flash_Clipboard* ppb_flash_clipboard_target() const { + return reinterpret_cast<const PPB_Flash_Clipboard*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgIsFormatAvailable(PP_Instance instance_id, + int clipboard_type, + int format, + bool* result); + void OnMsgReadPlainText(PP_Instance instance_id, + int clipboard_type, + SerializedVarReturnValue result); + void OnMsgWritePlainText(PP_Instance instance_id, + int clipboard_type, + SerializedVarReceiveInput text); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FLASH_CLIPBOARD_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_file_proxy.cc b/ppapi/proxy/ppb_flash_file_proxy.cc new file mode 100644 index 0000000..7b6dc2d --- /dev/null +++ b/ppapi/proxy/ppb_flash_file_proxy.cc @@ -0,0 +1,732 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_file_proxy.h" + +#include <map> +#include <set> +#include <vector> + +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "build/build_config.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_sync_message.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/private/ppb_flash_file.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +// Given an error code and a handle result from a Pepper API call, converts to a +// PlatformFileForTransit by sharing with the other side, closing the original +// handle, possibly also updating the error value if an error occurred. +IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit( + Dispatcher* dispatcher, + int32_t* error, + base::PlatformFile file) { + if (*error != PP_OK) + return IPC::InvalidPlatformFileForTransit(); + IPC::PlatformFileForTransit out_handle = + dispatcher->ShareHandleWithRemote(file, true); + if (out_handle == IPC::InvalidPlatformFileForTransit()) + *error = PP_ERROR_NOACCESS; + return out_handle; +} + +void FreeDirContents(PP_Instance /* instance */, + PP_DirContents_Dev* contents) { + for (int32_t i = 0; i < contents->count; ++i) + delete[] contents->entries[i].name; + delete[] contents->entries; + delete contents; +} + +} // namespace + +// ModuleLocalThreadAdapter ---------------------------------------------------- + +class ModuleLocalThreadAdapter + : public base::RefCountedThreadSafe<ModuleLocalThreadAdapter> { + class Filter; + public: + ModuleLocalThreadAdapter(); + + void AddInstanceRouting(PP_Instance instance, Dispatcher* dispatcher); + void ClearInstanceRouting(PP_Instance instance); + void ClearFilter(Dispatcher* dispatcher, Filter* filter); + + bool OnModuleLocalMessageReceived(const IPC::Message& msg); + + // Called on the I/O thread when the channel is being destroyed and the + // given message will never be issued a reply. + void OnModuleLocalMessageFailed(int message_id); + + bool Send(PP_Instance instance, IPC::Message* msg); + + private: + class Filter : public IPC::ChannelProxy::MessageFilter { + public: + explicit Filter(Dispatcher* dispatcher); + ~Filter(); + + void Send(IPC::Message* msg); + + virtual void OnFilterAdded(IPC::Channel* channel); + virtual void OnFilterRemoved(); + virtual bool OnMessageReceived(const IPC::Message& message); + + private: + // DO NOT DEREFERENCE! This is used only for tracking. + Dispatcher* dispatcher_; + + IPC::Channel* channel_; + + // Holds the IPC messages that were sent before the channel was connected. + // These will be sent ASAP. + std::vector<IPC::Message*> pre_connect_pending_messages_; + + // Holds the IDs of the sync messages we're currently waiting on for this + // channel. This tracking allows us to cancel those requests if the + // remote process crashes and we're cleaning up this filter (without just + // deadlocking the waiting thread(s). + std::set<int> pending_requests_for_filter_; + }; + + void SendFromIOThread(Dispatcher* dispatcher, IPC::Message* msg); + + // Internal version of OnModuleLocalMessageFailed which assumes the lock + // is already held. + void OnModuleLocalMessageFailedLocked(int message_id); + + base::Lock lock_; + + scoped_refptr<base::MessageLoopProxy> main_thread_; + + // Will be NULL before an instance routing is added. + scoped_refptr<base::MessageLoopProxy> io_thread_; + + typedef std::map<PP_Instance, Dispatcher*> InstanceToDispatcher; + InstanceToDispatcher instance_to_dispatcher_; + + // The filters are owned by the channel. + typedef std::map<Dispatcher*, Filter*> DispatcherToFilter; + DispatcherToFilter dispatcher_to_filter_; + + // Tracks all messages with currently waiting threads. This does not own + // the pointer, the pointer lifetime is managed by Send(). + typedef std::map<int, IPC::PendingSyncMsg*> SyncRequestMap; + SyncRequestMap pending_sync_requests_; +}; + +ModuleLocalThreadAdapter* g_module_local_thread_adapter = NULL; + +ModuleLocalThreadAdapter::Filter::Filter(Dispatcher* dispatcher) + : dispatcher_(dispatcher), channel_(NULL) { +} + +ModuleLocalThreadAdapter::Filter::~Filter() { +} + +void ModuleLocalThreadAdapter::Filter::Send(IPC::Message* msg) { + if (channel_) { + int message_id = IPC::SyncMessage::GetMessageId(*msg); + if (channel_->Send(msg)) + pending_requests_for_filter_.insert(message_id); + else // Message lost, notify adapter so it can unblock. + g_module_local_thread_adapter->OnModuleLocalMessageFailed(message_id); + } else { + // No channel, save this message for when it's connected. + pre_connect_pending_messages_.push_back(msg); + } +} + +void ModuleLocalThreadAdapter::Filter::OnFilterAdded(IPC::Channel* channel) { + DCHECK(!channel_); + channel_ = channel; + + // Now that we have a channel, process all pending messages. + for (size_t i = 0; i < pre_connect_pending_messages_.size(); i++) + Send(pre_connect_pending_messages_[i]); + pre_connect_pending_messages_.clear(); +} + +void ModuleLocalThreadAdapter::Filter::OnFilterRemoved() { + DCHECK(channel_); + channel_ = NULL; + g_module_local_thread_adapter->ClearFilter(dispatcher_, this); + + for (std::set<int>::iterator i = pending_requests_for_filter_.begin(); + i != pending_requests_for_filter_.end(); ++i) { + g_module_local_thread_adapter->OnModuleLocalMessageFailed(*i); + } +} + +bool ModuleLocalThreadAdapter::Filter::OnMessageReceived( + const IPC::Message& message) { + if (!message.is_reply() || + message.routing_id() != INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL) + return false; + + if (g_module_local_thread_adapter->OnModuleLocalMessageReceived(message)) { + // The message was consumed, this means we can remove the message ID from + // the list of messages this channel is waiting on. + pending_requests_for_filter_.erase(IPC::SyncMessage::GetMessageId(message)); + return true; + } + return false; +} + +ModuleLocalThreadAdapter::ModuleLocalThreadAdapter() + : main_thread_(base::MessageLoopProxy::CreateForCurrentThread()) { +} + +void ModuleLocalThreadAdapter::AddInstanceRouting(PP_Instance instance, + Dispatcher* dispatcher) { + base::AutoLock lock(lock_); + + // Now that we've had contact with a dispatcher, we can set up the IO thread. + DCHECK(main_thread_->BelongsToCurrentThread()); + if (!io_thread_.get()) + io_thread_ = dispatcher->GetIPCMessageLoop(); + + // Set up the instance -> dispatcher routing. + DCHECK(instance_to_dispatcher_.find(instance) == + instance_to_dispatcher_.end()); + instance_to_dispatcher_[instance] = dispatcher; + + DispatcherToFilter::iterator found_filter = + dispatcher_to_filter_.find(dispatcher); + if (found_filter == dispatcher_to_filter_.end()) { + // Need to set up a filter for this dispatcher to intercept the messages. + Filter* filter = new Filter(dispatcher); + dispatcher_to_filter_[dispatcher] = filter; + dispatcher->AddIOThreadMessageFilter(filter); + } +} + +void ModuleLocalThreadAdapter::ClearInstanceRouting(PP_Instance instance) { + // The dispatcher->filter mapping is cleaned up by ClearFilter which is + // initiated by the channel. + instance_to_dispatcher_.erase(instance); +} + +void ModuleLocalThreadAdapter::ClearFilter(Dispatcher* dispatcher, + Filter* filter) { + // DANGER! Don't dereference the dispatcher, it's just used to identify + // which filter to remove. The dispatcher may not even exist any more. + // + // Since the dispatcher may be gone, there's a potential for ambiguity if + // another one is created on the main thread before this code runs on the + // I/O thread. So we check that the filter matches to avoid this rare case. + base::AutoLock lock(lock_); + if (dispatcher_to_filter_[dispatcher] == filter) + dispatcher_to_filter_.erase(dispatcher); +} + +bool ModuleLocalThreadAdapter::OnModuleLocalMessageReceived( + const IPC::Message& msg) { + base::AutoLock lock(lock_); + + int message_id = IPC::SyncMessage::GetMessageId(msg); + SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); + if (found == pending_sync_requests_.end()) { + // Not waiting for this event. This will happen for sync messages to the + // main thread which use the "regular" sync channel code path. + return false; + } + + IPC::PendingSyncMsg& info = *found->second; + + if (!msg.is_reply_error()) + info.deserializer->SerializeOutputParameters(msg); + info.done_event->Signal(); + return true; +} + +void ModuleLocalThreadAdapter::OnModuleLocalMessageFailed(int message_id) { + base::AutoLock lock(lock_); + OnModuleLocalMessageFailedLocked(message_id); +} + +bool ModuleLocalThreadAdapter::Send(PP_Instance instance, IPC::Message* msg) { + // Compute the dispatcher corresponding to this message. + Dispatcher* dispatcher = NULL; + { + base::AutoLock lock(lock_); + InstanceToDispatcher::iterator found = + instance_to_dispatcher_.find(instance); + if (found == instance_to_dispatcher_.end()) { + NOTREACHED(); + delete msg; + return false; + } + dispatcher = found->second; + } + + if (main_thread_->BelongsToCurrentThread()) { + // Easy case: We're on the same thread as the dispatcher, so we don't need + // a lock to access it, and we can just use the normal sync channel stuff + // to handle the message. Actually, we MUST use the normal sync channel + // stuff since there may be incoming sync messages that need processing. + // The code below doesn't handle any nested message loops. + return dispatcher->Send(msg); + } + + // Background thread case + // ---------------------- + // 1. Generate tracking info, stick in pending_sync_messages_map. + // 2. Kick off the request. This is done on the I/O thread. + // 3. Filter on the I/O thread notices reply, writes the reply data and + // signals the event. We block on the event while this is happening. + // 4. Remove tracking info. + + // Generate the tracking info. and copied + IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(msg); + int message_id = IPC::SyncMessage::GetMessageId(*sync_msg); + base::WaitableEvent event(true, false); + scoped_ptr<IPC::MessageReplyDeserializer> deserializer( + sync_msg->GetReplyDeserializer()); // We own this pointer once retrieved. + IPC::PendingSyncMsg info(message_id, deserializer.get(), &event); + + // Add the tracking information to our map. + { + base::AutoLock lock(lock_); + pending_sync_requests_[message_id] = &info; + } + + // This is a bit dangerous. We use the dispatcher pointer as the routing + // ID for this message. While we don't dereference it, there is an + // exceedingly remote possibility that while this is going to the background + // thread the connection will be shut down and a new one will be created with + // a dispatcher at the same address. It could potentially get sent to a + // random place, but it should actually still work (since the Flash file + // operations are global). + io_thread_->PostTask(FROM_HERE, + NewRunnableMethod(this, &ModuleLocalThreadAdapter::SendFromIOThread, + dispatcher, msg)); + + // Now we block the current thread waiting for the reply. + event.Wait(); + + { + // Clear our tracking info for this message now that we're done. + base::AutoLock lock(lock_); + DCHECK(pending_sync_requests_.find(message_id) != + pending_sync_requests_.end()); + pending_sync_requests_.erase(message_id); + } + + return true; +} + +void ModuleLocalThreadAdapter::SendFromIOThread(Dispatcher* dispatcher, + IPC::Message* msg) { + // DO NOT DEREFERENCE DISPATCHER. Used as a lookup only. + base::AutoLock lock(lock_); + DispatcherToFilter::iterator found = dispatcher_to_filter_.find(dispatcher); + + // The dispatcher could have been destroyed by the time we got here since + // we're on another thread. Need to unblock the caller. + if (found == dispatcher_to_filter_.end()) { + OnModuleLocalMessageFailedLocked(IPC::SyncMessage::GetMessageId(*msg)); + delete msg; + return; + } + + // Takes ownership of pointer. + found->second->Send(msg); +} + +void ModuleLocalThreadAdapter::OnModuleLocalMessageFailedLocked( + int message_id) { + lock_.AssertAcquired(); + + // Unblock the thread waiting for the message that will never come. + SyncRequestMap::iterator found = pending_sync_requests_.find(message_id); + if (found == pending_sync_requests_.end()) { + NOTREACHED(); + return; + } + found->second->done_event->Signal(); +} + +// PPB_Flash_File_ModuleLocal -------------------------------------------------- + +namespace { + +bool CreateThreadAdapterForInstance(PP_Instance instance) { + if (!g_module_local_thread_adapter) { + g_module_local_thread_adapter = new ModuleLocalThreadAdapter(); + g_module_local_thread_adapter->AddRef(); // Leaked, this object is global. + } + + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return false; + } + g_module_local_thread_adapter->AddInstanceRouting(instance, dispatcher); + return true; +} + +void ClearThreadAdapterForInstance(PP_Instance instance) { + if (g_module_local_thread_adapter) + g_module_local_thread_adapter->ClearInstanceRouting(instance); +} + +int32_t OpenModuleLocalFile(PP_Instance instance, + const char* path, + int32_t mode, + PP_FileHandle* file) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + IPC::PlatformFileForTransit transit; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + instance, path, mode, &transit, &result)); + *file = IPC::PlatformFileForTransitToPlatformFile(transit); + return result; +} + +int32_t RenameModuleLocalFile(PP_Instance instance, + const char* from_path, + const char* to_path) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + instance, from_path, to_path, &result)); + return result; +} + +int32_t DeleteModuleLocalFileOrDir(PP_Instance instance, + const char* path, + PP_Bool recursive) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + instance, path, recursive, &result)); + return result; +} + +int32_t CreateModuleLocalDir(PP_Instance instance, const char* path) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path, &result)); + return result; +} + +int32_t QueryModuleLocalFile(PP_Instance instance, + const char* path, + PP_FileInfo* info) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path, + info, &result)); + return result; +} + +int32_t GetModuleLocalDirContents(PP_Instance instance, + const char* path, + PP_DirContents_Dev** contents) { + if (!g_module_local_thread_adapter) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + std::vector<SerializedDirEntry> entries; + g_module_local_thread_adapter->Send(instance, + new PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents( + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + instance, path, &entries, &result)); + + if (result != PP_OK) + return result; + + // Copy the serialized dir entries to the output struct. + *contents = new PP_DirContents_Dev; + (*contents)->count = static_cast<int32_t>(entries.size()); + (*contents)->entries = new PP_DirEntry_Dev[entries.size()]; + for (size_t i = 0; i < entries.size(); i++) { + const SerializedDirEntry& source = entries[i]; + PP_DirEntry_Dev* dest = &(*contents)->entries[i]; + + char* name_copy = new char[source.name.size() + 1]; + memcpy(name_copy, source.name.c_str(), source.name.size() + 1); + dest->name = name_copy; + dest->is_dir = PP_FromBool(source.is_dir); + } + + return result; +} + +const PPB_Flash_File_ModuleLocal flash_file_modulelocal_interface = { + &CreateThreadAdapterForInstance, + &ClearThreadAdapterForInstance, + &OpenModuleLocalFile, + &RenameModuleLocalFile, + &DeleteModuleLocalFileOrDir, + &CreateModuleLocalDir, + &QueryModuleLocalFile, + &GetModuleLocalDirContents, + &FreeDirContents, +}; + +InterfaceProxy* CreateFlashFileModuleLocalProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_File_ModuleLocal_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_File_ModuleLocal_Proxy::PPB_Flash_File_ModuleLocal_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Flash_File_ModuleLocal_Proxy::~PPB_Flash_File_ModuleLocal_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_File_ModuleLocal_Proxy::GetInfo() { + static const Info info = { + &flash_file_modulelocal_interface, + PPB_FLASH_FILE_MODULELOCAL_INTERFACE, + INTERFACE_ID_PPB_FLASH_FILE_MODULELOCAL, + true, + &CreateFlashFileModuleLocalProxy, + }; + return &info; +} + +bool PPB_Flash_File_ModuleLocal_Proxy::OnMessageReceived( + const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_ModuleLocal_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile, + OnMsgOpenFile) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile, + OnMsgRenameFile) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir, + OnMsgDeleteFileOrDir) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir, + OnMsgCreateDir) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile, + OnMsgQueryFile) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents, + OnMsgGetDirContents) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgOpenFile( + PP_Instance instance, + const std::string& path, + int32_t mode, + IPC::PlatformFileForTransit* file_handle, + int32_t* result) { + base::PlatformFile file; + *result = ppb_flash_file_module_local_target()-> + OpenFile(instance, path.c_str(), mode, &file); + *file_handle = PlatformFileToPlatformFileForTransit( + dispatcher(), result, file); +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgRenameFile( + PP_Instance instance, + const std::string& from_path, + const std::string& to_path, + int32_t* result) { + *result = ppb_flash_file_module_local_target()-> + RenameFile(instance, from_path.c_str(), to_path.c_str()); +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgDeleteFileOrDir( + PP_Instance instance, + const std::string& path, + PP_Bool recursive, + int32_t* result) { + *result = ppb_flash_file_module_local_target()-> + DeleteFileOrDir(instance, path.c_str(), recursive); +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgCreateDir(PP_Instance instance, + const std::string& path, + int32_t* result) { + *result = ppb_flash_file_module_local_target()-> + CreateDir(instance, path.c_str()); +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgQueryFile(PP_Instance instance, + const std::string& path, + PP_FileInfo* info, + int32_t* result) { + *result = ppb_flash_file_module_local_target()-> + QueryFile(instance, path.c_str(), info); +} + +void PPB_Flash_File_ModuleLocal_Proxy::OnMsgGetDirContents( + PP_Instance instance, + const std::string& path, + std::vector<pp::proxy::SerializedDirEntry>* entries, + int32_t* result) { + PP_DirContents_Dev* contents = NULL; + *result = ppb_flash_file_module_local_target()-> + GetDirContents(instance, path.c_str(), &contents); + if (*result != PP_OK) + return; + + // Convert the list of entries to the serialized version. + entries->resize(contents->count); + for (int32_t i = 0; i < contents->count; i++) { + (*entries)[i].name.assign(contents->entries[i].name); + (*entries)[i].is_dir = PP_ToBool(contents->entries[i].is_dir); + } + ppb_flash_file_module_local_target()->FreeDirContents(instance, contents); +} + +// PPB_Flash_File_FileRef ------------------------------------------------------ + +namespace { + +int32_t OpenFileRefFile(PP_Resource file_ref_id, + int32_t mode, + PP_FileHandle* file) { + PluginResource* file_ref = + PluginResourceTracker::GetInstance()->GetResourceObject(file_ref_id); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + PluginDispatcher* dispatcher = + PluginDispatcher::GetForInstance(file_ref->instance()); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + int32_t result = PP_ERROR_FAILED; + IPC::PlatformFileForTransit transit; + dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_OpenFile( + INTERFACE_ID_PPB_FLASH_FILE_FILEREF, + file_ref->host_resource(), mode, &transit, &result)); + *file = IPC::PlatformFileForTransitToPlatformFile(transit); + return result; +} + +int32_t QueryFileRefFile(PP_Resource file_ref_id, + PP_FileInfo* info) { + PluginResource* file_ref = + PluginResourceTracker::GetInstance()->GetResourceObject(file_ref_id); + if (!file_ref) + return PP_ERROR_BADRESOURCE; + + PluginDispatcher* dispatcher = + PluginDispatcher::GetForInstance(file_ref->instance()); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + int32_t result = PP_ERROR_FAILED; + dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_QueryFile( + INTERFACE_ID_PPB_FLASH_FILE_FILEREF, + file_ref->host_resource(), info, &result)); + return result; +} + +const PPB_Flash_File_FileRef flash_file_fileref_interface = { + &OpenFileRefFile, + &QueryFileRefFile, +}; + +InterfaceProxy* CreateFlashFileFileRefProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_File_FileRef_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_File_FileRef_Proxy::PPB_Flash_File_FileRef_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Flash_File_FileRef_Proxy::~PPB_Flash_File_FileRef_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_File_FileRef_Proxy::GetInfo() { + static const Info info = { + &flash_file_fileref_interface, + PPB_FLASH_FILE_FILEREF_INTERFACE, + INTERFACE_ID_PPB_FLASH_FILE_FILEREF, + true, + &CreateFlashFileFileRefProxy, + }; + return &info; +} + +bool PPB_Flash_File_FileRef_Proxy::OnMessageReceived( + const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_FileRef_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_OpenFile, + OnMsgOpenFile) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_QueryFile, + OnMsgQueryFile) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Flash_File_FileRef_Proxy::OnMsgOpenFile( + const HostResource& host_resource, + int32_t mode, + IPC::PlatformFileForTransit* file_handle, + int32_t* result) { + base::PlatformFile file; + *result = ppb_flash_file_module_local_target()-> + OpenFile(host_resource.host_resource(), mode, &file); + *file_handle = PlatformFileToPlatformFileForTransit( + dispatcher(), result, file); +} + +void PPB_Flash_File_FileRef_Proxy::OnMsgQueryFile( + const HostResource& host_resource, + PP_FileInfo* info, + int32_t* result) { + *result = ppb_flash_file_module_local_target()-> + QueryFile(host_resource.host_resource(), info); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_file_proxy.h b/ppapi/proxy/ppb_flash_file_proxy.h new file mode 100644 index 0000000..e09ae54 --- /dev/null +++ b/ppapi/proxy/ppb_flash_file_proxy.h @@ -0,0 +1,98 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_FLASH_FILE_PROXY_H_ +#define PPAPI_PPB_FLASH_FILE_PROXY_H_ + +#include <string> +#include <vector> + +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PP_FileInfo; +struct PPB_Flash_File_FileRef; +struct PPB_Flash_File_ModuleLocal; + +namespace pp { +namespace proxy { + +class HostResource; +struct SerializedDirEntry; + +class PPB_Flash_File_ModuleLocal_Proxy : public InterfaceProxy { + public: + PPB_Flash_File_ModuleLocal_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Flash_File_ModuleLocal_Proxy(); + + static const Info* GetInfo(); + + const PPB_Flash_File_ModuleLocal* ppb_flash_file_module_local_target() const { + return static_cast<const PPB_Flash_File_ModuleLocal*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgOpenFile(PP_Instance instance, + const std::string& path, + int32_t mode, + IPC::PlatformFileForTransit* file_handle, + int32_t* result); + void OnMsgRenameFile(PP_Instance instance, + const std::string& path_from, + const std::string& path_to, + int32_t* result); + void OnMsgDeleteFileOrDir(PP_Instance instance, + const std::string& path, + PP_Bool recursive, + int32_t* result); + void OnMsgCreateDir(PP_Instance instance, + const std::string& path, + int32_t* result); + void OnMsgQueryFile(PP_Instance instance, + const std::string& path, + PP_FileInfo* info, + int32_t* result); + void OnMsgGetDirContents(PP_Instance instance, + const std::string& path, + std::vector<pp::proxy::SerializedDirEntry>* entries, + int32_t* result); +}; + +class PPB_Flash_File_FileRef_Proxy : public InterfaceProxy { + public: + PPB_Flash_File_FileRef_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Flash_File_FileRef_Proxy(); + + static const Info* GetInfo(); + + const PPB_Flash_File_FileRef* ppb_flash_file_module_local_target() const { + return static_cast<const PPB_Flash_File_FileRef*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgOpenFile(const HostResource& host_resource, + int32_t mode, + IPC::PlatformFileForTransit* file_handle, + int32_t* result); + void OnMsgQueryFile(const HostResource& host_resource, + PP_FileInfo* info, + int32_t* result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_FLASH_FILE_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_menu_proxy.cc b/ppapi/proxy/ppb_flash_menu_proxy.cc new file mode 100644 index 0000000..c42c10e --- /dev/null +++ b/ppapi/proxy/ppb_flash_menu_proxy.cc @@ -0,0 +1,204 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_menu_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_flash_menu_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_Flash_Menu_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +class FlashMenu : public PPB_Flash_Menu_API, public PluginResource { + public: + explicit FlashMenu(const HostResource& resource); + virtual ~FlashMenu(); + + // ResourceObjectBase overrides. + virtual PPB_Flash_Menu_API* AsPPB_Flash_Menu_API() OVERRIDE; + + // PPB_Flash_Menu_API implementation. + virtual int32_t Show(const PP_Point* location, + int32_t* selected_id, + PP_CompletionCallback callback) OVERRIDE; + + void ShowACK(int32_t selected_id, int32_t result); + + private: + PP_CompletionCallback callback_; + int32_t* selected_id_ptr_; + + DISALLOW_COPY_AND_ASSIGN(FlashMenu); +}; + +FlashMenu::FlashMenu(const HostResource& resource) + : PluginResource(resource), + callback_(PP_BlockUntilComplete()), + selected_id_ptr_(NULL) { +} + +FlashMenu::~FlashMenu() { +} + +PPB_Flash_Menu_API* FlashMenu::AsPPB_Flash_Menu_API() { + return this; +} + +int32_t FlashMenu::Show(const struct PP_Point* location, + int32_t* selected_id, + struct PP_CompletionCallback callback) { + if (callback_.func) + return PP_ERROR_INPROGRESS; + + selected_id_ptr_ = selected_id; + callback_ = callback; + + GetDispatcher()->Send(new PpapiHostMsg_PPBFlashMenu_Show( + INTERFACE_ID_PPB_FLASH_MENU, host_resource(), *location)); + return PP_OK_COMPLETIONPENDING; +} + +void FlashMenu::ShowACK(int32_t selected_id, int32_t result) { + *selected_id_ptr_ = selected_id; + PP_RunAndClearCompletionCallback(&callback_, result); +} + +namespace { + +InterfaceProxy* CreateFlashMenuProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_Menu_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_Menu_Proxy::PPB_Flash_Menu_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Flash_Menu_Proxy::~PPB_Flash_Menu_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_Menu_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_Flash_Menu_Thunk(), + PPB_FLASH_MENU_INTERFACE, + INTERFACE_ID_PPB_FLASH_MENU, + true, + &CreateFlashMenuProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Flash_Menu_Proxy::CreateProxyResource( + PP_Instance instance_id, + const PP_Flash_Menu* menu_data) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return 0; + + HostResource result; + pp::proxy::SerializedFlashMenu serialized_menu; + if (!serialized_menu.SetPPMenu(menu_data)) + return 0; + + dispatcher->Send(new PpapiHostMsg_PPBFlashMenu_Create( + INTERFACE_ID_PPB_FLASH_MENU, instance_id, serialized_menu, &result)); + if (result.is_null()) + return 0; + + linked_ptr<FlashMenu> menu(new FlashMenu(result)); + return PluginResourceTracker::GetInstance()->AddResource(menu); +} + +bool PPB_Flash_Menu_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_Menu_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashMenu_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashMenu_Show, + OnMsgShow) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashMenu_ShowACK, + OnMsgShowACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // FIXME(brettw) handle bad messages! + return handled; +} + +void PPB_Flash_Menu_Proxy::OnMsgCreate(PP_Instance instance, + const SerializedFlashMenu& menu_data, + HostResource* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource( + instance, + enter.functions()->CreateFlashMenu(instance, menu_data.pp_menu())); + } +} + +struct PPB_Flash_Menu_Proxy::ShowRequest { + HostResource menu; + int32_t selected_id; +}; + +void PPB_Flash_Menu_Proxy::OnMsgShow(const HostResource& menu, + const PP_Point& location) { + ShowRequest* request = new ShowRequest; + request->menu = menu; + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Flash_Menu_Proxy::SendShowACKToPlugin, request); + + EnterHostFromHostResource<PPB_Flash_Menu_API> enter(menu); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) { + result = enter.object()->Show(&location, + &request->selected_id, + callback.pp_completion_callback()); + } + if (result != PP_OK_COMPLETIONPENDING) { + // There was some error, so we won't get a callback. We need to now issue + // the ACK to the plugin so that it hears about the error. This will also + // clean up the data associated with the callback. + callback.Run(result); + } +} + +void PPB_Flash_Menu_Proxy::OnMsgShowACK(const HostResource& menu, + int32_t selected_id, + int32_t result) { + EnterPluginFromHostResource<PPB_Flash_Menu_API> enter(menu); + if (enter.failed()) + return; + static_cast<FlashMenu*>(enter.object())->ShowACK(selected_id, result); +} + +void PPB_Flash_Menu_Proxy::SendShowACKToPlugin( + int32_t result, + ShowRequest* request) { + dispatcher()->Send(new PpapiMsg_PPBFlashMenu_ShowACK( + INTERFACE_ID_PPB_FLASH_MENU, + request->menu, + request->selected_id, + result)); + delete request; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_menu_proxy.h b/ppapi/proxy/ppb_flash_menu_proxy.h new file mode 100644 index 0000000..d999905 --- /dev/null +++ b/ppapi/proxy/ppb_flash_menu_proxy.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_FLASH_MENU_PROXY_H_ +#define PPAPI_PPB_FLASH_MENU_PROXY_H_ + +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PP_Flash_Menu; +struct PP_Point; +struct PPB_Flash_Menu; + +namespace pp { +namespace proxy { + +class SerializedFlashMenu; + +class PPB_Flash_Menu_Proxy : public InterfaceProxy { + public: + PPB_Flash_Menu_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Flash_Menu_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance_id, + const PP_Flash_Menu* menu_data); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + struct ShowRequest; + + void OnMsgCreate(PP_Instance instance_id, + const SerializedFlashMenu& menu_data, + HostResource* resource); + void OnMsgShow(const HostResource& menu, + const PP_Point& location); + void OnMsgShowACK(const HostResource& menu, + int32_t selected_id, + int32_t result); + void SendShowACKToPlugin(int32_t result, ShowRequest* request); + + CompletionCallbackFactory<PPB_Flash_Menu_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_FLASH_MENU_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_net_connector_proxy.cc b/ppapi/proxy/ppb_flash_net_connector_proxy.cc new file mode 100644 index 0000000..ba2c218 --- /dev/null +++ b/ppapi/proxy/ppb_flash_net_connector_proxy.cc @@ -0,0 +1,345 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_net_connector_proxy.h" + +#include <algorithm> + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_flash_net_connector.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_flash_net_connector_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_Flash_NetConnector_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +std::string NetAddressToString(const PP_Flash_NetAddress& addr) { + return std::string(addr.data, std::min(static_cast<size_t>(addr.size), + sizeof(addr.data))); +} + +void StringToNetAddress(const std::string& str, PP_Flash_NetAddress* addr) { + addr->size = std::min(str.size(), sizeof(addr->data)); + memcpy(addr->data, str.data(), addr->size); +} + +class AbortCallbackTask : public Task { + public: + AbortCallbackTask(PP_CompletionCallback callback) + : callback_(callback) {} + + virtual void Run() { + PP_RunCompletionCallback(&callback_, PP_ERROR_ABORTED); + } + + private: + PP_CompletionCallback callback_; +}; + +class FlashNetConnector : public PPB_Flash_NetConnector_API, + public PluginResource { + public: + explicit FlashNetConnector(const HostResource& resource); + virtual ~FlashNetConnector(); + + // ResourceObjectBase overrides. + virtual PPB_Flash_NetConnector_API* AsPPB_Flash_NetConnector_API() OVERRIDE; + + // PPB_Flash_NetConnector_API implementation. + virtual int32_t ConnectTcp(const char* host, + uint16_t port, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t ConnectTcpAddress(const PP_Flash_NetAddress* addr, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback) OVERRIDE; + + void ConnectComplete(int32_t result, + base::PlatformFile file, + const std::string& local_addr_as_string, + const std::string& remote_addr_as_string); + + private: + // Backend for both ConnectTcp and ConnectTcpAddress. To keep things generic, + // the message is passed in (on error, it's deleted). + int32_t ConnectWithMessage(IPC::Message* msg, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback); + + PP_CompletionCallback callback_; + PP_FileHandle* socket_out_; + PP_Flash_NetAddress* local_addr_out_; + PP_Flash_NetAddress* remote_addr_out_; +}; + +FlashNetConnector::FlashNetConnector(const HostResource& resource) + : PluginResource(resource), + callback_(PP_BlockUntilComplete()), + local_addr_out_(NULL), + remote_addr_out_(NULL) { +} + +FlashNetConnector::~FlashNetConnector() { + if (callback_.func) { + MessageLoop::current()->PostTask(FROM_HERE, + new AbortCallbackTask(callback_)); + } +} + +PPB_Flash_NetConnector_API* FlashNetConnector::AsPPB_Flash_NetConnector_API() { + return this; +} + +int32_t FlashNetConnector::ConnectTcp( + const char* host, + uint16_t port, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback) { + return ConnectWithMessage( + new PpapiHostMsg_PPBFlashNetConnector_ConnectTcp( + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, host_resource(), host, port), + socket_out, local_addr_out, remote_addr_out, callback); +} + +int32_t FlashNetConnector::ConnectTcpAddress( + const PP_Flash_NetAddress* addr, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback) { + return ConnectWithMessage( + new PpapiHostMsg_PPBFlashNetConnector_ConnectTcpAddress( + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, + host_resource(), NetAddressToString(*addr)), + socket_out, local_addr_out, remote_addr_out, callback); +} + +void FlashNetConnector::ConnectComplete( + int32_t result, + base::PlatformFile file, + const std::string& local_addr_as_string, + const std::string& remote_addr_as_string) { + if (!callback_.func) { + base::ClosePlatformFile(file); + return; + } + + *socket_out_ = static_cast<PP_FileHandle>(file); + StringToNetAddress(local_addr_as_string, local_addr_out_); + StringToNetAddress(remote_addr_as_string, remote_addr_out_); + + PP_RunAndClearCompletionCallback(&callback_, result); +} + +int32_t FlashNetConnector::ConnectWithMessage( + IPC::Message* msg, + PP_FileHandle* socket_out, + PP_Flash_NetAddress* local_addr_out, + PP_Flash_NetAddress* remote_addr_out, + PP_CompletionCallback callback) { + scoped_ptr<IPC::Message> msg_deletor(msg); + if (callback_.func != NULL) + return PP_ERROR_INPROGRESS; // Can only have one pending request. + + // Send the request, it will call us back via ConnectACK. + GetDispatcher()->Send(msg_deletor.release()); + + callback_ = callback; + socket_out_ = socket_out; + local_addr_out_ = local_addr_out; + remote_addr_out_ = remote_addr_out; + return PP_OK_COMPLETIONPENDING; +} + +// Contains the data that the host interface will write to so we can send it +// to the plugin. This is created when a request is initiated, and deleted in +// the callback handler. +struct PPB_Flash_NetConnector_Proxy::ConnectCallbackInfo { + ConnectCallbackInfo(const HostResource& r) : resource(r), handle(0) { + local_addr.size = 0; + remote_addr.size = 0; + } + + HostResource resource; + + PP_FileHandle handle; + PP_Flash_NetAddress local_addr; + PP_Flash_NetAddress remote_addr; +}; + +namespace { + +InterfaceProxy* CreateFlashNetConnectorProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_NetConnector_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_NetConnector_Proxy::PPB_Flash_NetConnector_Proxy( + Dispatcher* dispatcher, const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Flash_NetConnector_Proxy::~PPB_Flash_NetConnector_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_NetConnector_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_Flash_NetConnector_Thunk(), + PPB_FLASH_NETCONNECTOR_INTERFACE, + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, + false, + &CreateFlashNetConnectorProxy + }; + return &info; +} + +// static +PP_Resource PPB_Flash_NetConnector_Proxy::CreateProxyResource( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBFlashNetConnector_Create( + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, instance, &result)); + if (result.is_null()) + return 0; + + linked_ptr<FlashNetConnector> object(new FlashNetConnector(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_Flash_NetConnector_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_NetConnector_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashNetConnector_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashNetConnector_ConnectTcp, + OnMsgConnectTcp) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashNetConnector_ConnectTcpAddress, + OnMsgConnectTcpAddress) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashNetConnector_ConnectACK, + OnMsgConnectACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Flash_NetConnector_Proxy::OnMsgCreate(PP_Instance instance, + HostResource* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource( + instance, + enter.functions()->CreateFlashNetConnector(instance)); + } +} + +void PPB_Flash_NetConnector_Proxy::OnMsgConnectTcp( + const HostResource& resource, + const std::string& host, + uint16_t port) { + ConnectCallbackInfo* info = new ConnectCallbackInfo(resource); + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Flash_NetConnector_Proxy::OnCompleteCallbackInHost, info); + + EnterHostFromHostResource<PPB_Flash_NetConnector_API> enter(resource); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) { + result = enter.object()->ConnectTcp( + host.c_str(), port, &info->handle, &info->local_addr, + &info->remote_addr, callback.pp_completion_callback()); + } + if (result != PP_OK_COMPLETIONPENDING) + OnCompleteCallbackInHost(result, info); +} + +void PPB_Flash_NetConnector_Proxy::OnMsgConnectTcpAddress( + const HostResource& resource, + const std::string& net_address_as_string) { + ConnectCallbackInfo* info = new ConnectCallbackInfo(resource); + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Flash_NetConnector_Proxy::OnCompleteCallbackInHost, info); + + PP_Flash_NetAddress net_address; + StringToNetAddress(net_address_as_string, &net_address); + + EnterHostFromHostResource<PPB_Flash_NetConnector_API> enter(resource); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) { + result = enter.object()->ConnectTcpAddress( + &net_address, &info->handle, &info->local_addr, &info->remote_addr, + callback.pp_completion_callback()); + } + if (result != PP_OK_COMPLETIONPENDING) + OnCompleteCallbackInHost(result, info); +} + +void PPB_Flash_NetConnector_Proxy::OnMsgConnectACK( + const HostResource& host_resource, + int32_t result, + IPC::PlatformFileForTransit handle, + const std::string& load_addr_as_string, + const std::string& remote_addr_as_string) { + base::PlatformFile platform_file = + IPC::PlatformFileForTransitToPlatformFile(handle); + + EnterPluginFromHostResource<PPB_Flash_NetConnector_API> enter(host_resource); + if (enter.failed()) { + base::ClosePlatformFile(platform_file); + return; + } + FlashNetConnector* object = static_cast<FlashNetConnector*>(enter.object()); + object->ConnectComplete(result, platform_file, + load_addr_as_string, remote_addr_as_string); +} + +void PPB_Flash_NetConnector_Proxy::OnCompleteCallbackInHost( + int32_t result, + ConnectCallbackInfo* info) { + // Callback must always delete the info. + scoped_ptr<ConnectCallbackInfo> info_deletor(info); + + if (result == PP_OK) { + dispatcher()->Send(new PpapiMsg_PPBFlashNetConnector_ConnectACK( + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, + info->resource, result, + dispatcher()->ShareHandleWithRemote( + static_cast<base::PlatformFile>(info->handle), true), + NetAddressToString(info->local_addr), + NetAddressToString(info->remote_addr))); + } else { + dispatcher()->Send(new PpapiMsg_PPBFlashNetConnector_ConnectACK( + INTERFACE_ID_PPB_FLASH_NETCONNECTOR, + info->resource, result, + IPC::InvalidPlatformFileForTransit(), std::string(), std::string())); + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_net_connector_proxy.h b/ppapi/proxy/ppb_flash_net_connector_proxy.h new file mode 100644 index 0000000..67647c2 --- /dev/null +++ b/ppapi/proxy/ppb_flash_net_connector_proxy.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FLASH_NET_CONNECTOR_PROXY_H_ +#define PPAPI_PROXY_PPB_FLASH_NET_CONNECTOR_PROXY_H_ + +#include "base/platform_file.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_Flash_NetConnector; + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_Flash_NetConnector_Proxy : public InterfaceProxy { + public: + PPB_Flash_NetConnector_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Flash_NetConnector_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + struct ConnectCallbackInfo; + + // Plugin->host message handlers. + void OnMsgCreate(PP_Instance instance, + HostResource* result); + void OnMsgConnectTcp(const HostResource& resource, + const std::string& host, + uint16_t port); + void OnMsgConnectTcpAddress(const HostResource& resource_id, + const std::string& net_address_as_string); + + // Host->plugin message handler. + void OnMsgConnectACK(const HostResource& host_resource, + int32_t result, + IPC::PlatformFileForTransit handle, + const std::string& load_addr_as_string, + const std::string& remote_addr_as_string); + + void OnCompleteCallbackInHost(int32_t result, ConnectCallbackInfo* info); + + CompletionCallbackFactory<PPB_Flash_NetConnector_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FLASH_NET_CONNECTOR_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_proxy.cc b/ppapi/proxy/ppb_flash_proxy.cc new file mode 100644 index 0000000..c430b05 --- /dev/null +++ b/ppapi/proxy/ppb_flash_proxy.cc @@ -0,0 +1,291 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_proxy.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/time.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_flash.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/proxy_module.h" +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +namespace proxy { + +namespace { + +void SetInstanceAlwaysOnTop(PP_Instance pp_instance, PP_Bool on_top) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance); + if (dispatcher) { + dispatcher->Send(new PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop( + INTERFACE_ID_PPB_FLASH, pp_instance, on_top)); + } +} + +PP_Bool DrawGlyphs(PP_Instance instance, + PP_Resource pp_image_data, + const PP_FontDescription_Dev* font_desc, + uint32_t color, + PP_Point position, + PP_Rect clip, + const float transformation[3][3], + uint32_t glyph_count, + const uint16_t glyph_indices[], + const PP_Point glyph_advances[]) { + PluginResource* image_data = PluginResourceTracker::GetInstance()-> + GetResourceObject(pp_image_data); + if (!image_data) + return PP_FALSE; + // The instance parameter isn't strictly necessary but we check that it + // matches anyway. + if (image_data->instance() != instance) + return PP_FALSE; + + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance( + image_data->instance()); + if (!dispatcher) + return PP_FALSE; + + PPBFlash_DrawGlyphs_Params params; + params.image_data = image_data->host_resource(); + params.font_desc.SetFromPPFontDescription(dispatcher, *font_desc, true); + params.color = color; + params.position = position; + params.clip = clip; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) + params.transformation[i][j] = transformation[i][j]; + } + + params.glyph_indices.insert(params.glyph_indices.begin(), + &glyph_indices[0], + &glyph_indices[glyph_count]); + params.glyph_advances.insert(params.glyph_advances.begin(), + &glyph_advances[0], + &glyph_advances[glyph_count]); + + PP_Bool result = PP_FALSE; + dispatcher->Send(new PpapiHostMsg_PPBFlash_DrawGlyphs( + INTERFACE_ID_PPB_FLASH, params, &result)); + return result; +} + +PP_Var GetProxyForURL(PP_Instance instance, const char* url) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBFlash_GetProxyForURL( + INTERFACE_ID_PPB_FLASH, instance, url, &result)); + return result.Return(dispatcher); +} + +int32_t Navigate(PP_Resource request_id, + const char* target, + bool from_user_action) { + PluginResource* request_object = + PluginResourceTracker::GetInstance()->GetResourceObject(request_id); + if (!request_object) + return PP_ERROR_BADRESOURCE; + + PluginDispatcher* dispatcher = + PluginDispatcher::GetForInstance(request_object->instance()); + if (!dispatcher) + return PP_ERROR_FAILED; + + int32_t result = PP_ERROR_FAILED; + dispatcher->Send(new PpapiHostMsg_PPBFlash_Navigate( + INTERFACE_ID_PPB_FLASH, + request_object->host_resource(), target, from_user_action, + &result)); + return result; +} + +void RunMessageLoop(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + IPC::SyncMessage* msg = new PpapiHostMsg_PPBFlash_RunMessageLoop( + INTERFACE_ID_PPB_FLASH, instance); + msg->EnableMessagePumping(); + dispatcher->Send(msg); +} + +void QuitMessageLoop(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + dispatcher->Send(new PpapiHostMsg_PPBFlash_QuitMessageLoop( + INTERFACE_ID_PPB_FLASH, instance)); +} + +double GetLocalTimeZoneOffset(PP_Instance instance, PP_Time t) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0.0; + + // TODO(brettw) on Windows it should be possible to do the time calculation + // in-process since it doesn't need to read files on disk. This will improve + // performance. + // + // On Linux, it would be better to go directly to the browser process for + // this message rather than proxy it through some instance in a renderer. + double result = 0; + dispatcher->Send(new PpapiHostMsg_PPBFlash_GetLocalTimeZoneOffset( + INTERFACE_ID_PPB_FLASH, instance, t, &result)); + return result; +} + +PP_Var GetCommandLineArgs(PP_Module pp_module) { + const PPB_Var_Deprecated* var_deprecated = + static_cast<const PPB_Var_Deprecated*>( + PluginDispatcher::GetInterfaceFromDispatcher( + PPB_VAR_DEPRECATED_INTERFACE)); + std::string args = + pp::proxy::ProxyModule::GetInstance()->GetFlashCommandLineArgs(); + return var_deprecated->VarFromUtf8(pp_module, args.data(), args.length()); +} + +const PPB_Flash flash_interface = { + &SetInstanceAlwaysOnTop, + &DrawGlyphs, + &GetProxyForURL, + &Navigate, + &RunMessageLoop, + &QuitMessageLoop, + &GetLocalTimeZoneOffset, + &GetCommandLineArgs +}; + +InterfaceProxy* CreateFlashProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Flash_Proxy::PPB_Flash_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Flash_Proxy::~PPB_Flash_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_Proxy::GetInfo() { + static const Info info = { + &flash_interface, + PPB_FLASH_INTERFACE, + INTERFACE_ID_PPB_FLASH, + true, + &CreateFlashProxy, + }; + return &info; +} + +bool PPB_Flash_Proxy::OnMessageReceived(const IPC::Message& msg) { + // Prevent the dispatcher from going away during a call to Navigate. + // This must happen OUTSIDE of OnMsgNavigate since the handling code use + // the dispatcher upon return of the function (sending the reply message). + ScopedModuleReference death_grip(dispatcher()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop, + OnMsgSetInstanceAlwaysOnTop) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_DrawGlyphs, + OnMsgDrawGlyphs) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetProxyForURL, + OnMsgGetProxyForURL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_Navigate, OnMsgNavigate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_RunMessageLoop, + OnMsgRunMessageLoop) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_QuitMessageLoop, + OnMsgQuitMessageLoop) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlash_GetLocalTimeZoneOffset, + OnMsgGetLocalTimeZoneOffset) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Flash_Proxy::OnMsgSetInstanceAlwaysOnTop( + PP_Instance instance, + PP_Bool on_top) { + ppb_flash_target()->SetInstanceAlwaysOnTop(instance, on_top); +} + +void PPB_Flash_Proxy::OnMsgDrawGlyphs( + const pp::proxy::PPBFlash_DrawGlyphs_Params& params, + PP_Bool* result) { + *result = PP_FALSE; + + PP_FontDescription_Dev font_desc; + params.font_desc.SetToPPFontDescription(dispatcher(), &font_desc, false); + + if (params.glyph_indices.size() != params.glyph_advances.size() || + params.glyph_indices.empty()) + return; + + *result = ppb_flash_target()->DrawGlyphs( + 0, // Unused instance param. + params.image_data.host_resource(), &font_desc, + params.color, params.position, params.clip, + const_cast<float(*)[3]>(params.transformation), + static_cast<uint32_t>(params.glyph_indices.size()), + const_cast<uint16_t*>(¶ms.glyph_indices[0]), + const_cast<PP_Point*>(¶ms.glyph_advances[0])); +} + +void PPB_Flash_Proxy::OnMsgGetProxyForURL(PP_Instance instance, + const std::string& url, + SerializedVarReturnValue result) { + result.Return(dispatcher(), ppb_flash_target()->GetProxyForURL( + instance, url.c_str())); +} + +void PPB_Flash_Proxy::OnMsgNavigate(const HostResource& request_info, + const std::string& target, + bool from_user_action, + int32_t* result) { + DCHECK(!dispatcher()->IsPlugin()); + // We need to allow re-entrancy here, because this may call into Javascript + // (e.g. with a "javascript:" URL), or do things like navigate away from the + // page, either one of which will need to re-enter into the plugin. + // It is safe, because it is essentially equivalent to NPN_GetURL, where Flash + // would expect re-entrancy. When running in-process, it does re-enter here. + static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); + *result = ppb_flash_target()->Navigate(request_info.host_resource(), + target.c_str(), + from_user_action); +} + +void PPB_Flash_Proxy::OnMsgRunMessageLoop(PP_Instance instance) { + ppb_flash_target()->RunMessageLoop(instance); +} + +void PPB_Flash_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) { + ppb_flash_target()->QuitMessageLoop(instance); +} + +void PPB_Flash_Proxy::OnMsgGetLocalTimeZoneOffset(PP_Instance instance, + PP_Time t, + double* result) { + *result = ppb_flash_target()->GetLocalTimeZoneOffset(instance, t); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_proxy.h b/ppapi/proxy/ppb_flash_proxy.h new file mode 100644 index 0000000..8316135 --- /dev/null +++ b/ppapi/proxy/ppb_flash_proxy.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_FLASH_PROXY_H_ +#define PPAPI_PPB_FLASH_PROXY_H_ + +#include <string> +#include <vector> + +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_time.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PP_FileInfo; +struct PPB_Flash; + +namespace pp { +namespace proxy { + +struct PPBFlash_DrawGlyphs_Params; +class SerializedVarReturnValue; + +class PPB_Flash_Proxy : public InterfaceProxy { + public: + PPB_Flash_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Flash_Proxy(); + + static const Info* GetInfo(); + + const PPB_Flash* ppb_flash_target() const { + return static_cast<const PPB_Flash*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgSetInstanceAlwaysOnTop(PP_Instance instance, + PP_Bool on_top); + void OnMsgDrawGlyphs(const pp::proxy::PPBFlash_DrawGlyphs_Params& params, + PP_Bool* result); + void OnMsgGetProxyForURL(PP_Instance instance, + const std::string& url, + SerializedVarReturnValue result); + void OnMsgNavigate(const HostResource& request_info, + const std::string& target, + bool from_user_action, + int32_t* result); + void OnMsgRunMessageLoop(PP_Instance instance); + void OnMsgQuitMessageLoop(PP_Instance instance); + void OnMsgGetLocalTimeZoneOffset(PP_Instance instance, PP_Time t, + double* result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_FLASH_PROXY_H_ diff --git a/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc b/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc new file mode 100644 index 0000000..6a6ab50 --- /dev/null +++ b/ppapi/proxy/ppb_flash_tcp_socket_proxy.cc @@ -0,0 +1,439 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_flash_tcp_socket_proxy.h" + +#include <algorithm> +#include <cstring> +#include <map> + +#include "base/logging.h" +#include "base/memory/linked_ptr.h" +#include "base/message_loop.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/ppb_flash_tcp_socket_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::PPB_Flash_TCPSocket_API; + +namespace pp { +namespace proxy { + +const int32_t kFlashTCPSocketMaxReadSize = 1024 * 1024; +const int32_t kFlashTCPSocketMaxWriteSize = 1024 * 1024; + +class FlashTCPSocket; + +namespace { + +typedef std::map<uint32, FlashTCPSocket*> IDToSocketMap; +IDToSocketMap* g_id_to_socket = NULL; + +class AbortCallbackTask : public Task { + public: + explicit AbortCallbackTask(PP_CompletionCallback callback) + : callback_(callback) {} + virtual ~AbortCallbackTask() {} + virtual void Run() { + if (callback_.func) + PP_RunCompletionCallback(&callback_, PP_ERROR_ABORTED); + } + + private: + PP_CompletionCallback callback_; +}; + +InterfaceProxy* CreateFlashTCPSocketProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Flash_TCPSocket_Proxy(dispatcher, target_interface); +} + +} // namespace + +class FlashTCPSocket : public PPB_Flash_TCPSocket_API, + public PluginResource { + public: + FlashTCPSocket(const HostResource& resource, uint32 socket_id); + virtual ~FlashTCPSocket(); + + // ResourceObjectBase overrides. + virtual PPB_Flash_TCPSocket_API* AsPPB_Flash_TCPSocket_API() OVERRIDE; + + // PPB_Flash_TCPSocket_API implementation. + virtual int32_t Connect(const char* host, + uint16_t port, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t ConnectWithNetAddress( + const PP_Flash_NetAddress* addr, + PP_CompletionCallback callback) OVERRIDE; + virtual PP_Bool GetLocalAddress(PP_Flash_NetAddress* local_addr) OVERRIDE; + virtual PP_Bool GetRemoteAddress(PP_Flash_NetAddress* remote_addr) OVERRIDE; + virtual int32_t InitiateSSL(const char* server_name, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Read(char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Write(const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) OVERRIDE; + virtual void Disconnect() OVERRIDE; + + // Notifications from the proxy. + void OnConnectCompleted(bool succeeded, + const PP_Flash_NetAddress& local_addr, + const PP_Flash_NetAddress& remote_addr); + void OnReadCompleted(bool succeeded, const std::string& data); + void OnWriteCompleted(bool succeeded, int32_t bytes_written); + + private: + enum ConnectionState { + // Before a connection is successfully established (including a connect + // request is pending or a previous connect request failed). + BEFORE_CONNECT, + CONNECTED, + DISCONNECTED + }; + + // Backend for both Connect() and ConnectWithNetAddress(). To keep things + // generic, the message is passed in (on error, it's deleted). + int32_t ConnectWithMessage(IPC::Message* msg, + PP_CompletionCallback callback); + + void PostAbortAndClearIfNecessary(PP_CompletionCallback* callback); + + uint32 socket_id_; + ConnectionState connection_state_; + + PP_CompletionCallback connect_callback_; + PP_CompletionCallback read_callback_; + PP_CompletionCallback write_callback_; + + char* read_buffer_; + int32_t bytes_to_read_; + + PP_Flash_NetAddress local_addr_; + PP_Flash_NetAddress remote_addr_; + + DISALLOW_COPY_AND_ASSIGN(FlashTCPSocket); +}; + +FlashTCPSocket::FlashTCPSocket(const HostResource& resource, uint32 socket_id) + : PluginResource(resource), + socket_id_(socket_id), + connection_state_(BEFORE_CONNECT), + connect_callback_(PP_BlockUntilComplete()), + read_callback_(PP_BlockUntilComplete()), + write_callback_(PP_BlockUntilComplete()), + read_buffer_(NULL), + bytes_to_read_(-1) { + DCHECK(socket_id != 0); + + local_addr_.size = 0; + memset(local_addr_.data, 0, sizeof(local_addr_.data)); + remote_addr_.size = 0; + memset(remote_addr_.data, 0, sizeof(remote_addr_.data)); + + if (!g_id_to_socket) + g_id_to_socket = new IDToSocketMap(); + DCHECK(g_id_to_socket->find(socket_id) == g_id_to_socket->end()); + (*g_id_to_socket)[socket_id] = this; +} + +FlashTCPSocket::~FlashTCPSocket() { + Disconnect(); +} + +PPB_Flash_TCPSocket_API* FlashTCPSocket::AsPPB_Flash_TCPSocket_API() { + return this; +} + +int32_t FlashTCPSocket::Connect(const char* host, + uint16_t port, + PP_CompletionCallback callback) { + if (!host) + return PP_ERROR_BADARGUMENT; + + return ConnectWithMessage( + new PpapiHostMsg_PPBFlashTCPSocket_Connect(socket_id_, host, port), + callback); +} + +int32_t FlashTCPSocket::ConnectWithNetAddress( + const PP_Flash_NetAddress* addr, + PP_CompletionCallback callback) { + if (!addr) + return PP_ERROR_BADARGUMENT; + + return ConnectWithMessage( + new PpapiHostMsg_PPBFlashTCPSocket_ConnectWithNetAddress( + socket_id_, *addr), + callback); +} + +PP_Bool FlashTCPSocket::GetLocalAddress(PP_Flash_NetAddress* local_addr) { + if (connection_state_ != CONNECTED || !local_addr) + return PP_FALSE; + + *local_addr = local_addr_; + return PP_TRUE; +} + +PP_Bool FlashTCPSocket::GetRemoteAddress(PP_Flash_NetAddress* remote_addr) { + if (connection_state_ != CONNECTED || !remote_addr) + return PP_FALSE; + + *remote_addr = remote_addr_; + return PP_TRUE; +} + +int32_t FlashTCPSocket::InitiateSSL(const char* server_name, + PP_CompletionCallback callback) { + // TODO(yzshen): add it. + return PP_ERROR_FAILED; +} + +int32_t FlashTCPSocket::Read(char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + if (!buffer || bytes_to_read <= 0 || !callback.func) + return PP_ERROR_BADARGUMENT; + + if (connection_state_ != CONNECTED) + return PP_ERROR_FAILED; + if (read_callback_.func) + return PP_ERROR_INPROGRESS; + + read_buffer_ = buffer; + bytes_to_read_ = std::min(bytes_to_read, kFlashTCPSocketMaxReadSize); + read_callback_ = callback; + + // Send the request, the browser will call us back via ReadACK. + GetDispatcher()->SendToBrowser( + new PpapiHostMsg_PPBFlashTCPSocket_Read(socket_id_, bytes_to_read_)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FlashTCPSocket::Write(const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + if (!buffer || bytes_to_write <= 0 || !callback.func) + return PP_ERROR_BADARGUMENT; + + if (connection_state_ != CONNECTED) + return PP_ERROR_FAILED; + if (write_callback_.func) + return PP_ERROR_INPROGRESS; + + if (bytes_to_write > kFlashTCPSocketMaxWriteSize) + bytes_to_write = kFlashTCPSocketMaxWriteSize; + + write_callback_ = callback; + + // Send the request, the browser will call us back via WriteACK. + GetDispatcher()->SendToBrowser( + new PpapiHostMsg_PPBFlashTCPSocket_Write( + socket_id_, std::string(buffer, bytes_to_write))); + return PP_OK_COMPLETIONPENDING; +} + +void FlashTCPSocket::Disconnect() { + if (connection_state_ == DISCONNECTED) + return; + + connection_state_ = DISCONNECTED; + // After removed from the mapping, this object won't receive any notfications + // from the proxy. + DCHECK(g_id_to_socket->find(socket_id_) != g_id_to_socket->end()); + g_id_to_socket->erase(socket_id_); + + GetDispatcher()->SendToBrowser( + new PpapiHostMsg_PPBFlashTCPSocket_Disconnect(socket_id_)); + socket_id_ = 0; + + PostAbortAndClearIfNecessary(&connect_callback_); + PostAbortAndClearIfNecessary(&read_callback_); + PostAbortAndClearIfNecessary(&write_callback_); + read_buffer_ = NULL; + bytes_to_read_ = -1; +} + +void FlashTCPSocket::OnConnectCompleted( + bool succeeded, + const PP_Flash_NetAddress& local_addr, + const PP_Flash_NetAddress& remote_addr) { + if (connection_state_ != BEFORE_CONNECT || !connect_callback_.func) { + NOTREACHED(); + return; + } + + if (succeeded) { + local_addr_ = local_addr; + remote_addr_ = remote_addr; + connection_state_ = CONNECTED; + } + PP_RunAndClearCompletionCallback(&connect_callback_, + succeeded ? PP_OK : PP_ERROR_FAILED); +} + +void FlashTCPSocket::OnReadCompleted(bool succeeded, const std::string& data) { + if (!read_callback_.func || !read_buffer_) { + NOTREACHED(); + return; + } + + if (succeeded) { + CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_); + if (!data.empty()) + memcpy(read_buffer_, data.c_str(), data.size()); + } + read_buffer_ = NULL; + bytes_to_read_ = -1; + + PP_RunAndClearCompletionCallback( + &read_callback_, + succeeded ? static_cast<int32_t>(data.size()) : + static_cast<int32_t>(PP_ERROR_FAILED)); +} + +void FlashTCPSocket::OnWriteCompleted(bool succeeded, int32_t bytes_written) { + if (!write_callback_.func || (succeeded && bytes_written < 0)) { + NOTREACHED(); + return; + } + + PP_RunAndClearCompletionCallback( + &write_callback_, + succeeded ? bytes_written : static_cast<int32_t>(PP_ERROR_FAILED)); +} + +int32_t FlashTCPSocket::ConnectWithMessage(IPC::Message* msg, + PP_CompletionCallback callback) { + scoped_ptr<IPC::Message> msg_deletor(msg); + if (!callback.func) + return PP_ERROR_BADARGUMENT; + if (connection_state_ != BEFORE_CONNECT) + return PP_ERROR_FAILED; + if (connect_callback_.func) + return PP_ERROR_INPROGRESS; // Can only have one pending request. + + connect_callback_ = callback; + // Send the request, the browser will call us back via ConnectACK. + GetDispatcher()->SendToBrowser(msg_deletor.release()); + return PP_OK_COMPLETIONPENDING; +} + +void FlashTCPSocket::PostAbortAndClearIfNecessary( + PP_CompletionCallback* callback) { + DCHECK(callback); + + if (callback->func) { + MessageLoop::current()->PostTask(FROM_HERE, + new AbortCallbackTask(*callback)); + *callback = PP_BlockUntilComplete(); + } +} + +PPB_Flash_TCPSocket_Proxy::PPB_Flash_TCPSocket_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Flash_TCPSocket_Proxy::~PPB_Flash_TCPSocket_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Flash_TCPSocket_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_Flash_TCPSocket_Thunk(), + PPB_FLASH_TCPSOCKET_INTERFACE, + INTERFACE_ID_PPB_FLASH_TCPSOCKET, + false, + &CreateFlashTCPSocketProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Flash_TCPSocket_Proxy::CreateProxyResource( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + uint32 socket_id = 0; + dispatcher->SendToBrowser(new PpapiHostMsg_PPBFlashTCPSocket_Create( + INTERFACE_ID_PPB_FLASH_TCPSOCKET, dispatcher->plugin_dispatcher_id(), + &socket_id)); + if (socket_id == 0) + return 0; + + linked_ptr<FlashTCPSocket> object(new FlashTCPSocket( + HostResource::MakeInstanceOnly(instance), socket_id)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_Flash_TCPSocket_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Flash_TCPSocket_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_ConnectACK, OnMsgConnectACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_ReadACK, OnMsgReadACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBFlashTCPSocket_WriteACK, OnMsgWriteACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Flash_TCPSocket_Proxy::OnMsgConnectACK( + uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + bool succeeded, + const PP_Flash_NetAddress& local_addr, + const PP_Flash_NetAddress& remote_addr) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnConnectCompleted(succeeded, local_addr, remote_addr); +} + +void PPB_Flash_TCPSocket_Proxy::OnMsgReadACK(uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + bool succeeded, + const std::string& data) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnReadCompleted(succeeded, data); +} + +void PPB_Flash_TCPSocket_Proxy::OnMsgWriteACK(uint32 /* plugin_dispatcher_id */, + uint32 socket_id, + bool succeeded, + int32_t bytes_written) { + if (!g_id_to_socket) { + NOTREACHED(); + return; + } + IDToSocketMap::iterator iter = g_id_to_socket->find(socket_id); + if (iter == g_id_to_socket->end()) + return; + iter->second->OnWriteCompleted(succeeded, bytes_written); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_flash_tcp_socket_proxy.h b/ppapi/proxy/ppb_flash_tcp_socket_proxy.h new file mode 100644 index 0000000..aac9bbd --- /dev/null +++ b/ppapi/proxy/ppb_flash_tcp_socket_proxy.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FLASH_TCP_SOCKET_PROXY_H_ +#define PPAPI_PROXY_PPB_FLASH_TCP_SOCKET_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_flash_tcp_socket.h" +#include "ppapi/proxy/interface_proxy.h" + +namespace pp { +namespace proxy { + +// The maximum number of bytes that each PpapiHostMsg_PPBFlashTCPSocket_Read +// message is allowed to request. +extern const int32_t kFlashTCPSocketMaxReadSize; +// The maximum number of bytes that each PpapiHostMsg_PPBFlashTCPSocket_Write +// message is allowed to carry. +extern const int32_t kFlashTCPSocketMaxWriteSize; + +class PPB_Flash_TCPSocket_Proxy : public InterfaceProxy { + public: + PPB_Flash_TCPSocket_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Flash_TCPSocket_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Browser->plugin message handlers. + void OnMsgConnectACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + bool succeeded, + const PP_Flash_NetAddress& local_addr, + const PP_Flash_NetAddress& remote_addr); + void OnMsgReadACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + bool succeeded, + const std::string& data); + void OnMsgWriteACK(uint32 plugin_dispatcher_id, + uint32 socket_id, + bool succeeded, + int32_t bytes_written); + + DISALLOW_COPY_AND_ASSIGN(PPB_Flash_TCPSocket_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FLASH_TCP_SOCKET_PROXY_H_ diff --git a/ppapi/proxy/ppb_font_proxy.cc b/ppapi/proxy/ppb_font_proxy.cc new file mode 100644 index 0000000..38b00e2 --- /dev/null +++ b/ppapi/proxy/ppb_font_proxy.cc @@ -0,0 +1,233 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_font_proxy.h" + +#include "base/bind.h" +#include "base/debug/trace_event.h" +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/shared_impl/ppapi_preferences.h" +#include "ppapi/shared_impl/resource_object_base.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_ImageData_API; +using ppapi::WebKitForwarding; + +namespace pp { +namespace proxy { + +namespace { + +bool PPTextRunToTextRun(const PP_TextRun_Dev* run, + WebKitForwarding::Font::TextRun* output) { + const std::string* str = PluginVarTracker::GetInstance()->GetExistingString( + run->text); + if (!str) + return false; + + output->text = *str; + output->rtl = PP_ToBool(run->rtl); + output->override_direction = PP_ToBool(run->override_direction); + return true; +} + +InterfaceProxy* CreateFontProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Font_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Font_Proxy::PPB_Font_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Font_Proxy::~PPB_Font_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Font_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_Font_Thunk(), + PPB_FONT_DEV_INTERFACE, + INTERFACE_ID_PPB_FONT, + false, + &CreateFontProxy, + }; + return &info; +} + +::ppapi::thunk::PPB_Font_FunctionAPI* PPB_Font_Proxy::AsPPB_Font_FunctionAPI() { + return this; +} + +PP_Var PPB_Font_Proxy::GetFontFamilies(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + // Assume the font families don't change, so we can cache the result globally. + static std::string families; + if (families.empty()) { + dispatcher->SendToBrowser( + new PpapiHostMsg_PPBFont_GetFontFamilies(&families)); + } + + PP_Var result; + result.type = PP_VARTYPE_STRING; + result.value.as_id = PluginVarTracker::GetInstance()->MakeString(families); + return result; +} + +bool PPB_Font_Proxy::OnMessageReceived(const IPC::Message& msg) { + // There aren't any font messages. + NOTREACHED(); + return false; +} + +Font::Font(const HostResource& resource, + const PP_FontDescription_Dev& desc) + : PluginResource(resource), + webkit_event_(false, false) { + TRACE_EVENT0("ppapi proxy", "Font::Font"); + const std::string* face = PluginVarTracker::GetInstance()->GetExistingString( + desc.face); + + WebKitForwarding* forwarding = GetDispatcher()->GetWebKitForwarding(); + + WebKitForwarding::Font* result = NULL; + RunOnWebKitThread(base::Bind(&WebKitForwarding::CreateFontForwarding, + base::Unretained(forwarding), + &webkit_event_, desc, + face ? *face : std::string(), + GetDispatcher()->preferences(), + &result)); + font_forwarding_.reset(result); +} + +Font::~Font() { +} + +ppapi::thunk::PPB_Font_API* Font::AsPPB_Font_API() { + return this; +} + +Font* Font::AsFont() { + return this; +} + +PP_Bool Font::Describe(PP_FontDescription_Dev* description, + PP_FontMetrics_Dev* metrics) { + TRACE_EVENT0("ppapi proxy", "Font::Describe"); + std::string face; + PP_Bool result = PP_FALSE; + RunOnWebKitThread(base::Bind(&WebKitForwarding::Font::Describe, + base::Unretained(font_forwarding_.get()), + &webkit_event_, description, &face, metrics, + &result)); + + if (result == PP_TRUE) { + description->face.type = PP_VARTYPE_STRING; + description->face.value.as_id = + PluginVarTracker::GetInstance()->MakeString(face); + } else { + description->face.type = PP_VARTYPE_UNDEFINED; + } + return result; +} + +PP_Bool Font::DrawTextAt(PP_Resource pp_image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + PP_Bool image_data_is_opaque) { + TRACE_EVENT0("ppapi proxy", "Font::DrawTextAt"); + // Convert to an ImageData object. + EnterResourceNoLock<PPB_ImageData_API> enter(pp_image_data, true); + if (enter.failed()) + return PP_FALSE; + ImageData* image_data = static_cast<ImageData*>(enter.object()); + + skia::PlatformCanvas* canvas = image_data->mapped_canvas(); + bool needs_unmapping = false; + if (!canvas) { + needs_unmapping = true; + image_data->Map(); + canvas = image_data->mapped_canvas(); + if (!canvas) + return PP_FALSE; // Failure mapping. + } + + WebKitForwarding::Font::TextRun run; + if (!PPTextRunToTextRun(text, &run)) { + if (needs_unmapping) + image_data->Unmap(); + return PP_FALSE; + } + RunOnWebKitThread(base::Bind( + &WebKitForwarding::Font::DrawTextAt, + base::Unretained(font_forwarding_.get()), + &webkit_event_, + WebKitForwarding::Font::DrawTextParams(canvas, run, position, color, + clip, image_data_is_opaque))); + + if (needs_unmapping) + image_data->Unmap(); + return PP_TRUE; +} + +int32_t Font::MeasureText(const PP_TextRun_Dev* text) { + TRACE_EVENT0("ppapi proxy", "Font::MeasureText"); + WebKitForwarding::Font::TextRun run; + if (!PPTextRunToTextRun(text, &run)) + return -1; + int32_t result = -1; + RunOnWebKitThread(base::Bind(&WebKitForwarding::Font::MeasureText, + base::Unretained(font_forwarding_.get()), + &webkit_event_, run, &result)); + return result; +} + +uint32_t Font::CharacterOffsetForPixel(const PP_TextRun_Dev* text, + int32_t pixel_position) { + TRACE_EVENT0("ppapi proxy", "Font::CharacterOffsetForPixel"); + WebKitForwarding::Font::TextRun run; + if (!PPTextRunToTextRun(text, &run)) + return -1; + uint32_t result = -1; + RunOnWebKitThread(base::Bind(&WebKitForwarding::Font::CharacterOffsetForPixel, + base::Unretained(font_forwarding_.get()), + &webkit_event_, run, pixel_position, &result)); + return result; +} + +int32_t Font::PixelOffsetForCharacter(const PP_TextRun_Dev* text, + uint32_t char_offset) { + TRACE_EVENT0("ppapi proxy", "Font::PixelOffsetForCharacter"); + WebKitForwarding::Font::TextRun run; + if (!PPTextRunToTextRun(text, &run)) + return -1; + int32_t result = -1; + RunOnWebKitThread(base::Bind(&WebKitForwarding::Font::PixelOffsetForCharacter, + base::Unretained(font_forwarding_.get()), + &webkit_event_, run, char_offset, &result)); + return result; +} + +void Font::RunOnWebKitThread(const base::Closure& task) { + GetDispatcher()->PostToWebKitThread(FROM_HERE, task); + webkit_event_.Wait(); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_font_proxy.h b/ppapi/proxy/ppb_font_proxy.h new file mode 100644 index 0000000..32893ea --- /dev/null +++ b/ppapi/proxy/ppb_font_proxy.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_FONT_PROXY_H_ +#define PPAPI_PROXY_PPB_FONT_PROXY_H_ + +#include "base/basictypes.h" +#include "base/synchronization/waitable_event.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/shared_impl/webkit_forwarding.h" +#include "ppapi/thunk/ppb_font_api.h" + +struct PPB_Font_Dev; + +namespace pp { +namespace proxy { + +class SerializedVarReturnValue; + +class PPB_Font_Proxy : public ppapi::FunctionGroupBase, + public ppapi::thunk::PPB_Font_FunctionAPI, + public InterfaceProxy { + public: + PPB_Font_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Font_Proxy(); + + static const Info* GetInfo(); + + // FunctionGroupBase overrides. + virtual ppapi::thunk::PPB_Font_FunctionAPI* AsPPB_Font_FunctionAPI() OVERRIDE; + + // PPB_Font_FunctionAPI implementation. + virtual PP_Var GetFontFamilies(PP_Instance instance) OVERRIDE; + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_Font_Proxy); +}; + +class Font : public PluginResource, + public ppapi::thunk::PPB_Font_API { + public: + // Note that there isn't a "real" resource in the renderer backing a font, + // it lives entirely in the plugin process. So the resource ID in the host + // resource should be 0. However, various code assumes the instance in the + // host resource is valid (this is how resources are associated with + // instances), so that should be set. + Font(const HostResource& resource, const PP_FontDescription_Dev& desc); + virtual ~Font(); + + // ResourceObjectBase. + virtual ppapi::thunk::PPB_Font_API* AsPPB_Font_API() OVERRIDE; + + // PluginResource overrides. + virtual Font* AsFont() OVERRIDE; + + // PPB_Font_API implementation. + virtual PP_Bool Describe(PP_FontDescription_Dev* description, + PP_FontMetrics_Dev* metrics) OVERRIDE; + virtual PP_Bool DrawTextAt(PP_Resource image_data, + const PP_TextRun_Dev* text, + const PP_Point* position, + uint32_t color, + const PP_Rect* clip, + PP_Bool image_data_is_opaque) OVERRIDE; + virtual int32_t MeasureText(const PP_TextRun_Dev* text) OVERRIDE; + virtual uint32_t CharacterOffsetForPixel(const PP_TextRun_Dev* text, + int32_t pixel_position) OVERRIDE; + virtual int32_t PixelOffsetForCharacter(const PP_TextRun_Dev* text, + uint32_t char_offset) OVERRIDE; + + private: + // Posts the given closure to the WebKit thread and waits on the + // webkit_event_ for the task to continue. + void RunOnWebKitThread(const base::Closure& task); + + base::WaitableEvent webkit_event_; + + scoped_ptr<ppapi::WebKitForwarding::Font> font_forwarding_; + + DISALLOW_COPY_AND_ASSIGN(Font); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_FONT_PROXY_H_ diff --git a/ppapi/proxy/ppb_graphics_2d_proxy.cc b/ppapi/proxy/ppb_graphics_2d_proxy.cc new file mode 100644 index 0000000..0f8a247 --- /dev/null +++ b/ppapi/proxy/ppb_graphics_2d_proxy.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_graphics_2d_proxy.h" + +#include <string.h> // For memset. + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_graphics_2d.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_graphics_2d_api.h" +#include "ppapi/thunk/thunk.h" + +using ::ppapi::thunk::PPB_Graphics2D_API; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateGraphics2DProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Graphics2D_Proxy(dispatcher, target_interface); +} + +} // namespace + +class Graphics2D : public PluginResource, + public ::ppapi::thunk::PPB_Graphics2D_API { + public: + Graphics2D(const HostResource& host_resource, + const PP_Size& size, + PP_Bool is_always_opaque); + virtual ~Graphics2D(); + + // ResourceObjectBase. + virtual PPB_Graphics2D_API* AsPPB_Graphics2D_API(); + + // PPB_Graphics_2D_API. + PP_Bool Describe(PP_Size* size, PP_Bool* is_always_opaque); + void PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect); + void Scroll(const PP_Rect* clip_rect, + const PP_Point* amount); + void ReplaceContents(PP_Resource image_data); + int32_t Flush(PP_CompletionCallback callback); + + // Notification that the host has sent an ACK for a pending Flush. + void FlushACK(int32_t result_code); + + private: + PP_Size size_; + PP_Bool is_always_opaque_; + + // In the plugin, this is the current callback set for Flushes. When the + // callback function pointer is non-NULL, we're waiting for a flush ACK. + PP_CompletionCallback current_flush_callback_; + + DISALLOW_COPY_AND_ASSIGN(Graphics2D); +}; + +Graphics2D::Graphics2D(const HostResource& host_resource, + const PP_Size& size, + PP_Bool is_always_opaque) + : PluginResource(host_resource), + size_(size), + is_always_opaque_(is_always_opaque), + current_flush_callback_(PP_BlockUntilComplete()) { +} + +Graphics2D::~Graphics2D() { +} + +PPB_Graphics2D_API* Graphics2D::AsPPB_Graphics2D_API() { + return this; +} + +PP_Bool Graphics2D::Describe(PP_Size* size, PP_Bool* is_always_opaque) { + *size = size_; + *is_always_opaque = is_always_opaque_; + return PP_TRUE; +} + +void Graphics2D::PaintImageData(PP_Resource image_data, + const PP_Point* top_left, + const PP_Rect* src_rect) { + PluginResource* image_object = PluginResourceTracker::GetInstance()-> + GetResourceObject(image_data); + //if (!image_object || instance() != image_object->instance()) + // return; + + PP_Rect dummy; + memset(&dummy, 0, sizeof(PP_Rect)); + GetDispatcher()->Send(new PpapiHostMsg_PPBGraphics2D_PaintImageData( + INTERFACE_ID_PPB_GRAPHICS_2D, host_resource(), + image_object->host_resource(), *top_left, !!src_rect, + src_rect ? *src_rect : dummy)); +} + +void Graphics2D::Scroll(const PP_Rect* clip_rect, + const PP_Point* amount) { + PP_Rect dummy; + memset(&dummy, 0, sizeof(PP_Rect)); + GetDispatcher()->Send(new PpapiHostMsg_PPBGraphics2D_Scroll( + INTERFACE_ID_PPB_GRAPHICS_2D, host_resource(), + !!clip_rect, clip_rect ? *clip_rect : dummy, *amount)); +} + +void Graphics2D::ReplaceContents(PP_Resource image_data) { + PluginResource* image_object = PluginResourceTracker::GetInstance()-> + GetResourceObject(image_data); + if (!image_object || instance() != image_object->instance()) + return; + + GetDispatcher()->Send(new PpapiHostMsg_PPBGraphics2D_ReplaceContents( + INTERFACE_ID_PPB_GRAPHICS_2D, host_resource(), + image_object->host_resource())); +} + +int32_t Graphics2D::Flush(PP_CompletionCallback callback) { + // For now, disallow blocking calls. We'll need to add support for other + // threads to this later. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + if (current_flush_callback_.func) + return PP_ERROR_INPROGRESS; // Can't have >1 flush pending. + current_flush_callback_ = callback; + + GetDispatcher()->Send(new PpapiHostMsg_PPBGraphics2D_Flush( + INTERFACE_ID_PPB_GRAPHICS_2D, host_resource())); + return PP_OK_COMPLETIONPENDING; +} + +void Graphics2D::FlushACK(int32_t result_code) { + PP_RunAndClearCompletionCallback(¤t_flush_callback_, result_code); +} + +PPB_Graphics2D_Proxy::PPB_Graphics2D_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Graphics2D_Proxy::~PPB_Graphics2D_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Graphics2D_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_Graphics2D_Thunk(), + PPB_GRAPHICS_2D_INTERFACE, + INTERFACE_ID_PPB_GRAPHICS_2D, + false, + &CreateGraphics2DProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Graphics2D_Proxy::CreateProxyResource( + PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_ResourceCreation_Graphics2D( + INTERFACE_ID_RESOURCE_CREATION, instance, size, is_always_opaque, + &result)); + if (result.is_null()) + return 0; + linked_ptr<Graphics2D> graphics_2d(new Graphics2D(result, size, + is_always_opaque)); + return PluginResourceTracker::GetInstance()->AddResource(graphics_2d); +} + +bool PPB_Graphics2D_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Graphics2D_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics2D_PaintImageData, + OnMsgPaintImageData) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics2D_Scroll, + OnMsgScroll) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics2D_ReplaceContents, + OnMsgReplaceContents) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics2D_Flush, + OnMsgFlush) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics2D_FlushACK, + OnMsgFlushACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // FIXME(brettw) handle bad messages! + return handled; +} + +void PPB_Graphics2D_Proxy::OnMsgPaintImageData( + const HostResource& graphics_2d, + const HostResource& image_data, + const PP_Point& top_left, + bool src_rect_specified, + const PP_Rect& src_rect) { + EnterHostFromHostResource<PPB_Graphics2D_API> enter(graphics_2d); + if (enter.failed()) + return; + enter.object()->PaintImageData(image_data.host_resource(), &top_left, + src_rect_specified ? &src_rect : NULL); +} + +void PPB_Graphics2D_Proxy::OnMsgScroll(const HostResource& graphics_2d, + bool clip_specified, + const PP_Rect& clip, + const PP_Point& amount) { + EnterHostFromHostResource<PPB_Graphics2D_API> enter(graphics_2d); + if (enter.failed()) + return; + enter.object()->Scroll(clip_specified ? &clip : NULL, &amount); +} + +void PPB_Graphics2D_Proxy::OnMsgReplaceContents( + const HostResource& graphics_2d, + const HostResource& image_data) { + EnterHostFromHostResource<PPB_Graphics2D_API> enter(graphics_2d); + if (enter.failed()) + return; + enter.object()->ReplaceContents(image_data.host_resource()); +} + +void PPB_Graphics2D_Proxy::OnMsgFlush(const HostResource& graphics_2d) { + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Graphics2D_Proxy::SendFlushACKToPlugin, graphics_2d); + int32_t result = ppb_graphics_2d_target()->Flush( + graphics_2d.host_resource(), callback.pp_completion_callback()); + if (result != PP_OK_COMPLETIONPENDING) { + // There was some error, so we won't get a flush callback. We need to now + // issue the ACK to the plugin hears about the error. This will also clean + // up the data associated with the callback. + callback.Run(result); + } +} + +void PPB_Graphics2D_Proxy::OnMsgFlushACK(const HostResource& host_resource, + int32_t pp_error) { + EnterPluginFromHostResource<PPB_Graphics2D_API> enter(host_resource); + if (enter.succeeded()) + static_cast<Graphics2D*>(enter.object())->FlushACK(pp_error); +} + +void PPB_Graphics2D_Proxy::SendFlushACKToPlugin( + int32_t result, + const HostResource& graphics_2d) { + dispatcher()->Send(new PpapiMsg_PPBGraphics2D_FlushACK( + INTERFACE_ID_PPB_GRAPHICS_2D, graphics_2d, result)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_graphics_2d_proxy.h b/ppapi/proxy/ppb_graphics_2d_proxy.h new file mode 100644 index 0000000..9be7f83 --- /dev/null +++ b/ppapi/proxy/ppb_graphics_2d_proxy.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_GRAPHICS_2D_PROXY_H_ +#define PPAPI_PPB_GRAPHICS_2D_PROXY_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_Graphics2D; +struct PP_Point; +struct PP_Rect; + +namespace pp { +namespace proxy { + +class PPB_Graphics2D_Proxy : public InterfaceProxy { + public: + PPB_Graphics2D_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Graphics2D_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque); + + const PPB_Graphics2D* ppb_graphics_2d_target() const { + return static_cast<const PPB_Graphics2D*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Plugin->renderer message handlers. + void OnMsgPaintImageData(const HostResource& graphics_2d, + const HostResource& image_data, + const PP_Point& top_left, + bool src_rect_specified, + const PP_Rect& src_rect); + void OnMsgScroll(const HostResource& graphics_2d, + bool clip_specified, + const PP_Rect& clip, + const PP_Point& amount); + void OnMsgReplaceContents(const HostResource& graphics_2d, + const HostResource& image_data); + void OnMsgFlush(const HostResource& graphics_2d); + + // Renderer->plugin message handlers. + void OnMsgFlushACK(const HostResource& graphics_2d, + int32_t pp_error); + + // Called in the renderer to send the given flush ACK to the plugin. + void SendFlushACKToPlugin(int32_t result, + const HostResource& graphics_2d); + + CompletionCallbackFactory<PPB_Graphics2D_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_GRAPHICS_2D_PROXY_H_ diff --git a/ppapi/proxy/ppb_image_data_proxy.cc b/ppapi/proxy/ppb_image_data_proxy.cc new file mode 100644 index 0000000..18f9e02 --- /dev/null +++ b/ppapi/proxy/ppb_image_data_proxy.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_image_data_proxy.h" + +#include <string.h> // For memcpy + +#include <vector> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/thunk.h" +#include "skia/ext/platform_canvas.h" +#include "ui/gfx/surface/transport_dib.h" + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateImageDataProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_ImageData_Proxy(dispatcher, target_interface); +} + +} // namespace + +// PPB_ImageData_Proxy --------------------------------------------------------- + +PPB_ImageData_Proxy::PPB_ImageData_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_ImageData_Proxy::~PPB_ImageData_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_ImageData_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_ImageData_Thunk(), + PPB_IMAGEDATA_INTERFACE, + INTERFACE_ID_PPB_IMAGE_DATA, + false, + &CreateImageDataProxy, + }; + return &info; +} + +bool PPB_ImageData_Proxy::OnMessageReceived(const IPC::Message& msg) { + return false; +} + +// ImageData ------------------------------------------------------------------- + +ImageData::ImageData(const HostResource& resource, + const PP_ImageDataDesc& desc, + ImageHandle handle) + : PluginResource(resource), + desc_(desc) { +#if defined(OS_WIN) + transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); +#else + transport_dib_.reset(TransportDIB::Map(handle)); +#endif +} + +ImageData::~ImageData() { +} + +::ppapi::thunk::PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { + return this; +} + +ImageData* ImageData::AsImageData() { + return this; +} + +PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { + memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); + return PP_TRUE; +} + +void* ImageData::Map() { + if (!mapped_canvas_.get()) { + mapped_canvas_.reset(transport_dib_->GetPlatformCanvas(desc_.size.width, + desc_.size.height)); + if (!mapped_canvas_.get()) + return NULL; + } + const SkBitmap& bitmap = + skia::GetTopDevice(*mapped_canvas_)->accessBitmap(true); + + bitmap.lockPixels(); + return bitmap.getAddr(0, 0); +} + +void ImageData::Unmap() { + // TODO(brettw) have a way to unmap a TransportDIB. Currently this isn't + // possible since deleting the TransportDIB also frees all the handles. + // We need to add a method to TransportDIB to release the handles. +} + +int32_t ImageData::GetSharedMemory(int* /* handle */, + uint32_t* /* byte_count */) { + // Not supported in the proxy (this method is for actually implementing the + // proxy in the host). + return PP_ERROR_NOACCESS; +} + +#if defined(OS_WIN) +const ImageHandle ImageData::NullHandle = NULL; +#elif defined(OS_MACOSX) +const ImageHandle ImageData::NullHandle = ImageHandle(); +#else +const ImageHandle ImageData::NullHandle = 0; +#endif + +ImageHandle ImageData::HandleFromInt(int32_t i) { +#if defined(OS_WIN) + return reinterpret_cast<ImageHandle>(i); +#elif defined(OS_MACOSX) + return ImageHandle(i, false); +#else + return static_cast<ImageHandle>(i); +#endif +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_image_data_proxy.h b/ppapi/proxy/ppb_image_data_proxy.h new file mode 100644 index 0000000..23cf442 --- /dev/null +++ b/ppapi/proxy/ppb_image_data_proxy.h @@ -0,0 +1,90 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_IMAGE_DATA_PROXY_H_ +#define PPAPI_PPB_IMAGE_DATA_PROXY_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/image_data_impl.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +struct PPB_ImageData; +class TransportDIB; + +namespace skia { +class PlatformCanvas; +} + +namespace pp { +namespace proxy { + +class HostResource; + +class PPB_ImageData_Proxy : public InterfaceProxy { + public: + PPB_ImageData_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_ImageData_Proxy(); + + static const Info* GetInfo(); + + const PPB_ImageData* ppb_image_data_target() const { + return static_cast<const PPB_ImageData*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); +}; + +class ImageData : public PluginResource, + public ::ppapi::thunk::PPB_ImageData_API, + public ppapi::ImageDataImpl { + public: + ImageData(const HostResource& resource, + const PP_ImageDataDesc& desc, + ImageHandle handle); + virtual ~ImageData(); + + // ResourceObjectBase overrides. + virtual ::ppapi::thunk::PPB_ImageData_API* AsPPB_ImageData_API() OVERRIDE; + + // Resource overrides. + virtual ImageData* AsImageData() OVERRIDE; + + // PPB_ImageData API. + virtual PP_Bool Describe(PP_ImageDataDesc* desc) OVERRIDE; + virtual void* Map() OVERRIDE; + virtual void Unmap() OVERRIDE; + virtual int32_t GetSharedMemory(int* handle, uint32_t* byte_count) OVERRIDE; + + skia::PlatformCanvas* mapped_canvas() const { return mapped_canvas_.get(); } + + const PP_ImageDataDesc& desc() const { return desc_; } + + static const ImageHandle NullHandle; + static ImageHandle HandleFromInt(int32_t i); + + private: + PP_ImageDataDesc desc_; + + scoped_ptr<TransportDIB> transport_dib_; + + // Null when the image isn't mapped. + scoped_ptr<skia::PlatformCanvas> mapped_canvas_; + + DISALLOW_COPY_AND_ASSIGN(ImageData); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_IMAGE_DATA_PROXY_H_ diff --git a/ppapi/proxy/ppb_input_event_proxy.cc b/ppapi/proxy/ppb_input_event_proxy.cc new file mode 100644 index 0000000..d5c6f4b --- /dev/null +++ b/ppapi/proxy/ppb_input_event_proxy.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_input_event_proxy.h" + +#include "ppapi/c/ppb_audio_config.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/input_event_impl.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::InputEventData; +using ppapi::InputEventImpl; +using ppapi::thunk::PPB_InputEvent_API; + +namespace pp { +namespace proxy { + +// The implementation is actually in InputEventImpl. +class InputEvent : public PluginResource, public InputEventImpl { + public: + InputEvent(const HostResource& resource, const InputEventData& data); + virtual ~InputEvent(); + + // ResourceObjectBase overrides. + virtual PPB_InputEvent_API* AsPPB_InputEvent_API() OVERRIDE; + + // InputEventImpl overrides. + virtual PP_Var StringToPPVar(const std::string& str) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(InputEvent); +}; + +InputEvent::InputEvent(const HostResource& resource, const InputEventData& data) + : PluginResource(resource), + InputEventImpl(data) { +} + +InputEvent::~InputEvent() { +} + +PPB_InputEvent_API* InputEvent::AsPPB_InputEvent_API() { + return this; +} + +PP_Var InputEvent::StringToPPVar(const std::string& str) { + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = PluginVarTracker::GetInstance()->MakeString(str); + return ret; +} + +namespace { + +InterfaceProxy* CreateInputEventProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_InputEvent_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_InputEvent_Proxy::PPB_InputEvent_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_InputEvent_Proxy::~PPB_InputEvent_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_InputEvent_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_InputEvent_Thunk(), + PPB_INPUT_EVENT_INTERFACE, + INTERFACE_ID_NONE, + false, + &CreateInputEventProxy, + }; + return &info; +} + +// static +PP_Resource PPB_InputEvent_Proxy::CreateProxyResource( + PP_Instance instance, + const InputEventData& data) { + linked_ptr<InputEvent> object(new InputEvent( + HostResource::MakeInstanceOnly(instance), data)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_InputEvent_Proxy::OnMessageReceived(const IPC::Message& msg) { + // There are no IPC messages for this interface. + NOTREACHED(); + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_input_event_proxy.h b/ppapi/proxy/ppb_input_event_proxy.h new file mode 100644 index 0000000..bd80535 --- /dev/null +++ b/ppapi/proxy/ppb_input_event_proxy.h @@ -0,0 +1,40 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_INPUT_EVENT_PROXY_H_ +#define PPAPI_PROXY_PPB_INPUT_EVENT_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/input_event_impl.h" + +namespace ppapi { +struct InputEventData; +} + +namespace pp { +namespace proxy { + +class PPB_InputEvent_Proxy : public InterfaceProxy { + public: + PPB_InputEvent_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_InputEvent_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + const ppapi::InputEventData& data); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_InputEvent_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_INPUT_EVENT_PROXY_H_ diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc new file mode 100644 index 0000000..7bb6ba1 --- /dev/null +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -0,0 +1,367 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_instance_proxy.h" + +#include "ppapi/c/dev/ppb_fullscreen_dev.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppb_messaging.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/thunk.h" + +// Windows headers interfere with this file. +#ifdef PostMessage +#undef PostMessage +#endif + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_Instance_FunctionAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Instance_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Instance_Proxy::PPB_Instance_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Instance_Proxy::~PPB_Instance_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfo0_5() { + static const Info info = { + ppapi::thunk::GetPPB_Instance_1_0_Thunk(), + PPB_INSTANCE_INTERFACE_0_5, + INTERFACE_ID_NONE, // 1_0 is the canonical one. + false, + &CreateInstanceProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfo1_0() { + static const Info info = { + ppapi::thunk::GetPPB_Instance_1_0_Thunk(), + PPB_INSTANCE_INTERFACE_1_0, + INTERFACE_ID_PPB_INSTANCE, + false, + &CreateInstanceProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfoMessaging() { + static const Info info = { + ppapi::thunk::GetPPB_Messaging_Thunk(), + PPB_MESSAGING_INTERFACE, + INTERFACE_ID_NONE, // 1_0 is the canonical one. + false, + &CreateInstanceProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfoPrivate() { + static const Info info = { + ppapi::thunk::GetPPB_Instance_Private_Thunk(), + PPB_INSTANCE_PRIVATE_INTERFACE, + INTERFACE_ID_NONE, // 1_0 is the canonical one. + false, + &CreateInstanceProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_Instance_Proxy::GetInfoFullscreen() { + static const Info info = { + ppapi::thunk::GetPPB_Fullscreen_Thunk(), + PPB_FULLSCREEN_DEV_INTERFACE, + INTERFACE_ID_NONE, // 1_0 is the canonical one. + false, + &CreateInstanceProxy, + }; + return &info; +} + +bool PPB_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) { + // Prevent the dispatcher from going away during a call to ExecuteScript. + // This must happen OUTSIDE of ExecuteScript since the SerializedVars use + // the dispatcher upon return of the function (converting the + // SerializedVarReturnValue/OutParam to a SerializedVar in the destructor). + ScopedModuleReference death_grip(dispatcher()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Instance_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetWindowObject, + OnMsgGetWindowObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetOwnerElementObject, + OnMsgGetOwnerElementObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_BindGraphics, + OnMsgBindGraphics) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_IsFullFrame, + OnMsgIsFullFrame) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_ExecuteScript, + OnMsgExecuteScript) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_PostMessage, + OnMsgPostMessage) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_SetFullscreen, + OnMsgSetFullscreen) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_GetScreenSize, + OnMsgGetScreenSize) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_RequestInputEvents, + OnMsgRequestInputEvents) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBInstance_ClearInputEvents, + OnMsgClearInputEvents) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +PPB_Instance_FunctionAPI* PPB_Instance_Proxy::AsPPB_Instance_FunctionAPI() { + return this; +} + +PP_Bool PPB_Instance_Proxy::BindGraphics(PP_Instance instance, + PP_Resource device) { + PluginResource* object = + PluginResourceTracker::GetInstance()->GetResourceObject(device); + if (!object || object->instance() != instance) + return PP_FALSE; + + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_BindGraphics( + INTERFACE_ID_PPB_INSTANCE, instance, object->host_resource(), + &result)); + return result; +} + +PP_Bool PPB_Instance_Proxy::IsFullFrame(PP_Instance instance) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_IsFullFrame( + INTERFACE_ID_PPB_INSTANCE, instance, &result)); + return result; +} + +PP_Var PPB_Instance_Proxy::GetWindowObject(PP_Instance instance) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetWindowObject( + INTERFACE_ID_PPB_INSTANCE, instance, &result)); + return result.Return(dispatcher()); +} + +PP_Var PPB_Instance_Proxy::GetOwnerElementObject(PP_Instance instance) { + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetOwnerElementObject( + INTERFACE_ID_PPB_INSTANCE, instance, &result)); + return result.Return(dispatcher()); +} + +PP_Var PPB_Instance_Proxy::ExecuteScript(PP_Instance instance, + PP_Var script, + PP_Var* exception) { + ReceiveSerializedException se(dispatcher(), exception); + if (se.IsThrown()) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_ExecuteScript( + INTERFACE_ID_PPB_INSTANCE, instance, + SerializedVarSendInput(dispatcher(), script), &se, &result)); + return result.Return(dispatcher()); +} + +PP_Bool PPB_Instance_Proxy::IsFullscreen(PP_Instance instance) { + InstanceData* data = static_cast<PluginDispatcher*>(dispatcher())-> + GetInstanceData(instance); + if (!data) + return PP_FALSE; + return data->fullscreen; +} + +PP_Bool PPB_Instance_Proxy::SetFullscreen(PP_Instance instance, + PP_Bool fullscreen) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_SetFullscreen( + INTERFACE_ID_PPB_INSTANCE, instance, fullscreen, &result)); + return result; +} + +PP_Bool PPB_Instance_Proxy::GetScreenSize(PP_Instance instance, + PP_Size* size) { + PP_Bool result = PP_FALSE; + dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetScreenSize( + INTERFACE_ID_PPB_INSTANCE, instance, &result, size)); + return result; +} + +int32_t PPB_Instance_Proxy::RequestInputEvents(PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_RequestInputEvents( + INTERFACE_ID_PPB_INSTANCE, instance, false, event_classes)); + + // We always register for the classes we can handle, this function validates + // the flags so we can notify it if anything was invalid, without requiring + // a sync reply. + return ValidateRequestInputEvents(false, event_classes); +} + +int32_t PPB_Instance_Proxy::RequestFilteringInputEvents( + PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_RequestInputEvents( + INTERFACE_ID_PPB_INSTANCE, instance, true, event_classes)); + + // We always register for the classes we can handle, this function validates + // the flags so we can notify it if anything was invalid, without requiring + // a sync reply. + return ValidateRequestInputEvents(true, event_classes); +} + +void PPB_Instance_Proxy::ClearInputEventRequest(PP_Instance instance, + uint32_t event_classes) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_ClearInputEvents( + INTERFACE_ID_PPB_INSTANCE, instance, event_classes)); +} + +void PPB_Instance_Proxy::ZoomChanged(PP_Instance instance, + double factor) { + // Not proxied yet. + NOTIMPLEMENTED(); +} + +void PPB_Instance_Proxy::ZoomLimitsChanged(PP_Instance instance, + double minimum_factor, + double maximium_factor) { + // Not proxied yet. + NOTIMPLEMENTED(); +} + +void PPB_Instance_Proxy::PostMessage(PP_Instance instance, + PP_Var message) { + dispatcher()->Send(new PpapiHostMsg_PPBInstance_PostMessage( + INTERFACE_ID_PPB_INSTANCE, + instance, SerializedVarSendInput(dispatcher(), message))); +} + +void PPB_Instance_Proxy::OnMsgGetWindowObject( + PP_Instance instance, + SerializedVarReturnValue result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + result.Return(dispatcher(), enter.functions()->GetWindowObject(instance)); +} + +void PPB_Instance_Proxy::OnMsgGetOwnerElementObject( + PP_Instance instance, + SerializedVarReturnValue result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) { + result.Return(dispatcher(), + enter.functions()->GetOwnerElementObject(instance)); + } +} + +void PPB_Instance_Proxy::OnMsgBindGraphics(PP_Instance instance, + HostResource device, + PP_Bool* result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) { + *result = enter.functions()->BindGraphics(instance, + device.host_resource()); + } +} + +void PPB_Instance_Proxy::OnMsgIsFullFrame(PP_Instance instance, + PP_Bool* result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + *result = enter.functions()->IsFullFrame(instance); +} + +void PPB_Instance_Proxy::OnMsgExecuteScript( + PP_Instance instance, + SerializedVarReceiveInput script, + SerializedVarOutParam out_exception, + SerializedVarReturnValue result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.failed()) + return; + + if (dispatcher()->IsPlugin()) + NOTREACHED(); + else + static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); + + result.Return(dispatcher(), enter.functions()->ExecuteScript( + instance, + script.Get(dispatcher()), + out_exception.OutParam(dispatcher()))); +} + +void PPB_Instance_Proxy::OnMsgSetFullscreen(PP_Instance instance, + PP_Bool fullscreen, + PP_Bool* result) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + *result = enter.functions()->SetFullscreen(instance, fullscreen); +} + +void PPB_Instance_Proxy::OnMsgGetScreenSize(PP_Instance instance, + PP_Bool* result, + PP_Size* size) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + *result = enter.functions()->GetScreenSize(instance, size); +} + +void PPB_Instance_Proxy::OnMsgRequestInputEvents(PP_Instance instance, + bool is_filtering, + uint32_t event_classes) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) { + if (is_filtering) + enter.functions()->RequestFilteringInputEvents(instance, event_classes); + else + enter.functions()->RequestInputEvents(instance, event_classes); + } +} + +void PPB_Instance_Proxy::OnMsgClearInputEvents(PP_Instance instance, + uint32_t event_classes) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + enter.functions()->ClearInputEventRequest(instance, event_classes); +} + +void PPB_Instance_Proxy::OnMsgPostMessage(PP_Instance instance, + SerializedVarReceiveInput message) { + EnterFunctionNoLock<PPB_Instance_FunctionAPI> enter(instance, false); + if (enter.succeeded()) + enter.functions()->PostMessage(instance, message.Get(dispatcher())); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h new file mode 100644 index 0000000..fc2dac3 --- /dev/null +++ b/ppapi/proxy/ppb_instance_proxy.h @@ -0,0 +1,101 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_INSTANCE_PROXY_H_ +#define PPAPI_PROXY_PPB_INSTANCE_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/shared_impl/instance_impl.h" +#include "ppapi/thunk/ppb_instance_api.h" + +namespace pp { +namespace proxy { + +class SerializedVarReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPB_Instance_Proxy : public InterfaceProxy, + public ppapi::InstanceImpl, + public ppapi::FunctionGroupBase, + public ppapi::thunk::PPB_Instance_FunctionAPI { + public: + PPB_Instance_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Instance_Proxy(); + + static const Info* GetInfo0_5(); + static const Info* GetInfo1_0(); + static const Info* GetInfoMessaging(); + static const Info* GetInfoPrivate(); + static const Info* GetInfoFullscreen(); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // FunctionGroupBase overrides. + ppapi::thunk::PPB_Instance_FunctionAPI* AsPPB_Instance_FunctionAPI() OVERRIDE; + + // PPB_Instance_FunctionAPI implementation. + virtual PP_Bool BindGraphics(PP_Instance instance, + PP_Resource device) OVERRIDE; + virtual PP_Bool IsFullFrame(PP_Instance instance) OVERRIDE; + virtual PP_Var GetWindowObject(PP_Instance instance) OVERRIDE; + virtual PP_Var GetOwnerElementObject(PP_Instance instance) OVERRIDE; + virtual PP_Var ExecuteScript(PP_Instance instance, + PP_Var script, + PP_Var* exception) OVERRIDE; + virtual PP_Bool IsFullscreen(PP_Instance instance) OVERRIDE; + virtual PP_Bool SetFullscreen(PP_Instance instance, + PP_Bool fullscreen) OVERRIDE; + virtual PP_Bool GetScreenSize(PP_Instance instance, PP_Size* size) OVERRIDE; + virtual int32_t RequestInputEvents(PP_Instance instance, + uint32_t event_classes) OVERRIDE; + virtual int32_t RequestFilteringInputEvents(PP_Instance instance, + uint32_t event_classes) OVERRIDE; + virtual void ClearInputEventRequest(PP_Instance instance, + uint32_t event_classes) OVERRIDE; + virtual void ZoomChanged(PP_Instance instance, double factor) OVERRIDE; + virtual void ZoomLimitsChanged(PP_Instance instance, + double minimum_factor, + double maximium_factor) OVERRIDE; + virtual void PostMessage(PP_Instance instance, PP_Var message) OVERRIDE; + + private: + // Message handlers. + void OnMsgGetWindowObject(PP_Instance instance, + SerializedVarReturnValue result); + void OnMsgGetOwnerElementObject(PP_Instance instance, + SerializedVarReturnValue result); + void OnMsgBindGraphics(PP_Instance instance, + HostResource device, + PP_Bool* result); + void OnMsgIsFullFrame(PP_Instance instance, PP_Bool* result); + void OnMsgExecuteScript(PP_Instance instance, + SerializedVarReceiveInput script, + SerializedVarOutParam out_exception, + SerializedVarReturnValue result); + void OnMsgSetFullscreen(PP_Instance instance, + PP_Bool fullscreen, + PP_Bool* result); + void OnMsgGetScreenSize(PP_Instance instance, + PP_Bool* result, + PP_Size* size); + void OnMsgRequestInputEvents(PP_Instance instance, + bool is_filtering, + uint32_t event_classes); + void OnMsgClearInputEvents(PP_Instance instance, + uint32_t event_classes); + void OnMsgPostMessage(PP_Instance instance, + SerializedVarReceiveInput message); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_INSTANCE_PROXY_H_ diff --git a/ppapi/proxy/ppb_memory_proxy.cc b/ppapi/proxy/ppb_memory_proxy.cc new file mode 100644 index 0000000..616e789 --- /dev/null +++ b/ppapi/proxy/ppb_memory_proxy.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_memory_proxy.h" + +#include "ppapi/c/dev/ppb_memory_dev.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +namespace pp { +namespace proxy { + +namespace { + +// PPB_Memory_Dev plugin ------------------------------------------------------- + +void* MemAlloc(uint32_t num_bytes) { + return malloc(num_bytes); +} + +void MemFree(void *ptr) { + free(ptr); +} + +const PPB_Memory_Dev memory_dev_interface = { + &MemAlloc, + &MemFree +}; + +InterfaceProxy* CreateMemoryProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Memory_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Memory_Proxy::PPB_Memory_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Memory_Proxy::~PPB_Memory_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Memory_Proxy::GetInfo() { + static const Info info = { + &memory_dev_interface, + PPB_MEMORY_DEV_INTERFACE, + INTERFACE_ID_PPB_MEMORY, + false, + &CreateMemoryProxy, + }; + return &info; +} + +bool PPB_Memory_Proxy::OnMessageReceived(const IPC::Message& msg) { + // All PPB_Memory_Dev calls are handled locally; there is no need to send or + // receive messages here. + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_memory_proxy.h b/ppapi/proxy/ppb_memory_proxy.h new file mode 100644 index 0000000..503dd70 --- /dev/null +++ b/ppapi/proxy/ppb_memory_proxy.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_MEMORY_PROXY_H_ +#define PPAPI_PPB_MEMORY_PROXY_H_ + +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Memory_Dev; + +namespace pp { +namespace proxy { + +class PPB_Memory_Proxy : public InterfaceProxy { + public: + PPB_Memory_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Memory_Proxy(); + + static const Info* GetInfo(); + + const PPB_Memory_Dev* ppb_memory_target() const { + return static_cast<const PPB_Memory_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. In this case, no messages are sent or + // received, so this always returns false. + virtual bool OnMessageReceived(const IPC::Message& msg); + +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_MEMORY_PROXY_H_ diff --git a/ppapi/proxy/ppb_opengles2_proxy.cc b/ppapi/proxy/ppb_opengles2_proxy.cc new file mode 100644 index 0000000..ce301c6 --- /dev/null +++ b/ppapi/proxy/ppb_opengles2_proxy.cc @@ -0,0 +1,939 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is auto-generated from +// gpu/command_buffer/build_gles2_cmd_buffer.py +// DO NOT EDIT! + +#include "ppapi/proxy/ppb_opengles2_proxy.h" + +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_opengles_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppb_context_3d_proxy.h" +#include "ppapi/shared_impl/resource_object_base.h" +#include "ppapi/shared_impl/tracker_base.h" + +namespace pp { +namespace proxy { + +namespace { + +gpu::gles2::GLES2Implementation* GetGLES(PP_Resource context) { + ppapi::ResourceObjectBase* base = + ppapi::TrackerBase::Get()->GetResourceAPI(context); + DCHECK(base->AsPPB_Context3D_API()); + return static_cast<Context3D*>(base)->gles2_impl(); +} + +void ActiveTexture(PP_Resource context_id, GLenum texture) { + GetGLES(context_id)->ActiveTexture(texture); +} + +void AttachShader(PP_Resource context_id, GLuint program, GLuint shader) { + GetGLES(context_id)->AttachShader(program, shader); +} + +void BindAttribLocation( + PP_Resource context_id, GLuint program, GLuint index, const char* name) { + GetGLES(context_id)->BindAttribLocation(program, index, name); +} + +void BindBuffer(PP_Resource context_id, GLenum target, GLuint buffer) { + GetGLES(context_id)->BindBuffer(target, buffer); +} + +void BindFramebuffer( + PP_Resource context_id, GLenum target, GLuint framebuffer) { + GetGLES(context_id)->BindFramebuffer(target, framebuffer); +} + +void BindRenderbuffer( + PP_Resource context_id, GLenum target, GLuint renderbuffer) { + GetGLES(context_id)->BindRenderbuffer(target, renderbuffer); +} + +void BindTexture(PP_Resource context_id, GLenum target, GLuint texture) { + GetGLES(context_id)->BindTexture(target, texture); +} + +void BlendColor( + PP_Resource context_id, GLclampf red, GLclampf green, GLclampf blue, + GLclampf alpha) { + GetGLES(context_id)->BlendColor(red, green, blue, alpha); +} + +void BlendEquation(PP_Resource context_id, GLenum mode) { + GetGLES(context_id)->BlendEquation(mode); +} + +void BlendEquationSeparate( + PP_Resource context_id, GLenum modeRGB, GLenum modeAlpha) { + GetGLES(context_id)->BlendEquationSeparate(modeRGB, modeAlpha); +} + +void BlendFunc(PP_Resource context_id, GLenum sfactor, GLenum dfactor) { + GetGLES(context_id)->BlendFunc(sfactor, dfactor); +} + +void BlendFuncSeparate( + PP_Resource context_id, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, + GLenum dstAlpha) { + GetGLES(context_id)->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void BufferData( + PP_Resource context_id, GLenum target, GLsizeiptr size, const void* data, + GLenum usage) { + GetGLES(context_id)->BufferData(target, size, data, usage); +} + +void BufferSubData( + PP_Resource context_id, GLenum target, GLintptr offset, GLsizeiptr size, + const void* data) { + GetGLES(context_id)->BufferSubData(target, offset, size, data); +} + +GLenum CheckFramebufferStatus(PP_Resource context_id, GLenum target) { + return GetGLES(context_id)->CheckFramebufferStatus(target); +} + +void Clear(PP_Resource context_id, GLbitfield mask) { + GetGLES(context_id)->Clear(mask); +} + +void ClearColor( + PP_Resource context_id, GLclampf red, GLclampf green, GLclampf blue, + GLclampf alpha) { + GetGLES(context_id)->ClearColor(red, green, blue, alpha); +} + +void ClearDepthf(PP_Resource context_id, GLclampf depth) { + GetGLES(context_id)->ClearDepthf(depth); +} + +void ClearStencil(PP_Resource context_id, GLint s) { + GetGLES(context_id)->ClearStencil(s); +} + +void ColorMask( + PP_Resource context_id, GLboolean red, GLboolean green, GLboolean blue, + GLboolean alpha) { + GetGLES(context_id)->ColorMask(red, green, blue, alpha); +} + +void CompileShader(PP_Resource context_id, GLuint shader) { + GetGLES(context_id)->CompileShader(shader); +} + +void CompressedTexImage2D( + PP_Resource context_id, GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, GLsizei imageSize, + const void* data) { + GetGLES( + context_id)->CompressedTexImage2D( + target, level, internalformat, width, height, border, imageSize, + data); +} + +void CompressedTexSubImage2D( + PP_Resource context_id, GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, GLenum format, + GLsizei imageSize, const void* data) { + GetGLES( + context_id)->CompressedTexSubImage2D( + target, level, xoffset, yoffset, width, height, format, imageSize, + data); +} + +void CopyTexImage2D( + PP_Resource context_id, GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + GetGLES( + context_id)->CopyTexImage2D( + target, level, internalformat, x, y, width, height, border); +} + +void CopyTexSubImage2D( + PP_Resource context_id, GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + GetGLES( + context_id)->CopyTexSubImage2D( + target, level, xoffset, yoffset, x, y, width, height); +} + +GLuint CreateProgram(PP_Resource context_id) { + return GetGLES(context_id)->CreateProgram(); +} + +GLuint CreateShader(PP_Resource context_id, GLenum type) { + return GetGLES(context_id)->CreateShader(type); +} + +void CullFace(PP_Resource context_id, GLenum mode) { + GetGLES(context_id)->CullFace(mode); +} + +void DeleteBuffers(PP_Resource context_id, GLsizei n, const GLuint* buffers) { + GetGLES(context_id)->DeleteBuffers(n, buffers); +} + +void DeleteFramebuffers( + PP_Resource context_id, GLsizei n, const GLuint* framebuffers) { + GetGLES(context_id)->DeleteFramebuffers(n, framebuffers); +} + +void DeleteProgram(PP_Resource context_id, GLuint program) { + GetGLES(context_id)->DeleteProgram(program); +} + +void DeleteRenderbuffers( + PP_Resource context_id, GLsizei n, const GLuint* renderbuffers) { + GetGLES(context_id)->DeleteRenderbuffers(n, renderbuffers); +} + +void DeleteShader(PP_Resource context_id, GLuint shader) { + GetGLES(context_id)->DeleteShader(shader); +} + +void DeleteTextures( + PP_Resource context_id, GLsizei n, const GLuint* textures) { + GetGLES(context_id)->DeleteTextures(n, textures); +} + +void DepthFunc(PP_Resource context_id, GLenum func) { + GetGLES(context_id)->DepthFunc(func); +} + +void DepthMask(PP_Resource context_id, GLboolean flag) { + GetGLES(context_id)->DepthMask(flag); +} + +void DepthRangef(PP_Resource context_id, GLclampf zNear, GLclampf zFar) { + GetGLES(context_id)->DepthRangef(zNear, zFar); +} + +void DetachShader(PP_Resource context_id, GLuint program, GLuint shader) { + GetGLES(context_id)->DetachShader(program, shader); +} + +void Disable(PP_Resource context_id, GLenum cap) { + GetGLES(context_id)->Disable(cap); +} + +void DisableVertexAttribArray(PP_Resource context_id, GLuint index) { + GetGLES(context_id)->DisableVertexAttribArray(index); +} + +void DrawArrays( + PP_Resource context_id, GLenum mode, GLint first, GLsizei count) { + GetGLES(context_id)->DrawArrays(mode, first, count); +} + +void DrawElements( + PP_Resource context_id, GLenum mode, GLsizei count, GLenum type, + const void* indices) { + GetGLES(context_id)->DrawElements(mode, count, type, indices); +} + +void Enable(PP_Resource context_id, GLenum cap) { + GetGLES(context_id)->Enable(cap); +} + +void EnableVertexAttribArray(PP_Resource context_id, GLuint index) { + GetGLES(context_id)->EnableVertexAttribArray(index); +} + +void Finish(PP_Resource context_id) { + GetGLES(context_id)->Finish(); +} + +void Flush(PP_Resource context_id) { + GetGLES(context_id)->Flush(); +} + +void FramebufferRenderbuffer( + PP_Resource context_id, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer) { + GetGLES( + context_id)->FramebufferRenderbuffer( + target, attachment, renderbuffertarget, renderbuffer); +} + +void FramebufferTexture2D( + PP_Resource context_id, GLenum target, GLenum attachment, GLenum textarget, + GLuint texture, GLint level) { + GetGLES( + context_id)->FramebufferTexture2D( + target, attachment, textarget, texture, level); +} + +void FrontFace(PP_Resource context_id, GLenum mode) { + GetGLES(context_id)->FrontFace(mode); +} + +void GenBuffers(PP_Resource context_id, GLsizei n, GLuint* buffers) { + GetGLES(context_id)->GenBuffers(n, buffers); +} + +void GenerateMipmap(PP_Resource context_id, GLenum target) { + GetGLES(context_id)->GenerateMipmap(target); +} + +void GenFramebuffers(PP_Resource context_id, GLsizei n, GLuint* framebuffers) { + GetGLES(context_id)->GenFramebuffers(n, framebuffers); +} + +void GenRenderbuffers( + PP_Resource context_id, GLsizei n, GLuint* renderbuffers) { + GetGLES(context_id)->GenRenderbuffers(n, renderbuffers); +} + +void GenTextures(PP_Resource context_id, GLsizei n, GLuint* textures) { + GetGLES(context_id)->GenTextures(n, textures); +} + +void GetActiveAttrib( + PP_Resource context_id, GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, char* name) { + GetGLES( + context_id)->GetActiveAttrib( + program, index, bufsize, length, size, type, name); +} + +void GetActiveUniform( + PP_Resource context_id, GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, char* name) { + GetGLES( + context_id)->GetActiveUniform( + program, index, bufsize, length, size, type, name); +} + +void GetAttachedShaders( + PP_Resource context_id, GLuint program, GLsizei maxcount, GLsizei* count, + GLuint* shaders) { + GetGLES(context_id)->GetAttachedShaders(program, maxcount, count, shaders); +} + +GLint GetAttribLocation( + PP_Resource context_id, GLuint program, const char* name) { + return GetGLES(context_id)->GetAttribLocation(program, name); +} + +void GetBooleanv(PP_Resource context_id, GLenum pname, GLboolean* params) { + GetGLES(context_id)->GetBooleanv(pname, params); +} + +void GetBufferParameteriv( + PP_Resource context_id, GLenum target, GLenum pname, GLint* params) { + GetGLES(context_id)->GetBufferParameteriv(target, pname, params); +} + +GLenum GetError(PP_Resource context_id) { + return GetGLES(context_id)->GetError(); +} + +void GetFloatv(PP_Resource context_id, GLenum pname, GLfloat* params) { + GetGLES(context_id)->GetFloatv(pname, params); +} + +void GetFramebufferAttachmentParameteriv( + PP_Resource context_id, GLenum target, GLenum attachment, GLenum pname, + GLint* params) { + GetGLES( + context_id)->GetFramebufferAttachmentParameteriv( + target, attachment, pname, params); +} + +void GetIntegerv(PP_Resource context_id, GLenum pname, GLint* params) { + GetGLES(context_id)->GetIntegerv(pname, params); +} + +void GetProgramiv( + PP_Resource context_id, GLuint program, GLenum pname, GLint* params) { + GetGLES(context_id)->GetProgramiv(program, pname, params); +} + +void GetProgramInfoLog( + PP_Resource context_id, GLuint program, GLsizei bufsize, GLsizei* length, + char* infolog) { + GetGLES(context_id)->GetProgramInfoLog(program, bufsize, length, infolog); +} + +void GetRenderbufferParameteriv( + PP_Resource context_id, GLenum target, GLenum pname, GLint* params) { + GetGLES(context_id)->GetRenderbufferParameteriv(target, pname, params); +} + +void GetShaderiv( + PP_Resource context_id, GLuint shader, GLenum pname, GLint* params) { + GetGLES(context_id)->GetShaderiv(shader, pname, params); +} + +void GetShaderInfoLog( + PP_Resource context_id, GLuint shader, GLsizei bufsize, GLsizei* length, + char* infolog) { + GetGLES(context_id)->GetShaderInfoLog(shader, bufsize, length, infolog); +} + +void GetShaderPrecisionFormat( + PP_Resource context_id, GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision) { + GetGLES( + context_id)->GetShaderPrecisionFormat( + shadertype, precisiontype, range, precision); +} + +void GetShaderSource( + PP_Resource context_id, GLuint shader, GLsizei bufsize, GLsizei* length, + char* source) { + GetGLES(context_id)->GetShaderSource(shader, bufsize, length, source); +} + +const GLubyte* GetString(PP_Resource context_id, GLenum name) { + return GetGLES(context_id)->GetString(name); +} + +void GetTexParameterfv( + PP_Resource context_id, GLenum target, GLenum pname, GLfloat* params) { + GetGLES(context_id)->GetTexParameterfv(target, pname, params); +} + +void GetTexParameteriv( + PP_Resource context_id, GLenum target, GLenum pname, GLint* params) { + GetGLES(context_id)->GetTexParameteriv(target, pname, params); +} + +void GetUniformfv( + PP_Resource context_id, GLuint program, GLint location, GLfloat* params) { + GetGLES(context_id)->GetUniformfv(program, location, params); +} + +void GetUniformiv( + PP_Resource context_id, GLuint program, GLint location, GLint* params) { + GetGLES(context_id)->GetUniformiv(program, location, params); +} + +GLint GetUniformLocation( + PP_Resource context_id, GLuint program, const char* name) { + return GetGLES(context_id)->GetUniformLocation(program, name); +} + +void GetVertexAttribfv( + PP_Resource context_id, GLuint index, GLenum pname, GLfloat* params) { + GetGLES(context_id)->GetVertexAttribfv(index, pname, params); +} + +void GetVertexAttribiv( + PP_Resource context_id, GLuint index, GLenum pname, GLint* params) { + GetGLES(context_id)->GetVertexAttribiv(index, pname, params); +} + +void GetVertexAttribPointerv( + PP_Resource context_id, GLuint index, GLenum pname, void** pointer) { + GetGLES(context_id)->GetVertexAttribPointerv(index, pname, pointer); +} + +void Hint(PP_Resource context_id, GLenum target, GLenum mode) { + GetGLES(context_id)->Hint(target, mode); +} + +GLboolean IsBuffer(PP_Resource context_id, GLuint buffer) { + return GetGLES(context_id)->IsBuffer(buffer); +} + +GLboolean IsEnabled(PP_Resource context_id, GLenum cap) { + return GetGLES(context_id)->IsEnabled(cap); +} + +GLboolean IsFramebuffer(PP_Resource context_id, GLuint framebuffer) { + return GetGLES(context_id)->IsFramebuffer(framebuffer); +} + +GLboolean IsProgram(PP_Resource context_id, GLuint program) { + return GetGLES(context_id)->IsProgram(program); +} + +GLboolean IsRenderbuffer(PP_Resource context_id, GLuint renderbuffer) { + return GetGLES(context_id)->IsRenderbuffer(renderbuffer); +} + +GLboolean IsShader(PP_Resource context_id, GLuint shader) { + return GetGLES(context_id)->IsShader(shader); +} + +GLboolean IsTexture(PP_Resource context_id, GLuint texture) { + return GetGLES(context_id)->IsTexture(texture); +} + +void LineWidth(PP_Resource context_id, GLfloat width) { + GetGLES(context_id)->LineWidth(width); +} + +void LinkProgram(PP_Resource context_id, GLuint program) { + GetGLES(context_id)->LinkProgram(program); +} + +void PixelStorei(PP_Resource context_id, GLenum pname, GLint param) { + GetGLES(context_id)->PixelStorei(pname, param); +} + +void PolygonOffset(PP_Resource context_id, GLfloat factor, GLfloat units) { + GetGLES(context_id)->PolygonOffset(factor, units); +} + +void ReadPixels( + PP_Resource context_id, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, void* pixels) { + GetGLES(context_id)->ReadPixels(x, y, width, height, format, type, pixels); +} + +void ReleaseShaderCompiler(PP_Resource context_id) { + GetGLES(context_id)->ReleaseShaderCompiler(); +} + +void RenderbufferStorage( + PP_Resource context_id, GLenum target, GLenum internalformat, GLsizei width, + GLsizei height) { + GetGLES( + context_id)->RenderbufferStorage(target, internalformat, width, height); +} + +void SampleCoverage(PP_Resource context_id, GLclampf value, GLboolean invert) { + GetGLES(context_id)->SampleCoverage(value, invert); +} + +void Scissor( + PP_Resource context_id, GLint x, GLint y, GLsizei width, GLsizei height) { + GetGLES(context_id)->Scissor(x, y, width, height); +} + +void ShaderBinary( + PP_Resource context_id, GLsizei n, const GLuint* shaders, + GLenum binaryformat, const void* binary, GLsizei length) { + GetGLES(context_id)->ShaderBinary(n, shaders, binaryformat, binary, length); +} + +void ShaderSource( + PP_Resource context_id, GLuint shader, GLsizei count, const char** str, + const GLint* length) { + GetGLES(context_id)->ShaderSource(shader, count, str, length); +} + +void StencilFunc(PP_Resource context_id, GLenum func, GLint ref, GLuint mask) { + GetGLES(context_id)->StencilFunc(func, ref, mask); +} + +void StencilFuncSeparate( + PP_Resource context_id, GLenum face, GLenum func, GLint ref, GLuint mask) { + GetGLES(context_id)->StencilFuncSeparate(face, func, ref, mask); +} + +void StencilMask(PP_Resource context_id, GLuint mask) { + GetGLES(context_id)->StencilMask(mask); +} + +void StencilMaskSeparate(PP_Resource context_id, GLenum face, GLuint mask) { + GetGLES(context_id)->StencilMaskSeparate(face, mask); +} + +void StencilOp( + PP_Resource context_id, GLenum fail, GLenum zfail, GLenum zpass) { + GetGLES(context_id)->StencilOp(fail, zfail, zpass); +} + +void StencilOpSeparate( + PP_Resource context_id, GLenum face, GLenum fail, GLenum zfail, + GLenum zpass) { + GetGLES(context_id)->StencilOpSeparate(face, fail, zfail, zpass); +} + +void TexImage2D( + PP_Resource context_id, GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, + const void* pixels) { + GetGLES( + context_id)->TexImage2D( + target, level, internalformat, width, height, border, format, type, + pixels); +} + +void TexParameterf( + PP_Resource context_id, GLenum target, GLenum pname, GLfloat param) { + GetGLES(context_id)->TexParameterf(target, pname, param); +} + +void TexParameterfv( + PP_Resource context_id, GLenum target, GLenum pname, + const GLfloat* params) { + GetGLES(context_id)->TexParameterfv(target, pname, params); +} + +void TexParameteri( + PP_Resource context_id, GLenum target, GLenum pname, GLint param) { + GetGLES(context_id)->TexParameteri(target, pname, param); +} + +void TexParameteriv( + PP_Resource context_id, GLenum target, GLenum pname, const GLint* params) { + GetGLES(context_id)->TexParameteriv(target, pname, params); +} + +void TexSubImage2D( + PP_Resource context_id, GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, + const void* pixels) { + GetGLES( + context_id)->TexSubImage2D( + target, level, xoffset, yoffset, width, height, format, type, + pixels); +} + +void Uniform1f(PP_Resource context_id, GLint location, GLfloat x) { + GetGLES(context_id)->Uniform1f(location, x); +} + +void Uniform1fv( + PP_Resource context_id, GLint location, GLsizei count, const GLfloat* v) { + GetGLES(context_id)->Uniform1fv(location, count, v); +} + +void Uniform1i(PP_Resource context_id, GLint location, GLint x) { + GetGLES(context_id)->Uniform1i(location, x); +} + +void Uniform1iv( + PP_Resource context_id, GLint location, GLsizei count, const GLint* v) { + GetGLES(context_id)->Uniform1iv(location, count, v); +} + +void Uniform2f(PP_Resource context_id, GLint location, GLfloat x, GLfloat y) { + GetGLES(context_id)->Uniform2f(location, x, y); +} + +void Uniform2fv( + PP_Resource context_id, GLint location, GLsizei count, const GLfloat* v) { + GetGLES(context_id)->Uniform2fv(location, count, v); +} + +void Uniform2i(PP_Resource context_id, GLint location, GLint x, GLint y) { + GetGLES(context_id)->Uniform2i(location, x, y); +} + +void Uniform2iv( + PP_Resource context_id, GLint location, GLsizei count, const GLint* v) { + GetGLES(context_id)->Uniform2iv(location, count, v); +} + +void Uniform3f( + PP_Resource context_id, GLint location, GLfloat x, GLfloat y, GLfloat z) { + GetGLES(context_id)->Uniform3f(location, x, y, z); +} + +void Uniform3fv( + PP_Resource context_id, GLint location, GLsizei count, const GLfloat* v) { + GetGLES(context_id)->Uniform3fv(location, count, v); +} + +void Uniform3i( + PP_Resource context_id, GLint location, GLint x, GLint y, GLint z) { + GetGLES(context_id)->Uniform3i(location, x, y, z); +} + +void Uniform3iv( + PP_Resource context_id, GLint location, GLsizei count, const GLint* v) { + GetGLES(context_id)->Uniform3iv(location, count, v); +} + +void Uniform4f( + PP_Resource context_id, GLint location, GLfloat x, GLfloat y, GLfloat z, + GLfloat w) { + GetGLES(context_id)->Uniform4f(location, x, y, z, w); +} + +void Uniform4fv( + PP_Resource context_id, GLint location, GLsizei count, const GLfloat* v) { + GetGLES(context_id)->Uniform4fv(location, count, v); +} + +void Uniform4i( + PP_Resource context_id, GLint location, GLint x, GLint y, GLint z, + GLint w) { + GetGLES(context_id)->Uniform4i(location, x, y, z, w); +} + +void Uniform4iv( + PP_Resource context_id, GLint location, GLsizei count, const GLint* v) { + GetGLES(context_id)->Uniform4iv(location, count, v); +} + +void UniformMatrix2fv( + PP_Resource context_id, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value) { + GetGLES(context_id)->UniformMatrix2fv(location, count, transpose, value); +} + +void UniformMatrix3fv( + PP_Resource context_id, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value) { + GetGLES(context_id)->UniformMatrix3fv(location, count, transpose, value); +} + +void UniformMatrix4fv( + PP_Resource context_id, GLint location, GLsizei count, GLboolean transpose, + const GLfloat* value) { + GetGLES(context_id)->UniformMatrix4fv(location, count, transpose, value); +} + +void UseProgram(PP_Resource context_id, GLuint program) { + GetGLES(context_id)->UseProgram(program); +} + +void ValidateProgram(PP_Resource context_id, GLuint program) { + GetGLES(context_id)->ValidateProgram(program); +} + +void VertexAttrib1f(PP_Resource context_id, GLuint indx, GLfloat x) { + GetGLES(context_id)->VertexAttrib1f(indx, x); +} + +void VertexAttrib1fv( + PP_Resource context_id, GLuint indx, const GLfloat* values) { + GetGLES(context_id)->VertexAttrib1fv(indx, values); +} + +void VertexAttrib2f( + PP_Resource context_id, GLuint indx, GLfloat x, GLfloat y) { + GetGLES(context_id)->VertexAttrib2f(indx, x, y); +} + +void VertexAttrib2fv( + PP_Resource context_id, GLuint indx, const GLfloat* values) { + GetGLES(context_id)->VertexAttrib2fv(indx, values); +} + +void VertexAttrib3f( + PP_Resource context_id, GLuint indx, GLfloat x, GLfloat y, GLfloat z) { + GetGLES(context_id)->VertexAttrib3f(indx, x, y, z); +} + +void VertexAttrib3fv( + PP_Resource context_id, GLuint indx, const GLfloat* values) { + GetGLES(context_id)->VertexAttrib3fv(indx, values); +} + +void VertexAttrib4f( + PP_Resource context_id, GLuint indx, GLfloat x, GLfloat y, GLfloat z, + GLfloat w) { + GetGLES(context_id)->VertexAttrib4f(indx, x, y, z, w); +} + +void VertexAttrib4fv( + PP_Resource context_id, GLuint indx, const GLfloat* values) { + GetGLES(context_id)->VertexAttrib4fv(indx, values); +} + +void VertexAttribPointer( + PP_Resource context_id, GLuint indx, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, const void* ptr) { + GetGLES( + context_id)->VertexAttribPointer( + indx, size, type, normalized, stride, ptr); +} + +void Viewport( + PP_Resource context_id, GLint x, GLint y, GLsizei width, GLsizei height) { + GetGLES(context_id)->Viewport(x, y, width, height); +} + +void SetLatchCHROMIUM(PP_Resource context_id, GLuint latch_id) { + GetGLES(context_id)->SetLatchCHROMIUM(latch_id); +} + +void WaitLatchCHROMIUM(PP_Resource context_id, GLuint latch_id) { + GetGLES(context_id)->WaitLatchCHROMIUM(latch_id); +} + +const struct PPB_OpenGLES2_Dev opengles2_interface = { + &ActiveTexture, + &AttachShader, + &BindAttribLocation, + &BindBuffer, + &BindFramebuffer, + &BindRenderbuffer, + &BindTexture, + &BlendColor, + &BlendEquation, + &BlendEquationSeparate, + &BlendFunc, + &BlendFuncSeparate, + &BufferData, + &BufferSubData, + &CheckFramebufferStatus, + &Clear, + &ClearColor, + &ClearDepthf, + &ClearStencil, + &ColorMask, + &CompileShader, + &CompressedTexImage2D, + &CompressedTexSubImage2D, + &CopyTexImage2D, + &CopyTexSubImage2D, + &CreateProgram, + &CreateShader, + &CullFace, + &DeleteBuffers, + &DeleteFramebuffers, + &DeleteProgram, + &DeleteRenderbuffers, + &DeleteShader, + &DeleteTextures, + &DepthFunc, + &DepthMask, + &DepthRangef, + &DetachShader, + &Disable, + &DisableVertexAttribArray, + &DrawArrays, + &DrawElements, + &Enable, + &EnableVertexAttribArray, + &Finish, + &Flush, + &FramebufferRenderbuffer, + &FramebufferTexture2D, + &FrontFace, + &GenBuffers, + &GenerateMipmap, + &GenFramebuffers, + &GenRenderbuffers, + &GenTextures, + &GetActiveAttrib, + &GetActiveUniform, + &GetAttachedShaders, + &GetAttribLocation, + &GetBooleanv, + &GetBufferParameteriv, + &GetError, + &GetFloatv, + &GetFramebufferAttachmentParameteriv, + &GetIntegerv, + &GetProgramiv, + &GetProgramInfoLog, + &GetRenderbufferParameteriv, + &GetShaderiv, + &GetShaderInfoLog, + &GetShaderPrecisionFormat, + &GetShaderSource, + &GetString, + &GetTexParameterfv, + &GetTexParameteriv, + &GetUniformfv, + &GetUniformiv, + &GetUniformLocation, + &GetVertexAttribfv, + &GetVertexAttribiv, + &GetVertexAttribPointerv, + &Hint, + &IsBuffer, + &IsEnabled, + &IsFramebuffer, + &IsProgram, + &IsRenderbuffer, + &IsShader, + &IsTexture, + &LineWidth, + &LinkProgram, + &PixelStorei, + &PolygonOffset, + &ReadPixels, + &ReleaseShaderCompiler, + &RenderbufferStorage, + &SampleCoverage, + &Scissor, + &ShaderBinary, + &ShaderSource, + &StencilFunc, + &StencilFuncSeparate, + &StencilMask, + &StencilMaskSeparate, + &StencilOp, + &StencilOpSeparate, + &TexImage2D, + &TexParameterf, + &TexParameterfv, + &TexParameteri, + &TexParameteriv, + &TexSubImage2D, + &Uniform1f, + &Uniform1fv, + &Uniform1i, + &Uniform1iv, + &Uniform2f, + &Uniform2fv, + &Uniform2i, + &Uniform2iv, + &Uniform3f, + &Uniform3fv, + &Uniform3i, + &Uniform3iv, + &Uniform4f, + &Uniform4fv, + &Uniform4i, + &Uniform4iv, + &UniformMatrix2fv, + &UniformMatrix3fv, + &UniformMatrix4fv, + &UseProgram, + &ValidateProgram, + &VertexAttrib1f, + &VertexAttrib1fv, + &VertexAttrib2f, + &VertexAttrib2fv, + &VertexAttrib3f, + &VertexAttrib3fv, + &VertexAttrib4f, + &VertexAttrib4fv, + &VertexAttribPointer, + &Viewport +}; + + +InterfaceProxy* CreateOpenGLES2Proxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_OpenGLES2_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_OpenGLES2_Proxy::PPB_OpenGLES2_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_OpenGLES2_Proxy::~PPB_OpenGLES2_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_OpenGLES2_Proxy::GetInfo() { + static const Info info = { + &opengles2_interface, + PPB_OPENGLES2_DEV_INTERFACE, + INTERFACE_ID_PPB_OPENGLES2, + false, + &CreateOpenGLES2Proxy, + }; + return &info; +} + +bool PPB_OpenGLES2_Proxy::OnMessageReceived(const IPC::Message& msg) { + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_opengles2_proxy.h b/ppapi/proxy/ppb_opengles2_proxy.h new file mode 100644 index 0000000..d4ea6f9 --- /dev/null +++ b/ppapi/proxy/ppb_opengles2_proxy.h @@ -0,0 +1,35 @@ +// 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_PPB_OPENGLES2_PROXY_H_ +#define PPAPI_PPB_OPENGLES2_PROXY_H_ + +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_OpenGLES2_Dev; + +namespace pp { +namespace proxy { + +class PPB_OpenGLES2_Proxy : public InterfaceProxy { + public: + PPB_OpenGLES2_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_OpenGLES2_Proxy(); + + static const Info* GetInfo(); + + const PPB_OpenGLES2_Dev* ppb_gles2_target() const { + return reinterpret_cast<const PPB_OpenGLES2_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_OPENGLES2_PROXY_H_ diff --git a/ppapi/proxy/ppb_pdf_proxy.cc b/ppapi/proxy/ppb_pdf_proxy.cc new file mode 100644 index 0000000..f7dbb28 --- /dev/null +++ b/ppapi/proxy/ppb_pdf_proxy.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_pdf_proxy.h" + +#include <string.h> // For memcpy. + +#include <map> + +#include "base/logging.h" +#include "base/memory/linked_ptr.h" +#include "build/build_config.h" +#include "ppapi/c/private/ppb_pdf.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +class PrivateFontFile : public PluginResource { + public: + PrivateFontFile(const HostResource& resource) : PluginResource(resource) { + } + virtual ~PrivateFontFile() {} + + // Resource overrides. + virtual PrivateFontFile* AsPrivateFontFile() { return this; } + + // Sees if we have a cache of the font table and returns a pointer to it. + // Returns NULL if we don't have it. + std::string* GetFontTable(uint32_t table) const; + + std::string* AddFontTable(uint32_t table, const std::string& contents); + + private: + typedef std::map<uint32_t, linked_ptr<std::string> > FontTableMap; + FontTableMap font_tables_; + + DISALLOW_COPY_AND_ASSIGN(PrivateFontFile); +}; + +std::string* PrivateFontFile::GetFontTable(uint32_t table) const { + FontTableMap::const_iterator found = font_tables_.find(table); + if (found == font_tables_.end()) + return NULL; + return found->second.get(); +} + +std::string* PrivateFontFile::AddFontTable(uint32_t table, + const std::string& contents) { + linked_ptr<std::string> heap_string(new std::string(contents)); + font_tables_[table] = heap_string; + return heap_string.get(); +} + +namespace { + +PP_Resource GetFontFileWithFallback( + PP_Instance instance, + const PP_FontDescription_Dev* description, + PP_PrivateFontCharset charset) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + SerializedFontDescription desc; + desc.SetFromPPFontDescription(dispatcher, *description, true); + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBPDF_GetFontFileWithFallback( + INTERFACE_ID_PPB_PDF, instance, desc, charset, &result)); + if (result.is_null()) + return 0; + + linked_ptr<PrivateFontFile> object(new PrivateFontFile(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool GetFontTableForPrivateFontFile(PP_Resource font_file, + uint32_t table, + void* output, + uint32_t* output_length) { + PrivateFontFile* object = PluginResource::GetAs<PrivateFontFile>(font_file); + if (!object) + return false; + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance( + object->instance()); + if (!dispatcher) + return false; + + std::string* contents = object->GetFontTable(table); + if (!contents) { + std::string deserialized; + dispatcher->Send(new PpapiHostMsg_PPBPDF_GetFontTableForPrivateFontFile( + INTERFACE_ID_PPB_PDF, object->host_resource(), table, &deserialized)); + if (deserialized.empty()) + return false; + contents = object->AddFontTable(table, deserialized); + } + + *output_length = static_cast<uint32_t>(contents->size()); + if (output) + memcpy(output, contents->c_str(), *output_length); + return true; +} + +const PPB_PDF pdf_interface = { + NULL, // &GetLocalizedString, + NULL, // &GetResourceImage, + &GetFontFileWithFallback, + &GetFontTableForPrivateFontFile, +}; + +InterfaceProxy* CreatePDFProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_PDF_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_PDF_Proxy::PPB_PDF_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_PDF_Proxy::~PPB_PDF_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_PDF_Proxy::GetInfo() { + static const Info info = { + &pdf_interface, + PPB_PDF_INTERFACE, + INTERFACE_ID_PPB_PDF, + true, + &CreatePDFProxy, + }; + return &info; +} + +bool PPB_PDF_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_PDF_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBPDF_GetFontFileWithFallback, + OnMsgGetFontFileWithFallback) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBPDF_GetFontTableForPrivateFontFile, + OnMsgGetFontTableForPrivateFontFile) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw): handle bad messages! + return handled; +} + +void PPB_PDF_Proxy::OnMsgGetFontFileWithFallback( + PP_Instance instance, + const SerializedFontDescription& in_desc, + int32_t charset, + HostResource* result) { + PP_FontDescription_Dev desc; + in_desc.SetToPPFontDescription(dispatcher(), &desc, false); + result->SetHostResource(instance, + ppb_pdf_target()->GetFontFileWithFallback( + instance, &desc, static_cast<PP_PrivateFontCharset>(charset))); +} + +void PPB_PDF_Proxy::OnMsgGetFontTableForPrivateFontFile( + const HostResource& font_file, + uint32_t table, + std::string* result) { + // TODO(brettw): It would be nice not to copy here. At least on Linux, + // we can map the font file into shared memory and read it that way. + uint32_t table_length = 0; + if (!ppb_pdf_target()->GetFontTableForPrivateFontFile( + font_file.host_resource(), table, NULL, &table_length)) + return; + + result->resize(table_length); + ppb_pdf_target()->GetFontTableForPrivateFontFile(font_file.host_resource(), + table, const_cast<char*>(result->c_str()), &table_length); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_pdf_proxy.h b/ppapi/proxy/ppb_pdf_proxy.h new file mode 100644 index 0000000..dbafd2d --- /dev/null +++ b/ppapi/proxy/ppb_pdf_proxy.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_PDF_PROXY_H_ +#define PPAPI_PPB_PDF_PROXY_H_ + +#include "ppapi/c/pp_module.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_PDF; + +namespace pp { +namespace proxy { + +struct SerializedFontDescription; + +class PPB_PDF_Proxy : public InterfaceProxy { + public: + PPB_PDF_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_PDF_Proxy(); + + static const Info* GetInfo(); + + const PPB_PDF* ppb_pdf_target() const { + return static_cast<const PPB_PDF*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgGetFontFileWithFallback(PP_Module module, + const SerializedFontDescription& desc, + int32_t charset, + HostResource* result); + void OnMsgGetFontTableForPrivateFontFile(const HostResource& font_file, + uint32_t table, + std::string* result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_PDF_PROXY_H_ diff --git a/ppapi/proxy/ppb_surface_3d_proxy.cc b/ppapi/proxy/ppb_surface_3d_proxy.cc new file mode 100644 index 0000000..c0288d0 --- /dev/null +++ b/ppapi/proxy/ppb_surface_3d_proxy.cc @@ -0,0 +1,210 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_surface_3d_proxy.h" + +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/dev/ppb_surface_3d_dev.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_context_3d_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_Surface3D_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateSurface3DProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Surface3D_Proxy(dispatcher, target_interface); +} + +} // namespace + +// Surface3D ------------------------------------------------------------------- + +Surface3D::Surface3D(const HostResource& host_resource) + : PluginResource(host_resource), + resource_(0), + context_(NULL), + current_flush_callback_(PP_BlockUntilComplete()) { +} + +Surface3D::~Surface3D() { + if (context_) + context_->BindSurfaces(0, 0); +} + +PPB_Surface3D_API* Surface3D::AsPPB_Surface3D_API() { + return this; +} + +int32_t Surface3D::SetAttrib(int32_t attribute, int32_t value) { + // TODO(alokp): Implement me. + return 0; +} + +int32_t Surface3D::GetAttrib(int32_t attribute, int32_t* value) { + // TODO(alokp): Implement me. + return 0; +} + +int32_t Surface3D::SwapBuffers(PP_CompletionCallback callback) { + // For now, disallow blocking calls. We'll need to add support for other + // threads to this later. + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + if (is_flush_pending()) + return PP_ERROR_INPROGRESS; // Can't have >1 flush pending. + + if (!context_) + return PP_ERROR_FAILED; + + current_flush_callback_ = callback; + + IPC::Message* msg = new PpapiHostMsg_PPBSurface3D_SwapBuffers( + INTERFACE_ID_PPB_SURFACE_3D, host_resource()); + msg->set_unblock(true); + GetDispatcher()->Send(msg); + + context_->gles2_impl()->SwapBuffers(); + return PP_OK_COMPLETIONPENDING; +} + +void Surface3D::SwapBuffersACK(int32_t pp_error) { + PP_RunAndClearCompletionCallback(¤t_flush_callback_, pp_error); +} + +// PPB_Surface3D_Proxy --------------------------------------------------------- + +PPB_Surface3D_Proxy::PPB_Surface3D_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Surface3D_Proxy::~PPB_Surface3D_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Surface3D_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_Surface3D_Thunk(), + PPB_SURFACE_3D_DEV_INTERFACE, + INTERFACE_ID_PPB_SURFACE_3D, + false, + &CreateSurface3DProxy, + }; + return &info; +} + +// static +PP_Resource PPB_Surface3D_Proxy::CreateProxyResource( + PP_Instance instance, + PP_Config3D_Dev config, + const int32_t* attrib_list) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + std::vector<int32_t> attribs; + if (attrib_list) { + const int32_t* attr = attrib_list; + while(*attr != PP_GRAPHICS3DATTRIB_NONE) { + attribs.push_back(*(attr++)); // Attribute. + attribs.push_back(*(attr++)); // Value. + } + } + attribs.push_back(PP_GRAPHICS3DATTRIB_NONE); // Always terminate. + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBSurface3D_Create( + INTERFACE_ID_PPB_SURFACE_3D, instance, config, attribs, &result)); + + if (result.is_null()) + return 0; + linked_ptr<Surface3D> surface_3d(new Surface3D(result)); + PP_Resource resource = + PluginResourceTracker::GetInstance()->AddResource(surface_3d); + surface_3d->set_resource(resource); + return resource; +} + +bool PPB_Surface3D_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Surface3D_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBSurface3D_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBSurface3D_SwapBuffers, + OnMsgSwapBuffers) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBSurface3D_SwapBuffersACK, + OnMsgSwapBuffersACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // FIXME(brettw) handle bad messages! + return handled; +} + +void PPB_Surface3D_Proxy::OnMsgCreate(PP_Instance instance, + PP_Config3D_Dev config, + const std::vector<int32_t>& attribs, + HostResource* result) { + if (attribs.empty() || + attribs.size() % 2 != 1 || + attribs.back() != PP_GRAPHICS3DATTRIB_NONE) + return; // Bad message. + + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource( + instance, + enter.functions()->CreateSurface3D(instance, config, &attribs.front())); + } +} + +void PPB_Surface3D_Proxy::OnMsgSwapBuffers(const HostResource& surface_3d) { + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_Surface3D_Proxy::SendSwapBuffersACKToPlugin, surface_3d); + + EnterHostFromHostResource<PPB_Surface3D_API> enter(surface_3d); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) + result = enter.object()->SwapBuffers(callback.pp_completion_callback()); + if (result != PP_OK_COMPLETIONPENDING) { + // There was some error, so we won't get a flush callback. We need to now + // issue the ACK to the plugin hears about the error. This will also clean + // up the data associated with the callback. + callback.Run(result); + } +} + +void PPB_Surface3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource, + int32_t pp_error) { + EnterPluginFromHostResource<PPB_Surface3D_API> enter(resource); + if (enter.succeeded()) + static_cast<Surface3D*>(enter.object())->SwapBuffersACK(pp_error); +} + +void PPB_Surface3D_Proxy::SendSwapBuffersACKToPlugin( + int32_t result, + const HostResource& surface_3d) { + dispatcher()->Send(new PpapiMsg_PPBSurface3D_SwapBuffersACK( + INTERFACE_ID_PPB_SURFACE_3D, surface_3d, result)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_surface_3d_proxy.h b/ppapi/proxy/ppb_surface_3d_proxy.h new file mode 100644 index 0000000..f44ad76 --- /dev/null +++ b/ppapi/proxy/ppb_surface_3d_proxy.h @@ -0,0 +1,102 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_SURFACE_3D_PROXY_H_ +#define PPAPI_PPB_SURFACE_3D_PROXY_H_ + +#include <vector> + +#include "ppapi/c/dev/pp_graphics_3d_dev.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" +#include "ppapi/thunk/ppb_surface_3d_api.h" + +struct PPB_Surface3D_Dev; + +namespace pp { +namespace proxy { + +class Context3D; + +class Surface3D : public PluginResource, + public ppapi::thunk::PPB_Surface3D_API { + public: + explicit Surface3D(const HostResource& host_resource); + virtual ~Surface3D(); + + // ResourceObjectBase overrides. + virtual PPB_Surface3D_API* AsPPB_Surface3D_API() OVERRIDE; + + // PPB_Surface3D_API implementation. + virtual int32_t SetAttrib(int32_t attribute, int32_t value) OVERRIDE; + virtual int32_t GetAttrib(int32_t attribute, int32_t* value) OVERRIDE; + virtual int32_t SwapBuffers(PP_CompletionCallback callback) OVERRIDE; + + void SwapBuffersACK(int32_t pp_error); + + bool is_flush_pending() const { return !!current_flush_callback_.func; } + + PP_CompletionCallback current_flush_callback() const { + return current_flush_callback_; + } + + void set_context(Context3D* context) { + context_ = context; + } + + Context3D* context() const { return context_; } + + void set_resource(PP_Resource resource) { resource_ = resource; } + PP_Resource resource() const { return resource_; } + + private: + PP_Resource resource_; + Context3D* context_; + + // In the plugin, this is the current callback set for Flushes. When the + // callback function pointer is non-NULL, we're waiting for a flush ACK. + PP_CompletionCallback current_flush_callback_; + + DISALLOW_COPY_AND_ASSIGN(Surface3D); +}; + +class PPB_Surface3D_Proxy : public InterfaceProxy { + public: + PPB_Surface3D_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Surface3D_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance, + PP_Config3D_Dev config, + const int32_t* attrib_list); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, + PP_Config3D_Dev config, + const std::vector<int32_t>& attribs, + HostResource* result); + void OnMsgSwapBuffers(const HostResource& surface); + // Renderer->plugin message handlers. + void OnMsgSwapBuffersACK(const HostResource& surface, int32_t pp_error); + + void SendSwapBuffersACKToPlugin(int32_t result, + const HostResource& surface_3d); + + CompletionCallbackFactory<PPB_Surface3D_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_SURFACE_3D_PROXY_H_ diff --git a/ppapi/proxy/ppb_testing_proxy.cc b/ppapi/proxy/ppb_testing_proxy.cc new file mode 100644 index 0000000..593ed7d --- /dev/null +++ b/ppapi/proxy/ppb_testing_proxy.cc @@ -0,0 +1,146 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_testing_proxy.h" + +#include "base/message_loop.h" +#include "ppapi/c/dev/ppb_testing_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Bool ReadImageData(PP_Resource graphics_2d, + PP_Resource image, + const PP_Point* top_left) { + PluginResource* image_object = PluginResourceTracker::GetInstance()-> + GetResourceObject(image); + if (!image_object) + return PP_FALSE; + PluginResource* graphics_2d_object = + PluginResourceTracker::GetInstance()->GetResourceObject(graphics_2d); + if (!graphics_2d_object || + image_object->instance() != graphics_2d_object->instance()) + return PP_FALSE; + + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance( + image_object->instance()); + if (!dispatcher) + return PP_FALSE; + + PP_Bool result = PP_FALSE; + dispatcher->Send(new PpapiHostMsg_PPBTesting_ReadImageData( + INTERFACE_ID_PPB_TESTING, graphics_2d_object->host_resource(), + image_object->host_resource(), *top_left, &result)); + return result; +} + +void RunMessageLoop(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + IPC::SyncMessage* msg = new PpapiHostMsg_PPBTesting_RunMessageLoop( + INTERFACE_ID_PPB_TESTING, instance); + msg->EnableMessagePumping(); + dispatcher->Send(msg); +} + +void QuitMessageLoop(PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + dispatcher->Send(new PpapiHostMsg_PPBTesting_QuitMessageLoop( + INTERFACE_ID_PPB_TESTING, instance)); +} + +uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance_id); + if (!dispatcher) + return static_cast<uint32_t>(-1); + + uint32_t result = 0; + dispatcher->Send(new PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance( + INTERFACE_ID_PPB_TESTING, instance_id, &result)); + return result; +} + +const PPB_Testing_Dev testing_interface = { + &ReadImageData, + &RunMessageLoop, + &QuitMessageLoop, + &GetLiveObjectsForInstance +}; + +InterfaceProxy* CreateTestingProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Testing_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Testing_Proxy::PPB_Testing_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Testing_Proxy::~PPB_Testing_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Testing_Proxy::GetInfo() { + static const Info info = { + &testing_interface, + PPB_TESTING_DEV_INTERFACE, + INTERFACE_ID_PPB_TESTING, + false, + &CreateTestingProxy, + }; + return &info; +} + +bool PPB_Testing_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Testing_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_ReadImageData, + OnMsgReadImageData) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_RunMessageLoop, + OnMsgRunMessageLoop) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_QuitMessageLoop, + OnMsgQuitMessageLoop) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTesting_GetLiveObjectsForInstance, + OnMsgGetLiveObjectsForInstance) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_Testing_Proxy::OnMsgReadImageData( + const HostResource& device_context_2d, + const HostResource& image, + const PP_Point& top_left, + PP_Bool* result) { + *result = ppb_testing_target()->ReadImageData( + device_context_2d.host_resource(), image.host_resource(), &top_left); +} + +void PPB_Testing_Proxy::OnMsgRunMessageLoop(PP_Instance instance) { + ppb_testing_target()->RunMessageLoop(instance); +} + +void PPB_Testing_Proxy::OnMsgQuitMessageLoop(PP_Instance instance) { + ppb_testing_target()->QuitMessageLoop(instance); +} + +void PPB_Testing_Proxy::OnMsgGetLiveObjectsForInstance(PP_Instance instance, + uint32_t* result) { + *result = ppb_testing_target()->GetLiveObjectsForInstance(instance); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_testing_proxy.h b/ppapi/proxy/ppb_testing_proxy.h new file mode 100644 index 0000000..352a2ae --- /dev/null +++ b/ppapi/proxy/ppb_testing_proxy.h @@ -0,0 +1,50 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_TESTING_PROXY_H_ +#define PPAPI_PROXY_PPB_TESTING_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PP_Point; +struct PPB_Testing_Dev; + +namespace pp { +namespace proxy { + +class PPB_Testing_Proxy : public InterfaceProxy { + public: + PPB_Testing_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_Testing_Proxy(); + + static const Info* GetInfo(); + + const PPB_Testing_Dev* ppb_testing_target() const { + return static_cast<const PPB_Testing_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgReadImageData(const HostResource& device_context_2d, + const HostResource& image, + const PP_Point& top_left, + PP_Bool* result); + void OnMsgRunMessageLoop(PP_Instance instance); + void OnMsgQuitMessageLoop(PP_Instance instance); + void OnMsgGetLiveObjectsForInstance(PP_Instance instance, uint32_t* result); + + DISALLOW_COPY_AND_ASSIGN(PPB_Testing_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_TESTING_PROXY_H_ diff --git a/ppapi/proxy/ppb_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc new file mode 100644 index 0000000..b2d6276 --- /dev/null +++ b/ppapi/proxy/ppb_url_loader_proxy.cc @@ -0,0 +1,595 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_url_loader_proxy.h" + +#include <algorithm> +#include <deque> +#include <vector> + +#include "base/logging.h" +#include "build/build_config.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_url_response_info_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_url_loader_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +#if defined(OS_LINUX) +#include <sys/shm.h> +#endif + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_URLLoader_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +// The maximum size we'll read into the plugin without being explicitly +// asked for a larger buffer. +const int32_t kMaxReadBufferSize = 16777216; // 16MB + +// Called in the renderer when the byte counts have changed. We send a message +// to the plugin to synchronize its counts so it can respond to status polls +// from the plugin. +void UpdateResourceLoadStatus(PP_Instance pp_instance, + PP_Resource pp_resource, + int64 bytes_sent, + int64 total_bytes_to_be_sent, + int64 bytes_received, + int64 total_bytes_to_be_received) { + Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance); + if (!dispatcher) + return; + + PPBURLLoader_UpdateProgress_Params params; + params.instance = pp_instance; + params.resource.SetHostResource(pp_instance, pp_resource); + params.bytes_sent = bytes_sent; + params.total_bytes_to_be_sent = total_bytes_to_be_sent; + params.bytes_received = bytes_received; + params.total_bytes_to_be_received = total_bytes_to_be_received; + dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress( + INTERFACE_ID_PPB_URL_LOADER, params)); +} + +InterfaceProxy* CreateURLLoaderProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_URLLoader_Proxy(dispatcher, target_interface); +} + +} // namespace + +// URLLoader ------------------------------------------------------------------- + +class URLLoader : public PluginResource, public PPB_URLLoader_API { + public: + URLLoader(const HostResource& resource); + virtual ~URLLoader(); + + // ResourceObjectBase overrides. + virtual PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; + + // PPB_URLLoader_API implementation. + virtual int32_t Open(PP_Resource request_id, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t FollowRedirect(PP_CompletionCallback callback) OVERRIDE; + virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) OVERRIDE; + virtual PP_Bool GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) OVERRIDE; + virtual PP_Resource GetResponseInfo() OVERRIDE; + virtual int32_t ReadResponseBody(void* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t FinishStreamingToFile( + PP_CompletionCallback callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual void GrantUniversalAccess() OVERRIDE; + virtual void SetStatusCallback( + PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE; + + // Called when the browser has new up/download progress to report. + void UpdateProgress(const PPBURLLoader_UpdateProgress_Params& params); + + // Called when the browser responds to our ReadResponseBody request. + void ReadResponseBodyAck(int32 result, const std::string& data); + + private: + // Reads the give bytes out of the buffer_, placing them in the given output + // buffer, and removes the bytes from the buffer. + // + // The size must be not more than the current size of the buffer. + void PopBuffer(void* output_buffer, int32_t output_size); + + // Initialized to -1. Will be set to nonnegative values by the UpdateProgress + // message when the values are known. + int64_t bytes_sent_; + int64_t total_bytes_to_be_sent_; + int64_t bytes_received_; + int64_t total_bytes_to_be_received_; + + // When an asynchronous read is pending, this will contain the callback and + // the buffer to put the data. + PP_CompletionCallback current_read_callback_; + void* current_read_buffer_; + int32_t current_read_buffer_size_; + + // A buffer of all the data that's been sent to us from the host that we + // have yet to send out to the plugin. + std::deque<char> buffer_; + + // Cached copy of the response info. When nonzero, we're holding a reference + // to this resource. + PP_Resource response_info_; + + private: + DISALLOW_COPY_AND_ASSIGN(URLLoader); +}; + +URLLoader::URLLoader(const HostResource& resource) + : PluginResource(resource), + bytes_sent_(-1), + total_bytes_to_be_sent_(-1), + bytes_received_(-1), + total_bytes_to_be_received_(-1), + current_read_callback_(PP_MakeCompletionCallback(NULL, NULL)), + current_read_buffer_(NULL), + current_read_buffer_size_(0), + response_info_(0) { +} + +URLLoader::~URLLoader() { + // Always need to fire completion callbacks to prevent a leak in the plugin. + if (current_read_callback_.func) { + // TODO(brettw) the callbacks at this level should be refactored with a + // more automatic tracking system like we have in the renderer. + MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( + current_read_callback_.func, current_read_callback_.user_data, + static_cast<int32_t>(PP_ERROR_ABORTED))); + } + + if (response_info_) + PluginResourceTracker::GetInstance()->ReleaseResource(response_info_); +} + +PPB_URLLoader_API* URLLoader::AsPPB_URLLoader_API() { + return this; +} + +int32_t URLLoader::Open(PP_Resource request_id, + PP_CompletionCallback callback) { + PluginResource* request_object = + PluginResourceTracker::GetInstance()->GetResourceObject(request_id); + if (!request_object) + return PP_ERROR_BADARGUMENT; + + // TODO(brettw) http://crbug.com/86279: SendCallback doesn't ensure that + // the proper callback semantics happen if the object is deleted. + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open( + INTERFACE_ID_PPB_URL_LOADER, host_resource(), + request_object->host_resource(), + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoader::FollowRedirect(PP_CompletionCallback callback) { + // TODO(brettw) http://crbug.com/86279: SendCallback doesn't ensure that + // the proper callback semantics happen if the object is deleted. + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect( + INTERFACE_ID_PPB_URL_LOADER, host_resource(), + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool URLLoader::GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) { + if (bytes_sent_ == -1) { + *bytes_sent = 0; + *total_bytes_to_be_sent = 0; + return PP_FALSE; + } + *bytes_sent = bytes_sent_; + *total_bytes_to_be_sent = total_bytes_to_be_sent_; + return PP_TRUE; +} + +PP_Bool URLLoader::GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) { + if (bytes_received_ == -1) { + *bytes_received = 0; + *total_bytes_to_be_received = 0; + return PP_FALSE; + } + *bytes_received = bytes_received_; + *total_bytes_to_be_received = total_bytes_to_be_received_; + return PP_TRUE; +} + +PP_Resource URLLoader::GetResponseInfo() { + if (!response_info_) { + HostResource response_id; + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo( + INTERFACE_ID_PPB_URL_LOADER, host_resource(), &response_id)); + if (response_id.is_null()) + return 0; + + response_info_ = PPB_URLResponseInfo_Proxy::CreateResponseForResource( + response_id); + } + + // The caller expects to get a ref, and we want to keep holding ours. + PluginResourceTracker::GetInstance()->AddRefResource(response_info_); + return response_info_; +} + +int32_t URLLoader::ReadResponseBody(void* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + if (!buffer || bytes_to_read <= 0) + return PP_ERROR_BADARGUMENT; // Must specify an output buffer. + if (current_read_callback_.func) + return PP_ERROR_INPROGRESS; // Can only have one request pending. + + // Currently we don't support sync calls to read. We'll need to revisit + // how this works when we allow blocking calls (from background threads). + if (!callback.func) + return PP_ERROR_BADARGUMENT; + + if (static_cast<size_t>(bytes_to_read) <= buffer_.size()) { + // Special case: we've buffered enough data to be able to synchronously + // return data to the caller. Do so without making IPCs. + PopBuffer(buffer, bytes_to_read); + return bytes_to_read; + } + + current_read_callback_ = callback; + current_read_buffer_ = buffer; + current_read_buffer_size_ = bytes_to_read; + + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody( + INTERFACE_ID_PPB_URL_LOADER, host_resource(), bytes_to_read)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoader::FinishStreamingToFile(PP_CompletionCallback callback) { + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile( + INTERFACE_ID_PPB_URL_LOADER, host_resource(), + GetDispatcher()->callback_tracker().SendCallback(callback))); + return PP_OK_COMPLETIONPENDING; +} + +void URLLoader::Close() { + GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Close( + INTERFACE_ID_PPB_URL_LOADER, host_resource())); +} + +void URLLoader::GrantUniversalAccess() { + GetDispatcher()->Send( + new PpapiHostMsg_PPBURLLoader_GrantUniversalAccess( + INTERFACE_ID_PPB_URL_LOADER, host_resource())); +} + +void URLLoader::SetStatusCallback( + PP_URLLoaderTrusted_StatusCallback cb) { + // Not implemented in the proxied version, this is for implementing the + // proxy itself in the host. +} + +void URLLoader::UpdateProgress( + const PPBURLLoader_UpdateProgress_Params& params) { + bytes_sent_ = params.bytes_sent; + total_bytes_to_be_sent_ = params.total_bytes_to_be_sent; + bytes_received_ = params.bytes_received; + total_bytes_to_be_received_ = params.total_bytes_to_be_received; +} + +void URLLoader::ReadResponseBodyAck(int32 result, const std::string& data) { + if (!current_read_callback_.func || !current_read_buffer_) { + NOTREACHED(); + return; + } + + // Append the data we requested to the internal buffer. + // TODO(brettw) avoid double-copying data that's coming from IPC and going + // into the plugin buffer (we can skip the internal buffer in this case). + buffer_.insert(buffer_.end(), data.begin(), data.end()); + + if (result >= 0) { + // Fill the user buffer. We may get fewer bytes than requested in the + // case of stream end. + int32_t bytes_to_return = std::min(current_read_buffer_size_, + static_cast<int32_t>(buffer_.size())); + PopBuffer(current_read_buffer_, bytes_to_return); + result = bytes_to_return; + } + + // The plugin should be able to make a new request from their callback, so + // we have to clear our copy first. + PP_RunAndClearCompletionCallback(¤t_read_callback_, result); +} + +void URLLoader::PopBuffer(void* output_buffer, int32_t output_size) { + CHECK(output_size <= static_cast<int32_t>(buffer_.size())); + std::copy(buffer_.begin(), + buffer_.begin() + output_size, + static_cast<char*>(output_buffer)); + buffer_.erase(buffer_.begin(), + buffer_.begin() + output_size); +} + +// PPB_URLLoader_Proxy --------------------------------------------------------- + +struct PPB_URLLoader_Proxy::ReadCallbackInfo { + HostResource resource; + std::string read_buffer; +}; + +PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + host_urlloader_trusted_interface_(NULL) { +} + +PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() { +} + +// static +PP_Resource PPB_URLLoader_Proxy::TrackPluginResource( + const HostResource& url_loader_resource) { + linked_ptr<URLLoader> object(new URLLoader(url_loader_resource)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +// static +const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_URLLoader_Thunk(), + PPB_URLLOADER_INTERFACE, + INTERFACE_ID_PPB_URL_LOADER, + false, + &CreateURLLoaderProxy, + }; + return &info; +} + +// static +const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetTrustedInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_URLLoaderTrusted_Thunk(), + PPB_URLLOADERTRUSTED_INTERFACE, + INTERFACE_ID_NONE, // URL_LOADER is the canonical one. + false, + &CreateURLLoaderProxy + }; + return &info; +} + +// static +PP_Resource PPB_URLLoader_Proxy::CreateProxyResource(PP_Instance pp_instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create( + INTERFACE_ID_PPB_URL_LOADER, pp_instance, &result)); + if (result.is_null()) + return 0; + return PPB_URLLoader_Proxy::TrackPluginResource(result); +} + +bool PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create, + OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open, + OnMsgOpen) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect, + OnMsgFollowRedirect) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo, + OnMsgGetResponseInfo) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody, + OnMsgReadResponseBody) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile, + OnMsgFinishStreamingToFile) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close, + OnMsgClose) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess, + OnMsgGrantUniversalAccess) + + IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress, + OnMsgUpdateProgress) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack, + OnMsgReadResponseBodyAck) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_URLLoader_Proxy::PrepareURLLoaderForSendingToPlugin( + PP_Resource resource) { + // So the plugin can query load status, we need to register our status + // callback before sending any URLLoader to the plugin. + EnterResourceNoLock<PPB_URLLoader_API> enter(resource, false); + if (enter.succeeded()) + enter.object()->SetStatusCallback(&UpdateResourceLoadStatus); + else + NOTREACHED(); // Only called internally, resource should be valid. +} + +void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance, + HostResource* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource(instance, + enter.functions()->CreateURLLoader(instance)); + PrepareURLLoaderForSendingToPlugin(result->host_resource()); + } +} + +void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader, + const HostResource& request_info, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) + result = enter.object()->Open(request_info.host_resource(), callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); + // TODO(brettw) bug 73236 register for the status callbacks. +} + +void PPB_URLLoader_Proxy::OnMsgFollowRedirect( + const HostResource& loader, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) + result = enter.object()->FollowRedirect(callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(const HostResource& loader, + HostResource* result) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + if (enter.succeeded()) { + result->SetHostResource(loader.instance(), + enter.object()->GetResponseInfo()); + } +} + +void PPB_URLLoader_Proxy::OnMsgReadResponseBody( + const HostResource& loader, + int32_t bytes_to_read) { + // The plugin could be sending us malicious messages, don't accept negative + // sizes. + if (bytes_to_read < 0) { + // TODO(brettw) kill plugin. + bytes_to_read = 0; + } + + // Read more than requested if there are bytes available for synchronous + // reading. This prevents us from getting too far behind due to IPC message + // latency. Any extra data will get buffered in the plugin. + int32_t synchronously_available_bytes = + static_cast<HostDispatcher*>(dispatcher())->ppb_proxy()-> + GetURLLoaderBufferedBytes(loader.host_resource()); + if (bytes_to_read < kMaxReadBufferSize) { + // Grow the amount to read so we read ahead synchronously, if possible. + bytes_to_read = + std::max(bytes_to_read, + std::min(synchronously_available_bytes, kMaxReadBufferSize)); + } + + // This heap object will get deleted by the callback handler. + // TODO(brettw) this will be leaked if the plugin closes the resource! + // (Also including the plugin unloading and having the resource implicitly + // destroyed. Depending on the cleanup ordering, we may not need the weak + // pointer here.) + ReadCallbackInfo* info = new ReadCallbackInfo; + info->resource = loader; + // TODO(brettw) have a way to check for out-of-memory. + info->read_buffer.resize(bytes_to_read); + + CompletionCallback callback = callback_factory_.NewOptionalCallback( + &PPB_URLLoader_Proxy::OnReadCallback, info); + + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) { + result = enter.object()->ReadResponseBody( + const_cast<char*>(info->read_buffer.c_str()), + bytes_to_read, callback.pp_completion_callback()); + } + if (result != PP_OK_COMPLETIONPENDING) { + // Send error (or perhaps success for synchronous reads) back to plugin. + // The callback function is already set up to do this and also delete the + // callback info. + callback.Run(result); + } +} + +void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile( + const HostResource& loader, + uint32_t serialized_callback) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = PP_ERROR_BADRESOURCE; + if (enter.succeeded()) + result = enter.object()->FinishStreamingToFile(callback); + if (result != PP_OK_COMPLETIONPENDING) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_URLLoader_Proxy::OnMsgClose(const HostResource& loader) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + if (enter.succeeded()) + enter.object()->Close(); +} + +void PPB_URLLoader_Proxy::OnMsgGrantUniversalAccess( + const HostResource& loader) { + EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); + if (enter.succeeded()) + enter.object()->GrantUniversalAccess(); +} + +// Called in the Plugin. +void PPB_URLLoader_Proxy::OnMsgUpdateProgress( + const PPBURLLoader_UpdateProgress_Params& params) { + EnterPluginFromHostResource<PPB_URLLoader_API> enter(params.resource); + if (enter.succeeded()) + static_cast<URLLoader*>(enter.object())->UpdateProgress(params); +} + +// Called in the Plugin. +void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck( + const HostResource& host_resource, + int32 result, + const std::string& data) { + EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource); + if (enter.succeeded()) + static_cast<URLLoader*>(enter.object())->ReadResponseBodyAck(result, data); +} + +void PPB_URLLoader_Proxy::OnReadCallback(int32_t result, + ReadCallbackInfo* info) { + int32_t bytes_read = 0; + if (result > 0) + bytes_read = result; // Positive results indicate bytes read. + info->read_buffer.resize(bytes_read); + + dispatcher()->Send(new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack( + INTERFACE_ID_PPB_URL_LOADER, info->resource, result, info->read_buffer)); + + delete info; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_url_loader_proxy.h b/ppapi/proxy/ppb_url_loader_proxy.h new file mode 100644 index 0000000..0ff7b7e --- /dev/null +++ b/ppapi/proxy/ppb_url_loader_proxy.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_URL_LOADER_PROXY_H_ +#define PPAPI_PPB_URL_LOADER_PROXY_H_ + +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h" + +struct PPB_URLLoader; +struct PPB_URLLoaderTrusted; + +namespace pp { +namespace proxy { + +struct PPBURLLoader_UpdateProgress_Params; + +class PPB_URLLoader_Proxy : public InterfaceProxy { + public: + PPB_URLLoader_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_URLLoader_Proxy(); + + static const Info* GetInfo(); + static const Info* GetTrustedInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // URLLoader objects are normally allocated by the Create function, but + // they are also provided to PPP_Instance.OnMsgHandleDocumentLoad. This + // function allows the proxy for DocumentLoad to create the correct plugin + // proxied info for the given browser-supplied URLLoader resource ID. + static PP_Resource TrackPluginResource( + const HostResource& url_loader_resource); + + const PPB_URLLoader* ppb_url_loader_target() const { + return reinterpret_cast<const PPB_URLLoader*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // URLLoader objects are sent from places other than just URLLoader.Create, + // in particular when doing a full-frame plugin. This function does the + // necessary setup in the host before the resource is sent. Call this any + // time you're sending a new URLLoader that the plugin hasn't seen yet. + void PrepareURLLoaderForSendingToPlugin(PP_Resource resource); + + private: + // Data associated with callbacks for ReadResponseBody. + struct ReadCallbackInfo; + + // Plugin->renderer message handlers. + void OnMsgCreate(PP_Instance instance, + HostResource* result); + void OnMsgOpen(const HostResource& loader, + const HostResource& request_info, + uint32_t serialized_callback); + void OnMsgFollowRedirect(const HostResource& loader, + uint32_t serialized_callback); + void OnMsgGetResponseInfo(const HostResource& loader, + HostResource* result); + void OnMsgReadResponseBody(const HostResource& loader, + int32_t bytes_to_read); + void OnMsgFinishStreamingToFile(const HostResource& loader, + uint32_t serialized_callback); + void OnMsgClose(const HostResource& loader); + void OnMsgGrantUniversalAccess(const HostResource& loader); + + // Renderer->plugin message handlers. + void OnMsgUpdateProgress( + const PPBURLLoader_UpdateProgress_Params& params); + void OnMsgReadResponseBodyAck(const HostResource& pp_resource, + int32_t result, + const std::string& data); + + // Handles callbacks for read complete messages. Takes ownership of the info + // pointer. + void OnReadCallback(int32_t result, ReadCallbackInfo* info); + + CompletionCallbackFactory<PPB_URLLoader_Proxy, + ProxyNonThreadSafeRefCount> callback_factory_; + + // Valid only in the host, this lazily-initialized pointer indicates the + // URLLoaderTrusted interface. + const PPB_URLLoaderTrusted* host_urlloader_trusted_interface_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_URL_LOADER_PROXY_H_ diff --git a/ppapi/proxy/ppb_url_request_info_proxy.cc b/ppapi/proxy/ppb_url_request_info_proxy.cc new file mode 100644 index 0000000..9d545a2 --- /dev/null +++ b/ppapi/proxy/ppb_url_request_info_proxy.cc @@ -0,0 +1,206 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_url_request_info_proxy.h" + +#include "ppapi/c/ppb_url_request_info.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/thunk/ppb_url_request_info_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::EnterFunctionNoLock; +using ppapi::thunk::PPB_URLRequestInfo_API; +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateURLRequestInfoProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_URLRequestInfo_Proxy(dispatcher, target_interface); +} + +} // namespace + +class URLRequestInfo : public PluginResource, + public PPB_URLRequestInfo_API { + public: + URLRequestInfo(const HostResource& resource); + virtual ~URLRequestInfo(); + + virtual PPB_URLRequestInfo_API* AsPPB_URLRequestInfo_API() OVERRIDE; + + // PPB_URLRequestInfo_API implementation. + virtual PP_Bool SetProperty(PP_URLRequestProperty property, + PP_Var var) OVERRIDE; + virtual PP_Bool AppendDataToBody(const void* data, uint32_t len) OVERRIDE; + virtual PP_Bool AppendFileToBody( + PP_Resource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(URLRequestInfo); +}; + +URLRequestInfo::URLRequestInfo(const HostResource& resource) + : PluginResource(resource) { +} + +URLRequestInfo::~URLRequestInfo() { +} + +PPB_URLRequestInfo_API* URLRequestInfo::AsPPB_URLRequestInfo_API() { + return this; +} + +PP_Bool URLRequestInfo::SetProperty(PP_URLRequestProperty property, + PP_Var var) { + GetDispatcher()->Send(new PpapiHostMsg_PPBURLRequestInfo_SetProperty( + INTERFACE_ID_PPB_URL_REQUEST_INFO, host_resource(), + static_cast<int32_t>(property), + SerializedVarSendInput(GetDispatcher(), var))); + + // TODO(brettw) do some validation on the types. We should be able to tell on + // the plugin side whether the request will succeed or fail in the renderer. + return PP_TRUE; +} + +PP_Bool URLRequestInfo::AppendDataToBody(const void* data, uint32_t len) { + GetDispatcher()->Send(new PpapiHostMsg_PPBURLRequestInfo_AppendDataToBody( + INTERFACE_ID_PPB_URL_REQUEST_INFO, host_resource(), + std::string(static_cast<const char*>(data), len))); + + // TODO(brettw) do some validation. We should be able to tell on the plugin + // side whether the request will succeed or fail in the renderer. + return PP_TRUE; +} + +PP_Bool URLRequestInfo::AppendFileToBody(PP_Resource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + PP_Time expected_last_modified_time) { + PluginResource* file_ref_object = + PluginResourceTracker::GetInstance()->GetResourceObject(file_ref); + if (!file_ref_object) + return PP_FALSE; + + GetDispatcher()->Send(new PpapiHostMsg_PPBURLRequestInfo_AppendFileToBody( + INTERFACE_ID_PPB_URL_REQUEST_INFO, host_resource(), + file_ref_object->host_resource(), + start_offset, number_of_bytes, expected_last_modified_time)); + + // TODO(brettw) do some validation. We should be able to tell on the plugin + // side whether the request will succeed or fail in the renderer. + return PP_TRUE; +} + +// PPB_URLRequestInfo_Proxy ---------------------------------------------------- + +PPB_URLRequestInfo_Proxy::PPB_URLRequestInfo_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_URLRequestInfo_Proxy::~PPB_URLRequestInfo_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_URLRequestInfo_Proxy::GetInfo() { + static const Info info = { + ::ppapi::thunk::GetPPB_URLRequestInfo_Thunk(), + PPB_URLREQUESTINFO_INTERFACE, + INTERFACE_ID_PPB_URL_REQUEST_INFO, + false, + &CreateURLRequestInfoProxy, + }; + return &info; +} + +// static +PP_Resource PPB_URLRequestInfo_Proxy::CreateProxyResource( + PP_Instance instance) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + dispatcher->Send(new PpapiHostMsg_PPBURLRequestInfo_Create( + INTERFACE_ID_PPB_URL_REQUEST_INFO, instance, &result)); + if (result.is_null()) + return 0; + + linked_ptr<URLRequestInfo> object(new URLRequestInfo(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_URLRequestInfo_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_URLRequestInfo_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLRequestInfo_Create, OnMsgCreate) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLRequestInfo_SetProperty, + OnMsgSetProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLRequestInfo_AppendDataToBody, + OnMsgAppendDataToBody) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLRequestInfo_AppendFileToBody, + OnMsgAppendFileToBody) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw): handle bad messages. + return handled; +} + +void PPB_URLRequestInfo_Proxy::OnMsgCreate( + PP_Instance instance, + HostResource* result) { + EnterFunctionNoLock<ResourceCreationAPI> enter(instance, true); + if (enter.succeeded()) { + result->SetHostResource(instance, + enter.functions()->CreateURLRequestInfo(instance)); + } +} + +void PPB_URLRequestInfo_Proxy::OnMsgSetProperty( + HostResource request, + int32_t property, + SerializedVarReceiveInput value) { + EnterHostFromHostResource<PPB_URLRequestInfo_API> enter(request); + if (enter.succeeded()) { + enter.object()->SetProperty(static_cast<PP_URLRequestProperty>(property), + value.Get(dispatcher())); + } +} + +void PPB_URLRequestInfo_Proxy::OnMsgAppendDataToBody( + HostResource request, + const std::string& data) { + EnterHostFromHostResource<PPB_URLRequestInfo_API> enter(request); + if (enter.succeeded()) + enter.object()->AppendDataToBody(data.c_str(), data.size()); +} + +void PPB_URLRequestInfo_Proxy::OnMsgAppendFileToBody( + HostResource request, + HostResource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + double expected_last_modified_time) { + EnterHostFromHostResource<PPB_URLRequestInfo_API> enter(request); + if (enter.succeeded()) { + enter.object()->AppendFileToBody( + file_ref.host_resource(), start_offset, number_of_bytes, + expected_last_modified_time); + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_url_request_info_proxy.h b/ppapi/proxy/ppb_url_request_info_proxy.h new file mode 100644 index 0000000..5bfb4d4 --- /dev/null +++ b/ppapi/proxy/ppb_url_request_info_proxy.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_URL_REQUEST_INFO_PROXY_H_ +#define PPAPI_PROXY_PPB_URL_REQUEST_INFO_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_URLRequestInfo; + +namespace pp { +namespace proxy { + +class SerializedVarReceiveInput; + +class PPB_URLRequestInfo_Proxy : public InterfaceProxy { + public: + PPB_URLRequestInfo_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_URLRequestInfo_Proxy(); + + static const Info* GetInfo(); + + static PP_Resource CreateProxyResource(PP_Instance instance); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgCreate(PP_Instance instance, HostResource* result); + void OnMsgSetProperty(HostResource request, + int32_t property, + SerializedVarReceiveInput value); + void OnMsgAppendDataToBody(HostResource request, + const std::string& data); + void OnMsgAppendFileToBody(HostResource request, + HostResource file_ref, + int64_t start_offset, + int64_t number_of_bytes, + double expected_last_modified_time); + + DISALLOW_COPY_AND_ASSIGN(PPB_URLRequestInfo_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_URL_REQUEST_INFO_PROXY_H_ diff --git a/ppapi/proxy/ppb_url_response_info_proxy.cc b/ppapi/proxy/ppb_url_response_info_proxy.cc new file mode 100644 index 0000000..7d6f17d --- /dev/null +++ b/ppapi/proxy/ppb_url_response_info_proxy.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_url_response_info_proxy.h" + +#include "ppapi/c/ppb_url_response_info.h" +#include "ppapi/proxy/enter_proxy.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/serialized_var.h" +#include "ppapi/thunk/ppb_url_response_info_api.h" +#include "ppapi/thunk/thunk.h" + +using ppapi::thunk::PPB_URLResponseInfo_API; + +namespace pp { +namespace proxy { + +namespace { + +InterfaceProxy* CreateURLResponseInfoProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_URLResponseInfo_Proxy(dispatcher, target_interface); +} + +} // namespace + +// URLResponseInfo ------------------------------------------------------------- + +class URLResponseInfo : public PluginResource, + public PPB_URLResponseInfo_API { + public: + URLResponseInfo(const HostResource& resource); + virtual ~URLResponseInfo(); + + // ResourceObjectBase override. + virtual PPB_URLResponseInfo_API* AsPPB_URLResponseInfo_API() OVERRIDE; + + // PPB_URLResponseInfo_API implementation. + virtual PP_Var GetProperty(PP_URLResponseProperty property) OVERRIDE; + virtual PP_Resource GetBodyAsFileRef() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(URLResponseInfo); +}; + +URLResponseInfo::URLResponseInfo(const HostResource& resource) + : PluginResource(resource) { +} + +URLResponseInfo::~URLResponseInfo() { +} + +PPB_URLResponseInfo_API* URLResponseInfo::AsPPB_URLResponseInfo_API() { + return this; +} + +PP_Var URLResponseInfo::GetProperty(PP_URLResponseProperty property) { + ReceiveSerializedVarReturnValue result; + GetDispatcher()->Send(new PpapiHostMsg_PPBURLResponseInfo_GetProperty( + INTERFACE_ID_PPB_URL_RESPONSE_INFO, host_resource(), property, &result)); + return result.Return(GetDispatcher()); +} + +PP_Resource URLResponseInfo::GetBodyAsFileRef() { + // This could be more efficient by having the host automatically send us the + // file ref when the request is streaming to a file and it's in the state + // where the file is ready. This will prevent us from having to do this sync + // IPC here. + PPBFileRef_CreateInfo create_info; + GetDispatcher()->Send(new PpapiHostMsg_PPBURLResponseInfo_GetBodyAsFileRef( + INTERFACE_ID_PPB_URL_RESPONSE_INFO, host_resource(), &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +// PPB_URLResponseInfo_Proxy --------------------------------------------------- + +PPB_URLResponseInfo_Proxy::PPB_URLResponseInfo_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_URLResponseInfo_Proxy::~PPB_URLResponseInfo_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_URLResponseInfo_Proxy::GetInfo() { + static const Info info = { + ppapi::thunk::GetPPB_URLResponseInfo_Thunk(), + PPB_URLRESPONSEINFO_INTERFACE, + INTERFACE_ID_PPB_URL_RESPONSE_INFO, + false, + &CreateURLResponseInfoProxy, + }; + return &info; +} + +// static +PP_Resource PPB_URLResponseInfo_Proxy::CreateResponseForResource( + const HostResource& resource) { + linked_ptr<URLResponseInfo> object(new URLResponseInfo(resource)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +bool PPB_URLResponseInfo_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_URLResponseInfo_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLResponseInfo_GetProperty, + OnMsgGetProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLResponseInfo_GetBodyAsFileRef, + OnMsgGetBodyAsFileRef) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw): handle bad messages. + return handled; +} + +void PPB_URLResponseInfo_Proxy::OnMsgGetProperty( + const HostResource& response, + int32_t property, + SerializedVarReturnValue result) { + EnterHostFromHostResource<PPB_URLResponseInfo_API> enter(response); + PP_Var result_var = PP_MakeUndefined(); + if (enter.succeeded()) { + result_var = enter.object()->GetProperty( + static_cast<PP_URLResponseProperty>(property)); + } + result.Return(dispatcher(), result_var); +} + +void PPB_URLResponseInfo_Proxy::OnMsgGetBodyAsFileRef( + const HostResource& response, + PPBFileRef_CreateInfo* result) { + EnterHostFromHostResource<PPB_URLResponseInfo_API> enter(response); + PP_Resource file_ref = 0; + if (enter.succeeded()) + file_ref = enter.object()->GetBodyAsFileRef(); + + // Use the FileRef proxy to serialize. + DCHECK(!dispatcher()->IsPlugin()); + HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher()); + PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>( + host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF)); + file_ref_proxy->SerializeFileRef(file_ref, result); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_url_response_info_proxy.h b/ppapi/proxy/ppb_url_response_info_proxy.h new file mode 100644 index 0000000..ed6fb43 --- /dev/null +++ b/ppapi/proxy/ppb_url_response_info_proxy.h @@ -0,0 +1,55 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_URL_RESPONSE_INFO_PROXY_H_ +#define PPAPI_PROXY_PPB_URL_RESPONSE_INFO_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_URLResponseInfo; + +namespace pp { +namespace proxy { + +struct PPBFileRef_CreateInfo; +class SerializedVarReturnValue; + +class PPB_URLResponseInfo_Proxy : public InterfaceProxy { + public: + PPB_URLResponseInfo_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_URLResponseInfo_Proxy(); + + static const Info* GetInfo(); + + // URLResponseInfo objects are actually created and returned by the + // URLLoader. This function allows the URLLoader to convert a new + // HostResource representing a response info to a properly tracked + // URLReponseInfo PluginResource. Returns the plugin resource ID for the + // new resource. + static PP_Resource CreateResponseForResource(const HostResource& resource); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgGetProperty(const HostResource& response, + int32_t property, + SerializedVarReturnValue result); + void OnMsgGetBodyAsFileRef(const HostResource& response, + PPBFileRef_CreateInfo* result); + + DISALLOW_COPY_AND_ASSIGN(PPB_URLResponseInfo_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_URL_RESPONSE_INFO_PROXY_H_ diff --git a/ppapi/proxy/ppb_url_util_proxy.cc b/ppapi/proxy/ppb_url_util_proxy.cc new file mode 100644 index 0000000..b59ef3c --- /dev/null +++ b/ppapi/proxy/ppb_url_util_proxy.cc @@ -0,0 +1,228 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_url_util_proxy.h" + +#include "base/basictypes.h" +#include "ppapi/c/dev/ppb_url_util_dev.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/url_util_impl.h" + +namespace pp { +namespace proxy { + +using ppapi::URLUtilImpl; + +namespace { + +URLUtilImpl::VarFromUtf8 GetVarFromUtf8() { + const PPB_Var_Deprecated* var_deprecated = + static_cast<const PPB_Var_Deprecated*>( + PluginDispatcher::GetInterfaceFromDispatcher( + PPB_VAR_DEPRECATED_INTERFACE)); + return var_deprecated->VarFromUtf8; +} + +const std::string* GetStringFromVar(PP_Var var) { + return PluginVarTracker::GetInstance()->GetExistingString(var); +} + +PP_Var Canonicalize(PP_Var url, + PP_URLComponents_Dev* components) { + return URLUtilImpl::Canonicalize(&GetStringFromVar, GetVarFromUtf8(), + 0, url, components); +} + +// Helper function for the functions below that optionally take a components +// structure. It's annoying to serialze the large PP_URLComponents structure +// and this data often isn't needed. +// +// To avoid this, we instead just parse the result again in the plugin, which +// this function does if the given URL is valid and the components are +// non-NULL. The URL var will be returned. +PP_Var ConvertComponentsAndReturnURL(PP_Var url, + PP_URLComponents_Dev* components) { + if (!components) + return url; // Common case - plugin doesn't care about parsing. + + const std::string* url_string = GetStringFromVar(url); + if (!url_string) + return url; + + PP_Var result = Canonicalize(url, components); + PluginVarTracker::GetInstance()->Release(url); + return result; +} + +PP_Var ResolveRelativeToURL(PP_Var base_url, + PP_Var relative, + PP_URLComponents_Dev* components) { + return URLUtilImpl::ResolveRelativeToURL(&GetStringFromVar, GetVarFromUtf8(), + 0, base_url, relative, components); +} + +PP_Var ResolveRelativeToDocument(PP_Instance instance, + PP_Var relative_string, + PP_URLComponents_Dev* components) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeNull(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBURLUtil_ResolveRelativeToDocument( + INTERFACE_ID_PPB_URL_UTIL, instance, + SerializedVarSendInput(dispatcher, relative_string), + &result)); + return ConvertComponentsAndReturnURL(result.Return(dispatcher), components); +} + +PP_Bool IsSameSecurityOrigin(PP_Var url_a, PP_Var url_b) { + return URLUtilImpl::IsSameSecurityOrigin(&GetStringFromVar, url_a, url_b); +} + +PP_Bool DocumentCanRequest(PP_Instance instance, PP_Var url) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_FALSE; + + PP_Bool result = PP_FALSE; + dispatcher->Send(new PpapiHostMsg_PPBURLUtil_DocumentCanRequest( + INTERFACE_ID_PPB_URL_UTIL, instance, + SerializedVarSendInput(dispatcher, url), + &result)); + return result; +} + +PP_Bool DocumentCanAccessDocument(PP_Instance active, PP_Instance target) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(active); + if (!dispatcher) + return PP_FALSE; + + PP_Bool result = PP_FALSE; + dispatcher->Send(new PpapiHostMsg_PPBURLUtil_DocumentCanAccessDocument( + INTERFACE_ID_PPB_URL_UTIL, active, target, &result)); + return result; +} + +PP_Var GetDocumentURL(PP_Instance instance, + struct PP_URLComponents_Dev* components) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeNull(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBURLUtil_GetDocumentURL( + INTERFACE_ID_PPB_URL_UTIL, instance, &result)); + return ConvertComponentsAndReturnURL(result.Return(dispatcher), components); +} + +PP_Var GetPluginInstanceURL(PP_Instance instance, + struct PP_URLComponents_Dev* components) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeNull(); + + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiHostMsg_PPBURLUtil_GetPluginInstanceURL( + INTERFACE_ID_PPB_URL_UTIL, instance, &result)); + return ConvertComponentsAndReturnURL(result.Return(dispatcher), components); +} + +const PPB_URLUtil_Dev url_util_interface = { + &Canonicalize, + &ResolveRelativeToURL, + &ResolveRelativeToDocument, + &IsSameSecurityOrigin, + &DocumentCanRequest, + &DocumentCanAccessDocument, + &GetDocumentURL, + &GetPluginInstanceURL +}; + +InterfaceProxy* CreateURLUtilProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_URLUtil_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_URLUtil_Proxy::PPB_URLUtil_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_URLUtil_Proxy::~PPB_URLUtil_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_URLUtil_Proxy::GetInfo() { + static const Info info = { + &url_util_interface, + PPB_URLUTIL_DEV_INTERFACE, + INTERFACE_ID_PPB_URL_UTIL, + false, + &CreateURLUtilProxy, + }; + return &info; +} + +bool PPB_URLUtil_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_URLUtil_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLUtil_ResolveRelativeToDocument, + OnMsgResolveRelativeToDocument) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLUtil_DocumentCanRequest, + OnMsgDocumentCanRequest) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLUtil_DocumentCanAccessDocument, + OnMsgDocumentCanAccessDocument) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLUtil_GetDocumentURL, + OnMsgGetDocumentURL) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLUtil_GetPluginInstanceURL, + OnMsgGetPluginInstanceURL) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPB_URLUtil_Proxy::OnMsgResolveRelativeToDocument( + PP_Instance instance, + SerializedVarReceiveInput relative, + SerializedVarReturnValue result) { + result.Return(dispatcher(), + ppb_url_util_target()->ResolveRelativeToDocument( + instance, relative.Get(dispatcher()), NULL)); +} + +void PPB_URLUtil_Proxy::OnMsgDocumentCanRequest(PP_Instance instance, + SerializedVarReceiveInput url, + PP_Bool* result) { + *result = ppb_url_util_target()->DocumentCanRequest(instance, + url.Get(dispatcher())); +} + +void PPB_URLUtil_Proxy::OnMsgDocumentCanAccessDocument(PP_Instance active, + PP_Instance target, + PP_Bool* result) { + *result = ppb_url_util_target()->DocumentCanAccessDocument( + active, target); +} + +void PPB_URLUtil_Proxy::OnMsgGetDocumentURL(PP_Instance instance, + SerializedVarReturnValue result) { + result.Return(dispatcher(), + ppb_url_util_target()->GetDocumentURL(instance, NULL)); +} + +void PPB_URLUtil_Proxy::OnMsgGetPluginInstanceURL( + PP_Instance instance, SerializedVarReturnValue result) { + result.Return(dispatcher(), + ppb_url_util_target()->GetPluginInstanceURL(instance, NULL)); +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/ppb_url_util_proxy.h b/ppapi/proxy/ppb_url_util_proxy.h new file mode 100644 index 0000000..548d2ef --- /dev/null +++ b/ppapi/proxy/ppb_url_util_proxy.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPB_URL_UTIL_PROXY_H_ +#define PPAPI_PROXY_PPB_URL_UTIL_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/proxy/serialized_var.h" + +struct PPB_URLUtil_Dev; + +namespace pp { +namespace proxy { + +class PPB_URLUtil_Proxy : public InterfaceProxy { + public: + PPB_URLUtil_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPB_URLUtil_Proxy(); + + static const Info* GetInfo(); + + const PPB_URLUtil_Dev* ppb_url_util_target() const { + return static_cast<const PPB_URLUtil_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgResolveRelativeToDocument(PP_Instance instance, + SerializedVarReceiveInput relative, + SerializedVarReturnValue result); + void OnMsgDocumentCanRequest(PP_Instance instance, + SerializedVarReceiveInput url, + PP_Bool* result); + void OnMsgDocumentCanAccessDocument(PP_Instance active, + PP_Instance target, + PP_Bool* result); + void OnMsgGetDocumentURL(PP_Instance instance, + SerializedVarReturnValue result); + void OnMsgGetPluginInstanceURL(PP_Instance instance, + SerializedVarReturnValue result); + + DISALLOW_COPY_AND_ASSIGN(PPB_URLUtil_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPB_URL_UTIL_PROXY_H_ + diff --git a/ppapi/proxy/ppb_var_deprecated_proxy.cc b/ppapi/proxy/ppb_var_deprecated_proxy.cc new file mode 100644 index 0000000..652bdc8 --- /dev/null +++ b/ppapi/proxy/ppb_var_deprecated_proxy.cc @@ -0,0 +1,523 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_var_deprecated_proxy.h" + +#include <stdlib.h> // For malloc + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/task.h" +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_var_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppp_class_proxy.h" +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +namespace proxy { + +namespace { + +// Used to do get the set-up information for calling a var object. If the +// exception is set, returns NULL. Otherwise, computes the dispatcher for the +// given var object. If the var is not a valid object, returns NULL and sets +// the exception. +PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object, + PP_Var* exception) { + // If an exception is already set, we don't need to do anything, just return + // an error to the caller. + if (exception && exception->type != PP_VARTYPE_UNDEFINED) + return NULL; + + PluginVarTracker* tracker = PluginVarTracker::GetInstance(); + PluginDispatcher* dispatcher = tracker->DispatcherForPluginObject(object); + if (dispatcher) + return dispatcher; + + // The object is invalid. This means we can't figure out which dispatcher + // to use, which is OK because the call will fail anyway. Set the exception. + if (exception) { + exception->type = PP_VARTYPE_STRING; + exception->value.as_id = + tracker->MakeString("Attempting to use an invalid object"); + } + return NULL; +} + +// PPP_Var_Deprecated plugin --------------------------------------------------- + +void AddRefVar(PP_Var var) { + PluginVarTracker::GetInstance()->AddRef(var); +} + +void ReleaseVar(PP_Var var) { + PluginVarTracker::GetInstance()->Release(var); +} + +PP_Var VarFromUtf8(PP_Module module, const char* data, uint32_t len) { + PP_Var ret = {}; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = PluginVarTracker::GetInstance()->MakeString( + data, len); + return ret; +} + +const char* VarToUtf8(PP_Var var, uint32_t* len) { + const std::string* str = + PluginVarTracker::GetInstance()->GetExistingString(var); + if (str) { + *len = static_cast<uint32_t>(str->size()); + return str->c_str(); + } + *len = 0; + return NULL; +} + +bool HasProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return false; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return PP_ToBool(result); +} + +bool HasMethod(PP_Var var, + PP_Var name, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return false; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return PP_ToBool(result); +} + +PP_Var GetProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedException se(dispatcher, exception); + ReceiveSerializedVarReturnValue result; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } + return result.Return(dispatcher); +} + +void EnumerateProperties(PP_Var var, + uint32_t* property_count, + PP_Var** properties, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) { + *property_count = 0; + *properties = NULL; + return; + } + + ReceiveSerializedVarVectorOutParam out_vector(dispatcher, + property_count, properties); + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + out_vector.OutParam(), &se)); + } +} + +void SetProperty(PP_Var var, + PP_Var name, + PP_Var value, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return; + + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), + SerializedVarSendInput(dispatcher, value), &se)); + } +} + +void RemoveProperty(PP_Var var, + PP_Var name, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); + if (!dispatcher) + return; + + ReceiveSerializedException se(dispatcher, exception); + PP_Bool result = PP_FALSE; + if (!se.IsThrown()) { + dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, var), + SerializedVarSendInput(dispatcher, name), &se, &result)); + } +} + +PP_Var Call(PP_Var object, + PP_Var method_name, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); + + dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, object), + SerializedVarSendInput(dispatcher, method_name), argv_vect, + &se, &result)); + } + return result.Return(dispatcher); +} + +PP_Var Construct(PP_Var object, + uint32_t argc, + PP_Var* argv, + PP_Var* exception) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + ReceiveSerializedException se(dispatcher, exception); + if (!se.IsThrown()) { + std::vector<SerializedVar> argv_vect; + SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); + + dispatcher->Send(new PpapiHostMsg_PPBVar_Construct( + INTERFACE_ID_PPB_VAR_DEPRECATED, + SerializedVarSendInput(dispatcher, object), + argv_vect, &se, &result)); + } + return result.Return(dispatcher); +} + +bool IsInstanceOf(PP_Var var, + const PPP_Class_Deprecated* ppp_class, + void** ppp_class_data) { + Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL); + if (!dispatcher) + return false; + + PP_Bool result = PP_FALSE; + int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); + int64 class_data_int = 0; + dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated( + INTERFACE_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var), + class_int, &class_data_int, &result)); + *ppp_class_data = + reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int)); + return PP_ToBool(result); +} + +PP_Var CreateObject(PP_Instance instance, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return PP_MakeUndefined(); + + ReceiveSerializedVarReturnValue result; + int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); + int64 data_int = + static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class_data)); + dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated( + INTERFACE_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int, + &result)); + return result.Return(dispatcher); +} + +const PPB_Var_Deprecated var_deprecated_interface = { + &AddRefVar, + &ReleaseVar, + &VarFromUtf8, + &VarToUtf8, + &HasProperty, + &HasMethod, + &GetProperty, + &EnumerateProperties, + &SetProperty, + &RemoveProperty, + &Call, + &Construct, + &IsInstanceOf, + &CreateObject +}; + +InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Var_Deprecated_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy( + Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface), + task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Var_Deprecated_Proxy::GetInfo() { + static const Info info = { + &var_deprecated_interface, + PPB_VAR_DEPRECATED_INTERFACE, + INTERFACE_ID_PPB_VAR_DEPRECATED, + false, + &CreateVarDeprecatedProxy, + }; + return &info; +} + +bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) { + // Prevent the dispatcher from going away during a call to Call or other + // function that could mutate the DOM. This must happen OUTSIDE of + // the message handlers since the SerializedVars use the dispatcher upon + // return of the function (converting the SerializedVarReturnValue/OutParam + // to a SerializedVar in the destructor). + ScopedModuleReference death_grip(dispatcher()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty, + OnMsgHasProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated, + OnMsgHasMethodDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty, + OnMsgGetProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty, + OnMsgDeleteProperty) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties, + OnMsgEnumerateProperties) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated, + OnMsgSetPropertyDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated, + OnMsgCallDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct, + OnMsgConstruct) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, + OnMsgIsInstanceOfDeprecated) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated, + OnMsgCreateObjectDeprecated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + // TODO(brettw) handle bad messages! + return handled; +} + +void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id, + int* /* unused */) { + PP_Var var; + var.type = PP_VARTYPE_OBJECT; + var.value.as_id = object_id; + ppb_var_target()->AddRef(var); +} + +void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) { + // Ok, so this is super subtle. + // When the browser side sends a sync IPC message that returns a var, and the + // plugin wants to give ownership of that var to the browser, dropping all + // references, it may call ReleaseObject right after returning the result. + // However, the IPC system doesn't enforce strict ordering of messages in that + // case, where a message that is set to unblock (e.g. a sync message, or in + // our case all messages coming from the plugin) that is sent *after* the + // result may be dispatched on the browser side *before* the sync send + // returned (see ipc_sync_channel.cc). In this case, that means it could + // release the object before it is AddRef'ed on the browser side. + // To work around this, we post a task here, that will not execute before + // control goes back to the main message loop, that will ensure the sync send + // has returned and the browser side can take its reference before we Release. + // Note: if the instance is gone by the time the task is executed, then it + // will Release the objects itself and this Release will be a NOOP (aside of a + // spurious warning). + // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and + // then remove this. + MessageLoop::current()->PostNonNestableTask(FROM_HERE, + task_factory_.NewRunnableMethod( + &PPB_Var_Deprecated_Proxy::DoReleaseObject, object_id)); +} + +void PPB_Var_Deprecated_Proxy::OnMsgHasProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + *result = PP_FromBool(ppb_var_target()->HasProperty( + var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + *result = PP_FromBool(ppb_var_target()->HasMethod( + var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgGetProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + result.Return(dispatcher(), ppb_var_target()->GetProperty( + var.Get(dispatcher()), name.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties( + SerializedVarReceiveInput var, + SerializedVarVectorOutParam props, + SerializedVarOutParam exception) { + SetAllowPluginReentrancy(); + ppb_var_target()->GetAllPropertyNames(var.Get(dispatcher()), + props.CountOutParam(), props.ArrayOutParam(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarReceiveInput value, + SerializedVarOutParam exception) { + SetAllowPluginReentrancy(); + ppb_var_target()->SetProperty(var.Get(dispatcher()), + name.Get(dispatcher()), + value.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty( + SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result) { + SetAllowPluginReentrancy(); + ppb_var_target()->RemoveProperty(var.Get(dispatcher()), + name.Get(dispatcher()), + exception.OutParam(dispatcher())); + // This deprecated function doesn't actually return a value, but we re-use + // the message from the non-deprecated interface with the return value. + *result = PP_TRUE; +} + +void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated( + SerializedVarReceiveInput object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ppb_var_target()->Call( + object.Get(dispatcher()), + method_name.Get(dispatcher()), + arg_count, args, + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgConstruct( + SerializedVarReceiveInput var, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ppb_var_target()->Construct( + var.Get(dispatcher()), arg_count, args, + exception.OutParam(dispatcher()))); +} + +void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated( + pp::proxy::SerializedVarReceiveInput var, + int64 ppp_class, + int64* ppp_class_data, + PP_Bool* result) { + // TODO(brettw) write this. +} + +void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated( + PP_Instance instance, + int64 ppp_class, + int64 class_data, + SerializedVarReturnValue result) { + SetAllowPluginReentrancy(); + result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject( + ppb_var_target(), dispatcher(), instance, ppp_class, class_data)); +} + +void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() { + if (dispatcher()->IsPlugin()) + NOTREACHED(); + else + static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); +} + +void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) { + PP_Var var; + var.type = PP_VARTYPE_OBJECT; + var.value.as_id = object_id; + ppb_var_target()->Release(var); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_var_deprecated_proxy.h b/ppapi/proxy/ppb_var_deprecated_proxy.h new file mode 100644 index 0000000..1e6a70c --- /dev/null +++ b/ppapi/proxy/ppb_var_deprecated_proxy.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_VAR_DEPRECATED_PROXY_H_ +#define PPAPI_PPB_VAR_DEPRECATED_PROXY_H_ + +#include <vector> + +#include "base/task.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Var_Deprecated; + +namespace pp { +namespace proxy { + +class SerializedVar; +class SerializedVarArray; +class SerializedVarReceiveInput; +class SerializedVarVectorOutParam; +class SerializedVarVectorReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPB_Var_Deprecated_Proxy : public InterfaceProxy { + public: + PPB_Var_Deprecated_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Var_Deprecated_Proxy(); + + static const Info* GetInfo(); + + const PPB_Var_Deprecated* ppb_var_target() const { + return static_cast<const PPB_Var_Deprecated*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgAddRefObject(int64 object_id, int* unused); + void OnMsgReleaseObject(int64 object_id); + void OnMsgHasProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgHasMethodDeprecated(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgGetProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgEnumerateProperties( + SerializedVarReceiveInput var, + SerializedVarVectorOutParam props, + SerializedVarOutParam exception); + void OnMsgSetPropertyDeprecated(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarReceiveInput value, + SerializedVarOutParam exception); + void OnMsgDeleteProperty(SerializedVarReceiveInput var, + SerializedVarReceiveInput name, + SerializedVarOutParam exception, + PP_Bool* result); + void OnMsgCall(SerializedVarReceiveInput object, + SerializedVarReceiveInput this_object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgCallDeprecated(SerializedVarReceiveInput object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgConstruct(SerializedVarReceiveInput var, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgIsInstanceOfDeprecated(pp::proxy::SerializedVarReceiveInput var, + int64 ppp_class, + int64* ppp_class_data, + PP_Bool* result); + void OnMsgCreateObjectDeprecated(PP_Instance instance, + int64 ppp_class, + int64 ppp_class_data, + SerializedVarReturnValue result); + + // Call in the host for messages that can be reentered. + void SetAllowPluginReentrancy(); + + void DoReleaseObject(int64 object_id); + ScopedRunnableMethodFactory<PPB_Var_Deprecated_Proxy> task_factory_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_VAR_DEPRECATED_PROXY_H_ diff --git a/ppapi/proxy/ppb_var_proxy.cc b/ppapi/proxy/ppb_var_proxy.cc new file mode 100644 index 0000000..063d4d3 --- /dev/null +++ b/ppapi/proxy/ppb_var_proxy.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppb_var_proxy.h" + +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_var.h" +#include "ppapi/proxy/plugin_var_tracker.h" + +namespace pp { +namespace proxy { + +namespace { + +// PPP_Var plugin -------------------------------------------------------------- + +void AddRefVar(PP_Var var) { + PluginVarTracker::GetInstance()->AddRef(var); +} + +void ReleaseVar(PP_Var var) { + PluginVarTracker::GetInstance()->Release(var); +} + +PP_Var VarFromUtf8(PP_Module module, const char* data, uint32_t len) { + PP_Var ret = {}; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = PluginVarTracker::GetInstance()->MakeString(data, len); + return ret; +} + +const char* VarToUtf8(PP_Var var, uint32_t* len) { + const std::string* str = + PluginVarTracker::GetInstance()->GetExistingString(var); + if (str) { + *len = static_cast<uint32_t>(str->size()); + return str->c_str(); + } + *len = 0; + return NULL; +} + +const PPB_Var var_interface = { + &AddRefVar, + &ReleaseVar, + &VarFromUtf8, + &VarToUtf8 +}; + +InterfaceProxy* CreateVarProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_Var_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPB_Var_Proxy::PPB_Var_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPB_Var_Proxy::~PPB_Var_Proxy() { +} + +// static +const InterfaceProxy::Info* PPB_Var_Proxy::GetInfo() { + static const Info info = { + &var_interface, + PPB_VAR_INTERFACE, + INTERFACE_ID_PPB_VAR, + false, + &CreateVarProxy, + }; + return &info; +} + +bool PPB_Var_Proxy::OnMessageReceived(const IPC::Message& msg) { + // All PPB_Var calls are handled locally; there is no need to send or receive + // messages here. + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppb_var_proxy.h b/ppapi/proxy/ppb_var_proxy.h new file mode 100644 index 0000000..e527aab --- /dev/null +++ b/ppapi/proxy/ppb_var_proxy.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PPB_VAR_PROXY_H_ +#define PPAPI_PPB_VAR_PROXY_H_ + +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Var; + +namespace pp { +namespace proxy { + +class PPB_Var_Proxy : public InterfaceProxy { + public: + PPB_Var_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPB_Var_Proxy(); + + static const Info* GetInfo(); + + const PPB_Var* ppb_var_target() const { + return static_cast<const PPB_Var*>(target_interface()); + } + + // InterfaceProxy implementation. In this case, no messages are sent or + // received, so this always returns false. + virtual bool OnMessageReceived(const IPC::Message& msg); + +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PPB_VAR_PROXY_H_ diff --git a/ppapi/proxy/ppp_class_proxy.cc b/ppapi/proxy/ppp_class_proxy.cc new file mode 100644 index 0000000..0a020cc --- /dev/null +++ b/ppapi/proxy/ppp_class_proxy.cc @@ -0,0 +1,298 @@ +// 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/ppp_class_proxy.h" + +#include "ppapi/c/dev/ppb_var_deprecated.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +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 p, int64 ud) + : dispatcher(d), + ppp_class(p), + user_data(ud) { + } + + Dispatcher* dispatcher; + int64 ppp_class; + int64 user_data; +}; + +ObjectProxy* ToObjectProxy(void* data) { + return reinterpret_cast<ObjectProxy*>(data); +} + +bool HasProperty(void* object, PP_Var name, PP_Var* exception) { + ObjectProxy* obj = ToObjectProxy(object); + bool result = false; + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty( + INTERFACE_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); + bool result = false; + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod( + INTERFACE_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); + ReceiveSerializedException se(obj->dispatcher, exception); + ReceiveSerializedVarReturnValue result; + obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty( + INTERFACE_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); + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty( + INTERFACE_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); + ReceiveSerializedException se(obj->dispatcher, exception); + obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty( + INTERFACE_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); + + 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( + INTERFACE_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); + + 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( + INTERFACE_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); + obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate( + INTERFACE_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 object from IPC to a PPP_Class* for calling into the +// plugin's implementation. +const PPP_Class_Deprecated* ToPPPClass(int64 value) { + return reinterpret_cast<const PPP_Class_Deprecated*>( + static_cast<intptr_t>(value)); +} + +// Converts an int64 object from IPC to a void* for calling into the plugin's +// implementation as the user data. +void* ToUserData(int64 value) { + return reinterpret_cast<void*>(static_cast<intptr_t>(value)); +} + +} // namespace + +// PPP_Class_Proxy ------------------------------------------------------------- + +PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher, NULL) { +} + +PPP_Class_Proxy::~PPP_Class_Proxy() { +} + +// static +PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var, + Dispatcher* dispatcher, + PP_Module module_id, + int64 ppp_class, + int64 class_data) { + ObjectProxy* object_proxy = new ObjectProxy(dispatcher, + ppp_class, class_data); + return var->CreateObject(module_id, &class_interface, object_proxy); +} + +bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) { + 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 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result) { + *result = ToPPPClass(ppp_class)->HasProperty(ToUserData(object), + property.Get(dispatcher()), exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result) { + *result = ToPPPClass(ppp_class)->HasMethod(ToUserData(object), + property.Get(dispatcher()), exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + result.Return(dispatcher(), ToPPPClass(ppp_class)->GetProperty( + ToUserData(object), property.Get(dispatcher()), + exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgEnumerateProperties( + int64 ppp_class, int64 object, + std::vector<pp::proxy::SerializedVar>* props, + SerializedVarOutParam exception) { + NOTIMPLEMENTED(); + // TODO(brettw) implement this. +} + +void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarReceiveInput value, + SerializedVarOutParam exception) { + ToPPPClass(ppp_class)->SetProperty( + ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception) { + ToPPPClass(ppp_class)->RemoveProperty( + ToUserData(object), property.Get(dispatcher()), + exception.OutParam(dispatcher())); +} + +void PPP_Class_Proxy::OnMsgCall( + int64 ppp_class, int64 object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ToPPPClass(ppp_class)->Call( + ToUserData(object), method_name.Get(dispatcher()), + arg_count, args, exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgConstruct( + int64 ppp_class, int64 object, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result) { + uint32_t arg_count = 0; + PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); + result.Return(dispatcher(), ToPPPClass(ppp_class)->Construct( + ToUserData(object), arg_count, args, exception.OutParam(dispatcher()))); +} + +void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) { + ToPPPClass(ppp_class)->Deallocate(ToUserData(object)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppp_class_proxy.h b/ppapi/proxy/ppp_class_proxy.h new file mode 100644 index 0000000..2cba23d --- /dev/null +++ b/ppapi/proxy/ppp_class_proxy.h @@ -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. + +#ifndef PPAPI_PROXY_PPP_CLASS_PROXY_H_ +#define PPAPI_PROXY_PPP_CLASS_PROXY_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_Var_Deprecated; +struct PPP_Class_Deprecated; + +namespace pp { +namespace proxy { + +class SerializedVar; +class SerializedVarReceiveInput; +class SerializedVarVectorReceiveInput; +class SerializedVarOutParam; +class SerializedVarReturnValue; + +class PPP_Class_Proxy : public InterfaceProxy { + public: + // PPP_Class isn't a normal interface that you can query for, so this + // constructor doesn't take an interface pointer. + PPP_Class_Proxy(Dispatcher* dispatcher); + virtual ~PPP_Class_Proxy(); + + // Creates a proxied object in the browser process. This takes the browser's + // PPB_Var_Deprecated interface to use to create the object. The class and + static PP_Var CreateProxiedObject(const PPB_Var_Deprecated* var, + Dispatcher* dispatcher, + PP_Module module_id, + int64 ppp_class, + int64 class_data); + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // IPC message handlers. + void OnMsgHasProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result); + void OnMsgHasMethod(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + bool* result); + void OnMsgGetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgEnumerateProperties( + int64 ppp_class, int64 object, + std::vector<pp::proxy::SerializedVar>* props, + SerializedVarOutParam exception); + void OnMsgSetProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarReceiveInput value, + SerializedVarOutParam exception); + void OnMsgRemoveProperty(int64 ppp_class, int64 object, + SerializedVarReceiveInput property, + SerializedVarOutParam exception); + void OnMsgCall(int64 ppp_class, int64 object, + SerializedVarReceiveInput method_name, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgConstruct(int64 ppp_class, int64 object, + SerializedVarVectorReceiveInput arg_vector, + SerializedVarOutParam exception, + SerializedVarReturnValue result); + void OnMsgDeallocate(int64 ppp_class, int64 object); + + DISALLOW_COPY_AND_ASSIGN(PPP_Class_Proxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPP_CLASS_PROXY_H_ diff --git a/ppapi/proxy/ppp_graphics_3d_proxy.cc b/ppapi/proxy/ppp_graphics_3d_proxy.cc new file mode 100644 index 0000000..ef31e92b --- /dev/null +++ b/ppapi/proxy/ppp_graphics_3d_proxy.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppp_graphics_3d_proxy.h" + +#include "ppapi/c/dev/ppp_graphics_3d_dev.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +void ContextLost(PP_Instance instance) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPGraphics3D_ContextLost(INTERFACE_ID_PPP_GRAPHICS_3D_DEV, + instance)); +} + +static const PPP_Graphics3D_Dev graphics_3d_interface = { + &ContextLost +}; + +InterfaceProxy* CreateGraphics3DProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPP_Graphics3D_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPP_Graphics3D_Proxy::PPP_Graphics3D_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPP_Graphics3D_Proxy::~PPP_Graphics3D_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Graphics3D_Proxy::GetInfo() { + static const Info info = { + &graphics_3d_interface, + PPP_GRAPHICS_3D_DEV_INTERFACE, + INTERFACE_ID_PPP_GRAPHICS_3D_DEV, + false, + &CreateGraphics3DProxy, + }; + return &info; +} + +bool PPP_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Graphics3D_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPGraphics3D_ContextLost, + OnMsgContextLost) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Graphics3D_Proxy::OnMsgContextLost(PP_Instance instance) { + if (ppp_graphics_3d_target()) + ppp_graphics_3d_target()->Graphics3DContextLost(instance); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppp_graphics_3d_proxy.h b/ppapi/proxy/ppp_graphics_3d_proxy.h new file mode 100644 index 0000000..41c400a --- /dev/null +++ b/ppapi/proxy/ppp_graphics_3d_proxy.h @@ -0,0 +1,39 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPP_GRAPHICS_3D_PROXY_H_ +#define PPAPI_PROXY_PPP_GRAPHICS_3D_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPP_Graphics3D_Dev; + +namespace pp { +namespace proxy { + +class PPP_Graphics3D_Proxy : public InterfaceProxy { + public: + PPP_Graphics3D_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPP_Graphics3D_Proxy(); + + static const Info* GetInfo(); + + const PPP_Graphics3D_Dev* ppp_graphics_3d_target() const { + return reinterpret_cast<const PPP_Graphics3D_Dev*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgContextLost(PP_Instance instance); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPP_GRAPHICS_3D_PROXY_H_ diff --git a/ppapi/proxy/ppp_input_event_proxy.cc b/ppapi/proxy/ppp_input_event_proxy.cc new file mode 100644 index 0000000..1a1945d --- /dev/null +++ b/ppapi/proxy/ppp_input_event_proxy.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppp_input_event_proxy.h" + +#include <algorithm> + +#include "ppapi/c/ppp_input_event.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_input_event_proxy.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_input_event_api.h" + +using ppapi::InputEventData; +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_InputEvent_API; + +namespace pp { +namespace proxy { + +namespace { + +PP_Bool HandleInputEvent(PP_Instance instance, PP_Resource input_event) { + EnterResourceNoLock<PPB_InputEvent_API> enter(input_event, false); + if (enter.failed()) { + NOTREACHED(); + return PP_FALSE; + } + const InputEventData& data = enter.object()->GetInputEventData(); + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + if (!dispatcher) { + NOTREACHED(); + return PP_FALSE; + } + + // Need to send different messages depending on whether filtering is needed. + PP_Bool result = PP_FALSE; + if (data.is_filtered) { + dispatcher->Send(new PpapiMsg_PPPInputEvent_HandleFilteredInputEvent( + INTERFACE_ID_PPP_INPUT_EVENT, instance, data, &result)); + } else { + dispatcher->Send(new PpapiMsg_PPPInputEvent_HandleInputEvent( + INTERFACE_ID_PPP_INPUT_EVENT, instance, data)); + } + return result; +} + +static const PPP_InputEvent input_event_interface = { + &HandleInputEvent +}; + +InterfaceProxy* CreateInputEventProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPP_InputEvent_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPP_InputEvent_Proxy::PPP_InputEvent_Proxy(Dispatcher* dispatcher, + const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPP_InputEvent_Proxy::~PPP_InputEvent_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_InputEvent_Proxy::GetInfo() { + static const Info info = { + &input_event_interface, + PPP_INPUT_EVENT_INTERFACE, + INTERFACE_ID_PPP_INPUT_EVENT, + false, + &CreateInputEventProxy, + }; + return &info; +} + +bool PPP_InputEvent_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_InputEvent_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInputEvent_HandleInputEvent, + OnMsgHandleInputEvent) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInputEvent_HandleFilteredInputEvent, + OnMsgHandleFilteredInputEvent) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_InputEvent_Proxy::OnMsgHandleInputEvent(PP_Instance instance, + const InputEventData& data) { + PP_Resource event_resource = PPB_InputEvent_Proxy::CreateProxyResource( + instance, data); + ppp_input_event_target()->HandleInputEvent(instance, event_resource); + PluginResourceTracker::GetInstance()->ReleaseResource(event_resource); +} + +void PPP_InputEvent_Proxy::OnMsgHandleFilteredInputEvent( + PP_Instance instance, + const InputEventData& data, + PP_Bool* result) { + PP_Resource event_resource = PPB_InputEvent_Proxy::CreateProxyResource( + instance, data); + *result = ppp_input_event_target()->HandleInputEvent(instance, + event_resource); + PluginResourceTracker::GetInstance()->ReleaseResource(event_resource); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppp_input_event_proxy.h b/ppapi/proxy/ppp_input_event_proxy.h new file mode 100644 index 0000000..b294aa5 --- /dev/null +++ b/ppapi/proxy/ppp_input_event_proxy.h @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPP_INPUT_EVENT_PROXY_H_ +#define PPAPI_PROXY_PPP_INPUT_EVENT_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPP_InputEvent; + +namespace ppapi { +struct InputEventData; +} + +namespace pp { +namespace proxy { + +class PPP_InputEvent_Proxy : public InterfaceProxy { + public: + PPP_InputEvent_Proxy(Dispatcher* dispatcher, const void* target_interface); + virtual ~PPP_InputEvent_Proxy(); + + static const Info* GetInfo(); + + const PPP_InputEvent* ppp_input_event_target() const { + return static_cast<const PPP_InputEvent*>(target_interface()); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgHandleInputEvent(PP_Instance instance, + const ppapi::InputEventData& data); + void OnMsgHandleFilteredInputEvent(PP_Instance instance, + const ppapi::InputEventData& data, + PP_Bool* result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPP_INPUT_EVENT_PROXY_H_ diff --git a/ppapi/proxy/ppp_instance_private_proxy.cc b/ppapi/proxy/ppp_instance_private_proxy.cc new file mode 100644 index 0000000..20beb8a --- /dev/null +++ b/ppapi/proxy/ppp_instance_private_proxy.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppp_instance_private_proxy.h" + +#include <algorithm> + +#include "ppapi/c/pp_var.h" +#include "ppapi/c/private/ppp_instance_private.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Var GetInstanceObject(PP_Instance instance) { + Dispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + ReceiveSerializedVarReturnValue result; + dispatcher->Send(new PpapiMsg_PPPInstancePrivate_GetInstanceObject( + INTERFACE_ID_PPP_INSTANCE_PRIVATE, instance, &result)); + return result.Return(dispatcher); +} + +static const PPP_Instance_Private instance_private_interface = { + &GetInstanceObject +}; + +InterfaceProxy* CreateInstancePrivateProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPP_Instance_Private_Proxy(dispatcher, target_interface); +} + +} // namespace + +PPP_Instance_Private_Proxy::PPP_Instance_Private_Proxy( + Dispatcher* dispatcher, const void* target_interface) + : InterfaceProxy(dispatcher, target_interface) { +} + +PPP_Instance_Private_Proxy::~PPP_Instance_Private_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Instance_Private_Proxy::GetInfo() { + static const Info info = { + &instance_private_interface, + PPP_INSTANCE_PRIVATE_INTERFACE, + INTERFACE_ID_PPP_INSTANCE_PRIVATE, + false, + &CreateInstancePrivateProxy, + }; + return &info; +} + +bool PPP_Instance_Private_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Private_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstancePrivate_GetInstanceObject, + OnMsgGetInstanceObject) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Instance_Private_Proxy::OnMsgGetInstanceObject( + PP_Instance instance, + SerializedVarReturnValue result) { + result.Return(dispatcher(), + ppp_instance_private_target()->GetInstanceObject(instance)); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppp_instance_private_proxy.h b/ppapi/proxy/ppp_instance_private_proxy.h new file mode 100644 index 0000000..1df2e44 --- /dev/null +++ b/ppapi/proxy/ppp_instance_private_proxy.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ +#define PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ + +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPP_Instance_Private; + +namespace pp { +namespace proxy { + +class SerializedVarReturnValue; + +class PPP_Instance_Private_Proxy : public InterfaceProxy { + public: + PPP_Instance_Private_Proxy(Dispatcher* dispatcher, + const void* target_interface); + virtual ~PPP_Instance_Private_Proxy(); + + static const Info* GetInfo(); + + const PPP_Instance_Private* ppp_instance_private_target() const { + return reinterpret_cast<const PPP_Instance_Private*>(target_interface()); + } + + private: + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + // Message handlers. + void OnMsgGetInstanceObject(PP_Instance instance, + SerializedVarReturnValue result); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPP_INSTANCE_PRIVATE_PROXY_H_ diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc new file mode 100644 index 0000000..99dcaab --- /dev/null +++ b/ppapi/proxy/ppp_instance_proxy.cc @@ -0,0 +1,250 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppp_instance_proxy.h" + +#include <algorithm> + +#include "ppapi/c/dev/ppb_fullscreen_dev.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/host_dispatcher.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_url_loader_proxy.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Bool DidCreate(PP_Instance instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + std::vector<std::string> argn_vect; + std::vector<std::string> argv_vect; + for (uint32_t i = 0; i < argc; i++) { + argn_vect.push_back(std::string(argn[i])); + argv_vect.push_back(std::string(argv[i])); + } + + PP_Bool result = PP_FALSE; + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidCreate(INTERFACE_ID_PPP_INSTANCE, instance, + argn_vect, argv_vect, &result)); + return result; +} + +void DidDestroy(PP_Instance instance) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidDestroy(INTERFACE_ID_PPP_INSTANCE, instance)); +} + +void DidChangeView(PP_Instance instance, + const PP_Rect* position, + const PP_Rect* clip) { + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + const PPB_Fullscreen_Dev* fullscreen_interface = + static_cast<const PPB_Fullscreen_Dev*>( + dispatcher->GetLocalInterface(PPB_FULLSCREEN_DEV_INTERFACE)); + DCHECK(fullscreen_interface); + PP_Bool fullscreen = fullscreen_interface->IsFullscreen(instance); + dispatcher->Send( + new PpapiMsg_PPPInstance_DidChangeView(INTERFACE_ID_PPP_INSTANCE, + instance, *position, *clip, + fullscreen)); +} + +void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { + HostDispatcher::GetForInstance(instance)->Send( + new PpapiMsg_PPPInstance_DidChangeFocus(INTERFACE_ID_PPP_INSTANCE, + instance, has_focus)); +} + +PP_Bool HandleInputEvent(PP_Instance instance, + const PP_InputEvent* event) { + PP_Bool result = PP_FALSE; + IPC::Message* msg = new PpapiMsg_PPPInstance_HandleInputEvent( + INTERFACE_ID_PPP_INSTANCE, instance, *event, &result); + // Make this message not unblock, to avoid re-entrancy problems when the + // plugin does a synchronous call to the renderer. This will force any + // synchronous calls from the plugin to complete before processing this + // message. We avoid deadlock by never un-setting the unblock flag on messages + // from the plugin to the renderer. + msg->set_unblock(false); + HostDispatcher::GetForInstance(instance)->Send(msg); + return result; +} + +PP_Bool HandleDocumentLoad(PP_Instance instance, + PP_Resource url_loader) { + PP_Bool result = PP_FALSE; + HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); + + // Set up the URLLoader for proxying. + + PPB_URLLoader_Proxy* url_loader_proxy = static_cast<PPB_URLLoader_Proxy*>( + dispatcher->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_URL_LOADER)); + url_loader_proxy->PrepareURLLoaderForSendingToPlugin(url_loader); + + // PluginResourceTracker in the plugin process assumes that resources that it + // tracks have been addrefed on behalf of the plugin at the renderer side. So + // we explicitly do it for |url_loader| here. + // + // Please also see comments in PPP_Instance_Proxy::OnMsgHandleDocumentLoad() + // about releasing of this extra reference. + const PPB_Core* core = reinterpret_cast<const PPB_Core*>( + dispatcher->GetLocalInterface(PPB_CORE_INTERFACE)); + if (!core) { + NOTREACHED(); + return PP_FALSE; + } + core->AddRefResource(url_loader); + + HostResource serialized_loader; + serialized_loader.SetHostResource(instance, url_loader); + dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad( + INTERFACE_ID_PPP_INSTANCE, instance, serialized_loader, &result)); + return result; +} + +static const PPP_Instance_0_5 instance_interface_0_5 = { + &DidCreate, + &DidDestroy, + &DidChangeView, + &DidChangeFocus, + &HandleInputEvent, + &HandleDocumentLoad +}; + +template <class PPP_Instance_Type> +InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPP_Instance_Proxy( + dispatcher, + static_cast<const PPP_Instance_Type*>(target_interface)); +} + +} // namespace + +PPP_Instance_Proxy::~PPP_Instance_Proxy() { +} + +// static +const InterfaceProxy::Info* PPP_Instance_Proxy::GetInfo0_5() { + static const Info info = { + &instance_interface_0_5, + PPP_INSTANCE_INTERFACE_0_5, + INTERFACE_ID_PPP_INSTANCE, + false, + &CreateInstanceProxy<PPP_Instance_0_5>, + }; + return &info; +} + +bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate, + OnMsgDidCreate) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy, + OnMsgDidDestroy) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView, + OnMsgDidChangeView) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus, + OnMsgDidChangeFocus) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleInputEvent, + OnMsgHandleInputEvent) + IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleDocumentLoad, + OnMsgHandleDocumentLoad) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PPP_Instance_Proxy::OnMsgDidCreate( + PP_Instance instance, + const std::vector<std::string>& argn, + const std::vector<std::string>& argv, + PP_Bool* result) { + *result = PP_FALSE; + if (argn.size() != argv.size()) + return; + + // Set up the routing associating this new instance with the dispatcher we + // just got the message from. This must be done before calling into the + // plugin so it can in turn call PPAPI functions. + PluginDispatcher* plugin_dispatcher = + static_cast<PluginDispatcher*>(dispatcher()); + plugin_dispatcher->DidCreateInstance(instance); + + // Make sure the arrays always have at least one element so we can take the + // address below. + std::vector<const char*> argn_array( + std::max(static_cast<size_t>(1), argn.size())); + std::vector<const char*> argv_array( + std::max(static_cast<size_t>(1), argn.size())); + for (size_t i = 0; i < argn.size(); i++) { + argn_array[i] = argn[i].c_str(); + argv_array[i] = argv[i].c_str(); + } + + DCHECK(combined_interface_.get()); + *result = combined_interface_->DidCreate(instance, + static_cast<uint32_t>(argn.size()), + &argn_array[0], &argv_array[0]); +} + +void PPP_Instance_Proxy::OnMsgDidDestroy(PP_Instance instance) { + combined_interface_->DidDestroy(instance); + static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance); +} + +void PPP_Instance_Proxy::OnMsgDidChangeView(PP_Instance instance, + const PP_Rect& position, + const PP_Rect& clip, + PP_Bool fullscreen) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + InstanceData* data = dispatcher->GetInstanceData(instance); + if (!data) + return; + data->position = position; + data->fullscreen = fullscreen; + combined_interface_->DidChangeView(instance, &position, &clip); +} + +void PPP_Instance_Proxy::OnMsgDidChangeFocus(PP_Instance instance, + PP_Bool has_focus) { + combined_interface_->DidChangeFocus(instance, has_focus); +} + +void PPP_Instance_Proxy::OnMsgHandleInputEvent(PP_Instance instance, + const PP_InputEvent& event, + PP_Bool* result) { + *result = combined_interface_->HandleInputEvent(instance, &event); +} + +void PPP_Instance_Proxy::OnMsgHandleDocumentLoad(PP_Instance instance, + const HostResource& url_loader, + PP_Bool* result) { + PP_Resource plugin_loader = + PPB_URLLoader_Proxy::TrackPluginResource(url_loader); + *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader); + + // This balances the one reference that TrackPluginResource() initialized it + // with. The plugin will normally take an additional reference which will keep + // the resource alive in the plugin (and the one reference in the renderer + // representing all plugin references). + // Once all references at the plugin side are released, the renderer side will + // be notified and release the reference added in HandleDocumentLoad() above. + PluginResourceTracker::GetInstance()->ReleaseResource(plugin_loader); +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/ppp_instance_proxy.h b/ppapi/proxy/ppp_instance_proxy.h new file mode 100644 index 0000000..9448332 --- /dev/null +++ b/ppapi/proxy/ppp_instance_proxy.h @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ +#define PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ + +#include <string> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_proxy.h" +#include "ppapi/shared_impl/ppp_instance_combined.h" + +struct PP_InputEvent; +struct PP_Rect; + +namespace pp { +namespace proxy { + +class SerializedVarReturnValue; + +class PPP_Instance_Proxy : public InterfaceProxy { + public: + template <class PPP_Instance_Type> + PPP_Instance_Proxy(Dispatcher* dispatcher, + const PPP_Instance_Type* target_interface) + : InterfaceProxy(dispatcher, static_cast<const void*>(target_interface)), + combined_interface_( + new ::ppapi::PPP_Instance_Combined(*target_interface)) { + } + virtual ~PPP_Instance_Proxy(); + + // Return the info for the 0.5 (latest, canonical) version of the interface. + static const Info* GetInfo0_5(); + + ::ppapi::PPP_Instance_Combined* ppp_instance_target() const { + return combined_interface_.get(); + } + + // InterfaceProxy implementation. + virtual bool OnMessageReceived(const IPC::Message& msg); + + private: + // Message handlers. + void OnMsgDidCreate(PP_Instance instance, + const std::vector<std::string>& argn, + const std::vector<std::string>& argv, + PP_Bool* result); + void OnMsgDidDestroy(PP_Instance instance); + void OnMsgDidChangeView(PP_Instance instance, + const PP_Rect& position, + const PP_Rect& clip, + PP_Bool fullscreen); + void OnMsgDidChangeFocus(PP_Instance instance, PP_Bool has_focus); + void OnMsgHandleInputEvent(PP_Instance instance, + const PP_InputEvent& event, + PP_Bool* result); + void OnMsgHandleDocumentLoad(PP_Instance instance, + const HostResource& url_loader, + PP_Bool* result); + scoped_ptr< ::ppapi::PPP_Instance_Combined> combined_interface_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PPP_INSTANCE_PROXY_H_ diff --git a/ppapi/proxy/ppp_instance_proxy_test.cc b/ppapi/proxy/ppp_instance_proxy_test.cc new file mode 100644 index 0000000..00d776b --- /dev/null +++ b/ppapi/proxy/ppp_instance_proxy_test.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/synchronization/waitable_event.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/c/dev/ppb_fullscreen_dev.h" +#include "ppapi/c/pp_var.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppapi_proxy_test.h" + +namespace pp { +namespace proxy { + +namespace { +// This is a poor man's mock of PPP_Instance using global variables. Eventually +// we should generalize making PPAPI interface mocks by using IDL or macro/ +// template magic. +PP_Instance received_instance; +uint32_t received_argc; +std::vector<std::string> received_argn; +std::vector<std::string> received_argv; +PP_Bool bool_to_return; +PP_Bool DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], + const char* argv[]) { + received_instance = instance; + received_argc = argc; + received_argn.clear(); + received_argn.insert(received_argn.begin(), argn, argn + argc); + received_argv.clear(); + received_argv.insert(received_argv.begin(), argv, argv + argc); + return bool_to_return; +} + +void DidDestroy(PP_Instance instance) { + received_instance = instance; +} + +PP_Rect received_position; +PP_Rect received_clip; +// DidChangeView is asynchronous. We wait until the call has completed before +// proceeding on to the next test. +base::WaitableEvent did_change_view_called(false, false); +void DidChangeView(PP_Instance instance, const PP_Rect* position, + const PP_Rect* clip) { + received_instance = instance; + received_position = *position; + received_clip = *clip; + did_change_view_called.Signal(); +} + +PP_Bool received_has_focus; +base::WaitableEvent did_change_focus_called(false, false); +void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { + received_instance = instance; + received_has_focus = has_focus; + did_change_focus_called.Signal(); +} + +PP_InputEvent received_event; +PP_Bool HandleInputEvent(PP_Instance instance, const PP_InputEvent* event) { + received_instance = instance; + memcpy(&received_event, event, sizeof(*event));; + return bool_to_return; +} + +PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) { + // This one requires use of the PPB_URLLoader proxy and PPB_Core, plus a + // resource tracker for the url_loader resource. + // TODO(dmichael): Mock those out and test this function. + NOTREACHED(); + return PP_FALSE; +} + +PP_Var var_to_return; +PP_Var GetInstanceObject(PP_Instance instance) { + received_instance = instance; + return var_to_return; +} + +// Clear all the 'received' values for our mock. Call this before you expect +// one of the functions to be invoked. TODO(dmichael): It would be better to +// have a flag also for each function, so we know the right one got called. +void ResetReceived() { + received_instance = 0; + received_argc = 0; + received_argn.clear(); + received_argv.clear(); + memset(&received_position, 0, sizeof(received_position)); + memset(&received_clip, 0, sizeof(received_clip)); + received_has_focus = PP_FALSE; + memset(&received_event, 0, sizeof(received_event)); +} + +PPP_Instance_0_5 ppp_instance_0_5 = { + &DidCreate, + &DidDestroy, + &DidChangeView, + &DidChangeFocus, + &HandleInputEvent, + &HandleDocumentLoad +}; + +// PPP_Instance_Proxy::DidChangeView relies on PPB_FullscreenDev being +// available with a valid implementation of IsFullScreen, so we mock it. +PP_Bool IsFullscreen(PP_Instance instance) { + return PP_FALSE; +} +PPB_Fullscreen_Dev ppb_fullscreen_dev = { &IsFullscreen }; + +} // namespace + +class PPP_Instance_ProxyTest : public TwoWayTest { + public: + PPP_Instance_ProxyTest() + : TwoWayTest(TwoWayTest::TEST_PPP_INTERFACE) { + } +}; + +TEST_F(PPP_Instance_ProxyTest, PPPInstance0_5) { + plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_0_5, &ppp_instance_0_5); + host().RegisterTestInterface(PPB_FULLSCREEN_DEV_INTERFACE, + &ppb_fullscreen_dev); + + // Grab the host-side proxy for the 0.5 interface. + const PPP_Instance_0_5* ppp_instance = static_cast<const PPP_Instance_0_5*>( + host().host_dispatcher()->GetProxiedInterface( + PPP_INSTANCE_INTERFACE_0_5)); + + // Call each function in turn, make sure we get the expected values and + // returns. + // + // We don't test DidDestroy, because it has the side-effect of removing the + // PP_Instance from the PluginDispatcher, which will cause a failure later + // when the test is torn down. + PP_Instance expected_instance = pp_instance(); + std::vector<std::string> expected_argn, expected_argv; + expected_argn.push_back("Hello"); + expected_argn.push_back("world."); + expected_argv.push_back("elloHay"); + expected_argv.push_back("orldway."); + std::vector<const char*> argn_to_pass, argv_to_pass; + CHECK(expected_argn.size() == expected_argv.size()); + for (size_t i = 0; i < expected_argn.size(); ++i) { + argn_to_pass.push_back(expected_argn[i].c_str()); + argv_to_pass.push_back(expected_argv[i].c_str()); + } + uint32_t expected_argc = expected_argn.size(); + bool_to_return = PP_TRUE; + ResetReceived(); + EXPECT_EQ(bool_to_return, ppp_instance->DidCreate(expected_instance, + expected_argc, + &argn_to_pass[0], + &argv_to_pass[0])); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_argc, expected_argc); + EXPECT_EQ(received_argn, expected_argn); + EXPECT_EQ(received_argv, expected_argv); + + PP_Rect expected_position = { {1, 2}, {3, 4} }; + PP_Rect expected_clip = { {5, 6}, {7, 8} }; + ResetReceived(); + ppp_instance->DidChangeView(expected_instance, &expected_position, + &expected_clip); + did_change_view_called.Wait(); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_position.point.x, expected_position.point.x); + EXPECT_EQ(received_position.point.y, expected_position.point.y); + EXPECT_EQ(received_position.size.width, expected_position.size.width); + EXPECT_EQ(received_position.size.height, expected_position.size.height); + EXPECT_EQ(received_clip.point.x, expected_clip.point.x); + EXPECT_EQ(received_clip.point.y, expected_clip.point.y); + EXPECT_EQ(received_clip.size.width, expected_clip.size.width); + EXPECT_EQ(received_clip.size.height, expected_clip.size.height); + + PP_Bool expected_has_focus = PP_TRUE; + ResetReceived(); + ppp_instance->DidChangeFocus(expected_instance, expected_has_focus); + did_change_focus_called.Wait(); + EXPECT_EQ(received_instance, expected_instance); + EXPECT_EQ(received_has_focus, expected_has_focus); + + PP_InputEvent expected_event = { PP_INPUTEVENT_TYPE_KEYDOWN, // type + 0, // padding + 1.0, // time_stamp + { { 2, 3 } } }; // u (as PP_InputEvent_Key) + ResetReceived(); + EXPECT_EQ(bool_to_return, + ppp_instance->HandleInputEvent(expected_instance, &expected_event)); + EXPECT_EQ(received_instance, expected_instance); + ASSERT_EQ(received_event.type, expected_event.type); + // Ignore padding; it's okay if it's not serialized. + EXPECT_EQ(received_event.time_stamp, expected_event.time_stamp); + EXPECT_EQ(received_event.u.key.modifier, expected_event.u.key.modifier); + EXPECT_EQ(received_event.u.key.key_code, expected_event.u.key.key_code); + + // TODO(dmichael): Need to mock out a resource Tracker to be able to test + // HandleResourceLoad. It also requires + // PPB_Core.AddRefResource and for PPB_URLLoader to be + // registered. +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/proxy_channel.cc b/ppapi/proxy/proxy_channel.cc new file mode 100644 index 0000000..d304dca --- /dev/null +++ b/ppapi/proxy/proxy_channel.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/proxy_channel.h" + +#include "ipc/ipc_platform_file.h" +#include "ipc/ipc_test_sink.h" + +namespace pp { +namespace proxy { + +ProxyChannel::ProxyChannel(base::ProcessHandle remote_process_handle) + : delegate_(NULL), + remote_process_handle_(remote_process_handle), + test_sink_(NULL) { +} + +ProxyChannel::~ProxyChannel() { +} + +bool ProxyChannel::InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client) { + delegate_ = delegate; + IPC::Channel::Mode mode = is_client ? IPC::Channel::MODE_CLIENT + : IPC::Channel::MODE_SERVER; + channel_.reset(new IPC::SyncChannel(channel_handle, mode, this, + delegate->GetIPCMessageLoop(), false, + delegate->GetShutdownEvent())); + return true; +} + +void ProxyChannel::InitWithTestSink(IPC::TestSink* test_sink) { + DCHECK(!test_sink_); + test_sink_ = test_sink; +} + +void ProxyChannel::OnChannelError() { + channel_.reset(); +} + +#if defined(OS_POSIX) +int ProxyChannel::GetRendererFD() { + DCHECK(channel()); + return channel()->GetClientFileDescriptor(); +} +#endif + +IPC::PlatformFileForTransit ProxyChannel::ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source) { + return IPC::GetFileHandleForProcess(handle, remote_process_handle_, + should_close_source); +} + +bool ProxyChannel::Send(IPC::Message* msg) { + if (test_sink_) + return test_sink_->Send(msg); + if (channel_.get()) + return channel_->Send(msg); + + // Remote side crashed, drop this message. + delete msg; + return false; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/proxy_channel.h b/ppapi/proxy/proxy_channel.h new file mode 100644 index 0000000..3dbb977 --- /dev/null +++ b/ppapi/proxy/proxy_channel.h @@ -0,0 +1,110 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PROXY_CHANNEL_H_ +#define PPAPI_PROXY_PROXY_CHANNEL_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/process.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_platform_file.h" +#include "ipc/ipc_sync_channel.h" + +namespace base { +class MessageLoopProxy; +class WaitableEvent; +} + +namespace IPC { +class TestSink; +} + +namespace pp { +namespace proxy { + +class VarSerializationRules; + +class ProxyChannel : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + typedef void (*ShutdownModuleFunc)(); + + class Delegate { + public: + // Returns the dedicated message loop for processing IPC requests. + virtual base::MessageLoopProxy* GetIPCMessageLoop() = 0; + + // Returns the event object that becomes signalled when the main thread's + // message loop exits. + virtual base::WaitableEvent* GetShutdownEvent() = 0; + }; + + virtual ~ProxyChannel(); + + // Alternative to InitWithChannel() for unit tests that want to send all + // messages sent via this channel to the given test sink. The test sink + // must outlive this class. + void InitWithTestSink(IPC::TestSink* test_sink); + + // Shares a file handle (HANDLE / file descriptor) with the remote side. It + // returns a handle that should be sent in exactly one IPC message. Upon + // receipt, the remote side then owns that handle. Note: if sending the + // message fails, the returned handle is properly closed by the IPC system. If + // should_close_source is set to true, the original handle is closed by this + // operation and should not be used again. + IPC::PlatformFileForTransit ShareHandleWithRemote( + base::PlatformFile handle, + bool should_close_source); + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* msg); + + // IPC::Channel::Listener implementation. + virtual void OnChannelError(); + + // Will be NULL in some unit tests and if the remote side has crashed. + IPC::SyncChannel* channel() const { + return channel_.get(); + } + +#if defined(OS_POSIX) + int GetRendererFD(); +#endif + + protected: + ProxyChannel(base::ProcessHandle remote_process_handle); + + // You must call this function before anything else. Returns true on success. + // The delegate pointer must outlive this class, ownership is not + // transferred. + virtual bool InitWithChannel(Delegate* delegate, + const IPC::ChannelHandle& channel_handle, + bool is_client); + + ProxyChannel::Delegate* delegate() const { + return delegate_; + } + + private: + // Non-owning pointer. Guaranteed non-NULL after init is called. + ProxyChannel::Delegate* delegate_; + + base::ProcessHandle remote_process_handle_; // See getter above. + + // When we're unit testing, this will indicate the sink for the messages to + // be deposited so they can be inspected by the test. When non-NULL, this + // indicates that the channel should not be used. + IPC::TestSink* test_sink_; + + // Will be null for some tests when there is a test_sink_, and if the + // remote side has crashed. + scoped_ptr<IPC::SyncChannel> channel_; + + DISALLOW_COPY_AND_ASSIGN(ProxyChannel); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PROXY_CHANNEL_H_ diff --git a/ppapi/proxy/proxy_module.cc b/ppapi/proxy/proxy_module.cc new file mode 100644 index 0000000..94de0c1 --- /dev/null +++ b/ppapi/proxy/proxy_module.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/proxy_module.h" + +#include "base/memory/singleton.h" + +namespace pp { +namespace proxy { + +ProxyModule::ProxyModule() { +} + +ProxyModule::~ProxyModule() { +} + +// static +ProxyModule* ProxyModule::GetInstance() { + return Singleton<ProxyModule>::get(); +} + +const std::string& ProxyModule::GetFlashCommandLineArgs() { + return flash_command_line_args_; +} + +void ProxyModule::SetFlashCommandLineArgs(const std::string& args) { + flash_command_line_args_ = args; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/proxy_module.h b/ppapi/proxy/proxy_module.h new file mode 100644 index 0000000..304f24f --- /dev/null +++ b/ppapi/proxy/proxy_module.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_PROXY_MODULE_H_ +#define PPAPI_PROXY_PROXY_MODULE_H_ + +#include <string> + +#include "base/basictypes.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace pp { +namespace proxy { + +class PluginDispatcher; +class PluginResource; + +class ProxyModule { + public: + // The global singleton getter. + static ProxyModule* GetInstance(); + + // TODO(viettrungluu): Generalize this for use with other plugins if it proves + // necessary. (Currently, we can't do this easily, since we can't tell from + // |PpapiPluginMain()| which plugin will be loaded.) + const std::string& GetFlashCommandLineArgs(); + void SetFlashCommandLineArgs(const std::string& args); + + private: + friend struct DefaultSingletonTraits<ProxyModule>; + + std::string flash_command_line_args_; + + ProxyModule(); + ~ProxyModule(); + + DISALLOW_COPY_AND_ASSIGN(ProxyModule); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PROXY_MODULE_H_ diff --git a/ppapi/proxy/proxy_non_thread_safe_ref_count.h b/ppapi/proxy/proxy_non_thread_safe_ref_count.h new file mode 100644 index 0000000..cfcb720 --- /dev/null +++ b/ppapi/proxy/proxy_non_thread_safe_ref_count.h @@ -0,0 +1,49 @@ +// 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_PROXY_NON_THREAD_SAFE_REF_COUNT_H_ +#define PPAPI_PROXY_PROXY_NON_THREAD_SAFE_REF_COUNT_H_ + +#include "base/message_loop.h" +#include "ppapi/cpp/completion_callback.h" + +namespace pp { +namespace proxy { + +// This class is just like ppapi/cpp/non_thread_safe_ref_count.h but rather +// than using pp::Module::core (which doesn't exist), it uses Chrome threads +// which do. +class ProxyNonThreadSafeRefCount { + public: + ProxyNonThreadSafeRefCount() : ref_(0) { +#ifndef NDEBUG + message_loop_ = MessageLoop::current(); +#endif + } + + ~ProxyNonThreadSafeRefCount() { + PP_DCHECK(message_loop_ == MessageLoop::current()); + } + + int32_t AddRef() { + PP_DCHECK(message_loop_ == MessageLoop::current()); + return ++ref_; + } + + int32_t Release() { + PP_DCHECK(message_loop_ == MessageLoop::current()); + return --ref_; + } + + private: + int32_t ref_; +#ifndef NDEBUG + MessageLoop* message_loop_; +#endif +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PROXY_NON_THREAD_SAFE_REF_COUNT_H_ diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc new file mode 100644 index 0000000..20e6735 --- /dev/null +++ b/ppapi/proxy/resource_creation_proxy.cc @@ -0,0 +1,316 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/resource_creation_proxy.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/pp_size.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/c/trusted/ppb_image_data_trusted.h" +#include "ppapi/proxy/plugin_resource_tracker.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_audio_config_proxy.h" +#include "ppapi/proxy/ppb_audio_proxy.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" +#include "ppapi/proxy/ppb_broker_proxy.h" +#include "ppapi/proxy/ppb_context_3d_proxy.h" +#include "ppapi/proxy/ppb_file_chooser_proxy.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/ppb_file_system_proxy.h" +#include "ppapi/proxy/ppb_flash_menu_proxy.h" +#include "ppapi/proxy/ppb_flash_net_connector_proxy.h" +#include "ppapi/proxy/ppb_flash_tcp_socket_proxy.h" +#include "ppapi/proxy/ppb_font_proxy.h" +#include "ppapi/proxy/ppb_graphics_2d_proxy.h" +#include "ppapi/proxy/ppb_image_data_proxy.h" +#include "ppapi/proxy/ppb_surface_3d_proxy.h" +#include "ppapi/proxy/ppb_url_loader_proxy.h" +#include "ppapi/proxy/ppb_url_request_info_proxy.h" +#include "ppapi/shared_impl/font_impl.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_image_data_api.h" + +using ppapi::thunk::ResourceCreationAPI; + +namespace pp { +namespace proxy { + +ResourceCreationProxy::ResourceCreationProxy(Dispatcher* dispatcher) + : dispatcher_(dispatcher) { +} + +ResourceCreationProxy::~ResourceCreationProxy() { +} + +ResourceCreationAPI* ResourceCreationProxy::AsResourceCreationAPI() { + return this; +} + +PP_Resource ResourceCreationProxy::CreateAudio( + PP_Instance instance, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data) { + return PPB_Audio_Proxy::CreateProxyResource(instance, config_id, + audio_callback, user_data); +} + +PP_Resource ResourceCreationProxy::CreateAudioConfig( + PP_Instance instance, + PP_AudioSampleRate sample_rate, + uint32_t sample_frame_count) { + return PPB_AudioConfig_Proxy::CreateProxyResource( + instance, sample_rate, sample_frame_count); +} + +PP_Resource ResourceCreationProxy::CreateAudioTrusted(PP_Instance instance) { + // Proxied plugins can't created trusted audio devices. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateBroker(PP_Instance instance) { + return PPB_Broker_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateBuffer(PP_Instance instance, + uint32_t size) { + return PPB_Buffer_Proxy::CreateProxyResource(instance, size); +} + +PP_Resource ResourceCreationProxy::CreateContext3D( + PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) { + return PPB_Context3D_Proxy::Create(instance, config, share_context, + attrib_list); +} + +PP_Resource ResourceCreationProxy::CreateContext3DRaw( + PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) { + // Not proxied. The raw creation function is used only in the implementation + // of the proxy on the host side. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateDirectoryReader( + PP_Resource directory_ref) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateFileChooser( + PP_Instance instance, + const PP_FileChooserOptions_Dev* options) { + return PPB_FileChooser_Proxy::CreateProxyResource(instance, options); +} + +PP_Resource ResourceCreationProxy::CreateFileIO(PP_Instance instance) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateFileRef(PP_Resource file_system, + const char* path) { + return PPB_FileRef_Proxy::CreateProxyResource(file_system, path); +} + +PP_Resource ResourceCreationProxy::CreateFileSystem( + PP_Instance instance, + PP_FileSystemType type) { + return PPB_FileSystem_Proxy::CreateProxyResource(instance, type); +} + +PP_Resource ResourceCreationProxy::CreateFlashMenu( + PP_Instance instance, + const PP_Flash_Menu* menu_data) { + return PPB_Flash_Menu_Proxy::CreateProxyResource(instance, menu_data); +} + +PP_Resource ResourceCreationProxy::CreateFlashNetConnector( + PP_Instance instance) { + return PPB_Flash_NetConnector_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateFlashTCPSocket( + PP_Instance instance) { + return PPB_Flash_TCPSocket_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateFontObject( + PP_Instance instance, + const PP_FontDescription_Dev* description) { + if (!ppapi::FontImpl::IsPPFontDescriptionValid(*description)) + return 0; + + linked_ptr<Font> object(new Font(HostResource::MakeInstanceOnly(instance), + *description)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +PP_Resource ResourceCreationProxy::CreateGraphics2D(PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque) { + return PPB_Graphics2D_Proxy::CreateProxyResource(instance, size, + is_always_opaque); +} + +PP_Resource ResourceCreationProxy::CreateImageData(PP_Instance instance, + PP_ImageDataFormat format, + const PP_Size& size, + PP_Bool init_to_zero) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + + HostResource result; + std::string image_data_desc; + ImageHandle image_handle = ImageData::NullHandle; + dispatcher->Send(new PpapiHostMsg_ResourceCreation_ImageData( + INTERFACE_ID_RESOURCE_CREATION, instance, format, size, init_to_zero, + &result, &image_data_desc, &image_handle)); + + if (result.is_null() || image_data_desc.size() != sizeof(PP_ImageDataDesc)) + return 0; + + // We serialize the PP_ImageDataDesc just by copying to a string. + PP_ImageDataDesc desc; + memcpy(&desc, image_data_desc.data(), sizeof(PP_ImageDataDesc)); + + linked_ptr<ImageData> object(new ImageData(result, desc, image_handle)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +PP_Resource ResourceCreationProxy::CreateGraphics3D( + PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateScrollbar(PP_Instance instance, + PP_Bool vertical) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateSurface3D( + PP_Instance instance, + PP_Config3D_Dev config, + const int32_t* attrib_list) { + return PPB_Surface3D_Proxy::CreateProxyResource(instance, config, + attrib_list); +} + +PP_Resource ResourceCreationProxy::CreateTransport(PP_Instance instance, + const char* name, + const char* proto) { + NOTIMPLEMENTED(); // Not proxied yet. + return 0; +} + +PP_Resource ResourceCreationProxy::CreateURLLoader(PP_Instance instance) { + return PPB_URLLoader_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateURLRequestInfo(PP_Instance instance) { + return PPB_URLRequestInfo_Proxy::CreateProxyResource(instance); +} + +PP_Resource ResourceCreationProxy::CreateVideoDecoder(PP_Instance instance) { + NOTIMPLEMENTED(); + return 0; +} + +PP_Resource ResourceCreationProxy::CreateVideoLayer( + PP_Instance instance, + PP_VideoLayerMode_Dev mode) { + NOTIMPLEMENTED(); + return 0; +} + +bool ResourceCreationProxy::Send(IPC::Message* msg) { + return dispatcher_->Send(msg); +} + +bool ResourceCreationProxy::OnMessageReceived(const IPC::Message& msg) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ResourceCreationProxy, msg) + IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCreation_Graphics2D, + OnMsgCreateGraphics2D) + IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCreation_ImageData, + OnMsgCreateImageData) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ResourceCreationProxy::OnMsgCreateGraphics2D(PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque, + HostResource* result) { + ppapi::thunk::EnterFunction<ResourceCreationAPI> enter(instance, false); + if (enter.succeeded()) { + result->SetHostResource(instance, enter.functions()->CreateGraphics2D( + instance, size, is_always_opaque)); + } +} + +void ResourceCreationProxy::OnMsgCreateImageData( + PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + std::string* image_data_desc, + ImageHandle* result_image_handle) { + *result_image_handle = ImageData::NullHandle; + + ppapi::thunk::EnterFunction<ResourceCreationAPI> enter(instance, false); + if (enter.failed()) + return; + + PP_Resource resource = enter.functions()->CreateImageData( + instance, static_cast<PP_ImageDataFormat>(format), size, init_to_zero); + if (!resource) + return; + result->SetHostResource(instance, resource); + + // Get the description, it's just serialized as a string. + ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API> + enter_resource(resource, false); + PP_ImageDataDesc desc; + if (enter_resource.object()->Describe(&desc) == PP_TRUE) { + image_data_desc->resize(sizeof(PP_ImageDataDesc)); + memcpy(&(*image_data_desc)[0], &desc, sizeof(PP_ImageDataDesc)); + } + + // Get the shared memory handle. + const PPB_ImageDataTrusted* trusted = + reinterpret_cast<const PPB_ImageDataTrusted*>( + dispatcher_->GetLocalInterface(PPB_IMAGEDATA_TRUSTED_INTERFACE)); + uint32_t byte_count = 0; + if (trusted) { + int32_t handle; + if (trusted->GetSharedMemory(resource, &handle, &byte_count) == PP_OK) { +#if defined(OS_WIN) + pp::proxy::ImageHandle ih = ImageData::HandleFromInt(handle); + *result_image_handle = dispatcher_->ShareHandleWithRemote(ih, false); +#else + *result_image_handle = ImageData::HandleFromInt(handle); +#endif + } + } +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h new file mode 100644 index 0000000..e6b609f --- /dev/null +++ b/ppapi/proxy/resource_creation_proxy.h @@ -0,0 +1,126 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_RESOURCE_CREATION_PROXY_H_ +#define PPAPI_PROXY_RESOURCE_CREATION_PROXY_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/function_group_base.h" +#include "ppapi/thunk/resource_creation_api.h" + +struct PP_Size; + +namespace pp { +namespace proxy { + +class HostResource; +class Dispatcher; + +class ResourceCreationProxy : public ::ppapi::FunctionGroupBase, + public ::ppapi::thunk::ResourceCreationAPI, + public ::IPC::Channel::Listener, + public IPC::Message::Sender { + public: + explicit ResourceCreationProxy(Dispatcher* dispatcher); + virtual ~ResourceCreationProxy(); + + virtual ::ppapi::thunk::ResourceCreationAPI* AsResourceCreationAPI() OVERRIDE; + + // ResourceCreationAPI (called in plugin). + virtual PP_Resource CreateAudio(PP_Instance instance, + PP_Resource config_id, + PPB_Audio_Callback audio_callback, + void* user_data) OVERRIDE; + virtual PP_Resource CreateAudioConfig(PP_Instance instance, + PP_AudioSampleRate sample_rate, + uint32_t sample_frame_count) OVERRIDE; + virtual PP_Resource CreateAudioTrusted(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateBroker(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateBuffer(PP_Instance instance, + uint32_t size) OVERRIDE; + virtual PP_Resource CreateContext3D(PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) OVERRIDE; + virtual PP_Resource CreateContext3DRaw(PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) OVERRIDE; + virtual PP_Resource CreateDirectoryReader(PP_Resource directory_ref) OVERRIDE; + virtual PP_Resource CreateFileChooser( + PP_Instance instance, + const PP_FileChooserOptions_Dev* options) OVERRIDE; + virtual PP_Resource CreateFileIO(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateFileRef(PP_Resource file_system, + const char* path) OVERRIDE; + virtual PP_Resource CreateFileSystem(PP_Instance instance, + PP_FileSystemType type) OVERRIDE; + virtual PP_Resource CreateFlashMenu(PP_Instance instance, + const PP_Flash_Menu* menu_data) OVERRIDE; + virtual PP_Resource CreateFlashNetConnector(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateFlashTCPSocket(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateFontObject( + PP_Instance instance, + const PP_FontDescription_Dev* description) OVERRIDE; + virtual PP_Resource CreateGraphics2D(PP_Instance pp_instance, + const PP_Size& size, + PP_Bool is_always_opaque) OVERRIDE; + virtual PP_Resource CreateGraphics3D(PP_Instance instance, + PP_Config3D_Dev config, + PP_Resource share_context, + const int32_t* attrib_list) OVERRIDE; + virtual PP_Resource CreateImageData(PP_Instance instance, + PP_ImageDataFormat format, + const PP_Size& size, + PP_Bool init_to_zero) OVERRIDE; + virtual PP_Resource CreateScrollbar(PP_Instance instance, + PP_Bool vertical) OVERRIDE; + virtual PP_Resource CreateSurface3D(PP_Instance instance, + PP_Config3D_Dev config, + const int32_t* attrib_list) OVERRIDE; + virtual PP_Resource CreateTransport(PP_Instance instance, + const char* name, + const char* proto) OVERRIDE; + virtual PP_Resource CreateURLLoader(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateURLRequestInfo(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateVideoDecoder(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateVideoLayer(PP_Instance instance, + PP_VideoLayerMode_Dev mode) OVERRIDE; + + virtual bool Send(IPC::Message* msg) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + + private: + // IPC message handlers (called in browser). + void OnMsgCreateAudio(PP_Instance instance, + int32_t sample_rate, + uint32_t sample_frame_count, + HostResource* result); + void OnMsgCreateGraphics2D(PP_Instance instance, + const PP_Size& size, + PP_Bool is_always_opaque, + HostResource* result); + void OnMsgCreateImageData(PP_Instance instance, + int32_t format, + const PP_Size& size, + PP_Bool init_to_zero, + HostResource* result, + std::string* image_data_desc, + ImageHandle* result_image_handle); + + Dispatcher* dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ResourceCreationProxy); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_RESOURCE_CREATION_PROXY_H_ diff --git a/ppapi/proxy/run_all_unittests.cc b/ppapi/proxy/run_all_unittests.cc new file mode 100644 index 0000000..7fd6ef2 --- /dev/null +++ b/ppapi/proxy/run_all_unittests.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/test_suite.h" + +int main(int argc, char** argv) { + return base::TestSuite(argc, argv).Run(); +} diff --git a/ppapi/proxy/serialized_flash_menu.cc b/ppapi/proxy/serialized_flash_menu.cc new file mode 100644 index 0000000..c7ef5ab --- /dev/null +++ b/ppapi/proxy/serialized_flash_menu.cc @@ -0,0 +1,172 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/serialized_flash_menu.h" + +#include "ipc/ipc_message.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/proxy/ppapi_param_traits.h" + +namespace pp { +namespace proxy { + +namespace { +// Maximum depth of submenus allowed (e.g., 1 indicates that submenus are +// allowed, but not sub-submenus). +const int kMaxMenuDepth = 2; + +bool CheckMenu(int depth, const PP_Flash_Menu* menu); +void FreeMenu(const PP_Flash_Menu* menu); +void WriteMenu(IPC::Message* m, const PP_Flash_Menu* menu); +PP_Flash_Menu* ReadMenu(int depth, const IPC::Message* m, void** iter); + +bool CheckMenuItem(int depth, const PP_Flash_MenuItem* item) { + if (item->type == PP_FLASH_MENUITEM_TYPE_SUBMENU) + return CheckMenu(depth, item->submenu); + return true; +} + +bool CheckMenu(int depth, const PP_Flash_Menu* menu) { + if (depth > kMaxMenuDepth || !menu) + return false; + ++depth; + + if (menu->count && !menu->items) + return false; + + for (uint32_t i = 0; i < menu->count; ++i) { + if (!CheckMenuItem(depth, menu->items + i)) + return false; + } + return true; +} + +void WriteMenuItem(IPC::Message* m, const PP_Flash_MenuItem* menu_item) { + PP_Flash_MenuItem_Type type = menu_item->type; + m->WriteUInt32(type); + m->WriteString(menu_item->name ? menu_item->name : ""); + m->WriteInt(menu_item->id); + IPC::ParamTraits<PP_Bool>::Write(m, menu_item->enabled); + IPC::ParamTraits<PP_Bool>::Write(m, menu_item->checked); + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) + WriteMenu(m, menu_item->submenu); +} + +void WriteMenu(IPC::Message* m, const PP_Flash_Menu* menu) { + m->WriteUInt32(menu->count); + for (uint32_t i = 0; i < menu->count; ++i) + WriteMenuItem(m, menu->items + i); +} + +void FreeMenuItem(const PP_Flash_MenuItem* menu_item) { + if (menu_item->name) + delete [] menu_item->name; + if (menu_item->submenu) + FreeMenu(menu_item->submenu); +} + +void FreeMenu(const PP_Flash_Menu* menu) { + if (menu->items) { + for (uint32_t i = 0; i < menu->count; ++i) + FreeMenuItem(menu->items + i); + delete [] menu->items; + } + delete menu; +} + +bool ReadMenuItem(int depth, + const IPC::Message* m, + void** iter, + PP_Flash_MenuItem* menu_item) { + uint32_t type; + if (!m->ReadUInt32(iter, &type)) + return false; + if (type > PP_FLASH_MENUITEM_TYPE_SUBMENU) + return false; + menu_item->type = static_cast<PP_Flash_MenuItem_Type>(type); + std::string name; + if (!m->ReadString(iter, &name)) + return false; + menu_item->name = new char[name.size() + 1]; + std::copy(name.begin(), name.end(), menu_item->name); + menu_item->name[name.size()] = 0; + if (!m->ReadInt(iter, &menu_item->id)) + return false; + if (!IPC::ParamTraits<PP_Bool>::Read(m, iter, &menu_item->enabled)) + return false; + if (!IPC::ParamTraits<PP_Bool>::Read(m, iter, &menu_item->checked)) + return false; + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { + menu_item->submenu = ReadMenu(depth, m, iter); + if (!menu_item->submenu) + return false; + } + return true; +} + +PP_Flash_Menu* ReadMenu(int depth, const IPC::Message* m, void** iter) { + if (depth > kMaxMenuDepth) + return NULL; + ++depth; + + PP_Flash_Menu* menu = new PP_Flash_Menu; + menu->items = NULL; + + if (!m->ReadUInt32(iter, &menu->count)) { + FreeMenu(menu); + return NULL; + } + + if (menu->count == 0) + return menu; + + menu->items = new PP_Flash_MenuItem[menu->count]; + memset(menu->items, 0, sizeof(PP_Flash_MenuItem) * menu->count); + for (uint32_t i = 0; i < menu->count; ++i) { + if (!ReadMenuItem(depth, m, iter, menu->items + i)) { + FreeMenu(menu); + return NULL; + } + } + return menu; +} + +} // anonymous namespace + +SerializedFlashMenu::SerializedFlashMenu() + : pp_menu_(NULL), + own_menu_(false) { +} + +SerializedFlashMenu::~SerializedFlashMenu() { + if (own_menu_) + FreeMenu(pp_menu_); +} + +bool SerializedFlashMenu::SetPPMenu(const PP_Flash_Menu* menu) { + DCHECK(!pp_menu_); + if (!CheckMenu(0, menu)) + return false; + pp_menu_ = menu; + own_menu_ = false; + return true; +} + + +void SerializedFlashMenu::WriteToMessage(IPC::Message* m) const { + WriteMenu(m, pp_menu_); +} + +bool SerializedFlashMenu::ReadFromMessage(const IPC::Message* m, void** iter) { + DCHECK(!pp_menu_); + pp_menu_ = ReadMenu(0, m, iter); + if (!pp_menu_) + return false; + + own_menu_ = true; + return true; +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/serialized_flash_menu.h b/ppapi/proxy/serialized_flash_menu.h new file mode 100644 index 0000000..84b7bb9 --- /dev/null +++ b/ppapi/proxy/serialized_flash_menu.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_SERIALIZED_FLASH_MENU_H_ +#define PPAPI_PROXY_SERIALIZED_FLASH_MENU_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +struct PP_Flash_Menu; + +namespace IPC { +class Message; +} + +namespace pp { +namespace proxy { + +class SerializedFlashMenu { + public: + SerializedFlashMenu(); + ~SerializedFlashMenu(); + + bool SetPPMenu(const PP_Flash_Menu* menu); + + const PP_Flash_Menu* pp_menu() const { return pp_menu_; } + + void WriteToMessage(IPC::Message* m) const; + bool ReadFromMessage(const IPC::Message* m, void** iter); + + private: + const PP_Flash_Menu* pp_menu_; + bool own_menu_; + DISALLOW_COPY_AND_ASSIGN(SerializedFlashMenu); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_SERIALIZED_FLASH_MENU_H_ diff --git a/ppapi/proxy/serialized_structs.cc b/ppapi/proxy/serialized_structs.cc new file mode 100644 index 0000000..71c7376 --- /dev/null +++ b/ppapi/proxy/serialized_structs.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/serialized_structs.h" + +#include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/pp_file_info.h" +#include "ppapi/c/pp_rect.h" + +namespace pp { +namespace proxy { + +SerializedFontDescription::SerializedFontDescription() + : face(), + family(0), + size(0), + weight(0), + italic(PP_FALSE), + small_caps(PP_FALSE), + letter_spacing(0), + word_spacing(0) { +} + +SerializedFontDescription::~SerializedFontDescription() {} + +void SerializedFontDescription::SetFromPPFontDescription( + Dispatcher* dispatcher, + const PP_FontDescription_Dev& desc, + bool source_owns_ref) { + if (source_owns_ref) + face = SerializedVarSendInput(dispatcher, desc.face); + else + SerializedVarReturnValue(&face).Return(dispatcher, desc.face); + + family = desc.family; + size = desc.size; + weight = desc.weight; + italic = desc.italic; + small_caps = desc.small_caps; + letter_spacing = desc.letter_spacing; + word_spacing = desc.word_spacing; +} + +void SerializedFontDescription::SetToPPFontDescription( + Dispatcher* dispatcher, + PP_FontDescription_Dev* desc, + bool dest_owns_ref) const { + if (dest_owns_ref) { + ReceiveSerializedVarReturnValue face_return_value; + *static_cast<SerializedVar*>(&face_return_value) = face; + desc->face = face_return_value.Return(dispatcher); + } else { + desc->face = SerializedVarReceiveInput(face).Get(dispatcher); + } + + desc->family = static_cast<PP_FontFamily_Dev>(family); + desc->size = size; + desc->weight = static_cast<PP_FontWeight_Dev>(weight); + desc->italic = italic; + desc->small_caps = small_caps; + desc->letter_spacing = letter_spacing; + desc->word_spacing = word_spacing; +} + +PPBFileRef_CreateInfo::PPBFileRef_CreateInfo() + : file_system_type(PP_FILESYSTEMTYPE_EXTERNAL) { +} + +PPBFlash_DrawGlyphs_Params::PPBFlash_DrawGlyphs_Params() + : instance(0), + font_desc(), + color(0) { + clip.point.x = 0; + clip.point.y = 0; + clip.size.height = 0; + clip.size.width = 0; + position.x = 0; + position.y = 0; +} + +PPBFlash_DrawGlyphs_Params::~PPBFlash_DrawGlyphs_Params() {} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/serialized_structs.h b/ppapi/proxy/serialized_structs.h new file mode 100644 index 0000000..516d53d --- /dev/null +++ b/ppapi/proxy/serialized_structs.h @@ -0,0 +1,128 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_SERIALIZED_STRUCTS_H_ +#define PPAPI_PROXY_SERIALIZED_STRUCTS_H_ + +#include <string> +#include <vector> + +#include "base/shared_memory.h" +#include "build/build_config.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_rect.h" +#include "ppapi/proxy/host_resource.h" +#include "ppapi/proxy/serialized_var.h" + +struct PP_FontDescription_Dev; + +namespace pp { +namespace proxy { + +class Dispatcher; + +// PP_FontDescript_Dev has to be redefined with a SerializedVar in place of +// the PP_Var used for the face name. +struct SerializedFontDescription { + SerializedFontDescription(); + ~SerializedFontDescription(); + + // Converts a PP_FontDescription_Dev to a SerializedFontDescription. + // + // If source_owns_ref is true, the reference owned by the + // PP_FontDescription_Dev will be unchanged and the caller is responsible for + // freeing it. When false, the SerializedFontDescription will take ownership + // of the ref. This is the difference between serializing as an input value + // (owns_ref = true) and an output value (owns_ref = true). + void SetFromPPFontDescription(Dispatcher* dispatcher, + const PP_FontDescription_Dev& desc, + bool source_owns_ref); + + // Converts to a PP_FontDescription_Dev. The face name will have one ref + // assigned to it on behalf of the caller. + // + // If dest_owns_ref is set, the resulting PP_FontDescription_Dev will keep a + // reference to any strings we made on its behalf even when the + // SerializedFontDescription goes away. When false, ownership of the ref will + // stay with the SerializedFontDescription and the PP_FontDescription_Dev + // will just refer to that one. This is the difference between deserializing + // as an input value (owns_ref = false) and an output value (owns_ref = true). + void SetToPPFontDescription(Dispatcher* dispatcher, + PP_FontDescription_Dev* desc, + bool dest_owns_ref) const; + + pp::proxy::SerializedVar face; + int32_t family; + uint32_t size; + int32_t weight; + PP_Bool italic; + PP_Bool small_caps; + int32_t letter_spacing; + int32_t word_spacing; +}; + +struct SerializedDirEntry { + std::string name; + bool is_dir; +}; + +// FileRefs are created in a number of places and they include a number of +// return values. This struct encapsulates everything in one place. +struct PPBFileRef_CreateInfo { + PPBFileRef_CreateInfo(); // Initializes to 0. + + HostResource resource; + int file_system_type; // One of PP_FileSystemType values. + SerializedVar path; + SerializedVar name; +}; + +struct PPBFlash_DrawGlyphs_Params { + PPBFlash_DrawGlyphs_Params(); + ~PPBFlash_DrawGlyphs_Params(); + + PP_Instance instance; + HostResource image_data; + SerializedFontDescription font_desc; + uint32_t color; + PP_Point position; + PP_Rect clip; + float transformation[3][3]; + std::vector<uint16_t> glyph_indices; + std::vector<PP_Point> glyph_advances; +}; + +struct PPBAudio_NotifyAudioStreamCreated_Params { + pp::proxy::HostResource audio_id; + int32_t result_code; // Will be != PP_OK on failure + IPC::PlatformFileForTransit socket_handle; + base::SharedMemoryHandle handle; + int32_t length; +}; + +struct PPBURLLoader_UpdateProgress_Params { + PP_Instance instance; + pp::proxy::HostResource resource; + int64_t bytes_sent; + int64_t total_bytes_to_be_sent; + int64_t bytes_received; + int64_t total_bytes_to_be_received; +}; + +#if defined(OS_WIN) +typedef HANDLE ImageHandle; +#elif defined(OS_MACOSX) +typedef base::SharedMemoryHandle ImageHandle; +#else +// On X Windows this is a SysV shared memory key. +typedef int ImageHandle; +#endif + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_SERIALIZED_STRUCTS_H_ diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc new file mode 100644 index 0000000..786cc9e --- /dev/null +++ b/ppapi/proxy/serialized_var.cc @@ -0,0 +1,536 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/serialized_var.h" + +#include "base/logging.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/interface_proxy.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), + dispatcher_for_end_send_pass_ref_(NULL) { +#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), + dispatcher_for_end_send_pass_ref_(NULL) { +#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), + dispatcher_for_end_send_pass_ref_(NULL) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::~Inner() { + switch (cleanup_mode_) { + case END_SEND_PASS_REF: + DCHECK(dispatcher_for_end_send_pass_ref_); + serialization_rules_->EndSendPassRef(var_, + dispatcher_for_end_send_pass_ref_); + 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(PP_ToBool(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; + case PP_VARTYPE_ARRAY: + case PP_VARTYPE_DICTIONARY: + // TODO(brettw) when these are supported, implement this. + NOTIMPLEMENTED(); + 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: { + bool bool_value; + success = m->ReadBool(iter, &bool_value); + var_.value.as_bool = PP_FromBool(bool_value); + 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; + case PP_VARTYPE_ARRAY: + case PP_VARTYPE_DICTIONARY: + // TODO(brettw) when these types are supported, implement this. + NOTIMPLEMENTED(); + 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; +} + +void SerializedVar::Inner::SetCleanupModeToEndSendPassRef( + Dispatcher* dispatcher) { + DCHECK(dispatcher); + DCHECK(!dispatcher_for_end_send_pass_ref_); + dispatcher_for_end_send_pass_ref_ = dispatcher; + cleanup_mode_ = END_SEND_PASS_REF; +} + +void SerializedVar::Inner::SetCleanupModeToEndReceiveCallerOwned() { + cleanup_mode_ = END_RECEIVE_CALLER_OWNED; +} + +// 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()) { + inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned( + var, inner_->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++) { + SerializedVar& cur = (*output)[i]; + cur = SerializedVar(dispatcher->serialization_rules()); + cur.inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned( + input[i], cur.inner_->GetStringPtr())); + } +} + +// ReceiveSerializedVarReturnValue --------------------------------------------- + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { +} + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue( + const SerializedVar& serialized) + : SerializedVar(serialized) { +} + +PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { + inner_->set_serialization_rules(dispatcher->serialization_rules()); + inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( + inner_->GetIncompleteVar(), inner_->GetString(), dispatcher)); + return inner_->GetVar(); +} + +// ReceiveSerializedException -------------------------------------------------- + +ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, + PP_Var* exception) + : SerializedVar(dispatcher->serialization_rules()), + dispatcher_(dispatcher), + exception_(exception) { +} + +ReceiveSerializedException::~ReceiveSerializedException() { + if (exception_) { + // When an output exception is specified, it will take ownership of the + // reference. + inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( + inner_->GetIncompleteVar(), inner_->GetString(), dispatcher_)); + *exception_ = inner_->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 (inner_->GetVar().type == PP_VARTYPE_OBJECT) + inner_->serialization_rules()->ReleaseObjectRef(inner_->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_.inner_->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_.inner_->SetCleanupModeToEndReceiveCallerOwned(); + + serialized_.inner_->SetVar( + serialized_.inner_->serialization_rules()->BeginReceiveCallerOwned( + serialized_.inner_->GetIncompleteVar(), + serialized_.inner_->GetStringPtr(), + dispatcher)); + return serialized_.inner_->GetVar(); +} + +// SerializedVarVectorReceiveInput --------------------------------------------- + +SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( + const std::vector<SerializedVar>& serialized) + : serialized_(serialized) { +} + +SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { + for (size_t i = 0; i < deserialized_.size(); i++) { + serialized_[i].inner_->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].inner_->set_serialization_rules( + dispatcher->serialization_rules()); + + serialized_[i].inner_->SetVar( + serialized_[i].inner_->serialization_rules()->BeginReceiveCallerOwned( + serialized_[i].inner_->GetIncompleteVar(), + serialized_[i].inner_->GetStringPtr(), + dispatcher)); + deserialized_[i] = serialized_[i].inner_->GetVar(); + } + + *array_size = static_cast<uint32_t>(serialized_.size()); + return deserialized_.empty() ? NULL : &deserialized_[0]; +} + +// SerializedVarReturnValue ---------------------------------------------------- + +SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) + : serialized_(serialized) { +} + +void SerializedVarReturnValue::Return(Dispatcher* dispatcher, + const PP_Var& var) { + serialized_->inner_->set_serialization_rules( + dispatcher->serialization_rules()); + + // Var must clean up after our BeginSendPassRef call. + serialized_->inner_->SetCleanupModeToEndSendPassRef(dispatcher); + + serialized_->inner_->SetVar( + dispatcher->serialization_rules()->BeginSendPassRef( + var, + serialized_->inner_->GetStringPtr())); +} + +// static +SerializedVar SerializedVarReturnValue::Convert(Dispatcher* dispatcher, + const PP_Var& var) { + // Mimic what happens in the normal case. + SerializedVar result; + SerializedVarReturnValue retvalue(&result); + retvalue.Return(dispatcher, var); + return result; +} + +// SerializedVarOutParam ------------------------------------------------------- + +SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) + : serialized_(serialized), + writable_var_(PP_MakeUndefined()), + dispatcher_(NULL) { +} + +SerializedVarOutParam::~SerializedVarOutParam() { + if (serialized_->inner_->serialization_rules()) { + // When unset, OutParam wasn't called. We'll just leave the var untouched + // in that case. + serialized_->inner_->SetVar( + serialized_->inner_->serialization_rules()->BeginSendPassRef( + writable_var_, serialized_->inner_->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_->inner_->SetCleanupModeToEndSendPassRef(dispatcher_); + } +} + +PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { + dispatcher_ = dispatcher; + serialized_->inner_->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_; +} + +SerializedVarTestConstructor::SerializedVarTestConstructor( + const PP_Var& pod_var) { + DCHECK(pod_var.type != PP_VARTYPE_STRING); + inner_->SetVar(pod_var); +} + +SerializedVarTestConstructor::SerializedVarTestConstructor( + const std::string& str) { + PP_Var string_var = {}; + string_var.type = PP_VARTYPE_STRING; + string_var.value.as_id = 0; + inner_->SetVar(string_var); + *inner_->GetStringPtr() = str; +} + +SerializedVarTestReader::SerializedVarTestReader(const SerializedVar& var) + : SerializedVar(var) { +} + +} // namespace proxy +} // namespace pp + diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h new file mode 100644 index 0000000..3f74a28 --- /dev/null +++ b/ppapi/proxy/serialized_var.h @@ -0,0 +1,455 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_PROXY_SERIALIZED_VAR_H_ +#define PPAPI_PROXY_SERIALIZED_VAR_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "ppapi/c/pp_var.h" + +namespace IPC { +class Message; +} + +namespace pp { +namespace proxy { + +class Dispatcher; +class VarSerializationRules; + +// This class encapsulates a var so that we can serialize and deserialize it +// The problem is that for strings, serialization and deserialization requires +// knowledge from outside about how to get at or create a string. So this +// object groups the var with a dispatcher so that string values can be set or +// gotten. +// +// Declare IPC messages as using this type, but don't use it directly (it has +// no useful public methods). Instead, instantiate one of the helper classes +// below which are conveniently named for each use case to prevent screwups. +// +// Design background +// ----------------- +// This is sadly super complicated. The IPC system needs a consistent type to +// use for sending and receiving vars (this is a SerializedVar). But there are +// different combinations of reference counting for sending and receiving +// objects and for dealing with strings +// +// This makes SerializedVar complicated and easy to mess up. To make it +// reasonable to use all functions are protected and there are a use-specific +// classes that encapsulate exactly one type of use in a way that typically +// won't compile if you do the wrong thing. +// +// The IPC system is designed to pass things around and will make copies in +// some cases, so our system must be designed so that this stuff will work. +// This is challenging when the SerializedVar must to some cleanup after the +// message is sent. To work around this, we create an inner class using a +// linked_ptr so all copies of a SerializedVar can share and we can guarantee +// that the actual data will get cleaned up on shutdown. +// +// Constness +// --------- +// SerializedVar basically doesn't support const. Everything is mutable and +// most functions are declared const. This unfortunateness is because of the +// way the IPC system works. When deserializing, it will have a const +// SerializedVar in a Tuple and this will be given to the function. We kind of +// want to modify that to convert strings and do refcounting. +// +// The helper classes used for accessing the SerializedVar have more reasonable +// behavior and will enforce that you don't do stupid things. +class SerializedVar { + public: + SerializedVar(); + ~SerializedVar(); + + // Backend implementation for IPC::ParamTraits<SerializedVar>. + void WriteToMessage(IPC::Message* m) const { + inner_->WriteToMessage(m); + } + bool ReadFromMessage(const IPC::Message* m, void** iter) { + return inner_->ReadFromMessage(m, iter); + } + + protected: + friend class SerializedVarReceiveInput; + friend class SerializedVarReturnValue; + friend class SerializedVarOutParam; + friend class SerializedVarSendInput; + friend class SerializedVarTestConstructor; + friend class SerializedVarVectorReceiveInput; + + class Inner : public base::RefCounted<Inner> { + public: + Inner(); + Inner(VarSerializationRules* serialization_rules); + Inner(VarSerializationRules* serialization_rules, const PP_Var& var); + ~Inner(); + + VarSerializationRules* serialization_rules() { + return serialization_rules_; + } + void set_serialization_rules(VarSerializationRules* serialization_rules) { + serialization_rules_ = serialization_rules; + } + + // See outer class's declarations above. + PP_Var GetVar() const; + PP_Var GetIncompleteVar() const; + void SetVar(PP_Var var); + const std::string& GetString() const; + std::string* GetStringPtr(); + + void WriteToMessage(IPC::Message* m) const; + bool ReadFromMessage(const IPC::Message* m, void** iter); + + // Sets the cleanup mode. See the CleanupMode enum below. These functions + // are not just a simple setter in order to require that the appropriate + // data is set along with the corresponding mode. + void SetCleanupModeToEndSendPassRef(Dispatcher* dispatcher); + void SetCleanupModeToEndReceiveCallerOwned(); + + private: + enum CleanupMode { + // The serialized var won't do anything special in the destructor + // (default). + CLEANUP_NONE, + + // The serialized var will call EndSendPassRef in the destructor. + END_SEND_PASS_REF, + + // The serialized var will call EndReceiveCallerOwned in the destructor. + END_RECEIVE_CALLER_OWNED + }; + + // Rules for serializing and deserializing vars for this process type. + // This may be NULL, but must be set before trying to serialize to IPC when + // sending, or before converting back to a PP_Var when receiving. + VarSerializationRules* serialization_rules_; + + // If this is set to VARTYPE_STRING and the 'value.id' is 0, then the + // string_value_ contains the string. This means that the caller hasn't + // called Deserialize with a valid Dispatcher yet, which is how we can + // convert the serialized string value to a PP_Var string ID. + // + // This var may not be complete until the serialization rules are set when + // reading from IPC since we'll need that to convert the string_value to + // a string ID. Before this, the as_id will be 0 for VARTYPE_STRING. + PP_Var var_; + + // Holds the literal string value to/from IPC. This will be valid of the + // var_ is VARTYPE_STRING. + std::string string_value_; + + CleanupMode cleanup_mode_; + + // The dispatcher saved for the call to EndSendPassRef for the cleanup. + // This is only valid when cleanup_mode == END_SEND_PASS_REF. + Dispatcher* dispatcher_for_end_send_pass_ref_; + +#ifndef NDEBUG + // When being sent or received over IPC, we should only be serialized or + // deserialized once. These flags help us assert this is true. + mutable bool has_been_serialized_; + mutable bool has_been_deserialized_; +#endif + + DISALLOW_COPY_AND_ASSIGN(Inner); + }; + + SerializedVar(VarSerializationRules* serialization_rules); + SerializedVar(VarSerializationRules* serialization, const PP_Var& var); + + mutable scoped_refptr<Inner> inner_; +}; + +// Helpers for message sending side -------------------------------------------- + +// For sending a value to the remote side. +// +// Example for API: +// void MyFunction(PP_Var) +// IPC message: +// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); +// Sender would be: +// void MyFunctionProxy(PP_Var param) { +// Send(new MyFunctionMsg(SerializedVarSendInput(param)); +// } +class SerializedVarSendInput : public SerializedVar { + public: + SerializedVarSendInput(Dispatcher* dispatcher, const PP_Var& var); + + // Helper function for serializing a vector of input vars for serialization. + static void ConvertVector(Dispatcher* dispatcher, + const PP_Var* input, + size_t input_count, + std::vector<SerializedVar>* output); + + private: + // Disallow the empty constructor, but keep the default copy constructor + // which is required to send the object to the IPC system. + SerializedVarSendInput(); +}; + +// For the calling side of a function returning a var. The sending side uses +// SerializedVarReturnValue. +// +// Example for API: +// PP_Var MyFunction() +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// PP_Var MyFunctionProxy() { +// ReceiveSerializedVarReturnValue result; +// Send(new MyFunctionMsg(&result)); +// return result.Return(dispatcher()); +// } +class ReceiveSerializedVarReturnValue : public SerializedVar { + public: + // Note that we can't set the dispatcher in the constructor because the + // data will be overridden when the return value is set. This constructor is + // normally used in the pattern above (operator= will be implicitly invoked + // when the sync message writes the output values). + ReceiveSerializedVarReturnValue(); + + // This constructor can be used when deserializing manually. This is useful + // when you're getting strings "returned" via a struct and need to manually + // get the PP_Vars out. In this case just do: + // ReceiveSerializedVarReturnValue(serialized).Return(dispatcher); + explicit ReceiveSerializedVarReturnValue(const SerializedVar& serialized); + + PP_Var Return(Dispatcher* dispatcher); + + private: + DISALLOW_COPY_AND_ASSIGN(ReceiveSerializedVarReturnValue); +}; + +// Example for API: +// "void MyFunction(PP_Var* exception);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(PP_Var* exception) { +// ReceiveSerializedException se(dispatcher(), exception) +// Send(new PpapiHostMsg_Foo(&se)); +// } +class ReceiveSerializedException : public SerializedVar { + public: + ReceiveSerializedException(Dispatcher* dispatcher, PP_Var* exception); + ~ReceiveSerializedException(); + + // Returns true if the exception passed in the constructor is set. Check + // this before actually issuing the IPC. + bool IsThrown() const; + + private: + Dispatcher* dispatcher_; + + // The input/output exception we're wrapping. May be NULL. + PP_Var* exception_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedException); +}; + +// Helper class for when we're returning a vector of Vars. When it goes out +// of scope it will automatically convert the vector filled by the IPC layer +// into the array specified by the constructor params. +// +// Example for API: +// "void MyFunction(uint32_t* count, PP_Var** vars);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, std::vector<SerializedVar>); +// Proxy function: +// void MyFunction(uint32_t* count, PP_Var** vars) { +// ReceiveSerializedVarVectorOutParam vect(dispatcher, count, vars); +// Send(new MyMsg(vect.OutParam())); +// } +class ReceiveSerializedVarVectorOutParam { + public: + ReceiveSerializedVarVectorOutParam(Dispatcher* dispatcher, + uint32_t* output_count, + PP_Var** output); + ~ReceiveSerializedVarVectorOutParam(); + + std::vector<SerializedVar>* OutParam(); + + private: + Dispatcher* dispatcher_; + uint32_t* output_count_; + PP_Var** output_; + + std::vector<SerializedVar> vector_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedVarVectorOutParam); +}; + +// Helpers for message receiving side ------------------------------------------ + +// For receiving a value from the remote side. +// +// Example for API: +// void MyFunction(PP_Var) +// IPC message: +// IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarReceiveInput param) { +// MyFunction(param.Get()); +// } +class SerializedVarReceiveInput { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarReceiveInput(const SerializedVar& serialized); + ~SerializedVarReceiveInput(); + + PP_Var Get(Dispatcher* dispatcher); + + private: + const SerializedVar& serialized_; + + // Since the SerializedVar is const, we can't set its dispatcher (which is + // OK since we don't need to). But since we need it for our own uses, we + // track it here. Will be NULL before Get() is called. + Dispatcher* dispatcher_; + PP_Var var_; +}; + +// For receiving an input vector of vars from the remote side. +// +// Example: +// OnMsgMyFunction(SerializedVarVectorReceiveInput vector) { +// uint32_t size; +// PP_Var* array = vector.Get(dispatcher, &size); +// MyFunction(size, array); +// } +class SerializedVarVectorReceiveInput { + public: + SerializedVarVectorReceiveInput(const std::vector<SerializedVar>& serialized); + ~SerializedVarVectorReceiveInput(); + + // Only call Get() once. It will return a pointer to the converted array and + // place the array size in the out param. Will return NULL when the array is + // empty. + PP_Var* Get(Dispatcher* dispatcher, uint32_t* array_size); + + private: + const std::vector<SerializedVar>& serialized_; + + // Filled by Get(). + std::vector<PP_Var> deserialized_; +}; + +// For the receiving side of a function returning a var. The calling side uses +// ReceiveSerializedVarReturnValue. +// +// Example for API: +// PP_Var MyFunction() +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarReturnValue result) { +// result.Return(dispatcher(), MyFunction()); +// } +class SerializedVarReturnValue { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar*. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarReturnValue(SerializedVar* serialized); + + void Return(Dispatcher* dispatcher, const PP_Var& var); + + // Helper function for code that doesn't use the pattern above, but gets + // a return value from the remote side via a struct. You can pass in the + // SerializedVar and a PP_Var will be created with return value semantics. + static SerializedVar Convert(Dispatcher* dispatcher, const PP_Var& var); + + private: + SerializedVar* serialized_; +}; + +// For writing an out param to the remote side. +// +// Example for API: +// "void MyFunction(PP_Var* out);" +// IPC message: +// IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); +// Message handler would be: +// void OnMsgMyFunction(SerializedVarOutParam out_param) { +// MyFunction(out_param.OutParam(dispatcher())); +// } +class SerializedVarOutParam { + public: + // We rely on the implicit constructor here since the IPC layer will call + // us with a SerializedVar*. Pass this object by value, the copy constructor + // will pass along the pointer (as cheap as passing a pointer arg). + SerializedVarOutParam(SerializedVar* serialized); + ~SerializedVarOutParam(); + + // Call this function only once. The caller should write its result to the + // returned var pointer before this class goes out of scope. The var's + // initial value will be VARTYPE_UNDEFINED. + PP_Var* OutParam(Dispatcher* dispatcher); + + private: + SerializedVar* serialized_; + + // This is the value actually written by the code and returned by OutParam. + // We'll write this into serialized_ in our destructor. + PP_Var writable_var_; + + Dispatcher* dispatcher_; +}; + +// For returning an array of PP_Vars to the other side and transferring +// ownership. +// +class SerializedVarVectorOutParam { + public: + SerializedVarVectorOutParam(std::vector<SerializedVar>* serialized); + ~SerializedVarVectorOutParam(); + + uint32_t* CountOutParam() { return &count_; } + PP_Var** ArrayOutParam(Dispatcher* dispatcher); + + private: + Dispatcher* dispatcher_; + std::vector<SerializedVar>* serialized_; + + uint32_t count_; + PP_Var* array_; +}; + +// For tests that just want to construct a SerializedVar for giving it to one +// of the other classes. +class SerializedVarTestConstructor : public SerializedVar { + public: + // For POD-types and objects. + explicit SerializedVarTestConstructor(const PP_Var& pod_var); + + // For strings. + explicit SerializedVarTestConstructor(const std::string& str); +}; + +// For tests that want to read what's in a SerializedVar. +class SerializedVarTestReader : public SerializedVar { + public: + explicit SerializedVarTestReader(const SerializedVar& var); + + // The "incomplete" var is the one sent over the wire. Strings and object + // IDs have not yet been converted, so this is the thing that tests will + // actually want to check. + PP_Var GetIncompleteVar() const { return inner_->GetIncompleteVar(); } + + const std::string& GetString() const { return inner_->GetString(); } +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_SERIALIZED_VAR_H_ + diff --git a/ppapi/proxy/serialized_var_unittest.cc b/ppapi/proxy/serialized_var_unittest.cc new file mode 100644 index 0000000..3cc4e61 --- /dev/null +++ b/ppapi/proxy/serialized_var_unittest.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/proxy/ppapi_proxy_test.h" + +#include "ppapi/proxy/serialized_var.h" + +namespace pp { +namespace proxy { + +namespace { + +PP_Var MakeStringVar(int64_t string_id) { + PP_Var ret; + ret.type = PP_VARTYPE_STRING; + ret.value.as_id = string_id; + return ret; +} + +PP_Var MakeObjectVar(int64_t object_id) { + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = object_id; + return ret; +} + +class SerializedVarTest : public PluginProxyTest { + public: + SerializedVarTest() {} +}; + +} // namespace + +// Tests output arguments. +TEST_F(SerializedVarTest, PluginSerializedVarOutParam) { + PP_Var host_object = MakeObjectVar(0x31337); + + // Start tracking this object in the plugin. + PP_Var plugin_object = var_tracker().ReceiveObjectPassRef( + host_object, plugin_dispatcher()); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + + { + SerializedVar sv; + { + // The "OutParam" does its work in its destructor, it will write the + // information to the SerializedVar we passed in the constructor. + SerializedVarOutParam out_param(&sv); + *out_param.OutParam(plugin_dispatcher()) = plugin_object; + } + + // The object should have transformed the plugin object back to the host + // object ID. Nothing in the var tracker should have changed yet, and no + // messages should have been sent. + SerializedVarTestReader reader(sv); + EXPECT_EQ(host_object.value.as_id, reader.GetIncompleteVar().value.as_id); + EXPECT_EQ(1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(0u, sink().message_count()); + } + + // The out param should have done an "end send pass ref" on the plugin + // var serialization rules, which should have in turn released the reference + // in the var tracker. Since we only had one reference, this should have sent + // a release to the browser. + EXPECT_EQ(-1, var_tracker().GetRefCountForObject(plugin_object)); + EXPECT_EQ(1u, sink().message_count()); + + // We don't bother validating that message since it's nontrivial and the + // PluginVarTracker test has cases that cover that this message is correct. +} + +} // namespace proxy +} // namespace pp diff --git a/ppapi/proxy/var_serialization_rules.h b/ppapi/proxy/var_serialization_rules.h new file mode 100644 index 0000000..38698ae --- /dev/null +++ b/ppapi/proxy/var_serialization_rules.h @@ -0,0 +1,93 @@ +// 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_VAR_SERIALIZATION_RULES_H_ +#define PPAPI_PROXY_VAR_SERIALIZATION_RULES_H_ + +#include "ppapi/c/pp_var.h" + +#include <string> + +namespace pp { +namespace proxy { + +class Dispatcher; + +// Encapsulates the rules for serializing and deserializing vars to and from +// the local process. The renderer and the plugin process each have separate +// bookkeeping rules. +class VarSerializationRules { + public: + virtual ~VarSerializationRules() {} + + // Caller-owned calls -------------------------------------------------------- + // + // A caller-owned call is when doing a function call with a "normal" input + // argument. The caller has a reference to the var, and the caller is + // responsible for freeing that reference. + + // Prepares the given var for sending to the callee. If the var is a string, + // the value of that string will be placed in *str_val. If the var is not + // a string, str_val will be untouched and may be NULL. The return value will + // be the var valid for the host process. + virtual PP_Var SendCallerOwned(const PP_Var& var, std::string* str_val) = 0; + + // When receiving a caller-owned variable, normally we don't have to do + // anything. However, in the case of strings, we need to deserialize the + // string from IPC, create a new PP_Var string in the local process, call the + // function, and then destroy the temporary string. These two functions + // handle that process + // + // BeginReceiveCallerOwned takes a var from IPC and an optional pointer to + // the deserialized string (which will be used only when var is a + // VARTYPE_STRING and may be NULL otherwise) and returns a new var + // representing the input in the local process. + // + // EndReceiveCallerOwned destroys the string created by Begin* and does + // nothing otherwise. It should be called with the result of Begin*. + virtual PP_Var BeginReceiveCallerOwned(const PP_Var& var, + const std::string* str_val, + Dispatcher* dispatcher) = 0; + virtual void EndReceiveCallerOwned(const PP_Var& var) = 0; + + // Passinag refs ------------------------------------------------------------- + // + // A pass-ref transfer is when ownership of a reference is passed from + // onen side to the other. Normally, this happens via return values and + // output arguments, as for exceptions. The code generating the value + // (the function returning it in the case of a return value) will AddRef + // the var on behalf of the consumer of the value. Responsibility for + // Release is on the consumer (the caller of the function in the case of a + // return value). + + // Creates a var in the context of the local process from the given + // deserialized var and deserialized string (which will be used only when var + // is a VARTYPE_STRING and may be NULL otherwise). The input var/string + // should be the result of calling SendPassRef in the remote process. The + // return value is the var valid in the plugin process. + virtual PP_Var ReceivePassRef(const PP_Var& var, + const std::string& str_val, + Dispatcher* dispatcher) = 0; + + // Prepares a var to be sent to the remote side. One local reference will + // be passed to the remote side. Call Begin* before doing the send and End* + // after doing the send. See SendCallerOwned for a description of the string. + // + // The return value from BeginSendPassRef will be the var valid for the host + // process. This same value must be passed to EndSendPassRef. + virtual PP_Var BeginSendPassRef(const PP_Var& var, std::string* str_val) = 0; + virtual void EndSendPassRef(const PP_Var& var, Dispatcher* dispatcher) = 0; + + // --------------------------------------------------------------------------- + + virtual void ReleaseObjectRef(const PP_Var& var) = 0; + + protected: + VarSerializationRules() {} +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_VAR_SERIALIZATION_RULES_H_ |