tizen beta release
[framework/web/webkit-efl.git] / Source / WebKit / chromium / src / WorkerFileSystemCallbacksBridge.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "WorkerFileSystemCallbacksBridge.h"
33
34 #if ENABLE(FILE_SYSTEM) && ENABLE(WORKERS)
35
36 #include "CrossThreadTask.h"
37 #include "KURL.h"
38 #include "WebCommonWorkerClient.h"
39 #include "WebFileInfo.h"
40 #include "WebFileSystemCallbacks.h"
41 #include "WebFileSystemEntry.h"
42 #include "WebString.h"
43 #include "WebURL.h"
44 #include "WebWorkerBase.h"
45 #include "WorkerContext.h"
46 #include "WorkerLoaderProxy.h"
47 #include "WorkerScriptController.h"
48 #include "WorkerThread.h"
49 #include <wtf/MainThread.h>
50 #include <wtf/Threading.h>
51 #include <wtf/UnusedParam.h>
52
53 namespace WebCore {
54
55 template<> struct CrossThreadCopierBase<false, false, WebKit::WebFileInfo> {
56     typedef WebKit::WebFileInfo Type;
57     static Type copy(const WebKit::WebFileInfo& info)
58     {
59         // Perform per-field copy to make sure we don't do any (unexpected) non-thread safe copy here.
60         struct WebKit::WebFileInfo newInfo;
61         newInfo.modificationTime = info.modificationTime;
62         newInfo.length = info.length;
63         newInfo.type = info.type;
64         newInfo.platformPath.assign(info.platformPath.data(), info.platformPath.length());
65         return newInfo;
66     }
67 };
68
69 template<> struct CrossThreadCopierBase<false, false, WebKit::WebVector<WebKit::WebFileSystemEntry> > {
70     typedef WebKit::WebVector<WebKit::WebFileSystemEntry> Type;
71     static Type copy(const WebKit::WebVector<WebKit::WebFileSystemEntry>& entries)
72     {
73         WebKit::WebVector<WebKit::WebFileSystemEntry> newEntries(entries.size());
74         for (size_t i = 0; i < entries.size(); ++i) {
75             String name = entries[i].name;
76             newEntries[i].isDirectory = entries[i].isDirectory;
77             newEntries[i].name = name.isolatedCopy();
78         }
79         return newEntries;
80     }
81 };
82
83 }
84
85 using namespace WebCore;
86
87 namespace WebKit {
88
89 // FileSystemCallbacks that are to be dispatched on the main thread.
90 class MainThreadFileSystemCallbacks : public WebFileSystemCallbacks {
91 public:
92     // Callbacks are self-destructed and we always return leaked pointer here.
93     static MainThreadFileSystemCallbacks* createLeakedPtr(WorkerFileSystemCallbacksBridge* bridge, const String& mode)
94     {
95         OwnPtr<MainThreadFileSystemCallbacks> callbacks = adoptPtr(new MainThreadFileSystemCallbacks(bridge, mode));
96         return callbacks.leakPtr();
97     }
98
99     virtual ~MainThreadFileSystemCallbacks()
100     {
101     }
102
103     virtual void didOpenFileSystem(const WebString& name, const WebURL& rootURL)
104     {
105         m_bridge->didOpenFileSystemOnMainThread(name, rootURL, m_mode);
106         delete this;
107     }
108
109     virtual void didFail(WebFileError error)
110     {
111         m_bridge->didFailOnMainThread(error, m_mode);
112         delete this;
113     }
114
115     virtual void didSucceed()
116     {
117         m_bridge->didSucceedOnMainThread(m_mode);
118         delete this;
119     }
120
121     virtual void didReadMetadata(const WebFileInfo& info)
122     {
123         m_bridge->didReadMetadataOnMainThread(info, m_mode);
124         delete this;
125     }
126
127     virtual void didReadDirectory(const WebVector<WebFileSystemEntry>& entries, bool hasMore)
128     {
129         m_bridge->didReadDirectoryOnMainThread(entries, hasMore, m_mode);
130         delete this;
131     }
132
133 private:
134     MainThreadFileSystemCallbacks(WorkerFileSystemCallbacksBridge* bridge, const String& mode)
135         : m_bridge(bridge)
136         , m_mode(mode)
137     {
138         ASSERT(m_bridge);
139     }
140
141     friend class WorkerFileSystemCallbacksBridge;
142     // The bridge pointer is kept by the bridge itself on the WorkerThread.
143     WorkerFileSystemCallbacksBridge* m_bridge;
144     const String m_mode;
145 };
146
147 void WorkerFileSystemCallbacksBridge::stop()
148 {
149     ASSERT(m_workerContext->isContextThread());
150     MutexLocker locker(m_mutex);
151     m_workerLoaderProxy = 0;
152
153     if (m_callbacksOnWorkerThread) {
154         m_callbacksOnWorkerThread->didFail(WebFileErrorAbort);
155         m_callbacksOnWorkerThread = 0;
156     }
157 }
158
159 void WorkerFileSystemCallbacksBridge::postOpenFileSystemToMainThread(NewWebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, const String& mode)
160 {
161     dispatchTaskToMainThread(
162         createCallbackTask(&openFileSystemOnMainThread,
163                            AllowCrossThreadAccess(commonClient), type, size, create,
164                            AllowCrossThreadAccess(this), mode));
165 }
166
167 void WorkerFileSystemCallbacksBridge::postMoveToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
168 {
169     dispatchTaskToMainThread(
170         createCallbackTask(&moveOnMainThread,
171                            AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
172                            AllowCrossThreadAccess(this), mode));
173 }
174
175 void WorkerFileSystemCallbacksBridge::postCopyToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
176 {
177     dispatchTaskToMainThread(
178         createCallbackTask(&copyOnMainThread,
179                            AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
180                            AllowCrossThreadAccess(this), mode));
181 }
182
183 void WorkerFileSystemCallbacksBridge::postRemoveToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
184 {
185     ASSERT(fileSystem);
186     dispatchTaskToMainThread(
187         createCallbackTask(&removeOnMainThread,
188                            AllowCrossThreadAccess(fileSystem), path,
189                            AllowCrossThreadAccess(this), mode));
190 }
191
192 void WorkerFileSystemCallbacksBridge::postRemoveRecursivelyToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
193 {
194     ASSERT(fileSystem);
195     dispatchTaskToMainThread(
196         createCallbackTask(&removeRecursivelyOnMainThread,
197                            AllowCrossThreadAccess(fileSystem), path,
198                            AllowCrossThreadAccess(this), mode));
199 }
200
201 void WorkerFileSystemCallbacksBridge::postReadMetadataToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
202 {
203     ASSERT(fileSystem);
204     dispatchTaskToMainThread(
205         createCallbackTask(&readMetadataOnMainThread,
206                            AllowCrossThreadAccess(fileSystem), path,
207                            AllowCrossThreadAccess(this), mode));
208 }
209
210 void WorkerFileSystemCallbacksBridge::postCreateFileToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
211 {
212     dispatchTaskToMainThread(
213         createCallbackTask(&createFileOnMainThread,
214                            AllowCrossThreadAccess(fileSystem), path, exclusive,
215                            AllowCrossThreadAccess(this), mode));
216 }
217
218 void WorkerFileSystemCallbacksBridge::postCreateDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
219 {
220     ASSERT(fileSystem);
221     dispatchTaskToMainThread(
222         createCallbackTask(&createDirectoryOnMainThread,
223                            AllowCrossThreadAccess(fileSystem), path, exclusive,
224                            AllowCrossThreadAccess(this), mode));
225 }
226
227 void WorkerFileSystemCallbacksBridge::postFileExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
228 {
229     ASSERT(fileSystem);
230     dispatchTaskToMainThread(
231         createCallbackTask(&fileExistsOnMainThread,
232                            AllowCrossThreadAccess(fileSystem), path,
233                            AllowCrossThreadAccess(this), mode));
234 }
235
236 void WorkerFileSystemCallbacksBridge::postDirectoryExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
237 {
238     ASSERT(fileSystem);
239     dispatchTaskToMainThread(
240         createCallbackTask(&directoryExistsOnMainThread,
241                            AllowCrossThreadAccess(fileSystem), path,
242                            AllowCrossThreadAccess(this), mode));
243 }
244
245 void WorkerFileSystemCallbacksBridge::postReadDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
246 {
247     ASSERT(fileSystem);
248     dispatchTaskToMainThread(
249         createCallbackTask(&readDirectoryOnMainThread,
250                            AllowCrossThreadAccess(fileSystem), path,
251                            AllowCrossThreadAccess(this), mode));
252 }
253
254 void WorkerFileSystemCallbacksBridge::openFileSystemOnMainThread(ScriptExecutionContext*, NewWebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
255 {
256     if (!commonClient)
257         bridge->didFailOnMainThread(WebFileErrorAbort, mode);
258     else {
259         commonClient->openFileSystem(type, size, create, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
260     }
261 }
262
263 void WorkerFileSystemCallbacksBridge::moveOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
264 {
265     fileSystem->move(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
266 }
267
268 void WorkerFileSystemCallbacksBridge::copyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
269 {
270     fileSystem->copy(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
271 }
272
273 void WorkerFileSystemCallbacksBridge::removeOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
274 {
275     fileSystem->remove(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
276 }
277
278 void WorkerFileSystemCallbacksBridge::removeRecursivelyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
279 {
280     fileSystem->removeRecursively(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
281 }
282
283 void WorkerFileSystemCallbacksBridge::readMetadataOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
284 {
285     fileSystem->readMetadata(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
286 }
287
288 void WorkerFileSystemCallbacksBridge::createFileOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
289 {
290     fileSystem->createFile(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
291 }
292
293 void WorkerFileSystemCallbacksBridge::createDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
294 {
295     fileSystem->createDirectory(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
296 }
297
298 void WorkerFileSystemCallbacksBridge::fileExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
299 {
300     fileSystem->fileExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
301 }
302
303 void WorkerFileSystemCallbacksBridge::directoryExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
304 {
305     fileSystem->directoryExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
306 }
307
308 void WorkerFileSystemCallbacksBridge::readDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
309 {
310     fileSystem->readDirectory(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
311 }
312
313 void WorkerFileSystemCallbacksBridge::didFailOnMainThread(WebFileError error, const String& mode)
314 {
315     mayPostTaskToWorker(createCallbackTask(&didFailOnWorkerThread, AllowCrossThreadAccess(this), error), mode);
316 }
317
318 void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnMainThread(const String& name, const KURL& rootURL, const String& mode)
319 {
320     mayPostTaskToWorker(createCallbackTask(&didOpenFileSystemOnWorkerThread,
321                                            AllowCrossThreadAccess(this), name, rootURL), mode);
322 }
323
324 void WorkerFileSystemCallbacksBridge::didSucceedOnMainThread(const String& mode)
325 {
326     mayPostTaskToWorker(createCallbackTask(&didSucceedOnWorkerThread, AllowCrossThreadAccess(this)), mode);
327 }
328
329 void WorkerFileSystemCallbacksBridge::didReadMetadataOnMainThread(const WebFileInfo& info, const String& mode)
330 {
331     mayPostTaskToWorker(createCallbackTask(&didReadMetadataOnWorkerThread, AllowCrossThreadAccess(this), info), mode);
332 }
333
334 void WorkerFileSystemCallbacksBridge::didReadDirectoryOnMainThread(const WebVector<WebFileSystemEntry>& entries, bool hasMore, const String& mode)
335 {
336     mayPostTaskToWorker(
337         createCallbackTask(&didReadDirectoryOnWorkerThread,
338                            AllowCrossThreadAccess(this), entries, hasMore), mode);
339 }
340
341 WorkerFileSystemCallbacksBridge::WorkerFileSystemCallbacksBridge(WebCore::WorkerLoaderProxy* workerLoaderProxy, ScriptExecutionContext* scriptExecutionContext, WebFileSystemCallbacks* callbacks)
342     : WorkerContext::Observer(static_cast<WorkerContext*>(scriptExecutionContext))
343     , m_workerLoaderProxy(workerLoaderProxy)
344     , m_workerContext(scriptExecutionContext)
345     , m_callbacksOnWorkerThread(callbacks)
346 {
347     ASSERT(m_workerContext->isContextThread());
348 }
349
350 WorkerFileSystemCallbacksBridge::~WorkerFileSystemCallbacksBridge()
351 {
352     ASSERT(!m_callbacksOnWorkerThread);
353 }
354
355 void WorkerFileSystemCallbacksBridge::didFailOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, WebFileError error)
356 {
357     bridge->m_callbacksOnWorkerThread->didFail(error);
358 }
359
360 void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const String& name, const KURL& rootURL)
361 {
362     bridge->m_callbacksOnWorkerThread->didOpenFileSystem(name, rootURL);
363 }
364
365 void WorkerFileSystemCallbacksBridge::didSucceedOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge)
366 {
367     bridge->m_callbacksOnWorkerThread->didSucceed();
368 }
369
370 void WorkerFileSystemCallbacksBridge::didReadMetadataOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const WebFileInfo& info)
371 {
372     bridge->m_callbacksOnWorkerThread->didReadMetadata(info);
373 }
374
375 void WorkerFileSystemCallbacksBridge::didReadDirectoryOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const WebVector<WebFileSystemEntry>& entries, bool hasMore)
376 {
377     bridge->m_callbacksOnWorkerThread->didReadDirectory(entries, hasMore);
378 }
379
380
381 void WorkerFileSystemCallbacksBridge::runTaskOnMainThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
382 {
383     ASSERT(isMainThread());
384
385     // Every task run will result in one call to mayPostTaskToWorker, which is where this ref is released.
386     WorkerFileSystemCallbacksBridge* leaked = bridge.leakRef();
387     UNUSED_PARAM(leaked);
388     taskToRun->performTask(scriptExecutionContext);
389 }
390
391 void WorkerFileSystemCallbacksBridge::runTaskOnWorkerThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
392 {
393     if (!bridge->m_callbacksOnWorkerThread)
394         return;
395     ASSERT(bridge->m_workerContext->isContextThread());
396     taskToRun->performTask(scriptExecutionContext);
397     bridge->m_callbacksOnWorkerThread = 0;
398     bridge->stopObserving();
399 }
400
401 void WorkerFileSystemCallbacksBridge::dispatchTaskToMainThread(PassOwnPtr<WebCore::ScriptExecutionContext::Task> task)
402 {
403     ASSERT(m_workerLoaderProxy);
404     ASSERT(m_workerContext->isContextThread());
405     WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&runTaskOnMainThread, RefPtr<WorkerFileSystemCallbacksBridge>(this).release(), task));
406 }
407
408 void WorkerFileSystemCallbacksBridge::mayPostTaskToWorker(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
409 {
410     ASSERT(isMainThread());
411
412     // Balancing out the ref() done in runTaskOnMainThread. (Since m_mutex is a member and the deref may result
413     // in the destruction of WorkerFileSystemCallbacksBridge, the ordering of the RefPtr and the MutexLocker
414     // is very important, to ensure that the m_mutex is still valid when it gets unlocked.)
415     RefPtr<WorkerFileSystemCallbacksBridge> bridge = adoptRef(this);
416     MutexLocker locker(m_mutex);
417     if (m_workerLoaderProxy)
418         m_workerLoaderProxy->postTaskForModeToWorkerContext(createCallbackTask(&runTaskOnWorkerThread, bridge, task), mode);
419 }
420
421 } // namespace WebCore
422
423 #endif // ENABLE(FILE_SYSTEM)