Title: [229297] trunk
Revision
229297
Author
[email protected]
Date
2018-03-05 17:36:31 -0800 (Mon, 05 Mar 2018)

Log Message

[Mac] Teach WebCore::Pasteboard about file promise drags
https://bugs.webkit.org/show_bug.cgi?id=183314
<rdar://problem/38105493>

Reviewed by Darin Adler.

Source/WebCore:

While WebKit does support receiving file promise drags (since r210360), WebCore::Pasteboard
has not been instructed on how to read their file paths. When the various pasteboard readers
ask for file paths after a file promise drop, they receive an empty vector. This impacts
various features, most notably the DataTransfer API.

Pasteboard actually cannot learn about promised file paths from the pasteboard itself, as
the pasteboard only contains the dragged files' UTIs. Promised file paths aren't known until
the WebKits call -[NSFilePromiseReceiver receivePromisedFilesAtDestination:...], at which
point the file paths are passed to WebCore as part of WebCore::DragData.

When we construct new Pasteboards for drag and drop, we need to store any promised file
paths from the DragData. Then, when the various pasteboard readers ask for file paths and
NSFilesPromisePboardType is on the pasteboard, we can return these promised file paths.

Tests: editing/pasteboard/data-transfer-items-drag-drop-file-promise.html
       editing/pasteboard/data-transfer-items-drop-file-promise.html
       editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html
       editing/pasteboard/datatransfer-types-dropping-text-file-promise.html
       editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html
       editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html
       editing/pasteboard/file-input-files-access-promise.html

* platform/FileSystem.h:
* platform/Pasteboard.h:
(WebCore::Pasteboard::Pasteboard):
* platform/mac/DragDataMac.mm:
(WebCore::DragData::containsPromise const):
* platform/mac/PasteboardMac.mm:
(WebCore::Pasteboard::Pasteboard):
(WebCore::Pasteboard::createForDragAndDrop):
(WebCore::toString):
(WebCore::Pasteboard::read):
(WebCore::Pasteboard::readFilePaths):
(WebCore::absoluteURLsFromPasteboardFilenames): Deleted.
* platform/mac/PlatformPasteboardMac.mm:
(WebCore::PlatformPasteboard::numberOfFiles const):

Source/WebKit:

Added a FIXME comment.

* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::performDragOperation):

Source/WebKitLegacy/mac:

Added a FIXME comment.

* WebView/WebView.mm:
(-[WebView performDragOperation:]):

Tools:

* DumpRenderTree/DumpRenderTreeFileDraggingSource.h:
* DumpRenderTree/DumpRenderTreeFileDraggingSource.m:
(-[DumpRenderTreeFileDraggingSource initWithPromisedFileURLs:]):
(-[DumpRenderTreeFileDraggingSource dealloc]):

Taught DumpRenderTreeFileDraggingSource to store the promised file URLs.

* DumpRenderTree/mac/DumpRenderTree.mm:
(runTest):

Called +[DumpRenderTreeDraggingInfo clearAllFilePromiseReceivers] after running a test.

* DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h:
* DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm:
(-[DumpRenderTreeFilePromiseReceiver initWithPromisedUTIs:]):
(-[DumpRenderTreeFilePromiseReceiver fileTypes]):
(-[DumpRenderTreeFilePromiseReceiver fileNames]):
(-[DumpRenderTreeFilePromiseReceiver dealloc]):
(copyFile):
(-[DumpRenderTreeFilePromiseReceiver receivePromisedFilesAtDestination:options:operationQueue:reader:]):

We can't instantiate real NSFilePromiseReceivers in DumpRenderTree. They rely on the
pasteboard server to generate unique file URLs, which is incompatible with our swizzled
NSPasteboard.

Instead, create a subclass of NSFilePromiseReceiver that implements its own promise resolution.
-receivePromisedFilesAtDestination:... asks its DumpRenderTreeFileDraggingSource for the
array of file URLs, then copies each to the destination directory on the specified operation
queue. It emulates how NSPasteboard tries to find a unique destination name by appending
numbers to the file name.

All receivers are collected in a global array that is cleared when each test finishes.
DumpRenderTreeFilePromiseReceiver will delete the files it copied in -dealloc.

(+[DumpRenderTreeDraggingInfo clearAllFilePromiseReceivers]):
(-[DumpRenderTreeDraggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:]):

If NSFilesPromisePboardType is on the pasteboard and classArray contains
NSFilePromiseReceiver, construct a DumpRenderTreeFilePromiseReceiver, add it to the array of
all file promise receivers, then wrap it in an NSDraggingItem and call block.

* DumpRenderTree/mac/EventSendingController.mm:
(+[EventSendingController isSelectorExcludedFromWebScript:]):
(+[EventSendingController webScriptNameForSelector:]):
(-[EventSendingController beginDragWithFilePromises:]):

Implement eventSender.beginDragWithFilePromises() by placing file UTIs on the pasteboard
with type NSFilesPromisePboardType, creating a DumpRenderTreeFileDraggingSource with the
file URLs, and creating a new DumpRenderTreeDraggingInfo and passing it to
-[WebView draggingEntered:].

LayoutTests:

Added versions of file dragging tests in editing/pasteboard/ that use
beginDragWithFilePromises() instead of beginDragWithFiles().

* TestExpectations: Skipped the new tests.
* editing/pasteboard/data-transfer-items-drag-drop-file-promise-expected.txt: Added.
* editing/pasteboard/data-transfer-items-drag-drop-file-promise.html: Added.
* editing/pasteboard/data-transfer-items-drop-file-promise-expected.txt: Added.
* editing/pasteboard/data-transfer-items-drop-file-promise.html: Added.
* editing/pasteboard/datatransfer-items-drop-plaintext-file-promise-expected.txt: Added.
* editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html: Added.
* editing/pasteboard/datatransfer-types-dropping-text-file-promise-expected.txt: Added.
* editing/pasteboard/datatransfer-types-dropping-text-file-promise.html: Added.
* editing/pasteboard/drag-file-promises-to-editable-element-as-URLs-expected.txt: Added.
* editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html: Added.
* editing/pasteboard/drag-file-promises-to-editable-element-as-attachment-expected.txt: Added.
* editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html: Added.
* editing/pasteboard/file-input-files-access-promise-expected.txt: Added.
* editing/pasteboard/file-input-files-access-promise.html: Added.
* platform/mac-wk1/TestExpectations: Un-skipped the new tests.
* platform/win/TestExpectations: Skipped the new tests.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (229296 => 229297)


--- trunk/LayoutTests/ChangeLog	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/LayoutTests/ChangeLog	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,3 +1,32 @@
+2018-03-05  Andy Estes  <[email protected]>
+
+        [Mac] Teach WebCore::Pasteboard about file promise drags
+        https://bugs.webkit.org/show_bug.cgi?id=183314
+        <rdar://problem/38105493>
+
+        Reviewed by Darin Adler.
+
+        Added versions of file dragging tests in editing/pasteboard/ that use
+        beginDragWithFilePromises() instead of beginDragWithFiles().
+
+        * TestExpectations: Skipped the new tests.
+        * editing/pasteboard/data-transfer-items-drag-drop-file-promise-expected.txt: Added.
+        * editing/pasteboard/data-transfer-items-drag-drop-file-promise.html: Added.
+        * editing/pasteboard/data-transfer-items-drop-file-promise-expected.txt: Added.
+        * editing/pasteboard/data-transfer-items-drop-file-promise.html: Added.
+        * editing/pasteboard/datatransfer-items-drop-plaintext-file-promise-expected.txt: Added.
+        * editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html: Added.
+        * editing/pasteboard/datatransfer-types-dropping-text-file-promise-expected.txt: Added.
+        * editing/pasteboard/datatransfer-types-dropping-text-file-promise.html: Added.
+        * editing/pasteboard/drag-file-promises-to-editable-element-as-URLs-expected.txt: Added.
+        * editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html: Added.
+        * editing/pasteboard/drag-file-promises-to-editable-element-as-attachment-expected.txt: Added.
+        * editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html: Added.
+        * editing/pasteboard/file-input-files-access-promise-expected.txt: Added.
+        * editing/pasteboard/file-input-files-access-promise.html: Added.
+        * platform/mac-wk1/TestExpectations: Un-skipped the new tests.
+        * platform/win/TestExpectations: Skipped the new tests.
+
 2018-03-05  Ryan Haddad  <[email protected]>
 
         Unreviewed, add baseline for fast/text/combining-enclosing-keycap.html.

Modified: trunk/LayoutTests/TestExpectations (229296 => 229297)


--- trunk/LayoutTests/TestExpectations	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/LayoutTests/TestExpectations	2018-03-06 01:36:31 UTC (rev 229297)
@@ -81,14 +81,20 @@
 editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Skip ]
 editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Skip ]
 editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Skip ]
+editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Skip ]
+editing/pasteboard/data-transfer-items-drag-drop-file-promise.html [ Skip ]
+editing/pasteboard/data-transfer-items-drop-file.html [ Skip ]
+editing/pasteboard/data-transfer-items-drop-file-promise.html [ Skip ]
 editing/pasteboard/data-transfer-set-data-sanitize-html-when-dragging-in-null-origin.html [ Skip ]
 editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin.html [ Skip ]
+editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html [ Skip ]
+editing/pasteboard/datatransfer-types-dropping-text-file-promise.html [ Skip ]
+editing/pasteboard/drag-end-crash-accessing-item-list.html [ Skip ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html [ Skip ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html [ Skip ]
+editing/pasteboard/file-input-files-access-promise.html [ Skip ]
 http/tests/security/clipboard/drag-drop-html-cross-origin-iframe-in-same-origin.html [ Skip ]
 
-editing/pasteboard/drag-end-crash-accessing-item-list.html [ Skip ]
-editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Skip ]
-editing/pasteboard/data-transfer-items-drop-file.html [ Skip ]
-
 # Only iOS supports QuickLook
 quicklook [ Skip ]
 http/tests/quicklook [ Skip ]

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,23 @@
+This tests the basic functionality and properties of DataTransferItems for file promises with drag and drop. This test requires DRT.
+Drop files here if you test this manually
+Dragging file: resources/mozilla.gif
+Dragging file: resources/drop-file-svg.svg
+Dragging file: resources/copy-backslash-euc.html
+Verifying contents of DataTransferItems...
+PASS: "3" == "3"
+PASS: "file" == "file"
+PASS: "image/gif" == "image/gif"
+PASS: "image/gif" == "image/gif"
+PASS: "2593" == "2593"
+PASS: "mozilla.gif" == "mozilla.gif"
+PASS: "file" == "file"
+PASS: "image/svg+xml" == "image/svg+xml"
+PASS: "image/svg+xml" == "image/svg+xml"
+PASS: "109" == "109"
+PASS: "drop-file-svg.svg" == "drop-file-svg.svg"
+PASS: "file" == "file"
+PASS: "text/html" == "text/html"
+PASS: "text/html" == "text/html"
+PASS: "478" == "478"
+PASS: "copy-backslash-euc.html" == "copy-backslash-euc.html"
+

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-items-drag-drop-file-promise.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div>This tests the basic functionality and properties of DataTransferItems for file promises with drag and drop. This test requires DRT.</div>
+
+<div id="destination" style="min-height:100px; border: solid 1px black">Drop files here if you test this manually</div>
+
+<div id="console"></div>
+
+<script>
+var testFiles = [
+  { path: 'resources/mozilla.gif',
+    type: 'image/gif',
+    size: 2593 },
+  { path: 'resources/drop-file-svg.svg',
+    type: 'image/svg+xml',
+    size: 109 },
+  { path: 'resources/copy-backslash-euc.html',
+    type: 'text/html',
+    size: 478 }
+];
+
+function log(text)
+{
+    var console = document.getElementById('console');
+    console.appendChild(document.createTextNode(text));
+    console.appendChild(document.createElement('br'));
+}
+
+function test(expect, actual)
+{
+    log((expect == actual ? 'PASS' : 'FAIL') + ': "' + expect + '" == "' + actual + '"');
+}
+
+function startTest()
+{
+    var destination = document.getElementById('destination');
+    destination.addEventListener('dragover', handleDragOver, false);
+    destination.addEventListener('drop', handleDrop, false);
+
+    if (!window.testRunner)
+        return;
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+
+    var files = [];
+    for (var i = 0; i < testFiles.length; ++i) {
+      log('Dragging file: ' + testFiles[i].path);
+      files.push(testFiles[i].path);
+    }
+
+    // Perform drag-and-drop with the testFiles.
+    eventSender.beginDragWithFilePromises(files);
+    eventSender.leapForward(500);
+    eventSender.mouseMoveTo(destination.offsetLeft + 10, destination.offsetTop + destination.offsetHeight / 2);
+    eventSender.mouseUp();
+}
+
+function handleDragOver(e)
+{
+    e.stopPropagation();
+    e.preventDefault();
+}
+
+function handleDrop(e)
+{
+    e.stopPropagation();
+    e.preventDefault();
+
+    log('Verifying contents of DataTransferItems...');
+    var items = e.dataTransfer.items;
+    var files = [];
+    test(testFiles.length, items.length);
+    for (var i = 0; i < items.length; ++i) {
+        // The items should be in the same order as we added.
+        var expected = testFiles[i];
+
+        var file = items[i].getAsFile();
+        files.push(file);
+
+        test('file', items[i].kind);
+        test(expected.type, items[i].type);
+        test(expected.type, file.type);
+        test(expected.size, file.size);
+
+        var components = expected.path.split('/');
+        var name = components[components.length - 1];
+        test(name, file.name);
+    }
+
+    testRunner.notifyDone();
+}
+
+startTest();
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,9 @@
+
+*** Handling drop ***
+
+Types => data
+Files => ""
+Item list
+[0] => (name = 'apple.gif', size = 1476 bytes, type = 'image/gif')
+File list
+[0] => (name = 'apple.gif', size = 1476 bytes, type = 'image/gif')

Added: trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/data-transfer-items-drop-file-promise.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+html, body {
+    width: 100%;
+    height: 100%;
+}
+</style>
+<body contenteditable>
+    <pre id="output">
+        This test is best run under DumpRenderTree. To manually test, drop a file anywhere in the body.
+        This will dump the contents of the DataTransfer on drop as output text.
+        You should see an item of kind "file" in the resulting item list, as well as an entry in the item list.
+        There should <i>not</i> be an item of kind "string" and type "file".
+    </pre>
+</body>
+<script>
+
+function write(markup) {
+    output.insertAdjacentHTML("beforeend", markup);
+}
+
+function outputForFile(file) {
+    return file ? `(name = '${file.name}', size = ${file.size} bytes, type = '${file.type}')` : "(null)";
+}
+
+function writeOutputForEvent(event) {
+    output.textContent = "";
+
+    write(`<br><h3>*** Handling ${event.type} ***</h3>`);
+    const pasteboard = event.dataTransfer || event.clipboardData;
+    write(`<div><strong>Types => data</strong></div>`);
+    for (const type of pasteboard.types)
+        write(`<div>${type} => "${pasteboard.getData(type)}"</div>`);
+    let index = 0;
+    write(`<div><strong>Item list</strong></div>`);
+    for (const item of pasteboard.items) {
+        if (item.kind === "file")
+            write(`<div>[${index++}] => ${outputForFile(item.getAsFile())}</div>`);
+        else
+            write(`<div>[${index++}] => (kind = ${item.kind}, type = ${item.type})</div>`);
+    }
+    write(`<div><strong>File list</strong></div>`);
+    index = 0;
+    for (const file of pasteboard.files)
+        write(`<div>[${index++}] => ${outputForFile(file)}</div>`);
+}
+
+document.body.addEventListener("drop", event => {
+    event.preventDefault();
+    writeOutputForEvent(event);
+    testRunner.notifyDone();
+});
+
+if (window.testRunner && window.internals && window.eventSender) {
+    internals.settings.setCustomPasteboardDataEnabled(true);
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+
+    eventSender.beginDragWithFilePromises(["resources/apple.gif"]);
+    eventSender.mouseMoveTo(100, 100);
+    eventSender.mouseUp();
+}
+</script>

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,17 @@
+This tests accessing DataTransferItemList when dropping a file promise. To manually test, drag and drop LayoutTests/editing/resources/text-pasteboard-data.txt from another app (e.g. Finder) to the box below.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 1
+PASS dataTransfer.items[0].kind is "file"
+PASS dataTransfer.items[0].type is "text/plain"
+PASS file = dataTransfer.items[0].getAsFile(); file is not null
+PASS file.name is "text-pasteboard-data.txt"
+PASS reader = new FileReader(); reader._onload_ = () => checkFileContent(reader.result); reader.readAsText(file); did not throw exception.
+PASS "hello, world." is "hello, world."
+PASS dataTransfer.items[0].getAsFile() is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<body _onload_="runTest()">
+<script src=""
+<script>
+
+description('This tests accessing DataTransferItemList when dropping a file promise.'
+    + ' To manually test, drag and drop <a href="" from another app (e.g. Finder) to the box below.');
+
+function runTest()
+{
+    if (!window.testRunner)
+        return;
+    if (!window.eventSender || !eventSender.beginDragWithFilePromises) {
+        testFailed('This test requires eventSender.beginDragWithFilePromises');
+        finishJSTest();
+        return;
+    }
+
+    eventSender.beginDragWithFilePromises(["../resources/text-pasteboard-data.txt"]);
+    const target = document.getElementById('target');
+    eventSender.mouseMoveTo(target.offsetLeft + 5, target.offsetTop + 5);
+    eventSender.mouseUp();
+}
+
+function drop(event)
+{
+    event.preventDefault();
+    dataTransfer = event.dataTransfer;
+    shouldBe('dataTransfer.items.length', '1');
+    shouldBeEqualToString('dataTransfer.items[0].kind', 'file');
+    shouldBeEqualToString('dataTransfer.items[0].type', 'text/plain');
+    shouldNotBe('file = dataTransfer.items[0].getAsFile(); file', 'null');
+    shouldBeEqualToString('file.name', 'text-pasteboard-data.txt');
+    shouldNotThrow('reader = new FileReader(); reader._onload_ = () => checkFileContent(reader.result); reader.readAsText(file);');
+}
+
+function checkFileContent(content)
+{
+    shouldBeEqualToString('"' + content + '"', 'hello, world.');
+    shouldBe('dataTransfer.items[0].getAsFile()', 'null');
+    finishJSTest();
+}
+
+jsTestIsAsync = true;
+successfullyParsed = true;
+
+</script>
+<script src=""
+<div id="target" contenteditable="true" _ondrop_="drop(event)" style="width: 100px; height: 100px; border: solid 1px black;"></div>
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,12 @@
+When dropping a file promise, dataTransfer.types must contain "Files" and not "text/uri-list". This test requires eventSender.beginDragWithFilePromises.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.types.includes("Files") is true
+PASS dataTransfer.types.includes("text/uri-list") is false
+PASS dataTransfer.getData("url") is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/datatransfer-types-dropping-text-file-promise.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div id="target" contentEditable="true" _ondrop_="check(event)"></div>
+<script src=""
+<script>
+description('When dropping a file promise, dataTransfer.types must contain "Files" and not "text/uri-list". This test requires eventSender.beginDragWithFilePromises.');
+
+function runTest() {
+    jsTestIsAsync = true;
+    const target = document.getElementById('target');
+    eventSender.beginDragWithFilePromises(['../resources/abe.png']);
+    eventSender.mouseMoveTo(target.offsetLeft + 5, target.offsetTop + 5);
+    eventSender.mouseUp();
+}
+
+function check(event) {
+    dataTransfer = event.dataTransfer;
+    shouldBeTrue('dataTransfer.types.includes("Files")');
+    shouldBeFalse('dataTransfer.types.includes("text/uri-list")');
+    shouldBeEqualToString('dataTransfer.getData("url")', '');
+    finishJSTest();
+}
+
+if (window.eventSender)
+    runTest();
+else
+    testFailed('This test requires eventSender.beginDragWithFilePromises');
+
+var successfullyParsed = true;
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,13 @@
+If we drag file promises onto an editable area, then attachments should not be inserted into the editable area since attachment elements are disabled.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.HTMLAttachmentElement is undefined.
+PASS document.createElement("attachment") instanceof HTMLUnknownElement is true
+PASS editable.querySelector("attachment") is null
+PASS editable.textContent is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,43 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableAttachmentElement=false ] -->
+<html>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<div id="editable" contentEditable=true style="width:200px; height:200px"></div>
+<script src=""
+<script>
+description('If we drag file promises onto an editable area, then attachments should not be inserted into the editable area since attachment elements are disabled.');
+jsTestIsAsync = true;
+
+var editable = document.getElementById("editable");
+editable.addEventListener("drop", () => window.setTimeout(() => {
+    shouldBeUndefined('window.HTMLAttachmentElement');
+    shouldBeTrue('document.createElement("attachment") instanceof HTMLUnknownElement');
+    shouldBe('editable.querySelector("attachment")', 'null');
+    shouldBe('editable.textContent', '""');
+    editable.innerHTML = '';
+    finishJSTest();
+}, 0));
+
+if (window.eventSender)
+    dragFilesOntoEditable(['resources/apple.gif', 'resources/mozilla.gif', 'resources/drop-file-svg.svg']);
+
+function moveMouseToCenterOfElement(element)
+{
+    var centerX = element.offsetLeft + element.offsetWidth / 2;
+    var centerY = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(centerX, centerY);
+}
+
+function dragFilesOntoEditable(files)
+{
+    eventSender.beginDragWithFilePromises(files);
+    moveMouseToCenterOfElement(editable);
+    eventSender.mouseUp();
+}
+
+var successfullyParsed = true;
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,13 @@
+If we drag file promises onto an editable area, then attachments should be inserted into the editable area.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS attachment.nodeName is "ATTACHMENT"
+PASS attachment.nodeName is "ATTACHMENT"
+PASS attachment.nodeName is "ATTACHMENT"
+PASS fileNames is "apple.gif mozilla.gif drop-file-svg.svg "
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,47 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableAttachmentElement=true ] -->
+<html>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<div id="editable" contentEditable=true style="width:200px; height:200px"></div>
+<script src=""
+<script>
+description('If we drag file promises onto an editable area, then attachments should be inserted into the editable area.');
+jsTestIsAsync = true;
+
+var editable = document.getElementById("editable");
+editable.addEventListener("drop", () => window.setTimeout(() => {
+    var resultChildren = editable.children;
+    fileNames = "";
+    for (var i = 0; i < resultChildren.length; i++) {
+        attachment = resultChildren[i];
+        shouldBeEqualToString('attachment.nodeName', 'ATTACHMENT');
+        fileNames += attachment.file.name + " ";
+    }
+    shouldBeEqualToString('fileNames', 'apple.gif mozilla.gif drop-file-svg.svg ');
+    editable.innerHTML = '';
+    finishJSTest();
+}, 0));
+
+if (window.eventSender)
+    dragFilesOntoEditable(['resources/apple.gif', 'resources/mozilla.gif', 'resources/drop-file-svg.svg']);
+
+function moveMouseToCenterOfElement(element)
+{
+    var centerX = element.offsetLeft + element.offsetWidth / 2;
+    var centerY = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(centerX, centerY);
+}
+
+function dragFilesOntoEditable(files)
+{
+    eventSender.beginDragWithFilePromises(files);
+    moveMouseToCenterOfElement(editable);
+    eventSender.mouseUp();
+}
+
+var successfullyParsed = true;
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise-expected.txt (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise-expected.txt	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,27 @@
+Tests for multi-file promise drag onto file input elements
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Dragging a real file to a file input control:
+PASS fileInput.value is "C:\\fakepath\\apple.gif"
+PASS fileInput.files.length is 1
+PASS fileInput.files[0].name is "apple.gif"
+PASS fileInput.files[0].type is "image/gif"
+PASS fileInput.files[0].size is 1476
+Dragging two files to a single-file input control:
+PASS fileInput.value is ""
+PASS fileInput.files.length is 0
+Dragging three files to a multi-file input control:
+PASS fileInput.value is "C:\\fakepath\\apple 2.gif"
+PASS fileInput.files.length is 2
+PASS fileInput.files[0].name is "apple 2.gif"
+PASS fileInput.files[0].type is "image/gif"
+PASS fileInput.files[0].size is 1476
+PASS fileInput.files[1].name is "mozilla.gif"
+PASS fileInput.files[1].type is "image/gif"
+PASS fileInput.files[1].size is 2593
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise.html (0 => 229297)


--- trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise.html	                        (rev 0)
+++ trunk/LayoutTests/editing/pasteboard/file-input-files-access-promise.html	2018-03-06 01:36:31 UTC (rev 229297)
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+description("Tests for multi-file promise drag onto file input elements");
+jsTestIsAsync = true;
+
+var fileInput = document.createElement("input");
+fileInput.type = 'file';
+fileInput.style.width = "100%"; // So that any manual testing will show full file names
+// Important that we put this at the top of the doc so that logging does not cause it to go out of view (where it can't be dragged to)
+document.body.insertBefore(fileInput, document.body.firstChild);
+
+function moveMouseToCenterOfElement(element)
+{
+    var centerX = element.offsetLeft + element.offsetWidth / 2;
+    var centerY = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(centerX, centerY);
+}
+
+function dragFilesOntoInput(files)
+{
+    fileInput.value = ""; // Clear the <input>
+
+    eventSender.beginDragWithFilePromises(files);
+    moveMouseToCenterOfElement(fileInput);
+    eventSender.mouseUp();
+}
+
+function fileListShouldBe(fileListString, filesArray)
+{
+    shouldBe(fileListString + ".length", "" + filesArray.length);
+    for (var x = 0; x < filesArray.length; x++) {
+        var fileValueString = fileListString + "[" + x + "]";
+        shouldBeEqualToString(fileValueString + ".name", filesArray[x]['name']);
+        shouldBeEqualToString(fileValueString + ".type", filesArray[x]['type']);
+        shouldBe(fileValueString + ".size", "" + filesArray[x]['size']);
+    }
+}
+
+function filesShouldBe(filesArray)
+{
+    fileListShouldBe("fileInput.files", filesArray);
+}
+
+async function draggingPathsShouldResultInFiles(pathsArray, filesArray)
+{
+    const dropPromise = new Promise(resolve => fileInput._ondrop_ = () => window.setTimeout(resolve, 0));
+    const dragleavePromise = new Promise(resolve => fileInput._ondragleave_ = () => window.setTimeout(resolve, 0));
+    dragFilesOntoInput(pathsArray);
+    await Promise.race([dropPromise, dragleavePromise]);
+    shouldBeEqualToString("fileInput.value", filesArray[0] ? "C:\\fakepath\\" + filesArray[0]['name'] : '');
+    filesShouldBe(filesArray);
+}
+
+async function testDraggingFiles(filesArray)
+{
+    // We could make a way to parse the filename from the path, and then only need to pass
+    // the path in the filesArray.
+    var pathsOnly = filesArray.map(function(fileSpec) { return fileSpec['path']; });
+    await draggingPathsShouldResultInFiles(pathsOnly, filesArray);
+}
+
+async function runTest()
+{
+    debug("Dragging a real file to a file input control:");
+    await testDraggingFiles([
+        { 'path': 'resources/apple.gif', 'name' : 'apple.gif', 'size' : 1476, 'type' : 'image/gif' }
+    ]);
+
+    debug("Dragging two files to a single-file input control:")
+    await draggingPathsShouldResultInFiles(['resources/apple.gif', 'resources/mozilla.gif'], []);
+
+    fileInput.multiple = true;
+
+    debug("Dragging three files to a multi-file input control:");
+    await testDraggingFiles([
+        { 'path': 'resources/apple.gif', 'name' : 'apple 2.gif', 'size' : 1476, 'type' : 'image/gif' },
+        { 'path': 'resources/mozilla.gif', 'name' : 'mozilla.gif', 'size' : 2593, 'type' : 'image/gif' },
+    ]);
+
+    // Clean up after ourselves
+    fileInput.parentNode.removeChild(fileInput);
+
+    finishJSTest();
+}
+
+var successfullyParsed = true;
+
+if (window.eventSender) {
+    runTest();
+} else {
+    testFailed("This test is not interactive, please run using run-webkit-tests");
+}
+
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (229296 => 229297)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2018-03-06 01:36:31 UTC (rev 229297)
@@ -6,17 +6,24 @@
 #//////////////////////////////////////////////////////////////////////////////////////////
 
 fast/forms/attributed-strings.html [ Pass ]
-editing/pasteboard/drag-drop-href-as-url.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-custom.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-url.html [ Pass ]
 editing/pasteboard/data-transfer-is-unique-for-dragenter-and-dragleave.html [ Pass ]
+editing/pasteboard/data-transfer-items-drag-drop-file-promise.html [ Pass ]
+editing/pasteboard/data-transfer-items-drop-file.html [ Pass ]
+editing/pasteboard/data-transfer-items-drop-file-promise.html [ Pass ]
 editing/pasteboard/data-transfer-set-data-sanitize-html-when-dragging-in-null-origin.html [ Pass ]
 editing/pasteboard/data-transfer-set-data-sanitize-url-when-dragging-in-null-origin.html [ Pass ]
+editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Pass ]
+editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html [ Pass ]
+editing/pasteboard/datatransfer-types-dropping-text-file-promise.html [ Pass ]
+editing/pasteboard/drag-drop-href-as-url.html [ Pass ]
 editing/pasteboard/drag-end-crash-accessing-item-list.html [ Pass ]
-editing/pasteboard/data-transfer-item-list-add-file-on-drag.html [ Pass ]
-editing/pasteboard/data-transfer-items-drop-file.html [ Pass ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html [ Pass ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html [ Pass ]
+editing/pasteboard/file-input-files-access-promise.html [ Pass ]
 http/tests/security/clipboard/drag-drop-html-cross-origin-iframe-in-same-origin.html [ Pass ]
 
 #//////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/LayoutTests/platform/win/TestExpectations (229296 => 229297)


--- trunk/LayoutTests/platform/win/TestExpectations	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/LayoutTests/platform/win/TestExpectations	2018-03-06 01:36:31 UTC (rev 229297)
@@ -133,6 +133,13 @@
 
 # TODO Drag & Drop doesn't work correctly in DRT <rdar://5621244>
 editing/pasteboard/datatransfer-items-drop-plaintext-file.html
+editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html [ Skip ]
+editing/pasteboard/datatransfer-types-dropping-text-file-promise.html [ Skip ]
+editing/pasteboard/data-transfer-items-drag-drop-file-promise.html [ Skip ]
+editing/pasteboard/data-transfer-items-drop-file-promise.html [ Skip ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html [ Skip ]
+editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html [ Skip ]
+editing/pasteboard/file-input-files-access-promise.html [ Skip ]
 fast/events/drop-handler-should-not-stop-navigate.html [ Skip ]
 fast/events/drag-in-frames.html [ Skip ]
 fast/events/drag-to-navigate.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (229296 => 229297)


--- trunk/Source/WebCore/ChangeLog	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebCore/ChangeLog	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,50 @@
 2018-03-05  Andy Estes  <[email protected]>
 
+        [Mac] Teach WebCore::Pasteboard about file promise drags
+        https://bugs.webkit.org/show_bug.cgi?id=183314
+        <rdar://problem/38105493>
+
+        Reviewed by Darin Adler.
+
+        While WebKit does support receiving file promise drags (since r210360), WebCore::Pasteboard
+        has not been instructed on how to read their file paths. When the various pasteboard readers
+        ask for file paths after a file promise drop, they receive an empty vector. This impacts
+        various features, most notably the DataTransfer API.
+
+        Pasteboard actually cannot learn about promised file paths from the pasteboard itself, as
+        the pasteboard only contains the dragged files' UTIs. Promised file paths aren't known until
+        the WebKits call -[NSFilePromiseReceiver receivePromisedFilesAtDestination:...], at which
+        point the file paths are passed to WebCore as part of WebCore::DragData.
+
+        When we construct new Pasteboards for drag and drop, we need to store any promised file
+        paths from the DragData. Then, when the various pasteboard readers ask for file paths and
+        NSFilesPromisePboardType is on the pasteboard, we can return these promised file paths.
+
+        Tests: editing/pasteboard/data-transfer-items-drag-drop-file-promise.html
+               editing/pasteboard/data-transfer-items-drop-file-promise.html
+               editing/pasteboard/datatransfer-items-drop-plaintext-file-promise.html
+               editing/pasteboard/datatransfer-types-dropping-text-file-promise.html
+               editing/pasteboard/drag-file-promises-to-editable-element-as-URLs.html
+               editing/pasteboard/drag-file-promises-to-editable-element-as-attachment.html
+               editing/pasteboard/file-input-files-access-promise.html
+
+        * platform/FileSystem.h:
+        * platform/Pasteboard.h:
+        (WebCore::Pasteboard::Pasteboard):
+        * platform/mac/DragDataMac.mm:
+        (WebCore::DragData::containsPromise const):
+        * platform/mac/PasteboardMac.mm:
+        (WebCore::Pasteboard::Pasteboard):
+        (WebCore::Pasteboard::createForDragAndDrop):
+        (WebCore::toString):
+        (WebCore::Pasteboard::read):
+        (WebCore::Pasteboard::readFilePaths):
+        (WebCore::absoluteURLsFromPasteboardFilenames): Deleted.
+        * platform/mac/PlatformPasteboardMac.mm:
+        (WebCore::PlatformPasteboard::numberOfFiles const):
+
+2018-03-05  Andy Estes  <[email protected]>
+
         [Mac] Fix the build
 
         * Modules/applepay/ApplePaySession.cpp:

Modified: trunk/Source/WebCore/platform/Pasteboard.h (229296 => 229297)


--- trunk/Source/WebCore/platform/Pasteboard.h	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebCore/platform/Pasteboard.h	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -247,14 +247,17 @@
 
 #if PLATFORM(IOS)
     explicit Pasteboard(long changeCount);
+    explicit Pasteboard(const String& pasteboardName);
 
     static NSArray *supportedWebContentPasteboardTypes();
     static String resourceMIMEType(NSString *mimeType);
 #endif
 
+#if PLATFORM(MAC)
+    explicit Pasteboard(const String& pasteboardName, const Vector<String>& promisedFilePaths = { });
+#endif
+
 #if PLATFORM(COCOA)
-    explicit Pasteboard(const String& pasteboardName);
-
     static bool shouldTreatCocoaTypeAsFile(const String&);
     WEBCORE_EXPORT static NSArray *supportedFileUploadPasteboardTypes();
     const String& name() const { return m_pasteboardName; }
@@ -313,6 +316,10 @@
     std::optional<PasteboardCustomData> m_customDataCache;
 #endif
 
+#if PLATFORM(MAC)
+    Vector<String> m_promisedFilePaths;
+#endif
+
 #if PLATFORM(WIN)
     HWND m_owner;
     COMPtr<IDataObject> m_dataObject;

Modified: trunk/Source/WebCore/platform/mac/DragDataMac.mm (229296 => 229297)


--- trunk/Source/WebCore/platform/mac/DragDataMac.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebCore/platform/mac/DragDataMac.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -246,6 +246,8 @@
 
 bool DragData::containsPromise() const
 {
+    // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, why do we
+    // think promises should only contain one file (or UTI)?
     Vector<String> files;
 #if PLATFORM(MAC)
     platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(legacyFilesPromisePasteboardType()), m_pasteboardName);

Modified: trunk/Source/WebCore/platform/mac/PasteboardMac.mm (229296 => 229297)


--- trunk/Source/WebCore/platform/mac/PasteboardMac.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebCore/platform/mac/PasteboardMac.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -88,9 +88,10 @@
 {
 }
 
-Pasteboard::Pasteboard(const String& pasteboardName)
+Pasteboard::Pasteboard(const String& pasteboardName, const Vector<String>& promisedFilePaths)
     : m_pasteboardName(pasteboardName)
     , m_changeCount(platformStrategies()->pasteboardStrategy()->changeCount(m_pasteboardName))
+    , m_promisedFilePaths(promisedFilePaths)
 {
     ASSERT(pasteboardName);
 }
@@ -114,7 +115,7 @@
 
 std::unique_ptr<Pasteboard> Pasteboard::createForDragAndDrop(const DragData& dragData)
 {
-    return std::make_unique<Pasteboard>(dragData.pasteboardName());
+    return std::make_unique<Pasteboard>(dragData.pasteboardName(), dragData.fileNames());
 }
 #endif
 
@@ -275,6 +276,20 @@
 {
 }
 
+// FIXME: This should be a general utility function for Vectors of Strings (or things that can be
+// converted to Strings). It could also be faster by computing the total length and reserving that
+// capacity in the StringBuilder.
+static String joinPathnames(const Vector<String>& pathnames)
+{
+    StringBuilder builder;
+    for (auto& path : pathnames) {
+        if (!builder.isEmpty())
+            builder.append('\n');
+        builder.append(path);
+    }
+    return builder.toString();
+}
+
 void Pasteboard::read(PasteboardPlainText& text)
 {
     PasteboardStrategy& strategy = *platformStrategies()->pasteboardStrategy();
@@ -317,17 +332,17 @@
     if (types.contains(String(legacyFilenamesPasteboardType()))) {
         Vector<String> pathnames;
         strategy.getPathnamesForType(pathnames, legacyFilenamesPasteboardType(), m_pasteboardName);
-        StringBuilder builder;
-        for (size_t i = 0, size = pathnames.size(); i < size; i++) {
-            if (i)
-                builder.append('\n');
-            builder.append(pathnames[i]);
-        }
-        text.text = builder.toString();
+        text.text = joinPathnames(pathnames);
         text.isURL = false;
         return;
     }
 
+    if (types.contains(String(legacyFilesPromisePasteboardType()))) {
+        text.text = joinPathnames(m_promisedFilePaths);
+        text.isURL = false;
+        return;
+    }
+
     // FIXME: The code above looks at the types vector first, but this just gets the string without checking. Why the difference?
     text.text = strategy.stringForType(legacyURLPasteboardType(), m_pasteboardName);
     text.isURL = !text.text.isNull();
@@ -356,6 +371,11 @@
             return;
     }
 
+    if (policy == WebContentReadingPolicy::AnyType && types.contains(String(legacyFilesPromisePasteboardType()))) {
+        if (m_changeCount != changeCount() || reader.readFilePaths(m_promisedFilePaths))
+            return;
+    }
+
     if (types.contains(String(legacyHTMLPasteboardType()))) {
         String string = strategy.stringForType(legacyHTMLPasteboardType(), m_pasteboardName);
         if (m_changeCount != changeCount() || (!string.isNull() && reader.readHTML(string)))
@@ -463,23 +483,6 @@
     m_changeCount = platformStrategies()->pasteboardStrategy()->setStringForType(emptyString(), cocoaType, m_pasteboardName);
 }
 
-static Vector<String> absoluteURLsFromPasteboardFilenames(const String& pasteboardName, bool _onlyFirstURL_ = false)
-{
-    Vector<String> fileList;
-    platformStrategies()->pasteboardStrategy()->getPathnamesForType(fileList, String(legacyFilenamesPasteboardType()), pasteboardName);
-
-    if (fileList.isEmpty())
-        return fileList;
-
-    size_t count = onlyFirstURL ? 1 : fileList.size();
-    Vector<String> urls;
-    for (size_t i = 0; i < count; i++) {
-        NSURL *url = "" fileURLWithPath:fileList[i]];
-        urls.append(String([url absoluteString]));
-    }
-    return urls;
-}
-
 String Pasteboard::readPlatformValueAsString(const String& domType, long changeCount, const String& pasteboardName)
 {
     const String& cocoaType = cocoaTypeFromHTMLClipboardType(domType);
@@ -561,16 +564,21 @@
 
 Vector<String> Pasteboard::readFilePaths()
 {
-    // FIXME: Seems silly to convert paths to URLs and then back to paths. Does that do anything helpful?
-    Vector<String> absoluteURLs = absoluteURLsFromPasteboardFilenames(m_pasteboardName);
-    Vector<String> paths;
-    paths.reserveCapacity(absoluteURLs.size());
-    for (size_t i = 0; i < absoluteURLs.size(); i++) {
-        NSURL *absoluteURL = [NSURL URLWithString:absoluteURLs[i]];
-        ASSERT([absoluteURL isFileURL]);
-        paths.uncheckedAppend([absoluteURL path]);
+    auto& strategy = *platformStrategies()->pasteboardStrategy();
+
+    Vector<String> types;
+    strategy.getTypes(types, m_pasteboardName);
+
+    if (types.contains(String(legacyFilenamesPasteboardType()))) {
+        Vector<String> filePaths;
+        strategy.getPathnamesForType(filePaths, legacyFilenamesPasteboardType(), m_pasteboardName);
+        return filePaths;
     }
-    return paths;
+
+    if (types.contains(String(legacyFilesPromisePasteboardType())))
+        return m_promisedFilePaths;
+    
+    return { };
 }
 
 #if ENABLE(DRAG_SUPPORT)

Modified: trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm (229296 => 229297)


--- trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -65,6 +65,10 @@
 {
     Vector<String> files;
     getPathnamesForType(files, String(legacyFilenamesPasteboardType()));
+
+    // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, it's not
+    // guaranteed that the count of UTIs equals the count of files, since some clients only write
+    // unique UTIs.
     if (!files.size())
         getPathnamesForType(files, String(legacyFilesPromisePasteboardType()));
     return files.size();

Modified: trunk/Source/WebKit/ChangeLog (229296 => 229297)


--- trunk/Source/WebKit/ChangeLog	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebKit/ChangeLog	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,3 +1,16 @@
+2018-03-05  Andy Estes  <[email protected]>
+
+        [Mac] Teach WebCore::Pasteboard about file promise drags
+        https://bugs.webkit.org/show_bug.cgi?id=183314
+        <rdar://problem/38105493>
+
+        Reviewed by Darin Adler.
+
+        Added a FIXME comment.
+
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::performDragOperation):
+
 2018-03-05  Jeff Miller  <[email protected]>
 
         Expose still more WKPreferences SPI to match C SPI

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm (229296 => 229297)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -3711,6 +3711,10 @@
             fileNames.append(file);
         m_page->createSandboxExtensionsIfNeeded(fileNames, sandboxExtensionHandle, sandboxExtensionForUpload);
     } else if (![types containsObject:PasteboardTypes::WebArchivePboardType] && [types containsObject:WebCore::legacyFilesPromisePasteboardType()]) {
+        
+        // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, it's not
+        // guaranteed that the count of UTIs equals the count of files, since some clients only write
+        // unique UTIs.
         NSArray *files = [draggingInfo.draggingPasteboard propertyListForType:WebCore::legacyFilesPromisePasteboardType()];
         if (![files isKindOfClass:[NSArray class]]) {
             delete dragData;

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (229296 => 229297)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,3 +1,16 @@
+2018-03-05  Andy Estes  <[email protected]>
+
+        [Mac] Teach WebCore::Pasteboard about file promise drags
+        https://bugs.webkit.org/show_bug.cgi?id=183314
+        <rdar://problem/38105493>
+
+        Reviewed by Darin Adler.
+
+        Added a FIXME comment.
+
+        * WebView/WebView.mm:
+        (-[WebView performDragOperation:]):
+
 2018-03-04  Yusuke Suzuki  <[email protected]>
 
         [WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebView.mm (229296 => 229297)


--- trunk/Source/WebKitLegacy/mac/WebView/WebView.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebView.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -6715,6 +6715,10 @@
 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
     NSArray* types = draggingInfo.draggingPasteboard.types;
     if (![types containsObject:WebArchivePboardType] && ![types containsObject:legacyFilenamesPasteboardType()] && [types containsObject:legacyFilesPromisePasteboardType()]) {
+        
+        // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, it's not
+        // guaranteed that the count of UTIs equals the count of files, since some clients only write
+        // unique UTIs.
         NSArray *files = [draggingInfo.draggingPasteboard propertyListForType:legacyFilesPromisePasteboardType()];
         if (![files isKindOfClass:[NSArray class]]) {
             delete dragData;

Modified: trunk/Tools/ChangeLog (229296 => 229297)


--- trunk/Tools/ChangeLog	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/ChangeLog	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,3 +1,62 @@
+2018-03-05  Andy Estes  <[email protected]>
+
+        [Mac] Teach WebCore::Pasteboard about file promise drags
+        https://bugs.webkit.org/show_bug.cgi?id=183314
+        <rdar://problem/38105493>
+
+        Reviewed by Darin Adler.
+
+        * DumpRenderTree/DumpRenderTreeFileDraggingSource.h:
+        * DumpRenderTree/DumpRenderTreeFileDraggingSource.m:
+        (-[DumpRenderTreeFileDraggingSource initWithPromisedFileURLs:]):
+        (-[DumpRenderTreeFileDraggingSource dealloc]):
+
+        Taught DumpRenderTreeFileDraggingSource to store the promised file URLs.
+
+        * DumpRenderTree/mac/DumpRenderTree.mm:
+        (runTest):
+
+        Called +[DumpRenderTreeDraggingInfo clearAllFilePromiseReceivers] after running a test.
+
+        * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h:
+        * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm:
+        (-[DumpRenderTreeFilePromiseReceiver initWithPromisedUTIs:]):
+        (-[DumpRenderTreeFilePromiseReceiver fileTypes]):
+        (-[DumpRenderTreeFilePromiseReceiver fileNames]):
+        (-[DumpRenderTreeFilePromiseReceiver dealloc]):
+        (copyFile):
+        (-[DumpRenderTreeFilePromiseReceiver receivePromisedFilesAtDestination:options:operationQueue:reader:]):
+
+        We can't instantiate real NSFilePromiseReceivers in DumpRenderTree. They rely on the
+        pasteboard server to generate unique file URLs, which is incompatible with our swizzled
+        NSPasteboard.
+
+        Instead, create a subclass of NSFilePromiseReceiver that implements its own promise resolution.
+        -receivePromisedFilesAtDestination:... asks its DumpRenderTreeFileDraggingSource for the
+        array of file URLs, then copies each to the destination directory on the specified operation
+        queue. It emulates how NSPasteboard tries to find a unique destination name by appending
+        numbers to the file name.
+
+        All receivers are collected in a global array that is cleared when each test finishes.
+        DumpRenderTreeFilePromiseReceiver will delete the files it copied in -dealloc.
+
+        (+[DumpRenderTreeDraggingInfo clearAllFilePromiseReceivers]):
+        (-[DumpRenderTreeDraggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:]):
+        
+        If NSFilesPromisePboardType is on the pasteboard and classArray contains
+        NSFilePromiseReceiver, construct a DumpRenderTreeFilePromiseReceiver, add it to the array of
+        all file promise receivers, then wrap it in an NSDraggingItem and call block.
+
+        * DumpRenderTree/mac/EventSendingController.mm:
+        (+[EventSendingController isSelectorExcludedFromWebScript:]):
+        (+[EventSendingController webScriptNameForSelector:]):
+        (-[EventSendingController beginDragWithFilePromises:]):
+
+        Implement eventSender.beginDragWithFilePromises() by placing file UTIs on the pasteboard
+        with type NSFilesPromisePboardType, creating a DumpRenderTreeFileDraggingSource with the
+        file URLs, and creating a new DumpRenderTreeDraggingInfo and passing it to
+        -[WebView draggingEntered:].
+
 2018-03-05  Aakash Jain  <[email protected]>
 
         [webkitpy] Bugzilla class should use NetworkTransaction for network operations

Modified: trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h (229296 => 229297)


--- trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,4 +1,5 @@
 // Copyright (c) 2009, Google Inc. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
 // 
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -34,9 +35,12 @@
 // Used by -[EventSendingController beginDragWithFiles:]
 
 @interface DumpRenderTreeFileDraggingSource : NSObject {
+    NSArray<NSURL *> *_promisedFileURLs;
 }
 
+- (instancetype)initWithPromisedFileURLs:(NSArray<NSURL *> *)promisedFileURLs;
 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag;
+@property (nonatomic, readonly) NSArray<NSURL *> *promisedFileURLs;
 
 @end
 

Modified: trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m (229296 => 229297)


--- trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,4 +1,5 @@
 // Copyright (c) 2009, Google Inc. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
 // 
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
@@ -31,6 +32,24 @@
 
 @implementation DumpRenderTreeFileDraggingSource
 
+@synthesize promisedFileURLs=_promisedFileURLs;
+
+- (instancetype)initWithPromisedFileURLs:(NSArray<NSURL *> *)promisedFileURLs
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    _promisedFileURLs = [promisedFileURLs copy];
+    return self;
+}
+
+- (void)dealloc
+{
+    [_promisedFileURLs release];
+    [super dealloc];
+}
+
 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
 {
     return NSDragOperationCopy;

Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm (229296 => 229297)


--- trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  *           (C) 2007 Graham Dennis ([email protected])
  *
  * Redistribution and use in source and binary forms, with or without
@@ -2051,6 +2051,10 @@
     gTestRunner->cleanup();
     gTestRunner = nullptr;
 
+#if PLATFORM(MAC)
+    [DumpRenderTreeDraggingInfo clearAllFilePromiseReceivers];
+#endif
+
     if (ignoreWebCoreNodeLeaks)
         [WebCoreStatistics stopIgnoringWebCoreNodeLeaks];
 

Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h (229296 => 229297)


--- trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2006 Apple Inc.  All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,6 +51,8 @@
 
 - (void)slideDraggedImageTo:(NSPoint)screenPoint;
 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination;
+
++ (void)clearAllFilePromiseReceivers;
 @end
 
 #endif

Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm (229296 => 229297)


--- trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2006 Apple Inc.  All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,9 +32,114 @@
 #if !PLATFORM(IOS)
 
 #import "DumpRenderTree.h"
+#import "DumpRenderTreeFileDraggingSource.h"
+#import "DumpRenderTreePasteboard.h"
 #import "EventSendingController.h"
 #import <WebKit/WebKit.h>
+#import <wtf/RetainPtr.h>
 
+@interface NSDraggingItem ()
+- (void)setItem:(id)item;
+@end
+
+@interface DumpRenderTreeFilePromiseReceiver : NSFilePromiseReceiver {
+    RetainPtr<NSArray<NSString *>> _promisedUTIs;
+    RetainPtr<NSMutableArray<NSURL *>> _destinationURLs;
+    DumpRenderTreeFileDraggingSource *_draggingSource;
+}
+
+- (instancetype)initWithPromisedUTIs:(NSArray<NSString *> *)promisedUTIs;
+
+@property (nonatomic, retain) DumpRenderTreeFileDraggingSource *draggingSource;
+
+@end
+
+@implementation DumpRenderTreeFilePromiseReceiver
+
+@synthesize draggingSource=_draggingSource;
+
+- (instancetype)initWithPromisedUTIs:(NSArray<NSString *> *)promisedUTIs
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _promisedUTIs = adoptNS([promisedUTIs copy]);
+    _destinationURLs = adoptNS([NSMutableArray new]);
+    return self;
+}
+
+- (NSArray<NSString *> *)fileTypes
+{
+    return _promisedUTIs.get();
+}
+
+- (NSArray<NSString *> *)fileNames
+{
+    NSMutableArray *fileNames = [NSMutableArray arrayWithCapacity:[_destinationURLs count]];
+    for (NSURL *url in _destinationURLs.get())
+        [fileNames addObject:url.lastPathComponent];
+    return fileNames;
+}
+
+- (void)dealloc
+{
+    // WebKit does not delete promised files it receives into NSTemporaryDirectory() (it should!),
+    // so we need to. Failing to do so could result in unpredictable file names in a subsequent test
+    // that promises a file with the same name as one of these destination URLs.
+
+    for (NSURL *destinationURL in _destinationURLs.get()) {
+        assert([destinationURL.path hasPrefix:NSTemporaryDirectory()]);
+        [NSFileManager.defaultManager removeItemAtURL:destinationURL error:nil];
+    }
+
+    [_draggingSource release];
+    [super dealloc];
+}
+
+static NSURL *copyFile(NSURL *sourceURL, NSURL *destinationDirectory, NSError *&error)
+{
+    // Emulate how CFPasteboard finds unique destination file names by inserting " 2", " 3", and so
+    // on between the file name's base and extension until a new file is successfully created in
+    // the destination directory.
+
+    NSUInteger number = 2;
+    NSString *fileName = sourceURL.lastPathComponent;
+    NSURL *destinationURL = [NSURL fileURLWithPath:fileName relativeToURL:destinationDirectory];
+    while (![NSFileManager.defaultManager copyItemAtURL:sourceURL toURL:destinationURL error:&error]) {
+        if (error.domain != NSCocoaErrorDomain || error.code != NSFileWriteFileExistsError)
+            return nil;
+
+        NSString *newFileName = [NSString stringWithFormat:@"%@ %lu.%@", fileName.stringByDeletingPathExtension, (unsigned long)number++, fileName.pathExtension];
+        destinationURL = [NSURL fileURLWithPath:newFileName relativeToURL:destinationDirectory];
+        error = nil;
+    }
+
+    return destinationURL;
+}
+
+- (void)receivePromisedFilesAtDestination:(NSURL *)destinationDirectory options:(NSDictionary *)options operationQueue:(NSOperationQueue *)operationQueue reader:(void (^)(NSURL *fileURL, NSError * __nullable errorOrNil))reader
+{
+    // Layout tests need files to be received in a predictable order, so execute operations in serial.
+    operationQueue.maxConcurrentOperationCount = 1;
+
+    NSArray<NSURL *> *sourceURLs = _draggingSource.promisedFileURLs;
+    for (NSURL *sourceURL in sourceURLs) {
+        [operationQueue addOperationWithBlock:^{
+            NSError *error = nil;
+            NSURL *destinationURL = copyFile(sourceURL, destinationDirectory, error);
+            if (destinationURL) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    [_destinationURLs addObject:destinationURL];
+                });
+            }
+
+            reader(destinationURL, error);
+        }];
+    }
+}
+
+@end
+
 @implementation DumpRenderTreeDraggingInfo
 
 - (id)initWithImage:(NSImage *)anImage offset:(NSSize)o pasteboard:(NSPasteboard *)pboard source:(id)source
@@ -137,11 +242,49 @@
     // Ignored.
 }
 
-- (void)enumerateDraggingItemsWithOptions:(NSEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block
+static NSMutableArray<NSFilePromiseReceiver *> *allFilePromiseReceivers()
 {
-    // Ignored.
+    static NSMutableArray<NSFilePromiseReceiver *> *allReceivers = [[NSMutableArray alloc] init];
+    return allReceivers;
 }
 
++ (void)clearAllFilePromiseReceivers
+{
+    [allFilePromiseReceivers() removeAllObjects];
+}
+
+- (void)enumerateDraggingItemsWithOptions:(NSEnumerationOptions)enumOptions forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block
+{
+    assert(!enumOptions);
+    assert(!searchOptions.count);
+
+    BOOL stop = NO;
+    for (Class classObject in classArray) {
+        if (classObject != NSFilePromiseReceiver.class)
+            continue;
+
+        id promisedUTIs = [draggingPasteboard propertyListForType:NSFilesPromisePboardType];
+        if (![promisedUTIs isKindOfClass:NSArray.class])
+            return;
+
+        for (id object in promisedUTIs) {
+            if (![object isKindOfClass:NSString.class])
+                return;
+        }
+
+        auto receiver = adoptNS([[DumpRenderTreeFilePromiseReceiver alloc] initWithPromisedUTIs:promisedUTIs]);
+        [receiver setDraggingSource:draggingSource];
+        [allFilePromiseReceivers() addObject:receiver.get()];
+
+        auto item = adoptNS([NSDraggingItem new]);
+        [item setItem:receiver.get()];
+
+        block(item.get(), 0, &stop);
+        if (stop)
+            return;
+    }
+}
+
 -(NSSpringLoadingHighlight)springLoadingHighlight
 {
     return NSSpringLoadingHighlightNone;

Modified: trunk/Tools/DumpRenderTree/mac/EventSendingController.mm (229296 => 229297)


--- trunk/Tools/DumpRenderTree/mac/EventSendingController.mm	2018-03-06 01:30:37 UTC (rev 229296)
+++ trunk/Tools/DumpRenderTree/mac/EventSendingController.mm	2018-03-06 01:36:31 UTC (rev 229297)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2006, 2007, 2008, 2014-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2005-2018 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Jonas Witt <[email protected]>
  * Copyright (C) 2006 Samuel Weinig <[email protected]>
  * Copyright (C) 2006 Alexey Proskuryakov <[email protected]>
@@ -35,11 +35,13 @@
 #import "DumpRenderTree.h"
 #import "DumpRenderTreeDraggingInfo.h"
 #import "DumpRenderTreeFileDraggingSource.h"
+#import "DumpRenderTreePasteboard.h"
 #import "WebCoreTestSupport.h"
 #import <WebKit/DOMPrivate.h>
 #import <WebKit/WebKit.h>
 #import <WebKit/WebViewPrivate.h>
 #import <functional>
+#import <wtf/RetainPtr.h>
 
 #if !PLATFORM(IOS)
 #import <Carbon/Carbon.h> // for GetCurrentEventTime()
@@ -255,6 +257,7 @@
             || aSelector == @selector(callAfterScrollingCompletes:)
 #if PLATFORM(MAC)
             || aSelector == @selector(beginDragWithFiles:)
+            || aSelector == @selector(beginDragWithFilePromises:)
 #endif
 #if PLATFORM(IOS)
             || aSelector == @selector(addTouchAtX:y:)
@@ -286,6 +289,8 @@
 #if PLATFORM(MAC)
     if (aSelector == @selector(beginDragWithFiles:))
         return @"beginDragWithFiles";
+    if (aSelector == @selector(beginDragWithFilePromises:))
+        return @"beginDragWithFilePromises";
 #endif
     if (aSelector == @selector(contextClick))
         return @"contextClick";
@@ -458,6 +463,43 @@
     dragMode = NO; // dragMode saves events and then replays them later.  We don't need/want that.
     leftMouseButtonDown = YES; // Make the rest of eventSender think a drag is in progress
 }
+
+- (void)beginDragWithFilePromises:(WebScriptObject *)filePaths
+{
+    assert(!draggingInfo);
+
+    NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
+    [pasteboard declareTypes:@[NSFilesPromisePboardType] owner:nil];
+
+    NSURL *currentTestURL = [NSURL URLWithString:mainFrame.webView.mainFrameURL];
+
+    size_t i = 0;
+    NSMutableArray *fileURLs = [NSMutableArray array];
+    NSMutableArray *fileUTIs = [NSMutableArray array];
+    while (true) {
+        id filePath = [filePaths webScriptValueAtIndex:i++];
+        if (![filePath isKindOfClass:NSString.class])
+            break;
+
+        NSURL *fileURL = [NSURL fileURLWithPath:(NSString *)filePath relativeToURL:currentTestURL];
+        [fileURLs addObject:fileURL];
+
+        NSString *fileUTI;
+        if (![fileURL getResourceValue:&fileUTI forKey:NSURLTypeIdentifierKey error:nil])
+            break;
+        [fileUTIs addObject:fileUTI];
+    }
+
+    [pasteboard setPropertyList:fileUTIs forType:NSFilesPromisePboardType];
+    assert([pasteboard propertyListForType:NSFilesPromisePboardType]);
+
+    auto source = adoptNS([[DumpRenderTreeFileDraggingSource alloc] initWithPromisedFileURLs:fileURLs]);
+    draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:nil offset:NSZeroSize pasteboard:pasteboard source:source.get()];
+    [mainFrame.webView draggingEntered:draggingInfo];
+
+    dragMode = NO;
+    leftMouseButtonDown = YES;
+}
 #endif // !PLATFORM(IOS)
 
 - (void)updateClickCountForButton:(int)buttonNumber
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to