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