WorkerFileSystemCallbacksBridge.cpp [plain text]
#include "config.h"
#include "WorkerFileSystemCallbacksBridge.h"
#if ENABLE(FILE_SYSTEM) && ENABLE(WORKERS)
#include "CrossThreadTask.h"
#include "KURL.h"
#include "WebCommonWorkerClient.h"
#include "WebFileInfo.h"
#include "WebFileSystemCallbacks.h"
#include "WebFileSystemEntry.h"
#include "platform/WebString.h"
#include "platform/WebURL.h"
#include "WebWorkerBase.h"
#include "WorkerContext.h"
#include "WorkerLoaderProxy.h"
#include "WorkerScriptController.h"
#include "WorkerThread.h"
#include <wtf/MainThread.h>
#include <wtf/Threading.h>
#include <wtf/UnusedParam.h>
namespace WebCore {
template<> struct CrossThreadCopierBase<false, false, WebKit::WebFileInfo> {
typedef WebKit::WebFileInfo Type;
static Type copy(const WebKit::WebFileInfo& info)
{
struct WebKit::WebFileInfo newInfo;
newInfo.modificationTime = info.modificationTime;
newInfo.length = info.length;
newInfo.type = info.type;
newInfo.platformPath.assign(info.platformPath.data(), info.platformPath.length());
return newInfo;
}
};
template<> struct CrossThreadCopierBase<false, false, WebKit::WebVector<WebKit::WebFileSystemEntry> > {
typedef WebKit::WebVector<WebKit::WebFileSystemEntry> Type;
static Type copy(const WebKit::WebVector<WebKit::WebFileSystemEntry>& entries)
{
WebKit::WebVector<WebKit::WebFileSystemEntry> newEntries(entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
String name = entries[i].name;
newEntries[i].isDirectory = entries[i].isDirectory;
newEntries[i].name = name.isolatedCopy();
}
return newEntries;
}
};
}
using namespace WebCore;
namespace WebKit {
class MainThreadFileSystemCallbacks : public WebFileSystemCallbacks {
public:
static MainThreadFileSystemCallbacks* createLeakedPtr(PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
OwnPtr<MainThreadFileSystemCallbacks> callbacks = adoptPtr(new MainThreadFileSystemCallbacks(bridge, mode));
return callbacks.leakPtr();
}
virtual ~MainThreadFileSystemCallbacks()
{
}
virtual void didOpenFileSystem(const WebString& name, const WebURL& rootURL)
{
m_bridge->didOpenFileSystemOnMainThread(name, rootURL, m_mode);
delete this;
}
virtual void didFail(WebFileError error)
{
m_bridge->didFailOnMainThread(error, m_mode);
delete this;
}
virtual void didSucceed()
{
m_bridge->didSucceedOnMainThread(m_mode);
delete this;
}
virtual void didReadMetadata(const WebFileInfo& info)
{
m_bridge->didReadMetadataOnMainThread(info, m_mode);
delete this;
}
virtual void didReadDirectory(const WebVector<WebFileSystemEntry>& entries, bool hasMore)
{
m_bridge->didReadDirectoryOnMainThread(entries, hasMore, m_mode);
delete this;
}
private:
MainThreadFileSystemCallbacks(PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
: m_bridge(bridge)
, m_mode(mode)
{
ASSERT(m_bridge);
}
RefPtr<WorkerFileSystemCallbacksBridge> m_bridge;
const String m_mode;
};
class WorkerFileSystemContextObserver : public WebCore::WorkerContext::Observer {
public:
static PassOwnPtr<WorkerFileSystemContextObserver> create(WorkerContext* context, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge)
{
return adoptPtr(new WorkerFileSystemContextObserver(context, bridge));
}
virtual void notifyStop()
{
m_bridge->stop();
}
private:
WorkerFileSystemContextObserver(WorkerContext* context, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge)
: WebCore::WorkerContext::Observer(context)
, m_bridge(bridge)
{
}
RefPtr<WorkerFileSystemCallbacksBridge> m_bridge;
};
void WorkerFileSystemCallbacksBridge::stop()
{
ASSERT(m_workerContext->isContextThread());
{
MutexLocker locker(m_loaderProxyMutex);
m_workerLoaderProxy = 0;
}
if (m_callbacksOnWorkerThread)
m_callbacksOnWorkerThread->didFail(WebFileErrorAbort);
cleanUpAfterCallback();
}
void WorkerFileSystemCallbacksBridge::cleanUpAfterCallback()
{
ASSERT(m_workerContext->isContextThread());
m_callbacksOnWorkerThread = 0;
if (m_workerContextObserver) {
delete m_workerContextObserver;
m_workerContextObserver = 0;
}
}
void WorkerFileSystemCallbacksBridge::postOpenFileSystemToMainThread(WebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, const String& mode)
{
dispatchTaskToMainThread(
createCallbackTask(&openFileSystemOnMainThread,
AllowCrossThreadAccess(commonClient), type, size, create,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postMoveToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
{
dispatchTaskToMainThread(
createCallbackTask(&moveOnMainThread,
AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postCopyToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
{
dispatchTaskToMainThread(
createCallbackTask(©OnMainThread,
AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postRemoveToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&removeOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postRemoveRecursivelyToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&removeRecursivelyOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postReadMetadataToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&readMetadataOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postCreateFileToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
{
dispatchTaskToMainThread(
createCallbackTask(&createFileOnMainThread,
AllowCrossThreadAccess(fileSystem), path, exclusive,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postCreateDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&createDirectoryOnMainThread,
AllowCrossThreadAccess(fileSystem), path, exclusive,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postFileExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&fileExistsOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postDirectoryExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&directoryExistsOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postReadDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&readDirectoryOnMainThread,
AllowCrossThreadAccess(fileSystem), path,
this, mode));
}
void WorkerFileSystemCallbacksBridge::postCreateSnapshotFileToMainThread(WebFileSystem* fileSystem, const KURL& internalBlobURL, const KURL& path, const String& mode)
{
ASSERT(fileSystem);
dispatchTaskToMainThread(
createCallbackTask(&createSnapshotFileOnMainThread,
AllowCrossThreadAccess(fileSystem),
internalBlobURL, path, this, mode));
}
void WorkerFileSystemCallbacksBridge::openFileSystemOnMainThread(ScriptExecutionContext*, WebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
if (!commonClient)
bridge->didFailOnMainThread(WebFileErrorAbort, mode);
else {
commonClient->openFileSystem(type, size, create, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
}
void WorkerFileSystemCallbacksBridge::moveOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->move(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::copyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->copy(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::removeOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->remove(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::removeRecursivelyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->removeRecursively(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::readMetadataOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->readMetadata(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::createFileOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->createFile(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::createDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->createDirectory(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::fileExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->fileExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::directoryExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->directoryExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::readDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->readDirectory(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::createSnapshotFileOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& internalBlobURL, const KURL& path, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& mode)
{
fileSystem->createSnapshotFileAndReadMetadata(internalBlobURL, path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
}
void WorkerFileSystemCallbacksBridge::didFailOnMainThread(WebFileError error, const String& mode)
{
mayPostTaskToWorker(createCallbackTask(&didFailOnWorkerThread, this, error), mode);
}
void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnMainThread(const String& name, const KURL& rootURL, const String& mode)
{
mayPostTaskToWorker(createCallbackTask(&didOpenFileSystemOnWorkerThread,
this, name, rootURL), mode);
}
void WorkerFileSystemCallbacksBridge::didSucceedOnMainThread(const String& mode)
{
mayPostTaskToWorker(createCallbackTask(&didSucceedOnWorkerThread, this), mode);
}
void WorkerFileSystemCallbacksBridge::didReadMetadataOnMainThread(const WebFileInfo& info, const String& mode)
{
mayPostTaskToWorker(createCallbackTask(&didReadMetadataOnWorkerThread, this, info), mode);
}
void WorkerFileSystemCallbacksBridge::didReadDirectoryOnMainThread(const WebVector<WebFileSystemEntry>& entries, bool hasMore, const String& mode)
{
mayPostTaskToWorker(
createCallbackTask(&didReadDirectoryOnWorkerThread,
this, entries, hasMore), mode);
}
WorkerFileSystemCallbacksBridge::WorkerFileSystemCallbacksBridge(WebCore::WorkerLoaderProxy* workerLoaderProxy, ScriptExecutionContext* scriptExecutionContext, WebFileSystemCallbacks* callbacks)
: m_workerLoaderProxy(workerLoaderProxy)
, m_workerContext(scriptExecutionContext)
, m_workerContextObserver(WorkerFileSystemContextObserver::create(static_cast<WorkerContext*>(m_workerContext), this).leakPtr())
, m_callbacksOnWorkerThread(callbacks)
{
ASSERT(m_workerContext->isContextThread());
}
WorkerFileSystemCallbacksBridge::~WorkerFileSystemCallbacksBridge()
{
ASSERT(!m_callbacksOnWorkerThread);
}
void WorkerFileSystemCallbacksBridge::didFailOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, WebFileError error)
{
bridge->m_callbacksOnWorkerThread->didFail(error);
}
void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const String& name, const KURL& rootURL)
{
bridge->m_callbacksOnWorkerThread->didOpenFileSystem(name, rootURL);
}
void WorkerFileSystemCallbacksBridge::didSucceedOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge)
{
bridge->m_callbacksOnWorkerThread->didSucceed();
}
void WorkerFileSystemCallbacksBridge::didReadMetadataOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const WebFileInfo& info)
{
bridge->m_callbacksOnWorkerThread->didReadMetadata(info);
}
void WorkerFileSystemCallbacksBridge::didReadDirectoryOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, const WebVector<WebFileSystemEntry>& entries, bool hasMore)
{
bridge->m_callbacksOnWorkerThread->didReadDirectory(entries, hasMore);
}
void WorkerFileSystemCallbacksBridge::runTaskOnMainThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
{
ASSERT(isMainThread());
taskToRun->performTask(scriptExecutionContext);
}
void WorkerFileSystemCallbacksBridge::runTaskOnWorkerThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
{
if (!bridge->m_callbacksOnWorkerThread)
return;
ASSERT(bridge->m_workerContext->isContextThread());
taskToRun->performTask(scriptExecutionContext);
bridge->cleanUpAfterCallback();
}
void WorkerFileSystemCallbacksBridge::dispatchTaskToMainThread(PassOwnPtr<WebCore::ScriptExecutionContext::Task> task)
{
ASSERT(m_workerLoaderProxy);
ASSERT(m_workerContext->isContextThread());
WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&runTaskOnMainThread, RefPtr<WorkerFileSystemCallbacksBridge>(this).release(), task));
}
void WorkerFileSystemCallbacksBridge::mayPostTaskToWorker(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
{
ASSERT(isMainThread());
MutexLocker locker(m_loaderProxyMutex);
if (m_workerLoaderProxy)
m_workerLoaderProxy->postTaskForModeToWorkerContext(createCallbackTask(&runTaskOnWorkerThread, this, task), mode);
}
}
#endif // ENABLE(FILE_SYSTEM)