| 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 |