Bug 1029209 - Extract IndexedDB FileHandle from core FileHandle implementation (WebIDL changes: merge MutableFile into IDBMutableFile, rename FileHandle to IDBFileHandle, DOMFileMetadataParameters to IDBFileMetadataParameters and FileRequest to IDBFileRequest); r=bent
authorJan Varga <jan.varga@gmail.com>
Thu, 17 Jul 2014 12:40:54 -0400
changeset 215532 027f3828d0ab77915c613653f077ed83371538f9
parent 215531 b10531b4a946a5f7e8000da44c046e02e2b0dcac
child 215533 9d72b50b8460d0bdb0cf135aea364b0635d31e51
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs1029209
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1029209 - Extract IndexedDB FileHandle from core FileHandle implementation (WebIDL changes: merge MutableFile into IDBMutableFile, rename FileHandle to IDBFileHandle, DOMFileMetadataParameters to IDBFileMetadataParameters and FileRequest to IDBFileRequest); r=bent
dom/base/nsDOMWindowUtils.cpp
dom/bindings/Bindings.conf
dom/filehandle/File.cpp
dom/filehandle/File.h
dom/filehandle/FileHandle.cpp
dom/filehandle/FileHandle.h
dom/filehandle/FileHelper.cpp
dom/filehandle/FileHelper.h
dom/filehandle/FileRequest.cpp
dom/filehandle/FileRequest.h
dom/filehandle/FileService.cpp
dom/filehandle/FileService.h
dom/filehandle/MetadataHelper.h
dom/filehandle/MutableFile.cpp
dom/filehandle/MutableFile.h
dom/filehandle/moz.build
dom/filehandle/test/dummy_worker.js
dom/filehandle/test/helpers.js
dom/filehandle/test/mochitest.ini
dom/filehandle/test/moz.build
dom/filehandle/test/test_append_read_data.html
dom/filehandle/test/test_compat.html
dom/filehandle/test/test_filehandle_lifetimes.html
dom/filehandle/test/test_filehandle_lifetimes_nested.html
dom/filehandle/test/test_filehandle_ordering.html
dom/filehandle/test/test_getFile.html
dom/filehandle/test/test_getFileId.html
dom/filehandle/test/test_location.html
dom/filehandle/test/test_overlapping_filehandles.html
dom/filehandle/test/test_progress_events.html
dom/filehandle/test/test_readonly_filehandles.html
dom/filehandle/test/test_request_readyState.html
dom/filehandle/test/test_stream_tracking.html
dom/filehandle/test/test_success_events_after_abort.html
dom/filehandle/test/test_truncate.html
dom/filehandle/test/test_workers.html
dom/filehandle/test/test_write_read_data.html
dom/indexedDB/FileSnapshot.cpp
dom/indexedDB/FileSnapshot.h
dom/indexedDB/IDBFileHandle.cpp
dom/indexedDB/IDBFileHandle.h
dom/indexedDB/IDBFileRequest.cpp
dom/indexedDB/IDBFileRequest.h
dom/indexedDB/IDBMutableFile.cpp
dom/indexedDB/IDBMutableFile.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/moz.build
dom/indexedDB/test/dummy_worker.js
dom/indexedDB/test/file.js
dom/indexedDB/test/mochitest.ini
dom/indexedDB/test/test_filehandle_append_read_data.html
dom/indexedDB/test/test_filehandle_compat.html
dom/indexedDB/test/test_filehandle_getFile.html
dom/indexedDB/test/test_filehandle_lifetimes.html
dom/indexedDB/test/test_filehandle_lifetimes_nested.html
dom/indexedDB/test/test_filehandle_location.html
dom/indexedDB/test/test_filehandle_ordering.html
dom/indexedDB/test/test_filehandle_overlapping.html
dom/indexedDB/test/test_filehandle_progress_events.html
dom/indexedDB/test/test_filehandle_readonly_exceptions.html
dom/indexedDB/test/test_filehandle_request_readyState.html
dom/indexedDB/test/test_filehandle_stream_tracking.html
dom/indexedDB/test/test_filehandle_success_events_after_abort.html
dom/indexedDB/test/test_filehandle_truncate.html
dom/indexedDB/test/test_filehandle_workers.html
dom/indexedDB/test/test_filehandle_write_read_data.html
dom/indexedDB/test/test_getFileId.html
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/FileHandle.webidl
dom/webidl/FileRequest.webidl
dom/webidl/IDBFileHandle.webidl
dom/webidl/IDBFileRequest.webidl
dom/webidl/IDBMutableFile.webidl
dom/webidl/MutableFile.webidl
dom/webidl/moz.build
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -63,19 +63,19 @@
 #endif
 
 #include "Layers.h"
 #include "mozilla/layers/ShadowLayers.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
+#include "mozilla/dom/IDBMutableFileBinding.h"
+#include "mozilla/dom/indexedDB/IDBMutableFile.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
-#include "mozilla/dom/MutableFile.h"
-#include "mozilla/dom/MutableFileBinding.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/quota/PersistenceType.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsPrintfCString.h"
 #include "nsViewportInfo.h"
 #include "nsIFormControl.h"
 #include "nsIScriptError.h"
@@ -3025,18 +3025,18 @@ NS_IMETHODIMP
 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
                             int64_t* aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (!aFile.isPrimitive()) {
     JSObject* obj = aFile.toObjectOrNull();
 
-    MutableFile* mutableFile = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(MutableFile, obj, mutableFile))) {
+    indexedDB::IDBMutableFile* mutableFile = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, obj, mutableFile))) {
       *aResult = mutableFile->GetFileId();
       return NS_OK;
     }
 
     nsISupports* nativeObj =
       nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
 
     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(nativeObj);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -441,40 +441,32 @@ DOMInterfaces = {
 
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
 },
 
-'FileHandle': {
-    'nativeType': 'mozilla::dom::FileHandle',
-},
-
 'FileList': {
     'nativeType': 'nsDOMFileList',
     'headerFile': 'nsDOMFile.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'FileReader': {
     'nativeType': 'nsDOMFileReader',
     'implicitJSContext': [ 'readAsArrayBuffer' ],
 },
 
 'FileReaderSync': {
     'workers': True,
     'wrapperCache': False,
 },
 
-'FileRequest': {
-    'nativeType': 'mozilla::dom::FileRequest',
-},
-
 'FormData': [
 {
     'nativeType': 'nsFormData'
 },
 {
     'workers': True,
     'skipGen': True,
     'nativeType': 'JSObject'
@@ -651,16 +643,24 @@ DOMInterfaces = {
 'IDBDatabase': {
     'nativeType': 'mozilla::dom::indexedDB::IDBDatabase',
 },
 
 'IDBFactory': {
     'nativeType': 'mozilla::dom::indexedDB::IDBFactory',
 },
 
+'IDBFileHandle': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBFileHandle',
+},
+
+'IDBFileRequest': {
+    'nativeType': 'mozilla::dom::indexedDB::IDBFileRequest',
+},
+
 'IDBIndex': {
     'nativeType': 'mozilla::dom::indexedDB::IDBIndex',
     'binaryNames': {
         'mozGetAll': 'getAll',
         'mozGetAllKeys': 'getAllKeys',
     }
 },
 
@@ -884,20 +884,16 @@ DOMInterfaces = {
 'MozTimeManager': {
     'nativeType': 'mozilla::dom::time::TimeManager',
 },
 
 'MozVoicemail': {
     'nativeType': 'mozilla::dom::Voicemail',
 },
 
-'MutableFile': {
-    'nativeType': 'mozilla::dom::MutableFile'
-},
-
 'MutationObserver': {
     'nativeType': 'nsDOMMutationObserver',
 },
 
 'MutationRecord': {
     'nativeType': 'nsDOMMutationRecord',
     'headerFile': 'nsDOMMutationObserver.h',
     'resultNotAddRefed': [ 'target', 'addedNodes', 'removedNodes',
--- a/dom/filehandle/FileHandle.cpp
+++ b/dom/filehandle/FileHandle.cpp
@@ -7,50 +7,42 @@
 #include "FileHandle.h"
 
 #include "AsyncHelper.h"
 #include "FileHelper.h"
 #include "FileRequest.h"
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
-#include "MetadataHelper.h"
 #include "mozilla/dom/EncodingUtils.h"
-#include "mozilla/dom/FileHandleBinding.h"
-#include "mozilla/EventDispatcher.h"
 #include "MutableFile.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
-#include "nsIAppShell.h"
-#include "nsIDOMEvent.h"
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsISeekableStream.h"
 #include "nsNetUtil.h"
-#include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
-#include "nsWidgetsCID.h"
+#include "xpcpublic.h"
 
 #define STREAM_COPY_BLOCK_SIZE 32768
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
-NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
-
 class ReadHelper : public FileHelper
 {
 public:
-  ReadHelper(FileHandle* aFileHandle,
-             FileRequest* aFileRequest,
+  ReadHelper(FileHandleBase* aFileHandle,
+             FileRequestBase* aFileRequest,
              uint64_t aLocation,
              uint64_t aSize)
   : FileHelper(aFileHandle, aFileRequest),
     mLocation(aLocation), mSize(aSize)
   {
     MOZ_ASSERT(mSize, "Passed zero size!");
   }
 
@@ -69,18 +61,18 @@ protected:
   uint64_t mSize;
 
   nsRefPtr<MemoryOutputStream> mStream;
 };
 
 class ReadTextHelper : public ReadHelper
 {
 public:
-  ReadTextHelper(FileHandle* aFileHandle,
-                 FileRequest* aFileRequest,
+  ReadTextHelper(FileHandleBase* aFileHandle,
+                 FileRequestBase* aFileRequest,
                  uint64_t aLocation,
                  uint64_t aSize,
                  const nsAString& aEncoding)
   : ReadHelper(aFileHandle, aFileRequest, aLocation, aSize),
     mEncoding(aEncoding)
   { }
 
   nsresult
@@ -89,18 +81,18 @@ public:
 
 private:
   nsString mEncoding;
 };
 
 class WriteHelper : public FileHelper
 {
 public:
-  WriteHelper(FileHandle* aFileHandle,
-              FileRequest* aFileRequest,
+  WriteHelper(FileHandleBase* aFileHandle,
+              FileRequestBase* aFileRequest,
               uint64_t aLocation,
               nsIInputStream* aStream,
               uint64_t aLength)
   : FileHelper(aFileHandle, aFileRequest),
     mLocation(aLocation), mStream(aStream), mLength(aLength)
   {
     MOZ_ASSERT(mLength, "Passed zero length!");
   }
@@ -112,18 +104,18 @@ private:
   uint64_t mLocation;
   nsCOMPtr<nsIInputStream> mStream;
   uint64_t mLength;
 };
 
 class TruncateHelper : public FileHelper
 {
 public:
-  TruncateHelper(FileHandle* aFileHandle,
-                 FileRequest* aFileRequest,
+  TruncateHelper(FileHandleBase* aFileHandle,
+                 FileRequestBase* aFileRequest,
                  uint64_t aOffset)
   : FileHelper(aFileHandle, aFileRequest),
     mOffset(aOffset)
   { }
 
   nsresult
   DoAsyncRun(nsISupports* aStream);
 
@@ -143,18 +135,18 @@ private:
   };
 
   uint64_t mOffset;
 };
 
 class FlushHelper : public FileHelper
 {
 public:
-  FlushHelper(FileHandle* aFileHandle,
-              FileRequest* aFileRequest)
+  FlushHelper(FileHandleBase* aFileHandle,
+              FileRequestBase* aFileRequest)
   : FileHelper(aFileHandle, aFileRequest)
   { }
 
   nsresult
   DoAsyncRun(nsISupports* aStream);
 
 private:
   class AsyncFlusher : public AsyncHelper
@@ -167,17 +159,17 @@ private:
     nsresult
     DoStreamWork(nsISupports* aStream) MOZ_OVERRIDE;
   };
 };
 
 class OpenStreamHelper : public FileHelper
 {
 public:
-  OpenStreamHelper(FileHandle* aFileHandle,
+  OpenStreamHelper(FileHandleBase* aFileHandle,
                    bool aWholeFile,
                    uint64_t aStart,
                    uint64_t aLength)
   : FileHelper(aFileHandle, nullptr),
     mWholeFile(aWholeFile), mStart(aStart), mLength(aLength)
   { }
 
   nsresult
@@ -192,180 +184,108 @@ public:
 private:
   bool mWholeFile;
   uint64_t mStart;
   uint64_t mLength;
 
   nsCOMPtr<nsIInputStream> mStream;
 };
 
-already_AddRefed<nsIDOMEvent>
-CreateGenericEvent(EventTarget* aEventOwner,
-                   const nsAString& aType, bool aBubbles, bool aCancelable)
-{
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMEvent(getter_AddRefs(event), aEventOwner, nullptr, nullptr);
-  nsresult rv = event->InitEvent(aType, aBubbles, aCancelable);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  event->SetTrusted(true);
-
-  return event.forget();
-}
-
 } // anonymous namespace
 
-// static
-already_AddRefed<FileHandle>
-FileHandle::Create(MutableFile* aMutableFile,
-                   FileMode aMode,
-                   RequestMode aRequestMode)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  nsRefPtr<FileHandle> fileHandle = new FileHandle();
-
-  fileHandle->BindToOwner(aMutableFile);
-
-  fileHandle->mMutableFile = aMutableFile;
-  fileHandle->mMode = aMode;
-  fileHandle->mRequestMode = aRequestMode;
-
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  NS_ENSURE_TRUE(appShell, nullptr);
-
-  nsresult rv = appShell->RunBeforeNextEvent(fileHandle);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  fileHandle->mCreating = true;
-
-  FileService* service = FileService::GetOrCreate();
-  NS_ENSURE_TRUE(service, nullptr);
-
-  rv = service->Enqueue(fileHandle, nullptr);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  return fileHandle.forget();
-}
-
-FileHandle::FileHandle()
+FileHandleBase::FileHandleBase(FileMode aMode,
+                               RequestMode aRequestMode)
 : mReadyState(INITIAL),
-  mMode(FileMode::Readonly),
-  mRequestMode(NORMAL),
+  mMode(aMode),
+  mRequestMode(aRequestMode),
   mLocation(0),
   mPendingRequests(0),
   mAborted(false),
   mCreating(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-  SetIsDOMBinding();
 }
 
-FileHandle::~FileHandle()
+FileHandleBase::~FileHandleBase()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(FileHandle, DOMEventTargetHelper,
-                                   mMutableFile)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileHandle)
-  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-NS_IMPL_ADDREF_INHERITED(FileHandle, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(FileHandle, DOMEventTargetHelper)
-
-nsresult
-FileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mMutableFile;
-  return NS_OK;
-}
-
 void
-FileHandle::OnNewRequest()
+FileHandleBase::OnNewRequest()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   if (!mPendingRequests) {
     MOZ_ASSERT(mReadyState == INITIAL, "Reusing a file handle!");
     mReadyState = LOADING;
   }
   ++mPendingRequests;
 }
 
 void
-FileHandle::OnRequestFinished()
+FileHandleBase::OnRequestFinished()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(mPendingRequests, "Mismatched calls!");
   --mPendingRequests;
   if (!mPendingRequests) {
     MOZ_ASSERT(mAborted || mReadyState == LOADING, "Bad state!");
-    mReadyState = FileHandle::FINISHING;
+    mReadyState = FileHandleBase::FINISHING;
     Finish();
   }
 }
 
 nsresult
-FileHandle::CreateParallelStream(nsISupports** aStream)
+FileHandleBase::CreateParallelStream(nsISupports** aStream)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
-  if (mMutableFile->IsInvalid()) {
+  MutableFileBase* mutableFile = MutableFile();
+
+  if (mutableFile->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsCOMPtr<nsISupports> stream =
-    mMutableFile->CreateStream(mMutableFile->mFile,
-                               mMode == FileMode::Readonly);
+    mutableFile->CreateStream(mMode == FileMode::Readonly);
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
   mParallelStreams.AppendElement(stream);
 
   stream.forget(aStream);
   return NS_OK;
 }
 
 nsresult
-FileHandle::GetOrCreateStream(nsISupports** aStream)
+FileHandleBase::GetOrCreateStream(nsISupports** aStream)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
-  if (mMutableFile->IsInvalid()) {
+  MutableFileBase* mutableFile = MutableFile();
+
+  if (mutableFile->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mStream) {
     nsCOMPtr<nsISupports> stream =
-      mMutableFile->CreateStream(mMutableFile->mFile,
-                                 mMode == FileMode::Readonly);
+      mutableFile->CreateStream(mMode == FileMode::Readonly);
     NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
     stream.swap(mStream);
   }
 
   nsCOMPtr<nsISupports> stream(mStream);
   stream.forget(aStream);
 
   return NS_OK;
 }
 
-already_AddRefed<FileRequest>
-FileHandle::GenerateFileRequest()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-  return FileRequest::Create(GetOwner(), this, /* aWrapAsDOMRequest */ false);
-}
-
 bool
-FileHandle::IsOpen() const
+FileHandleBase::IsOpen() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // If we haven't started anything then we're open.
   if (mReadyState == INITIAL) {
     MOZ_ASSERT(FileHelper::GetCurrentFileHandle() != this,
                "This should be some other file handle (or null)!");
     return true;
@@ -384,124 +304,54 @@ FileHandle::IsOpen() const
     if (FileHelper::GetCurrentFileHandle() == this) {
       return true;
     }
   }
 
   return false;
 }
 
-// virtual
-JSObject*
-FileHandle::WrapObject(JSContext* aCx)
-{
-  return FileHandleBinding::Wrap(aCx, this);
-}
-
-already_AddRefed<FileRequest>
-FileHandle::GetMetadata(const DOMFileMetadataParameters& aParameters,
-                        ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  // Common state checking
-  if (!CheckState(aRv)) {
-    return nullptr;
-  }
-
-  // Do nothing if the window is closed
-  if (!GetOwner()) {
-    return nullptr;
-  }
-
-  nsRefPtr<MetadataParameters> params =
-    new MetadataParameters(aParameters.mSize, aParameters.mLastModified);
-  if (!params->IsConfigured()) {
-    aRv.ThrowTypeError(MSG_METADATA_NOT_CONFIGURED);
-    return nullptr;
-  }
-
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
-
-  nsRefPtr<MetadataHelper> helper =
-    new MetadataHelper(this, fileRequest, params);
-
-  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  return fileRequest.forget();
-}
-
-already_AddRefed<FileRequest>
-FileHandle::ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv)
+already_AddRefed<FileRequestBase>
+FileHandleBase::Read(uint64_t aSize, bool aHasEncoding,
+                     const nsAString& aEncoding, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // State and argument checking for read
   if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
     return nullptr;
   }
 
   // Do nothing if the window is closed
-  if (!GetOwner()) {
+  if (!CheckWindow()) {
     return nullptr;
   }
 
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
 
-  nsRefPtr<ReadHelper> helper =
-    new ReadHelper(this, fileRequest, mLocation, aSize);
+  nsRefPtr<ReadHelper> helper;
+  if (aHasEncoding) {
+    helper = new ReadTextHelper(this, fileRequest, mLocation, aSize, aEncoding);
+  } else {
+    helper = new ReadHelper(this, fileRequest, mLocation, aSize);
+  }
 
   if (NS_WARN_IF(NS_FAILED(helper->Init())) ||
       NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   mLocation += aSize;
 
   return fileRequest.forget();
 }
 
-already_AddRefed<FileRequest>
-FileHandle::ReadAsText(uint64_t aSize, const nsAString& aEncoding,
-                       ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  // State and argument checking for read
-  if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
-    return nullptr;
-  }
-
-  // Do nothing if the window is closed
-  if (!GetOwner()) {
-    return nullptr;
-  }
-
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
-
-  nsRefPtr<ReadTextHelper> helper =
-    new ReadTextHelper(this, fileRequest, mLocation, aSize, aEncoding);
-
-  if (NS_WARN_IF(NS_FAILED(helper->Init())) ||
-      NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  mLocation += aSize;
-
-  return fileRequest.forget();
-}
-
-already_AddRefed<FileRequest>
-FileHandle::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
+already_AddRefed<FileRequestBase>
+FileHandleBase::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // State checking for write
   if (!CheckStateForWrite(aRv)) {
     return nullptr;
   }
 
@@ -515,127 +365,125 @@ FileHandle::Truncate(const Optional<uint
     if (mLocation == UINT64_MAX) {
       aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
       return nullptr;
     }
     location = mLocation;
   }
 
   // Do nothing if the window is closed
-  if (!GetOwner()) {
+  if (!CheckWindow()) {
     return nullptr;
   }
 
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
 
   nsRefPtr<TruncateHelper> helper =
     new TruncateHelper(this, fileRequest, location);
 
   if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (aSize.WasPassed()) {
     mLocation = aSize.Value();
   }
 
   return fileRequest.forget();
 }
 
-already_AddRefed<FileRequest>
-FileHandle::Flush(ErrorResult& aRv)
+already_AddRefed<FileRequestBase>
+FileHandleBase::Flush(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // State checking for write
   if (!CheckStateForWrite(aRv)) {
     return nullptr;
   }
 
   // Do nothing if the window is closed
-  if (!GetOwner()) {
+  if (!CheckWindow()) {
     return nullptr;
   }
 
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
 
   nsRefPtr<FlushHelper> helper = new FlushHelper(this, fileRequest);
 
   if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   return fileRequest.forget();
 }
 
 void
-FileHandle::Abort(ErrorResult& aRv)
+FileHandleBase::Abort(ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // This method is special enough for not using generic state checking methods.
 
   // We can't use IsOpen here since we need it to be possible to call Abort()
   // even from outside of transaction callbacks.
-  if (mReadyState != FileHandle::INITIAL &&
-      mReadyState != FileHandle::LOADING) {
+  if (mReadyState != FileHandleBase::INITIAL &&
+      mReadyState != FileHandleBase::LOADING) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
     return;
   }
 
   bool needToFinish = mReadyState == INITIAL;
 
   mAborted = true;
   mReadyState = DONE;
 
   // Fire the abort event if there are no outstanding requests. Otherwise the
   // abort event will be fired when all outstanding requests finish.
   if (needToFinish) {
     aRv = Finish();
   }
 }
 
-NS_IMETHODIMP
-FileHandle::Run()
+void
+FileHandleBase::OnReturnToEventLoop()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   // We're back at the event loop, no longer newborn.
   mCreating = false;
 
   // Maybe set the readyState to DONE if there were no requests generated.
   if (mReadyState == INITIAL) {
     mReadyState = DONE;
 
     if (NS_FAILED(Finish())) {
       NS_WARNING("Failed to finish!");
     }
   }
-
-  return NS_OK;
 }
 
 nsresult
-FileHandle::OpenInputStream(bool aWholeFile, uint64_t aStart, uint64_t aLength,
-                            nsIInputStream** aResult)
+FileHandleBase::OpenInputStream(bool aWholeFile, uint64_t aStart,
+                                uint64_t aLength, nsIInputStream** aResult)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(mRequestMode == PARALLEL,
              "Don't call me in other than parallel mode!");
 
   // Common state checking
   ErrorResult error;
   if (!CheckState(error)) {
     return error.ErrorCode();
   }
 
   // Do nothing if the window is closed
-  if (!GetOwner()) {
+  if (!CheckWindow()) {
     return NS_OK;
   }
 
   nsRefPtr<OpenStreamHelper> helper =
     new OpenStreamHelper(this, aWholeFile, aStart, aLength);
 
   nsresult rv = helper->Enqueue();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
@@ -643,28 +491,28 @@ FileHandle::OpenInputStream(bool aWholeF
   nsCOMPtr<nsIInputStream>& result = helper->Result();
   NS_ENSURE_TRUE(result, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   result.forget(aResult);
   return NS_OK;
 }
 
 bool
-FileHandle::CheckState(ErrorResult& aRv)
+FileHandleBase::CheckState(ErrorResult& aRv)
 {
   if (!IsOpen()) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
     return false;
   }
 
   return true;
 }
 
 bool
-FileHandle::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
+FileHandleBase::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
 {
   // Common state checking
   if (!CheckState(aRv)) {
     return false;
   }
 
   // Additional state checking for read
   if (mLocation == UINT64_MAX) {
@@ -677,46 +525,47 @@ FileHandle::CheckStateAndArgumentsForRea
     aRv.ThrowTypeError(MSG_INVALID_READ_SIZE);
     return false;
   }
 
   return true;
 }
 
 bool
-FileHandle::CheckStateForWrite(ErrorResult& aRv)
+FileHandleBase::CheckStateForWrite(ErrorResult& aRv)
 {
   // Common state checking
   if (!CheckState(aRv)) {
     return false;
   }
 
   // Additional state checking for write
   if (mMode != FileMode::Readwrite) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
     return false;
   }
 
   return true;
 }
 
-already_AddRefed<FileRequest>
-FileHandle::WriteInternal(nsIInputStream* aInputStream, uint64_t aInputLength,
-                          bool aAppend, ErrorResult& aRv)
+already_AddRefed<FileRequestBase>
+FileHandleBase::WriteInternal(nsIInputStream* aInputStream,
+                              uint64_t aInputLength, bool aAppend,
+                              ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   DebugOnly<ErrorResult> error;
   MOZ_ASSERT(CheckStateForWrite(error));
   MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aInputLength);
-  MOZ_ASSERT(GetOwner());
+  MOZ_ASSERT(CheckWindow());
 
-  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
 
   uint64_t location = aAppend ? UINT64_MAX : mLocation;
 
   nsRefPtr<WriteHelper> helper =
     new WriteHelper(this, fileRequest, location, aInputStream, aInputLength);
 
   if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
@@ -729,17 +578,17 @@ FileHandle::WriteInternal(nsIInputStream
   else {
     mLocation += aInputLength;
   }
 
   return fileRequest.forget();
 }
 
 nsresult
-FileHandle::Finish()
+FileHandleBase::Finish()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<FinishHelper> helper(new FinishHelper(this));
 
   FileService* service = FileService::Get();
   MOZ_ASSERT(service, "This should never be null");
 
@@ -748,18 +597,18 @@ FileHandle::Finish()
   nsresult rv = target->Dispatch(helper, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandle::GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
+FileHandleBase::GetInputStream(const ArrayBuffer& aValue,
+                               uint64_t* aInputLength, ErrorResult& aRv)
 {
   aValue.ComputeLengthAndData();
   const char* data = reinterpret_cast<const char*>(aValue.Data());
   uint32_t length = aValue.Length();
 
   nsCOMPtr<nsIInputStream> stream;
   aRv = NS_NewByteInputStream(getter_AddRefs(stream), data, length,
                               NS_ASSIGNMENT_COPY);
@@ -768,18 +617,18 @@ FileHandle::GetInputStream(const ArrayBu
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandle::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
+FileHandleBase::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
+                               ErrorResult& aRv)
 {
   uint64_t length;
   aRv = aValue->GetSize(&length);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
@@ -789,74 +638,63 @@ FileHandle::GetInputStream(nsIDOMBlob* a
   }
 
   *aInputLength = length;
   return stream.forget();
 }
 
 // static
 already_AddRefed<nsIInputStream>
-FileHandle::GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
+FileHandleBase::GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
+                               ErrorResult& aRv)
 {
   NS_ConvertUTF16toUTF8 cstr(aValue);
 
   nsCOMPtr<nsIInputStream> stream;
   aRv = NS_NewCStringInputStream(getter_AddRefs(stream), cstr);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   *aInputLength = cstr.Length();
   return stream.forget();
 }
 
-FinishHelper::FinishHelper(FileHandle* aFileHandle)
+FinishHelper::FinishHelper(FileHandleBase* aFileHandle)
 : mFileHandle(aFileHandle),
   mAborted(aFileHandle->mAborted)
 {
   mParallelStreams.SwapElements(aFileHandle->mParallelStreams);
   mStream.swap(aFileHandle->mStream);
 }
 
 NS_IMPL_ISUPPORTS(FinishHelper, nsIRunnable)
 
 NS_IMETHODIMP
 FinishHelper::Run()
 {
   if (NS_IsMainThread()) {
-    mFileHandle->mReadyState = FileHandle::DONE;
+    mFileHandle->mReadyState = FileHandleBase::DONE;
 
     FileService* service = FileService::Get();
     if (service) {
       service->NotifyFileHandleCompleted(mFileHandle);
     }
 
-    nsCOMPtr<nsIDOMEvent> event;
-    if (mAborted) {
-      event = CreateGenericEvent(mFileHandle, NS_LITERAL_STRING("abort"),
-                                 true, false);
-    }
-    else {
-      event = CreateGenericEvent(mFileHandle, NS_LITERAL_STRING("complete"),
-                                 false, false);
-    }
-    NS_ENSURE_TRUE(event, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-
-    bool dummy;
-    if (NS_FAILED(mFileHandle->DispatchEvent(event, &dummy))) {
-      NS_WARNING("Dispatch failed!");
+    nsresult rv = mFileHandle->OnCompleteOrAbort(mAborted);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
     }
 
     mFileHandle = nullptr;
 
     return NS_OK;
   }
 
-  if (mFileHandle->mMutableFile->IsInvalid()) {
+  if (mFileHandle->MutableFile()->IsInvalid()) {
     mAborted = true;
   }
 
   for (uint32_t index = 0; index < mParallelStreams.Length(); index++) {
     nsCOMPtr<nsIInputStream> stream =
       do_QueryInterface(mParallelStreams[index]);
 
     if (NS_FAILED(stream->Close())) {
--- a/dom/filehandle/FileHandle.h
+++ b/dom/filehandle/FileHandle.h
@@ -2,138 +2,116 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FileHandle_h
 #define mozilla_dom_FileHandle_h
 
-#include "js/TypeDecls.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/FileModeBinding.h"
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/ErrorResult.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 #include "nsIInputStream.h"
 #include "nsIRunnable.h"
 #include "nsTArray.h"
 
 class nsAString;
 class nsIDOMBlob;
-class nsPIDOMWindow;
 
 namespace mozilla {
-
-class EventChainPreVisitor;
-
 namespace dom {
 
-struct DOMFileMetadataParameters;
 class FileHelper;
-class FileRequest;
+class FileRequestBase;
 class FileService;
 class FinishHelper;
 class MetadataHelper;
-class MutableFile;
+class MutableFileBase;
 
-class FileHandle : public DOMEventTargetHelper,
-                   public nsIRunnable
+/**
+ * This class provides a base for FileHandle implementations.
+ */
+class FileHandleBase
 {
-  friend class FileHelper;
-  friend class FileService;
-  friend class FinishHelper;
-  friend class MetadataHelper;
-
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIRUNNABLE
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileHandle, DOMEventTargetHelper)
-
   enum RequestMode
   {
     NORMAL = 0, // Sequential
     PARALLEL
   };
 
   enum ReadyState
   {
     INITIAL = 0,
     LOADING,
     FINISHING,
     DONE
   };
 
-  static already_AddRefed<FileHandle>
-  Create(MutableFile* aMutableFile,
-         FileMode aMode,
-         RequestMode aRequestMode = NORMAL);
+private:
+  friend class FileHelper;
+  friend class FileService;
+  friend class FinishHelper;
+  friend class MetadataHelper;
+
+  ReadyState mReadyState;
+  FileMode mMode;
+  RequestMode mRequestMode;
+  uint64_t mLocation;
+  uint32_t mPendingRequests;
 
-  // nsIDOMEventTarget
-  virtual nsresult
-  PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
+  nsTArray<nsCOMPtr<nsISupports>> mParallelStreams;
+  nsCOMPtr<nsISupports> mStream;
+
+  bool mAborted;
+  bool mCreating;
+
+public:
+  NS_IMETHOD_(MozExternalRefCountType)
+  AddRef() = 0;
+
+  NS_IMETHOD_(MozExternalRefCountType)
+  Release() = 0;
 
   nsresult
   CreateParallelStream(nsISupports** aStream);
 
   nsresult
   GetOrCreateStream(nsISupports** aStream);
 
   bool
   IsOpen() const;
 
   bool
   IsAborted() const
   {
     return mAborted;
   }
 
-  MutableFile*
-  File() const
+  void
+  SetCreating()
   {
-    return mMutableFile;
+    mCreating = true;
   }
 
+  virtual MutableFileBase*
+  MutableFile() const = 0;
+
   nsresult
   OpenInputStream(bool aWholeFile, uint64_t aStart, uint64_t aLength,
                   nsIInputStream** aResult);
 
-  // WrapperCache
-  virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
-
-  // WebIDL
-  nsPIDOMWindow*
-  GetParentObject() const
-  {
-    return GetOwner();
-  }
-
-  MutableFile*
-  GetMutableFile() const
-  {
-    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-    return File();
-  }
-
-  MutableFile*
-  GetFileHandle() const
-  {
-    return GetMutableFile();
-  }
-
+  // Shared WebIDL (IndexedDB FileHandle and FileSystem FileHandle)
   FileMode
   Mode() const
   {
     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
     return mMode;
   }
 
@@ -165,80 +143,63 @@ public:
     // Null means the end-of-file.
     if (aLocation.IsNull()) {
       mLocation = UINT64_MAX;
     } else {
       mLocation = aLocation.Value();
     }
   }
 
-  already_AddRefed<FileRequest>
-  GetMetadata(const DOMFileMetadataParameters& aParameters, ErrorResult& aRv);
-
-  already_AddRefed<FileRequest>
-  ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv);
-
-  already_AddRefed<FileRequest>
-  ReadAsText(uint64_t aSize, const nsAString& aEncoding, ErrorResult& aRv);
+  already_AddRefed<FileRequestBase>
+  Read(uint64_t aSize, bool aHasEncoding, const nsAString& aEncoding,
+       ErrorResult& aRv);
 
-  template<class T>
-  already_AddRefed<FileRequest>
-  Write(const T& aValue, ErrorResult& aRv)
-  {
-    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-    return WriteOrAppend(aValue, false, aRv);
-  }
-
-  template<class T>
-  already_AddRefed<FileRequest>
-  Append(const T& aValue, ErrorResult& aRv)
-  {
-    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-    return WriteOrAppend(aValue, true, aRv);
-  }
-
-  already_AddRefed<FileRequest>
+  already_AddRefed<FileRequestBase>
   Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv);
 
-  already_AddRefed<FileRequest>
+  already_AddRefed<FileRequestBase>
   Flush(ErrorResult& aRv);
 
   void
   Abort(ErrorResult& aRv);
 
-  IMPL_EVENT_HANDLER(complete)
-  IMPL_EVENT_HANDLER(abort)
-  IMPL_EVENT_HANDLER(error)
-
-private:
-  FileHandle();
-  ~FileHandle();
+protected:
+  FileHandleBase(FileMode aMode,
+                 RequestMode aRequestMode);
+  ~FileHandleBase();
 
   void
   OnNewRequest();
 
   void
   OnRequestFinished();
 
+  void
+  OnReturnToEventLoop();
+
+  virtual nsresult
+  OnCompleteOrAbort(bool aAborted) = 0;
+
   bool
   CheckState(ErrorResult& aRv);
 
   bool
   CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv);
 
   bool
   CheckStateForWrite(ErrorResult& aRv);
 
-  already_AddRefed<FileRequest>
-  GenerateFileRequest();
+  virtual bool
+  CheckWindow() = 0;
+
+  virtual already_AddRefed<FileRequestBase>
+  GenerateFileRequest() = 0;
 
   template<class T>
-  already_AddRefed<FileRequest>
+  already_AddRefed<FileRequestBase>
   WriteOrAppend(const T& aValue, bool aAppend, ErrorResult& aRv)
   {
     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
     // State checking for write
     if (!CheckStateForWrite(aRv)) {
       return nullptr;
     }
@@ -255,69 +216,56 @@ private:
       return nullptr;
     }
 
     if (!length) {
       return nullptr;
     }
 
     // Do nothing if the window is closed
-    if (!GetOwner()) {
+    if (!CheckWindow()) {
       return nullptr;
     }
 
     return WriteInternal(stream, length, aAppend, aRv);
   }
 
-  already_AddRefed<FileRequest>
+  already_AddRefed<FileRequestBase>
   WriteInternal(nsIInputStream* aInputStream, uint64_t aInputLength,
                 bool aAppend, ErrorResult& aRv);
 
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength, ErrorResult& aRv);
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
-
-  nsRefPtr<MutableFile> mMutableFile;
-  ReadyState mReadyState;
-  FileMode mMode;
-  RequestMode mRequestMode;
-  uint64_t mLocation;
-  uint32_t mPendingRequests;
-
-  nsTArray<nsCOMPtr<nsISupports>> mParallelStreams;
-  nsCOMPtr<nsISupports> mStream;
-
-  bool mAborted;
-  bool mCreating;
 };
 
 class FinishHelper MOZ_FINAL : public nsIRunnable
 {
-  friend class FileHandle;
+  friend class FileHandleBase;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
 private:
-  FinishHelper(FileHandle* aFileHandle);
+  FinishHelper(FileHandleBase* aFileHandle);
   ~FinishHelper()
   { }
 
-  nsRefPtr<FileHandle> mFileHandle;
+  nsRefPtr<FileHandleBase> mFileHandle;
   nsTArray<nsCOMPtr<nsISupports>> mParallelStreams;
   nsCOMPtr<nsISupports> mStream;
 
   bool mAborted;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/filehandle/FileHelper.cpp
+++ b/dom/filehandle/FileHelper.cpp
@@ -17,23 +17,23 @@
 #include "nsError.h"
 #include "nsIRequest.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
-FileHandle* gCurrentFileHandle = nullptr;
+FileHandleBase* gCurrentFileHandle = nullptr;
 
 } // anonymous namespace
 
-FileHelper::FileHelper(FileHandle* aFileHandle,
-                       FileRequest* aFileRequest)
-: mMutableFile(aFileHandle->mMutableFile),
+FileHelper::FileHelper(FileHandleBase* aFileHandle,
+                       FileRequestBase* aFileRequest)
+: mMutableFile(aFileHandle->MutableFile()),
   mFileHandle(aFileHandle),
   mFileRequest(aFileRequest),
   mResultCode(NS_OK),
   mFinished(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
@@ -70,17 +70,17 @@ FileHelper::AsyncRun(FileHelperListener*
 
   // Assign the listener early, so we can use it synchronously if the code
   // below fails.
   mListener = aListener;
 
   nsresult rv;
 
   nsCOMPtr<nsISupports> stream;
-  if (mFileHandle->mRequestMode == FileHandle::PARALLEL) {
+  if (mFileHandle->mRequestMode == FileHandleBase::PARALLEL) {
     rv = mFileHandle->CreateParallelStream(getter_AddRefs(stream));
   }
   else {
     rv = mFileHandle->GetOrCreateStream(getter_AddRefs(stream));
   }
 
   if (NS_SUCCEEDED(rv)) {
     NS_ASSERTION(stream, "This should never be null!");
@@ -141,17 +141,17 @@ FileHelper::OnStreamProgress(uint64_t aP
   }
 
   if (mFileRequest) {
     mFileRequest->OnProgress(aProgress, aProgressMax);
   }
 }
 
 // static
-FileHandle*
+FileHandleBase*
 FileHelper::GetCurrentFileHandle()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   return gCurrentFileHandle;
 }
 
 nsresult
@@ -188,17 +188,17 @@ FileHelper::Finish()
   mFinished = true;
 
   if (mFileHandle->IsAborted()) {
     // Always fire a "error" event with ABORT_ERR if the transaction was
     // aborted, even if the request succeeded or failed with another error.
     mResultCode = NS_ERROR_DOM_FILEHANDLE_ABORT_ERR;
   }
 
-  FileHandle* oldFileHandle = gCurrentFileHandle;
+  FileHandleBase* oldFileHandle = gCurrentFileHandle;
   gCurrentFileHandle = mFileHandle;
 
   if (mFileRequest) {
     nsresult rv = mFileRequest->NotifyHelperCompleted(this);
     if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
       mResultCode = rv;
     }
   }
--- a/dom/filehandle/FileHelper.h
+++ b/dom/filehandle/FileHelper.h
@@ -10,21 +10,21 @@
 #include "js/TypeDecls.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIRequestObserver.h"
 
 namespace mozilla {
 namespace dom {
 
-class FileHandle;
+class FileHandleBase;
 class FileHelper;
-class FileRequest;
+class FileRequestBase;
 class FileOutputStreamWrapper;
-class MutableFile;
+class MutableFileBase;
 
 class FileHelperListener
 {
 public:
   NS_IMETHOD_(MozExternalRefCountType)
   AddRef() = 0;
 
   NS_IMETHOD_(MozExternalRefCountType)
@@ -36,61 +36,66 @@ public:
 
 /**
  * Must be subclassed. The subclass must implement DoAsyncRun. It may then
  * choose to implement GetSuccessResult to properly set the result of the
  * success event. Call Enqueue to start the file operation.
  */
 class FileHelper : public nsIRequestObserver
 {
-  friend class FileRequest;
   friend class FileOutputStreamWrapper;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
 
   nsresult
+  ResultCode() const
+  {
+    return mResultCode;
+  }
+
+  nsresult
   Enqueue();
 
   nsresult
   AsyncRun(FileHelperListener* aListener);
 
+  virtual nsresult
+  GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal);
+
   void
   OnStreamProgress(uint64_t aProgress, uint64_t aProgressMax);
 
   void
   OnStreamClose();
 
   void
   OnStreamDestroy();
 
-  static FileHandle*
+  static FileHandleBase*
   GetCurrentFileHandle();
 
 protected:
-  FileHelper(FileHandle* aFileHandle, FileRequest* aRequest);
+  FileHelper(FileHandleBase* aFileHandle, FileRequestBase* aRequest);
 
   virtual ~FileHelper();
 
   virtual nsresult
   DoAsyncRun(nsISupports* aStream) = 0;
 
-  virtual nsresult
-  GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal);
-
   virtual void
   ReleaseObjects();
 
   void
   Finish();
 
-  nsRefPtr<MutableFile> mMutableFile;
-  nsRefPtr<FileHandle> mFileHandle;
-  nsRefPtr<FileRequest> mFileRequest;
+  nsRefPtr<MutableFileBase> mMutableFile;
+  nsRefPtr<FileHandleBase> mFileHandle;
+  nsRefPtr<FileRequestBase> mFileRequest;
 
   nsRefPtr<FileHelperListener> mListener;
   nsCOMPtr<nsIRequest> mRequest;
 
 private:
   nsresult mResultCode;
   bool mFinished;
 };
--- a/dom/filehandle/FileRequest.cpp
+++ b/dom/filehandle/FileRequest.cpp
@@ -1,151 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileRequest.h"
 
-#include "FileHandle.h"
-#include "FileHelper.h"
-#include "js/RootingAPI.h"
-#include "jsapi.h"
 #include "MainThreadUtils.h"
-#include "mozilla/dom/FileRequestBinding.h"
-#include "mozilla/EventDispatcher.h"
-#include "nsCOMPtr.h"
-#include "nsCxPusher.h"
-#include "nsDebug.h"
-#include "nsError.h"
-#include "nsIDOMEvent.h"
-#include "mozilla/dom/ProgressEvent.h"
-#include "nsIScriptContext.h"
-#include "nsLiteralString.h"
+#include "mozilla/Assertions.h"
 
 namespace mozilla {
 namespace dom {
 
-FileRequest::FileRequest(nsPIDOMWindow* aWindow)
-  : DOMRequest(aWindow), mWrapAsDOMRequest(false)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-}
-
-FileRequest::~FileRequest()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-}
-
-// static
-already_AddRefed<FileRequest>
-FileRequest::Create(nsPIDOMWindow* aOwner, FileHandle* aFileHandle,
-                    bool aWrapAsDOMRequest)
+FileRequestBase::FileRequestBase()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  nsRefPtr<FileRequest> request = new FileRequest(aOwner);
-  request->mFileHandle = aFileHandle;
-  request->mWrapAsDOMRequest = aWrapAsDOMRequest;
-
-  return request.forget();
-}
-
-nsresult
-FileRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mFileHandle;
-  return NS_OK;
+  MOZ_ASSERT(NS_IsMainThread());
 }
 
-nsresult
-FileRequest::NotifyHelperCompleted(FileHelper* aFileHelper)
+FileRequestBase::~FileRequestBase()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  nsresult rv = aFileHelper->mResultCode;
-
-  // If the request failed then fire error event and return.
-  if (NS_FAILED(rv)) {
-    FireError(rv);
-    return NS_OK;
-  }
-
-  // Otherwise we need to get the result from the helper.
-  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-  NS_ENSURE_STATE(sc);
-
-  AutoJSContext cx;
-  NS_ASSERTION(cx, "Failed to get a context!");
-
-  JS::Rooted<JS::Value> result(cx);
-
-  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
-  NS_ASSERTION(global, "Failed to get global object!");
-
-  JSAutoCompartment ac(cx, global);
-
-  rv = aFileHelper->GetSuccessResult(cx, &result);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("GetSuccessResult failed!");
-  }
-
-  if (NS_SUCCEEDED(rv)) {
-    FireSuccess(result);
-  }
-  else {
-    FireError(rv);
-  }
-
-  return NS_OK;
-}
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(FileRequest, DOMRequest,
-                                   mFileHandle)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileRequest)
-NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
-
-NS_IMPL_ADDREF_INHERITED(FileRequest, DOMRequest)
-NS_IMPL_RELEASE_INHERITED(FileRequest, DOMRequest)
-
-// virtual
-JSObject*
-FileRequest::WrapObject(JSContext* aCx)
-{
-  if (mWrapAsDOMRequest) {
-    return DOMRequest::WrapObject(aCx);
-  }
-  return FileRequestBinding::Wrap(aCx, this);
-}
-
-FileHandle*
-FileRequest::GetFileHandle() const
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-  return mFileHandle;
-}
-
-void
-FileRequest::FireProgressEvent(uint64_t aLoaded, uint64_t aTotal)
-{
-  if (NS_FAILED(CheckInnerWindowCorrectness())) {
-    return;
-  }
-
-  ProgressEventInit init;
-  init.mBubbles = false;
-  init.mCancelable = false;
-  init.mLengthComputable = false;
-  init.mLoaded = aLoaded;
-  init.mTotal = aTotal;
-
-  nsRefPtr<ProgressEvent> event =
-    ProgressEvent::Constructor(this, NS_LITERAL_STRING("progress"), init);
-  DispatchTrustedEvent(event);
+  MOZ_ASSERT(NS_IsMainThread());
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/filehandle/FileRequest.h
+++ b/dom/filehandle/FileRequest.h
@@ -2,81 +2,43 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FileRequest_h
 #define mozilla_dom_FileRequest_h
 
-#include "DOMRequest.h"
-#include "js/TypeDecls.h"
-#include "mozilla/Attributes.h"
-#include "nsAutoPtr.h"
-#include "nsCycleCollectionParticipant.h"
-
-class nsPIDOMWindow;
+#include "nscore.h"
 
 namespace mozilla {
-
-class EventChainPreVisitor;
-
 namespace dom {
 
-class FileHandle;
 class FileHelper;
 
-class FileRequest : public DOMRequest
+/**
+ * This class provides a base for FileRequest implementations.
+ */
+class FileRequestBase
 {
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileRequest, DOMRequest)
-
-  static already_AddRefed<FileRequest>
-  Create(nsPIDOMWindow* aOwner, FileHandle* aFileHandle,
-         bool aWrapAsDOMRequest);
+  NS_IMETHOD_(MozExternalRefCountType)
+  AddRef() = 0;
 
-  // nsIDOMEventTarget
-  virtual nsresult
-  PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
-
-  void
-  OnProgress(uint64_t aProgress, uint64_t aProgressMax)
-  {
-    FireProgressEvent(aProgress, aProgressMax);
-  }
+  NS_IMETHOD_(MozExternalRefCountType)
+  Release() = 0;
 
-  nsresult
-  NotifyHelperCompleted(FileHelper* aFileHelper);
-
-  // nsWrapperCache
-  virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+  virtual void
+  OnProgress(uint64_t aProgress, uint64_t aProgressMax) = 0;
 
-  // WebIDL
-  FileHandle*
-  GetFileHandle() const;
-
-  FileHandle*
-  GetLockedFile() const
-  {
-    return GetFileHandle();
-  }
-
-  IMPL_EVENT_HANDLER(progress)
+  virtual nsresult
+  NotifyHelperCompleted(FileHelper* aFileHelper) = 0;
 
 protected:
-  FileRequest(nsPIDOMWindow* aWindow);
-  ~FileRequest();
+  FileRequestBase();
 
-  void
-  FireProgressEvent(uint64_t aLoaded, uint64_t aTotal);
-
-  nsRefPtr<FileHandle> mFileHandle;
-
-  bool mWrapAsDOMRequest;
+  virtual ~FileRequestBase();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FileRequest_h
--- a/dom/filehandle/FileService.cpp
+++ b/dom/filehandle/FileService.cpp
@@ -141,22 +141,22 @@ FileService::Shutdown()
 // static
 bool
 FileService::IsShuttingDown()
 {
   return gShutdown;
 }
 
 nsresult
-FileService::Enqueue(FileHandle* aFileHandle, FileHelper* aFileHelper)
+FileService::Enqueue(FileHandleBase* aFileHandle, FileHelper* aFileHelper)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(aFileHandle, "Null pointer!");
 
-  MutableFile* mutableFile = aFileHandle->mMutableFile;
+  MutableFileBase* mutableFile = aFileHandle->MutableFile();
 
   if (mutableFile->IsInvalid()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   const nsACString& storageId = mutableFile->mStorageId;
   const nsAString& fileName = mutableFile->mFileName;
   bool modeIsWrite = aFileHandle->mMode == FileMode::Readwrite;
@@ -216,22 +216,22 @@ FileService::Enqueue(FileHandle* aFileHa
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
 }
 
 void
-FileService::NotifyFileHandleCompleted(FileHandle* aFileHandle)
+FileService::NotifyFileHandleCompleted(FileHandleBase* aFileHandle)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(aFileHandle, "Null pointer!");
 
-  MutableFile* mutableFile = aFileHandle->mMutableFile;
+  MutableFileBase* mutableFile = aFileHandle->MutableFile();
   const nsACString& storageId = mutableFile->mStorageId;
 
   StorageInfo* storageInfo;
   if (!mStorageInfos.Get(storageId, &storageInfo)) {
     NS_ERROR("We don't know anyting about this file handle?!");
     return;
   }
 
@@ -277,17 +277,17 @@ FileService::AbortFileHandlesForStorage(
   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   MOZ_ASSERT(aStorage, "Null pointer!");
 
   StorageInfo* storageInfo;
   if (!mStorageInfos.Get(aStorage->Id(), &storageInfo)) {
     return;
   }
 
-  nsAutoTArray<nsRefPtr<FileHandle>, 10> fileHandles;
+  nsAutoTArray<nsRefPtr<FileHandleBase>, 10> fileHandles;
   storageInfo->CollectRunningAndDelayedFileHandles(aStorage, fileHandles);
 
   for (uint32_t index = 0; index < fileHandles.Length(); index++) {
     ErrorResult ignored;
     fileHandles[index]->Abort(ignored);
   }
 }
 
@@ -329,17 +329,17 @@ FileService::MaybeFireCallback(StoragesC
       return false;
     }
   }
 
   aCallback.mCallback->Run();
   return true;
 }
 
-FileService::FileHandleQueue::FileHandleQueue(FileHandle* aFileHandle)
+FileService::FileHandleQueue::FileHandleQueue(FileHandleBase* aFileHandle)
 : mFileHandle(aFileHandle)
 {
   MOZ_ASSERT(aFileHandle, "Null pointer!");
 }
 
 FileService::FileHandleQueue::~FileHandleQueue()
 {
 }
@@ -348,32 +348,32 @@ NS_IMPL_ADDREF(FileService::FileHandleQu
 NS_IMPL_RELEASE(FileService::FileHandleQueue)
 
 nsresult
 FileService::FileHandleQueue::Enqueue(FileHelper* aFileHelper)
 {
   mQueue.AppendElement(aFileHelper);
 
   nsresult rv;
-  if (mFileHandle->mRequestMode == FileHandle::PARALLEL) {
+  if (mFileHandle->mRequestMode == FileHandleBase::PARALLEL) {
     rv = aFileHelper->AsyncRun(this);
   }
   else {
     rv = ProcessQueue();
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void
 FileService::
 FileHandleQueue::OnFileHelperComplete(FileHelper* aFileHelper)
 {
-  if (mFileHandle->mRequestMode == FileHandle::PARALLEL) {
+  if (mFileHandle->mRequestMode == FileHandleBase::PARALLEL) {
     int32_t index = mQueue.IndexOf(aFileHelper);
     NS_ASSERTION(index != -1, "We don't know anything about this helper!");
 
     mQueue.RemoveElementAt(index);
   }
   else {
     NS_ASSERTION(mCurrentHelper == aFileHelper, "How can this happen?!");
 
@@ -406,39 +406,39 @@ FileService::DelayedEnqueueInfo::Delayed
 {
 }
 
 FileService::DelayedEnqueueInfo::~DelayedEnqueueInfo()
 {
 }
 
 FileService::FileHandleQueue*
-FileService::StorageInfo::CreateFileHandleQueue(FileHandle* aFileHandle)
+FileService::StorageInfo::CreateFileHandleQueue(FileHandleBase* aFileHandle)
 {
   nsRefPtr<FileHandleQueue>* fileHandleQueue =
     mFileHandleQueues.AppendElement();
   *fileHandleQueue = new FileHandleQueue(aFileHandle);
   return fileHandleQueue->get();
 }
 
 FileService::FileHandleQueue*
-FileService::StorageInfo::GetFileHandleQueue(FileHandle* aFileHandle)
+FileService::StorageInfo::GetFileHandleQueue(FileHandleBase* aFileHandle)
 {
   uint32_t count = mFileHandleQueues.Length();
   for (uint32_t index = 0; index < count; index++) {
     nsRefPtr<FileHandleQueue>& fileHandleQueue = mFileHandleQueues[index];
     if (fileHandleQueue->mFileHandle == aFileHandle) {
       return fileHandleQueue;
     }
   }
   return nullptr;
 }
 
 void
-FileService::StorageInfo::RemoveFileHandleQueue(FileHandle* aFileHandle)
+FileService::StorageInfo::RemoveFileHandleQueue(FileHandleBase* aFileHandle)
 {
   for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
     if (mDelayedEnqueueInfos[index].mFileHandle == aFileHandle) {
       MOZ_ASSERT(!mDelayedEnqueueInfos[index].mFileHelper, "Should be null!");
       mDelayedEnqueueInfos.RemoveElementAt(index);
       return;
     }
   }
@@ -448,28 +448,28 @@ FileService::StorageInfo::RemoveFileHand
   // We can't just remove entries from lock hash tables, we have to rebuild
   // them instead. Multiple FileHandle objects may lock the same file
   // (one entry can represent multiple locks).
 
   mFilesReading.Clear();
   mFilesWriting.Clear();
 
   for (uint32_t index = 0, count = fileHandleCount; index < count; index++) {
-    FileHandle* fileHandle = mFileHandleQueues[index]->mFileHandle;
+    FileHandleBase* fileHandle = mFileHandleQueues[index]->mFileHandle;
     if (fileHandle == aFileHandle) {
       MOZ_ASSERT(count == fileHandleCount, "More than one match?!");
 
       mFileHandleQueues.RemoveElementAt(index);
       index--;
       count--;
 
       continue;
     }
 
-    const nsAString& fileName = fileHandle->mMutableFile->mFileName;
+    const nsAString& fileName = fileHandle->MutableFile()->mFileName;
 
     if (fileHandle->mMode == FileMode::Readwrite) {
       if (!IsFileLockedForWriting(fileName)) {
         LockFileForWriting(fileName);
       }
     }
     else {
       if (!IsFileLockedForReading(fileName)) {
@@ -492,48 +492,48 @@ FileService::StorageInfo::RemoveFileHand
     }
   }
 }
 
 bool
 FileService::StorageInfo::HasRunningFileHandles(nsIOfflineStorage* aStorage)
 {
   for (uint32_t index = 0; index < mFileHandleQueues.Length(); index++) {
-    FileHandle* fileHandle = mFileHandleQueues[index]->mFileHandle;
-    if (fileHandle->mMutableFile->Storage() == aStorage) {
+    FileHandleBase* fileHandle = mFileHandleQueues[index]->mFileHandle;
+    if (fileHandle->MutableFile()->Storage() == aStorage) {
       return true;
     }
   }
   return false;
 }
 
 FileService::DelayedEnqueueInfo*
-FileService::StorageInfo::CreateDelayedEnqueueInfo(FileHandle* aFileHandle,
+FileService::StorageInfo::CreateDelayedEnqueueInfo(FileHandleBase* aFileHandle,
                                                    FileHelper* aFileHelper)
 {
   DelayedEnqueueInfo* info = mDelayedEnqueueInfos.AppendElement();
   info->mFileHandle = aFileHandle;
   info->mFileHelper = aFileHelper;
   return info;
 }
 
 void
 FileService::StorageInfo::CollectRunningAndDelayedFileHandles(
-                                 nsIOfflineStorage* aStorage,
-                                 nsTArray<nsRefPtr<FileHandle>>& aFileHandles)
+                               nsIOfflineStorage* aStorage,
+                               nsTArray<nsRefPtr<FileHandleBase>>& aFileHandles)
 {
   for (uint32_t index = 0; index < mFileHandleQueues.Length(); index++) {
-    FileHandle* fileHandle = mFileHandleQueues[index]->mFileHandle;
-    if (fileHandle->mMutableFile->Storage() == aStorage) {
+    FileHandleBase* fileHandle = mFileHandleQueues[index]->mFileHandle;
+    if (fileHandle->MutableFile()->Storage() == aStorage) {
       aFileHandles.AppendElement(fileHandle);
     }
   }
 
   for (uint32_t index = 0; index < mDelayedEnqueueInfos.Length(); index++) {
-    FileHandle* fileHandle = mDelayedEnqueueInfos[index].mFileHandle;
-    if (fileHandle->mMutableFile->Storage() == aStorage) {
+    FileHandleBase* fileHandle = mDelayedEnqueueInfos[index].mFileHandle;
+    if (fileHandle->MutableFile()->Storage() == aStorage) {
       aFileHandles.AppendElement(fileHandle);
     }
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/filehandle/FileService.h
+++ b/dom/filehandle/FileService.h
@@ -21,17 +21,17 @@
 class nsAString;
 class nsIEventTarget;
 class nsIOfflineStorage;
 class nsIRunnable;
 
 namespace mozilla {
 namespace dom {
 
-class FileHandle;
+class FileHandleBase;
 
 class FileService MOZ_FINAL : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // Returns a non-owning reference!
@@ -45,20 +45,20 @@ public:
   static void
   Shutdown();
 
   // Returns true if we've begun the shutdown process.
   static bool
   IsShuttingDown();
 
   nsresult
-  Enqueue(FileHandle* aFileHandle, FileHelper* aFileHelper);
+  Enqueue(FileHandleBase* aFileHandle, FileHelper* aFileHelper);
 
   void
-  NotifyFileHandleCompleted(FileHandle* aFileHandle);
+  NotifyFileHandleCompleted(FileHandleBase* aFileHandle);
 
   void
   WaitForStoragesToComplete(nsTArray<nsCOMPtr<nsIOfflineStorage> >& aStorages,
                             nsIRunnable* aCallback);
 
   void
   AbortFileHandlesForStorage(nsIOfflineStorage* aStorage);
 
@@ -87,69 +87,70 @@ private:
     inline nsresult
     Enqueue(FileHelper* aFileHelper);
 
     virtual void
     OnFileHelperComplete(FileHelper* aFileHelper) MOZ_OVERRIDE;
 
   private:
     inline
-    FileHandleQueue(FileHandle* aFileHandle);
+    FileHandleQueue(FileHandleBase* aFileHandle);
 
     ~FileHandleQueue();
 
     nsresult
     ProcessQueue();
 
     ThreadSafeAutoRefCnt mRefCnt;
     NS_DECL_OWNINGTHREAD
-    nsRefPtr<FileHandle> mFileHandle;
+    nsRefPtr<FileHandleBase> mFileHandle;
     nsTArray<nsRefPtr<FileHelper> > mQueue;
     nsRefPtr<FileHelper> mCurrentHelper;
   };
 
   struct DelayedEnqueueInfo
   {
     DelayedEnqueueInfo();
     ~DelayedEnqueueInfo();
 
-    nsRefPtr<FileHandle> mFileHandle;
+    nsRefPtr<FileHandleBase> mFileHandle;
     nsRefPtr<FileHelper> mFileHelper;
   };
 
   class StorageInfo
   {
     friend class FileService;
 
   public:
     inline FileHandleQueue*
-    CreateFileHandleQueue(FileHandle* aFileHandle);
+    CreateFileHandleQueue(FileHandleBase* aFileHandle);
 
     inline FileHandleQueue*
-    GetFileHandleQueue(FileHandle* aFileHandle);
+    GetFileHandleQueue(FileHandleBase* aFileHandle);
 
     void
-    RemoveFileHandleQueue(FileHandle* aFileHandle);
+    RemoveFileHandleQueue(FileHandleBase* aFileHandle);
 
     bool
     HasRunningFileHandles()
     {
       return !mFileHandleQueues.IsEmpty();
     }
 
     inline bool
     HasRunningFileHandles(nsIOfflineStorage* aStorage);
 
     inline DelayedEnqueueInfo*
-    CreateDelayedEnqueueInfo(FileHandle* aFileHandle, FileHelper* aFileHelper);
+    CreateDelayedEnqueueInfo(FileHandleBase* aFileHandle,
+                             FileHelper* aFileHelper);
 
     inline void
     CollectRunningAndDelayedFileHandles(
-                                 nsIOfflineStorage* aStorage,
-                                 nsTArray<nsRefPtr<FileHandle>>& aFileHandles);
+                              nsIOfflineStorage* aStorage,
+                              nsTArray<nsRefPtr<FileHandleBase>>& aFileHandles);
 
     void
     LockFileForReading(const nsAString& aFileName)
     {
       mFilesReading.PutEntry(aFileName);
     }
 
     void
--- a/dom/filehandle/MetadataHelper.h
+++ b/dom/filehandle/MetadataHelper.h
@@ -2,20 +2,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_MetadataHelper_h
 #define mozilla_dom_MetadataHelper_h
 
-#include "AsyncHelper.h"
 #include "FileHelper.h"
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/AsyncHelper.h"
 #include "nsAutoPtr.h"
 
 namespace mozilla {
 namespace dom {
 
 class MetadataHelper;
 
 class MetadataParameters MOZ_FINAL
@@ -71,18 +71,18 @@ private:
   int64_t mLastModified;
   bool mSizeRequested;
   bool mLastModifiedRequested;
 };
 
 class MetadataHelper : public FileHelper
 {
 public:
-  MetadataHelper(FileHandle* aFileHandle,
-                 FileRequest* aFileRequest,
+  MetadataHelper(FileHandleBase* aFileHandle,
+                 FileRequestBase* aFileRequest,
                  MetadataParameters* aParams)
   : FileHelper(aFileHandle, aFileRequest),
     mParams(aParams)
   { }
 
   nsresult
   DoAsyncRun(nsISupports* aStream) MOZ_OVERRIDE;
 
--- a/dom/filehandle/MutableFile.cpp
+++ b/dom/filehandle/MutableFile.cpp
@@ -1,188 +1,52 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MutableFile.h"
 
-#include "File.h"
-#include "FileHandle.h"
-#include "FileRequest.h"
-#include "FileService.h"
-#include "MetadataHelper.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/dom/MutableFileBinding.h"
-#include "mozilla/ErrorResult.h"
-#include "nsAutoPtr.h"
-#include "nsContentUtils.h"
 #include "nsDebug.h"
-#include "nsError.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
+#include "nsIFileStreams.h"
+#include "nsIInputStream.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace dom {
 
-namespace {
-
-class GetFileHelper : public MetadataHelper
-{
-public:
-  GetFileHelper(FileHandle* aFileHandle,
-                FileRequest* aFileRequest,
-                MetadataParameters* aParams,
-                MutableFile* aMutableFile)
-  : MetadataHelper(aFileHandle, aFileRequest, aParams),
-    mMutableFile(aMutableFile)
-  { }
-
-  virtual nsresult
-  GetSuccessResult(JSContext* aCx,
-                   JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
-
-  virtual void
-  ReleaseObjects() MOZ_OVERRIDE
-  {
-    mMutableFile = nullptr;
-
-    MetadataHelper::ReleaseObjects();
-  }
-
-private:
-  nsRefPtr<MutableFile> mMutableFile;
-};
-
-} // anonymous namespace
-
-MutableFile::MutableFile(nsPIDOMWindow* aWindow)
-  : DOMEventTargetHelper(aWindow)
+MutableFileBase::MutableFileBase()
 {
 }
 
-MutableFile::MutableFile(DOMEventTargetHelper* aOwner)
-  : DOMEventTargetHelper(aOwner)
-{
-}
-
-MutableFile::~MutableFile()
+MutableFileBase::~MutableFileBase()
 {
 }
 
-bool
-MutableFile::IsShuttingDown()
-{
-  return FileService::IsShuttingDown();
-}
-
 // virtual
 already_AddRefed<nsISupports>
-MutableFile::CreateStream(nsIFile* aFile, bool aReadOnly)
+MutableFileBase::CreateStream(bool aReadOnly)
 {
   nsresult rv;
 
   if (aReadOnly) {
     nsCOMPtr<nsIInputStream> stream;
-    rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aFile, -1, -1,
+    rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
                                     nsIFileInputStream::DEFER_OPEN);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
     return stream.forget();
   }
 
   nsCOMPtr<nsIFileStream> stream;
-  rv = NS_NewLocalFileStream(getter_AddRefs(stream), aFile, -1, -1,
+  rv = NS_NewLocalFileStream(getter_AddRefs(stream), mFile, -1, -1,
                              nsIFileStream::DEFER_OPEN);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
   return stream.forget();
 }
 
-// virtual
-already_AddRefed<nsIDOMFile>
-MutableFile::CreateFileObject(FileHandle* aFileHandle, uint32_t aFileSize)
-{
-  nsCOMPtr<nsIDOMFile> file =
-    new DOMFile(new FileImpl(mName, mType, aFileSize, mFile, aFileHandle));
-
-  return file.forget();
-}
-
-// virtual
-JSObject*
-MutableFile::WrapObject(JSContext* aCx)
-{
-  return MutableFileBinding::Wrap(aCx, this);
-}
-
-already_AddRefed<FileHandle>
-MutableFile::Open(FileMode aMode, ErrorResult& aError)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (IsShuttingDown()) {
-    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  nsRefPtr<FileHandle> fileHandle = FileHandle::Create(this, aMode);
-  if (!fileHandle) {
-    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  return fileHandle.forget();
-}
-
-already_AddRefed<DOMRequest>
-MutableFile::GetFile(ErrorResult& aError)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // Do nothing if the window is closed
-  if (!GetOwner()) {
-    return nullptr;
-  }
-
-  nsRefPtr<FileHandle> fileHandle =
-    FileHandle::Create(this, FileMode::Readonly, FileHandle::PARALLEL);
-  if (!fileHandle) {
-    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  nsRefPtr<FileRequest> request =
-    FileRequest::Create(GetOwner(), fileHandle, /* aWrapAsDOMRequest */ true);
-
-  nsRefPtr<MetadataParameters> params = new MetadataParameters(true, false);
-
-  nsRefPtr<GetFileHelper> helper =
-    new GetFileHelper(fileHandle, request, params, this);
-
-  nsresult rv = helper->Enqueue();
-  if (NS_FAILED(rv)) {
-    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-    return nullptr;
-  }
-
-  return request.forget();
-}
-
-nsresult
-GetFileHelper::GetSuccessResult(JSContext* aCx,
-                                JS::MutableHandle<JS::Value> aVal)
-{
-  nsCOMPtr<nsIDOMFile> domFile =
-    mMutableFile->CreateFileObject(mFileHandle, mParams->Size());
-
-  nsresult rv =
-    nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), aVal);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
-  return NS_OK;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/filehandle/MutableFile.h
+++ b/dom/filehandle/MutableFile.h
@@ -2,154 +2,72 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_MutableFile_h
 #define mozilla_dom_MutableFile_h
 
-#include "js/TypeDecls.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/dom/FileModeBinding.h"
-#include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 
-class nsIDOMFile;
 class nsIFile;
 class nsIOfflineStorage;
-class nsPIDOMWindow;
 
 namespace mozilla {
-
-class ErrorResult;
-
 namespace dom {
 
-class DOMRequest;
-class FileHandle;
 class FileService;
-class FinishHelper;
-class FileHelper;
-
-namespace indexedDB {
-class FileInfo;
-} // namespace indexedDB
 
 /**
- * This class provides a default MutableFile implementation, but it can be also
- * subclassed. The subclass can override implementation of GetFileId,
- * GetFileInfo, IsShuttingDown, IsInvalid, CreateStream, SetThreadLocals,
- * UnsetThreadLocals and CreateFileObject.
+ * This class provides a base for MutableFile implementations.
+ * The subclasses can override implementation of IsInvalid, CreateStream,
+ * SetThreadLocals and UnsetThreadLocals.
  * (for example IDBMutableFile provides IndexedDB specific implementation).
  */
-class MutableFile : public DOMEventTargetHelper
+class MutableFileBase
 {
-  friend class FileHandle;
   friend class FileService;
-  friend class FinishHelper;
-  friend class FileHelper;
 
 public:
-  const nsAString&
-  Name() const
-  {
-    return mName;
-  }
-
-  const nsAString&
-  Type() const
-  {
-    return mType;
-  }
+  NS_IMETHOD_(MozExternalRefCountType)
+  AddRef() = 0;
 
-  virtual int64_t
-  GetFileId()
-  {
-    return -1;
-  }
-
-  virtual mozilla::dom::indexedDB::FileInfo*
-  GetFileInfo()
-  {
-    return nullptr;
-  }
-
-  virtual bool
-  IsShuttingDown();
+  NS_IMETHOD_(MozExternalRefCountType)
+  Release() = 0;
 
   virtual bool
   IsInvalid()
   {
     return false;
   }
 
   // A temporary method that will be removed along with nsIOfflineStorage
   // interface.
   virtual nsIOfflineStorage*
   Storage() = 0;
 
   virtual already_AddRefed<nsISupports>
-  CreateStream(nsIFile* aFile, bool aReadOnly);
+  CreateStream(bool aReadOnly);
 
   virtual void
   SetThreadLocals()
   {
   }
 
   virtual void
   UnsetThreadLocals()
   {
   }
 
-  virtual already_AddRefed<nsIDOMFile>
-  CreateFileObject(FileHandle* aFileHandle, uint32_t aFileSize);
-
-  // nsWrapperCache
-  virtual JSObject*
-  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
-
-  // WebIDL
-  nsPIDOMWindow*
-  GetParentObject() const
-  {
-    return GetOwner();
-  }
-
-  void
-  GetName(nsString& aName) const
-  {
-    aName = mName;
-  }
+protected:
+  MutableFileBase();
 
-  void
-  GetType(nsString& aType) const
-  {
-    aType = mType;
-  }
-
-  already_AddRefed<FileHandle>
-  Open(FileMode aMode, ErrorResult& aError);
-
-  already_AddRefed<DOMRequest>
-  GetFile(ErrorResult& aError);
-
-  IMPL_EVENT_HANDLER(abort)
-  IMPL_EVENT_HANDLER(error)
-
-protected:
-  MutableFile(nsPIDOMWindow* aWindow);
-
-  MutableFile(DOMEventTargetHelper* aOwner);
-
-  virtual ~MutableFile();
-
-  nsString mName;
-  nsString mType;
+  virtual ~MutableFileBase();
 
   nsCOMPtr<nsIFile> mFile;
 
   nsCString mStorageId;
   nsString mFileName;
 };
 
 } // namespace dom
--- a/dom/filehandle/moz.build
+++ b/dom/filehandle/moz.build
@@ -1,28 +1,26 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-TEST_DIRS += ['test']
-
 EXPORTS.mozilla.dom += [
-    'File.h',
+    'AsyncHelper.h',
     'FileHandle.h',
     'FileHelper.h',
     'FileRequest.h',
     'FileService.h',
+    'MetadataHelper.h',
     'MutableFile.h',
 ]
 
 UNIFIED_SOURCES += [
     'AsyncHelper.cpp',
-    'File.cpp',
     'FileHandle.cpp',
     'FileHelper.cpp',
     'FileRequest.cpp',
     'FileService.cpp',
     'FileStreamWrappers.cpp',
     'MemoryStreams.cpp',
     'MetadataHelper.cpp',
     'MutableFile.cpp',
deleted file mode 100644
--- a/dom/filehandle/test/helpers.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-const IndexedDatabaseKey = "IDB";
-const DeviceStorageKey = "DS";
-
-var fileStorages = [
-  { key: IndexedDatabaseKey }
-//  { key: DeviceStorageKey }
-];
-
-var utils = SpecialPowers.getDOMWindowUtils(window);
-
-var testGenerator = testSteps();
-
-function runTest()
-{
-  allowUnlimitedQuota();
-
-  SimpleTest.waitForExplicitFinish();
-  testGenerator.next();
-}
-
-function finishTest()
-{
-  resetUnlimitedQuota();
-
-  SimpleTest.executeSoon(function() {
-    testGenerator.close();
-    SimpleTest.finish();
-  });
-}
-
-function grabEventAndContinueHandler(event)
-{
-  testGenerator.send(event);
-}
-
-function continueToNextStep()
-{
-  SimpleTest.executeSoon(function() {
-    testGenerator.next();
-  });
-}
-
-function errorHandler(event)
-{
-  ok(false, "indexedDB error, code " + event.target.errorCode);
-  finishTest();
-}
-
-function unexpectedSuccessHandler()
-{
-  ok(false, "Got success, but did not expect it!");
-  finishTest();
-}
-
-function ExpectError(name)
-{
-  this._name = name;
-}
-ExpectError.prototype = {
-  handleEvent: function(event)
-  {
-    is(event.type, "error", "Got an error event");
-    is(event.target.error.name, this._name, "Expected error was thrown.");
-    event.preventDefault();
-    event.stopPropagation();
-    grabEventAndContinueHandler(event);
-  }
-};
-
-function addPermission(type, allow, url)
-{
-  if (!url) {
-    url = window.document;
-  }
-  SpecialPowers.addPermission(type, allow, url);
-}
-
-function removePermission(type, url)
-{
-  if (!url) {
-    url = window.document;
-  }
-  SpecialPowers.removePermission(type, url);
-}
-
-function allowUnlimitedQuota(url)
-{
-  addPermission("indexedDB-unlimited", true, url);
-}
-
-function resetUnlimitedQuota(url)
-{
-  removePermission("indexedDB-unlimited", url);
-}
-
-function getMutableFile(fileStorageKey, name)
-{
-  var requestService = SpecialPowers.getDOMRequestService();
-  var request = requestService.createRequest(window);
-
-  switch (fileStorageKey) {
-    case IndexedDatabaseKey:
-      var dbname = window.location.pathname;
-      indexedDB.open(dbname, 1).onsuccess = function(event) {
-        var db = event.target.result;
-        db.createMutableFile(name).onsuccess = function(event) {
-          var fileHandle = event.target.result;
-          requestService.fireSuccess(request, fileHandle);
-        }
-      }
-      break;
-
-    case DeviceStorageKey:
-      var dbname = window.location.pathname;
-      indexedDB.open(dbname, 1).onsuccess = function(event) {
-        var db = event.target.result;
-        db.createMutableFile(name).onsuccess = function(event) {
-          var fileHandle = event.target.result;
-          requestService.fireSuccess(request, fileHandle);
-        }
-      }
-      break;
-  }
-
-  return request;
-}
-
-function getFileHandle(fileStorageKey, name)
-{
-  var requestService = SpecialPowers.getDOMRequestService();
-  var request = requestService.createRequest(window);
-
-  switch (fileStorageKey) {
-    case IndexedDatabaseKey:
-      var dbname = window.location.pathname;
-      indexedDB.open(dbname, 1).onsuccess = function(event) {
-        var db = event.target.result;
-        db.mozCreateFileHandle(name).onsuccess = function(event) {
-          var fileHandle = event.target.result;
-          requestService.fireSuccess(request, fileHandle);
-        }
-      }
-      break;
-
-    case DeviceStorageKey:
-      var dbname = window.location.pathname;
-      indexedDB.open(dbname, 1).onsuccess = function(event) {
-        var db = event.target.result;
-        db.mozCreateFileHandle(name).onsuccess = function(event) {
-          var fileHandle = event.target.result;
-          requestService.fireSuccess(request, fileHandle);
-        }
-      }
-      break;
-  }
-
-  return request;
-}
-
-function getBuffer(size)
-{
-  let buffer = new ArrayBuffer(size);
-  is(buffer.byteLength, size, "Correct byte length");
-  return buffer;
-}
-
-function getRandomBuffer(size)
-{
-  let buffer = getBuffer(size);
-  let view = new Uint8Array(buffer);
-  for (let i = 0; i < size; i++) {
-    view[i] = parseInt(Math.random() * 255)
-  }
-  return buffer;
-}
-
-function compareBuffers(buffer1, buffer2)
-{
-  if (buffer1.byteLength != buffer2.byteLength) {
-    return false;
-  }
-  let view1 = new Uint8Array(buffer1);
-  let view2 = new Uint8Array(buffer2);
-  for (let i = 0; i < buffer1.byteLength; i++) {
-    if (view1[i] != view2[i]) {
-      return false;
-    }
-  }
-  return true;
-}
-
-function getRandomBlob(size)
-{
-  return new Blob([getRandomBuffer(size)], { type: "binary/random" });
-}
-
-function getFileId(blob)
-{
-  return SpecialPowers.unwrap(utils.getFileId(blob));
-}
deleted file mode 100644
--- a/dom/filehandle/test/mochitest.ini
+++ /dev/null
@@ -1,39 +0,0 @@
-[DEFAULT]
-skip-if = e10s
-support-files =
-  dummy_worker.js
-  helpers.js
-
-[test_append_read_data.html]
-skip-if = buildapp == 'b2g'
-[test_compat.html]
-skip-if = buildapp == 'b2g'
-[test_filehandle_lifetimes.html]
-skip-if = buildapp == 'b2g'
-[test_filehandle_lifetimes_nested.html]
-skip-if = buildapp == 'b2g'
-[test_filehandle_ordering.html]
-skip-if = buildapp == 'b2g'
-[test_getFile.html]
-skip-if = buildapp == 'b2g'
-[test_getFileId.html]
-[test_location.html]
-skip-if = buildapp == 'b2g'
-[test_overlapping_filehandles.html]
-skip-if = buildapp == 'b2g'
-[test_progress_events.html]
-skip-if = buildapp == 'b2g' # b2g(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109) b2g-debug(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109) b2g-desktop(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109)
-[test_readonly_filehandles.html]
-skip-if = buildapp == 'b2g'
-[test_request_readyState.html]
-skip-if = buildapp == 'b2g'
-[test_stream_tracking.html]
-skip-if = buildapp == 'b2g'
-[test_success_events_after_abort.html]
-skip-if = buildapp == 'b2g'
-[test_truncate.html]
-skip-if = buildapp == 'b2g'
-[test_workers.html]
-skip-if = buildapp == 'b2g'
-[test_write_read_data.html]
-skip-if = buildapp == 'b2g'
deleted file mode 100644
--- a/dom/filehandle/test/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_MANIFESTS += ['mochitest.ini']
-
rename from dom/filehandle/File.cpp
rename to dom/indexedDB/FileSnapshot.cpp
--- a/dom/filehandle/File.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -1,119 +1,109 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "File.h"
+#include "FileSnapshot.h"
 
-#include "FileHandle.h"
+#include "IDBFileHandle.h"
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
 
 namespace mozilla {
 namespace dom {
-
-using indexedDB::IndexedDatabaseManager;
-
-NS_IMPL_ISUPPORTS_INHERITED0(FileImpl, DOMFileImpl)
+namespace indexedDB {
 
-// Create as a file
-FileImpl::FileImpl(const nsAString& aName, const nsAString& aContentType,
-                   uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle)
-  : DOMFileImplBase(aName, aContentType, aLength),
-    mFile(aFile), mFileHandle(aFileHandle), mWholeFile(true), mStoredFile(false)
-{
-  MOZ_ASSERT(mFile, "Null file!");
-  MOZ_ASSERT(mFileHandle, "Null file handle!");
-}
+NS_IMPL_ISUPPORTS_INHERITED0(FileImplSnapshot, DOMFileImpl)
 
 // Create as a stored file
-FileImpl::FileImpl(const nsAString& aName, const nsAString& aContentType,
-                   uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
-                   indexedDB::FileInfo* aFileInfo)
+FileImplSnapshot::FileImplSnapshot(const nsAString& aName,
+                                   const nsAString& aContentType,
+                                   uint64_t aLength, nsIFile* aFile,
+                                   IDBFileHandle* aFileHandle,
+                                   FileInfo* aFileInfo)
   : DOMFileImplBase(aName, aContentType, aLength),
-    mFile(aFile), mFileHandle(aFileHandle), mWholeFile(true), mStoredFile(true)
+    mFile(aFile), mFileHandle(aFileHandle), mWholeFile(true)
 {
   MOZ_ASSERT(mFile, "Null file!");
   MOZ_ASSERT(mFileHandle, "Null file handle!");
   mFileInfos.AppendElement(aFileInfo);
 }
 
 // Create slice
-FileImpl::FileImpl(const FileImpl* aOther, uint64_t aStart, uint64_t aLength,
-                   const nsAString& aContentType)
+FileImplSnapshot::FileImplSnapshot(const FileImplSnapshot* aOther,
+                                   uint64_t aStart, uint64_t aLength,
+                                   const nsAString& aContentType)
   : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength),
     mFile(aOther->mFile), mFileHandle(aOther->mFileHandle),
-    mWholeFile(false), mStoredFile(aOther->mStoredFile)
+    mWholeFile(false)
 {
   MOZ_ASSERT(mFile, "Null file!");
   MOZ_ASSERT(mFileHandle, "Null file handle!");
 
-  if (mStoredFile) {
-    indexedDB::FileInfo* fileInfo;
+  FileInfo* fileInfo;
 
-    if (IndexedDatabaseManager::IsClosed()) {
-      fileInfo = aOther->GetFileInfo();
-    }
-    else {
-      MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
-      fileInfo = aOther->GetFileInfo();
-    }
+  if (IndexedDatabaseManager::IsClosed()) {
+    fileInfo = aOther->GetFileInfo();
+  } else {
+    MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
+    fileInfo = aOther->GetFileInfo();
+  }
 
-    mFileInfos.AppendElement(fileInfo);
-  }
+  mFileInfos.AppendElement(fileInfo);
 }
 
-FileImpl::~FileImpl()
+FileImplSnapshot::~FileImplSnapshot()
 {
 }
 
 void
-FileImpl::Unlink()
+FileImplSnapshot::Unlink()
 {
-  FileImpl* tmp = this;
+  FileImplSnapshot* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileHandle);
 }
 
 void
-FileImpl::Traverse(nsCycleCollectionTraversalCallback &cb)
+FileImplSnapshot::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
-  FileImpl* tmp = this;
+  FileImplSnapshot* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileHandle);
 }
 
 nsresult
-FileImpl::GetInternalStream(nsIInputStream** aStream)
+FileImplSnapshot::GetInternalStream(nsIInputStream** aStream)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsresult rv = mFileHandle->OpenInputStream(mWholeFile, mStart, mLength,
                                              aStream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 already_AddRefed<nsIDOMBlob>
-FileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
-                      const nsAString& aContentType)
+FileImplSnapshot::CreateSlice(uint64_t aStart, uint64_t aLength,
+                              const nsAString& aContentType)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIDOMBlob> t =
-    new DOMFile(new FileImpl(this, aStart, aLength, aContentType));
+    new DOMFile(new FileImplSnapshot(this, aStart, aLength, aContentType));
 
   return t.forget();
 }
 
 nsresult
-FileImpl::GetMozFullPathInternal(nsAString& aFilename)
+FileImplSnapshot::GetMozFullPathInternal(nsAString& aFilename)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
   return mFile->GetPath(aFilename);
 }
 
+} // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
rename from dom/filehandle/File.h
rename to dom/indexedDB/FileSnapshot.h
--- a/dom/filehandle/File.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -1,91 +1,91 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_File_h
-#define mozilla_dom_File_h
+#ifndef mozilla_dom_indexeddb_filesnapshot_h__
+#define mozilla_dom_indexeddb_filesnapshot_h__
 
 #include "mozilla/Attributes.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMFile.h"
 
 namespace mozilla {
 namespace dom {
-
-class FileHandle;
-class File;
+namespace indexedDB {
 
-class FileImpl : public DOMFileImplBase
+class IDBFileHandle;
+
+class FileImplSnapshot : public DOMFileImplBase
 {
-  friend class File;
-
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  // Create as a file
-  FileImpl(const nsAString& aName, const nsAString& aContentType,
-           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle);
-
   // Create as a stored file
-  FileImpl(const nsAString& aName, const nsAString& aContentType,
-           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
-           indexedDB::FileInfo* aFileInfo);
+  FileImplSnapshot(const nsAString& aName, const nsAString& aContentType,
+                   uint64_t aLength, nsIFile* aFile, IDBFileHandle* aFileHandle,
+                   FileInfo* aFileInfo);
 
   // Overrides
-  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual nsresult
+  GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
 
-  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+  virtual nsresult
+  GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  virtual void Unlink() MOZ_OVERRIDE;
-  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
+  virtual void
+  Unlink() MOZ_OVERRIDE;
 
-  virtual bool IsCCed() const MOZ_OVERRIDE
+  virtual void
+  Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
+
+  virtual bool
+  IsCCed() const MOZ_OVERRIDE
   {
     return true;
   }
 
 protected:
   // Create slice
-  FileImpl(const FileImpl* aOther, uint64_t aStart, uint64_t aLength,
-           const nsAString& aContentType);
+  FileImplSnapshot(const FileImplSnapshot* aOther, uint64_t aStart,
+                   uint64_t aLength, const nsAString& aContentType);
 
-  virtual ~FileImpl();
+  virtual ~FileImplSnapshot();
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType) MOZ_OVERRIDE;
 
   virtual bool
   IsStoredFile() const MOZ_OVERRIDE
   {
-    return mStoredFile;
+    return true;
   }
 
   virtual bool
   IsWholeFile() const MOZ_OVERRIDE
   {
     return mWholeFile;
   }
 
   virtual bool
   IsSnapshot() const MOZ_OVERRIDE
   {
     return true;
   }
 
 private:
   nsCOMPtr<nsIFile> mFile;
-  nsRefPtr<FileHandle> mFileHandle;
+  nsRefPtr<IDBFileHandle> mFileHandle;
 
   bool mWholeFile;
-  bool mStoredFile;
 };
 
+} // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_File_h
+#endif // mozilla_dom_indexeddb_filesnapshot_h__
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "IDBFileHandle.h"
+
+#include "IDBEvents.h"
+#include "IDBMutableFile.h"
+#include "mozilla/dom/FileService.h"
+#include "mozilla/dom/IDBFileHandleBinding.h"
+#include "mozilla/dom/MetadataHelper.h"
+#include "mozilla/EventDispatcher.h"
+#include "nsIAppShell.h"
+#include "nsServiceManagerUtils.h"
+#include "nsWidgetsCID.h"
+
+namespace {
+
+NS_DEFINE_CID(kAppShellCID2, NS_APPSHELL_CID);
+
+} // anonymous namespace
+
+namespace mozilla {
+namespace dom {
+namespace indexedDB {
+
+IDBFileHandle::IDBFileHandle(FileMode aMode,
+                             RequestMode aRequestMode,
+                             IDBMutableFile* aMutableFile)
+  : FileHandleBase(aMode, aRequestMode)
+  , mMutableFile(aMutableFile)
+{
+  SetIsDOMBinding();
+}
+
+IDBFileHandle::~IDBFileHandle()
+{
+}
+
+// static
+already_AddRefed<IDBFileHandle>
+IDBFileHandle::Create(FileMode aMode,
+                      RequestMode aRequestMode,
+                      IDBMutableFile* aMutableFile)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBFileHandle> fileHandle =
+    new IDBFileHandle(aMode, aRequestMode, aMutableFile);
+
+  fileHandle->BindToOwner(aMutableFile);
+
+  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID2);
+  if (NS_WARN_IF(!appShell)) {
+    return nullptr;
+  }
+
+  nsresult rv = appShell->RunBeforeNextEvent(fileHandle);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  fileHandle->SetCreating();
+
+  FileService* service = FileService::GetOrCreate();
+  if (NS_WARN_IF(!service)) {
+    return nullptr;
+  }
+
+  rv = service->Enqueue(fileHandle, nullptr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return fileHandle.forget();
+}
+
+mozilla::dom::MutableFileBase*
+IDBFileHandle::MutableFile() const
+{
+  return mMutableFile;
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileHandle, DOMEventTargetHelper,
+                                   mMutableFile)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileHandle)
+  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
+
+nsresult
+IDBFileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  aVisitor.mCanHandle = true;
+  aVisitor.mParentTarget = mMutableFile;
+  return NS_OK;
+}
+
+// virtual
+JSObject*
+IDBFileHandle::WrapObject(JSContext* aCx)
+{
+  return IDBFileHandleBinding::Wrap(aCx, this);
+}
+
+already_AddRefed<IDBFileRequest>
+IDBFileHandle::GetMetadata(const IDBFileMetadataParameters& aParameters,
+                           ErrorResult& aRv)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  // Common state checking
+  if (!CheckState(aRv)) {
+    return nullptr;
+  }
+
+  // Do nothing if the window is closed
+  if (!CheckWindow()) {
+    return nullptr;
+  }
+
+  nsRefPtr<MetadataParameters> params =
+    new MetadataParameters(aParameters.mSize, aParameters.mLastModified);
+  if (!params->IsConfigured()) {
+    aRv.ThrowTypeError(MSG_METADATA_NOT_CONFIGURED);
+    return nullptr;
+  }
+
+  nsRefPtr<FileRequestBase> fileRequest = GenerateFileRequest();
+
+  nsRefPtr<MetadataHelper> helper =
+    new MetadataHelper(this, fileRequest, params);
+
+  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
+    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
+    return nullptr;
+  }
+
+  return fileRequest.forget().downcast<IDBFileRequest>();
+}
+
+NS_IMETHODIMP
+IDBFileHandle::Run()
+{
+  OnReturnToEventLoop();
+  return NS_OK;
+}
+
+nsresult
+IDBFileHandle::OnCompleteOrAbort(bool aAborted)
+{
+  nsCOMPtr<nsIDOMEvent> event;
+  if (aAborted) {
+    event = CreateGenericEvent(this, NS_LITERAL_STRING(ABORT_EVT_STR),
+                               eDoesBubble, eNotCancelable);
+  } else {
+    event = CreateGenericEvent(this, NS_LITERAL_STRING(COMPLETE_EVT_STR),
+                               eDoesNotBubble, eNotCancelable);
+  }
+  if (NS_WARN_IF(!event)) {
+    return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
+  }
+
+  bool dummy;
+  if (NS_FAILED(DispatchEvent(event, &dummy))) {
+    NS_WARNING("Dispatch failed!");
+  }
+
+  return NS_OK;
+}
+
+bool
+IDBFileHandle::CheckWindow()
+{
+  return GetOwner();
+}
+
+already_AddRefed<mozilla::dom::FileRequestBase>
+IDBFileHandle::GenerateFileRequest()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  return IDBFileRequest::Create(GetOwner(), this,
+                                /* aWrapAsDOMRequest */ false);
+}
+
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_indexeddb_idbfilehandle_h__
+#define mozilla_dom_indexeddb_idbfilehandle_h__
+
+#include "IDBFileRequest.h"
+#include "js/TypeDecls.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/FileHandle.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+namespace dom {
+
+struct IDBFileMetadataParameters;
+
+namespace indexedDB {
+
+class IDBMutableFile;
+
+class IDBFileHandle MOZ_FINAL : public DOMEventTargetHelper,
+                                public nsIRunnable,
+                                public FileHandleBase
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIRUNNABLE
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileHandle, DOMEventTargetHelper)
+
+  static already_AddRefed<IDBFileHandle>
+  Create(FileMode aMode,
+         RequestMode aRequestMode,
+         IDBMutableFile* aMutableFile);
+
+  virtual MutableFileBase*
+  MutableFile() const MOZ_OVERRIDE;
+
+  // nsIDOMEventTarget
+  virtual nsresult
+  PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
+
+  // WrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+
+  IDBMutableFile*
+  GetMutableFile() const
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+    return mMutableFile;
+  }
+
+  IDBMutableFile*
+  GetFileHandle() const
+  {
+    return GetMutableFile();
+  }
+
+  already_AddRefed<IDBFileRequest>
+  GetMetadata(const IDBFileMetadataParameters& aParameters, ErrorResult& aRv);
+
+  already_AddRefed<IDBFileRequest>
+  ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv)
+  {
+    return Read(aSize, false, NullString(), aRv).downcast<IDBFileRequest>();
+  }
+
+  already_AddRefed<IDBFileRequest>
+  ReadAsText(uint64_t aSize, const nsAString& aEncoding, ErrorResult& aRv)
+  {
+    return Read(aSize, true, aEncoding, aRv).downcast<IDBFileRequest>();
+  }
+
+  template<class T>
+  already_AddRefed<IDBFileRequest>
+  Write(const T& aValue, ErrorResult& aRv)
+  {
+    return
+      WriteOrAppend(aValue, false, aRv).template downcast<IDBFileRequest>();
+  }
+
+  template<class T>
+  already_AddRefed<IDBFileRequest>
+  Append(const T& aValue, ErrorResult& aRv)
+  {
+    return WriteOrAppend(aValue, true, aRv).template downcast<IDBFileRequest>();
+  }
+
+  already_AddRefed<IDBFileRequest>
+  Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
+  {
+    return FileHandleBase::Truncate(aSize, aRv).downcast<IDBFileRequest>();
+  }
+
+  already_AddRefed<IDBFileRequest>
+  Flush(ErrorResult& aRv)
+  {
+    return FileHandleBase::Flush(aRv).downcast<IDBFileRequest>();
+  }
+
+  IMPL_EVENT_HANDLER(complete)
+  IMPL_EVENT_HANDLER(abort)
+  IMPL_EVENT_HANDLER(error)
+
+private:
+  IDBFileHandle(FileMode aMode,
+                RequestMode aRequestMode,
+                IDBMutableFile* aMutableFile);
+  ~IDBFileHandle();
+
+  virtual nsresult
+  OnCompleteOrAbort(bool aAborted) MOZ_OVERRIDE;
+
+  virtual bool
+  CheckWindow() MOZ_OVERRIDE;
+
+  virtual already_AddRefed<FileRequestBase>
+  GenerateFileRequest() MOZ_OVERRIDE;
+
+  nsRefPtr<IDBMutableFile> mMutableFile;
+};
+
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_indexeddb_idbfilehandle_h__
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBFileRequest.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "IDBFileRequest.h"
+
+#include "IDBFileHandle.h"
+#include "js/RootingAPI.h"
+#include "jsapi.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/FileHelper.h"
+#include "mozilla/dom/IDBFileRequestBinding.h"
+#include "mozilla/dom/ProgressEvent.h"
+#include "mozilla/EventDispatcher.h"
+#include "nsCOMPtr.h"
+#include "nsCxPusher.h"
+#include "nsDebug.h"
+#include "nsError.h"
+#include "nsIDOMEvent.h"
+#include "nsIScriptContext.h"
+#include "nsLiteralString.h"
+
+namespace mozilla {
+namespace dom {
+namespace indexedDB {
+
+IDBFileRequest::IDBFileRequest(nsPIDOMWindow* aWindow)
+  : DOMRequest(aWindow), mWrapAsDOMRequest(false)
+{
+}
+
+IDBFileRequest::~IDBFileRequest()
+{
+}
+
+// static
+already_AddRefed<IDBFileRequest>
+IDBFileRequest::Create(nsPIDOMWindow* aOwner, IDBFileHandle* aFileHandle,
+                       bool aWrapAsDOMRequest)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<IDBFileRequest> request = new IDBFileRequest(aOwner);
+  request->mFileHandle = aFileHandle;
+  request->mWrapAsDOMRequest = aWrapAsDOMRequest;
+
+  return request.forget();
+}
+
+nsresult
+IDBFileRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  aVisitor.mCanHandle = true;
+  aVisitor.mParentTarget = mFileHandle;
+  return NS_OK;
+}
+
+void
+IDBFileRequest::OnProgress(uint64_t aProgress, uint64_t aProgressMax)
+{
+  FireProgressEvent(aProgress, aProgressMax);
+}
+
+nsresult
+IDBFileRequest::NotifyHelperCompleted(FileHelper* aFileHelper)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  nsresult rv = aFileHelper->ResultCode();
+
+  // If the request failed then fire error event and return.
+  if (NS_FAILED(rv)) {
+    FireError(rv);
+    return NS_OK;
+  }
+
+  // Otherwise we need to get the result from the helper.
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_STATE(sc);
+
+  AutoJSContext cx;
+  MOZ_ASSERT(cx, "Failed to get a context!");
+
+  JS::Rooted<JS::Value> result(cx);
+
+  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+  MOZ_ASSERT(global, "Failed to get global object!");
+
+  JSAutoCompartment ac(cx, global);
+
+  rv = aFileHelper->GetSuccessResult(cx, &result);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("GetSuccessResult failed!");
+  }
+
+  if (NS_SUCCEEDED(rv)) {
+    FireSuccess(result);
+  }
+  else {
+    FireError(rv);
+  }
+  return NS_OK;
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileRequest, DOMRequest,
+                                   mFileHandle)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileRequest)
+NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
+
+NS_IMPL_ADDREF_INHERITED(IDBFileRequest, DOMRequest)
+NS_IMPL_RELEASE_INHERITED(IDBFileRequest, DOMRequest)
+
+// virtual
+JSObject*
+IDBFileRequest::WrapObject(JSContext* aCx)
+{
+  if (mWrapAsDOMRequest) {
+    return DOMRequest::WrapObject(aCx);
+  }
+  return IDBFileRequestBinding::Wrap(aCx, this);
+}
+
+
+IDBFileHandle*
+IDBFileRequest::GetFileHandle() const
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+  return static_cast<IDBFileHandle*>(mFileHandle.get());
+}
+
+void
+IDBFileRequest::FireProgressEvent(uint64_t aLoaded, uint64_t aTotal)
+{
+  if (NS_FAILED(CheckInnerWindowCorrectness())) {
+    return;
+  }
+
+  ProgressEventInit init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+  init.mLengthComputable = false;
+  init.mLoaded = aLoaded;
+  init.mTotal = aTotal;
+
+  nsRefPtr<ProgressEvent> event =
+    ProgressEvent::Constructor(this, NS_LITERAL_STRING("progress"), init);
+  DispatchTrustedEvent(event);
+}
+
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/IDBFileRequest.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_indexeddb_idbfilerequest_h__
+#define mozilla_dom_indexeddb_idbfilerequest_h__
+
+#include "DOMRequest.h"
+#include "js/TypeDecls.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/FileRequest.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class EventChainPreVisitor;
+
+namespace dom {
+namespace indexedDB {
+
+class IDBFileHandle;
+
+class IDBFileRequest MOZ_FINAL : public DOMRequest,
+                                 public FileRequestBase
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileRequest, DOMRequest)
+
+  static already_AddRefed<IDBFileRequest>
+  Create(nsPIDOMWindow* aOwner, IDBFileHandle* aFileHandle,
+         bool aWrapAsDOMRequest);
+
+  // nsIDOMEventTarget
+  virtual nsresult
+  PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
+
+  // FileRequest
+  virtual void
+  OnProgress(uint64_t aProgress, uint64_t aProgressMax) MOZ_OVERRIDE;
+
+  virtual nsresult
+  NotifyHelperCompleted(FileHelper* aFileHelper) MOZ_OVERRIDE;
+
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  // WebIDL
+  IDBFileHandle*
+  GetFileHandle() const;
+
+  IDBFileHandle*
+  GetLockedFile() const
+  {
+    return GetFileHandle();
+  }
+
+  IMPL_EVENT_HANDLER(progress)
+
+private:
+  IDBFileRequest(nsPIDOMWindow* aWindow);
+  ~IDBFileRequest();
+
+  void
+  FireProgressEvent(uint64_t aLoaded, uint64_t aTotal);
+
+  nsRefPtr<IDBFileHandle> mFileHandle;
+
+  bool mWrapAsDOMRequest;
+};
+
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_indexeddb_idbfilerequest_h__
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -1,28 +1,66 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IDBMutableFile.h"
 
-#include "mozilla/dom/File.h"
+#include "nsIDOMFile.h"
+
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/FileService.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
+#include "mozilla/dom/MetadataHelper.h"
 #include "mozilla/dom/quota/FileStreams.h"
 #include "mozilla/dom/quota/QuotaManager.h"
+#include "nsContentUtils.h"
+#include "nsDebug.h"
+#include "nsError.h"
 
+#include "FileSnapshot.h"
 #include "IDBDatabase.h"
+#include "IDBFileHandle.h"
+#include "IDBFileRequest.h"
 
+using namespace mozilla::dom;
 USING_INDEXEDDB_NAMESPACE
 USING_QUOTA_NAMESPACE
 
 namespace {
 
+class GetFileHelper : public MetadataHelper
+{
+public:
+  GetFileHelper(FileHandleBase* aFileHandle,
+                FileRequestBase* aFileRequest,
+                MetadataParameters* aParams,
+                IDBMutableFile* aMutableFile)
+  : MetadataHelper(aFileHandle, aFileRequest, aParams),
+    mMutableFile(aMutableFile)
+  { }
+
+  virtual nsresult
+  GetSuccessResult(JSContext* aCx,
+                   JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
+
+  virtual void
+  ReleaseObjects() MOZ_OVERRIDE
+  {
+    mMutableFile = nullptr;
+
+    MetadataHelper::ReleaseObjects();
+  }
+
+private:
+  nsRefPtr<IDBMutableFile> mMutableFile;
+};
+
 inline
 already_AddRefed<nsIFile>
 GetFileFor(FileInfo* aFileInfo)
 
 {
   FileManager* fileManager = aFileInfo->Manager();
   nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
   NS_ENSURE_TRUE(directory, nullptr);
@@ -31,28 +69,37 @@ GetFileFor(FileInfo* aFileInfo)
                                                      aFileInfo->Id());
   NS_ENSURE_TRUE(file, nullptr);
 
   return file.forget();
 }
 
 } // anonymous namespace
 
+namespace mozilla {
+namespace dom {
+namespace indexedDB {
+
 IDBMutableFile::IDBMutableFile(IDBDatabase* aOwner)
-  : MutableFile(aOwner)
+  : DOMEventTargetHelper(aOwner)
 {
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBMutableFile, MutableFile, mDatabase)
+IDBMutableFile::~IDBMutableFile()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBMutableFile, DOMEventTargetHelper,
+                                   mDatabase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBMutableFile)
-NS_INTERFACE_MAP_END_INHERITING(MutableFile)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
-NS_IMPL_ADDREF_INHERITED(IDBMutableFile, MutableFile)
-NS_IMPL_RELEASE_INHERITED(IDBMutableFile, MutableFile)
+NS_IMPL_ADDREF_INHERITED(IDBMutableFile, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(IDBMutableFile, DOMEventTargetHelper)
 
 // static
 already_AddRefed<IDBMutableFile>
 IDBMutableFile::Create(const nsAString& aName,
                        const nsAString& aType,
                        IDBDatabase* aDatabase,
                        already_AddRefed<FileInfo> aFileInfo)
 {
@@ -74,51 +121,45 @@ IDBMutableFile::Create(const nsAString& 
 
   newFile->mDatabase = aDatabase;
   fileInfo.swap(newFile->mFileInfo);
 
   return newFile.forget();
 }
 
 bool
-IDBMutableFile::IsShuttingDown()
-{
-  return QuotaManager::IsShuttingDown() || MutableFile::IsShuttingDown();
-}
-
-bool
 IDBMutableFile::IsInvalid()
 {
   return mDatabase->IsInvalidated();
 }
 
 nsIOfflineStorage*
 IDBMutableFile::Storage()
 {
   return mDatabase;
 }
 
 already_AddRefed<nsISupports>
-IDBMutableFile::CreateStream(nsIFile* aFile, bool aReadOnly)
+IDBMutableFile::CreateStream(bool aReadOnly)
 {
   PersistenceType persistenceType = mDatabase->Type();
   const nsACString& group = mDatabase->Group();
   const nsACString& origin = mDatabase->Origin();
 
   nsCOMPtr<nsISupports> result;
 
   if (aReadOnly) {
     nsRefPtr<FileInputStream> stream =
-      FileInputStream::Create(persistenceType, group, origin, aFile, -1, -1,
+      FileInputStream::Create(persistenceType, group, origin, mFile, -1, -1,
                               nsIFileInputStream::DEFER_OPEN);
     result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
   }
   else {
     nsRefPtr<FileStream> stream =
-      FileStream::Create(persistenceType, group, origin, aFile, -1, -1,
+      FileStream::Create(persistenceType, group, origin, mFile, -1, -1,
                          nsIFileStream::DEFER_OPEN);
     result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
   }
   NS_ENSURE_TRUE(result, nullptr);
 
   return result.forget();
 }
 
@@ -131,23 +172,98 @@ IDBMutableFile::SetThreadLocals()
 
 void
 IDBMutableFile::UnsetThreadLocals()
 {
   QuotaManager::SetCurrentWindow(nullptr);
 }
 
 already_AddRefed<nsIDOMFile>
-IDBMutableFile::CreateFileObject(mozilla::dom::FileHandle* aFileHandle,
-                                uint32_t aFileSize)
+IDBMutableFile::CreateFileObject(IDBFileHandle* aFileHandle, uint32_t aFileSize)
 {
-  nsCOMPtr<nsIDOMFile> file = new DOMFile(
-    new FileImpl(mName, mType, aFileSize, mFile, aFileHandle, mFileInfo));
+  nsCOMPtr<nsIDOMFile> fileSnapshot = new DOMFile(
+    new FileImplSnapshot(mName, mType, aFileSize, mFile, aFileHandle,
+                         mFileInfo));
 
-  return file.forget();
+  return fileSnapshot.forget();
 }
 
 // virtual
 JSObject*
 IDBMutableFile::WrapObject(JSContext* aCx)
 {
   return IDBMutableFileBinding::Wrap(aCx, this);
 }
+
+already_AddRefed<IDBFileHandle>
+IDBMutableFile::Open(FileMode aMode, ErrorResult& aError)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (QuotaManager::IsShuttingDown() || FileService::IsShuttingDown()) {
+    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
+    return nullptr;
+  }
+
+  nsRefPtr<IDBFileHandle> fileHandle =
+    IDBFileHandle::Create(aMode, FileHandleBase::NORMAL, this);
+  if (!fileHandle) {
+    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
+    return nullptr;
+  }
+
+  return fileHandle.forget();
+}
+
+already_AddRefed<DOMRequest>
+IDBMutableFile::GetFile(ErrorResult& aError)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Do nothing if the window is closed
+  if (!GetOwner()) {
+    return nullptr;
+  }
+
+  nsRefPtr<IDBFileHandle> fileHandle =
+    IDBFileHandle::Create(FileMode::Readonly, FileHandleBase::PARALLEL, this);
+
+  nsRefPtr<IDBFileRequest> request = 
+    IDBFileRequest::Create(GetOwner(), fileHandle, /* aWrapAsDOMRequest */
+                           true);
+
+  nsRefPtr<MetadataParameters> params = new MetadataParameters(true, false);
+
+  nsRefPtr<GetFileHelper> helper =
+    new GetFileHelper(fileHandle, request, params, this);
+
+  nsresult rv = helper->Enqueue();
+  if (NS_FAILED(rv)) {
+    aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
+    return nullptr;
+  }
+
+  return request.forget();
+}
+
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
+
+nsresult
+GetFileHelper::GetSuccessResult(JSContext* aCx,
+                                JS::MutableHandle<JS::Value> aVal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto fileHandle = static_cast<IDBFileHandle*>(mFileHandle.get());
+
+  nsCOMPtr<nsIDOMFile> domFile =
+    mMutableFile->CreateFileObject(fileHandle, mParams->Size());
+
+  nsresult rv =
+    nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), aVal);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
+  }
+
+  return NS_OK;
+}
--- a/dom/indexedDB/IDBMutableFile.h
+++ b/dom/indexedDB/IDBMutableFile.h
@@ -2,95 +2,145 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_idbmutablefile_h__
 #define mozilla_dom_indexeddb_idbmutablefile_h__
 
-#include "IndexedDatabase.h"
-
+#include "js/TypeDecls.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/FileModeBinding.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/MutableFile.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 
-BEGIN_INDEXEDDB_NAMESPACE
+class nsIDOMFile;
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class DOMRequest;
+
+namespace indexedDB {
 
 class IDBDatabase;
+class IDBFileHandle;
 
-class IDBMutableFile : public MutableFile
+class IDBMutableFile MOZ_FINAL : public DOMEventTargetHelper,
+                                 public MutableFileBase
 {
-  typedef mozilla::dom::FileHandle FileHandle;
-
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBMutableFile, MutableFile)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBMutableFile, DOMEventTargetHelper)
 
   static already_AddRefed<IDBMutableFile>
   Create(const nsAString& aName, const nsAString& aType,
          IDBDatabase* aDatabase, already_AddRefed<FileInfo> aFileInfo);
 
+  const nsAString&
+  Name() const
+  {
+    return mName;
+  }
 
-  virtual int64_t
-  GetFileId() MOZ_OVERRIDE
+  const nsAString&
+  Type() const
+  {
+    return mType;
+  }
+
+  int64_t
+  GetFileId() const
   {
     return mFileInfo->Id();
   }
 
-  virtual FileInfo*
-  GetFileInfo() MOZ_OVERRIDE
+  FileInfo*
+  GetFileInfo() const
   {
     return mFileInfo;
   }
 
   virtual bool
-  IsShuttingDown() MOZ_OVERRIDE;
-
-  virtual bool
   IsInvalid() MOZ_OVERRIDE;
 
   virtual nsIOfflineStorage*
   Storage() MOZ_OVERRIDE;
 
   virtual already_AddRefed<nsISupports>
-  CreateStream(nsIFile* aFile, bool aReadOnly) MOZ_OVERRIDE;
+  CreateStream(bool aReadOnly) MOZ_OVERRIDE;
 
   virtual void
   SetThreadLocals() MOZ_OVERRIDE;
 
   virtual void
   UnsetThreadLocals() MOZ_OVERRIDE;
 
-  virtual already_AddRefed<nsIDOMFile>
-  CreateFileObject(FileHandle* aFileHandle, uint32_t aFileSize) MOZ_OVERRIDE;
+  already_AddRefed<nsIDOMFile>
+  CreateFileObject(IDBFileHandle* aFileHandle, uint32_t aFileSize);
 
   // nsWrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+
+  void
+  GetName(nsString& aName) const
+  {
+    aName = mName;
+  }
+
+  void
+  GetType(nsString& aType) const
+  {
+    aType = mType;
+  }
+
   IDBDatabase*
   Database()
   {
     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
     return mDatabase;
   }
 
+  already_AddRefed<IDBFileHandle>
+  Open(FileMode aMode, ErrorResult& aError);
+
+  already_AddRefed<DOMRequest>
+  GetFile(ErrorResult& aError);
+
+  IMPL_EVENT_HANDLER(abort)
+  IMPL_EVENT_HANDLER(error)
+
 private:
   IDBMutableFile(IDBDatabase* aOwner);
+  ~IDBMutableFile();
 
-  ~IDBMutableFile()
-  {
-  }
+  nsString mName;
+  nsString mType;
 
   nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<FileInfo> mFileInfo;
 };
 
-END_INDEXEDDB_NAMESPACE
+} // namespace indexedDB
+} // namespace dom
+} // namespace mozilla
 
 #endif // mozilla_dom_indexeddb_idbmutablefile_h__
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -9,18 +9,18 @@
 #include "IDBObjectStore.h"
 
 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "nsIOutputStream.h"
 
 #include <algorithm>
 #include "jsfriendapi.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/IDBMutableFileBinding.h"
 #include "mozilla/dom/nsIContentParent.h"
-#include "mozilla/dom/MutableFileBinding.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/dom/quota/FileStreams.h"
 #include "mozilla/Endian.h"
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
@@ -1568,23 +1568,23 @@ IDBObjectStore::StructuredCloneWriteCall
     uint64_t value = 0;
     // Omit endian swap
     return JS_WriteBytes(aWriter, &value, sizeof(value));
   }
 
   IDBTransaction* transaction = cloneWriteInfo->mTransaction;
   FileManager* fileManager = transaction->Database()->Manager();
 
-  MutableFile* mutableFile = nullptr;
-  if (NS_SUCCEEDED(UNWRAP_OBJECT(MutableFile, aObj, mutableFile))) {
+  IDBMutableFile* mutableFile = nullptr;
+  if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, aObj, mutableFile))) {
     nsRefPtr<FileInfo> fileInfo = mutableFile->GetFileInfo();
-
-    // Throw when trying to store non IDB mutable files or IDB mutable files
-    // across databases.
-    if (!fileInfo || fileInfo->Manager() != fileManager) {
+    MOZ_ASSERT(fileInfo);
+
+    // Throw when trying to store mutable files across databases.
+    if (fileInfo->Manager() != fileManager) {
       return false;
     }
 
     NS_ConvertUTF16toUTF8 convType(mutableFile->Type());
     uint32_t convTypeLength =
       NativeEndian::swapToLittleEndian(convType.Length());
 
     NS_ConvertUTF16toUTF8 convName(mutableFile->Name());
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -7,20 +7,23 @@
 DIRS += ['ipc']
 TEST_DIRS += ['test']
 
 EXPORTS.mozilla.dom.indexedDB += [
     'Client.h',
     'DatabaseInfo.h',
     'FileInfo.h',
     'FileManager.h',
+    'FileSnapshot.h',
     'IDBCursor.h',
     'IDBDatabase.h',
     'IDBEvents.h',
     'IDBFactory.h',
+    'IDBFileHandle.h',
+    'IDBFileRequest.h',
     'IDBIndex.h',
     'IDBKeyRange.h',
     'IDBMutableFile.h',
     'IDBObjectStore.h',
     'IDBRequest.h',
     'IDBTransaction.h',
     'IDBWrapperCache.h',
     'IndexedDatabase.h',
@@ -31,19 +34,22 @@ EXPORTS.mozilla.dom.indexedDB += [
 
 UNIFIED_SOURCES += [
     'AsyncConnectionHelper.cpp',
     'CheckPermissionsHelper.cpp',
     'Client.cpp',
     'DatabaseInfo.cpp',
     'FileInfo.cpp',
     'FileManager.cpp',
+    'FileSnapshot.cpp',
     'IDBDatabase.cpp',
     'IDBEvents.cpp',
     'IDBFactory.cpp',
+    'IDBFileHandle.cpp',
+    'IDBFileRequest.cpp',
     'IDBKeyRange.cpp',
     'IDBMutableFile.cpp',
     'IDBRequest.cpp',
     'IDBTransaction.cpp',
     'IDBWrapperCache.cpp',
     'IndexedDatabaseManager.cpp',
     'Key.cpp',
     'KeyPath.cpp',
rename from dom/filehandle/test/dummy_worker.js
rename to dom/indexedDB/test/dummy_worker.js
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -10,16 +10,33 @@ var utils = SpecialPowers.getDOMWindowUt
 
 if (!SpecialPowers.isMainProcess()) {
   window.runTest = function() {
     todo(false, "Test disabled in child processes, for now");
     finishTest();
   }
 }
 
+function getBuffer(size)
+{
+  let buffer = new ArrayBuffer(size);
+  is(buffer.byteLength, size, "Correct byte length");
+  return buffer;
+}
+
+function getRandomBuffer(size)
+{
+  let buffer = getBuffer(size);
+  let view = new Uint8Array(buffer);
+  for (let i = 0; i < size; i++) {
+    view[i] = parseInt(Math.random() * 255)
+  }
+  return buffer;
+}
+
 function getView(size)
 {
   let buffer = new ArrayBuffer(size);
   let view = new Uint8Array(buffer);
   is(buffer.byteLength, size, "Correct byte length");
   return view;
 }
 
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 support-files =
   bfcache_iframe1.html
   bfcache_iframe2.html
   blob_worker_crash_iframe.html
+  dummy_worker.js
   error_events_abort_transactions_iframe.html
   event_propagation_iframe.html
   exceptions_in_events_iframe.html
   file.js
   file_app_isolation.html
   file_app_isolation.js
   helpers.js
   leaving_page_iframe.html
@@ -88,24 +89,57 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_file_resurrection_delete.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_file_resurrection_transaction_abort.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_file_sharing.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_file_transaction_abort.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+[test_filehandle_append_read_data.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_compat.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_getFile.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_lifetimes.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_lifetimes_nested.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_location.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_ordering.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_overlapping.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_progress_events.html]
+skip-if = buildapp == 'b2g' # b2g(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109) b2g-debug(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109) b2g-desktop(All of these fail fairly regularly with: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:109)
 [test_filehandle_quota.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+[test_filehandle_readonly_exceptions.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_request_readyState.html]
+skip-if = buildapp == 'b2g'
 [test_filehandle_serialization.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_filehandle_store_snapshot.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+[test_filehandle_stream_tracking.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_success_events_after_abort.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_truncate.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_workers.html]
+skip-if = buildapp == 'b2g'
+[test_filehandle_write_read_data.html]
+skip-if = buildapp == 'b2g'
 [test_getAll.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+[test_getFileId.html]
 [test_get_filehandle.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_globalObjects_content.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_global_data.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_index_empty_keyPath.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
rename from dom/filehandle/test/test_append_read_data.html
rename to dom/indexedDB/test/test_filehandle_append_read_data.html
--- a/dom/filehandle/test/test_append_read_data.html
+++ b/dom/indexedDB/test/test_filehandle_append_read_data.html
@@ -7,95 +7,104 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testString = "Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix. Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.";
     for (let i = 0; i < 5; i++) {
       testString += testString;
     }
 
     var testBuffer = getRandomBuffer(100000);
 
     var testBlob = new Blob([testBuffer], {type: "binary/random"});
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let location = 0;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let fileHandle = mutableFile.open("readwrite");
-      is(fileHandle.location, location, "Correct location");
+    let location = 0;
 
-      request = fileHandle.append(testString);
-      ok(fileHandle.location === null, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    let fileHandle = mutableFile.open("readwrite");
+    is(fileHandle.location, location, "Correct location");
+
+    request = fileHandle.append(testString);
+    ok(fileHandle.location === null, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location = 0;
-      request = fileHandle.readAsText(testString.length);
-      location += testString.length
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location = 0;
+    request = fileHandle.readAsText(testString.length);
+    location += testString.length
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let resultString = event.target.result;
-      ok(resultString == testString, "Correct string data");
+    let resultString = event.target.result;
+    ok(resultString == testString, "Correct string data");
 
-      request = fileHandle.append(testBuffer);
-      ok(fileHandle.location === null, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.append(testBuffer);
+    ok(fileHandle.location === null, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location = location;
-      request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
-      location += testBuffer.byteLength;
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location = location;
+    request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
+    location += testBuffer.byteLength;
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let resultBuffer = event.target.result;
-      ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
+    let resultBuffer = event.target.result;
+    ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
 
-      request = fileHandle.append(testBlob);
-      ok(fileHandle.location === null, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.append(testBlob);
+    ok(fileHandle.location === null, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location = location;
-      request = fileHandle.readAsArrayBuffer(testBlob.size);
-      location += testBlob.size;
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location = location;
+    request = fileHandle.readAsArrayBuffer(testBlob.size);
+    location += testBlob.size;
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      resultBuffer = event.target.result;
-      ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
+    resultBuffer = event.target.result;
+    ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
 
-      request = fileHandle.getMetadata({ size: true });
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.getMetadata({ size: true });
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let result = event.target.result;
-      is(result.size, location, "Correct size");
-    }
+    let result = event.target.result;
+    is(result.size, location, "Correct size");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_compat.html
rename to dom/indexedDB/test/test_filehandle_compat.html
--- a/dom/filehandle/test/test_compat.html
+++ b/dom/indexedDB/test/test_filehandle_compat.html
@@ -7,35 +7,44 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getFileHandle(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let fileHandle = event.target.result;
-      fileHandle.onerror = errorHandler;
+    request = db.mozCreateFileHandle("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let lockedFile = fileHandle.open();
-      ok(lockedFile.fileHandle === fileHandle, "Correct property");
+    let fileHandle = event.target.result;
+    fileHandle.onerror = errorHandler;
 
-      request = lockedFile.getMetadata({ size: true });
-      ok(request.lockedFile === lockedFile, "Correct property");
-    }
+    let lockedFile = fileHandle.open();
+    ok(lockedFile.fileHandle === fileHandle, "Correct property");
+
+    request = lockedFile.getMetadata({ size: true });
+    ok(request.lockedFile === lockedFile, "Correct property");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_getFile.html
rename to dom/indexedDB/test/test_filehandle_getFile.html
--- a/dom/filehandle/test/test_getFile.html
+++ b/dom/indexedDB/test/test_filehandle_getFile.html
@@ -7,39 +7,48 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      request = mutableFile.getFile();
-      ok(request instanceof DOMRequest, "Correct interface");
-      ok(!(request instanceof FileRequest), "Correct interface");
-      ok(!('fileHandle' in request), "Property should not exist");
-      ok(request.fileHandle === undefined, "Property should not exist");
-      ok(!('lockedFile' in request), "Property should not exist");
-      ok(request.lockedFile === undefined, "Property should not exist");
-      ok(!('onprogress' in request), "Property should not exist");
-      ok(request.onprogress === undefined, "Property should not exist");
-    }
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    request = mutableFile.getFile();
+    ok(request instanceof DOMRequest, "Correct interface");
+    ok(!(request instanceof IDBFileRequest), "Correct interface");
+    ok(!('fileHandle' in request), "Property should not exist");
+    ok(request.fileHandle === undefined, "Property should not exist");
+    ok(!('lockedFile' in request), "Property should not exist");
+    ok(request.lockedFile === undefined, "Property should not exist");
+    ok(!('onprogress' in request), "Property should not exist");
+    ok(request.onprogress === undefined, "Property should not exist");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_filehandle_lifetimes.html
rename to dom/indexedDB/test/test_filehandle_lifetimes.html
--- a/dom/filehandle/test/test_filehandle_lifetimes.html
+++ b/dom/indexedDB/test/test_filehandle_lifetimes.html
@@ -7,43 +7,52 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let db = event.target.result;
+    db.onerror = errorHandler;
+
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let fileHandle = mutableFile.open();
-      continueToNextStep();
-      yield undefined;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    let fileHandle = mutableFile.open();
+    continueToNextStep();
+    yield undefined;
 
-      try {
-        fileHandle.getMetadata({ size: true });
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "FileHandleInactiveError", "Good error.");
-        is(e.code, 0, "Good error code.");
-      }
+    try {
+      fileHandle.getMetadata({ size: true });
+      ok(false, "Should have thrown!");
+    }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "FileHandleInactiveError", "Good error.");
+      is(e.code, 0, "Good error code.");
     }
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_filehandle_lifetimes_nested.html
rename to dom/indexedDB/test/test_filehandle_lifetimes_nested.html
--- a/dom/filehandle/test/test_filehandle_lifetimes_nested.html
+++ b/dom/indexedDB/test/test_filehandle_lifetimes_nested.html
@@ -7,55 +7,64 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let fileHandle = mutableFile.open();
-
-      let fileHandle2;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let comp = SpecialPowers.wrap(SpecialPowers.Components);
-      let thread = comp.classes["@mozilla.org/thread-manager;1"]
-                       .getService(comp.interfaces.nsIThreadManager)
-                       .currentThread;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    let fileHandle = mutableFile.open();
+
+    let fileHandle2;
 
-      let eventHasRun;
+    let comp = SpecialPowers.wrap(SpecialPowers.Components);
+    let thread = comp.classes["@mozilla.org/thread-manager;1"]
+                     .getService(comp.interfaces.nsIThreadManager)
+                     .currentThread;
 
-      thread.dispatch(function() {
-        eventHasRun = true;
+    let eventHasRun;
 
-        fileHandle2 = mutableFile.open();
-      }, SpecialPowers.Ci.nsIThread.DISPATCH_NORMAL);
+    thread.dispatch(function() {
+      eventHasRun = true;
 
-      while (!eventHasRun) {
-        thread.processNextEvent(false);
-      }
+      fileHandle2 = mutableFile.open();
+    }, SpecialPowers.Ci.nsIThread.DISPATCH_NORMAL);
 
-      ok(fileHandle2, "Non-null fileHandle2");
+    while (!eventHasRun) {
+      thread.processNextEvent(false);
+    }
 
-      continueToNextStep();
-      yield undefined;
-    }
+    ok(fileHandle2, "Non-null fileHandle2");
+
+    continueToNextStep();
+    yield undefined;
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_location.html
rename to dom/indexedDB/test/test_filehandle_location.html
--- a/dom/filehandle/test/test_location.html
+++ b/dom/indexedDB/test/test_filehandle_location.html
@@ -7,90 +7,99 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let fileHandle = mutableFile.open("readwrite");
-      is(fileHandle.location, 0, "Correct location");
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      fileHandle.location = 100000;
-      is(fileHandle.location, 100000, "Correct location");
+    let fileHandle = mutableFile.open("readwrite");
+    is(fileHandle.location, 0, "Correct location");
 
-      fileHandle.location = null;
-      ok(fileHandle.location === null, "Correct location");
+    fileHandle.location = 100000;
+    is(fileHandle.location, 100000, "Correct location");
+
+    fileHandle.location = null;
+    ok(fileHandle.location === null, "Correct location");
 
-      try {
-        fileHandle.readAsArrayBuffer(1);
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "InvalidStateError", "Good error.");
-        is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
-      }
+    try {
+      fileHandle.readAsArrayBuffer(1);
+      ok(false, "Should have thrown!");
+    }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "InvalidStateError", "Good error.");
+      is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
+    }
 
-      try {
-        fileHandle.readAsText(1);
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "InvalidStateError", "Good error.");
-        is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
-      }
+    try {
+      fileHandle.readAsText(1);
+      ok(false, "Should have thrown!");
+    }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "InvalidStateError", "Good error.");
+      is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
+    }
 
-      try {
-        fileHandle.write({});
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "InvalidStateError", "Good error.");
-        is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
-      }
+    try {
+      fileHandle.write({});
+      ok(false, "Should have thrown!");
+    }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "InvalidStateError", "Good error.");
+      is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
+    }
 
-      request = fileHandle.append("foo");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.append("foo");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      ok(fileHandle.location === null, "Correct location");
+    ok(fileHandle.location === null, "Correct location");
 
-      try {
-        fileHandle.truncate();
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "InvalidStateError", "Good error.");
-        is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
-      }
+    try {
+      fileHandle.truncate();
+      ok(false, "Should have thrown!");
+    }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "InvalidStateError", "Good error.");
+      is(e.code, DOMException.INVALID_STATE_ERR, "Good error code.");
+    }
 
-      request = fileHandle.truncate(0);
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.truncate(0);
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      is(fileHandle.location, 0, "Correct location");
-    }
+    is(fileHandle.location, 0, "Correct location");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_filehandle_ordering.html
rename to dom/indexedDB/test/test_filehandle_ordering.html
--- a/dom/filehandle/test/test_filehandle_ordering.html
+++ b/dom/indexedDB/test/test_filehandle_ordering.html
@@ -7,48 +7,57 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let fileHandle1 = mutableFile.open("readwrite");
-      let fileHandle2 = mutableFile.open("readwrite");
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let request1 = fileHandle2.write("2");
-      let request2 = fileHandle1.write("1");
+    let fileHandle1 = mutableFile.open("readwrite");
+    let fileHandle2 = mutableFile.open("readwrite");
 
-      fileHandle1.oncomplete = grabEventAndContinueHandler;
-      fileHandle2.oncomplete = grabEventAndContinueHandler;
+    let request1 = fileHandle2.write("2");
+    let request2 = fileHandle1.write("1");
+
+    fileHandle1.oncomplete = grabEventAndContinueHandler;
+    fileHandle2.oncomplete = grabEventAndContinueHandler;
 
-      yield undefined;
-      yield undefined;
+    yield undefined;
+    yield undefined;
 
-      let fileHandle3 = mutableFile.open("readonly");
-      let request3 = fileHandle3.readAsText(1);
-      request3.onsuccess = grabEventAndContinueHandler;
+    let fileHandle3 = mutableFile.open("readonly");
+    let request3 = fileHandle3.readAsText(1);
+    request3.onsuccess = grabEventAndContinueHandler;
 
-      event = yield undefined;
-      is(event.target.result, "2", "File handles were ordered properly.");
-    }
+    event = yield undefined;
+    is(event.target.result, "2", "File handles were ordered properly.");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_overlapping_filehandles.html
rename to dom/indexedDB/test/test_filehandle_overlapping.html
--- a/dom/filehandle/test/test_overlapping_filehandles.html
+++ b/dom/indexedDB/test/test_filehandle_overlapping.html
@@ -7,59 +7,68 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      for (let i = 0; i < 50; i++) {
-        let stepNumber = 0;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-        request = mutableFile.open("readwrite").append("string1");
-        request.onsuccess = function(event) {
-          is(stepNumber, 1, "This callback came first");
-          stepNumber++;
-          event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
-        }
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    for (let i = 0; i < 50; i++) {
+      let stepNumber = 0;
 
-        request = mutableFile.open("readwrite").append("string2");
-        request.onsuccess = function(event) {
-          is(stepNumber, 2, "This callback came second");
-          stepNumber++;
-          event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
-        }
+      request = mutableFile.open("readwrite").append("string1");
+      request.onsuccess = function(event) {
+        is(stepNumber, 1, "This callback came first");
+        stepNumber++;
+        event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
+      }
 
-        request = mutableFile.open("readwrite").append("string3");
-        request.onsuccess = function(event) {
-          is(stepNumber, 3, "This callback came third");
-          stepNumber++;
-          event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
-        }
+      request = mutableFile.open("readwrite").append("string2");
+      request.onsuccess = function(event) {
+        is(stepNumber, 2, "This callback came second");
+        stepNumber++;
+        event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
+      }
 
+      request = mutableFile.open("readwrite").append("string3");
+      request.onsuccess = function(event) {
+        is(stepNumber, 3, "This callback came third");
         stepNumber++;
-        yield undefined; yield undefined; yield undefined;;
+        event.target.fileHandle.oncomplete = grabEventAndContinueHandler;
+      }
 
-        is(stepNumber, 4, "All callbacks received");
-      }
+      stepNumber++;
+      yield undefined; yield undefined; yield undefined;;
+
+      is(stepNumber, 4, "All callbacks received");
     }
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_progress_events.html
rename to dom/indexedDB/test/test_filehandle_progress_events.html
--- a/dom/filehandle/test/test_progress_events.html
+++ b/dom/indexedDB/test/test_filehandle_progress_events.html
@@ -7,64 +7,73 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testBuffer = getRandomBuffer(100000);
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let fileHandle = mutableFile.open("readwrite");
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let sum = 0;
+    let fileHandle = mutableFile.open("readwrite");
+
+    let sum = 0;
 
-      request = fileHandle.write(testBuffer);
-      request.onprogress = function(event) {
-        let loaded = event.loaded;
-        let total = event.total;
-        ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
-        is(total, testBuffer.byteLength, "Correct total progress");
-        sum += event.loaded - sum;
-      }
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.write(testBuffer);
+    request.onprogress = function(event) {
+      let loaded = event.loaded;
+      let total = event.total;
+      ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
+      is(total, testBuffer.byteLength, "Correct total progress");
+      sum += event.loaded - sum;
+    }
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      is(sum, testBuffer.byteLength, "Correct loaded progress sum");
-
-      sum = 0;
+    is(sum, testBuffer.byteLength, "Correct loaded progress sum");
 
-      fileHandle.location = 0;
-      request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
-      request.onprogress = function(event) {
-        let loaded = event.loaded;
-        let total = event.total;
-        ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
-        is(total, testBuffer.byteLength, "Correct total progress");
-        sum += event.loaded - sum;
-      }
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    sum = 0;
 
-      is(sum, testBuffer.byteLength, "Correct loaded progress sum");
+    fileHandle.location = 0;
+    request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
+    request.onprogress = function(event) {
+      let loaded = event.loaded;
+      let total = event.total;
+      ok(loaded >= 0 && loaded <= total, "Correct loaded progress");
+      is(total, testBuffer.byteLength, "Correct total progress");
+      sum += event.loaded - sum;
     }
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    is(sum, testBuffer.byteLength, "Correct loaded progress sum");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_readonly_filehandles.html
rename to dom/indexedDB/test/test_filehandle_readonly_exceptions.html
--- a/dom/filehandle/test/test_readonly_filehandles.html
+++ b/dom/indexedDB/test/test_filehandle_readonly_exceptions.html
@@ -7,67 +7,76 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      request = mutableFile.open("readwrite").write({});
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
-
-      is(event.target.fileHandle.mode, "readwrite", "Correct mode");
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      try {
-        mutableFile.open().write({});
-        ok(false, "Writing to a readonly file handle should fail!");
-      }
-      catch (e) {
-        ok(true, "Writing to a readonly file handle failed");
-      }
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    request = mutableFile.open("readwrite").write({});
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    is(event.target.fileHandle.mode, "readwrite", "Correct mode");
 
-      try {
-        mutableFile.open().append({});
-        ok(false, "Appending to a readonly file handle should fail!");
-      }
-      catch (e) {
-        ok(true, "Appending to a readonly file handle failed");
-      }
+    try {
+      mutableFile.open().write({});
+      ok(false, "Writing to a readonly file handle should fail!");
+    }
+    catch (e) {
+      ok(true, "Writing to a readonly file handle failed");
+    }
 
-      try {
-        mutableFile.open().truncate({});
-        ok(false, "Truncating a readonly file handle should fail!");
-      }
-      catch (e) {
-        ok(true, "Truncating a readonly file handle failed");
-      }
+    try {
+      mutableFile.open().append({});
+      ok(false, "Appending to a readonly file handle should fail!");
+    }
+    catch (e) {
+      ok(true, "Appending to a readonly file handle failed");
+    }
 
-      try {
-        mutableFile.open().flush({});
-        ok(false, "Flushing a readonly file handle should fail!");
-      }
-      catch (e) {
-        ok(true, "Flushing a readonly file handle failed");
-      }
+    try {
+      mutableFile.open().truncate({});
+      ok(false, "Truncating a readonly file handle should fail!");
+    }
+    catch (e) {
+      ok(true, "Truncating a readonly file handle failed");
+    }
+
+    try {
+      mutableFile.open().flush({});
+      ok(false, "Flushing a readonly file handle should fail!");
+    }
+    catch (e) {
+      ok(true, "Flushing a readonly file handle failed");
     }
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_request_readyState.html
rename to dom/indexedDB/test/test_filehandle_request_readyState.html
--- a/dom/filehandle/test/test_request_readyState.html
+++ b/dom/indexedDB/test/test_filehandle_request_readyState.html
@@ -7,51 +7,64 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      is(request.readyState, "pending", "Correct readyState");
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    is(request.readyState, "pending", "Correct readyState");
+
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
 
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    is(request.readyState, "done", "Correct readyState");
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      is(request.readyState, "done", "Correct readyState");
+    request = db.createMutableFile("test.txt");
+    is(request.readyState, "pending", "Correct readyState");
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let fileHandle = mutableFile.open("readwrite");
-      request = fileHandle.write("string");
-      is(request.readyState, "pending", "Correct readyState");
+    is(request.readyState, "done", "Correct readyState");
 
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      is(request.readyState, "done", "Correct readyState");
+    let fileHandle = mutableFile.open("readwrite");
+    request = fileHandle.write("string");
+    is(request.readyState, "pending", "Correct readyState");
 
-      fileHandle.location = 0;
-      request = fileHandle.readAsText(6);
-      request.onsuccess = grabEventAndContinueHandler;
-      is(request.readyState, "pending", "Correct readyState");
-      event = yield undefined;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    is(request.readyState, "done", "Correct readyState");
 
-      ok(event.target.result, "Got something");
-      is(request.readyState, "done", "Correct readyState");
-    }
+    fileHandle.location = 0;
+    request = fileHandle.readAsText(6);
+    request.onsuccess = grabEventAndContinueHandler;
+    is(request.readyState, "pending", "Correct readyState");
+    event = yield undefined;
+
+    ok(event.target.result, "Got something");
+    is(request.readyState, "done", "Correct readyState");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_stream_tracking.html
rename to dom/indexedDB/test/test_filehandle_stream_tracking.html
--- a/dom/filehandle/test/test_stream_tracking.html
+++ b/dom/indexedDB/test/test_filehandle_stream_tracking.html
@@ -7,97 +7,106 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testBuffer = getRandomBuffer(100000);
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let fileHandle = mutableFile.open("readwrite");
-
-      request = fileHandle.write(testBuffer);
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      request = mutableFile.getFile();
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let file = event.target.result;
+    let fileHandle = mutableFile.open("readwrite");
+
+    request = fileHandle.write(testBuffer);
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let resultBuffer1;
-      let resultBuffer2;
+    request = mutableFile.getFile();
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let reader1 = new FileReader();
-      reader1.readAsArrayBuffer(file);
-      reader1.onerror = errorHandler;
-      reader1.onload = function(event)
-      {
-        resultBuffer1 = event.target.result;
+    let file = event.target.result;
+
+    let resultBuffer1;
+    let resultBuffer2;
 
-        let reader = new FileReader();
-        try {
-          reader.readAsArrayBuffer(file);
-          ok(false, "Should have thrown!");
-        }
-        catch (e) {
-          ok(e instanceof DOMException, "Got exception.");
-          is(e.name, "FileHandleInactiveError", "Good error.");
-          is(e.code, 0, "Good error code.");
-        }
+    let reader1 = new FileReader();
+    reader1.readAsArrayBuffer(file);
+    reader1.onerror = errorHandler;
+    reader1.onload = function(event)
+    {
+      resultBuffer1 = event.target.result;
 
-        if (resultBuffer2) {
-          testGenerator.next();
-        }
+      let reader = new FileReader();
+      try {
+        reader.readAsArrayBuffer(file);
+        ok(false, "Should have thrown!");
+      }
+      catch (e) {
+        ok(e instanceof DOMException, "Got exception.");
+        is(e.name, "FileHandleInactiveError", "Good error.");
+        is(e.code, 0, "Good error code.");
       }
 
-      let reader2 = new FileReader();
-      reader2.readAsArrayBuffer(file);
-      reader2.onerror = errorHandler;
-      reader2.onload = function(event)
-      {
-        resultBuffer2 = event.target.result;
+      if (resultBuffer2) {
+        testGenerator.next();
+      }
+    }
 
-        let reader = new FileReader();
-        try {
-          reader.readAsArrayBuffer(file);
-          ok(false, "Should have thrown!");
-        }
-        catch (e) {
-          ok(e instanceof DOMException, "Got exception.");
-          is(e.name, "FileHandleInactiveError", "Good error.");
-          is(e.code, 0, "Good error code.");
-        }
+    let reader2 = new FileReader();
+    reader2.readAsArrayBuffer(file);
+    reader2.onerror = errorHandler;
+    reader2.onload = function(event)
+    {
+      resultBuffer2 = event.target.result;
 
-        if (resultBuffer1) {
-          testGenerator.next();
-        }
+      let reader = new FileReader();
+      try {
+        reader.readAsArrayBuffer(file);
+        ok(false, "Should have thrown!");
+      }
+      catch (e) {
+        ok(e instanceof DOMException, "Got exception.");
+        is(e.name, "FileHandleInactiveError", "Good error.");
+        is(e.code, 0, "Good error code.");
       }
 
-      yield undefined;
+      if (resultBuffer1) {
+        testGenerator.next();
+      }
+    }
 
-      ok(compareBuffers(resultBuffer1, testBuffer), "Correct data");
-      ok(compareBuffers(resultBuffer2, testBuffer), "Correct data");
-    }
+    yield undefined;
+
+    ok(compareBuffers(resultBuffer1, testBuffer), "Correct data");
+    ok(compareBuffers(resultBuffer2, testBuffer), "Correct data");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_success_events_after_abort.html
rename to dom/indexedDB/test/test_filehandle_success_events_after_abort.html
--- a/dom/filehandle/test/test_success_events_after_abort.html
+++ b/dom/indexedDB/test/test_filehandle_success_events_after_abort.html
@@ -7,60 +7,69 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    const name = window.location.pathname;
+
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
-
-      let fileHandle = mutableFile.open();
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.oncomplete = unexpectedSuccessHandler;
-      fileHandle.onabort = grabEventAndContinueHandler;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let sawError = false;
+    let fileHandle = mutableFile.open();
+
+    fileHandle.oncomplete = unexpectedSuccessHandler;
+    fileHandle.onabort = grabEventAndContinueHandler;
 
-      request = fileHandle.getMetadata({ size: true });
-      request.onsuccess = unexpectedSuccessHandler;
-      request.onerror = function(event) {
-        is(event.target.error.name, "AbortError", "Good error");
-        sawError = true;
-        event.stopPropagation();
-      }
+    let sawError = false;
 
-      fileHandle.abort();
+    request = fileHandle.getMetadata({ size: true });
+    request.onsuccess = unexpectedSuccessHandler;
+    request.onerror = function(event) {
+      is(event.target.error.name, "AbortError", "Good error");
+      sawError = true;
+      event.stopPropagation();
+    }
 
-      event = yield undefined;
+    fileHandle.abort();
 
-      is(event.type, "abort", "Got abort event");
-      is(sawError, true, "Saw getMetadata() error");
+    event = yield undefined;
+
+    is(event.type, "abort", "Got abort event");
+    is(sawError, true, "Saw getMetadata() error");
 
-      // Make sure the success event isn't queued somehow.
-      let comp = SpecialPowers.wrap(SpecialPowers.Components);
-      var thread = comp.classes["@mozilla.org/thread-manager;1"]
-                       .getService(comp.interfaces.nsIThreadManager)
-                       .currentThread;
-      while (thread.hasPendingEvents()) {
-        thread.processNextEvent(false);
-      }
+    // Make sure the success event isn't queued somehow.
+    let comp = SpecialPowers.wrap(SpecialPowers.Components);
+    var thread = comp.classes["@mozilla.org/thread-manager;1"]
+                     .getService(comp.interfaces.nsIThreadManager)
+                     .currentThread;
+    while (thread.hasPendingEvents()) {
+      thread.processNextEvent(false);
     }
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script> <!-- This is included just to skip this test in test_ipc.html -->
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_truncate.html
rename to dom/indexedDB/test/test_filehandle_truncate.html
--- a/dom/filehandle/test/test_truncate.html
+++ b/dom/indexedDB/test/test_filehandle_truncate.html
@@ -7,76 +7,85 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testBuffer = getRandomBuffer(100000);
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.bin");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
+
+    request = db.createMutableFile("test.bin");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
+
+    let fileHandle = mutableFile.open("readwrite");
+    request = fileHandle.write(testBuffer);
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let fileHandle = mutableFile.open("readwrite");
-      request = fileHandle.write(testBuffer);
+    is(fileHandle.location, 100000, "Correct location");
+
+    for (let i = 0; i < 10; i++) {
+      let location = fileHandle.location - 10000;
+      fileHandle.location = location;
+
+      request = fileHandle.truncate();
       request.onsuccess = grabEventAndContinueHandler;
       event = yield undefined;
 
-      is(fileHandle.location, 100000, "Correct location");
-
-      for (let i = 0; i < 10; i++) {
-        let location = fileHandle.location - 10000;
-        fileHandle.location = location;
-
-        request = fileHandle.truncate();
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield undefined;
+      is(fileHandle.location, location, "Correct location");
 
-        is(fileHandle.location, location, "Correct location");
-
-        request = fileHandle.getMetadata({ size: true });
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield undefined;
-
-        is(event.target.result.size, location, "Correct size");
-      }
-
-      request = fileHandle.write(testBuffer);
+      request = fileHandle.getMetadata({ size: true });
       request.onsuccess = grabEventAndContinueHandler;
       event = yield undefined;
 
-      let location = fileHandle.location;
-      for (let i = 0; i < 10; i++) {
-        location -= 10000;
+      is(event.target.result.size, location, "Correct size");
+    }
 
-        request = fileHandle.truncate(location);
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield undefined;
+    request = fileHandle.write(testBuffer);
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let location = fileHandle.location;
+    for (let i = 0; i < 10; i++) {
+      location -= 10000;
 
-        is(fileHandle.location, location, "Correct location");
+      request = fileHandle.truncate(location);
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield undefined;
+
+      is(fileHandle.location, location, "Correct location");
 
-        request = fileHandle.getMetadata({ size: true });
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield undefined;
+      request = fileHandle.getMetadata({ size: true });
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield undefined;
 
-        is(event.target.result.size, location, "Correct size");
-      }
+      is(event.target.result.size, location, "Correct size");
     }
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_workers.html
rename to dom/indexedDB/test/test_filehandle_workers.html
--- a/dom/filehandle/test/test_workers.html
+++ b/dom/indexedDB/test/test_filehandle_workers.html
@@ -7,55 +7,64 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testBuffer = getRandomBuffer(100000);
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let fileHandle = mutableFile.open("readwrite");
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      request = fileHandle.write(testBuffer);
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    let fileHandle = mutableFile.open("readwrite");
 
-      request = mutableFile.getFile();
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.write(testBuffer);
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let file = event.target.result;
+    request = mutableFile.getFile();
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
+
+    let file = event.target.result;
 
-      var worker = new Worker("dummy_worker.js");
-      try {
-        worker.postMessage(file);
-        ok(false, "Should have thrown!");
-      }
-      catch (e) {
-        ok(e instanceof DOMException, "Got exception.");
-        is(e.name, "DataCloneError", "Good error.");
-        is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
-      }
-      worker.terminate();
+    var worker = new Worker("dummy_worker.js");
+    try {
+      worker.postMessage(file);
+      ok(false, "Should have thrown!");
     }
+    catch (e) {
+      ok(e instanceof DOMException, "Got exception.");
+      is(e.name, "DataCloneError", "Good error.");
+      is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
+    }
+    worker.terminate();
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_write_read_data.html
rename to dom/indexedDB/test/test_filehandle_write_read_data.html
--- a/dom/filehandle/test/test_write_read_data.html
+++ b/dom/indexedDB/test/test_filehandle_write_read_data.html
@@ -7,95 +7,104 @@
   <title>File Handle Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
+    const name = window.location.pathname;
+
     var testString = "Lorem ipsum his ponderum delicatissimi ne, at noster dolores urbanitas pro, cibo elaboraret no his. Ea dicunt maiorum usu. Ad appareat facilisis mediocritatem eos. Tale graeci mentitum in eos, hinc insolens at nam. Graecis nominavi aliquyam eu vix. Id solet assentior sadipscing pro. Et per atqui graecis, usu quot viris repudiandae ei, mollis evertitur an nam. At nam dolor ignota, liber labore omnesque ea mei, has movet voluptaria in. Vel an impetus omittantur. Vim movet option salutandi ex, ne mei ignota corrumpit. Mucius comprehensam id per. Est ea putant maiestatis.";
     for (let i = 0; i < 5; i++) {
       testString += testString;
     }
 
     var testBuffer = getRandomBuffer(100000);
 
     var testBlob = new Blob([testBuffer], {type: "binary/random"});
 
-    for each (let fileStorage in fileStorages) {
-      let request = getMutableFile(fileStorage.key, "test.txt");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield undefined;
+    let request = indexedDB.open(name, 1);
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    let event = yield undefined;
+
+    let db = event.target.result;
+    db.onerror = errorHandler;
 
-      let mutableFile = event.target.result;
-      mutableFile.onerror = errorHandler;
+    request = db.createMutableFile("test.txt");
+    request.onerror = errorHandler;
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let location = 0;
+    let mutableFile = event.target.result;
+    mutableFile.onerror = errorHandler;
 
-      let fileHandle = mutableFile.open("readwrite");
-      is(fileHandle.location, location, "Correct location");
+    let location = 0;
 
-      request = fileHandle.write(testString);
-      location += testString.length;
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    let fileHandle = mutableFile.open("readwrite");
+    is(fileHandle.location, location, "Correct location");
+
+    request = fileHandle.write(testString);
+    location += testString.length;
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location = 0;
-      request = fileHandle.readAsText(testString.length);
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location = 0;
+    request = fileHandle.readAsText(testString.length);
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let resultString = event.target.result;
-      ok(resultString == testString, "Correct string data");
+    let resultString = event.target.result;
+    ok(resultString == testString, "Correct string data");
 
-      request = fileHandle.write(testBuffer);
-      location += testBuffer.byteLength;
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.write(testBuffer);
+    location += testBuffer.byteLength;
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location -= testBuffer.byteLength;
-      request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location -= testBuffer.byteLength;
+    request = fileHandle.readAsArrayBuffer(testBuffer.byteLength);
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let resultBuffer = event.target.result;
-      ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
+    let resultBuffer = event.target.result;
+    ok(compareBuffers(resultBuffer, testBuffer), "Correct array buffer data");
 
-      request = fileHandle.write(testBlob);
-      location += testBlob.size;
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.write(testBlob);
+    location += testBlob.size;
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      fileHandle.location -= testBlob.size;
-      request = fileHandle.readAsArrayBuffer(testBlob.size);
-      is(fileHandle.location, location, "Correct location");
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    fileHandle.location -= testBlob.size;
+    request = fileHandle.readAsArrayBuffer(testBlob.size);
+    is(fileHandle.location, location, "Correct location");
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      resultBuffer = event.target.result;
-      ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
+    resultBuffer = event.target.result;
+    ok(compareBuffers(resultBuffer, testBuffer), "Correct blob data");
 
-      request = fileHandle.getMetadata({ size: true });
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield undefined;
+    request = fileHandle.getMetadata({ size: true });
+    request.onsuccess = grabEventAndContinueHandler;
+    event = yield undefined;
 
-      let result = event.target.result;
-      is(result.size, location, "Correct size");
-    }
+    let result = event.target.result;
+    is(result.size, location, "Correct size");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
rename from dom/filehandle/test/test_getFileId.html
rename to dom/indexedDB/test/test_getFileId.html
--- a/dom/filehandle/test/test_getFileId.html
+++ b/dom/indexedDB/test/test_getFileId.html
@@ -17,15 +17,16 @@
 
     id = getFileId(getRandomBlob(100));
     ok(id == -1, "Correct id");
 
     finishTest();
     yield undefined;
   }
   </script>
+  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -365,24 +365,20 @@ var interfaceNamesInGlobalScope =
     "EventSource",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "EventTarget",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "External", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "File",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "FileHandle",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "FileList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FileReader",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "FileRequest",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "FMRadio", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FocusEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "FormData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "GainNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -561,16 +557,20 @@ var interfaceNamesInGlobalScope =
     "IDBCursor",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBCursorWithValue",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBDatabase",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBFactory",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "IDBFileHandle",
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    "IDBFileRequest",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBIndex",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBKeyRange",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBMutableFile",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "IDBObjectStore",
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -733,18 +733,16 @@ var interfaceNamesInGlobalScope =
     {name: "MozWifiStatusChangeEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pGroupOwner", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pManager", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "MutableFile",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "MutationEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MutationObserver",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MutationRecord",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Navigator",
 // IMPORTANT: Do not change this list without review from a DOM peer!
rename from dom/webidl/FileHandle.webidl
rename to dom/webidl/IDBFileHandle.webidl
--- a/dom/webidl/FileHandle.webidl
+++ b/dom/webidl/IDBFileHandle.webidl
@@ -1,50 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtaone at http://mozilla.org/MPL/2.0/. */
 
-dictionary DOMFileMetadataParameters
+dictionary IDBFileMetadataParameters
 {
   boolean size = true;
   boolean lastModified = true;
 };
 
-interface FileHandle : EventTarget
+interface IDBFileHandle : EventTarget
 {
-  readonly attribute MutableFile? mutableFile;
+  readonly attribute IDBMutableFile? mutableFile;
   // this is deprecated due to renaming in the spec
-  readonly attribute MutableFile? fileHandle; // now mutableFile
+  readonly attribute IDBMutableFile? fileHandle; // now mutableFile
   readonly attribute FileMode mode;
   readonly attribute boolean active;
   attribute unsigned long long? location;
 
   [Throws]
-  FileRequest? getMetadata(optional DOMFileMetadataParameters parameters);
+  IDBFileRequest? getMetadata(optional IDBFileMetadataParameters parameters);
   [Throws]
-  FileRequest? readAsArrayBuffer(unsigned long long size);
+  IDBFileRequest? readAsArrayBuffer(unsigned long long size);
   [Throws]
-  FileRequest? readAsText(unsigned long long size,
-                         optional DOMString? encoding = null);
+  IDBFileRequest? readAsText(unsigned long long size,
+                             optional DOMString? encoding = null);
 
   [Throws]
-  FileRequest? write(ArrayBuffer value);
+  IDBFileRequest? write(ArrayBuffer value);
   [Throws]
-  FileRequest? write(Blob value);
+  IDBFileRequest? write(Blob value);
   [Throws]
-  FileRequest? write(DOMString value);
+  IDBFileRequest? write(DOMString value);
   [Throws]
-  FileRequest? append(ArrayBuffer value);
+  IDBFileRequest? append(ArrayBuffer value);
   [Throws]
-  FileRequest? append(Blob value);
+  IDBFileRequest? append(Blob value);
   [Throws]
-  FileRequest? append(DOMString value);
+  IDBFileRequest? append(DOMString value);
   [Throws]
-  FileRequest? truncate(optional unsigned long long size);
+  IDBFileRequest? truncate(optional unsigned long long size);
   [Throws]
-  FileRequest? flush();
+  IDBFileRequest? flush();
   [Throws]
   void abort();
 
   attribute EventHandler oncomplete;
   attribute EventHandler onabort;
   attribute EventHandler onerror;
 };
rename from dom/webidl/FileRequest.webidl
rename to dom/webidl/IDBFileRequest.webidl
--- a/dom/webidl/FileRequest.webidl
+++ b/dom/webidl/IDBFileRequest.webidl
@@ -1,14 +1,13 @@
 /* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-interface FileRequest : DOMRequest {
-  readonly attribute FileHandle? fileHandle;
+interface IDBFileRequest : DOMRequest {
+  readonly attribute IDBFileHandle? fileHandle;
   // this is deprecated due to renaming in the spec
-  readonly attribute FileHandle? lockedFile; // now fileHandle
+  readonly attribute IDBFileHandle? lockedFile; // now fileHandle
 
   attribute EventHandler onprogress;
 };
-
--- a/dom/webidl/IDBMutableFile.webidl
+++ b/dom/webidl/IDBMutableFile.webidl
@@ -1,8 +1,20 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-interface IDBMutableFile : MutableFile {
+interface IDBMutableFile : EventTarget {
+  readonly attribute DOMString name;
+  readonly attribute DOMString type;
+
   readonly attribute IDBDatabase database;
+
+  [Throws]
+  IDBFileHandle open(optional FileMode mode = "readonly");
+
+  [Throws]
+  DOMRequest getFile();
+
+  attribute EventHandler onabort;
+  attribute EventHandler onerror;
 };
deleted file mode 100644
--- a/dom/webidl/MutableFile.webidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-interface MutableFile : EventTarget {
-  readonly attribute DOMString name;
-  readonly attribute DOMString type;
-
-  [Throws]
-  FileHandle open(optional FileMode mode = "readonly");
-
-  [Throws]
-  DOMRequest getFile();
-
-  attribute EventHandler onabort;
-  attribute EventHandler onerror;
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -113,22 +113,20 @@ WEBIDL_FILES = [
     'DynamicsCompressorNode.webidl',
     'Element.webidl',
     'Event.webidl',
     'EventHandler.webidl',
     'EventListener.webidl',
     'EventSource.webidl',
     'EventTarget.webidl',
     'File.webidl',
-    'FileHandle.webidl',
     'FileList.webidl',
     'FileMode.webidl',
     'FileReader.webidl',
     'FileReaderSync.webidl',
-    'FileRequest.webidl',
     'FocusEvent.webidl',
     'FormData.webidl',
     'Function.webidl',
     'GainNode.webidl',
     'Geolocation.webidl',
     'GeometryUtils.webidl',
     'GetUserMediaRequest.webidl',
     'History.webidl',
@@ -206,16 +204,18 @@ WEBIDL_FILES = [
     'HTMLTitleElement.webidl',
     'HTMLTrackElement.webidl',
     'HTMLUListElement.webidl',
     'HTMLVideoElement.webidl',
     'IDBCursor.webidl',
     'IDBDatabase.webidl',
     'IDBEnvironment.webidl',
     'IDBFactory.webidl',
+    'IDBFileHandle.webidl',
+    'IDBFileRequest.webidl',
     'IDBIndex.webidl',
     'IDBKeyRange.webidl',
     'IDBMutableFile.webidl',
     'IDBObjectStore.webidl',
     'IDBOpenDBRequest.webidl',
     'IDBRequest.webidl',
     'IDBTransaction.webidl',
     'IDBVersionChangeEvent.webidl',
@@ -256,17 +256,16 @@ WEBIDL_FILES = [
     'MouseScrollEvent.webidl',
     'MozActivity.webidl',
     'MozMmsMessage.webidl',
     'MozMobileMessageManager.webidl',
     'MozNamedAttrMap.webidl',
     'MozPowerManager.webidl',
     'MozTimeManager.webidl',
     'MozWakeLock.webidl',
-    'MutableFile.webidl',
     'MutationEvent.webidl',
     'MutationObserver.webidl',
     'NativeOSFileInternals.webidl',
     'NetDashboard.webidl',
     'NetworkInformation.webidl',
     'NetworkOptions.webidl',
     'Node.webidl',
     'NodeFilter.webidl',