Bug 1173320 - patch 4/8 - Directory in FileList, r=smaug
☠☠ backed out by bd8284e36c7c ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Sat, 19 Mar 2016 14:33:43 +0100
changeset 313236 e94ced2f8e3cf5e639924b1800f93f1e79f4b1a9
parent 313235 401c1e7df8eaef6c5801a84d1abf05fdf0e3d2be
child 313237 56bbea4fe19990be2b05cd31371e76c01a252fc5
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1173320
milestone48.0a1
Bug 1173320 - patch 4/8 - Directory in FileList, r=smaug
dom/base/FileList.cpp
dom/base/FileList.h
dom/base/StructuredCloneHolder.cpp
dom/base/test/test_postMessages.html
dom/events/DataTransfer.cpp
dom/filesystem/CreateDirectoryTask.cpp
dom/filesystem/CreateFileTask.cpp
dom/filesystem/DeviceStorageFileSystem.cpp
dom/filesystem/DeviceStorageFileSystem.h
dom/filesystem/Directory.cpp
dom/filesystem/Directory.h
dom/filesystem/FileSystemBase.cpp
dom/filesystem/FileSystemBase.h
dom/filesystem/FileSystemPermissionRequest.cpp
dom/filesystem/GetDirectoryListingTask.cpp
dom/filesystem/GetFileOrDirectoryTask.cpp
dom/filesystem/OSFileSystem.cpp
dom/filesystem/OSFileSystem.h
dom/filesystem/RemoveTask.cpp
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/webidl/FileList.webidl
--- a/dom/base/FileList.cpp
+++ b/dom/base/FileList.cpp
@@ -1,48 +1,115 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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 "mozilla/dom/Directory.h"
 #include "mozilla/dom/FileList.h"
 #include "mozilla/dom/FileListBinding.h"
 #include "mozilla/dom/File.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFilesOrDirectories, mParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(FileList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(FileList)
 
 JSObject*
 FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::FileListBinding::Wrap(aCx, this, aGivenProto);
 }
 
+void
+FileList::Append(File* aFile)
+{
+  OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
+  element->SetAsFile() = aFile;
+}
+
+void
+FileList::Append(Directory* aDirectory)
+{
+  OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
+  element->SetAsDirectory() = aDirectory;
+}
+
 NS_IMETHODIMP
 FileList::GetLength(uint32_t* aLength)
 {
   *aLength = Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FileList::Item(uint32_t aIndex, nsISupports** aFile)
+FileList::Item(uint32_t aIndex, nsISupports** aValue)
+{
+  if (aIndex >= mFilesOrDirectories.Length()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (mFilesOrDirectories[aIndex].IsFile()) {
+    nsCOMPtr<nsIDOMBlob> file = mFilesOrDirectories[aIndex].GetAsFile();
+    file.forget(aValue);
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory());
+  RefPtr<Directory> directory = mFilesOrDirectories[aIndex].GetAsDirectory();
+  directory.forget(aValue);
+  return NS_OK;
+}
+
+void
+FileList::Item(uint32_t aIndex, Nullable<OwningFileOrDirectory>& aValue,
+               ErrorResult& aRv) const
 {
-  nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
-  file.forget(aFile);
-  return NS_OK;
+  if (aIndex >= mFilesOrDirectories.Length()) {
+    aValue.SetNull();
+    return;
+  }
+
+  aValue.SetValue(mFilesOrDirectories[aIndex]);
+}
+
+void
+FileList::IndexedGetter(uint32_t aIndex, bool& aFound,
+                        Nullable<OwningFileOrDirectory>& aFileOrDirectory,
+                        ErrorResult& aRv) const
+{
+  aFound = aIndex < mFilesOrDirectories.Length();
+  Item(aIndex, aFileOrDirectory, aRv);
+}
+
+void
+FileList::ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
+                     ErrorResult& aRv) const
+{
+  MOZ_ASSERT(aSequence.IsEmpty());
+  if (mFilesOrDirectories.IsEmpty()) {
+    return;
+  }
+
+  if (!aSequence.SetLength(mFilesOrDirectories.Length(),
+                           mozilla::fallible_t())) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
+    aSequence[i] = mFilesOrDirectories[i];
+  }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/FileList.h
+++ b/dom/base/FileList.h
@@ -3,16 +3,17 @@
 /* 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_FileList_h
 #define mozilla_dom_FileList_h
 
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDOMFileList.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
 class BlobImpls;
@@ -34,34 +35,32 @@ public:
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
-  bool Append(File* aFile)
-  {
-    return mFiles.AppendElement(aFile);
-  }
+  void Append(File* aFile);
+  void Append(Directory* aDirectory);
 
   bool Remove(uint32_t aIndex)
   {
-    if (aIndex < mFiles.Length()) {
-      mFiles.RemoveElementAt(aIndex);
+    if (aIndex < mFilesOrDirectories.Length()) {
+      mFilesOrDirectories.RemoveElementAt(aIndex);
       return true;
     }
 
     return false;
   }
 
   void Clear()
   {
-    return mFiles.Clear();
+    return mFilesOrDirectories.Clear();
   }
 
   static FileList* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMFileList> list_qi = do_QueryInterface(aSupports);
 
@@ -71,38 +70,41 @@ public:
       NS_ASSERTION(list_qi == static_cast<nsIDOMFileList*>(aSupports),
                    "Uh, fix QI!");
     }
 #endif
 
     return static_cast<FileList*>(aSupports);
   }
 
-  File* Item(uint32_t aIndex)
+  const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const
   {
-    return mFiles.SafeElementAt(aIndex);
+    MOZ_ASSERT(aIndex < Length());
+    return mFilesOrDirectories[aIndex];
   }
 
-  File* IndexedGetter(uint32_t aIndex, bool& aFound)
+  void Item(uint32_t aIndex,
+            Nullable<OwningFileOrDirectory>& aFileOrDirectory,
+            ErrorResult& aRv) const;
+
+  void IndexedGetter(uint32_t aIndex, bool& aFound,
+                     Nullable<OwningFileOrDirectory>& aFileOrDirectory,
+                     ErrorResult& aRv) const;
+
+  uint32_t Length() const
   {
-    aFound = aIndex < mFiles.Length();
-    if (!aFound) {
-      return nullptr;
-    }
-    return mFiles.ElementAt(aIndex);
+    return mFilesOrDirectories.Length();
   }
 
-  uint32_t Length()
-  {
-    return mFiles.Length();
-  }
+  void ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
+                  ErrorResult& aRv) const;
 
 private:
   ~FileList() {}
 
-  nsTArray<RefPtr<File>> mFiles;
+  nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
   nsCOMPtr<nsISupports> mParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FileList_h
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "StructuredCloneHolder.h"
 
 #include "ImageContainer.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/CryptoKey.h"
+#include "mozilla/dom/Directory.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileList.h"
 #include "mozilla/dom/FileListBinding.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
@@ -718,94 +719,139 @@ ReadFileList(JSContext* aCx,
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aReader);
 
   JS::Rooted<JS::Value> val(aCx);
   {
     RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
 
-    uint32_t tag, offset;
-    // Offset is the index of the blobImpl from which we can find the blobImpl
-    // for this FileList.
-    if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
-      return nullptr;
-    }
-
-    MOZ_ASSERT(tag == 0);
-
-    // |aCount| is the number of BlobImpls to use from the |offset|.
+    // |aCount| is the number of Files or Directory for this FileList.
     for (uint32_t i = 0; i < aCount; ++i) {
-      uint32_t index = offset + i;
-      MOZ_ASSERT(index < aHolder->BlobImpls().Length());
-
-      RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[index];
-      MOZ_ASSERT(blobImpl->IsFile());
-
-      ErrorResult rv;
-      blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
-      if (NS_WARN_IF(rv.Failed())) {
-        rv.SuppressException();
+      uint32_t tagOrDirectoryType, indexOrLengthOfString;
+      if (!JS_ReadUint32Pair(aReader, &tagOrDirectoryType,
+                             &indexOrLengthOfString)) {
         return nullptr;
       }
 
-      MOZ_ASSERT(blobImpl);
+      MOZ_ASSERT(tagOrDirectoryType == SCTAG_DOM_BLOB ||
+                 tagOrDirectoryType == Directory::eDOMRootDirectory ||
+                 tagOrDirectoryType == Directory::eNotDOMRootDirectory);
+
+      if (tagOrDirectoryType == SCTAG_DOM_BLOB) {
+        MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
+
+        RefPtr<BlobImpl> blobImpl =
+          aHolder->BlobImpls()[indexOrLengthOfString];
+        MOZ_ASSERT(blobImpl->IsFile());
 
-      RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
-      if (!fileList->Append(file)) {
+        ErrorResult rv;
+        blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
+        if (NS_WARN_IF(rv.Failed())) {
+          rv.SuppressException();
+          return nullptr;
+        }
+
+        RefPtr<File> file =
+          File::Create(aHolder->ParentDuringRead(), blobImpl);
+        MOZ_ASSERT(file);
+
+        fileList->Append(file);
+        continue;
+      }
+
+      nsAutoString path;
+      path.SetLength(indexOrLengthOfString);
+      size_t charSize = sizeof(nsString::char_type);
+      if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
+                        indexOrLengthOfString * charSize)) {
         return nullptr;
       }
+
+      nsCOMPtr<nsIFile> file;
+      nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
+                                          getter_AddRefs(file));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return nullptr;
+      }
+
+      RefPtr<Directory> directory =
+        Directory::Create(aHolder->ParentDuringRead(), file,
+                          (Directory::DirectoryType) tagOrDirectoryType);
+      fileList->Append(directory);
     }
 
     if (!ToJSValue(aCx, fileList, &val)) {
       return nullptr;
     }
   }
 
   return &val.toObject();
 }
 
 // The format of the FileList serialization is:
 // - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
-// - pair of ints: 0, The offset of the BlobImpl array
+// - for each element of the FileList:
+//   - if it's a blob:
+//    - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
+//       mBlobImplArray.
+//   - else:
+//     - pair of ints: 0/1 is root, string length
+//     - value string
 bool
 WriteFileList(JSStructuredCloneWriter* aWriter,
               FileList* aFileList,
               StructuredCloneHolder* aHolder)
 {
   MOZ_ASSERT(aWriter);
   MOZ_ASSERT(aFileList);
   MOZ_ASSERT(aHolder);
 
-  // A FileList is serialized writing the X number of elements and the offset
-  // from mBlobImplArray. The Read will take X elements from mBlobImplArray
-  // starting from the offset.
   if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
-                          aFileList->Length()) ||
-      !JS_WriteUint32Pair(aWriter, 0,
-                          aHolder->BlobImpls().Length())) {
+                          aFileList->Length())) {
     return false;
   }
 
   ErrorResult rv;
   nsTArray<RefPtr<BlobImpl>> blobImpls;
 
   for (uint32_t i = 0; i < aFileList->Length(); ++i) {
-    RefPtr<BlobImpl> blobImpl =
-      EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
-    if (NS_WARN_IF(rv.Failed())) {
-      rv.SuppressException();
+    const OwningFileOrDirectory& data = aFileList->UnsafeItem(i);
+
+    if (data.IsFile()) {
+      RefPtr<BlobImpl> blobImpl =
+        EnsureBlobForBackgroundManager(data.GetAsFile()->Impl(), nullptr, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        rv.SuppressException();
+        return false;
+      }
+
+      if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
+                              aHolder->BlobImpls().Length())) {
+        return false;
+      }
+
+      aHolder->BlobImpls().AppendElement(blobImpl);
+      continue;
+    }
+
+    MOZ_ASSERT(data.IsDirectory());
+
+    nsAutoString path;
+    data.GetAsDirectory()->GetFullRealPath(path);
+
+    size_t charSize = sizeof(nsString::char_type);
+    if (!JS_WriteUint32Pair(aWriter,
+                            (uint32_t)data.GetAsDirectory()->Type(),
+                            path.Length()) ||
+        !JS_WriteBytes(aWriter, path.get(), path.Length() * charSize)) {
       return false;
     }
-
-    MOZ_ASSERT(blobImpl);
-    blobImpls.AppendElement(blobImpl);
   }
 
-  aHolder->BlobImpls().AppendElements(blobImpls);
   return true;
 }
 
 // Read the WriteFormData for the format.
 JSObject*
 ReadFormData(JSContext* aCx,
              JSStructuredCloneReader* aReader,
              uint32_t aCount,
@@ -957,16 +1003,17 @@ StructuredCloneHolder::CustomReadHandler
 {
   MOZ_ASSERT(mSupportsCloning);
 
   if (aTag == SCTAG_DOM_BLOB) {
     return ReadBlob(aCx, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_FILELIST) {
+    MOZ_ASSERT(mSupportedContext == SameProcessSameThread);
     return ReadFileList(aCx, aReader, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_FORMDATA) {
     return ReadFormData(aCx, aReader, aIndex, this);
   }
 
   if (aTag == SCTAG_DOM_IMAGEBITMAP) {
@@ -997,17 +1044,17 @@ StructuredCloneHolder::CustomWriteHandle
   {
     Blob* blob = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
       return WriteBlob(aWriter, blob, this);
     }
   }
 
   // See if this is a FileList object.
-  {
+  if (mSupportedContext == SameProcessSameThread) {
     FileList* fileList = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
       return WriteFileList(aWriter, fileList, this);
     }
   }
 
   // See if this is a FormData object.
   {
--- a/dom/base/test/test_postMessages.html
+++ b/dom/base/test/test_postMessages.html
@@ -56,40 +56,40 @@ function compare(a, b) {
   }
 
   if (type != 'null') {
     is (a.toSource(), b.toSource(), 'Matching using toSource()');
   }
 }
 
 var clonableObjects = [
-  'hello world',
-  123,
-  null,
-  true,
-  new Date(),
-  [ 1, 'test', true, new Date() ],
-  { a: true, b:  null, c: new Date(), d: [ true, false, {} ] },
-  new Blob([123], { type: 'plain/text' }),
-  new ImageData(2, 2),
+  { crossThreads: true, data: 'hello world' },
+  { crossThreads: true, data: 123 },
+  { crossThreads: true, data: null },
+  { crossThreads: true, data: true },
+  { crossThreads: true, data: new Date() },
+  { crossThreads: true, data: [ 1, 'test', true, new Date() ] },
+  { crossThreads: true, data: { a: true, b:  null, c: new Date(), d: [ true, false, {} ] } },
+  { crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
+  { crossThreads: true, data: new ImageData(2, 2) },
 ];
 
 function create_fileList() {
   var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
 
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
 
     // Just a simple test
     var domFile = fileList.files[0];
     is(domFile.name, "prefs.js", "fileName should be prefs.js");
 
-    clonableObjects.push(fileList.files);
+    clonableObjects.push({ crossThreads: false, data: fileList.files });
     script.destroy();
     next();
   }
 
   script.addMessageListener("file.opened", onOpened);
   script.sendAsyncMessage("file.open");
 }
 
@@ -108,18 +108,26 @@ function runTests(obj) {
     var clonableObjectsId = 0;
     function runClonableTest() {
       if (clonableObjectsId >= clonableObjects.length) {
         resolve();
         return;
       }
 
       var object = clonableObjects[clonableObjectsId++];
-      obj.send(object, []).then(function(received) {
-        compare(received.data, object);
+
+      // If this test requires a cross-thread structured clone algorithm, maybe
+      // we have to skip it.
+      if (!object.crossThread && obj.crossThread) {
+        runClonableTest();
+        return;
+      }
+
+      obj.send(object.data, []).then(function(received) {
+        compare(received.data, object.data);
         runClonableTest();
       });
     }
 
     runClonableTest();
   })
 
   // transfering tests
@@ -198,16 +206,17 @@ function test_windowToWindow() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: e.ports });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: true,
+    crossThread: false,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         resolve = r;
 
         try {
           postMessage(what, '*', ports);
         } catch(e) {
           resolve = null;
@@ -251,16 +260,17 @@ function test_windowToIframeURL(url) {
   }
 
   var ifr = document.createElement('iframe');
   ifr.src = url;
   ifr.onload = function() {
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: false,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             ifr.contentWindow.postMessage(what, '*', ports);
           } catch(e) {
             resolve = null;
             rr();
@@ -298,16 +308,17 @@ function test_workers() {
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             w.postMessage(what, ports);
           } catch(e) {
             resolve = null;
             rr();
@@ -341,16 +352,17 @@ function test_broadcastChannel() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: [] });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: false,
+    crossThread: true,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         if (ports.length) {
           rr();
           return;
         }
 
         resolve = r;
@@ -386,16 +398,17 @@ function test_broadcastChannel_inWorkers
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: false,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           if (ports.length) {
             rr();
             return;
           }
 
           resolve = r;
@@ -427,16 +440,17 @@ function test_messagePort() {
     let tmp = resolve;
     resolve = null;
     tmp({ data: e.data, ports: e.ports });
   }
 
   runTests({
     clonableObjects: true,
     transferableObjects: true,
+    crossThread: true,
     send: function(what, ports) {
       return new Promise(function(r, rr) {
         resolve = r;
         try {
           mc.port1.postMessage(what, ports);
         } catch(e) {
           resolve = null;
           rr();
@@ -472,16 +486,17 @@ function test_messagePort_inWorkers() {
       let tmp = resolve;
       resolve = null;
       tmp({ data: e.data, ports: e.ports });
     }
 
     runTests({
       clonableObjects: true,
       transferableObjects: true,
+      crossThread: true,
       send: function(what, ports) {
         return new Promise(function(r, rr) {
           resolve = r;
           try {
             mc.port1.postMessage(what, ports);
           } catch(e) {
             resolve = null;
             rr();
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -335,20 +335,17 @@ DataTransfer::GetFileListInternal(ErrorR
         }
 
         MOZ_ASSERT(blobImpl->IsFile());
 
         domFile = File::Create(GetParentObject(), blobImpl);
         MOZ_ASSERT(domFile);
       }
 
-      if (!mFileList->Append(domFile)) {
-        aRv.Throw(NS_ERROR_FAILURE);
-        return nullptr;
-      }
+      mFileList->Append(domFile);
     }
   }
 
   return mFileList;
 }
 
 NS_IMETHODIMP
 DataTransfer::GetFiles(nsIDOMFileList** aFileList)
@@ -859,26 +856,19 @@ DataTransfer::GetFilesAndDirectories(Err
   if (!mFileList) {
     GetFiles(aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
   Sequence<OwningFileOrDirectory> filesAndDirsSeq;
-
-  if (mFileList && mFileList->Length()) {
-    if (!filesAndDirsSeq.SetLength(mFileList->Length(), mozilla::fallible_t())) {
-      p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
-      return p.forget();
-    }
-
-    for (uint32_t i = 0; i < mFileList->Length(); ++i) {
-      filesAndDirsSeq[i].SetAsFile() = mFileList->Item(i);
-    }
+  mFileList->ToSequence(filesAndDirsSeq, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
   }
 
   p->MaybeResolve(filesAndDirsSeq);
 
   return p.forget();
 }
 
 void
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -25,17 +25,17 @@ CreateDirectoryTask::Create(FileSystemBa
   MOZ_ASSERT(aFileSystem);
 
   RefPtr<CreateDirectoryTask> task =
     new CreateDirectoryTask(aFileSystem, aTargetPath);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
-    do_QueryInterface(aFileSystem->GetWindow());
+    do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -177,17 +177,17 @@ CreateDirectoryTask::HandlerCallback()
     return;
   }
 
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
-  RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
+  RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
                                             mTargetPath,
                                             Directory::eNotDOMRootDirectory,
                                             mFileSystem);
   MOZ_ASSERT(dir);
 
   mPromise->MaybeResolve(dir);
   mPromise = nullptr;
 }
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -52,17 +52,17 @@ CreateFileTask::Create(FileSystemBase* a
     } else {
       task->mBlobData = aBlobData;
     }
   }
 
   task->mArrayData.SwapElements(aArrayData);
 
   nsCOMPtr<nsIGlobalObject> globalObject =
-    do_QueryInterface(aFileSystem->GetWindow());
+    do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -346,17 +346,18 @@ CreateFileTask::HandlerCallback()
 
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     mBlobData = nullptr;
     return;
   }
 
-  RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
+  RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
+                                   mTargetBlobImpl);
   mPromise->MaybeResolve(blob);
   mPromise = nullptr;
   mBlobData = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -78,18 +78,18 @@ DeviceStorageFileSystem::Init(nsDOMDevic
 
 void
 DeviceStorageFileSystem::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   mShutdown = true;
 }
 
-nsPIDOMWindowInner*
-DeviceStorageFileSystem::GetWindow() const
+nsISupports*
+DeviceStorageFileSystem::GetParentObject() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
   MOZ_ASSERT_IF(!mShutdown, window);
   return window ? window->AsInner() : nullptr;
 }
 
 void
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -25,18 +25,18 @@ public:
   void
   Init(nsDOMDeviceStorage* aDeviceStorage);
 
   // Overrides FileSystemBase
 
   virtual void
   Shutdown() override;
 
-  virtual nsPIDOMWindowInner*
-  GetWindow() const override;
+  virtual nsISupports*
+  GetParentObject() const override;
 
   virtual void
   GetRootName(nsAString& aRetval) const override;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -77,25 +77,25 @@ IsValidRelativeDOMPath(const nsString& a
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Directory)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory)
   if (tmp->mFileSystem) {
     tmp->mFileSystem->Unlink();
     tmp->mFileSystem = nullptr;
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory)
   if (tmp->mFileSystem) {
     tmp->mFileSystem->Traverse(cb);
   }
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Directory)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
@@ -122,57 +122,57 @@ Directory::GetRoot(FileSystemBase* aFile
     return nullptr;
   }
 
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 /* static */ already_AddRefed<Directory>
-Directory::Create(nsPIDOMWindowInner* aWindow, nsIFile* aFile,
+Directory::Create(nsISupports* aParent, nsIFile* aFile,
                   DirectoryType aType, FileSystemBase* aFileSystem)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aWindow);
+  MOZ_ASSERT(aParent);
   MOZ_ASSERT(aFile);
 
 #ifdef DEBUG
   bool isDir;
   nsresult rv = aFile->IsDirectory(&isDir);
   MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
 #endif
 
   RefPtr<Directory> directory =
-    new Directory(aWindow, aFile, aType, aFileSystem);
+    new Directory(aParent, aFile, aType, aFileSystem);
   return directory.forget();
 }
 
-Directory::Directory(nsPIDOMWindowInner* aWindow,
+Directory::Directory(nsISupports* aParent,
                      nsIFile* aFile,
                      DirectoryType aType,
                      FileSystemBase* aFileSystem)
-  : mWindow(aWindow)
+  : mParent(aParent)
   , mFileSystem(aFileSystem)
   , mFile(aFile)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aFile);
 
   // aFileSystem can be null. In this case we create a OSFileSystem when needed.
 }
 
 Directory::~Directory()
 {
 }
 
-nsPIDOMWindowInner*
+nsISupports*
 Directory::GetParentObject() const
 {
-  return mWindow;
+  return mParent;
 }
 
 JSObject*
 Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return DirectoryBinding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -401,17 +401,17 @@ Directory::GetFileSystem(ErrorResult& aR
 
     nsAutoString path;
     aRv = parent->GetPath(path);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     RefPtr<OSFileSystem> fs = new OSFileSystem(path);
-    fs->Init(mWindow);
+    fs->Init(mParent);
 
     mFileSystem = fs;
   }
 
   return mFileSystem;
 }
 
 nsresult
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -8,17 +8,16 @@
 #define mozilla_dom_Directory_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/File.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsPIDOMWindow.h"
 #include "nsWrapperCache.h"
 
 // Resolve the name collision of Microsoft's API name with macros defined in
 // Windows header files. Undefine the macro of CreateDirectory to avoid
 // Directory#CreateDirectory being replaced by Directory#CreateDirectoryW.
 #ifdef CreateDirectory
 #undef CreateDirectory
 #endif
@@ -65,22 +64,22 @@ public:
     // consider the '/' of this DOM filesystem.
     eDOMRootDirectory,
 
     // All the sub directories of the '/' will be marked using this other value.
     eNotDOMRootDirectory
   };
 
   static already_AddRefed<Directory>
-  Create(nsPIDOMWindowInner* aWindow, nsIFile* aDirectory,
+  Create(nsISupports* aParent, nsIFile* aDirectory,
          DirectoryType aType, FileSystemBase* aFileSystem = 0);
 
   // ========= Begin WebIDL bindings. ===========
 
-  nsPIDOMWindowInner*
+  nsISupports*
   GetParentObject() const;
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void
   GetName(nsAString& aRetval, ErrorResult& aRv);
 
@@ -136,33 +135,38 @@ public:
    * picker operation.
    */
   void
   SetContentFilters(const nsAString& aFilters);
 
   FileSystemBase*
   GetFileSystem(ErrorResult& aRv);
 
+  DirectoryType Type() const
+  {
+    return mType;
+  }
+
 private:
-  Directory(nsPIDOMWindowInner* aWindow,
+  Directory(nsISupports* aParent,
             nsIFile* aFile, DirectoryType aType,
             FileSystemBase* aFileSystem = nullptr);
   ~Directory();
 
   /*
    * Convert relative DOM path to the absolute real path.
    */
   nsresult
   DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
 
   already_AddRefed<Promise>
   RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                  ErrorResult& aRv);
 
-  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+  nsCOMPtr<nsISupports> mParent;
   RefPtr<FileSystemBase> mFileSystem;
   nsCOMPtr<nsIFile> mFile;
   DirectoryType mType;
 
   nsString mFilters;
 };
 
 } // namespace dom
--- a/dom/filesystem/FileSystemBase.cpp
+++ b/dom/filesystem/FileSystemBase.cpp
@@ -53,18 +53,18 @@ FileSystemBase::~FileSystemBase()
 }
 
 void
 FileSystemBase::Shutdown()
 {
   mShutdown = true;
 }
 
-nsPIDOMWindowInner*
-FileSystemBase::GetWindow() const
+nsISupports*
+FileSystemBase::GetParentObject() const
 {
   return nullptr;
 }
 
 bool
 FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -5,18 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FileSystemBase_h
 #define mozilla_dom_FileSystemBase_h
 
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
-class nsPIDOMWindowInner;
-
 namespace mozilla {
 namespace dom {
 
 class BlobImpl;
 class Directory;
 
 class FileSystemBase
 {
@@ -31,18 +29,18 @@ public:
 
   virtual void
   Shutdown();
 
   // SerializeDOMPath the FileSystem to string.
   virtual void
   SerializeDOMPath(nsAString& aOutput) const = 0;
 
-  virtual nsPIDOMWindowInner*
-  GetWindow() const;
+  virtual nsISupports*
+  GetParentObject() const;
 
   /*
    * Get the virtual name of the root directory. This name will be exposed to
    * the content page.
    */
   virtual void
   GetRootName(nsAString& aRetval) const = 0;
 
--- a/dom/filesystem/FileSystemPermissionRequest.cpp
+++ b/dom/filesystem/FileSystemPermissionRequest.cpp
@@ -39,18 +39,18 @@ FileSystemPermissionRequest::FileSystemP
 
   RefPtr<FileSystemBase> filesystem = mTask->GetFileSystem();
   if (!filesystem) {
     return;
   }
 
   mPermissionType = filesystem->GetPermission();
 
-  mWindow = filesystem->GetWindow();
-  if (!mWindow) {
+  mWindow = do_QueryInterface(filesystem->GetParentObject());
+  if (NS_WARN_IF(!mWindow)) {
     return;
   }
 
   nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
   if (!doc) {
     return;
   }
 
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -31,17 +31,17 @@ GetDirectoryListingTask::Create(FileSyst
   MOZ_ASSERT(aFileSystem);
 
   RefPtr<GetDirectoryListingTask> task =
     new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
-    do_QueryInterface(aFileSystem->GetWindow());
+    do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -361,29 +361,29 @@ GetDirectoryListingTask::HandlerCallback
         mPromise->MaybeReject(rv);
         mPromise = nullptr;
         return;
       }
 
       MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, directoryPath));
 #endif
 
-      RefPtr<Directory> directory = Directory::Create(mFileSystem->GetWindow(),
+      RefPtr<Directory> directory = Directory::Create(mFileSystem->GetParentObject(),
                                                       directoryPath,
                                                       Directory::eNotDOMRootDirectory,
                                                       mFileSystem);
       MOZ_ASSERT(directory);
 
       // Propogate mFilter onto sub-Directory object:
       directory->SetContentFilters(mFilters);
       listing[i].SetAsDirectory() = directory;
     } else {
       MOZ_ASSERT(mTargetData[i].mType == Directory::BlobImplOrDirectoryPath::eBlobImpl);
       listing[i].SetAsFile() =
-        File::Create(mFileSystem->GetWindow(), mTargetData[i].mBlobImpl);
+        File::Create(mFileSystem->GetParentObject(), mTargetData[i].mBlobImpl);
     }
   }
 
   mPromise->MaybeResolve(listing);
   mPromise = nullptr;
 }
 
 void
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -30,17 +30,17 @@ GetFileOrDirectoryTask::Create(FileSyste
   MOZ_ASSERT(aFileSystem);
 
   RefPtr<GetFileOrDirectoryTask> task =
     new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
-    do_QueryInterface(aFileSystem->GetWindow());
+    do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -258,28 +258,29 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (HasError()) {
     mPromise->MaybeReject(mErrorValue);
     mPromise = nullptr;
     return;
   }
 
   if (mIsDirectory) {
-    RefPtr<Directory> dir = Directory::Create(mFileSystem->GetWindow(),
+    RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
                                               mTargetPath,
                                               mType,
                                               mFileSystem);
     MOZ_ASSERT(dir);
 
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(), mTargetBlobImpl);
+  RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
+                                   mTargetBlobImpl);
   mPromise->MaybeResolve(blob);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
--- a/dom/filesystem/OSFileSystem.cpp
+++ b/dom/filesystem/OSFileSystem.cpp
@@ -4,20 +4,20 @@
  * 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 "mozilla/dom/OSFileSystem.h"
 
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileSystemUtils.h"
+#include "nsIGlobalObject.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsIFile.h"
-#include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 OSFileSystem::OSFileSystem(const nsAString& aRootDir)
 {
   mLocalRootPath = aRootDir;
   FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
@@ -28,29 +28,34 @@ OSFileSystem::OSFileSystem(const nsAStri
   mRequiresPermissionChecks = false;
 
 #ifdef DEBUG
   mPermission.AssignLiteral("never-used");
 #endif
 }
 
 void
-OSFileSystem::Init(nsPIDOMWindowInner* aWindow)
+OSFileSystem::Init(nsISupports* aParent)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  MOZ_ASSERT(!mWindow, "No duple Init() calls");
-  MOZ_ASSERT(aWindow);
-  mWindow = aWindow;
+  MOZ_ASSERT(!mParent, "No duple Init() calls");
+  MOZ_ASSERT(aParent);
+  mParent = aParent;
+
+#ifdef DEBUG
+  nsCOMPtr<nsIGlobalObject> obj = do_QueryInterface(aParent);
+  MOZ_ASSERT(obj);
+#endif
 }
 
-nsPIDOMWindowInner*
-OSFileSystem::GetWindow() const
+nsISupports*
+OSFileSystem::GetParentObject() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  return mWindow;
+  return mParent;
 }
 
 void
 OSFileSystem::GetRootName(nsAString& aRetval) const
 {
   aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
 }
 
@@ -72,24 +77,24 @@ OSFileSystem::IsSafeDirectory(Directory*
   // storage that it is being used with.
   MOZ_CRASH("Don't use OSFileSystem with the Device Storage API");
   return true;
 }
 
 void
 OSFileSystem::Unlink()
 {
-  mWindow = nullptr;
+  mParent = nullptr;
 }
 
 void
 OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
 {
   OSFileSystem* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
 }
 
 void
 OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
 {
   aOutput = mLocalRootPath;
 }
 
--- a/dom/filesystem/OSFileSystem.h
+++ b/dom/filesystem/OSFileSystem.h
@@ -13,22 +13,22 @@ namespace mozilla {
 namespace dom {
 
 class OSFileSystem final : public FileSystemBase
 {
 public:
   explicit OSFileSystem(const nsAString& aRootDir);
 
   void
-  Init(nsPIDOMWindowInner* aWindow);
+  Init(nsISupports* aParent);
 
   // Overrides FileSystemBase
 
-  virtual nsPIDOMWindowInner*
-  GetWindow() const override;
+  virtual nsISupports*
+  GetParentObject() const override;
 
   virtual void
   GetRootName(nsAString& aRetval) const override;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const override;
 
   virtual bool
@@ -39,15 +39,15 @@ public:
 
   // CC methods
   virtual void Unlink() override;
   virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
 
 private:
   virtual ~OSFileSystem() {}
 
-   nsCOMPtr<nsPIDOMWindowInner> mWindow;
+   nsCOMPtr<nsISupports> mParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_OSFileSystem_h
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -31,17 +31,17 @@ RemoveTask::Create(FileSystemBase* aFile
   MOZ_ASSERT(aDirPath);
 
   RefPtr<RemoveTask> task =
     new RemoveTask(aFileSystem, aDirPath, aTargetBlob, aTargetPath, aRecursive);
 
   // aTargetPath can be null. In this case SetError will be called.
 
   nsCOMPtr<nsIGlobalObject> globalObject =
-    do_QueryInterface(aFileSystem->GetWindow());
+    do_QueryInterface(aFileSystem->GetParentObject());
   if (NS_WARN_IF(!globalObject)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   task->mPromise = Promise::Create(globalObject, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
@@ -143,17 +143,17 @@ RemoveTask::GetRequestParams(const nsStr
 
   aRv = mDirPath->GetPath(param.directory());
   if (NS_WARN_IF(aRv.Failed())) {
     return param;
   }
 
   param.recursive() = mRecursive;
   if (mTargetBlobImpl) {
-    RefPtr<Blob> blob = Blob::Create(mFileSystem->GetWindow(),
+    RefPtr<Blob> blob = Blob::Create(mFileSystem->GetParentObject(),
                                      mTargetBlobImpl);
     BlobChild* actor
       = ContentChild::GetSingleton()->GetOrCreateActorForBlob(blob);
     if (actor) {
       param.target() = actor;
     }
   } else {
     nsAutoString path;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -6,18 +6,16 @@
 
 #include "mozilla/dom/HTMLInputElement.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/Directory.h"
-#include "mozilla/dom/FileSystemUtils.h"
-#include "mozilla/dom/OSFileSystem.h"
 #include "nsAttrValueInlines.h"
 #include "nsCRTGlue.h"
 
 #include "nsIDOMHTMLInputElement.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIPhonetic.h"
@@ -2520,20 +2518,18 @@ HTMLInputElement::SetFiles(nsIDOMFileLis
 {
   RefPtr<FileList> files = static_cast<FileList*>(aFiles);
   mFilesOrDirectories.Clear();
 
   if (aFiles) {
     uint32_t listLength;
     aFiles->GetLength(&listLength);
     for (uint32_t i = 0; i < listLength; i++) {
-      RefPtr<File> file = files->Item(i);
-
       OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
-      element->SetAsFile() = file;
+      *element = files->UnsafeItem(i);
     }
   }
 
   AfterSetFilesOrDirectories(aSetValueChanged);
 }
 
 void
 HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
@@ -2627,36 +2623,37 @@ HTMLInputElement::HandleNumberControlSpi
     // or else we've lost our frame. Either way, stop the timer and don't do
     // anything else.
     input->StopNumberControlSpinnerSpin();
   } else {
     input->StepNumberControlForUserEvent(input->mNumberControlSpinnerSpinsUp ? 1 : -1);
   }
 }
 
-nsresult
+void
 HTMLInputElement::UpdateFileList()
 {
   if (mFileList) {
     mFileList->Clear();
 
     const nsTArray<OwningFileOrDirectory>& array =
       GetFilesOrDirectoriesInternal();
 
     for (uint32_t i = 0; i < array.Length(); ++i) {
-      if (array[i].IsFile() && !mFileList->Append(array[i].GetAsFile())) {
-        return NS_ERROR_FAILURE;
+      if (array[i].IsFile()) {
+        mFileList->Append(array[i].GetAsFile());
+      } else {
+        MOZ_ASSERT(array[i].IsDirectory());
+        mFileList->Append(array[i].GetAsDirectory());
       }
     }
   }
 
   // Make sure we (lazily) create a new Promise for GetFilesAndDirectories:
   mFilesAndDirectoriesPromise = nullptr;
-
-  return NS_OK;
 }
 
 nsresult
 HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
 {
   NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
                   "Don't call SetValueInternal for file inputs");
 
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -919,17 +919,17 @@ protected:
    * MaybeSubmitForm looks for a submit input or a single text control
    * and submits the form if either is present.
    */
   nsresult MaybeSubmitForm(nsPresContext* aPresContext);
 
   /**
    * Update mFileList with the currently selected file.
    */
-  nsresult UpdateFileList();
+  void UpdateFileList();
 
   /**
    * Called after calling one of the SetFilesOrDirectories() functions.
    */
   void AfterSetFilesOrDirectories(bool aSetValueChanged);
 
   /**
    * Determine whether the editor needs to be initialized explicitly for
--- a/dom/webidl/FileList.webidl
+++ b/dom/webidl/FileList.webidl
@@ -6,11 +6,13 @@
  * The origin of this IDL file is
  * http://dev.w3.org/2006/webapi/FileAPI/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface FileList {
-  getter File? item(unsigned long index);
+  [Throws]
+  getter (File or Directory)? item(unsigned long index);
+
   readonly attribute unsigned long length;
 };