Implement FileSystemEntry.getParent()
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2017 17:37:00 +0000 (17:37 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Sep 2017 17:37:00 +0000 (17:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176165
<rdar://problem/34187743>

Reviewed by Andreas Kling.

Source/WebCore:

Implement FileSystemEntry.getParent():
- https://wicg.github.io/entries-api/#dom-filesystementry-getparent

Tests: editing/pasteboard/datatransfer-items-drop-getParent-root.html
       editing/pasteboard/datatransfer-items-drop-getParent.html
       editing/pasteboard/datatransfer-items-drop-getParent2.html

* Modules/entriesapi/DOMFileSystem.cpp:
(WebCore::toFileSystemEntries):
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

(WebCore::isAbsoluteVirtualPath):
Add utility function to determine if a virtual path is absolute:
- https://wicg.github.io/entries-api/#absolute-path

(WebCore::DOMFileSystem::root):
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

(WebCore::DOMFileSystem::fileAsEntry):
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

(WebCore::resolveRelativePath):
Add implementation for:
- https://wicg.github.io/entries-api/#resolve-a-relative-path

(WebCore::DOMFileSystem::listDirectory):
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

(WebCore::DOMFileSystem::getParent):
Add implementation of getParent() as per:
- https://wicg.github.io/entries-api/#dom-filesystementry-getparent

* Modules/entriesapi/DOMFileSystem.h:
(WebCore::DOMFileSystem::createEntryForFile):
* Modules/entriesapi/DOMFileSystem.idl:
* Modules/entriesapi/FileSystemDirectoryEntry.cpp:
(WebCore::FileSystemDirectoryEntry::FileSystemDirectoryEntry):
* Modules/entriesapi/FileSystemDirectoryEntry.h:
* Modules/entriesapi/FileSystemDirectoryReader.cpp:
(WebCore::FileSystemDirectoryReader::readEntries):
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

* Modules/entriesapi/FileSystemEntry.cpp:
(WebCore::FileSystemEntry::FileSystemEntry):
(WebCore::FileSystemEntry::activeDOMObjectName const):
(WebCore::FileSystemEntry::canSuspendForDocumentSuspension const):
(WebCore::FileSystemEntry::getParent):
* Modules/entriesapi/FileSystemEntry.h:
* Modules/entriesapi/FileSystemEntry.idl:
- Add implementation of FileSystemEntry.getParent() which relies on
  DOMFileSystem::getParent()
- Make FileSystemEntry an ActiveDOMObject as getParent() is an asynchronous
  operation which causes delayed JS execution.

* Modules/entriesapi/FileSystemFileEntry.cpp:
(WebCore::FileSystemFileEntry::FileSystemFileEntry):
* Modules/entriesapi/FileSystemFileEntry.h:
* dom/DataTransferItem.cpp:
(WebCore::DataTransferItem::getAsEntry const):
* dom/DataTransferItem.h:
* dom/DataTransferItem.idl:
Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.

LayoutTests:

* editing/pasteboard/datatransfer-items-drop-getParent-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-getParent-root-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-getParent-root.html: Added.
* editing/pasteboard/datatransfer-items-drop-getParent.html: Added.
* editing/pasteboard/datatransfer-items-drop-getParent2-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-getParent2.html: Added.
Add layout test coverage for FileSystemEntry.getParent().

* http/wpt/entries-api/interfaces-expected.txt:
Rebaseline test now that one more check is passing.

* platform/wk2/TestExpectations:
Skip new tests on WK2 since they rely on beginDragWithFiles.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221481 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2.html [new file with mode: 0644]
LayoutTests/http/wpt/entries-api/interfaces-expected.txt
LayoutTests/platform/wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp
Source/WebCore/Modules/entriesapi/DOMFileSystem.h
Source/WebCore/Modules/entriesapi/DOMFileSystem.idl
Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp
Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.h
Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp
Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp
Source/WebCore/Modules/entriesapi/FileSystemEntry.h
Source/WebCore/Modules/entriesapi/FileSystemEntry.idl
Source/WebCore/Modules/entriesapi/FileSystemFileEntry.cpp
Source/WebCore/Modules/entriesapi/FileSystemFileEntry.h
Source/WebCore/dom/DataTransferItem.cpp
Source/WebCore/dom/DataTransferItem.h
Source/WebCore/dom/DataTransferItem.idl

index f12c693..605a439 100644 (file)
@@ -1,3 +1,25 @@
+2017-09-01  Chris Dumez  <cdumez@apple.com>
+
+        Implement FileSystemEntry.getParent()
+        https://bugs.webkit.org/show_bug.cgi?id=176165
+        <rdar://problem/34187743>
+
+        Reviewed by Andreas Kling.
+
+        * editing/pasteboard/datatransfer-items-drop-getParent-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-getParent-root-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-getParent-root.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-getParent.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-getParent2-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-getParent2.html: Added.
+        Add layout test coverage for FileSystemEntry.getParent().
+
+        * http/wpt/entries-api/interfaces-expected.txt:
+        Rebaseline test now that one more check is passing.
+
+        * platform/wk2/TestExpectations:
+        Skip new tests on WK2 since they rely on beginDragWithFiles.
+
 2017-09-01  Ms2ger  <Ms2ger@igalia.com>
 
         [GTK] Mark audio-mpeg-supported.html as passing.
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-expected.txt b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-expected.txt
new file mode 100644 (file)
index 0000000..fda3459
--- /dev/null
@@ -0,0 +1,18 @@
+Basic test coverage for fileSystemEntry.getParent()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 2
+PASS firstEntryParent.name is ""
+PASS firstEntryParent.fullPath is "/"
+PASS firstEntryParent.isDirectory is true
+PASS firstEntryParent.isFile is false
+PASS secondEntryParent.name is ""
+PASS secondEntryParent.fullPath is "/"
+PASS secondEntryParent.isDirectory is true
+PASS secondEntryParent.isFile is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root-expected.txt b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root-expected.txt
new file mode 100644 (file)
index 0000000..e64464d
--- /dev/null
@@ -0,0 +1,13 @@
+Basic test coverage for fileSystemEntry.getParent() on the root
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rootParent.name is ""
+PASS rootParent.fullPath is "/"
+PASS rootParent.isDirectory is true
+PASS rootParent.isFile is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root.html b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent-root.html
new file mode 100644 (file)
index 0000000..30909c8
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemEntry.getParent() on the root");
+jsTestIsAsync = true;
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    let entry = dataTransfer.items[0].webkitGetAsEntry();
+    entry.filesystem.root.getParent(function(parent) {
+        rootParent = parent;
+
+        // Should be the root itself.
+        shouldBeEqualToString("rootParent.name", "");
+        shouldBeEqualToString("rootParent.fullPath", "/");
+        shouldBeTrue("rootParent.isDirectory");
+        shouldBeFalse("rootParent.isFile");
+
+        finishJSTest();
+    }, function(e) {
+        testFailed("getParent() call failed: " + e);
+        finishJSTest();
+    });
+};
+
+dropzone.ondragover = function(ev) {
+    ev.preventDefault();
+}
+
+onload = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/resources/test.txt']);
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent.html b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent.html
new file mode 100644 (file)
index 0000000..0ce0b0c
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemEntry.getParent()");
+jsTestIsAsync = true;
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "2");
+
+    firstDataTransferItem = dataTransfer.items[0];
+    firstEntry = firstDataTransferItem.webkitGetAsEntry();
+    secondDataTransferItem = dataTransfer.items[1];
+    secondEntry = secondDataTransferItem.webkitGetAsEntry();
+
+    firstEntry.getParent(function(parent) {
+        firstEntryParent = parent;
+        shouldBeEqualToString("firstEntryParent.name", "");
+        shouldBeEqualToString("firstEntryParent.fullPath", "/");
+        shouldBeTrue("firstEntryParent.isDirectory");
+        shouldBeFalse("firstEntryParent.isFile");
+
+        secondEntry.getParent(function(parent) {
+            secondEntryParent = parent;
+            shouldBeEqualToString("secondEntryParent.name", "");
+            shouldBeEqualToString("secondEntryParent.fullPath", "/");
+            shouldBeTrue("secondEntryParent.isDirectory");
+            shouldBeFalse("secondEntryParent.isFile");
+
+            finishJSTest();
+        }, function(e) {
+            testFailed("getParent() call failed: " + e);
+            finishJSTest();
+        });
+    }, function(e) {
+        testFailed("getParent() call failed: " + e);
+        finishJSTest();
+    });
+};
+
+dropzone.ondragover = function(ev) {
+    ev.preventDefault();
+}
+
+onload = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/resources/test.txt', '../../fast/forms/file/resources/testFiles']);
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2-expected.txt b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2-expected.txt
new file mode 100644 (file)
index 0000000..ccaa4f5
--- /dev/null
@@ -0,0 +1,17 @@
+Basic test coverage for fileSystemEntry.getParent()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS directoryEntry.name is "testFiles"
+PASS directoryEntry.fullPath is "/testFiles"
+PASS directoryEntry.isDirectory is true
+PASS directoryEntry.isFile is false
+PASS entryParent.name is "testFiles"
+PASS entryParent.fullPath is "/testFiles"
+PASS entryParent.isDirectory is true
+PASS entryParent.isFile is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2.html b/LayoutTests/editing/pasteboard/datatransfer-items-drop-getParent2.html
new file mode 100644 (file)
index 0000000..20cfbe2
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+<script src="../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemEntry.getParent()");
+jsTestIsAsync = true;
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    directoryEntry = dataTransfer.items[0].webkitGetAsEntry();
+    shouldBeEqualToString("directoryEntry.name", "testFiles");
+    shouldBeEqualToString("directoryEntry.fullPath", "/testFiles");
+    shouldBeTrue("directoryEntry.isDirectory");
+    shouldBeFalse("directoryEntry.isFile");
+
+    let directoryReader = directoryEntry.createReader();
+    directoryReader.readEntries(function(entries) {
+        entries[0].getParent(function(parent) {
+            entryParent = parent;
+            shouldBeEqualToString("entryParent.name", "testFiles");
+            shouldBeEqualToString("entryParent.fullPath", "/testFiles");
+            shouldBeTrue("entryParent.isDirectory");
+            shouldBeFalse("entryParent.isFile");
+
+            finishJSTest();
+        }, function(e) {
+            testFailed("getParent() call failed: " + e);
+            finishJSTest();
+        });
+    }, function(e) {
+        testFailed("readEntries() call failed: " + e);
+        finishJSTest();
+    });
+};
+
+dropzone.ondragover = function(ev) {
+    ev.preventDefault();
+}
+
+onload = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/file/resources/testFiles']);
+}
+</script>
+</body>
+</html>
index e71b9ee..4cc17a2 100644 (file)
@@ -15,7 +15,7 @@ PASS FileSystemEntry interface: attribute isDirectory
 PASS FileSystemEntry interface: attribute name 
 PASS FileSystemEntry interface: attribute fullPath 
 PASS FileSystemEntry interface: attribute filesystem 
-FAIL FileSystemEntry interface: operation getParent(FileSystemEntryCallback,ErrorCallback) assert_own_property: interface prototype object missing non-static operation expected property "getParent" missing
+PASS FileSystemEntry interface: operation getParent(FileSystemEntryCallback,ErrorCallback) 
 PASS FileSystemDirectoryEntry interface: existence and properties of interface object 
 PASS FileSystemDirectoryEntry interface object length 
 PASS FileSystemDirectoryEntry interface object name 
index 8a2a2a1..6544f65 100644 (file)
@@ -567,6 +567,9 @@ editing/pasteboard/datatransfer-items-drop-directoryReader.html
 editing/pasteboard/datatransfer-items-drop-directoryReader-error.html
 editing/pasteboard/datatransfer-items-drop-directoryReader-root.html
 editing/pasteboard/datatransfer-items-drop-getAsEntry.html
+editing/pasteboard/datatransfer-items-drop-getParent-root.html
+editing/pasteboard/datatransfer-items-drop-getParent.html
+editing/pasteboard/datatransfer-items-drop-getParent2.html
 editing/pasteboard/datatransfer-items-drop-plaintext-file.html
 editing/pasteboard/file-drag-to-editable.html [ Skip ]
 editing/pasteboard/file-input-files-access.html
index 7b55fe7..a9625dd 100644 (file)
@@ -1,3 +1,74 @@
+2017-09-01  Chris Dumez  <cdumez@apple.com>
+
+        Implement FileSystemEntry.getParent()
+        https://bugs.webkit.org/show_bug.cgi?id=176165
+        <rdar://problem/34187743>
+
+        Reviewed by Andreas Kling.
+
+        Implement FileSystemEntry.getParent():
+        - https://wicg.github.io/entries-api/#dom-filesystementry-getparent
+
+        Tests: editing/pasteboard/datatransfer-items-drop-getParent-root.html
+               editing/pasteboard/datatransfer-items-drop-getParent.html
+               editing/pasteboard/datatransfer-items-drop-getParent2.html
+
+        * Modules/entriesapi/DOMFileSystem.cpp:
+        (WebCore::toFileSystemEntries):
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
+        (WebCore::isAbsoluteVirtualPath):
+        Add utility function to determine if a virtual path is absolute:
+        - https://wicg.github.io/entries-api/#absolute-path
+
+        (WebCore::DOMFileSystem::root):
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
+        (WebCore::DOMFileSystem::fileAsEntry):
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
+        (WebCore::resolveRelativePath):
+        Add implementation for:
+        - https://wicg.github.io/entries-api/#resolve-a-relative-path
+
+        (WebCore::DOMFileSystem::listDirectory):
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
+        (WebCore::DOMFileSystem::getParent):
+        Add implementation of getParent() as per:
+        - https://wicg.github.io/entries-api/#dom-filesystementry-getparent
+
+        * Modules/entriesapi/DOMFileSystem.h:
+        (WebCore::DOMFileSystem::createEntryForFile):
+        * Modules/entriesapi/DOMFileSystem.idl:
+        * Modules/entriesapi/FileSystemDirectoryEntry.cpp:
+        (WebCore::FileSystemDirectoryEntry::FileSystemDirectoryEntry):
+        * Modules/entriesapi/FileSystemDirectoryEntry.h:
+        * Modules/entriesapi/FileSystemDirectoryReader.cpp:
+        (WebCore::FileSystemDirectoryReader::readEntries):
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
+        * Modules/entriesapi/FileSystemEntry.cpp:
+        (WebCore::FileSystemEntry::FileSystemEntry):
+        (WebCore::FileSystemEntry::activeDOMObjectName const):
+        (WebCore::FileSystemEntry::canSuspendForDocumentSuspension const):
+        (WebCore::FileSystemEntry::getParent):
+        * Modules/entriesapi/FileSystemEntry.h:
+        * Modules/entriesapi/FileSystemEntry.idl:
+        - Add implementation of FileSystemEntry.getParent() which relies on
+          DOMFileSystem::getParent()
+        - Make FileSystemEntry an ActiveDOMObject as getParent() is an asynchronous
+          operation which causes delayed JS execution.
+
+        * Modules/entriesapi/FileSystemFileEntry.cpp:
+        (WebCore::FileSystemFileEntry::FileSystemFileEntry):
+        * Modules/entriesapi/FileSystemFileEntry.h:
+        * dom/DataTransferItem.cpp:
+        (WebCore::DataTransferItem::getAsEntry const):
+        * dom/DataTransferItem.h:
+        * dom/DataTransferItem.idl:
+        Take a ScriptExecutionContext now that FileSystemEntry is an ActiveDOMObject.
+
 2017-09-01  Yoshiaki Jitsukawa  <Yoshiaki.Jitsukawa@sony.com>
 
         Ensure RenderStyle and SameSizeAsRenderStyle have the same size
index 38c354e..2550bc3 100644 (file)
 #include "FileSystem.h"
 #include "FileSystemDirectoryEntry.h"
 #include "FileSystemFileEntry.h"
+#include "ScriptExecutionContext.h"
 #include <wtf/CrossThreadCopier.h>
 #include <wtf/UUID.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -61,7 +63,7 @@ static ExceptionOr<Vector<ListedChild>> listDirectoryWithMetadata(const String&
     return WTFMove(listedChildren);
 }
 
-static ExceptionOr<Vector<Ref<FileSystemEntry>>> toFileSystemEntries(DOMFileSystem& fileSystem, ExceptionOr<Vector<ListedChild>>&& listedChildren, const String& parentVirtualPath)
+static ExceptionOr<Vector<Ref<FileSystemEntry>>> toFileSystemEntries(ScriptExecutionContext& context, DOMFileSystem& fileSystem, ExceptionOr<Vector<ListedChild>>&& listedChildren, const String& parentVirtualPath)
 {
     ASSERT(isMainThread());
     if (listedChildren.hasException())
@@ -73,10 +75,10 @@ static ExceptionOr<Vector<Ref<FileSystemEntry>>> toFileSystemEntries(DOMFileSyst
         String virtualPath = parentVirtualPath + "/" + child.filename;
         switch (child.type) {
         case FileMetadata::TypeFile:
-            entries.uncheckedAppend(FileSystemFileEntry::create(fileSystem, virtualPath));
+            entries.uncheckedAppend(FileSystemFileEntry::create(context, fileSystem, virtualPath));
             break;
         case FileMetadata::TypeDirectory:
-            entries.uncheckedAppend(FileSystemDirectoryEntry::create(fileSystem, virtualPath));
+            entries.uncheckedAppend(FileSystemDirectoryEntry::create(context, fileSystem, virtualPath));
             break;
         default:
             break;
@@ -85,6 +87,11 @@ static ExceptionOr<Vector<Ref<FileSystemEntry>>> toFileSystemEntries(DOMFileSyst
     return WTFMove(entries);
 }
 
+static bool isAbsoluteVirtualPath(const String& virtualPath)
+{
+    return !virtualPath.isEmpty() && virtualPath[0] == '/';
+}
+
 DOMFileSystem::DOMFileSystem(Ref<File>&& file)
     : m_name(createCanonicalUUIDString())
     , m_file(WTFMove(file))
@@ -98,16 +105,48 @@ DOMFileSystem::~DOMFileSystem()
 {
 }
 
-Ref<FileSystemDirectoryEntry> DOMFileSystem::root()
+Ref<FileSystemDirectoryEntry> DOMFileSystem::root(ScriptExecutionContext& context)
 {
-    return FileSystemDirectoryEntry::create(*this, ASCIILiteral("/"));
+    return FileSystemDirectoryEntry::create(context, *this, ASCIILiteral("/"));
 }
 
-Ref<FileSystemEntry> DOMFileSystem::fileAsEntry()
+Ref<FileSystemEntry> DOMFileSystem::fileAsEntry(ScriptExecutionContext& context)
 {
     if (m_file->isDirectory())
-        return FileSystemDirectoryEntry::create(*this, "/" + m_file->name());
-    return FileSystemFileEntry::create(*this, "/" + m_file->name());
+        return FileSystemDirectoryEntry::create(context, *this, "/" + m_file->name());
+    return FileSystemFileEntry::create(context, *this, "/" + m_file->name());
+}
+
+// https://wicg.github.io/entries-api/#resolve-a-relative-path
+static String resolveRelativePath(const String& virtualPath, const String& relativePath)
+{
+    ASSERT(virtualPath[0] == '/');
+    if (isAbsoluteVirtualPath(relativePath))
+        return relativePath;
+
+    auto virtualPathSegments = virtualPath.split('/');
+    auto relativePathSegments = relativePath.split('/');
+    for (auto& segment : relativePathSegments) {
+        ASSERT(!segment.isEmpty());
+        if (segment == ".")
+            continue;
+        if (segment == "..") {
+            if (!virtualPathSegments.isEmpty())
+                virtualPathSegments.removeLast();
+            continue;
+        }
+        virtualPathSegments.append(segment);
+    }
+
+    if (virtualPathSegments.isEmpty())
+        return ASCIILiteral("/");
+
+    StringBuilder builder;
+    for (auto& segment : virtualPathSegments) {
+        builder.append('/');
+        builder.append(segment);
+    }
+    return builder.toString();
 }
 
 // https://wicg.github.io/entries-api/#evaluate-a-path
@@ -132,7 +171,7 @@ String DOMFileSystem::evaluatePath(const String& virtualPath)
     return pathByAppendingComponents(m_rootPath, resolvedComponents);
 }
 
-void DOMFileSystem::listDirectory(FileSystemDirectoryEntry& directory, DirectoryListingCallback&& completionHandler)
+void DOMFileSystem::listDirectory(ScriptExecutionContext& context, FileSystemDirectoryEntry& directory, DirectoryListingCallback&& completionHandler)
 {
     ASSERT(&directory.filesystem() == this);
 
@@ -140,15 +179,33 @@ void DOMFileSystem::listDirectory(FileSystemDirectoryEntry& directory, Directory
     auto fullPath = evaluatePath(directoryVirtualPath);
     if (fullPath == m_rootPath) {
         Vector<Ref<FileSystemEntry>> children;
-        children.append(fileAsEntry());
+        children.append(fileAsEntry(context));
         completionHandler(WTFMove(children));
         return;
     }
 
-    m_workQueue->dispatch([this, completionHandler = WTFMove(completionHandler), fullPath = fullPath.isolatedCopy(), directoryVirtualPath = directoryVirtualPath.isolatedCopy()]() mutable {
+    m_workQueue->dispatch([this, context = makeRef(context), completionHandler = WTFMove(completionHandler), fullPath = fullPath.isolatedCopy(), directoryVirtualPath = directoryVirtualPath.isolatedCopy()]() mutable {
         auto listedChildren = listDirectoryWithMetadata(fullPath);
-        callOnMainThread([this, completionHandler = WTFMove(completionHandler), listedChildren = crossThreadCopy(listedChildren), directoryVirtualPath = directoryVirtualPath.isolatedCopy()]() mutable {
-            completionHandler(toFileSystemEntries(*this, WTFMove(listedChildren), directoryVirtualPath));
+        callOnMainThread([this, context = WTFMove(context), completionHandler = WTFMove(completionHandler), listedChildren = crossThreadCopy(listedChildren), directoryVirtualPath = directoryVirtualPath.isolatedCopy()]() mutable {
+            completionHandler(toFileSystemEntries(context, *this, WTFMove(listedChildren), directoryVirtualPath));
+        });
+    });
+}
+
+void DOMFileSystem::getParent(ScriptExecutionContext& context, FileSystemEntry& entry, GetParentCallback&& completionCallback)
+{
+    String virtualPath = resolveRelativePath(entry.virtualPath(), ASCIILiteral(".."));
+    ASSERT(virtualPath[0] == '/');
+    String fullPath = evaluatePath(virtualPath);
+    m_workQueue->dispatch([this, context = makeRef(context), fullPath = crossThreadCopy(fullPath), virtualPath = crossThreadCopy(virtualPath), completionCallback = WTFMove(completionCallback)]() mutable {
+        if (!fileIsDirectory(fullPath, ShouldFollowSymbolicLinks::No)) {
+            callOnMainThread([completionCallback = WTFMove(completionCallback)] {
+                completionCallback(Exception { NotFoundError, "Path no longer exists or is no longer a directory" });
+            });
+            return;
+        }
+        callOnMainThread([this, context = WTFMove(context), virtualPath = crossThreadCopy(virtualPath), completionCallback = WTFMove(completionCallback)] {
+            completionCallback(FileSystemDirectoryEntry::create(context, *this, virtualPath));
         });
     });
 }
index 6d3c5d3..d5a489c 100644 (file)
@@ -36,28 +36,32 @@ namespace WebCore {
 class File;
 class FileSystemDirectoryEntry;
 class FileSystemEntry;
+class ScriptExecutionContext;
 
 class DOMFileSystem : public ScriptWrappable, public RefCounted<DOMFileSystem> {
 public:
-    static Ref<FileSystemEntry> createEntryForFile(Ref<File>&& file)
+    static Ref<FileSystemEntry> createEntryForFile(ScriptExecutionContext& context, Ref<File>&& file)
     {
         auto fileSystem = adoptRef(*new DOMFileSystem(WTFMove(file)));
-        return fileSystem->fileAsEntry();
+        return fileSystem->fileAsEntry(context);
     }
 
     ~DOMFileSystem();
 
     const String& name() const { return m_name; }
-    Ref<FileSystemDirectoryEntry> root();
+    Ref<FileSystemDirectoryEntry> root(ScriptExecutionContext&);
 
     using DirectoryListingCallback = WTF::Function<void(ExceptionOr<Vector<Ref<FileSystemEntry>>>&&)>;
-    void listDirectory(FileSystemDirectoryEntry&, DirectoryListingCallback&&);
+    void listDirectory(ScriptExecutionContext&, FileSystemDirectoryEntry&, DirectoryListingCallback&&);
+
+    using GetParentCallback = WTF::Function<void(ExceptionOr<Ref<FileSystemDirectoryEntry>>&&)>;
+    void getParent(ScriptExecutionContext&, FileSystemEntry&, GetParentCallback&&);
 
 private:
     explicit DOMFileSystem(Ref<File>&&);
 
     String evaluatePath(const String& virtualPath);
-    Ref<FileSystemEntry> fileAsEntry();
+    Ref<FileSystemEntry> fileAsEntry(ScriptExecutionContext&);
 
     String m_name;
     Ref<File> m_file;
index b25ec65..c1972ce 100644 (file)
@@ -29,5 +29,5 @@
     InterfaceName=FileSystem,
 ] interface DOMFileSystem {
     readonly attribute USVString name;
-    [CachedAttribute] readonly attribute FileSystemDirectoryEntry root;
+    [CachedAttribute, CallWith=ScriptExecutionContext] readonly attribute FileSystemDirectoryEntry root;
 };
index c915b00..6ae8675 100644 (file)
@@ -32,8 +32,8 @@
 
 namespace WebCore {
 
-FileSystemDirectoryEntry::FileSystemDirectoryEntry(DOMFileSystem& filesystem, const String& virtualPath)
-    : FileSystemEntry(filesystem, virtualPath)
+FileSystemDirectoryEntry::FileSystemDirectoryEntry(ScriptExecutionContext& context, DOMFileSystem& filesystem, const String& virtualPath)
+    : FileSystemEntry(context, filesystem, virtualPath)
 {
 }
 
index 8db6f93..3cdfe9b 100644 (file)
@@ -36,9 +36,9 @@ class ScriptExecutionContext;
 
 class FileSystemDirectoryEntry final : public FileSystemEntry {
 public:
-    static Ref<FileSystemDirectoryEntry> create(DOMFileSystem& filesystem, const String& virtualPath)
+    static Ref<FileSystemDirectoryEntry> create(ScriptExecutionContext& context, DOMFileSystem& filesystem, const String& virtualPath)
     {
-        return adoptRef(*new FileSystemDirectoryEntry(filesystem, virtualPath));
+        return adoptRef(*new FileSystemDirectoryEntry(context, filesystem, virtualPath));
     }
 
     Ref<FileSystemDirectoryReader> createReader(ScriptExecutionContext&);
@@ -54,7 +54,7 @@ public:
 private:
     bool isDirectory() const final { return true; }
 
-    FileSystemDirectoryEntry(DOMFileSystem&, const String& virtualPath);
+    FileSystemDirectoryEntry(ScriptExecutionContext&, DOMFileSystem&, const String& virtualPath);
 };
 
 } // namespace WebCore
index 07d8168..43f28a4 100644 (file)
@@ -31,6 +31,7 @@
 #include "ErrorCallback.h"
 #include "FileSystemDirectoryEntry.h"
 #include "FileSystemEntriesCallback.h"
+#include "ScriptExecutionContext.h"
 #include <wtf/MainThread.h>
 
 namespace WebCore {
@@ -78,9 +79,9 @@ void FileSystemDirectoryReader::readEntries(ScriptExecutionContext& context, Ref
 
     m_isReading = true;
     auto pendingActivity = makePendingActivity(*this);
-    callOnMainThread([this, successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)]() mutable {
+    callOnMainThread([this, context = makeRef(context), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)]() mutable {
         m_isReading = false;
-        m_directory->filesystem().listDirectory(m_directory, [this, successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)](ExceptionOr<Vector<Ref<FileSystemEntry>>>&& result) {
+        m_directory->filesystem().listDirectory(context, m_directory, [this, successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback), pendingActivity = WTFMove(pendingActivity)](ExceptionOr<Vector<Ref<FileSystemEntry>>>&& result) {
             if (result.hasException()) {
                 m_error = result.releaseException();
                 if (errorCallback)
index 6aae82c..80949ce 100644 (file)
 #include "config.h"
 #include "FileSystemEntry.h"
 
+#include "DOMException.h"
 #include "DOMFileSystem.h"
+#include "ErrorCallback.h"
 #include "FileSystem.h"
+#include "FileSystemDirectoryEntry.h"
+#include "FileSystemEntryCallback.h"
+#include "ScriptExecutionContext.h"
 
 namespace WebCore {
 
-FileSystemEntry::FileSystemEntry(DOMFileSystem& filesystem, const String& virtualPath)
-    : m_filesystem(filesystem)
+FileSystemEntry::FileSystemEntry(ScriptExecutionContext& context, DOMFileSystem& filesystem, const String& virtualPath)
+    : ActiveDOMObject(&context)
+    , m_filesystem(filesystem)
     , m_name(pathGetFileName(virtualPath))
     , m_virtualPath(virtualPath)
 {
+    suspendIfNeeded();
 }
 
 FileSystemEntry::~FileSystemEntry()
@@ -47,5 +54,31 @@ DOMFileSystem& FileSystemEntry::filesystem() const
     return m_filesystem.get();
 }
 
+const char* FileSystemEntry::activeDOMObjectName() const
+{
+    return "FileSystemEntry";
+}
+
+bool FileSystemEntry::canSuspendForDocumentSuspension() const
+{
+    return !hasPendingActivity();
+}
+
+void FileSystemEntry::getParent(ScriptExecutionContext& context, RefPtr<FileSystemEntryCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
+{
+    if (!successCallback && !errorCallback)
+        return;
+
+    filesystem().getParent(context, *this, [pendingActivity = makePendingActivity(*this), successCallback = WTFMove(successCallback), errorCallback = WTFMove(errorCallback)](auto&& result) {
+        if (result.hasException()) {
+            if (errorCallback)
+                errorCallback->handleEvent(DOMException::create(result.releaseException()));
+            return;
+        }
+        if (successCallback)
+            successCallback->handleEvent(result.releaseReturnValue());
+    });
+}
+
 
 } // namespace WebCore
index a74d87e..3e76e78 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "ActiveDOMObject.h"
 #include "ScriptWrappable.h"
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
 namespace WebCore {
 
 class DOMFileSystem;
+class ErrorCallback;
+class FileSystemEntryCallback;
 
-class FileSystemEntry : public ScriptWrappable, public RefCounted<FileSystemEntry> {
+class FileSystemEntry : public ScriptWrappable, public ActiveDOMObject, public RefCounted<FileSystemEntry> {
 public:
     virtual ~FileSystemEntry();
 
@@ -44,10 +47,15 @@ public:
     const String& virtualPath() const { return m_virtualPath; }
     DOMFileSystem& filesystem() const;
 
+    void getParent(ScriptExecutionContext&, RefPtr<FileSystemEntryCallback>&&, RefPtr<ErrorCallback>&&);
+
 protected:
-    FileSystemEntry(DOMFileSystem&, const String& virtualPath);
+    FileSystemEntry(ScriptExecutionContext&, DOMFileSystem&, const String& virtualPath);
 
 private:
+    const char* activeDOMObjectName() const final;
+    bool canSuspendForDocumentSuspension() const final;
+
     Ref<DOMFileSystem> m_filesystem;
     String m_name;
     String m_virtualPath;
index f716401..be0692f 100644 (file)
@@ -33,5 +33,5 @@
     [ImplementedAs=virtualPath] readonly attribute USVString fullPath;
     readonly attribute DOMFileSystem filesystem;
 
-    // void getParent(optional FileSystemEntryCallback successCallback, optional ErrorCallback errorCallback);
+    [CallWith=ScriptExecutionContext] void getParent(optional FileSystemEntryCallback? successCallback, optional ErrorCallback? errorCallback);
 };
index 780a5f0..b80b65b 100644 (file)
@@ -31,8 +31,8 @@
 
 namespace WebCore {
 
-FileSystemFileEntry::FileSystemFileEntry(DOMFileSystem& filesystem, const String& virtualPath)
-    : FileSystemEntry(filesystem, virtualPath)
+FileSystemFileEntry::FileSystemFileEntry(ScriptExecutionContext& context, DOMFileSystem& filesystem, const String& virtualPath)
+    : FileSystemEntry(context, filesystem, virtualPath)
 {
 }
 
index 1fa3acc..89be8df 100644 (file)
@@ -35,9 +35,9 @@ class ScriptExecutionContext;
 
 class FileSystemFileEntry final : public FileSystemEntry {
 public:
-    static Ref<FileSystemFileEntry> create(DOMFileSystem& filesystem, const String& virtualPath)
+    static Ref<FileSystemFileEntry> create(ScriptExecutionContext& context, DOMFileSystem& filesystem, const String& virtualPath)
     {
-        return adoptRef(*new FileSystemFileEntry(filesystem, virtualPath));
+        return adoptRef(*new FileSystemFileEntry(context, filesystem, virtualPath));
     }
 
     void file(ScriptExecutionContext&, RefPtr<FileCallback>&&, RefPtr<ErrorCallback>&& = nullptr);
@@ -45,7 +45,7 @@ public:
 private:
     bool isFile() const final { return true; }
 
-    FileSystemFileEntry(DOMFileSystem&, const String& virtualPath);
+    FileSystemFileEntry(ScriptExecutionContext&, DOMFileSystem&, const String& virtualPath);
 };
 
 } // namespace WebCore
index e32282b..831904c 100644 (file)
@@ -105,13 +105,13 @@ RefPtr<File> DataTransferItem::getAsFile() const
     return m_file.copyRef();
 }
 
-RefPtr<FileSystemEntry> DataTransferItem::getAsEntry() const
+RefPtr<FileSystemEntry> DataTransferItem::getAsEntry(ScriptExecutionContext& context) const
 {
     auto file = getAsFile();
     if (!file)
         return nullptr;
 
-    return DOMFileSystem::createEntryForFile(*file);
+    return DOMFileSystem::createEntryForFile(context, *file);
 }
 
 } // namespace WebCore
index 7133043..9ac11e7 100644 (file)
@@ -61,7 +61,7 @@ public:
     String type() const;
     void getAsString(ScriptExecutionContext&, RefPtr<StringCallback>&&) const;
     RefPtr<File> getAsFile() const;
-    RefPtr<FileSystemEntry> getAsEntry() const;
+    RefPtr<FileSystemEntry> getAsEntry(ScriptExecutionContext&) const;
 
 private:
     DataTransferItem(WeakPtr<DataTransferItemList>&&, const String&);
index cd52f50..e7d1e03 100644 (file)
@@ -40,6 +40,6 @@
     File getAsFile();
 
     // https://wicg.github.io/entries-api/#html-data
-    [ImplementedAs=getAsEntry] FileSystemEntry? webkitGetAsEntry();
+    [CallWith=ScriptExecutionContext, ImplementedAs=getAsEntry] FileSystemEntry? webkitGetAsEntry();
 };