From 08c222b3594a72492d427aac5edfbbc3fe22edf4 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Tue, 12 Apr 2016 17:56:00 +0200 Subject: [PATCH] Backed out changeset 166555b48e77 (bug 1258482) --- dom/base/FileList.cpp | 96 ++++++++++----- dom/base/FileList.h | 35 ++++-- dom/base/StructuredCloneHolder.cpp | 124 ++++++++++++++------ dom/base/test/test_postMessages.html | 26 +++- dom/events/DataTransfer.cpp | 6 +- dom/filesystem/tests/test_basic.html | 14 +-- dom/filesystem/tests/test_worker_basic.html | 28 +++-- dom/filesystem/tests/worker_basic.js | 8 +- dom/html/HTMLInputElement.cpp | 5 +- dom/webidl/FileList.webidl | 4 +- embedding/browser/nsDocShellTreeOwner.cpp | 4 +- 11 files changed, 241 insertions(+), 109 deletions(-) diff --git a/dom/base/FileList.cpp b/dom/base/FileList.cpp index 79aef3e065fb..41dd07a71dde 100644 --- a/dom/base/FileList.cpp +++ b/dom/base/FileList.cpp @@ -12,7 +12,7 @@ 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 @@ -29,6 +29,20 @@ FileList::WrapObject(JSContext* aCx, JS::Handle 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) { @@ -40,47 +54,75 @@ FileList::GetLength(uint32_t* aLength) NS_IMETHODIMP FileList::Item(uint32_t aIndex, nsISupports** aValue) { - nsCOMPtr file = Item(aIndex); - file.forget(aValue); + if (aIndex >= mFilesOrDirectories.Length()) { + return NS_ERROR_FAILURE; + } + + if (mFilesOrDirectories[aIndex].IsFile()) { + nsCOMPtr file = mFilesOrDirectories[aIndex].GetAsFile(); + file.forget(aValue); + return NS_OK; + } + + MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory()); + RefPtr directory = mFilesOrDirectories[aIndex].GetAsDirectory(); + directory.forget(aValue); return NS_OK; } -File* -FileList::Item(uint32_t aIndex) const -{ - if (aIndex >= mFiles.Length()) { - return nullptr; - } - - return mFiles[aIndex]; -} - -File* -FileList::IndexedGetter(uint32_t aIndex, bool& aFound) const -{ - aFound = aIndex < mFiles.Length(); - return Item(aIndex); -} - void -FileList::ToSequence(Sequence>& aSequence, - ErrorResult& aRv) const +FileList::Item(uint32_t aIndex, Nullable& aValue, + ErrorResult& aRv) const { - MOZ_ASSERT(aSequence.IsEmpty()); - if (mFiles.IsEmpty()) { + if (aIndex >= mFilesOrDirectories.Length()) { + aValue.SetNull(); return; } - if (!aSequence.SetLength(mFiles.Length(), + aValue.SetValue(mFilesOrDirectories[aIndex]); +} + +void +FileList::IndexedGetter(uint32_t aIndex, bool& aFound, + Nullable& aFileOrDirectory, + ErrorResult& aRv) const +{ + aFound = aIndex < mFilesOrDirectories.Length(); + Item(aIndex, aFileOrDirectory, aRv); +} + +void +FileList::ToSequence(Sequence& 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 < mFiles.Length(); ++i) { - aSequence[i] = mFiles[i]; + for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) { + aSequence[i] = mFilesOrDirectories[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 diff --git a/dom/base/FileList.h b/dom/base/FileList.h index cf951ad3490d..b6aeeb7940a2 100644 --- a/dom/base/FileList.h +++ b/dom/base/FileList.h @@ -40,16 +40,13 @@ public: return mParent; } - bool Append(File* aFile) - { - MOZ_ASSERT(aFile); - return mFiles.AppendElement(aFile, fallible); - } + 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; } @@ -58,7 +55,7 @@ public: void Clear() { - return mFiles.Clear(); + return mFilesOrDirectories.Clear(); } static FileList* FromSupports(nsISupports* aSupports) @@ -78,22 +75,34 @@ public: return static_cast(aSupports); } - File* Item(uint32_t aIndex) const; + const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const + { + MOZ_ASSERT(aIndex < Length()); + return mFilesOrDirectories[aIndex]; + } - File* IndexedGetter(uint32_t aIndex, bool& aFound) const; + void Item(uint32_t aIndex, + Nullable& aFileOrDirectory, + ErrorResult& aRv) const; + + void IndexedGetter(uint32_t aIndex, bool& aFound, + Nullable& aFileOrDirectory, + ErrorResult& aRv) const; uint32_t Length() const { - return mFiles.Length(); + return mFilesOrDirectories.Length(); } - void ToSequence(Sequence>& aSequence, + void ToSequence(Sequence& aSequence, ErrorResult& aRv) const; + bool ClonableToDifferentThreadOrProcess() const; + private: ~FileList() {} - FallibleTArray> mFiles; + nsTArray mFilesOrDirectories; nsCOMPtr mParent; }; diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 559761458280..73d48d0f55ae 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -794,35 +794,59 @@ ReadFileList(JSContext* aCx, { RefPtr fileList = new FileList(aHolder->ParentDuringRead()); - 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|. + // |aCount| is the number of Files or Directory for this FileList. for (uint32_t i = 0; i < aCount; ++i) { - uint32_t pos = index + i; - MOZ_ASSERT(pos < aHolder->BlobImpls().Length()); - - RefPtr blobImpl = aHolder->BlobImpls()[pos]; - 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); - RefPtr file = File::Create(aHolder->ParentDuringRead(), blobImpl); - if (!fileList->Append(file)) { + if (tagOrDirectoryType == SCTAG_DOM_BLOB) { + MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length()); + + RefPtr blobImpl = + aHolder->BlobImpls()[indexOrLengthOfString]; + MOZ_ASSERT(blobImpl->IsFile()); + + ErrorResult rv; + blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return nullptr; + } + + RefPtr 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 file; + nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true, + getter_AddRefs(file)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + RefPtr directory = + Directory::Create(aHolder->ParentDuringRead(), file, + (Directory::DirectoryType) tagOrDirectoryType); + fileList->Append(directory); } if (!ToJSValue(aCx, fileList, &val)) { @@ -835,7 +859,13 @@ ReadFileList(JSContext* aCx, // 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, @@ -845,13 +875,8 @@ WriteFileList(JSStructuredCloneWriter* 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; } @@ -859,18 +884,39 @@ WriteFileList(JSStructuredCloneWriter* aWriter, nsTArray> blobImpls; for (uint32_t i = 0; i < aFileList->Length(); ++i) { - RefPtr blobImpl = - EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv); - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - return false; + const OwningFileOrDirectory& data = aFileList->UnsafeItem(i); + + if (data.IsFile()) { + RefPtr 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(blobImpl); - blobImpls.AppendElement(blobImpl); + 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; + } } - aHolder->BlobImpls().AppendElements(blobImpls); return true; } @@ -1086,7 +1132,9 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, // See if this is a FileList object. { FileList* fileList = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) { + if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList)) && + (mSupportedContext == SameProcessSameThread || + fileList->ClonableToDifferentThreadOrProcess())) { return WriteFileList(aWriter, fileList, this); } } diff --git a/dom/base/test/test_postMessages.html b/dom/base/test/test_postMessages.html index e6e9e7914dce..93e9511bf163 100644 --- a/dom/base/test/test_postMessages.html +++ b/dom/base/test/test_postMessages.html @@ -72,7 +72,7 @@ var clonableObjects = [ new ImageData(2, 2), ]; -function create_fileList() { +function create_fileList_forFile() { var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js"); var script = SpecialPowers.loadChromeScript(url); @@ -93,6 +93,27 @@ function create_fileList() { 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(); @@ -527,7 +548,8 @@ function test_messagePort_inWorkers() { } var tests = [ - create_fileList, + create_fileList_forFile, + create_fileList_forDir, create_directory, test_windowToWindow, diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 2e105e99b19e..e687509aa87a 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -866,13 +866,13 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv) } } - Sequence> filesSeq; - mFileList->ToSequence(filesSeq, aRv); + Sequence filesAndDirsSeq; + mFileList->ToSequence(filesAndDirsSeq, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } - p->MaybeResolve(filesSeq); + p->MaybeResolve(filesAndDirsSeq); return p.forget(); } diff --git a/dom/filesystem/tests/test_basic.html b/dom/filesystem/tests/test_basic.html index 7e170fd23d72..1a929f56a821 100644 --- a/dom/filesystem/tests/test_basic.html +++ b/dom/filesystem/tests/test_basic.html @@ -20,14 +20,14 @@ function create_fileList(aPath) { var fileList = document.getElementById('fileList'); SpecialPowers.wrap(fileList).mozSetDirectory(message.dir); - fileList.getFilesAndDirectories().then(function(array) { - is(array.length, 1, "We want just 1 directory."); - ok(array[0] instanceof Directory, "We want just 1 directory."); + // Just a simple test + is(fileList.files.length, 1, "Filelist has 1 element"); + ok(fileList.files[0] instanceof Directory, "We have a directory."); - directory = array[0]; - script.destroy(); - next(); - }); + directory = fileList.files[0]; + + script.destroy(); + next(); } script.addMessageListener("dir.opened", onOpened); diff --git a/dom/filesystem/tests/test_worker_basic.html b/dom/filesystem/tests/test_worker_basic.html index 8e81251712ee..0be76962421a 100644 --- a/dom/filesystem/tests/test_worker_basic.html +++ b/dom/filesystem/tests/test_worker_basic.html @@ -17,6 +17,11 @@ function create_fileList() { 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(); } @@ -27,21 +32,20 @@ function create_fileList() { 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; - } - if (e.data.type == 'test') { - ok(e.data.test, e.data.message); - } + var worker = new Worker('worker_basic.js'); + worker.onmessage = function(e) { + if (e.data.type == 'finish') { + next(); + return; } - worker.postMessage(array[0]); - }); + if (e.data.type == 'test') { + ok(e.data.test, e.data.message); + } + } + + worker.postMessage(fileList.files); } var tests = [ diff --git a/dom/filesystem/tests/worker_basic.js b/dom/filesystem/tests/worker_basic.js index c27abcc32b3c..4da78eef0e5d 100644 --- a/dom/filesystem/tests/worker_basic.js +++ b/dom/filesystem/tests/worker_basic.js @@ -31,10 +31,12 @@ function checkSubDir(dir) { } onmessage = function(e) { - var directory = e.data; - ok(directory instanceof Directory, "This is a directory."); + 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."); - directory.getFilesAndDirectories().then( + fileList[0].getFilesAndDirectories().then( function(data) { ok(data.length, "We should have some data."); var promises = []; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 83fc75fbcd32..00d2d801d029 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -2562,7 +2562,7 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles, aFiles->GetLength(&listLength); for (uint32_t i = 0; i < listLength; i++) { OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement(); - element->SetAsFile() = files->Item(i); + *element = files->UnsafeItem(i); } } @@ -2678,6 +2678,9 @@ HTMLInputElement::UpdateFileList() 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()); } } } diff --git a/dom/webidl/FileList.webidl b/dom/webidl/FileList.webidl index 84a56be1bf90..0dc10401c390 100644 --- a/dom/webidl/FileList.webidl +++ b/dom/webidl/FileList.webidl @@ -11,6 +11,8 @@ */ interface FileList { - getter File? item(unsigned long index); + [Throws] + getter (File or Directory)? item(unsigned long index); + readonly attribute unsigned long length; }; diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index c9eee74c9f66..05e939761bf4 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -1186,7 +1186,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText, NS_ENSURE_SUCCESS(rv, rv); } else { FileList* fl = static_cast(fileList.get()); - fl->Item(0)->GetName(outText); + fl->UnsafeItem(0).GetAsFile()->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" @@ -1195,7 +1195,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText, uint32_t count = std::min(listLength, TRUNCATED_FILE_COUNT); for (uint32_t i = 1; i < count; ++i) { nsString fileName; - fl->Item(i)->GetName(fileName); + fl->UnsafeItem(i).GetAsFile()->GetName(fileName); outText.Append(NS_LITERAL_STRING("\n")); outText.Append(fileName); }