summaryrefslogtreecommitdiffstats
path: root/dom/events/DataTransferItemList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/events/DataTransferItemList.cpp')
-rw-r--r--dom/events/DataTransferItemList.cpp642
1 files changed, 642 insertions, 0 deletions
diff --git a/dom/events/DataTransferItemList.cpp b/dom/events/DataTransferItemList.cpp
new file mode 100644
index 0000000000..f5c84f75f8
--- /dev/null
+++ b/dom/events/DataTransferItemList.cpp
@@ -0,0 +1,642 @@
+/* -*- 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 "DataTransferItemList.h"
+
+#include "nsContentUtils.h"
+#include "nsIGlobalObject.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+#include "nsQueryObject.h"
+#include "nsVariant.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/ContentEvents.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/storage/Variant.h"
+#include "mozilla/dom/DataTransferItemListBinding.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItemList, mDataTransfer,
+ mItems, mIndexedItems, mFiles)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItemList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransferItemList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransferItemList)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject* DataTransferItemList::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return DataTransferItemList_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+already_AddRefed<DataTransferItemList> DataTransferItemList::Clone(
+ DataTransfer* aDataTransfer) const {
+ RefPtr<DataTransferItemList> list = new DataTransferItemList(aDataTransfer);
+
+ // We need to clone the mItems and mIndexedItems lists while keeping the same
+ // correspondences between the mIndexedItems and mItems lists (namely, if an
+ // item is in mIndexedItems, and mItems it must have the same new identity)
+
+ // First, we copy over indexedItems, and clone every entry. Then, we go over
+ // mItems. For every entry, we use its mIndex property to locate it in
+ // mIndexedItems on the original DataTransferItemList, and then copy over the
+ // reference from the same index pair on the new DataTransferItemList
+
+ list->mIndexedItems.SetLength(mIndexedItems.Length());
+ list->mItems.SetLength(mItems.Length());
+
+ // Copy over mIndexedItems, cloning every entry
+ for (uint32_t i = 0; i < mIndexedItems.Length(); i++) {
+ const nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
+ nsTArray<RefPtr<DataTransferItem>>& newItems = list->mIndexedItems[i];
+ newItems.SetLength(items.Length());
+ for (uint32_t j = 0; j < items.Length(); j++) {
+ newItems[j] = items[j]->Clone(aDataTransfer);
+ }
+ }
+
+ // Copy over mItems, getting the actual entries from mIndexedItems
+ for (uint32_t i = 0; i < mItems.Length(); i++) {
+ uint32_t index = mItems[i]->Index();
+ MOZ_ASSERT(index < mIndexedItems.Length());
+ uint32_t subIndex = mIndexedItems[index].IndexOf(mItems[i]);
+
+ // Copy over the reference
+ list->mItems[i] = list->mIndexedItems[index][subIndex];
+ }
+
+ return list.forget();
+}
+
+void DataTransferItemList::Remove(uint32_t aIndex,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ if (mDataTransfer->IsReadOnly()) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ if (aIndex >= Length()) {
+ return;
+ }
+
+ ClearDataHelper(mItems[aIndex], aIndex, -1, aSubjectPrincipal, aRv);
+}
+
+DataTransferItem* DataTransferItemList::IndexedGetter(uint32_t aIndex,
+ bool& aFound) const {
+ if (aIndex >= mItems.Length()) {
+ aFound = false;
+ return nullptr;
+ }
+
+ MOZ_ASSERT(mItems[aIndex]);
+ aFound = true;
+ return mItems[aIndex];
+}
+
+uint32_t DataTransferItemList::MozItemCount() const {
+ uint32_t length = mIndexedItems.Length();
+ // XXX: Compat hack - Index 0 always exists due to changes in internals, but
+ // if it is empty, scripts using the moz* APIs should see it as not existing.
+ if (length == 1 && mIndexedItems[0].IsEmpty()) {
+ return 0;
+ }
+ return length;
+}
+
+void DataTransferItemList::Clear(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
+ return;
+ }
+
+ uint32_t count = Length();
+ for (uint32_t i = 0; i < count; i++) {
+ // We always remove the last item first, to avoid moving items around in
+ // memory as much
+ Remove(Length() - 1, aSubjectPrincipal, aRv);
+ ENSURE_SUCCESS_VOID(aRv);
+ }
+
+ MOZ_ASSERT(Length() == 0);
+}
+
+DataTransferItem* DataTransferItemList::Add(const nsAString& aData,
+ const nsAString& aType,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
+ return nullptr;
+ }
+
+ RefPtr<nsVariantCC> data(new nsVariantCC());
+ data->SetAsAString(aData);
+
+ nsAutoString format;
+ mDataTransfer->GetRealFormat(aType, format);
+
+ if (!DataTransfer::PrincipalMaySetData(format, data, &aSubjectPrincipal)) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+
+ // We add the textual data to index 0. We set aInsertOnly to true, as we don't
+ // want to update an existing entry if it is already present, as per the spec.
+ RefPtr<DataTransferItem> item =
+ SetDataWithPrincipal(format, data, 0, &aSubjectPrincipal,
+ /* aInsertOnly = */ true,
+ /* aHidden = */ false, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+ MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE);
+
+ return item;
+}
+
+DataTransferItem* DataTransferItemList::Add(File& aData,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ if (mDataTransfer->IsReadOnly()) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsISupports> supports = do_QueryObject(&aData);
+ nsCOMPtr<nsIWritableVariant> data = new nsVariantCC();
+ data->SetAsISupports(supports);
+
+ nsAutoString type;
+ aData.GetType(type);
+
+ if (!DataTransfer::PrincipalMaySetData(type, data, &aSubjectPrincipal)) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+
+ // We need to add this as a new item, as multiple files can't exist in the
+ // same item in the Moz DataTransfer layout. It will be appended at the end of
+ // the internal specced layout.
+ uint32_t index = mIndexedItems.Length();
+ RefPtr<DataTransferItem> item =
+ SetDataWithPrincipal(type, data, index, &aSubjectPrincipal,
+ /* aInsertOnly = */ true,
+ /* aHidden = */ false, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+ MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE);
+
+ return item;
+}
+
+already_AddRefed<FileList> DataTransferItemList::Files(
+ nsIPrincipal* aPrincipal) {
+ // The DataTransfer can hold data with varying principals, coming from
+ // different windows. This means that permissions checks need to be made when
+ // accessing data from the DataTransfer. With the accessor methods, this is
+ // checked by DataTransferItem::Data(), however with files, we keep a cached
+ // live copy of the files list for spec compliance.
+ //
+ // A DataTransfer is only exposed to one webpage, chrome code and expanded
+ // principals related to WebExtensions content scripts or user scripts.
+ // The chrome code should be able to see all files on the DataTransfer, while
+ // the webpage and WebExtensions content scripts and user scripts should only
+ // be able to see the files they can see.
+ //
+ // As chrome code doesn't need as strict spec compliance as web visible code,
+ // we generate a new FileList object every time you access the Files list from
+ // chrome code, but re-use the cached one when accessing from content code.
+ //
+ // For WebExtensions content scripts (expanded principals subsuming both
+ // the attached web page principal and the extension principal) and
+ // WebExtensions user scripts (expanded principals subsuming the attached
+ // web page principal but not the extension principal) we also don't cache
+ // the FileList as for chrome code (because the webpage principal and other
+ // extension content scripts/user scripts principals would not be able to
+ // access the cached FileList when accessed by a different expanded principal
+ // first, see Bug 1707214).
+ //
+ // It is not legal to expose an identical DataTransfer object is to multiple
+ // different principals without using the `Clone` method or similar to copy it
+ // first. If that happens, this method will assert, and return nullptr in
+ // release builds. If this functionality is required in the future, a more
+ // advanced caching mechanism for the FileList objects will be required.
+ RefPtr<FileList> files;
+ if (aPrincipal->IsSystemPrincipal() ||
+ // WebExtensions content scripts and user scripts.
+ nsContentUtils::IsExpandedPrincipal(aPrincipal)) {
+ files = new FileList(mDataTransfer);
+ GenerateFiles(files, aPrincipal);
+ return files.forget();
+ }
+
+ if (!mFiles) {
+ mFiles = new FileList(mDataTransfer);
+ mFilesPrincipal = aPrincipal;
+ RegenerateFiles();
+ }
+
+ if (!aPrincipal->Subsumes(mFilesPrincipal)) {
+ MOZ_ASSERT(false,
+ "This DataTransfer should only be accessed by the system "
+ "and a single principal");
+ return nullptr;
+ }
+
+ files = mFiles;
+ return files.forget();
+}
+
+void DataTransferItemList::MozRemoveByTypeAt(const nsAString& aType,
+ uint32_t aIndex,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ if (NS_WARN_IF(mDataTransfer->IsReadOnly() ||
+ aIndex >= mIndexedItems.Length())) {
+ return;
+ }
+
+ bool removeAll = aType.IsEmpty();
+
+ nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex];
+ uint32_t count = items.Length();
+ // We remove the last item of the list repeatedly - that way we don't
+ // have to worry about modifying the loop iterator
+ if (removeAll) {
+ for (uint32_t i = 0; i < count; ++i) {
+ uint32_t index = items.Length() - 1;
+ MOZ_ASSERT(index == count - i - 1);
+
+ ClearDataHelper(items[index], -1, index, aSubjectPrincipal, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+ }
+
+ // items is no longer a valid reference, as removing the last element from
+ // it via ClearDataHelper invalidated it. so we can't MOZ_ASSERT that the
+ // length is now 0.
+ return;
+ }
+
+ for (uint32_t i = 0; i < count; ++i) {
+ // NOTE: As this is a moz-prefixed API, it works based on internal types.
+ nsAutoString type;
+ items[i]->GetInternalType(type);
+ if (type == aType) {
+ ClearDataHelper(items[i], -1, i, aSubjectPrincipal, aRv);
+ return;
+ }
+ }
+}
+
+DataTransferItem* DataTransferItemList::MozItemByTypeAt(const nsAString& aType,
+ uint32_t aIndex) {
+ if (NS_WARN_IF(aIndex >= mIndexedItems.Length())) {
+ return nullptr;
+ }
+
+ uint32_t count = mIndexedItems[aIndex].Length();
+ for (uint32_t i = 0; i < count; i++) {
+ RefPtr<DataTransferItem> item = mIndexedItems[aIndex][i];
+ // NOTE: As this is a moz-prefixed API it works on internal types
+ nsString type;
+ item->GetInternalType(type);
+ if (type.Equals(aType)) {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+already_AddRefed<DataTransferItem> DataTransferItemList::SetDataWithPrincipal(
+ const nsAString& aType, nsIVariant* aData, uint32_t aIndex,
+ nsIPrincipal* aPrincipal, bool aInsertOnly, bool aHidden,
+ ErrorResult& aRv) {
+ if (aIndex < mIndexedItems.Length()) {
+ nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex];
+ uint32_t count = items.Length();
+ for (uint32_t i = 0; i < count; i++) {
+ RefPtr<DataTransferItem> item = items[i];
+ nsString type;
+ item->GetInternalType(type);
+ if (type.Equals(aType)) {
+ if (NS_WARN_IF(aInsertOnly)) {
+ aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+ return nullptr;
+ }
+
+ // don't allow replacing data that has a stronger principal
+ bool subsumes;
+ if (NS_WARN_IF(item->Principal() && aPrincipal &&
+ (NS_FAILED(aPrincipal->Subsumes(item->Principal(),
+ &subsumes)) ||
+ !subsumes))) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+ item->SetPrincipal(aPrincipal);
+
+ DataTransferItem::eKind oldKind = item->Kind();
+ item->SetData(aData);
+
+ mDataTransfer->TypesListMayHaveChanged();
+
+ if (aIndex != 0) {
+ // If the item changes from being a file to not a file or vice-versa,
+ // its presence in the mItems array may need to change.
+ if (item->Kind() == DataTransferItem::KIND_FILE &&
+ oldKind != DataTransferItem::KIND_FILE) {
+ // not file => file
+ mItems.AppendElement(item);
+ } else if (item->Kind() != DataTransferItem::KIND_FILE &&
+ oldKind == DataTransferItem::KIND_FILE) {
+ // file => not file
+ mItems.RemoveElement(item);
+ }
+ }
+
+ // Regenerate the Files array if we have modified a file's status
+ if (item->Kind() == DataTransferItem::KIND_FILE ||
+ oldKind == DataTransferItem::KIND_FILE) {
+ RegenerateFiles();
+ }
+
+ return item.forget();
+ }
+ }
+ } else {
+ // Make sure that we aren't adding past the end of the mIndexedItems array.
+ // XXX Should this be a MOZ_ASSERT instead?
+ aIndex = mIndexedItems.Length();
+ }
+
+ // Add the new item
+ RefPtr<DataTransferItem> item =
+ AppendNewItem(aIndex, aType, aData, aPrincipal, aHidden);
+
+ if (item->Kind() == DataTransferItem::KIND_FILE) {
+ RegenerateFiles();
+ }
+
+ return item.forget();
+}
+
+DataTransferItem* DataTransferItemList::AppendNewItem(uint32_t aIndex,
+ const nsAString& aType,
+ nsIVariant* aData,
+ nsIPrincipal* aPrincipal,
+ bool aHidden) {
+ if (mIndexedItems.Length() <= aIndex) {
+ MOZ_ASSERT(mIndexedItems.Length() == aIndex);
+ mIndexedItems.AppendElement();
+ }
+ RefPtr<DataTransferItem> item = new DataTransferItem(mDataTransfer, aType);
+ item->SetIndex(aIndex);
+ item->SetPrincipal(aPrincipal);
+ item->SetData(aData);
+ item->SetChromeOnly(aHidden);
+
+ mIndexedItems[aIndex].AppendElement(item);
+
+ // We only want to add the item to the main mItems list if the index we are
+ // adding to is 0, or the item we are adding is a file. If we add an item
+ // which is not a file to a non-zero index, invariants could be broken.
+ // (namely the invariant that there are not 2 non-file entries in the items
+ // array with the same type).
+ //
+ // We also want to update our DataTransfer's type list any time we're adding a
+ // KIND_FILE item, or an item at index 0.
+ if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) {
+ if (!aHidden) {
+ mItems.AppendElement(item);
+ }
+ mDataTransfer->TypesListMayHaveChanged();
+ }
+
+ return item;
+}
+
+void DataTransferItemList::GetTypes(nsTArray<nsString>& aTypes,
+ CallerType aCallerType) const {
+ MOZ_ASSERT(aTypes.IsEmpty());
+
+ if (mIndexedItems.IsEmpty()) {
+ return;
+ }
+
+ bool foundFile = false;
+ for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
+ MOZ_ASSERT(item);
+
+ // XXX Why don't we check the caller type with item's permission only
+ // for "Files"?
+ if (!foundFile) {
+ foundFile = item->Kind() == DataTransferItem::KIND_FILE;
+ }
+
+ if (item->ChromeOnly() && aCallerType != CallerType::System) {
+ continue;
+ }
+
+ // NOTE: The reason why we get the internal type here is because we want
+ // kFileMime to appear in the types list for backwards compatibility
+ // reasons.
+ nsAutoString type;
+ item->GetInternalType(type);
+ if (item->Kind() != DataTransferItem::KIND_FILE ||
+ type.EqualsASCII(kFileMime)) {
+ aTypes.AppendElement(type);
+ }
+ }
+
+ // Additional files will be added at a non-zero index.
+ if (!foundFile) {
+ for (uint32_t i = 1; i < mIndexedItems.Length(); i++) {
+ for (const RefPtr<DataTransferItem>& item : mIndexedItems[i]) {
+ MOZ_ASSERT(item);
+
+ foundFile = item->Kind() == DataTransferItem::KIND_FILE;
+ if (foundFile) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundFile) {
+ aTypes.AppendElement(u"Files"_ns);
+ }
+}
+
+bool DataTransferItemList::HasType(const nsAString& aType) const {
+ MOZ_ASSERT(!aType.EqualsASCII("Files"), "Use HasFile instead");
+ if (mIndexedItems.IsEmpty()) {
+ return false;
+ }
+
+ for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
+ if (item->IsInternalType(aType)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DataTransferItemList::HasFile() const {
+ if (mIndexedItems.IsEmpty()) {
+ return false;
+ }
+
+ for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
+ if (item->Kind() == DataTransferItem::KIND_FILE) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const nsTArray<RefPtr<DataTransferItem>>* DataTransferItemList::MozItemsAt(
+ uint32_t aIndex) // -- INDEXED
+{
+ if (aIndex >= mIndexedItems.Length()) {
+ return nullptr;
+ }
+
+ return &mIndexedItems[aIndex];
+}
+
+void DataTransferItemList::PopIndexZero() {
+ MOZ_ASSERT(mIndexedItems.Length() > 1);
+ MOZ_ASSERT(mIndexedItems[0].IsEmpty());
+
+ mIndexedItems.RemoveElementAt(0);
+
+ // Update the index of every element which has now been shifted
+ for (uint32_t i = 0; i < mIndexedItems.Length(); i++) {
+ nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
+ for (uint32_t j = 0; j < items.Length(); j++) {
+ items[j]->SetIndex(i);
+ }
+ }
+}
+
+void DataTransferItemList::ClearAllItems() {
+ // We always need to have index 0, so don't delete that one
+ mItems.Clear();
+ mIndexedItems.Clear();
+ mIndexedItems.SetLength(1);
+ mDataTransfer->TypesListMayHaveChanged();
+
+ // Re-generate files (into an empty list)
+ RegenerateFiles();
+}
+
+void DataTransferItemList::ClearDataHelper(DataTransferItem* aItem,
+ uint32_t aIndexHint,
+ uint32_t aMozOffsetHint,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv) {
+ MOZ_ASSERT(aItem);
+ if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
+ return;
+ }
+
+ if (aItem->Principal() && !aSubjectPrincipal.Subsumes(aItem->Principal())) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ // Check if the aIndexHint is actually the index, and then remove the item
+ // from aItems
+ bool found;
+ if (IndexedGetter(aIndexHint, found) == aItem) {
+ mItems.RemoveElementAt(aIndexHint);
+ } else {
+ mItems.RemoveElement(aItem);
+ }
+
+ // Check if the aMozIndexHint and aMozOffsetHint are actually the index and
+ // offset, and then remove them from mIndexedItems
+ MOZ_ASSERT(aItem->Index() < mIndexedItems.Length());
+ nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aItem->Index()];
+ if (aMozOffsetHint < items.Length() && aItem == items[aMozOffsetHint]) {
+ items.RemoveElementAt(aMozOffsetHint);
+ } else {
+ items.RemoveElement(aItem);
+ }
+
+ mDataTransfer->TypesListMayHaveChanged();
+
+ // Check if we should remove the index. We never remove index 0.
+ if (items.Length() == 0 && aItem->Index() != 0) {
+ mIndexedItems.RemoveElementAt(aItem->Index());
+
+ // Update the index of every element which has now been shifted
+ for (uint32_t i = aItem->Index(); i < mIndexedItems.Length(); i++) {
+ nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
+ for (uint32_t j = 0; j < items.Length(); j++) {
+ items[j]->SetIndex(i);
+ }
+ }
+ }
+
+ // Give the removed item the invalid index
+ aItem->SetIndex(-1);
+
+ if (aItem->Kind() == DataTransferItem::KIND_FILE) {
+ RegenerateFiles();
+ }
+}
+
+void DataTransferItemList::RegenerateFiles() {
+ // We don't want to regenerate the files list unless we already have a files
+ // list. That way we can avoid the unnecessary work if the user never touches
+ // the files list.
+ if (mFiles) {
+ // We clear the list rather than performing smaller updates, because it
+ // simplifies the logic greatly on this code path, which should be very
+ // infrequently used.
+ mFiles->Clear();
+
+ DataTransferItemList::GenerateFiles(mFiles, mFilesPrincipal);
+ }
+}
+
+void DataTransferItemList::GenerateFiles(FileList* aFiles,
+ nsIPrincipal* aFilesPrincipal) {
+ MOZ_ASSERT(aFiles);
+ MOZ_ASSERT(aFilesPrincipal);
+
+ // For non-system principals, the Files list should be empty if the
+ // DataTransfer is protected.
+ if (!aFilesPrincipal->IsSystemPrincipal() && mDataTransfer->IsProtected()) {
+ return;
+ }
+
+ uint32_t count = Length();
+ for (uint32_t i = 0; i < count; i++) {
+ bool found;
+ RefPtr<DataTransferItem> item = IndexedGetter(i, found);
+ MOZ_ASSERT(found);
+
+ if (item->Kind() == DataTransferItem::KIND_FILE) {
+ RefPtr<File> file = item->GetAsFile(*aFilesPrincipal, IgnoreErrors());
+ if (NS_WARN_IF(!file)) {
+ continue;
+ }
+ aFiles->Append(file);
+ }
+ }
+}
+
+} // namespace mozilla::dom