From 0db597935ed62a39f17cc6bdd409d9514572d1dd Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Fri, 10 Jul 2015 18:57:23 +0100 Subject: [PATCH] Bug 1164310, part 6 - Implement the new Promise returning DataTransfer.getFilesAndDirectories() API. r=baku --- dom/base/nsContentUtils.cpp | 3 ++ dom/events/DataTransfer.cpp | 95 ++++++++++++++++++++++++++++++++++ dom/events/DataTransfer.h | 4 ++ dom/webidl/DataTransfer.webidl | 5 ++ 4 files changed, 107 insertions(+) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 5abc257bb38..04f5c7babd3 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7464,8 +7464,11 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable, if (file) { blobImpl = new BlobImplFile(file, false); ErrorResult rv; + // Ensure that file data is cached no that the content process + // has this data available to it when passed over: blobImpl->GetSize(rv); blobImpl->GetLastModified(rv); + blobImpl->LookupAndCacheIsDirectory(); } else { blobImpl = do_QueryInterface(data); } diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 774ff01d82b..322bd68960f 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -26,8 +26,10 @@ #include "nsIScriptGlobalObject.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/DataTransferBinding.h" +#include "mozilla/dom/Directory.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/OSFileSystem.h" namespace mozilla { namespace dom { @@ -295,6 +297,13 @@ DataTransfer::GetFiles(ErrorResult& aRv) nsRefPtr domFile; if (file) { +#ifdef DEBUG + if (XRE_GetProcessType() == GeckoProcessType_Default) { + bool isDir; + file->IsDirectory(&isDir); + MOZ_ASSERT(!isDir, "How did we get here?"); + } +#endif domFile = File::CreateFromFile(GetParentObject(), file); } else { nsCOMPtr blobImpl = do_QueryInterface(supports); @@ -814,6 +823,92 @@ DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY) return rv.StealNSResult(); } +static already_AddRefed +MakeOrReuseFileSystem(const nsAString& aNewLocalRootPath, + OSFileSystem* aFS, + nsPIDOMWindow* aWindow) +{ + MOZ_ASSERT(aWindow); + + nsRefPtr fs; + if (aFS) { + const nsAString& prevLocalRootPath = aFS->GetLocalRootPath(); + if (aNewLocalRootPath == prevLocalRootPath) { + fs = aFS; + } + } + if (!fs) { + fs = new OSFileSystem(aNewLocalRootPath); + fs->Init(aWindow); + } + return fs.forget(); +} + +already_AddRefed +DataTransfer::GetFilesAndDirectories(ErrorResult& aRv) +{ + nsCOMPtr parentNode = do_QueryInterface(mParent); + if (!parentNode) { + return nullptr; + } + + nsCOMPtr global = parentNode->OwnerDoc()->GetScopeObject(); + MOZ_ASSERT(global); + if (!global) { + return nullptr; + } + + nsRefPtr p = Promise::Create(global, aRv); + if (aRv.Failed()) { + return nullptr; + } + + if (!mFiles) { + ErrorResult dummy; + GetFiles(dummy); + if (!mFiles) { + return nullptr; + } + } + + Sequence filesAndDirsSeq; + + if (!filesAndDirsSeq.SetLength(mFiles->Length(), mozilla::fallible_t())) { + p->MaybeReject(NS_ERROR_OUT_OF_MEMORY); + return p.forget(); + } + + nsPIDOMWindow* window = parentNode->OwnerDoc()->GetInnerWindow(); + + nsRefPtr fs; + for (uint32_t i = 0; i < mFiles->Length(); ++i) { + if (mFiles->Item(i)->Impl()->IsDirectory()) { +#if defined(ANDROID) || defined(MOZ_B2G) + MOZ_ASSERT(false, + "Directory picking should have been redirected to normal " + "file picking for platforms that don't have a directory " + "picker"); +#endif + nsAutoString path; + mFiles->Item(i)->GetMozFullPathInternal(path, aRv); + if (aRv.Failed()) { + return nullptr; + } + int32_t leafSeparatorIndex = path.RFind(FILE_PATH_SEPARATOR); + nsDependentSubstring dirname = Substring(path, 0, leafSeparatorIndex); + nsDependentSubstring basename = Substring(path, leafSeparatorIndex); + fs = MakeOrReuseFileSystem(dirname, fs, window); + filesAndDirsSeq[i].SetAsDirectory() = new Directory(fs, basename); + } else { + filesAndDirsSeq[i].SetAsFile() = mFiles->Item(i); + } + } + + p->MaybeResolve(filesAndDirsSeq); + + return p.forget(); +} + void DataTransfer::AddElement(Element& aElement, ErrorResult& aRv) { diff --git a/dom/events/DataTransfer.h b/dom/events/DataTransfer.h index e31c431ed7a..db89f2cf708 100644 --- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -19,6 +19,7 @@ #include "nsAutoPtr.h" #include "mozilla/Attributes.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/Promise.h" class nsINode; class nsITransferable; @@ -145,6 +146,9 @@ public: void ClearData(const mozilla::dom::Optional& aFormat, mozilla::ErrorResult& aRv); FileList* GetFiles(mozilla::ErrorResult& aRv); + + already_AddRefed GetFilesAndDirectories(ErrorResult& aRv); + void AddElement(Element& aElement, mozilla::ErrorResult& aRv); uint32_t MozItemCount() { diff --git a/dom/webidl/DataTransfer.webidl b/dom/webidl/DataTransfer.webidl index 54bb1f607db..51b99943025 100644 --- a/dom/webidl/DataTransfer.webidl +++ b/dom/webidl/DataTransfer.webidl @@ -28,6 +28,11 @@ interface DataTransfer { readonly attribute FileList? files; }; +partial interface DataTransfer { + [Throws, Pref="dom.input.dirpicker"] + Promise> getFilesAndDirectories(); +}; + // Mozilla specific stuff partial interface DataTransfer { /*