Title: [221414] trunk
Revision
221414
Author
[email protected]
Date
2017-08-30 20:48:21 -0700 (Wed, 30 Aug 2017)

Log Message

Implement FileSystemDirectoryReader.readEntries()
https://bugs.webkit.org/show_bug.cgi?id=176091
<rdar://problem/34168015>

Reviewed by Andreas Kling.

Source/WebCore:

Tests: editing/pasteboard/datatransfer-items-drop-directoryReader-error.html
       editing/pasteboard/datatransfer-items-drop-directoryReader-root.html
       editing/pasteboard/datatransfer-items-drop-directoryReader.html

* Modules/entriesapi/DOMFileSystem.cpp:
(WebCore::ListedChild::isolatedCopy const):
(WebCore::listDirectoryWithMetadata):
(WebCore::toFileSystemEntries):
(WebCore::DOMFileSystem::DOMFileSystem):
(WebCore::DOMFileSystem::root):
(WebCore::DOMFileSystem::fileAsEntry):
(WebCore::DOMFileSystem::evaluatePath):
(WebCore::DOMFileSystem::listDirectory):
* Modules/entriesapi/DOMFileSystem.h:
(WebCore::DOMFileSystem::createEntryForFile):
* Modules/entriesapi/DOMFileSystem.idl:
- Implement directory listing operation for supporting
  FileSystemDirectoryReader::readEntries().
- Implement evaluatePath() operation as per:
  - https://wicg.github.io/entries-api/#evaluate-a-path
- DOMFileSystem should no longer hold a strong reference to
  the root entry and FileSystemEntry now holds a strong
  reference to the DOMFileSystem and this would create a
  cycle.

* Modules/entriesapi/FileSystemDirectoryEntry.cpp:
(WebCore::FileSystemDirectoryEntry::createReader):
* Modules/entriesapi/FileSystemDirectoryEntry.h:
* Modules/entriesapi/FileSystemDirectoryEntry.idl:
Have createReader() take a ScriptExecutionContext, which is needed
to construct a FileSystemDirectoryReader, now that FileSystemDirectoryReader
is an ActiveDOMObject.

* Modules/entriesapi/FileSystemDirectoryReader.cpp:
(WebCore::FileSystemDirectoryReader::FileSystemDirectoryReader):
(WebCore::FileSystemDirectoryReader::activeDOMObjectName const):
(WebCore::FileSystemDirectoryReader::canSuspendForDocumentSuspension const):
(WebCore::FileSystemDirectoryReader::readEntries):
* Modules/entriesapi/FileSystemDirectoryReader.h:
* Modules/entriesapi/FileSystemDirectoryReader.idl:
Provide implementation for FileSystemDirectoryReader.readEntries() as per:
- https://wicg.github.io/entries-api/#dom-filesystemdirectoryreader-readentries
For the actual directory listing operation, we ask the DOMFileSystem, which is
where all filesystem operations should live.
Also made the FileSystemDirectoryReader an ActiveDOMObject to keep it and its
wrapper alive while a file system operation is pending.

* Modules/entriesapi/FileSystemEntry.cpp:
(WebCore::FileSystemEntry::~FileSystemEntry):
(WebCore::FileSystemEntry::filesystem const):
* Modules/entriesapi/FileSystemEntry.h:
Make FileSystemEntry keep a strong reference to its DOMFileSystem object.
Previously, the DOMFileSystem was kept alive by the DataTransferItem but
this was unsafe because FileSystemEntry may outlive the DataTransferItem.

* dom/ActiveDOMObject.h:
(WebCore::ActiveDOMObject::PendingActivity::PendingActivity):
(WebCore::ActiveDOMObject::PendingActivity::~PendingActivity):
(WebCore::ActiveDOMObject::makePendingActivity):
Add PendingActivity / makePendingActivity() as a less error-prone
replacement for setPendingActivity() / unsetPendingActivity().

* dom/DOMException.cpp:
(WebCore::DOMException::create):
* dom/DOMException.h:
Add factory to construct a DOMException from an Exception.

* dom/DataTransferItem.cpp:
(WebCore::DataTransferItem::getAsEntry const):
* dom/DataTransferItem.h:

* dom/Exception.h:
(WebCore::Exception::isolatedCopy const):
* dom/ExceptionOr.h:
Make ExceptionOr<> / Exception work with CrossThreadCopier for convenience.

* html/FileListCreator.cpp:
(WebCore::FileListCreator::FileListCreator):
Use crossThreadCopy() instead of longer form.

* platform/FileSystem.h:
* platform/glib/FileSystemGlib.cpp:
(WebCore::pathByAppendingComponents):
* platform/posix/FileSystemPOSIX.cpp:
(WebCore::pathByAppendingComponents):
* platform/win/FileSystemWin.cpp:
(WebCore::pathByAppendingComponents):
Add pathByAppendingComponents() utility function, which is similar to
pathByAppendingComponent() but supports appending multiple components
in an efficient fashion.

Source/WTF:

* wtf/CrossThreadCopier.h:
(WTF::crossThreadCopy):
* wtf/CrossThreadTask.h:
Move crossThreadCopy() from CrossThreadTask.h to CrossThreadCopier.h and
add "using WTF::crossThreadCopy" statement to make it more easily usable
from WebCore.

LayoutTests:

Add layout test coverage.

* editing/editing.js:
(moveMouseToCenterOfElement):
(dragFilesOntoElement):
* editing/pasteboard/datatransfer-items-drop-directoryReader-error-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-directoryReader-error.html: Added.
* editing/pasteboard/datatransfer-items-drop-directoryReader-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-directoryReader-root-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-directoryReader-root.html: Added.
* editing/pasteboard/datatransfer-items-drop-directoryReader.html: Added.
* editing/pasteboard/datatransfer-items-drop-getAsEntry.html:
* platform/wk2/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (221413 => 221414)


--- trunk/LayoutTests/ChangeLog	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/LayoutTests/ChangeLog	2017-08-31 03:48:21 UTC (rev 221414)
@@ -1,3 +1,25 @@
+2017-08-30  Chris Dumez  <[email protected]>
+
+        Implement FileSystemDirectoryReader.readEntries()
+        https://bugs.webkit.org/show_bug.cgi?id=176091
+        <rdar://problem/34168015>
+
+        Reviewed by Andreas Kling.
+
+        Add layout test coverage.
+
+        * editing/editing.js:
+        (moveMouseToCenterOfElement):
+        (dragFilesOntoElement):
+        * editing/pasteboard/datatransfer-items-drop-directoryReader-error-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-directoryReader-error.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-directoryReader-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-directoryReader-root-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-directoryReader-root.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-directoryReader.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-getAsEntry.html:
+        * platform/wk2/TestExpectations:
+
 2017-08-30  Myles C. Maxfield  <[email protected]>
 
         Previous elements with lang= can affect fonts selected for subsequent elements

Modified: trunk/LayoutTests/editing/editing.js (221413 => 221414)


--- trunk/LayoutTests/editing/editing.js	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/LayoutTests/editing/editing.js	2017-08-31 03:48:21 UTC (rev 221414)
@@ -399,6 +399,26 @@
 
 //-------------------------------------------------------------------------------------------------------
 
+function moveMouseToCenterOfElement(element) {
+    if (!window.eventSender)
+        return;
+
+    const centerX = element.offsetLeft + element.offsetWidth / 2;
+    const centerY = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(centerX, centerY);
+}
+
+function dragFilesOntoElement(element, files) {
+    if (!window.eventSender)
+        return;
+
+    eventSender.beginDragWithFiles(files);
+    moveMouseToCenterOfElement(element);
+    eventSender.mouseUp();
+}
+
+//-------------------------------------------------------------------------------------------------------
+
 function doubleClick(x, y) {
     eventSender.mouseMoveTo(x, y);
     eventSender.mouseDown();

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error-expected.txt (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error-expected.txt	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,11 @@
+Error case coverage for fileSystemDirectoryReader.readEntries()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 1
+PASS ex.name is "InvalidStateError"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error.html (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-error.html	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Error case coverage for fileSystemDirectoryReader.readEntries()");
+jsTestIsAsync = true;
+
+var dropzone = document.getElementById('dropzone');
+dropzone._ondrop_ = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "1");
+
+    dirEntry = dataTransfer.items[0].webkitGetAsEntry();
+    let reader = dirEntry.createReader();
+    reader.readEntries(function() {});
+    reader.readEntries(function(entries) {
+        testFailed("Calling readEntries on a reader with the reading flag set did not throw an exception");
+        finishJSTest();
+    }, function(e) {
+        ex = e;
+        shouldBeEqualToString("ex.name", "InvalidStateError");
+        finishJSTest()
+    });
+};
+
+dropzone._ondragover_ = function(ev) {
+    ev.preventDefault();
+}
+
+_onload_ = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/file/resources/testFiles']);
+}
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-expected.txt (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-expected.txt	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,41 @@
+Basic test coverage for fileSystemDirectoryReader.readEntries()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 1
+PASS entry.isDirectory is true
+PASS entry.name is "testFiles"
+PASS entry.fullPath is "/testFiles"
+PASS childEntries.length is 4
+PASS childEntries[0].name is "file1.txt"
+PASS childEntries[0].fullPath is "/testFiles/file1.txt"
+PASS childEntries[0].isFile is true
+PASS childEntries[1].name is "file2.txt"
+PASS childEntries[1].fullPath is "/testFiles/file2.txt"
+PASS childEntries[1].isFile is true
+PASS childEntries[2].name is "subfolder1"
+PASS childEntries[2].fullPath is "/testFiles/subfolder1"
+PASS childEntries[2].isDirectory is true
+PASS childEntries[3].name is "subfolder2"
+PASS childEntries[3].fullPath is "/testFiles/subfolder2"
+PASS childEntries[3].isDirectory is true
+PASS grandChildEntries.length is 1
+PASS grandChildEntries[0].name is "file3.txt"
+PASS grandChildEntries[0].fullPath is "/testFiles/subfolder1/file3.txt"
+PASS grandChildEntries[0].isFile is true
+PASS grandChildEntries.length is 2
+PASS grandChildEntries[0].name is "file4.txt"
+PASS grandChildEntries[0].fullPath is "/testFiles/subfolder2/file4.txt"
+PASS grandChildEntries[0].isFile is true
+PASS grandChildEntries[1].name is "subfolder2a"
+PASS grandChildEntries[1].fullPath is "/testFiles/subfolder2/subfolder2a"
+PASS grandChildEntries[1].isDirectory is true
+PASS greatGrandChildEntries.length is 1
+PASS greatGrandChildEntries[0].name is "file5.txt"
+PASS greatGrandChildEntries[0].fullPath is "/testFiles/subfolder2/subfolder2a/file5.txt"
+PASS greatGrandChildEntries[0].isFile is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root-expected.txt (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root-expected.txt	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,22 @@
+Basic test coverage for fileSystemDirectoryReader.readEntries()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 2
+PASS entry1.isFile is true
+PASS entry1.name is "test.txt"
+PASS entry1.fullPath is "/test.txt"
+PASS entryFound.isFile is true
+PASS entryFound.name is "test.txt"
+PASS entryFound.fullPath is "/test.txt"
+PASS entry2.isDirectory is true
+PASS entry2.name is "testFiles"
+PASS entry2.fullPath is "/testFiles"
+PASS entryFound.isDirectory is true
+PASS entryFound.name is "testFiles"
+PASS entryFound.fullPath is "/testFiles"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root.html (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader-root.html	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemDirectoryReader.readEntries()");
+jsTestIsAsync = true;
+
+function getEntriesAsPromise(dirEntry) {
+    return new Promise((resolve, reject) => {
+        let result = [];
+        let reader = dirEntry.createReader();
+        let doBatch = () => {
+            reader.readEntries(entries => {
+            if (entries.length > 0) {
+                entries.forEach(e => result.push(e));
+                doBatch();
+            } else {
+                resolve(result);
+            }
+        }, reject);
+    };
+    doBatch();
+  });
+}
+
+function findEntryByName(entries, name)
+{
+    for (let childEntry of entries) {
+        if (childEntry.name == name)
+            return childEntry
+    }
+    return null;
+}
+
+var dropzone = document.getElementById('dropzone');
+dropzone._ondrop_ = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "2");
+
+    entry1 = dataTransfer.items[0].webkitGetAsEntry();
+    entry2 = dataTransfer.items[1].webkitGetAsEntry();
+
+    shouldBeTrue("entry1.isFile");
+    shouldBeEqualToString("entry1.name", "test.txt");
+    shouldBeEqualToString("entry1.fullPath", "/test.txt");
+    getEntriesAsPromise(entry1.filesystem.root).then(function(entries) {
+        entryFound = findEntryByName(entries, "test.txt");
+        shouldBeTrue("entryFound.isFile");
+        shouldBeEqualToString("entryFound.name", "test.txt");
+        shouldBeEqualToString("entryFound.fullPath", "/test.txt");
+
+        shouldBeTrue("entry2.isDirectory");
+        shouldBeEqualToString("entry2.name", "testFiles");
+        shouldBeEqualToString("entry2.fullPath", "/testFiles");
+        getEntriesAsPromise(entry2.filesystem.root).then(function(entries) {
+            entryFound = findEntryByName(entries, "testFiles");
+            shouldBeTrue("entryFound.isDirectory");
+            shouldBeEqualToString("entryFound.name", "testFiles");
+            shouldBeEqualToString("entryFound.fullPath", "/testFiles");
+
+            finishJSTest();
+        }, function(e) {
+            testFailed("readEntries failed: " + e);
+            finishJSTest();
+        });
+    }, function(e) {
+        testFailed("readEntries 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>

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader.html (0 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-directoryReader.html	2017-08-31 03:48:21 UTC (rev 221414)
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Basic test coverage for fileSystemDirectoryReader.readEntries()");
+jsTestIsAsync = true;
+
+function getEntriesAsPromise(dirEntry) {
+    return new Promise((resolve, reject) => {
+        let result = [];
+        let reader = dirEntry.createReader();
+        let doBatch = () => {
+            reader.readEntries(entries => {
+            if (entries.length > 0) {
+                entries.forEach(e => result.push(e));
+                doBatch();
+            } else {
+                resolve(result);
+            }
+        }, reject);
+    };
+    doBatch();
+  });
+}
+
+var dropzone = document.getElementById('dropzone');
+dropzone._ondrop_ = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "1");
+
+    entry = dataTransfer.items[0].webkitGetAsEntry();
+    shouldBeTrue("entry.isDirectory");
+    shouldBeEqualToString("entry.name", "testFiles");
+    shouldBeEqualToString("entry.fullPath", "/testFiles");
+
+    getEntriesAsPromise(entry).then(function(entries) {
+        childEntries = entries;
+        shouldBe("childEntries.length", "4");
+        shouldBeEqualToString("childEntries[0].name", "file1.txt");
+        shouldBeEqualToString("childEntries[0].fullPath", "/testFiles/file1.txt");
+        shouldBeTrue("childEntries[0].isFile");
+
+        shouldBeEqualToString("childEntries[1].name", "file2.txt");
+        shouldBeEqualToString("childEntries[1].fullPath", "/testFiles/file2.txt");
+        shouldBeTrue("childEntries[1].isFile");
+
+        shouldBeEqualToString("childEntries[2].name", "subfolder1");
+        shouldBeEqualToString("childEntries[2].fullPath", "/testFiles/subfolder1");
+        shouldBeTrue("childEntries[2].isDirectory");
+
+        shouldBeEqualToString("childEntries[3].name", "subfolder2");
+        shouldBeEqualToString("childEntries[3].fullPath", "/testFiles/subfolder2");
+        shouldBeTrue("childEntries[3].isDirectory");
+
+        getEntriesAsPromise(childEntries[2]).then(function(entries) {
+            grandChildEntries = entries;
+            shouldBe("grandChildEntries.length", "1");
+            shouldBeEqualToString("grandChildEntries[0].name", "file3.txt");
+            shouldBeEqualToString("grandChildEntries[0].fullPath", "/testFiles/subfolder1/file3.txt");
+            shouldBeTrue("grandChildEntries[0].isFile");
+
+            getEntriesAsPromise(childEntries[3]).then(function(entries) {
+                grandChildEntries = entries;
+                shouldBe("grandChildEntries.length", "2");
+                shouldBeEqualToString("grandChildEntries[0].name", "file4.txt");
+                shouldBeEqualToString("grandChildEntries[0].fullPath", "/testFiles/subfolder2/file4.txt");
+                shouldBeTrue("grandChildEntries[0].isFile");
+
+                shouldBeEqualToString("grandChildEntries[1].name", "subfolder2a");
+                shouldBeEqualToString("grandChildEntries[1].fullPath", "/testFiles/subfolder2/subfolder2a");
+                shouldBeTrue("grandChildEntries[1].isDirectory");
+
+                getEntriesAsPromise(grandChildEntries[1]).then(function(entries) {
+                    greatGrandChildEntries = entries;
+                    shouldBe("greatGrandChildEntries.length", "1");
+                    shouldBeEqualToString("greatGrandChildEntries[0].name", "file5.txt");
+                    shouldBeEqualToString("greatGrandChildEntries[0].fullPath", "/testFiles/subfolder2/subfolder2a/file5.txt");
+                    shouldBeTrue("greatGrandChildEntries[0].isFile");
+
+                    finishJSTest();
+                }, function(e) {
+                    testFailed("readEntries failed: " + e);
+                    finishJSTest();
+                });
+            }, function(e) {
+                testFailed("readEntries failed: " + e);
+                finishJSTest();
+            });
+        }, function(e) {
+            testFailed("readEntries failed: " + e);
+            finishJSTest();
+        });
+    }, function(e) {
+        testFailed("readEntries failed: " + e);
+        finishJSTest();
+    });
+};
+
+dropzone._ondragover_ = function(ev) {
+    ev.preventDefault();
+}
+
+_onload_ = function() {
+    dragFilesOntoElement(dropzone, ['../../fast/forms/file/resources/testFiles']);
+}
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-getAsEntry.html (221413 => 221414)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-getAsEntry.html	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-getAsEntry.html	2017-08-31 03:48:21 UTC (rev 221414)
@@ -2,6 +2,7 @@
 <html>
 <head>
 <script src=""
+<script src=""
 </head>
 <body>
 <div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
@@ -9,21 +10,6 @@
 description("Basic test coverage for dataTransferItem.webkitGetAsEntry()");
 jsTestIsAsync = true;
 
-function moveMouseToCenterOfElement(element) {
-    var centerX = element.offsetLeft + element.offsetWidth / 2;
-    var centerY = element.offsetTop + element.offsetHeight / 2;
-    eventSender.mouseMoveTo(centerX, centerY);
-}
-
-function dragFilesOntoElement(element, files) {
-    if (!window.eventSender)
-        return;
-
-    eventSender.beginDragWithFiles(files);
-    moveMouseToCenterOfElement(element);
-    eventSender.mouseUp();
-}
-
 var dropzone = document.getElementById('dropzone');
 dropzone._ondrop_ = function(e) {
     e.preventDefault();

Modified: trunk/LayoutTests/platform/wk2/TestExpectations (221413 => 221414)


--- trunk/LayoutTests/platform/wk2/TestExpectations	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/LayoutTests/platform/wk2/TestExpectations	2017-08-31 03:48:21 UTC (rev 221414)
@@ -563,6 +563,9 @@
 
 # WebKitTestRunner needs an implementation of eventSender.beginDragWithFiles
 # https://bugs.webkit.org/show_bug.cgi?id=64285
+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-plaintext-file.html
 editing/pasteboard/file-drag-to-editable.html [ Skip ]

Modified: trunk/Source/WTF/ChangeLog (221413 => 221414)


--- trunk/Source/WTF/ChangeLog	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WTF/ChangeLog	2017-08-31 03:48:21 UTC (rev 221414)
@@ -1,3 +1,18 @@
+2017-08-30  Chris Dumez  <[email protected]>
+
+        Implement FileSystemDirectoryReader.readEntries()
+        https://bugs.webkit.org/show_bug.cgi?id=176091
+        <rdar://problem/34168015>
+
+        Reviewed by Andreas Kling.
+
+        * wtf/CrossThreadCopier.h:
+        (WTF::crossThreadCopy):
+        * wtf/CrossThreadTask.h:
+        Move crossThreadCopy() from CrossThreadTask.h to CrossThreadCopier.h and
+        add "using WTF::crossThreadCopy" statement to make it more easily usable
+        from WebCore.
+
 2017-08-30  Matt Lewis  <[email protected]>
 
         Unreviewed, rolling out r221384.

Modified: trunk/Source/WTF/wtf/CrossThreadCopier.h (221413 => 221414)


--- trunk/Source/WTF/wtf/CrossThreadCopier.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WTF/wtf/CrossThreadCopier.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -139,6 +139,11 @@
         return destination;
     }
 };
+
+template<typename T> T crossThreadCopy(const T& source)
+{
+    return CrossThreadCopier<T>::copy(source);
+}
     
 } // namespace WTF
 
@@ -145,3 +150,4 @@
 using WTF::CrossThreadCopierBaseHelper;
 using WTF::CrossThreadCopierBase;
 using WTF::CrossThreadCopier;
+using WTF::crossThreadCopy;

Modified: trunk/Source/WTF/wtf/CrossThreadTask.h (221413 => 221414)


--- trunk/Source/WTF/wtf/CrossThreadTask.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WTF/wtf/CrossThreadTask.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -50,12 +50,6 @@
     Function<void ()> m_taskFunction;
 };
 
-template <typename T>
-T crossThreadCopy(const T& t)
-{
-    return CrossThreadCopier<T>::copy(t);
-}
-
 template <typename F, typename ArgsTuple, size_t... ArgsIndex>
 void callFunctionForCrossThreadTaskImpl(F function, ArgsTuple&& args, std::index_sequence<ArgsIndex...>)
 {

Modified: trunk/Source/WebCore/ChangeLog (221413 => 221414)


--- trunk/Source/WebCore/ChangeLog	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/ChangeLog	2017-08-31 03:48:21 UTC (rev 221414)
@@ -1,3 +1,102 @@
+2017-08-30  Chris Dumez  <[email protected]>
+
+        Implement FileSystemDirectoryReader.readEntries()
+        https://bugs.webkit.org/show_bug.cgi?id=176091
+        <rdar://problem/34168015>
+
+        Reviewed by Andreas Kling.
+
+        Tests: editing/pasteboard/datatransfer-items-drop-directoryReader-error.html
+               editing/pasteboard/datatransfer-items-drop-directoryReader-root.html
+               editing/pasteboard/datatransfer-items-drop-directoryReader.html
+
+        * Modules/entriesapi/DOMFileSystem.cpp:
+        (WebCore::ListedChild::isolatedCopy const):
+        (WebCore::listDirectoryWithMetadata):
+        (WebCore::toFileSystemEntries):
+        (WebCore::DOMFileSystem::DOMFileSystem):
+        (WebCore::DOMFileSystem::root):
+        (WebCore::DOMFileSystem::fileAsEntry):
+        (WebCore::DOMFileSystem::evaluatePath):
+        (WebCore::DOMFileSystem::listDirectory):
+        * Modules/entriesapi/DOMFileSystem.h:
+        (WebCore::DOMFileSystem::createEntryForFile):
+        * Modules/entriesapi/DOMFileSystem.idl:
+        - Implement directory listing operation for supporting
+          FileSystemDirectoryReader::readEntries().
+        - Implement evaluatePath() operation as per:
+          - https://wicg.github.io/entries-api/#evaluate-a-path
+        - DOMFileSystem should no longer hold a strong reference to
+          the root entry and FileSystemEntry now holds a strong
+          reference to the DOMFileSystem and this would create a
+          cycle.
+
+        * Modules/entriesapi/FileSystemDirectoryEntry.cpp:
+        (WebCore::FileSystemDirectoryEntry::createReader):
+        * Modules/entriesapi/FileSystemDirectoryEntry.h:
+        * Modules/entriesapi/FileSystemDirectoryEntry.idl:
+        Have createReader() take a ScriptExecutionContext, which is needed
+        to construct a FileSystemDirectoryReader, now that FileSystemDirectoryReader
+        is an ActiveDOMObject.
+
+        * Modules/entriesapi/FileSystemDirectoryReader.cpp:
+        (WebCore::FileSystemDirectoryReader::FileSystemDirectoryReader):
+        (WebCore::FileSystemDirectoryReader::activeDOMObjectName const):
+        (WebCore::FileSystemDirectoryReader::canSuspendForDocumentSuspension const):
+        (WebCore::FileSystemDirectoryReader::readEntries):
+        * Modules/entriesapi/FileSystemDirectoryReader.h:
+        * Modules/entriesapi/FileSystemDirectoryReader.idl:
+        Provide implementation for FileSystemDirectoryReader.readEntries() as per:
+        - https://wicg.github.io/entries-api/#dom-filesystemdirectoryreader-readentries
+        For the actual directory listing operation, we ask the DOMFileSystem, which is
+        where all filesystem operations should live.
+        Also made the FileSystemDirectoryReader an ActiveDOMObject to keep it and its
+        wrapper alive while a file system operation is pending.
+
+        * Modules/entriesapi/FileSystemEntry.cpp:
+        (WebCore::FileSystemEntry::~FileSystemEntry):
+        (WebCore::FileSystemEntry::filesystem const):
+        * Modules/entriesapi/FileSystemEntry.h:
+        Make FileSystemEntry keep a strong reference to its DOMFileSystem object.
+        Previously, the DOMFileSystem was kept alive by the DataTransferItem but
+        this was unsafe because FileSystemEntry may outlive the DataTransferItem.
+
+        * dom/ActiveDOMObject.h:
+        (WebCore::ActiveDOMObject::PendingActivity::PendingActivity):
+        (WebCore::ActiveDOMObject::PendingActivity::~PendingActivity):
+        (WebCore::ActiveDOMObject::makePendingActivity):
+        Add PendingActivity / makePendingActivity() as a less error-prone
+        replacement for setPendingActivity() / unsetPendingActivity().
+
+        * dom/DOMException.cpp:
+        (WebCore::DOMException::create):
+        * dom/DOMException.h:
+        Add factory to construct a DOMException from an Exception.
+
+        * dom/DataTransferItem.cpp:
+        (WebCore::DataTransferItem::getAsEntry const):
+        * dom/DataTransferItem.h:
+
+        * dom/Exception.h:
+        (WebCore::Exception::isolatedCopy const):
+        * dom/ExceptionOr.h:
+        Make ExceptionOr<> / Exception work with CrossThreadCopier for convenience.
+
+        * html/FileListCreator.cpp:
+        (WebCore::FileListCreator::FileListCreator):
+        Use crossThreadCopy() instead of longer form.
+
+        * platform/FileSystem.h:
+        * platform/glib/FileSystemGlib.cpp:
+        (WebCore::pathByAppendingComponents):
+        * platform/posix/FileSystemPOSIX.cpp:
+        (WebCore::pathByAppendingComponents):
+        * platform/win/FileSystemWin.cpp:
+        (WebCore::pathByAppendingComponents):
+        Add pathByAppendingComponents() utility function, which is similar to
+        pathByAppendingComponent() but supports appending multiple components
+        in an efficient fashion.
+
 2017-08-30  Antti Koivisto  <[email protected]>
 
         Factor RenderMultiColumnFlowThread construction and destruction into RenderTreeUpdater helper

Modified: trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -26,18 +26,131 @@
 #include "config.h"
 #include "DOMFileSystem.h"
 
+#include "File.h"
+#include "FileMetadata.h"
+#include "FileSystem.h"
 #include "FileSystemDirectoryEntry.h"
+#include "FileSystemFileEntry.h"
+#include <wtf/CrossThreadCopier.h>
+#include <wtf/UUID.h>
 
 namespace WebCore {
 
-DOMFileSystem::DOMFileSystem(const String& name)
-    : m_name(name)
-    , m_root(FileSystemDirectoryEntry::create(*this, ASCIILiteral("/")))
+struct ListedChild {
+    String filename;
+    FileMetadata::Type type;
+
+    ListedChild isolatedCopy() const { return { filename.isolatedCopy(), type }; }
+};
+
+static ExceptionOr<Vector<ListedChild>> listDirectoryWithMetadata(const String& fullPath)
 {
+    ASSERT(!isMainThread());
+    if (!fileIsDirectory(fullPath))
+        return Exception { NotFoundError, "Path no longer exists or is no longer a directory" };
+
+    auto childPaths = listDirectory(fullPath, "*");
+    Vector<ListedChild> listedChildren;
+    listedChildren.reserveInitialCapacity(childPaths.size());
+    for (auto& childPath : childPaths) {
+        FileMetadata metadata;
+        if (!getFileMetadata(childPath, metadata))
+            continue;
+        listedChildren.uncheckedAppend(ListedChild { pathGetFileName(childPath), metadata.type });
+    }
+    return WTFMove(listedChildren);
 }
 
+static ExceptionOr<Vector<Ref<FileSystemEntry>>> toFileSystemEntries(DOMFileSystem& fileSystem, ExceptionOr<Vector<ListedChild>>&& listedChildren, const String& parentVirtualPath)
+{
+    ASSERT(isMainThread());
+    if (listedChildren.hasException())
+        return listedChildren.releaseException();
+
+    Vector<Ref<FileSystemEntry>> entries;
+    entries.reserveInitialCapacity(listedChildren.returnValue().size());
+    for (auto& child : listedChildren.returnValue()) {
+        String virtualPath = parentVirtualPath + "/" + child.filename;
+        switch (child.type) {
+        case FileMetadata::TypeFile:
+            entries.uncheckedAppend(FileSystemFileEntry::create(fileSystem, virtualPath));
+            break;
+        case FileMetadata::TypeDirectory:
+            entries.uncheckedAppend(FileSystemDirectoryEntry::create(fileSystem, virtualPath));
+            break;
+        default:
+            break;
+        }
+    }
+    return WTFMove(entries);
+}
+
+DOMFileSystem::DOMFileSystem(Ref<File>&& file)
+    : m_name(createCanonicalUUIDString())
+    , m_file(WTFMove(file))
+    , m_rootPath(directoryName(m_file->path()))
+    , m_workQueue(WorkQueue::create("DOMFileSystem work queue"))
+{
+    ASSERT(!m_rootPath.endsWith('/'));
+}
+
 DOMFileSystem::~DOMFileSystem()
 {
 }
 
+Ref<FileSystemDirectoryEntry> DOMFileSystem::root()
+{
+    return FileSystemDirectoryEntry::create(*this, ASCIILiteral("/"));
+}
+
+Ref<FileSystemEntry> DOMFileSystem::fileAsEntry()
+{
+    if (m_file->isDirectory())
+        return FileSystemDirectoryEntry::create(*this, "/" + m_file->name());
+    return FileSystemFileEntry::create(*this, "/" + m_file->name());
+}
+
+// https://wicg.github.io/entries-api/#evaluate-a-path
+String DOMFileSystem::evaluatePath(const String& virtualPath)
+{
+    ASSERT(virtualPath[0] == '/');
+    auto components = virtualPath.split('/');
+
+    Vector<String> resolvedComponents;
+    resolvedComponents.reserveInitialCapacity(components.size());
+    for (auto& component : components) {
+        if (component == ".")
+            continue;
+        if (component == "..") {
+            if (!resolvedComponents.isEmpty())
+                resolvedComponents.removeLast();
+            continue;
+        }
+        resolvedComponents.uncheckedAppend(component);
+    }
+
+    return pathByAppendingComponents(m_rootPath, resolvedComponents);
+}
+
+void DOMFileSystem::listDirectory(FileSystemDirectoryEntry& directory, DirectoryListingCallback&& completionHandler)
+{
+    ASSERT(&directory.filesystem() == this);
+
+    String directoryVirtualPath = directory.virtualPath();
+    auto fullPath = evaluatePath(directoryVirtualPath);
+    if (fullPath == m_rootPath) {
+        Vector<Ref<FileSystemEntry>> children;
+        children.append(fileAsEntry());
+        completionHandler(WTFMove(children));
+        return;
+    }
+
+    m_workQueue->dispatch([this, 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));
+        });
+    });
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.h (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -25,32 +25,45 @@
 
 #pragma once
 
+#include "ExceptionOr.h"
 #include "ScriptWrappable.h"
 #include <wtf/RefCounted.h>
+#include <wtf/WorkQueue.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
+class File;
 class FileSystemDirectoryEntry;
 class FileSystemEntry;
 
 class DOMFileSystem : public ScriptWrappable, public RefCounted<DOMFileSystem> {
 public:
-    static Ref<DOMFileSystem> create(const String& name)
+    static Ref<FileSystemEntry> createEntryForFile(Ref<File>&& file)
     {
-        return adoptRef(*new DOMFileSystem(name));
+        auto fileSystem = adoptRef(*new DOMFileSystem(WTFMove(file)));
+        return fileSystem->fileAsEntry();
     }
 
     ~DOMFileSystem();
 
     const String& name() const { return m_name; }
-    FileSystemDirectoryEntry& root() const { return m_root; }
+    Ref<FileSystemDirectoryEntry> root();
 
+    using DirectoryListingCallback = WTF::Function<void(ExceptionOr<Vector<Ref<FileSystemEntry>>>&&)>;
+    void listDirectory(FileSystemDirectoryEntry&, DirectoryListingCallback&&);
+
 private:
-    explicit DOMFileSystem(const String& name);
+    explicit DOMFileSystem(Ref<File>&&);
 
+    String evaluatePath(const String& virtualPath);
+    Ref<FileSystemEntry> fileAsEntry();
+
     String m_name;
-    Ref<FileSystemDirectoryEntry> m_root;
+    Ref<File> m_file;
+    String m_rootPath;
+    Ref<WorkQueue> m_workQueue;
+
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.idl (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.idl	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/DOMFileSystem.idl	2017-08-31 03:48:21 UTC (rev 221414)
@@ -29,5 +29,5 @@
     InterfaceName=FileSystem,
 ] interface DOMFileSystem {
     readonly attribute USVString name;
-    readonly attribute FileSystemDirectoryEntry root;
+    [CachedAttribute] readonly attribute FileSystemDirectoryEntry root;
 };

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -37,9 +37,9 @@
 {
 }
 
-Ref<FileSystemDirectoryReader> FileSystemDirectoryEntry::createReader()
+Ref<FileSystemDirectoryReader> FileSystemDirectoryEntry::createReader(ScriptExecutionContext& context)
 {
-    return FileSystemDirectoryReader::create(*this);
+    return FileSystemDirectoryReader::create(context, *this);
 }
 
 void FileSystemDirectoryEntry::getFile(ScriptExecutionContext& context, const String&, const Flags&, RefPtr<FileSystemEntryCallback>&&, RefPtr<ErrorCallback>&& errorCallback)

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.h (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -41,7 +41,7 @@
         return adoptRef(*new FileSystemDirectoryEntry(filesystem, virtualPath));
     }
 
-    Ref<FileSystemDirectoryReader> createReader();
+    Ref<FileSystemDirectoryReader> createReader(ScriptExecutionContext&);
 
     struct Flags {
         bool create { false };

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.idl (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.idl	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryEntry.idl	2017-08-31 03:48:21 UTC (rev 221414)
@@ -26,7 +26,7 @@
 [
     EnabledAtRuntime=DirectoryUpload,
 ] interface FileSystemDirectoryEntry : FileSystemEntry {
-    FileSystemDirectoryReader createReader();
+    [CallWith=ScriptExecutionContext] FileSystemDirectoryReader createReader();
 
     [CallWith=ScriptExecutionContext] void getFile(optional USVString? path,
         optional FileSystemFlags options,

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -27,15 +27,19 @@
 #include "FileSystemDirectoryReader.h"
 
 #include "DOMException.h"
+#include "DOMFileSystem.h"
 #include "ErrorCallback.h"
 #include "FileSystemDirectoryEntry.h"
 #include "FileSystemEntriesCallback.h"
+#include <wtf/MainThread.h>
 
 namespace WebCore {
 
-FileSystemDirectoryReader::FileSystemDirectoryReader(FileSystemDirectoryEntry& directory)
-    : m_directory(directory)
+FileSystemDirectoryReader::FileSystemDirectoryReader(ScriptExecutionContext& context, FileSystemDirectoryEntry& directory)
+    : ActiveDOMObject(&context)
+    , m_directory(directory)
 {
+    suspendIfNeeded();
 }
 
 FileSystemDirectoryReader::~FileSystemDirectoryReader()
@@ -42,10 +46,51 @@
 {
 }
 
-void FileSystemDirectoryReader::readEntries(ScriptExecutionContext& context, Ref<FileSystemEntriesCallback>&&, RefPtr<ErrorCallback>&& errorCallback)
+const char* FileSystemDirectoryReader::activeDOMObjectName() const
 {
-    if (errorCallback)
-        errorCallback->scheduleCallback(context, DOMException::create(NotSupportedError));
+    return "FileSystemDirectoryReader";
 }
 
+bool FileSystemDirectoryReader::canSuspendForDocumentSuspension() const
+{
+    return !hasPendingActivity();
+}
+
+// https://wicg.github.io/entries-api/#dom-filesystemdirectoryentry-readentries
+void FileSystemDirectoryReader::readEntries(ScriptExecutionContext& context, Ref<FileSystemEntriesCallback>&& successCallback, RefPtr<ErrorCallback>&& errorCallback)
+{
+    if (m_isReading) {
+        if (errorCallback)
+            errorCallback->scheduleCallback(context, DOMException::create(Exception { InvalidStateError, ASCIILiteral("Directory reader is already reading") }));
+        return;
+    }
+
+    if (m_error) {
+        if (errorCallback)
+            errorCallback->scheduleCallback(context, DOMException::create(*m_error));
+        return;
+    }
+
+    if (m_isDone) {
+        successCallback->scheduleCallback(context, { });
+        return;
+    }
+
+    m_isReading = true;
+    auto pendingActivity = makePendingActivity(*this);
+    callOnMainThread([this, 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) {
+            if (result.hasException()) {
+                m_error = result.releaseException();
+                if (errorCallback)
+                    errorCallback->handleEvent(DOMException::create(*m_error));
+                return;
+            }
+            m_isDone = true;
+            successCallback->handleEvent(result.releaseReturnValue());
+        });
+    });
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include "ActiveDOMObject.h"
+#include "Exception.h"
 #include "ScriptWrappable.h"
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
@@ -36,11 +38,11 @@
 class FileSystemEntriesCallback;
 class ScriptExecutionContext;
 
-class FileSystemDirectoryReader : public ScriptWrappable, public RefCounted<FileSystemDirectoryReader> {
+class FileSystemDirectoryReader final : public ScriptWrappable, public ActiveDOMObject, public RefCounted<FileSystemDirectoryReader> {
 public:
-    static Ref<FileSystemDirectoryReader> create(FileSystemDirectoryEntry& directory)
+    static Ref<FileSystemDirectoryReader> create(ScriptExecutionContext& context, FileSystemDirectoryEntry& directory)
     {
-        return adoptRef(*new FileSystemDirectoryReader(directory));
+        return adoptRef(*new FileSystemDirectoryReader(context, directory));
     }
 
     ~FileSystemDirectoryReader();
@@ -48,9 +50,15 @@
     void readEntries(ScriptExecutionContext&, Ref<FileSystemEntriesCallback>&&, RefPtr<ErrorCallback>&&);
 
 private:
-    explicit FileSystemDirectoryReader(FileSystemDirectoryEntry&);
+    FileSystemDirectoryReader(ScriptExecutionContext&, FileSystemDirectoryEntry&);
 
+    const char* activeDOMObjectName() const final;
+    bool canSuspendForDocumentSuspension() const final;
+
     Ref<FileSystemDirectoryEntry> m_directory;
+    std::optional<Exception> m_error;
+    bool m_isReading { false };
+    bool m_isDone { false };
 };
 
 }

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.idl (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.idl	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemDirectoryReader.idl	2017-08-31 03:48:21 UTC (rev 221414)
@@ -25,7 +25,6 @@
 
 [
     EnabledAtRuntime=DirectoryUpload,
-    ImplementationLacksVTable,
 ] interface FileSystemDirectoryReader {
     [CallWith=ScriptExecutionContext] void readEntries(FileSystemEntriesCallback successCallback, optional ErrorCallback? errorCallback);
 };

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "FileSystemEntry.h"
 
+#include "DOMFileSystem.h"
 #include "FileSystem.h"
 
 namespace WebCore {
@@ -37,4 +38,14 @@
 {
 }
 
+FileSystemEntry::~FileSystemEntry()
+{
+}
+
+DOMFileSystem& FileSystemEntry::filesystem() const
+{
+    return m_filesystem.get();
+}
+
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.h (221413 => 221414)


--- trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/Modules/entriesapi/FileSystemEntry.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -35,7 +35,7 @@
 
 class FileSystemEntry : public ScriptWrappable, public RefCounted<FileSystemEntry> {
 public:
-    virtual ~FileSystemEntry() { }
+    virtual ~FileSystemEntry();
 
     virtual bool isFile() const { return false; }
     virtual bool isDirectory() const { return false; }
@@ -42,13 +42,13 @@
 
     const String& name() const { return m_name; }
     const String& virtualPath() const { return m_virtualPath; }
-    DOMFileSystem& filesystem() const { return m_filesystem; }
+    DOMFileSystem& filesystem() const;
 
 protected:
     FileSystemEntry(DOMFileSystem&, const String& virtualPath);
 
 private:
-    DOMFileSystem& m_filesystem;
+    Ref<DOMFileSystem> m_filesystem;
     String m_name;
     String m_virtualPath;
 };

Modified: trunk/Source/WebCore/dom/ActiveDOMObject.h (221413 => 221414)


--- trunk/Source/WebCore/dom/ActiveDOMObject.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/ActiveDOMObject.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -29,6 +29,7 @@
 #include "ContextDestructionObserver.h"
 #include <wtf/Assertions.h>
 #include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
 
 namespace WebCore {
 
@@ -83,6 +84,31 @@
         thisObject->deref();
     }
 
+    template<class T>
+    class PendingActivity : public RefCounted<PendingActivity<T>> {
+    public:
+        explicit PendingActivity(T& thisObject)
+            : m_thisObject(thisObject)
+        {
+            ++(m_thisObject->m_pendingActivityCount);
+        }
+
+        ~PendingActivity()
+        {
+            ASSERT(m_thisObject->m_pendingActivityCount > 0);
+            --(m_thisObject->m_pendingActivityCount);
+        }
+
+    private:
+        Ref<T> m_thisObject;
+    };
+
+    template<class T> Ref<PendingActivity<T>> makePendingActivity(T& thisObject)
+    {
+        ASSERT(&thisObject == this);
+        return adoptRef(*new PendingActivity<T>(thisObject));
+    }
+
 protected:
     explicit ActiveDOMObject(ScriptExecutionContext*);
     virtual ~ActiveDOMObject();

Modified: trunk/Source/WebCore/dom/DOMException.cpp (221413 => 221414)


--- trunk/Source/WebCore/dom/DOMException.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/DOMException.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -29,6 +29,8 @@
 #include "config.h"
 #include "DOMException.h"
 
+#include "Exception.h"
+
 namespace WebCore {
 
 // This array needs to be kept in sync with the ExceptionCode enumeration.
@@ -99,6 +101,12 @@
     return adoptRef(*new DOMException(legacyCodeFromName(name), name, message));
 }
 
+Ref<DOMException> DOMException::create(const Exception& exception)
+{
+    auto& description = DOMException::description(exception.code());
+    return adoptRef(*new DOMException(description.legacyCode, description.name, exception.message().isEmpty() ? description.message : exception.message()));
+}
+
 DOMException::DOMException(LegacyCode legacyCode, const String& name, const String& message)
     : m_legacyCode(legacyCode)
     , m_name(name)

Modified: trunk/Source/WebCore/dom/DOMException.h (221413 => 221414)


--- trunk/Source/WebCore/dom/DOMException.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/DOMException.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -33,9 +33,12 @@
 
 namespace WebCore {
 
+class Exception;
+
 class DOMException : public RefCounted<DOMException> {
 public:
     static Ref<DOMException> create(ExceptionCode, const String* message = nullptr);
+    static Ref<DOMException> create(const Exception&);
 
     // For DOM bindings.
     static Ref<DOMException> create(const String& message, const String& name);

Modified: trunk/Source/WebCore/dom/DataTransferItem.cpp (221413 => 221414)


--- trunk/Source/WebCore/dom/DataTransferItem.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/DataTransferItem.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -40,7 +40,6 @@
 #include "FileSystemFileEntry.h"
 #include "ScriptExecutionContext.h"
 #include "StringCallback.h"
-#include <wtf/UUID.h>
 
 namespace WebCore {
 
@@ -112,13 +111,7 @@
     if (!file)
         return nullptr;
 
-    if (!m_fileSystem)
-        m_fileSystem = DOMFileSystem::create(createCanonicalUUIDString());
-
-    String virtualPath = "/" + file->name();
-    if (file->isDirectory())
-        return FileSystemDirectoryEntry::create(*m_fileSystem, virtualPath);
-    return FileSystemFileEntry::create(*m_fileSystem, virtualPath);
+    return DOMFileSystem::createEntryForFile(*file);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/DataTransferItem.h (221413 => 221414)


--- trunk/Source/WebCore/dom/DataTransferItem.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/DataTransferItem.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -72,7 +72,6 @@
     WeakPtr<DataTransferItemList> m_list;
     const String m_type;
     RefPtr<File> m_file;
-    mutable RefPtr<DOMFileSystem> m_fileSystem;
 };
 
 }

Modified: trunk/Source/WebCore/dom/Exception.h (221413 => 221414)


--- trunk/Source/WebCore/dom/Exception.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/Exception.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -39,6 +39,11 @@
     const String& message() const { return m_message; }
     String&& releaseMessage() { return WTFMove(m_message); }
 
+    Exception isolatedCopy() const
+    {
+        return Exception { m_code, m_message.isolatedCopy() };
+    }
+
 private:
     ExceptionCode m_code;
     String m_message;

Modified: trunk/Source/WebCore/dom/ExceptionOr.h (221413 => 221414)


--- trunk/Source/WebCore/dom/ExceptionOr.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/dom/ExceptionOr.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -27,6 +27,7 @@
 #pragma once
 
 #include "Exception.h"
+#include <wtf/CrossThreadCopier.h>
 #include <wtf/Expected.h>
 
 namespace WebCore {
@@ -180,3 +181,15 @@
 }
 
 }
+
+namespace WTF {
+template<typename T> struct CrossThreadCopierBase<false, false, WebCore::ExceptionOr<T> > {
+    typedef WebCore::ExceptionOr<T> Type;
+    static Type copy(const Type& source)
+    {
+        if (source.hasException())
+            return crossThreadCopy(source.exception());
+        return crossThreadCopy(source.returnValue());
+    }
+};
+}

Modified: trunk/Source/WebCore/html/FileListCreator.cpp (221413 => 221414)


--- trunk/Source/WebCore/html/FileListCreator.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/html/FileListCreator.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -65,7 +65,7 @@
         // Resolve directories on a background thread to avoid blocking the main thread.
         m_completionHander = WTFMove(completionHandler);
         m_workQueue = WorkQueue::create("FileListCreator Work Queue");
-        m_workQueue->dispatch([this, protectedThis = makeRef(*this), paths = CrossThreadCopier<Vector<FileChooserFileInfo>>::copy(paths)]() mutable {
+        m_workQueue->dispatch([this, protectedThis = makeRef(*this), paths = crossThreadCopy(paths)]() mutable {
             auto fileList = createFileList<ShouldResolveDirectories::Yes>(paths);
             callOnMainThread([this, protectedThis = WTFMove(protectedThis), fileList = WTFMove(fileList)]() mutable {
                 if (auto completionHander = WTFMove(m_completionHander))

Modified: trunk/Source/WebCore/platform/FileSystem.h (221413 => 221414)


--- trunk/Source/WebCore/platform/FileSystem.h	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/platform/FileSystem.h	2017-08-31 03:48:21 UTC (rev 221414)
@@ -101,6 +101,7 @@
 bool getFileMetadata(const String&, FileMetadata&);
 bool fileIsDirectory(const String&);
 WEBCORE_EXPORT String pathByAppendingComponent(const String& path, const String& component);
+String pathByAppendingComponents(const String& path, const Vector<String>& components);
 String lastComponentOfPathIgnoringTrailingSlash(const String& path);
 WEBCORE_EXPORT bool makeAllDirectories(const String& path);
 String homeDirectoryPath();

Modified: trunk/Source/WebCore/platform/glib/FileSystemGlib.cpp (221413 => 221414)


--- trunk/Source/WebCore/platform/glib/FileSystemGlib.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/platform/glib/FileSystemGlib.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -35,6 +35,7 @@
 #include <wtf/glib/GRefPtr.h>
 #include <wtf/glib/GUniquePtr.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -180,6 +181,17 @@
     return path + G_DIR_SEPARATOR_S + component;
 }
 
+String pathByAppendingComponents(const String& path, const Vector<String>& components)
+{
+    StringBuilder builder;
+    builder.append(path);
+    for (auto& component : components) {
+        builder.append(G_DIR_SEPARATOR_S);
+        builder.append(component);
+    }
+    return builder.toString();
+}
+
 bool makeAllDirectories(const String& path)
 {
     GUniquePtr<gchar> filename = unescapedFilename(path);

Modified: trunk/Source/WebCore/platform/posix/FileSystemPOSIX.cpp (221413 => 221414)


--- trunk/Source/WebCore/platform/posix/FileSystemPOSIX.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/platform/posix/FileSystemPOSIX.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -40,6 +40,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -270,6 +271,17 @@
     return path + "/" + component;
 }
 
+String pathByAppendingComponents(const String& path, const Vector<String>& components)
+{
+    StringBuilder builder;
+    builder.append(path);
+    for (auto& component : components) {
+        builder.append('/');
+        builder.append(component);
+    }
+    return builder.toString();
+}
+
 bool makeAllDirectories(const String& path)
 {
     CString fullPath = fileSystemRepresentation(path);

Modified: trunk/Source/WebCore/platform/win/FileSystemWin.cpp (221413 => 221414)


--- trunk/Source/WebCore/platform/win/FileSystemWin.cpp	2017-08-31 02:54:21 UTC (rev 221413)
+++ trunk/Source/WebCore/platform/win/FileSystemWin.cpp	2017-08-31 03:48:21 UTC (rev 221414)
@@ -41,6 +41,7 @@
 #include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
 
@@ -201,6 +202,14 @@
     return String::adopt(WTFMove(buffer));
 }
 
+String pathByAppendingComponents(const String& path, const Vector<String>& components)
+{
+    String result = path;
+    for (auto& component : components)
+        result = pathByAppendingComponent(result, component);
+    return result;
+}
+
 #if !USE(CF)
 
 CString fileSystemRepresentation(const String& path)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to