Bug 1258482 - FileList should contain only Files, not Directories, r=smaug
☠☠ backed out by 66834c916e31 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 12 Apr 2016 08:51:52 -0400
changeset 330682 166555b48e772d021e298740a2ac389a76bdccec
parent 330681 83ce34cabf08a9b9d2ddc214c5cf880a81536107
child 330683 f151f04efa98a3050c528149c3b8ade1e0a9db84
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1258482
milestone48.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 1258482 - FileList should contain only Files, not Directories, 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/tests/test_basic.html
dom/filesystem/tests/test_worker_basic.html
dom/filesystem/tests/worker_basic.js
dom/html/HTMLInputElement.cpp
dom/webidl/FileList.webidl
embedding/browser/nsDocShellTreeOwner.cpp
--- a/dom/base/FileList.cpp
+++ b/dom/base/FileList.cpp
@@ -7,122 +7,80 @@
 #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, mFilesOrDirectories, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, 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** aValue)
 {
-  if (aIndex >= mFilesOrDirectories.Length()) {
-    return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
+  file.forget(aValue);
+  return NS_OK;
+}
+
+File*
+FileList::Item(uint32_t aIndex) const
+{
+  if (aIndex >= mFiles.Length()) {
+    return nullptr;
   }
 
-  if (mFilesOrDirectories[aIndex].IsFile()) {
-    nsCOMPtr<nsIDOMBlob> file = mFilesOrDirectories[aIndex].GetAsFile();
-    file.forget(aValue);
-    return NS_OK;
-  }
+  return mFiles[aIndex];
+}
 
-  MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory());
-  RefPtr<Directory> directory = mFilesOrDirectories[aIndex].GetAsDirectory();
-  directory.forget(aValue);
-  return NS_OK;
+File*
+FileList::IndexedGetter(uint32_t aIndex, bool& aFound) const
+{
+  aFound = aIndex < mFiles.Length();
+  return Item(aIndex);
 }
 
 void
-FileList::Item(uint32_t aIndex, Nullable<OwningFileOrDirectory>& aValue,
-               ErrorResult& aRv) const
+FileList::ToSequence(Sequence<RefPtr<File>>& aSequence,
+                     ErrorResult& aRv) const
 {
-  if (aIndex >= mFilesOrDirectories.Length()) {
-    aValue.SetNull();
+  MOZ_ASSERT(aSequence.IsEmpty());
+  if (mFiles.IsEmpty()) {
     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(),
+  if (!aSequence.SetLength(mFiles.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];
+  for (uint32_t i = 0; i < mFiles.Length(); ++i) {
+    aSequence[i] = mFiles[i];
   }
 }
 
-bool
-FileList::ClonableToDifferentThreadOrProcess() const
-{
-  for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
-    if (mFilesOrDirectories[i].IsDirectory() &&
-        !mFilesOrDirectories[i].GetAsDirectory()->ClonableToDifferentThreadOrProcess()) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/FileList.h
+++ b/dom/base/FileList.h
@@ -35,32 +35,35 @@ public:
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
-  void Append(File* aFile);
-  void Append(Directory* aDirectory);
+  bool Append(File* aFile)
+  {
+    MOZ_ASSERT(aFile);
+    return mFiles.AppendElement(aFile, fallible);
+  }
 
   bool Remove(uint32_t aIndex)
   {
-    if (aIndex < mFilesOrDirectories.Length()) {
-      mFilesOrDirectories.RemoveElementAt(aIndex);
+    if (aIndex < mFiles.Length()) {
+      mFiles.RemoveElementAt(aIndex);
       return true;
     }
 
     return false;
   }
 
   void Clear()
   {
-    return mFilesOrDirectories.Clear();
+    return mFiles.Clear();
   }
 
   static FileList* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMFileList> list_qi = do_QueryInterface(aSupports);
 
@@ -70,43 +73,31 @@ public:
       NS_ASSERTION(list_qi == static_cast<nsIDOMFileList*>(aSupports),
                    "Uh, fix QI!");
     }
 #endif
 
     return static_cast<FileList*>(aSupports);
   }
 
-  const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const
-  {
-    MOZ_ASSERT(aIndex < Length());
-    return mFilesOrDirectories[aIndex];
-  }
+  File* Item(uint32_t aIndex) const;
 
-  void Item(uint32_t aIndex,
-            Nullable<OwningFileOrDirectory>& aFileOrDirectory,
-            ErrorResult& aRv) const;
-
-  void IndexedGetter(uint32_t aIndex, bool& aFound,
-                     Nullable<OwningFileOrDirectory>& aFileOrDirectory,
-                     ErrorResult& aRv) const;
+  File* IndexedGetter(uint32_t aIndex, bool& aFound) const;
 
   uint32_t Length() const
   {
-    return mFilesOrDirectories.Length();
+    return mFiles.Length();
   }
 
-  void ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
+  void ToSequence(Sequence<RefPtr<File>>& aSequence,
                   ErrorResult& aRv) const;
 
-  bool ClonableToDifferentThreadOrProcess() const;
-
 private:
   ~FileList() {}
 
-  nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
+  FallibleTArray<RefPtr<File>> mFiles;
   nsCOMPtr<nsISupports> mParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_FileList_h
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -789,139 +789,93 @@ ReadFileList(JSContext* aCx,
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aReader);
 
   JS::Rooted<JS::Value> val(aCx);
   {
     RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
 
-    // |aCount| is the number of Files or Directory for this FileList.
+    uint32_t zero, index;
+    // |index| is the index of the first blobImpl.
+    if (!JS_ReadUint32Pair(aReader, &zero, &index)) {
+      return nullptr;
+    }
+
+    MOZ_ASSERT(zero == 0);
+
+    // |aCount| is the number of BlobImpls to use from the |index|.
     for (uint32_t i = 0; i < aCount; ++i) {
-      uint32_t tagOrDirectoryType, indexOrLengthOfString;
-      if (!JS_ReadUint32Pair(aReader, &tagOrDirectoryType,
-                             &indexOrLengthOfString)) {
+      uint32_t pos = index + i;
+      MOZ_ASSERT(pos < aHolder->BlobImpls().Length());
+
+      RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[pos];
+      MOZ_ASSERT(blobImpl->IsFile());
+
+      ErrorResult rv;
+      blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        rv.SuppressException();
         return nullptr;
       }
 
-      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());
+      MOZ_ASSERT(blobImpl);
 
-        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)) {
+      RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
+      if (!fileList->Append(file)) {
         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
-// - 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
+// - pair of ints: 0, The offset of the BlobImpl array
 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())) {
+                          aFileList->Length()) ||
+      !JS_WriteUint32Pair(aWriter, 0,
+                          aHolder->BlobImpls().Length())) {
     return false;
   }
 
   ErrorResult rv;
   nsTArray<RefPtr<BlobImpl>> blobImpls;
 
   for (uint32_t i = 0; i < aFileList->Length(); ++i) {
-    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;
+    RefPtr<BlobImpl> blobImpl =
+      EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      rv.SuppressException();
+      return false;
     }
 
-    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,
@@ -1127,19 +1081,17 @@ StructuredCloneHolder::CustomWriteHandle
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, aObj, directory))) {
       return WriteDirectory(aWriter, directory);
     }
   }
 
   // See if this is a FileList object.
   {
     FileList* fileList = nullptr;
-    if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList)) &&
-        (mSupportedContext == SameProcessSameThread ||
-         fileList->ClonableToDifferentThreadOrProcess())) {
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
       return WriteFileList(aWriter, fileList, this);
     }
   }
 
   // See if this is a FormData object.
   {
     FormData* formData = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
--- a/dom/base/test/test_postMessages.html
+++ b/dom/base/test/test_postMessages.html
@@ -67,17 +67,17 @@ var clonableObjects = [
   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),
 ];
 
-function create_fileList_forFile() {
+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
@@ -88,37 +88,16 @@ function create_fileList_forFile() {
     script.destroy();
     next();
   }
 
   script.addMessageListener("file.opened", onOpened);
   script.sendAsyncMessage("file.open");
 }
 
-function create_fileList_forDir() {
-  var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
-  var script = SpecialPowers.loadChromeScript(url);
-
-  function onOpened(message) {
-    var fileList = document.getElementById('fileList');
-    SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
-
-    // Just a simple test
-    is(fileList.files.length, 1, "Filelist has 1 element");
-    ok(fileList.files[0] instanceof Directory, "We have a directory.");
-
-    clonableObjects.push(fileList.files);
-    script.destroy();
-    next();
-  }
-
-  script.addMessageListener("dir.opened", onOpened);
-  script.sendAsyncMessage("dir.open");
-}
-
 function create_directory() {
   if (navigator.userAgent.toLowerCase().indexOf('Android') != -1) {
     next();
     return;
   }
 
   var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
@@ -543,18 +522,17 @@ function test_messagePort_inWorkers() {
         onmessage = null;
         next();
       }
     });
   }
 }
 
 var tests = [
-  create_fileList_forFile,
-  create_fileList_forDir,
+  create_fileList,
   create_directory,
 
   test_windowToWindow,
   test_windowToIframe,
   test_windowToCrossOriginIframe,
 
   test_workers,
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -861,23 +861,23 @@ DataTransfer::GetFilesAndDirectories(Err
 
   if (!mFileList) {
     GetFiles(aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  Sequence<OwningFileOrDirectory> filesAndDirsSeq;
-  mFileList->ToSequence(filesAndDirsSeq, aRv);
+  Sequence<RefPtr<File>> filesSeq;
+  mFileList->ToSequence(filesSeq, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  p->MaybeResolve(filesAndDirsSeq);
+  p->MaybeResolve(filesSeq);
 
   return p.forget();
 }
 
 void
 DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
 {
   if (mReadOnly) {
--- a/dom/filesystem/tests/test_basic.html
+++ b/dom/filesystem/tests/test_basic.html
@@ -15,24 +15,24 @@ var directory;
 function create_fileList(aPath) {
   var url = SimpleTest.getTestFileURL("script_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
 
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
 
-    // Just a simple test
-    is(fileList.files.length, 1, "Filelist has 1 element");
-    ok(fileList.files[0] instanceof Directory, "We have a directory.");
+    fileList.getFilesAndDirectories().then(function(array) {
+      is(array.length, 1, "We want just 1 directory.");
+      ok(array[0] instanceof Directory, "We want just 1 directory.");
 
-    directory = fileList.files[0];
-
-    script.destroy();
-    next();
+      directory = array[0];
+      script.destroy();
+      next();
+    });
   }
 
   script.addMessageListener("dir.opened", onOpened);
   script.sendAsyncMessage("dir.open", { path: aPath });
 }
 
 function test_basic() {
   ok(directory, "Directory exists.");
--- a/dom/filesystem/tests/test_worker_basic.html
+++ b/dom/filesystem/tests/test_worker_basic.html
@@ -12,45 +12,41 @@
 
 function create_fileList() {
   var url = SimpleTest.getTestFileURL("script_fileList.js");
   var script = SpecialPowers.loadChromeScript(url);
 
   function onOpened(message) {
     var fileList = document.getElementById('fileList');
     SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
-
-    // Just a simple test
-    is(fileList.files.length, 1, "Filelist has 1 element");
-    ok(fileList.files[0] instanceof Directory, "We have a directory.");
-
     script.destroy();
     next();
   }
 
   script.addMessageListener("dir.opened", onOpened);
   script.sendAsyncMessage("dir.open", { path: 'ProfD' });
 }
 
 function test_worker() {
   var fileList = document.getElementById('fileList');
+  fileList.getFilesAndDirectories().then(function(array) {
+    var worker = new Worker('worker_basic.js');
+    worker.onmessage = function(e) {
+      if (e.data.type == 'finish') {
+        next();
+        return;
+      }
 
-  var worker = new Worker('worker_basic.js');
-  worker.onmessage = function(e) {
-    if (e.data.type == 'finish') {
-      next();
-      return;
+      if (e.data.type == 'test') {
+        ok(e.data.test, e.data.message);
+      }
     }
 
-    if (e.data.type == 'test') {
-      ok(e.data.test, e.data.message);
-    }
-  }
-
-  worker.postMessage(fileList.files);
+    worker.postMessage(array[0]);
+  });
 }
 
 var tests = [
   create_fileList,
   test_worker,
 ];
 
 function next() {
--- a/dom/filesystem/tests/worker_basic.js
+++ b/dom/filesystem/tests/worker_basic.js
@@ -26,22 +26,20 @@ function checkSubDir(dir) {
           is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
         }
       }
     }
   );
 }
 
 onmessage = function(e) {
-  var fileList = e.data;
-  ok(fileList instanceof FileList, "This is a fileList.");
-  is(fileList.length, 1, "We want just 1 element.");
-  ok(fileList[0] instanceof Directory, "This is a directory.");
+  var directory = e.data;
+  ok(directory instanceof Directory, "This is a directory.");
 
-  fileList[0].getFilesAndDirectories().then(
+  directory.getFilesAndDirectories().then(
     function(data) {
       ok(data.length, "We should have some data.");
       var promises = [];
       for (var i = 0; i < data.length; ++i) {
         ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
         if (data[i] instanceof Directory) {
           isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
           is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2557,17 +2557,17 @@ 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++) {
       OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
-      *element = files->UnsafeItem(i);
+      element->SetAsFile() = files->Item(i);
     }
   }
 
   AfterSetFilesOrDirectories(aSetValueChanged);
 }
 
 void
 HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
@@ -2673,19 +2673,16 @@ HTMLInputElement::UpdateFileList()
     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());
-      } else {
-        MOZ_ASSERT(array[i].IsDirectory());
-        mFileList->Append(array[i].GetAsDirectory());
       }
     }
   }
 
   // Make sure we (lazily) create a new Promise for GetFilesAndDirectories:
   mFilesAndDirectoriesPromise = nullptr;
 }
 
--- a/dom/webidl/FileList.webidl
+++ b/dom/webidl/FileList.webidl
@@ -6,13 +6,11 @@
  * 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 {
-  [Throws]
-  getter (File or Directory)? item(unsigned long index);
-
+  getter File? item(unsigned long index);
   readonly attribute unsigned long length;
 };
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1181,26 +1181,26 @@ DefaultTooltipTextProvider::GetNodeText(
                                                  getter_Copies(outText));
                 } else {
                   rv = bundle->GetStringFromName(MOZ_UTF16("NoFileSelected"),
                                                  getter_Copies(outText));
                 }
                 NS_ENSURE_SUCCESS(rv, rv);
               } else {
                 FileList* fl = static_cast<FileList*>(fileList.get());
-                fl->UnsafeItem(0).GetAsFile()->GetName(outText);
+                fl->Item(0)->GetName(outText);
 
                 // For UX and performance (jank) reasons we cap the number of
                 // files that we list in the tooltip to 20 plus a "and xxx more"
                 // line, or to 21 if exactly 21 files were picked.
                 const uint32_t TRUNCATED_FILE_COUNT = 20;
                 uint32_t count = std::min(listLength, TRUNCATED_FILE_COUNT);
                 for (uint32_t i = 1; i < count; ++i) {
                   nsString fileName;
-                  fl->UnsafeItem(i).GetAsFile()->GetName(fileName);
+                  fl->Item(i)->GetName(fileName);
                   outText.Append(NS_LITERAL_STRING("\n"));
                   outText.Append(fileName);
                 }
               }
             } else if (NS_SUCCEEDED(currElement->GetAttribute(NS_LITERAL_STRING("title"), outText)) &&
                        outText.Length()) {
               found = true;
             }