SimpleFileWriter for test_shell and DRT.

BUG=none
TEST=manual

Review URL: http://codereview.chromium.org/3683004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62486 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/webkit/tools/test_shell/simple_file_system.cc b/webkit/tools/test_shell/simple_file_system.cc
index 411d987d..ae77ce4 100644
--- a/webkit/tools/test_shell/simple_file_system.cc
+++ b/webkit/tools/test_shell/simple_file_system.cc
@@ -12,10 +12,13 @@
 #include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
 #include "webkit/fileapi/file_system_callback_dispatcher.h"
 #include "webkit/glue/webkit_glue.h"
+#include "webkit/tools/test_shell/simple_file_writer.h"
 
 using WebKit::WebFileInfo;
 using WebKit::WebFileSystemCallbacks;
 using WebKit::WebFileSystemEntry;
+using WebKit::WebFileWriter;
+using WebKit::WebFileWriterClient;
 using WebKit::WebString;
 using WebKit::WebVector;
 
@@ -61,7 +64,10 @@
 
   virtual void DidReadMetadata(const base::PlatformFileInfo& info) {
     WebFileInfo web_file_info;
+    web_file_info.length = info.size;
     web_file_info.modificationTime = info.last_modified.ToDoubleT();
+    web_file_info.type = info.is_directory ?
+        WebFileInfo::TypeDirectory : WebFileInfo::TypeFile;
     callbacks_->didReadMetadata(web_file_info);
     file_system_->RemoveCompletedOperation(request_id_);
   }
@@ -165,7 +171,7 @@
 }
 
 void SimpleFileSystem::fileExists(
-  const WebString& path, WebFileSystemCallbacks* callbacks) {
+    const WebString& path, WebFileSystemCallbacks* callbacks) {
   FilePath filepath(webkit_glue::WebStringToFilePath(path));
 
   GetNewOperation(callbacks)->FileExists(filepath);
@@ -185,6 +191,11 @@
   GetNewOperation(callbacks)->ReadDirectory(filepath);
 }
 
+WebFileWriter* SimpleFileSystem::createFileWriter(
+    const WebString& path, WebFileWriterClient* client) {
+  return new SimpleFileWriter(path, client);
+}
+
 fileapi::FileSystemOperation* SimpleFileSystem::GetNewOperation(
     WebFileSystemCallbacks* callbacks) {
   // This pointer will be owned by |operation|.
diff --git a/webkit/tools/test_shell/simple_file_system.h b/webkit/tools/test_shell/simple_file_system.h
index 031ed8b..e1a8236 100644
--- a/webkit/tools/test_shell/simple_file_system.h
+++ b/webkit/tools/test_shell/simple_file_system.h
@@ -44,6 +44,8 @@
                                WebKit::WebFileSystemCallbacks* callbacks);
   virtual void readDirectory(const WebKit::WebString& path,
                              WebKit::WebFileSystemCallbacks* callbacks);
+  virtual WebKit::WebFileWriter* createFileWriter(
+      const WebKit::WebString& path, WebKit::WebFileWriterClient* client);
 
  private:
   // Helpers.
diff --git a/webkit/tools/test_shell/simple_file_writer.cc b/webkit/tools/test_shell/simple_file_writer.cc
new file mode 100644
index 0000000..0c1a434
--- /dev/null
+++ b/webkit/tools/test_shell/simple_file_writer.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/tools/test_shell/simple_file_writer.h"
+
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "net/url_request/url_request_context.h"
+#include "webkit/fileapi/file_system_callback_dispatcher.h"
+#include "webkit/fileapi/file_system_operation.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
+
+using fileapi::FileSystemOperation;
+using fileapi::FileSystemCallbackDispatcher;
+using fileapi::WebFileWriterBase;
+using WebKit::WebFileWriterClient;
+using WebKit::WebString;
+using WebKit::WebURL;
+
+URLRequestContext* SimpleFileWriter::request_context_ = NULL;
+
+// Helper class to proxy to write and truncate calls to the IO thread,
+// and to proxy the results back to the main thead. There is a one-to-one
+// relationship between SimpleFileWriters and IOThreadBackends.
+class SimpleFileWriter::IOThreadProxy
+    : public base::RefCountedThreadSafe<SimpleFileWriter::IOThreadProxy> {
+ public:
+  explicit IOThreadProxy(const base::WeakPtr<SimpleFileWriter>& simple_writer)
+      : simple_writer_(simple_writer) {
+    // The IO thread needs to be running for this class to work.
+    SimpleResourceLoaderBridge::EnsureIOThread();
+    io_thread_ = SimpleResourceLoaderBridge::GetIoThread();
+    main_thread_ = base::MessageLoopProxy::CreateForCurrentThread();
+  }
+
+  virtual ~IOThreadProxy() {
+  }
+
+  void Truncate(const FilePath& path, int64 offset) {
+    if (!io_thread_->BelongsToCurrentThread()) {
+      io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::Truncate, path, offset));
+      return;
+    }
+    DCHECK(!operation_.get());
+    operation_.reset(GetNewOperation());
+    operation_->Truncate(path, offset);
+  }
+
+  void Write(const FilePath& path, const GURL& blob_url, int64 offset) {
+    if (!io_thread_->BelongsToCurrentThread()) {
+      io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::Write, path, blob_url, offset));
+      return;
+    }
+    DCHECK(request_context_);
+    DCHECK(!operation_.get());
+    operation_.reset(GetNewOperation());
+    operation_->Write(request_context_, path, blob_url, offset);
+  }
+
+  void Cancel() {
+    if (!io_thread_->BelongsToCurrentThread()) {
+      io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::Cancel));
+      return;
+    }
+    if (!operation_.get()) {
+      DidFail(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+      return;
+    }
+    cancel_operation_.reset(GetNewOperation());
+    operation_->Cancel(cancel_operation_.get());
+  }
+
+ private:
+  // Inner class to receive callbacks from FileSystemOperation.
+  class CallbackDispatcher : public FileSystemCallbackDispatcher {
+   public:
+    explicit CallbackDispatcher(IOThreadProxy* proxy) : proxy_(proxy) {
+    }
+
+    virtual void DidSucceed() {
+      proxy_->DidSucceed();
+    }
+
+    virtual void DidFail(base::PlatformFileError error_code) {
+      proxy_->DidFail(error_code);
+    }
+
+    virtual void DidWrite(int64 bytes, bool complete) {
+      proxy_->DidWrite(bytes, complete);
+    }
+
+    virtual void DidReadMetadata(const base::PlatformFileInfo&) {
+      NOTREACHED();
+    }
+
+    virtual void DidReadDirectory(
+        const std::vector<base::file_util_proxy::Entry>& entries,
+        bool has_more) {
+      NOTREACHED();
+    }
+
+    virtual void DidOpenFileSystem(const std::string& name,
+                                   const FilePath& root_path) {
+      NOTREACHED();
+    }
+
+    scoped_refptr<IOThreadProxy> proxy_;
+  };
+
+  FileSystemOperation* GetNewOperation() {
+    // The FileSystemOperation takes ownership of the CallbackDispatcher.
+    return new FileSystemOperation(new CallbackDispatcher(this), io_thread_);
+  }
+
+  void DidSucceed() {
+    if (!main_thread_->BelongsToCurrentThread()) {
+      operation_.reset();
+      main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::DidSucceed));
+      return;
+    }
+    if (simple_writer_)
+      simple_writer_->DidSucceed();
+  }
+
+  void DidFail(base::PlatformFileError error_code) {
+    if (!main_thread_->BelongsToCurrentThread()) {
+      operation_.reset();
+      main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::DidFail, error_code));
+      return;
+    }
+    if (simple_writer_)
+      simple_writer_->DidFail(error_code);
+  }
+
+  void DidWrite(int64 bytes, bool complete) {
+    if (!main_thread_->BelongsToCurrentThread()) {
+      if (complete)
+        operation_.reset();
+      main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+          this, &IOThreadProxy::DidWrite, bytes, complete));
+      return;
+    }
+    if (simple_writer_)
+      simple_writer_->DidWrite(bytes, complete);
+  }
+
+  scoped_refptr<base::MessageLoopProxy> io_thread_;
+  scoped_refptr<base::MessageLoopProxy> main_thread_;
+
+  // Only used on the main thread.
+  base::WeakPtr<SimpleFileWriter> simple_writer_;
+
+  // Only used on the io thread.
+  scoped_ptr<FileSystemOperation> operation_;
+  scoped_ptr<FileSystemOperation> cancel_operation_;
+};
+
+
+SimpleFileWriter::SimpleFileWriter(
+     const WebString& path, WebFileWriterClient* client)
+  : WebFileWriterBase(path, client),
+    io_thread_proxy_(new IOThreadProxy(AsWeakPtr())) {
+}
+
+SimpleFileWriter::~SimpleFileWriter() {
+}
+
+void SimpleFileWriter::DoTruncate(const FilePath& path, int64 offset) {
+  io_thread_proxy_->Truncate(path, offset);
+}
+
+void SimpleFileWriter::DoWrite(
+    const FilePath& path, const GURL& blob_url, int64 offset) {
+  io_thread_proxy_->Write(path, blob_url, offset);
+}
+
+void SimpleFileWriter::DoCancel() {
+  io_thread_proxy_->Cancel();
+}
diff --git a/webkit/tools/test_shell/simple_file_writer.h b/webkit/tools/test_shell/simple_file_writer.h
new file mode 100644
index 0000000..285fc02
--- /dev/null
+++ b/webkit/tools/test_shell/simple_file_writer.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_TOOLS_TEST_SHELL_SIMPLE_FILE_WRITER_H_
+#define WEBKIT_TOOLS_TEST_SHELL_SIMPLE_FILE_WRITER_H_
+
+#include "base/ref_counted.h"
+#include "base/weak_ptr.h"
+#include "webkit/fileapi/webfilewriter_base.h"
+
+class URLRequestContext;
+
+
+// An implementation of WebFileWriter for use in test_shell and DRT.
+class SimpleFileWriter : public fileapi::WebFileWriterBase,
+                         public base::SupportsWeakPtr<SimpleFileWriter> {
+ public:
+  SimpleFileWriter(
+      const WebKit::WebString& path, WebKit::WebFileWriterClient* client);
+  virtual ~SimpleFileWriter();
+
+  // Called by SimpleResourceLoaderBridge when the context is
+  // created and destroyed.
+  static void InitializeOnIOThread(URLRequestContext* request_context) {
+    request_context_ = request_context;
+  }
+  static void CleanupOnIOThread() {
+    request_context_ = NULL;
+  }
+
+ protected:
+  // WebFileWriterBase overrides
+  virtual void DoTruncate(const FilePath& path, int64 offset);
+  virtual void DoWrite(const FilePath& path, const GURL& blob_url,
+                       int64 offset);
+  virtual void DoCancel();
+
+ private:
+  class IOThreadProxy;
+  scoped_refptr<IOThreadProxy> io_thread_proxy_;
+  static URLRequestContext* request_context_;
+};
+
+#endif  // WEBKIT_TOOLS_TEST_SHELL_SIMPLE_FILE_WRITER_H_
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index a4ef5e7..954b258 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -68,6 +68,7 @@
 #include "webkit/blob/deletable_file_reference.h"
 #include "webkit/glue/resource_loader_bridge.h"
 #include "webkit/tools/test_shell/simple_appcache_system.h"
+#include "webkit/tools/test_shell/simple_file_writer.h"
 #include "webkit/tools/test_shell/simple_socket_stream_bridge.h"
 #include "webkit/tools/test_shell/test_shell_request_context.h"
 #include "webkit/tools/test_shell/test_shell_webblobregistry_impl.h"
@@ -142,6 +143,7 @@
 
     SimpleAppCacheSystem::InitializeOnIOThread(g_request_context);
     SimpleSocketStreamBridge::InitializeOnIOThread(g_request_context);
+    SimpleFileWriter::InitializeOnIOThread(g_request_context);
 
     TestShellWebBlobRegistryImpl::InitializeOnIOThread(
         static_cast<TestShellRequestContext*>(g_request_context)->
@@ -152,6 +154,7 @@
   virtual void CleanUp() {
     SimpleSocketStreamBridge::Cleanup();
     TestShellWebBlobRegistryImpl::Cleanup();
+    SimpleFileWriter::CleanupOnIOThread();
     if (g_request_context) {
       g_request_context->Release();
       g_request_context = NULL;
diff --git a/webkit/tools/test_shell/test_webview_delegate.cc b/webkit/tools/test_shell/test_webview_delegate.cc
index 41bf9d3c..5727cab 100644
--- a/webkit/tools/test_shell/test_webview_delegate.cc
+++ b/webkit/tools/test_shell/test_webview_delegate.cc
@@ -1126,6 +1126,7 @@
     // The FileSystem temp directory was not initialized successfully.
     callbacks->didFail(WebKit::WebFileErrorSecurity);
   } else {
+    // TODO(michaeln): need to put origin/type in the path.
     callbacks->didOpenFileSystem(
         "TestShellFileSystem",
         webkit_glue::FilePathToWebString(shell_->file_system_root()));