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 |