diff options
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_; }; |
