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