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_ref_proxy.h" | 5 #include "ppapi/proxy/ppb_file_ref_proxy.h" |
6 | 6 |
7 #include <map> | |
8 | |
9 #include "base/bind.h" | |
10 #include "ppapi/c/pp_errors.h" | 7 #include "ppapi/c/pp_errors.h" |
11 #include "ppapi/c/ppb_file_ref.h" | 8 #include "ppapi/c/ppb_file_ref.h" |
12 #include "ppapi/c/private/ppb_proxy_private.h" | 9 #include "ppapi/c/private/ppb_proxy_private.h" |
13 #include "ppapi/proxy/enter_proxy.h" | 10 #include "ppapi/proxy/enter_proxy.h" |
14 #include "ppapi/proxy/host_dispatcher.h" | 11 #include "ppapi/proxy/host_dispatcher.h" |
15 #include "ppapi/proxy/plugin_dispatcher.h" | 12 #include "ppapi/proxy/plugin_dispatcher.h" |
16 #include "ppapi/proxy/ppapi_messages.h" | 13 #include "ppapi/proxy/ppapi_messages.h" |
17 #include "ppapi/proxy/serialized_var.h" | 14 #include "ppapi/proxy/serialized_var.h" |
18 #include "ppapi/shared_impl/file_ref_impl.h" | 15 #include "ppapi/shared_impl/file_ref_impl.h" |
19 #include "ppapi/thunk/resource_creation_api.h" | 16 #include "ppapi/thunk/resource_creation_api.h" |
(...skipping 16 matching lines...) Expand all Loading... |
36 virtual PP_Resource GetParent() OVERRIDE; | 33 virtual PP_Resource GetParent() OVERRIDE; |
37 virtual int32_t MakeDirectory(PP_Bool make_ancestors, | 34 virtual int32_t MakeDirectory(PP_Bool make_ancestors, |
38 PP_CompletionCallback callback) OVERRIDE; | 35 PP_CompletionCallback callback) OVERRIDE; |
39 virtual int32_t Touch(PP_Time last_access_time, | 36 virtual int32_t Touch(PP_Time last_access_time, |
40 PP_Time last_modified_time, | 37 PP_Time last_modified_time, |
41 PP_CompletionCallback callback) OVERRIDE; | 38 PP_CompletionCallback callback) OVERRIDE; |
42 virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE; | 39 virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE; |
43 virtual int32_t Rename(PP_Resource new_file_ref, | 40 virtual int32_t Rename(PP_Resource new_file_ref, |
44 PP_CompletionCallback callback) OVERRIDE; | 41 PP_CompletionCallback callback) OVERRIDE; |
45 | 42 |
46 // Executes the pending callback with the given ID. See pending_callbacks_. | |
47 void ExecuteCallback(int callback_id, int32_t result); | |
48 | |
49 private: | 43 private: |
50 PluginDispatcher* GetDispatcher() const { | 44 PluginDispatcher* GetDispatcher() const { |
51 return PluginDispatcher::GetForResource(this); | 45 return PluginDispatcher::GetForResource(this); |
52 } | 46 } |
53 | 47 |
54 // Adds a callback to the list and returns its ID. Returns 0 if the callback | |
55 // is invalid. | |
56 int SendCallback(PP_CompletionCallback callback); | |
57 | |
58 // This class can have any number of out-standing requests with completion | |
59 // callbacks, in contrast to most resources which have one possible pending | |
60 // callback pending (like a Flush callback). | |
61 // | |
62 // To keep track of them, assign integer IDs to the callbacks, which is how | |
63 // the callback will be identified when it's passed to the host and then | |
64 // back here. | |
65 int next_callback_id_; | |
66 typedef std::map<int, PP_CompletionCallback> PendingCallbackMap; | |
67 PendingCallbackMap pending_callbacks_; | |
68 | |
69 DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef); | 48 DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef); |
70 }; | 49 }; |
71 | 50 |
72 FileRef::FileRef(const PPB_FileRef_CreateInfo& info) | 51 FileRef::FileRef(const PPB_FileRef_CreateInfo& info) |
73 : FileRefImpl(FileRefImpl::InitAsProxy(), info), | 52 : FileRefImpl(FileRefImpl::InitAsProxy(), info) { |
74 next_callback_id_(0) { | |
75 } | 53 } |
76 | 54 |
77 FileRef::~FileRef() { | 55 FileRef::~FileRef() { |
78 // Abort all pending callbacks. Do this by posting a task to avoid reentering | |
79 // the plugin's Release() call that probably deleted this object. | |
80 for (PendingCallbackMap::iterator i = pending_callbacks_.begin(); | |
81 i != pending_callbacks_.end(); ++i) { | |
82 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | |
83 i->second.func, i->second.user_data, | |
84 static_cast<int32_t>(PP_ERROR_ABORTED))); | |
85 } | |
86 } | 56 } |
87 | 57 |
88 PP_Resource FileRef::GetParent() { | 58 PP_Resource FileRef::GetParent() { |
89 PPB_FileRef_CreateInfo create_info; | 59 PPB_FileRef_CreateInfo create_info; |
90 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( | 60 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( |
91 API_ID_PPB_FILE_REF, host_resource(), &create_info)); | 61 API_ID_PPB_FILE_REF, host_resource(), &create_info)); |
92 return PPB_FileRef_Proxy::DeserializeFileRef(create_info); | 62 return PPB_FileRef_Proxy::DeserializeFileRef(create_info); |
93 } | 63 } |
94 | 64 |
95 int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, | 65 int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, |
96 PP_CompletionCallback callback) { | 66 PP_CompletionCallback callback) { |
97 int callback_id = SendCallback(callback); | |
98 if (!callback_id) | |
99 return PP_ERROR_BADARGUMENT; | |
100 | |
101 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( | 67 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( |
102 API_ID_PPB_FILE_REF, host_resource(), make_ancestors, callback_id)); | 68 API_ID_PPB_FILE_REF, host_resource(), make_ancestors, |
| 69 GetDispatcher()->callback_tracker().SendCallback(callback))); |
103 return PP_OK_COMPLETIONPENDING; | 70 return PP_OK_COMPLETIONPENDING; |
104 } | 71 } |
105 | 72 |
106 int32_t FileRef::Touch(PP_Time last_access_time, | 73 int32_t FileRef::Touch(PP_Time last_access_time, |
107 PP_Time last_modified_time, | 74 PP_Time last_modified_time, |
108 PP_CompletionCallback callback) { | 75 PP_CompletionCallback callback) { |
109 int callback_id = SendCallback(callback); | |
110 if (!callback_id) | |
111 return PP_ERROR_BADARGUMENT; | |
112 | |
113 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( | 76 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( |
114 API_ID_PPB_FILE_REF, host_resource(), | 77 API_ID_PPB_FILE_REF, host_resource(), |
115 last_access_time, last_modified_time, callback_id)); | 78 last_access_time, last_modified_time, |
| 79 GetDispatcher()->callback_tracker().SendCallback(callback))); |
116 return PP_OK_COMPLETIONPENDING; | 80 return PP_OK_COMPLETIONPENDING; |
117 } | 81 } |
118 | 82 |
119 int32_t FileRef::Delete(PP_CompletionCallback callback) { | 83 int32_t FileRef::Delete(PP_CompletionCallback callback) { |
120 int callback_id = SendCallback(callback); | |
121 if (!callback_id) | |
122 return PP_ERROR_BADARGUMENT; | |
123 | |
124 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( | 84 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( |
125 API_ID_PPB_FILE_REF, host_resource(), callback_id)); | 85 API_ID_PPB_FILE_REF, host_resource(), |
| 86 GetDispatcher()->callback_tracker().SendCallback(callback))); |
126 return PP_OK_COMPLETIONPENDING; | 87 return PP_OK_COMPLETIONPENDING; |
127 } | 88 } |
128 | 89 |
129 int32_t FileRef::Rename(PP_Resource new_file_ref, | 90 int32_t FileRef::Rename(PP_Resource new_file_ref, |
130 PP_CompletionCallback callback) { | 91 PP_CompletionCallback callback) { |
131 int callback_id = SendCallback(callback); | |
132 if (!callback_id) | |
133 return PP_ERROR_BADARGUMENT; | |
134 | |
135 Resource* new_file_ref_object = | 92 Resource* new_file_ref_object = |
136 PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref); | 93 PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref); |
137 if (!new_file_ref_object || | 94 if (!new_file_ref_object || |
138 new_file_ref_object->host_resource().instance() != pp_instance()) | 95 new_file_ref_object->host_resource().instance() != pp_instance()) |
139 return PP_ERROR_BADRESOURCE; | 96 return PP_ERROR_BADRESOURCE; |
140 | 97 |
141 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( | 98 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( |
142 API_ID_PPB_FILE_REF, host_resource(), | 99 API_ID_PPB_FILE_REF, host_resource(), |
143 new_file_ref_object->host_resource(), callback_id)); | 100 new_file_ref_object->host_resource(), |
| 101 GetDispatcher()->callback_tracker().SendCallback(callback))); |
144 return PP_OK_COMPLETIONPENDING; | 102 return PP_OK_COMPLETIONPENDING; |
145 } | 103 } |
146 | 104 |
147 void FileRef::ExecuteCallback(int callback_id, int32_t result) { | |
148 PendingCallbackMap::iterator found = pending_callbacks_.find(callback_id); | |
149 if (found == pending_callbacks_.end()) { | |
150 // This will happen when the plugin deletes its resource with a pending | |
151 // callback. The callback will be locally issued with an ABORTED call while | |
152 // the operation may still be pending in the renderer. | |
153 return; | |
154 } | |
155 | |
156 // Executing the callback may mutate the callback list. | |
157 PP_CompletionCallback callback = found->second; | |
158 pending_callbacks_.erase(found); | |
159 PP_RunCompletionCallback(&callback, result); | |
160 } | |
161 | |
162 int FileRef::SendCallback(PP_CompletionCallback callback) { | |
163 if (!callback.func) | |
164 return 0; | |
165 | |
166 // In extreme cases the IDs may wrap around, so avoid duplicates. | |
167 while (pending_callbacks_.find(next_callback_id_) != pending_callbacks_.end()) | |
168 next_callback_id_++; | |
169 | |
170 pending_callbacks_[next_callback_id_] = callback; | |
171 return next_callback_id_++; | |
172 } | |
173 | |
174 PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher) | 105 PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher) |
175 : InterfaceProxy(dispatcher), | 106 : InterfaceProxy(dispatcher) { |
176 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
177 } | 107 } |
178 | 108 |
179 PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { | 109 PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { |
180 } | 110 } |
181 | 111 |
182 // static | 112 // static |
183 PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Resource file_system, | 113 PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Resource file_system, |
184 const char* path) { | 114 const char* path) { |
185 Resource* file_system_object = | 115 Resource* file_system_object = |
186 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_system); | 116 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_system); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 | 170 |
241 void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, | 171 void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, |
242 PPB_FileRef_CreateInfo* result) { | 172 PPB_FileRef_CreateInfo* result) { |
243 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); | 173 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); |
244 if (enter.succeeded()) | 174 if (enter.succeeded()) |
245 SerializeFileRef(enter.object()->GetParent(), result); | 175 SerializeFileRef(enter.object()->GetParent(), result); |
246 } | 176 } |
247 | 177 |
248 void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, | 178 void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, |
249 PP_Bool make_ancestors, | 179 PP_Bool make_ancestors, |
250 int callback_id) { | 180 uint32_t serialized_callback) { |
251 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( | 181 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); |
252 host_resource, callback_factory_, | 182 if (enter.failed()) |
253 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); | 183 return; |
254 if (enter.succeeded()) { | 184 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); |
255 enter.SetResult(enter.object()->MakeDirectory(make_ancestors, | 185 int32_t result = enter.object()->MakeDirectory(make_ancestors, callback); |
256 enter.callback())); | 186 if (result != PP_OK_COMPLETIONPENDING) |
257 } | 187 PP_RunCompletionCallback(&callback, result); |
258 } | 188 } |
259 | 189 |
260 void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, | 190 void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, |
261 PP_Time last_access, | 191 PP_Time last_access, |
262 PP_Time last_modified, | 192 PP_Time last_modified, |
263 int callback_id) { | 193 uint32_t serialized_callback) { |
264 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( | 194 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); |
265 host_resource, callback_factory_, | 195 if (enter.failed()) |
266 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); | 196 return; |
267 if (enter.succeeded()) { | 197 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); |
268 enter.SetResult(enter.object()->Touch(last_access, last_modified, | 198 int32_t result = enter.object()->Touch(last_access, last_modified, callback); |
269 enter.callback())); | 199 if (result != PP_OK_COMPLETIONPENDING) |
270 } | 200 PP_RunCompletionCallback(&callback, result); |
271 } | 201 } |
272 | 202 |
273 void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, | 203 void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, |
274 int callback_id) { | 204 uint32_t serialized_callback) { |
275 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( | 205 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); |
276 host_resource, callback_factory_, | 206 if (enter.failed()) |
277 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); | 207 return; |
278 if (enter.succeeded()) | 208 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); |
279 enter.SetResult(enter.object()->Delete(enter.callback())); | 209 int32_t result = enter.object()->Delete(callback); |
| 210 if (result != PP_OK_COMPLETIONPENDING) |
| 211 PP_RunCompletionCallback(&callback, result); |
280 } | 212 } |
281 | 213 |
282 void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, | 214 void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, |
283 const HostResource& new_file_ref, | 215 const HostResource& new_file_ref, |
284 int callback_id) { | 216 uint32_t serialized_callback) { |
285 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( | 217 EnterHostFromHostResource<PPB_FileRef_API> enter(file_ref); |
286 file_ref, callback_factory_, | 218 if (enter.failed()) |
287 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, file_ref, callback_id); | 219 return; |
288 if (enter.succeeded()) { | 220 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); |
289 enter.SetResult(enter.object()->Rename(new_file_ref.host_resource(), | 221 int32_t result = enter.object()->Rename(new_file_ref.host_resource(), |
290 enter.callback())); | 222 callback); |
291 } | 223 if (result != PP_OK_COMPLETIONPENDING) |
292 } | 224 PP_RunCompletionCallback(&callback, result); |
293 | |
294 void PPB_FileRef_Proxy::OnMsgCallbackComplete( | |
295 const HostResource& host_resource, | |
296 int callback_id, | |
297 int32_t result) { | |
298 // Forward the callback info to the plugin resource. | |
299 EnterPluginFromHostResource<PPB_FileRef_API> enter(host_resource); | |
300 if (enter.succeeded()) | |
301 static_cast<FileRef*>(enter.object())->ExecuteCallback(callback_id, result); | |
302 } | |
303 | |
304 void PPB_FileRef_Proxy::OnCallbackCompleteInHost( | |
305 int32_t result, | |
306 const HostResource& host_resource, | |
307 int callback_id) { | |
308 // Execute OnMsgCallbackComplete in the plugin process. | |
309 Send(new PpapiMsg_PPBFileRef_CallbackComplete( | |
310 API_ID_PPB_FILE_REF, host_resource, callback_id, result)); | |
311 } | 225 } |
312 | 226 |
313 } // namespace proxy | 227 } // namespace proxy |
314 } // namespace ppapi | 228 } // namespace ppapi |
OLD | NEW |