| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/proxy/ppb_file_chooser_proxy.h" | 5 #include "ppapi/proxy/ppb_file_chooser_proxy.h" |
| 6 | 6 |
| 7 #include <queue> | 7 #include <queue> |
| 8 | 8 |
| 9 #include "ppapi/c/dev/ppb_file_chooser_dev.h" | 9 #include "ppapi/c/dev/ppb_file_chooser_dev.h" |
| 10 #include "ppapi/c/pp_errors.h" | 10 #include "ppapi/c/pp_errors.h" |
| 11 #include "ppapi/c/private/ppb_proxy_private.h" | 11 #include "ppapi/c/private/ppb_proxy_private.h" |
| 12 #include "ppapi/proxy/enter_proxy.h" | |
| 13 #include "ppapi/proxy/host_dispatcher.h" | 12 #include "ppapi/proxy/host_dispatcher.h" |
| 14 #include "ppapi/proxy/plugin_dispatcher.h" | 13 #include "ppapi/proxy/plugin_dispatcher.h" |
| 15 #include "ppapi/proxy/plugin_resource.h" | 14 #include "ppapi/proxy/plugin_resource.h" |
| 16 #include "ppapi/proxy/ppapi_messages.h" | 15 #include "ppapi/proxy/ppapi_messages.h" |
| 17 #include "ppapi/proxy/ppb_file_ref_proxy.h" | 16 #include "ppapi/proxy/ppb_file_ref_proxy.h" |
| 18 #include "ppapi/proxy/serialized_var.h" | 17 #include "ppapi/proxy/serialized_var.h" |
| 19 #include "ppapi/thunk/thunk.h" | |
| 20 | |
| 21 using ::ppapi::thunk::PPB_FileChooser_API; | |
| 22 | 18 |
| 23 namespace pp { | 19 namespace pp { |
| 24 namespace proxy { | 20 namespace proxy { |
| 25 | 21 |
| 26 class FileChooser : public PluginResource, | 22 class FileChooser : public PluginResource { |
| 27 public PPB_FileChooser_API { | |
| 28 public: | 23 public: |
| 29 FileChooser(const HostResource& resource); | 24 FileChooser(const HostResource& resource); |
| 30 virtual ~FileChooser(); | 25 virtual ~FileChooser(); |
| 31 | 26 |
| 32 // ResourceObjectBase overrides. | 27 virtual FileChooser* AsFileChooser(); |
| 33 virtual PPB_FileChooser_API* AsPPB_FileChooser_API() OVERRIDE; | |
| 34 | 28 |
| 35 // PPB_FileChooser_API implementation. | |
| 36 virtual int32_t Show(PP_CompletionCallback callback) OVERRIDE; | |
| 37 virtual PP_Resource GetNextChosenFile() OVERRIDE; | |
| 38 | |
| 39 // Handles the choose complete notification from the host. | |
| 40 void ChooseComplete( | |
| 41 int32_t result_code, | |
| 42 const std::vector<PPBFileRef_CreateInfo>& chosen_files); | |
| 43 | |
| 44 private: | |
| 45 PP_CompletionCallback current_show_callback_; | 29 PP_CompletionCallback current_show_callback_; |
| 46 | 30 |
| 47 // All files returned by the current show callback that haven't yet been | 31 // All files returned by the current show callback that haven't yet been |
| 48 // given to the plugin. The plugin will repeatedly call us to get the next | 32 // given to the plugin. The plugin will repeatedly call us to get the next |
| 49 // file, and we'll vend those out of this queue, removing them when ownership | 33 // file, and we'll vend those out of this queue, removing them when ownership |
| 50 // has transferred to the plugin. | 34 // has transferred to the plugin. |
| 51 std::queue<PP_Resource> file_queue_; | 35 std::queue<PP_Resource> file_queue_; |
| 52 | 36 |
| 37 private: |
| 53 DISALLOW_COPY_AND_ASSIGN(FileChooser); | 38 DISALLOW_COPY_AND_ASSIGN(FileChooser); |
| 54 }; | 39 }; |
| 55 | 40 |
| 56 FileChooser::FileChooser(const HostResource& resource) | 41 FileChooser::FileChooser(const HostResource& resource) |
| 57 : PluginResource(resource), | 42 : PluginResource(resource), |
| 58 current_show_callback_(PP_MakeCompletionCallback(NULL, NULL)) { | 43 current_show_callback_(PP_MakeCompletionCallback(NULL, NULL)) { |
| 59 } | 44 } |
| 60 | 45 |
| 61 FileChooser::~FileChooser() { | 46 FileChooser::~FileChooser() { |
| 62 // Always need to fire completion callbacks to prevent a leak in the plugin. | 47 // Always need to fire completion callbacks to prevent a leak in the plugin. |
| 63 if (current_show_callback_.func) { | 48 if (current_show_callback_.func) { |
| 64 // TODO(brettw) the callbacks at this level should be refactored with a | 49 // TODO(brettw) the callbacks at this level should be refactored with a |
| 65 // more automatic tracking system like we have in the renderer. | 50 // more automatic tracking system like we have in the renderer. |
| 66 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( | 51 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction( |
| 67 current_show_callback_.func, current_show_callback_.user_data, | 52 current_show_callback_.func, current_show_callback_.user_data, |
| 68 static_cast<int32_t>(PP_ERROR_ABORTED))); | 53 static_cast<int32_t>(PP_ERROR_ABORTED))); |
| 69 } | 54 } |
| 70 | 55 |
| 71 // Any existing files we haven't transferred ownership to the plugin need | 56 // Any existing files we haven't transferred ownership to the plugin need |
| 72 // to be freed. | 57 // to be freed. |
| 73 PluginResourceTracker* tracker = PluginResourceTracker::GetInstance(); | 58 PluginResourceTracker* tracker = PluginResourceTracker::GetInstance(); |
| 74 while (!file_queue_.empty()) { | 59 while (!file_queue_.empty()) { |
| 75 tracker->ReleaseResource(file_queue_.front()); | 60 tracker->ReleaseResource(file_queue_.front()); |
| 76 file_queue_.pop(); | 61 file_queue_.pop(); |
| 77 } | 62 } |
| 78 } | 63 } |
| 79 | 64 |
| 80 PPB_FileChooser_API* FileChooser::AsPPB_FileChooser_API() { | 65 FileChooser* FileChooser::AsFileChooser() { |
| 81 return this; | 66 return this; |
| 82 } | 67 } |
| 83 | 68 |
| 84 int32_t FileChooser::Show(PP_CompletionCallback callback) { | 69 namespace { |
| 85 if (current_show_callback_.func) | 70 |
| 71 PP_Resource Create(PP_Instance instance, |
| 72 const PP_FileChooserOptions_Dev* options) { |
| 73 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 74 if (!dispatcher) |
| 75 return 0; |
| 76 |
| 77 HostResource result; |
| 78 dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create( |
| 79 INTERFACE_ID_PPB_FILE_CHOOSER, instance, |
| 80 options->mode, |
| 81 options->accept_mime_types ? options->accept_mime_types : std::string(), |
| 82 &result)); |
| 83 |
| 84 if (result.is_null()) |
| 85 return 0; |
| 86 linked_ptr<FileChooser> object(new FileChooser(result)); |
| 87 return PluginResourceTracker::GetInstance()->AddResource(object); |
| 88 } |
| 89 |
| 90 PP_Bool IsFileChooser(PP_Resource resource) { |
| 91 FileChooser* object = PluginResource::GetAs<FileChooser>(resource); |
| 92 return BoolToPPBool(!!object); |
| 93 } |
| 94 |
| 95 int32_t Show(PP_Resource chooser, struct PP_CompletionCallback callback) { |
| 96 FileChooser* object = PluginResource::GetAs<FileChooser>(chooser); |
| 97 if (!object) |
| 98 return PP_ERROR_BADRESOURCE; |
| 99 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance()); |
| 100 if (!dispatcher) |
| 101 return PP_ERROR_BADARGUMENT; |
| 102 |
| 103 if (object->current_show_callback_.func) |
| 86 return PP_ERROR_INPROGRESS; // Can't show more than once. | 104 return PP_ERROR_INPROGRESS; // Can't show more than once. |
| 87 | 105 |
| 88 current_show_callback_ = callback; | 106 object->current_show_callback_ = callback; |
| 89 GetDispatcher()->Send(new PpapiHostMsg_PPBFileChooser_Show( | 107 dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Show( |
| 90 INTERFACE_ID_PPB_FILE_CHOOSER, host_resource())); | 108 INTERFACE_ID_PPB_FILE_CHOOSER, |
| 109 object->host_resource())); |
| 91 return PP_OK_COMPLETIONPENDING; | 110 return PP_OK_COMPLETIONPENDING; |
| 92 } | 111 } |
| 93 | 112 |
| 94 PP_Resource FileChooser::GetNextChosenFile() { | 113 PP_Resource GetNextChosenFile(PP_Resource chooser) { |
| 95 if (file_queue_.empty()) | 114 FileChooser* object = PluginResource::GetAs<FileChooser>(chooser); |
| 115 if (!object || object->file_queue_.empty()) |
| 96 return 0; | 116 return 0; |
| 97 | 117 |
| 98 // Return the next resource in the queue. These resource have already been | 118 // Return the next resource in the queue. These resource have already been |
| 99 // addrefed (they're currently owned by the FileChooser) and returning them | 119 // addrefed (they're currently owned by the FileChooser) and returning them |
| 100 // transfers ownership of that reference to the plugin. | 120 // transfers ownership of that reference to the plugin. |
| 101 PP_Resource next = file_queue_.front(); | 121 PP_Resource next = object->file_queue_.front(); |
| 102 file_queue_.pop(); | 122 object->file_queue_.pop(); |
| 103 return next; | 123 return next; |
| 104 } | 124 } |
| 105 | 125 |
| 106 void FileChooser::ChooseComplete( | 126 const PPB_FileChooser_Dev file_chooser_interface = { |
| 107 int32_t result_code, | 127 &Create, |
| 108 const std::vector<PPBFileRef_CreateInfo>& chosen_files) { | 128 &IsFileChooser, |
| 109 // Convert each of the passed in file infos to resources. These will be owned | 129 &Show, |
| 110 // by the FileChooser object until they're passed to the plugin. | 130 &GetNextChosenFile |
| 111 DCHECK(file_queue_.empty()); | 131 }; |
| 112 for (size_t i = 0; i < chosen_files.size(); i++) | |
| 113 file_queue_.push(PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); | |
| 114 | |
| 115 // Notify the plugin of the new data. | |
| 116 PP_RunAndClearCompletionCallback(¤t_show_callback_, result_code); | |
| 117 // DANGER: May delete |this|! | |
| 118 } | |
| 119 | |
| 120 namespace { | |
| 121 | 132 |
| 122 InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher, | 133 InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher, |
| 123 const void* target_interface) { | 134 const void* target_interface) { |
| 124 return new PPB_FileChooser_Proxy(dispatcher, target_interface); | 135 return new PPB_FileChooser_Proxy(dispatcher, target_interface); |
| 125 } | 136 } |
| 126 | 137 |
| 127 } // namespace | 138 } // namespace |
| 128 | 139 |
| 129 PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher, | 140 PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher, |
| 130 const void* target_interface) | 141 const void* target_interface) |
| 131 : InterfaceProxy(dispatcher, target_interface), | 142 : InterfaceProxy(dispatcher, target_interface), |
| 132 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 143 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 133 } | 144 } |
| 134 | 145 |
| 135 PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() { | 146 PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() { |
| 136 } | 147 } |
| 137 | 148 |
| 138 const InterfaceProxy::Info* PPB_FileChooser_Proxy::GetInfo() { | 149 const InterfaceProxy::Info* PPB_FileChooser_Proxy::GetInfo() { |
| 139 static const Info info = { | 150 static const Info info = { |
| 140 ::ppapi::thunk::GetPPB_FileChooser_Thunk(), | 151 &file_chooser_interface, |
| 141 PPB_FILECHOOSER_DEV_INTERFACE, | 152 PPB_FILECHOOSER_DEV_INTERFACE, |
| 142 INTERFACE_ID_PPB_FILE_CHOOSER, | 153 INTERFACE_ID_PPB_FILE_CHOOSER, |
| 143 false, | 154 false, |
| 144 &CreateFileChooserProxy, | 155 &CreateFileChooserProxy, |
| 145 }; | 156 }; |
| 146 return &info; | 157 return &info; |
| 147 } | 158 } |
| 148 | 159 |
| 149 // static | |
| 150 PP_Resource PPB_FileChooser_Proxy::CreateProxyResource( | |
| 151 PP_Instance instance, | |
| 152 const PP_FileChooserOptions_Dev* options) { | |
| 153 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | |
| 154 if (!dispatcher) | |
| 155 return 0; | |
| 156 | |
| 157 HostResource result; | |
| 158 dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create( | |
| 159 INTERFACE_ID_PPB_FILE_CHOOSER, instance, | |
| 160 options->mode, | |
| 161 options->accept_mime_types ? options->accept_mime_types : std::string(), | |
| 162 &result)); | |
| 163 | |
| 164 if (result.is_null()) | |
| 165 return 0; | |
| 166 linked_ptr<FileChooser> object(new FileChooser(result)); | |
| 167 return PluginResourceTracker::GetInstance()->AddResource(object); | |
| 168 } | |
| 169 | |
| 170 bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) { | 160 bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| 171 bool handled = true; | 161 bool handled = true; |
| 172 IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg) | 162 IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg) |
| 173 // Plugin -> host messages. | 163 // Plugin -> host messages. |
| 174 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate) | 164 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate) |
| 175 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow) | 165 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow) |
| 176 | 166 |
| 177 // Host -> plugin messages. | 167 // Host -> plugin messages. |
| 178 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete, | 168 IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete, |
| 179 OnMsgChooseComplete) | 169 OnMsgChooseComplete) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 200 int32_t result = ppb_file_chooser_target()->Show( | 190 int32_t result = ppb_file_chooser_target()->Show( |
| 201 chooser.host_resource(), callback.pp_completion_callback()); | 191 chooser.host_resource(), callback.pp_completion_callback()); |
| 202 if (result != PP_OK_COMPLETIONPENDING) | 192 if (result != PP_OK_COMPLETIONPENDING) |
| 203 callback.Run(result); | 193 callback.Run(result); |
| 204 } | 194 } |
| 205 | 195 |
| 206 void PPB_FileChooser_Proxy::OnMsgChooseComplete( | 196 void PPB_FileChooser_Proxy::OnMsgChooseComplete( |
| 207 const HostResource& chooser, | 197 const HostResource& chooser, |
| 208 int32_t result_code, | 198 int32_t result_code, |
| 209 const std::vector<PPBFileRef_CreateInfo>& chosen_files) { | 199 const std::vector<PPBFileRef_CreateInfo>& chosen_files) { |
| 210 EnterPluginFromHostResource<PPB_FileChooser_API> enter(chooser); | 200 PP_Resource plugin_resource = |
| 211 if (enter.succeeded()) { | 201 PluginResourceTracker::GetInstance()->PluginResourceForHostResource( |
| 212 static_cast<FileChooser*>(enter.object())->ChooseComplete( | 202 chooser); |
| 213 result_code, chosen_files); | 203 if (!plugin_resource) |
| 204 return; |
| 205 FileChooser* object = PluginResource::GetAs<FileChooser>(plugin_resource); |
| 206 if (!object) |
| 207 return; |
| 208 |
| 209 // Convert each of the passed in file infos to resources. These will be owned |
| 210 // by the FileChooser object until they're passed to the plugin. |
| 211 DCHECK(object->file_queue_.empty()); |
| 212 for (size_t i = 0; i < chosen_files.size(); i++) { |
| 213 object->file_queue_.push( |
| 214 PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i])); |
| 214 } | 215 } |
| 216 |
| 217 // Notify the plugin of the new data. We have to swap out the callback |
| 218 // because the plugin may trigger deleting the object from the callback, and |
| 219 // the FileChooser object will attempt to call the callback in its destructor |
| 220 // with the ABORTED status. |
| 221 PP_RunAndClearCompletionCallback(&object->current_show_callback_, |
| 222 result_code); |
| 223 // DANGER: May delete |object|! |
| 215 } | 224 } |
| 216 | 225 |
| 217 void PPB_FileChooser_Proxy::OnShowCallback(int32_t result, | 226 void PPB_FileChooser_Proxy::OnShowCallback(int32_t result, |
| 218 const HostResource& chooser) { | 227 const HostResource& chooser) { |
| 219 std::vector<PPBFileRef_CreateInfo> files; | 228 std::vector<PPBFileRef_CreateInfo> files; |
| 220 if (result == PP_OK) { | 229 if (result == PP_OK) { |
| 221 // Jump through some hoops to get the FileRef proxy. Since we know we're | 230 // Jump through some hoops to get the FileRef proxy. Since we know we're |
| 222 // in the host at this point, we can ask the host dispatcher for it. | 231 // in the host at this point, we can ask the host dispatcher for it. |
| 223 DCHECK(!dispatcher()->IsPlugin()); | 232 DCHECK(!dispatcher()->IsPlugin()); |
| 224 HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher()); | 233 HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher()); |
| 225 PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>( | 234 PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>( |
| 226 host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF)); | 235 host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF)); |
| 227 | 236 |
| 228 // Convert the returned files to the serialized info. | 237 // Convert the returned files to the serialized info. |
| 229 while (PP_Resource cur_file_resource = | 238 while (PP_Resource cur_file_resource = |
| 230 ppb_file_chooser_target()->GetNextChosenFile( | 239 ppb_file_chooser_target()->GetNextChosenFile( |
| 231 chooser.host_resource())) { | 240 chooser.host_resource())) { |
| 232 PPBFileRef_CreateInfo cur_create_info; | 241 PPBFileRef_CreateInfo cur_create_info; |
| 233 file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info); | 242 file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info); |
| 234 files.push_back(cur_create_info); | 243 files.push_back(cur_create_info); |
| 235 } | 244 } |
| 236 } | 245 } |
| 237 | 246 |
| 238 dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete( | 247 dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete( |
| 239 INTERFACE_ID_PPB_FILE_CHOOSER, chooser, result, files)); | 248 INTERFACE_ID_PPB_FILE_CHOOSER, chooser, result, files)); |
| 240 } | 249 } |
| 241 | 250 |
| 242 } // namespace proxy | 251 } // namespace proxy |
| 243 } // namespace pp | 252 } // namespace pp |
| OLD | NEW |