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 |