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

View File

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

View File

@ -5,12 +5,132 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#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"
namespace mozilla {
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_RELEASE(DirectoryReader)
@ -20,9 +140,15 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DirectoryReader)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
DirectoryReader::DirectoryReader(nsIGlobalObject* aGlobal)
DirectoryReader::DirectoryReader(nsIGlobalObject* aGlobal,
Directory* aDirectory)
: mParent(aGlobal)
{}
, mDirectory(aDirectory)
, mAlreadyRead(false)
{
MOZ_ASSERT(aGlobal);
MOZ_ASSERT(aDirectory);
}
DirectoryReader::~DirectoryReader()
{}
@ -33,5 +159,43 @@ DirectoryReader::WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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
} // mozilla namespace

View File

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

View File

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

View File

@ -89,6 +89,33 @@ function test_directoryEntry() {
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 = [
setup_tests,
populate_entries,
@ -100,6 +127,7 @@ var tests = [
test_fileEntry_createWriter,
test_directoryEntry,
test_directoryEntry_createReader,
];
function next() {

View File

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

View File

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