Bug 1265767 - Subset of Blink FileSystem API - patch 4 - DirectoryEntry methods, r=smaug

This commit is contained in:
Andrea Marchesini 2016-06-07 00:55:17 +02:00
parent 52fbfbc75d
commit 5a24e4a0ff
8 changed files with 223 additions and 18 deletions

View File

@ -5,6 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DirectoryEntry.h" #include "DirectoryEntry.h"
#include "DirectoryReader.h"
#include "ErrorCallbackRunnable.h" #include "ErrorCallbackRunnable.h"
#include "mozilla/dom/Directory.h" #include "mozilla/dom/Directory.h"
@ -49,6 +50,14 @@ DirectoryEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
mDirectory->GetPath(aPath, aRv); mDirectory->GetPath(aPath, aRv);
} }
already_AddRefed<DirectoryReader>
DirectoryEntry::CreateReader() const
{
RefPtr<DirectoryReader> reader =
new DirectoryReader(GetParentObject(), mDirectory);
return reader.forget();
}
void void
DirectoryEntry::RemoveRecursively(VoidCallback& aSuccessCallback, DirectoryEntry::RemoveRecursively(VoidCallback& aSuccessCallback,
const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const

View File

@ -39,11 +39,7 @@ public:
GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const override; GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const override;
already_AddRefed<DirectoryReader> already_AddRefed<DirectoryReader>
CreateReader(ErrorResult& aRv) const CreateReader() const;
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
}
void void
GetFile(const nsAString& aPath, const FileSystemFlags& aFlag, GetFile(const nsAString& aPath, const FileSystemFlags& aFlag,

View File

@ -5,12 +5,132 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DirectoryReader.h" #include "DirectoryReader.h"
#include "FileEntry.h"
#include "mozilla/dom/FileBinding.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "nsIGlobalObject.h" #include "nsIGlobalObject.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DirectoryReader, mParent) namespace {
class EmptyEntriesCallbackRunnable final : public Runnable
{
public:
EmptyEntriesCallbackRunnable(EntriesCallback* aCallback)
: mCallback(aCallback)
{
MOZ_ASSERT(aCallback);
}
NS_IMETHOD
Run() override
{
Sequence<OwningNonNull<Entry>> sequence;
mCallback->HandleEvent(sequence);
return NS_OK;
}
private:
RefPtr<EntriesCallback> mCallback;
};
class PromiseHandler final : public PromiseNativeHandler
{
public:
NS_DECL_ISUPPORTS
PromiseHandler(nsIGlobalObject* aGlobalObject,
EntriesCallback* aSuccessCallback,
ErrorCallback* aErrorCallback)
: mGlobal(aGlobalObject)
, mSuccessCallback(aSuccessCallback)
, mErrorCallback(aErrorCallback)
{
MOZ_ASSERT(aGlobalObject);
MOZ_ASSERT(aSuccessCallback);
}
virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if(NS_WARN_IF(!aValue.isObject())) {
return;
}
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
uint32_t length;
if (NS_WARN_IF(!JS_GetArrayLength(aCx, obj, &length))) {
return;
}
Sequence<OwningNonNull<Entry>> sequence;
if (NS_WARN_IF(!sequence.SetLength(length, fallible))) {
return;
}
for (uint32_t i = 0; i < length; ++i) {
JS::Rooted<JS::Value> value(aCx);
if (NS_WARN_IF(!JS_GetElement(aCx, obj, i, &value))) {
return;
}
if(NS_WARN_IF(!value.isObject())) {
return;
}
JS::Rooted<JSObject*> valueObj(aCx, &value.toObject());
RefPtr<File> file;
if (NS_SUCCEEDED(UNWRAP_OBJECT(File, valueObj, file))) {
RefPtr<FileEntry> entry = new FileEntry(mGlobal, file);
sequence[i] = entry;
continue;
}
RefPtr<Directory> directory;
if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Directory, valueObj,
directory)))) {
return;
}
RefPtr<DirectoryEntry> entry = new DirectoryEntry(mGlobal, directory);
sequence[i] = entry;
}
mSuccessCallback->HandleEvent(sequence);
}
virtual void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
{
if (mErrorCallback) {
RefPtr<ErrorCallbackRunnable> runnable =
new ErrorCallbackRunnable(mGlobal, mErrorCallback,
NS_ERROR_DOM_INVALID_STATE_ERR);
nsresult rv = NS_DispatchToMainThread(runnable);
NS_WARN_IF(NS_FAILED(rv));
}
}
private:
~PromiseHandler() {}
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<EntriesCallback> mSuccessCallback;
RefPtr<ErrorCallback> mErrorCallback;
};
NS_IMPL_ISUPPORTS0(PromiseHandler);
} // anonymous namespace
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DirectoryReader, mParent, mDirectory)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DirectoryReader) NS_IMPL_CYCLE_COLLECTING_ADDREF(DirectoryReader)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DirectoryReader) NS_IMPL_CYCLE_COLLECTING_RELEASE(DirectoryReader)
@ -20,9 +140,15 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DirectoryReader)
NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
DirectoryReader::DirectoryReader(nsIGlobalObject* aGlobal) DirectoryReader::DirectoryReader(nsIGlobalObject* aGlobal,
Directory* aDirectory)
: mParent(aGlobal) : mParent(aGlobal)
{} , mDirectory(aDirectory)
, mAlreadyRead(false)
{
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(aDirectory);
}
DirectoryReader::~DirectoryReader() DirectoryReader::~DirectoryReader()
{} {}
@ -33,5 +159,43 @@ DirectoryReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DirectoryReaderBinding::Wrap(aCx, this, aGivenProto); return DirectoryReaderBinding::Wrap(aCx, this, aGivenProto);
} }
void
DirectoryReader::ReadEntries(EntriesCallback& aSuccessCallback,
const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
ErrorResult& aRv)
{
if (mAlreadyRead) {
RefPtr<EmptyEntriesCallbackRunnable> runnable =
new EmptyEntriesCallbackRunnable(&aSuccessCallback);
aRv = NS_DispatchToMainThread(runnable);
NS_WARN_IF(aRv.Failed());
return;
}
// This object can be used only once.
mAlreadyRead = true;
ErrorResult rv;
RefPtr<Promise> promise = mDirectory->GetFilesAndDirectories(rv);
if (NS_WARN_IF(rv.Failed())) {
if (aErrorCallback.WasPassed()) {
RefPtr<ErrorCallbackRunnable> runnable =
new ErrorCallbackRunnable(GetParentObject(),
&aErrorCallback.Value(),
rv.StealNSResult());
aRv = NS_DispatchToMainThread(runnable);
NS_WARN_IF(aRv.Failed());
}
return;
}
RefPtr<PromiseHandler> handler =
new PromiseHandler(GetParentObject(), &aSuccessCallback,
aErrorCallback.WasPassed()
? &aErrorCallback.Value() : nullptr);
promise->AppendNativeHandler(handler);
}
} // dom namespace } // dom namespace
} // mozilla namespace } // mozilla namespace

View File

@ -18,6 +18,8 @@ class nsIGlobalObject;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class Directory;
class DirectoryReader final class DirectoryReader final
: public nsISupports : public nsISupports
, public nsWrapperCache , public nsWrapperCache
@ -26,7 +28,8 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DirectoryReader) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DirectoryReader)
explicit DirectoryReader(nsIGlobalObject* aGlobalObject); explicit DirectoryReader(nsIGlobalObject* aGlobalObject,
Directory* aDirectory);
nsIGlobalObject* nsIGlobalObject*
GetParentObject() const GetParentObject() const
@ -40,15 +43,15 @@ public:
void void
ReadEntries(EntriesCallback& aSuccessCallback, ReadEntries(EntriesCallback& aSuccessCallback,
const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback, const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
ErrorResult& aRv) const ErrorResult& aRv);
{
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
}
private: private:
~DirectoryReader(); ~DirectoryReader();
nsCOMPtr<nsIGlobalObject> mParent; nsCOMPtr<nsIGlobalObject> mParent;
RefPtr<Directory> mDirectory;
bool mAlreadyRead;
}; };
} // namespace dom } // namespace dom

View File

@ -17,12 +17,15 @@ class ErrorCallbackRunnable final : public Runnable
{ {
public: public:
explicit ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject, explicit ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
ErrorCallback* aCallback) ErrorCallback* aCallback,
nsresult aError = NS_ERROR_DOM_NOT_SUPPORTED_ERR)
: mGlobal(aGlobalObject) : mGlobal(aGlobalObject)
, mCallback(aCallback) , mCallback(aCallback)
, mError(aError)
{ {
MOZ_ASSERT(aGlobalObject); MOZ_ASSERT(aGlobalObject);
MOZ_ASSERT(aCallback); MOZ_ASSERT(aCallback);
MOZ_ASSERT(NS_FAILED(aError));
} }
NS_IMETHOD NS_IMETHOD
@ -33,8 +36,7 @@ public:
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
RefPtr<DOMError> error = RefPtr<DOMError> error = new DOMError(window, mError);
new DOMError(window, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
mCallback->HandleEvent(*error); mCallback->HandleEvent(*error);
return NS_OK; return NS_OK;
} }
@ -42,6 +44,7 @@ public:
private: private:
nsCOMPtr<nsIGlobalObject> mGlobal; nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<ErrorCallback> mCallback; RefPtr<ErrorCallback> mCallback;
nsresult mError;
}; };
} // dom namespace } // dom namespace

View File

@ -89,6 +89,33 @@ function test_directoryEntry() {
next(); next();
} }
function test_directoryEntry_createReader() {
var reader = directoryEntry.createReader();
ok(reader, "We have a DirectoryReader");
reader.readEntries(function(a) {
ok(Array.isArray(a), "We want an array.");
is(a.length, 2, "reader.readyEntries returns 2 elements.");
for (var i = 0; i < 2; ++i) {
ok(a[i].name == "subdir" || a[i].name == "foo.txt", "Correct names");
is(a[i].fullPath, directoryEntry.fullPath + "/" + a[i].name, "FullPath is correct");
}
// Called twice:
reader.readEntries(function(a) {
ok(Array.isArray(a), "We want an array.");
is(a.length, 0, "reader.readyEntries returns 0 elements.");
next();
}, function() {
ok(false, "Something when wrong!");
});
}, function() {
ok(false, "Something when wrong!");
});
}
var tests = [ var tests = [
setup_tests, setup_tests,
populate_entries, populate_entries,
@ -100,6 +127,7 @@ var tests = [
test_fileEntry_createWriter, test_fileEntry_createWriter,
test_directoryEntry, test_directoryEntry,
test_directoryEntry_createReader,
]; ];
function next() { function next() {

View File

@ -32,7 +32,7 @@ public:
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0; RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
#ifdef SPIDERMONKEY_PROMISE #ifdef SPIDERMONKEY_PROMISE
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aWrapper); JS::MutableHandle<JSObject*> aWrapper);
#endif // SPIDERMONKEY_PROMISE #endif // SPIDERMONKEY_PROMISE

View File

@ -43,7 +43,6 @@ callback interface VoidCallback {
[NoInterfaceObject] [NoInterfaceObject]
interface DirectoryEntry : Entry { interface DirectoryEntry : Entry {
[Throws]
DirectoryReader createReader(); DirectoryReader createReader();
[Throws] [Throws]
@ -68,6 +67,9 @@ callback interface ErrorCallback {
[NoInterfaceObject] [NoInterfaceObject]
interface DirectoryReader { interface DirectoryReader {
// readEntries can be called just once. The second time it returns no data.
[Throws] [Throws]
void readEntries (EntriesCallback successCallback, optional ErrorCallback errorCallback); void readEntries (EntriesCallback successCallback, optional ErrorCallback errorCallback);
}; };