diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 23:59:39 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-17 23:59:39 +0000 |
commit | 4deeb43f8b7c1b21d3545228db86de2c73c9fd43 (patch) | |
tree | 9b44b6a5908d3948eb74d41f1dc69433c5a963d7 /ppapi/proxy | |
parent | c2a6aa323905a384677df735ccaa68ac700b1587 (diff) | |
download | chromium_src-4deeb43f8b7c1b21d3545228db86de2c73c9fd43.zip chromium_src-4deeb43f8b7c1b21d3545228db86de2c73c9fd43.tar.gz chromium_src-4deeb43f8b7c1b21d3545228db86de2c73c9fd43.tar.bz2 |
Implement proxying for FileRef and FileChooser.
This also changes the FileRef interface to remove the Query function, since
there is no close function, there's no way to cancel the current request, which
makes memory management of the info structure very difficult.
Review URL: http://codereview.chromium.org/6519057
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75331 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/proxy')
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 4 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.cc | 47 | ||||
-rw-r--r-- | ppapi/proxy/host_dispatcher.h | 12 | ||||
-rw-r--r-- | ppapi/proxy/interface_id.h | 2 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource.h | 2 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages_internal.h | 42 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_param_traits.cc | 29 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_param_traits.h | 9 | ||||
-rw-r--r-- | ppapi/proxy/ppb_file_chooser_proxy.cc | 246 | ||||
-rw-r--r-- | ppapi/proxy/ppb_file_chooser_proxy.h | 66 | ||||
-rw-r--r-- | ppapi/proxy/ppb_file_ref_proxy.cc | 350 | ||||
-rw-r--r-- | ppapi/proxy/ppb_file_ref_proxy.h | 86 | ||||
-rw-r--r-- | ppapi/proxy/ppb_url_loader_proxy.cc | 5 | ||||
-rw-r--r-- | ppapi/proxy/serialized_structs.cc | 5 | ||||
-rw-r--r-- | ppapi/proxy/serialized_structs.h | 11 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.cc | 15 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.h | 15 |
17 files changed, 934 insertions, 12 deletions
diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc index 4dc97f2..2eca735 100644 --- a/ppapi/proxy/dispatcher.cc +++ b/ppapi/proxy/dispatcher.cc @@ -48,6 +48,8 @@ #include "ppapi/proxy/ppb_context_3d_proxy.h" #include "ppapi/proxy/ppb_core_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_flash_proxy.h" #include "ppapi/proxy/ppb_flash_menu_proxy.h" #include "ppapi/proxy/ppb_font_proxy.h" @@ -103,6 +105,8 @@ InterfaceList::InterfaceList() { AddPPB(PPB_Context3D_Proxy::GetInfo()); AddPPB(PPB_Core_Proxy::GetInfo()); AddPPB(PPB_CursorControl_Proxy::GetInfo()); + AddPPB(PPB_FileChooser_Proxy::GetInfo()); + AddPPB(PPB_FileRef_Proxy::GetInfo()); AddPPB(PPB_Flash_Proxy::GetInfo()); AddPPB(PPB_Flash_Menu_Proxy::GetInfo()); AddPPB(PPB_Font_Proxy::GetInfo()); diff --git a/ppapi/proxy/host_dispatcher.cc b/ppapi/proxy/host_dispatcher.cc index 5572e91..aa972b5 100644 --- a/ppapi/proxy/host_dispatcher.cc +++ b/ppapi/proxy/host_dispatcher.cc @@ -94,17 +94,7 @@ bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) { if (!info || (info->is_trusted && disallow_trusted_interfaces())) return true; - - 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 true; - } - - proxy = info->create_proxy(this, local_interface); - target_proxies_[info->id].reset(proxy); + proxy = CreatePPBInterfaceProxy(info); } return proxy->OnMessageReceived(msg); @@ -142,6 +132,26 @@ const void* HostDispatcher::GetProxiedInterface(const std::string& interface) { 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; +} + const PPB_Proxy_Private* HostDispatcher::GetPPBProxy() { if (!ppb_proxy_) { ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>( @@ -150,6 +160,21 @@ const PPB_Proxy_Private* HostDispatcher::GetPPBProxy() { return ppb_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; +} + } // namespace proxy } // namespace pp diff --git a/ppapi/proxy/host_dispatcher.h b/ppapi/proxy/host_dispatcher.h index 5153f19..35cdece 100644 --- a/ppapi/proxy/host_dispatcher.h +++ b/ppapi/proxy/host_dispatcher.h @@ -70,12 +70,24 @@ class HostDispatcher : public Dispatcher { // 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); + // Returns the proxy interface for talking to the implementation. const PPB_Proxy_Private* GetPPBProxy(); 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_; enum PluginInterfaceSupport { diff --git a/ppapi/proxy/interface_id.h b/ppapi/proxy/interface_id.h index 4d38648..d3da24e 100644 --- a/ppapi/proxy/interface_id.h +++ b/ppapi/proxy/interface_id.h @@ -20,6 +20,8 @@ enum InterfaceID { INTERFACE_ID_PPB_CONTEXT_3D, INTERFACE_ID_PPB_CORE, INTERFACE_ID_PPB_CURSORCONTROL, + INTERFACE_ID_PPB_FILE_CHOOSER, + INTERFACE_ID_PPB_FILE_REF, INTERFACE_ID_PPB_FLASH, INTERFACE_ID_PPB_FLASH_MENU, INTERFACE_ID_PPB_FONT, diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h index 115fc66..92b1b8c 100644 --- a/ppapi/proxy/plugin_resource.h +++ b/ppapi/proxy/plugin_resource.h @@ -17,6 +17,8 @@ F(AudioConfig) \ F(Buffer) \ F(Context3D) \ + F(FileChooser) \ + F(FileRef) \ F(FlashMenu) \ F(Font) \ F(Graphics2D) \ diff --git a/ppapi/proxy/ppapi_messages_internal.h b/ppapi/proxy/ppapi_messages_internal.h index f9e09a6..be671a2 100644 --- a/ppapi/proxy/ppapi_messages_internal.h +++ b/ppapi/proxy/ppapi_messages_internal.h @@ -46,6 +46,13 @@ IPC_MESSAGE_ROUTED5(PpapiMsg_PPBAudio_NotifyAudioStreamCreated, base::SharedMemoryHandle /* handle */, int32_t /* length */) +// 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_Graphics2D. IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics2D_FlushACK, pp::proxy::HostResource /* graphics_2d */, @@ -276,6 +283,41 @@ 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_Flash. IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBFlash_SetInstanceAlwaysOnTop, PP_Instance /* instance */, diff --git a/ppapi/proxy/ppapi_param_traits.cc b/ppapi/proxy/ppapi_param_traits.cc index b3611f4..d522a37 100644 --- a/ppapi/proxy/ppapi_param_traits.cc +++ b/ppapi/proxy/ppapi_param_traits.cc @@ -241,6 +241,35 @@ void ParamTraits<pp::proxy::PPBFlash_DrawGlyphs_Params>::Log( 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) { +} + // PPBFont_DrawTextAt_Params --------------------------------------------------- // static diff --git a/ppapi/proxy/ppapi_param_traits.h b/ppapi/proxy/ppapi_param_traits.h index 83b4342..b4fdfca 100644 --- a/ppapi/proxy/ppapi_param_traits.h +++ b/ppapi/proxy/ppapi_param_traits.h @@ -20,6 +20,7 @@ namespace pp { namespace proxy { class HostResource; +struct PPBFileRef_CreateInfo; struct PPBFlash_DrawGlyphs_Params; struct PPBFont_DrawTextAt_Params; struct PPBURLLoader_UpdateProgress_Params; @@ -98,6 +99,14 @@ struct ParamTraits<pp::proxy::PPBFlash_DrawGlyphs_Params> { }; 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::PPBFont_DrawTextAt_Params> { typedef pp::proxy::PPBFont_DrawTextAt_Params param_type; static void Write(Message* m, const param_type& p); diff --git a/ppapi/proxy/ppb_file_chooser_proxy.cc b/ppapi/proxy/ppb_file_chooser_proxy.cc new file mode 100644 index 0000000..a50908c4 --- /dev/null +++ b/ppapi/proxy/ppb_file_chooser_proxy.cc @@ -0,0 +1,246 @@ +// 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/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" + +namespace pp { +namespace proxy { + +class FileChooser : public PluginResource { + public: + FileChooser(const HostResource& resource); + virtual ~FileChooser(); + + virtual FileChooser* AsFileChooser(); + + 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_; + + private: + 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) + PP_RunCompletionCallback(¤t_show_callback_, 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(); + } +} + +FileChooser* FileChooser::AsFileChooser() { + return this; +} + +namespace { + +PP_Resource Create(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, &result)); + + if (result.is_null()) + return 0; + linked_ptr<FileChooser> object(new FileChooser(result)); + return PluginResourceTracker::GetInstance()->AddResource(object); +} + +PP_Bool IsFileChooser(PP_Resource resource) { + FileChooser* object = PluginResource::GetAs<FileChooser>(resource); + return BoolToPPBool(!!object); +} + +int32_t Show(PP_Resource chooser, struct PP_CompletionCallback callback) { + FileChooser* object = PluginResource::GetAs<FileChooser>(chooser); + if (!object) + return PP_ERROR_BADRESOURCE; + Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); + if (!dispatcher) + return PP_ERROR_BADARGUMENT; + + if (object->current_show_callback_.func) + return PP_ERROR_INPROGRESS; // Can't show more than once. + + object->current_show_callback_ = callback; + dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Show( + INTERFACE_ID_PPB_FILE_CHOOSER, + object->host_resource())); + return PP_ERROR_WOULDBLOCK; +} + +PP_Resource GetNextChosenFile(PP_Resource chooser) { + FileChooser* object = PluginResource::GetAs<FileChooser>(chooser); + if (!object || object->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 = object->file_queue_.front(); + object->file_queue_.pop(); + return next; +} + +const PPB_FileChooser_Dev file_chooser_interface = { + &Create, + &IsFileChooser, + &Show, + &GetNextChosenFile +}; + +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 = { + &file_chooser_interface, + PPB_FILECHOOSER_DEV_INTERFACE, + INTERFACE_ID_PPB_FILE_CHOOSER, + false, + &CreateFileChooserProxy, + }; + return &info; +} + +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_.NewCallback( + &PPB_FileChooser_Proxy::OnShowCallback, chooser); + + int32_t result = ppb_file_chooser_target()->Show( + chooser.host_resource(), callback.pp_completion_callback()); + if (result != PP_ERROR_WOULDBLOCK) + callback.Run(result); +} + +void PPB_FileChooser_Proxy::OnMsgChooseComplete( + const HostResource& chooser, + int32_t result_code, + const std::vector<PPBFileRef_CreateInfo>& chosen_files) { + PP_Resource plugin_resource = + PluginResourceTracker::GetInstance()->PluginResourceForHostResource( + chooser); + if (!plugin_resource) + return; + FileChooser* object = PluginResource::GetAs<FileChooser>(plugin_resource); + if (!object) + return; + + // 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(object->file_queue_.empty()); + for (size_t i = 0; i < chosen_files.size(); i++) { + object->file_queue_.push( + PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); + } + + // Notify the plugin of the new data. We have to swap out the callback + // because the plugin may trigger deleting the object from the callback, and + // the FileChooser object will attempt to call the callback in its destructor + // with the ABORTED status. + PP_CompletionCallback callback = object->current_show_callback_; + object->current_show_callback_ = PP_MakeCompletionCallback(NULL, NULL); + PP_RunCompletionCallback(&callback, result_code); + // DANGER: May delete |object|! +} + +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..97b3aa2 --- /dev/null +++ b/ppapi/proxy/ppb_file_chooser_proxy.h @@ -0,0 +1,66 @@ +// 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" + +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(); + + 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..85b133e --- /dev/null +++ b/ppapi/proxy/ppb_file_ref_proxy.cc @@ -0,0 +1,350 @@ +// 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/dev/ppb_file_ref_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_proxy_private.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" + +namespace pp { +namespace proxy { + +// 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 FileRef : public PluginResource { + public: + FileRef(const PPBFileRef_CreateInfo& info); + virtual ~FileRef(); + + virtual FileRef* AsFileRef(); + + PP_FileSystemType_Dev file_system_type() const { return file_system_type_; } + const PP_Var& path() const { return path_; } + const PP_Var& name() const { return name_; } + + private: + PP_FileSystemType_Dev 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_Dev>(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_); +} + +FileRef* FileRef::AsFileRef() { + return this; +} + +namespace { + +bool FileRefAndDispatcherForResource(PP_Resource resource, + FileRef** file_ref, + Dispatcher** dispatcher) { + *file_ref = PluginResource::GetAs<FileRef>(resource); + if (!file_ref) + return false; + *dispatcher = PluginDispatcher::GetForInstance((*file_ref)->instance()); + return !!(*dispatcher); +} + +PP_Resource Create(PP_Resource file_system, const char* path) { + PluginResource* file_system_object = + PluginResourceTracker::GetInstance()->GetResourceObject(file_system); + if (!file_system_object) + return 0; + + Dispatcher* dispatcher = + PluginDispatcher::GetForInstance(file_system_object->instance()); + if (!dispatcher) + return 0; + + PPBFileRef_CreateInfo create_info; + dispatcher->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); +} + +PP_Bool IsFileRef(PP_Resource resource) { + FileRef* object = PluginResource::GetAs<FileRef>(resource); + return BoolToPPBool(!!object); +} + +PP_FileSystemType_Dev GetFileSystemType(PP_Resource file_ref) { + FileRef* object = PluginResource::GetAs<FileRef>(file_ref); + if (!object) + return PP_FILESYSTEMTYPE_EXTERNAL; + return object->file_system_type(); +} + +PP_Var GetName(PP_Resource file_ref) { + FileRef* object = PluginResource::GetAs<FileRef>(file_ref); + if (!object) + return PP_MakeUndefined(); + + PluginVarTracker::GetInstance()->AddRef(object->name()); + return object->name(); +} + +PP_Var GetPath(PP_Resource file_ref) { + FileRef* object = PluginResource::GetAs<FileRef>(file_ref); + if (!object) + return PP_MakeUndefined(); + + PluginVarTracker::GetInstance()->AddRef(object->path()); + return object->path(); +} + +PP_Resource GetParent(PP_Resource file_ref) { + FileRef* object; + Dispatcher* dispatcher; + if (!FileRefAndDispatcherForResource(file_ref, &object, &dispatcher)) + return 0; + + PPBFileRef_CreateInfo create_info; + dispatcher->Send(new PpapiHostMsg_PPBFileRef_GetParent( + INTERFACE_ID_PPB_FILE_REF, object->host_resource(), &create_info)); + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + +int32_t MakeDirectory(PP_Resource directory_ref, + PP_Bool make_ancestors, + struct PP_CompletionCallback callback) { + FileRef* object; + Dispatcher* dispatcher; + if (!FileRefAndDispatcherForResource(directory_ref, &object, &dispatcher)) + return PP_ERROR_BADRESOURCE; + + dispatcher->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( + INTERFACE_ID_PPB_FILE_REF, object->host_resource(), make_ancestors, + dispatcher->callback_tracker().SendCallback(callback))); + return PP_ERROR_WOULDBLOCK; +} + +int32_t Touch(PP_Resource file_ref, + PP_Time last_access_time, + PP_Time last_modified_time, + struct PP_CompletionCallback callback) { + FileRef* object; + Dispatcher* dispatcher; + if (!FileRefAndDispatcherForResource(file_ref, &object, &dispatcher)) + return PP_ERROR_BADRESOURCE; + + dispatcher->Send(new PpapiHostMsg_PPBFileRef_Touch( + INTERFACE_ID_PPB_FILE_REF, object->host_resource(), + last_access_time, last_modified_time, + dispatcher->callback_tracker().SendCallback(callback))); + return PP_ERROR_WOULDBLOCK; +} + +int32_t Delete(PP_Resource file_ref, + struct PP_CompletionCallback callback) { + FileRef* object; + Dispatcher* dispatcher; + if (!FileRefAndDispatcherForResource(file_ref, &object, &dispatcher)) + return PP_ERROR_BADRESOURCE; + + dispatcher->Send(new PpapiHostMsg_PPBFileRef_Delete( + INTERFACE_ID_PPB_FILE_REF, object->host_resource(), + dispatcher->callback_tracker().SendCallback(callback))); + return PP_ERROR_WOULDBLOCK; +} + +int32_t Rename(PP_Resource file_ref, + PP_Resource new_file_ref, + struct PP_CompletionCallback callback) { + FileRef* obj1; + Dispatcher* dispatcher1; + if (!FileRefAndDispatcherForResource(file_ref, &obj1, &dispatcher1)) + return PP_ERROR_BADRESOURCE; + + FileRef* obj2; + Dispatcher* dispatcher2; + if (!FileRefAndDispatcherForResource(new_file_ref, &obj2, &dispatcher2)) + return PP_ERROR_BADRESOURCE; + + if (obj1->instance() != obj2->instance()) + return PP_ERROR_BADRESOURCE; + + dispatcher1->Send(new PpapiHostMsg_PPBFileRef_Rename( + INTERFACE_ID_PPB_FILE_REF, obj1->host_resource(), + obj2->host_resource(), + dispatcher1->callback_tracker().SendCallback(callback))); + return PP_ERROR_WOULDBLOCK; +} + +const PPB_FileRef_Dev file_ref_interface = { + &Create, + &IsFileRef, + &GetFileSystemType, + &GetName, + &GetPath, + &GetParent, + &MakeDirectory, + &Touch, + &Delete, + &Rename +}; + +InterfaceProxy* CreateFileRefProxy(Dispatcher* dispatcher, + const void* target_interface) { + return new PPB_FileRef_Proxy(dispatcher, target_interface); +} + +} // namespace + +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 = { + &file_ref_interface, + PPB_FILEREF_DEV_INTERFACE, + INTERFACE_ID_PPB_FILE_REF, + false, + &CreateFileRefProxy, + }; + return &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) { + // 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->GetPPBProxy()->GetInstanceForResource(file_ref); + + result->resource.SetHostResource(instance, file_ref); + result->file_system_type = + static_cast<int>(ppb_file_ref_target()->GetFileSystemType(file_ref)); + result->path = SerializedVarReturnValue::Convert( + dispatcher(), + ppb_file_ref_target()->GetPath(file_ref)); + result->name = SerializedVarReturnValue::Convert( + dispatcher(), + ppb_file_ref_target()->GetName(file_ref)); +} + +// 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) { + + PP_Resource resource = ppb_file_ref_target()->Create( + 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) { + PP_Resource resource = ppb_file_ref_target()->GetParent( + host_resource.host_resource()); + if (!resource) + return; // CreateInfo default constructor initializes to 0. + SerializeFileRef(resource, result); +} + +void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, + PP_Bool make_ancestors, + uint32_t serialized_callback) { + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = + ppb_file_ref_target()->MakeDirectory(host_resource.host_resource(), + make_ancestors, callback); + if (result != PP_ERROR_WOULDBLOCK) + 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) { + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = + ppb_file_ref_target()->Touch(host_resource.host_resource(), + last_access, last_modified, callback); + if (result != PP_ERROR_WOULDBLOCK) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, + uint32_t serialized_callback) { + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = + ppb_file_ref_target()->Delete(host_resource.host_resource(), callback); + if (result != PP_ERROR_WOULDBLOCK) + PP_RunCompletionCallback(&callback, result); +} + +void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, + const HostResource& new_file_ref, + uint32_t serialized_callback) { + PP_CompletionCallback callback = ReceiveCallback(serialized_callback); + int32_t result = + ppb_file_ref_target()->Rename(file_ref.host_resource(), + new_file_ref.host_resource(), + callback); + if (result != PP_ERROR_WOULDBLOCK) + 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..ca0b588 --- /dev/null +++ b/ppapi/proxy/ppb_file_ref_proxy.h @@ -0,0 +1,86 @@ +// 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(); + + const PPB_FileRef_Dev* ppb_file_ref_target() const { + return static_cast<const PPB_FileRef_Dev*>(target_interface()); + } + + // 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_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc index a021eff..76e3a35 100644 --- a/ppapi/proxy/ppb_url_loader_proxy.cc +++ b/ppapi/proxy/ppb_url_loader_proxy.cc @@ -69,6 +69,10 @@ URLLoader::URLLoader(const HostResource& resource) } URLLoader::~URLLoader() { + // Always need to fire completion callbacks to prevent a leak in the plugin. + if (current_read_callback_.func) + PP_RunCompletionCallback(¤t_read_callback_, PP_ERROR_ABORTED); + if (response_info_) PluginResourceTracker::GetInstance()->ReleaseResource(response_info_); } @@ -365,6 +369,7 @@ void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader, loader.host_resource(), request_info.host_resource(), callback); if (result != PP_ERROR_WOULDBLOCK) PP_RunCompletionCallback(&callback, result); + // TODO(brettw) bug 73236 register for the status callbacks. } void PPB_URLLoader_Proxy::OnMsgFollowRedirect( diff --git a/ppapi/proxy/serialized_structs.cc b/ppapi/proxy/serialized_structs.cc index 576e31a..1e9ded0 100644 --- a/ppapi/proxy/serialized_structs.cc +++ b/ppapi/proxy/serialized_structs.cc @@ -5,6 +5,7 @@ #include "ppapi/proxy/serialized_structs.h" #include "ppapi/c/dev/ppb_font_dev.h" +#include "ppapi/c/dev/pp_file_info_dev.h" #include "ppapi/c/pp_rect.h" namespace pp { @@ -62,6 +63,10 @@ void SerializedFontDescription::SetToPPFontDescription( 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(), diff --git a/ppapi/proxy/serialized_structs.h b/ppapi/proxy/serialized_structs.h index 8b40042..1482ab3 100644 --- a/ppapi/proxy/serialized_structs.h +++ b/ppapi/proxy/serialized_structs.h @@ -70,6 +70,17 @@ struct SerializedDirEntry { 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_Dev values. + SerializedVar path; + SerializedVar name; +}; + // Since there are so many parameters, DrawTextAt requires this separate // structure. This includes everything but the font name. Because the font name // is a var, it's much more convenient to use the normal way of passing a diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc index a4888a0..e68c681 100644 --- a/ppapi/proxy/serialized_var.cc +++ b/ppapi/proxy/serialized_var.cc @@ -266,6 +266,11 @@ void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, 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( @@ -421,6 +426,16 @@ void SerializedVarReturnValue::Return(Dispatcher* dispatcher, 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) diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h index 75ef494..4d8d813 100644 --- a/ppapi/proxy/serialized_var.h +++ b/ppapi/proxy/serialized_var.h @@ -210,9 +210,17 @@ class SerializedVarSendInput : public SerializedVar { 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. + // 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: @@ -355,6 +363,11 @@ class SerializedVarReturnValue { 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_; }; |