[Clipboard API] Add support for Clipboard.readText()
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Nov 2019 15:26:13 +0000 (15:26 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Nov 2019 15:26:13 +0000 (15:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204310
<rdar://problem/57292754>

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Rebaseline a couple of imported web platform tests.

* web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt:
* web-platform-tests/clipboard-apis/async-write-text-read-text-manual.https-expected.txt:

Source/WebCore:

Implements readText; see below for more detail.

Tests: editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html
       editing/async-clipboard/clipboard-read-text-from-platform.html
       editing/async-clipboard/clipboard-read-text-same-origin.html
       editing/async-clipboard/clipboard-read-text.html

* Modules/async-clipboard/Clipboard.cpp:
(WebCore::Clipboard::readText):

Implement the method. This works similarly to Clipboard::read, but immediately reads text data for the first
clipboard item with data for "text/plain", instead of exposing a list of clipboard items.

* dom/DataTransfer.cpp:
(WebCore::DataTransfer::commitToPasteboard):

If the custom pasteboard data object is empty, then don't bother trying to write it to the platform pasteboard.
This avoids hitting an assertion in WebDragClient::beginDrag that checks to make sure there's no data on the
pasteboard right before beginning a drag in the UI process which was getting hit because we'd otherwise end up
writing just the pasteboard data origin; it also has an added bonus of avoiding an unnecessary sync IPC message.

* platform/mac/PlatformPasteboardMac.mm:
(WebCore::PlatformPasteboard::write):

Write the custom data type ("com.apple.WebKit.custom-pasteboard-data") when writing PasteboardCustomData to the
pasteboard on macOS, even when the custom pasteboard data only contains an origin. This allows DOM paste
requests to automatically accept when exchanging text data between the same origin via the async clipboard API.

LayoutTests:

Add several new layout tests.

* editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes-expected.txt: Added.
* editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html: Added.

Add a test to verify that if the clipboard changes content in the middle of a call to clipboard.readText, we
will reject the readText() promise and avoid exposing any text to the page.

* editing/async-clipboard/clipboard-read-text-expected.txt: Added.
* editing/async-clipboard/clipboard-read-text-from-platform-expected.txt: Added.
* editing/async-clipboard/clipboard-read-text-from-platform.html: Added.

Add a test to verify that we display DOM paste UI when reading text that was written to the pasteboard directly
via platform API.

* editing/async-clipboard/clipboard-read-text-same-origin-expected.txt: Added.
* editing/async-clipboard/clipboard-read-text-same-origin.html: Added.

Add a test to verify that we allow the page to access same origin text data on the pasteboard using readText,
during a user gesture.

* editing/async-clipboard/clipboard-read-text.html: Added.

Add a basic test to verify that readText works when the page writes text to the clipboard using DataTransfer and
document.execCommand.

* platform/gtk/TestExpectations:
* platform/mac-wk1/TestExpectations:
* platform/win/TestExpectations:
* platform/wpe/TestExpectations:

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes-expected.txt [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text-expected.txt [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform-expected.txt [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform.html [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin-expected.txt [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin.html [new file with mode: 0644]
LayoutTests/editing/async-clipboard/clipboard-read-text.html [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-write-text-read-text-manual.https-expected.txt
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/platform/win/TestExpectations
LayoutTests/platform/wpe/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/async-clipboard/Clipboard.cpp
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/platform/mac/PlatformPasteboardMac.mm

index ce6be1c..909cc3e 100644 (file)
@@ -1,3 +1,42 @@
+2019-11-19  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Add support for Clipboard.readText()
+        https://bugs.webkit.org/show_bug.cgi?id=204310
+        <rdar://problem/57292754>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add several new layout tests.
+
+        * editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes-expected.txt: Added.
+        * editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html: Added.
+
+        Add a test to verify that if the clipboard changes content in the middle of a call to clipboard.readText, we
+        will reject the readText() promise and avoid exposing any text to the page.
+
+        * editing/async-clipboard/clipboard-read-text-expected.txt: Added.
+        * editing/async-clipboard/clipboard-read-text-from-platform-expected.txt: Added.
+        * editing/async-clipboard/clipboard-read-text-from-platform.html: Added.
+
+        Add a test to verify that we display DOM paste UI when reading text that was written to the pasteboard directly
+        via platform API.
+
+        * editing/async-clipboard/clipboard-read-text-same-origin-expected.txt: Added.
+        * editing/async-clipboard/clipboard-read-text-same-origin.html: Added.
+
+        Add a test to verify that we allow the page to access same origin text data on the pasteboard using readText,
+        during a user gesture.
+
+        * editing/async-clipboard/clipboard-read-text.html: Added.
+
+        Add a basic test to verify that readText works when the page writes text to the clipboard using DataTransfer and
+        document.execCommand.
+
+        * platform/gtk/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+        * platform/win/TestExpectations:
+        * platform/wpe/TestExpectations:
+
 2019-11-18  John Wilander  <wilander@apple.com>
 
         Check if ITP is on before applying third-party cookie blocking
diff --git a/LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes-expected.txt b/LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes-expected.txt
new file mode 100644 (file)
index 0000000..ec85daa
--- /dev/null
@@ -0,0 +1,10 @@
+This test verifies that navigator.clipboard.readText rejects if the contents of the platform pasteboard change while reading. This test requires WebKitTestRunner.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Failed to read with exception: NotAllowedError
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html b/LayoutTests/editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html
new file mode 100644 (file)
index 0000000..f96f8cb
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true experimental:AsyncClipboardAPIEnabled=true domPasteAllowed=false ] -->
+<html>
+    <meta charset="utf8">
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+        <script src="../../resources/js-test.js"></script>
+        <script src="../../resources/ui-helper.js"></script>
+        <script src="./resources/async-clipboard-helpers.js"></script>
+        <style>
+            button, iframe {
+                width: 100%;
+                height: 150px;
+                display: block;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+
+        if (window.testRunner)
+            testRunner.setJavaScriptCanAccessClipboard(false);
+
+        async function runTest() {
+            description("This test verifies that navigator.clipboard.readText rejects if the contents of the platform pasteboard change while reading. This test requires WebKitTestRunner.");
+
+            paste = document.getElementById("paste");
+            paste.addEventListener("click", async () => {
+                try {
+                    testFailed(`Should not have been able to read ${await navigator.clipboard.readText()}`);
+                } catch (exception) {
+                    testPassed(`Failed to read with exception: ${exception.name}`);
+                } finally {
+                    paste.remove();
+                    finishJSTest();
+                }
+            });
+
+            await UIHelper.copyText("I should not be able to read this text.");
+            await triggerProgrammaticPaste(paste, ["ChangePasteboardWhenGrantingAccess"]);
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <button id="paste">Paste</button>
+        <p id="description"></p>
+        <p id="console"></p>
+    </body>
+</html>
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text-expected.txt b/LayoutTests/editing/async-clipboard/clipboard-read-text-expected.txt
new file mode 100644 (file)
index 0000000..4458343
--- /dev/null
@@ -0,0 +1,13 @@
+This test verifies that navigator.clipboard.readText can be used to read plain text from the system clipboard. To verify manually, click the 'Copy' button to copy text to the clipboard, and then click the 'Paste' button to read back the text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Copied text to clipboard using DataTransfer.
+PASS finishedCopying became true
+PASS Read text from clipboard using navigator.clipboard.readText.
+PASS clipboardText is "garply"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform-expected.txt b/LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform-expected.txt
new file mode 100644 (file)
index 0000000..63c3e20
--- /dev/null
@@ -0,0 +1,11 @@
+This test verifies that navigator.clipboard.readText causes DOM paste UI to appear, if the text was written using platform API. To run the test manually, copy text from elsewhere on the system, and then click 'Paste'; DOM paste UI should appear when clicking 'Paste', and pasting should allow the page to read the text that was copied.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Read text from clipboard using navigator.clipboard.readText.
+PASS clipboardText is "This text was written by the platform."
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform.html b/LayoutTests/editing/async-clipboard/clipboard-read-text-from-platform.html
new file mode 100644 (file)
index 0000000..1bb0e6d
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true experimental:AsyncClipboardAPIEnabled=true domPasteAllowed=false ] -->
+<html>
+    <meta charset="utf8">
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+        <script src="../../resources/js-test.js"></script>
+        <script src="../../resources/ui-helper.js"></script>
+        <script src="./resources/async-clipboard-helpers.js"></script>
+        <style>
+            button, iframe {
+                width: 100%;
+                height: 150px;
+                display: block;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+        shouldCheckString = true;
+
+        if (window.testRunner)
+            testRunner.setJavaScriptCanAccessClipboard(false);
+
+        async function runTest() {
+            description("This test verifies that navigator.clipboard.readText causes DOM paste UI to appear, if the text was written using platform API. To run the test manually, copy text from elsewhere on the system, and then click 'Paste'; DOM paste UI should appear when clicking 'Paste', and pasting should allow the page to read the text that was copied.");
+
+            paste = document.getElementById("paste");
+            paste.addEventListener("click", async () => {
+                try {
+                    clipboardText = await navigator.clipboard.readText();
+                    testPassed("Read text from clipboard using navigator.clipboard.readText.");
+                    if (shouldCheckString)
+                        shouldBeEqualToString("clipboardText", "This text was written by the platform.");
+                } catch (exception) {
+                    testFailed(`Failed to read with exception: ${exception.name}`);
+                } finally {
+                    paste.remove();
+                    finishJSTest();
+                }
+            });
+
+            if (!window.testRunner) {
+                shouldCheckString = false;
+                return;
+            }
+
+            await UIHelper.copyText("This text was written by the platform.");
+            await triggerProgrammaticPaste(paste);
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <button id="paste">Paste</button>
+        <p id="description"></p>
+        <p id="console"></p>
+    </body>
+</html>
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin-expected.txt b/LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin-expected.txt
new file mode 100644 (file)
index 0000000..4be86cc
--- /dev/null
@@ -0,0 +1,12 @@
+This test verifies that navigator.clipboard.readText can be used to read text from the clipboard without showing DOM paste UI for same-origin data. To run the test manually, click 'Copy' and then click 'Paste'. DOM paste UI should not appear.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS finishedCopying became true
+PASS Read text from clipboard using navigator.clipboard.readText.
+PASS clipboardText is "This text was copied."
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin.html b/LayoutTests/editing/async-clipboard/clipboard-read-text-same-origin.html
new file mode 100644 (file)
index 0000000..004a76a
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true experimental:AsyncClipboardAPIEnabled=true domPasteAllowed=false ] -->
+<html>
+    <meta charset="utf8">
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+        <script src="../../resources/js-test.js"></script>
+        <script src="../../resources/ui-helper.js"></script>
+        <script src="./resources/async-clipboard-helpers.js"></script>
+        <style>
+            button, iframe {
+                width: 100%;
+                height: 150px;
+                display: block;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+        finishedCopying = false;
+
+        if (window.testRunner)
+            testRunner.setJavaScriptCanAccessClipboard(false);
+
+        async function runTest() {
+            description("This test verifies that navigator.clipboard.readText can be used to read text from the clipboard without showing DOM paste UI for same-origin data. To run the test manually, click 'Copy' and then click 'Paste'. DOM paste UI should not appear.");
+
+            addEventListener("message", event => finishedCopying = event.data === "finished-copying");
+
+            subframe = document.querySelector("iframe");
+            paste = document.getElementById("paste");
+            paste.addEventListener("click", async () => {
+                clipboardText = await navigator.clipboard.readText();
+                testPassed("Read text from clipboard using navigator.clipboard.readText.");
+                shouldBeEqualToString("clipboardText", "This text was copied.");
+                paste.remove();
+                subframe.remove();
+                finishJSTest();
+            });
+
+            if (!window.testRunner)
+                return;
+
+            await UIHelper.activateElement(subframe);
+            await new Promise(r => shouldBecomeEqual("finishedCopying", "true", r));
+            await UIHelper.activateElement(paste);
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <iframe srcdoc="
+            <body>
+                <button style='width: 100%; height: 134px;'>Copy</button>
+                <script>
+                    const button = document.querySelector('button');
+                    const textToCopy = document.getElementById('textToCopy');
+                    button.addEventListener('click', async () => {
+                        await navigator.clipboard.writeText('This text was copied.');
+                        parent.postMessage('finished-copying', '*');
+                    });
+                </script>
+            </body>
+        "></iframe>
+        <button id="paste">Paste</button>
+        <p id="description"></p>
+        <p id="console"></p>
+    </body>
+</html>
diff --git a/LayoutTests/editing/async-clipboard/clipboard-read-text.html b/LayoutTests/editing/async-clipboard/clipboard-read-text.html
new file mode 100644 (file)
index 0000000..9e1c7d1
--- /dev/null
@@ -0,0 +1,63 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true experimental:AsyncClipboardAPIEnabled=true ] -->
+<html>
+    <meta charset="utf8">
+    <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+        <script src="../../resources/js-test.js"></script>
+        <script src="../../resources/ui-helper.js"></script>
+        <script src="./resources/async-clipboard-helpers.js"></script>
+        <style>
+            button {
+                width: 100%;
+                height: 150px;
+                display: block;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+        finishedCopying = false;
+
+        async function runTest() {
+            description("This test verifies that navigator.clipboard.readText can be used to read plain text from the system clipboard. To verify manually, click the 'Copy' button to copy text to the clipboard, and then click the 'Paste' button to read back the text.");
+
+            copy = document.getElementById("copy");
+            paste = document.getElementById("paste");
+
+            copy.addEventListener("click", () => {
+                writeToClipboardUsingDataTransfer({ "text/plain" : "garply" });
+                testPassed("Copied text to clipboard using DataTransfer.");
+                finishedCopying = true;
+            });
+
+            paste.addEventListener("click", async () => {
+                try {
+                    clipboardText = await navigator.clipboard.readText();
+                    testPassed("Read text from clipboard using navigator.clipboard.readText.");
+                } catch (exception) {
+                    testFailed("Could not read text from clipboard.");
+                } finally {
+                    shouldBeEqualToString("clipboardText", "garply");
+                    copy.remove();
+                    paste.remove();
+                    finishJSTest();
+                }
+            });
+
+            if (!window.testRunner)
+                return;
+
+            await UIHelper.activateElement(copy);
+            await new Promise(r => shouldBecomeEqual("finishedCopying", "true", r));
+            await UIHelper.activateElement(paste);
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <button id="copy">Copy</button>
+        <button id="paste">Paste</button>
+        <p id="description"></p>
+        <p id="console"></p>
+    </body>
+</html>
index 2aa5559..66ea9ea 100644 (file)
@@ -1,3 +1,16 @@
+2019-11-19  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Add support for Clipboard.readText()
+        https://bugs.webkit.org/show_bug.cgi?id=204310
+        <rdar://problem/57292754>
+
+        Reviewed by Ryosuke Niwa.
+
+        Rebaseline a couple of imported web platform tests.
+
+        * web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt:
+        * web-platform-tests/clipboard-apis/async-write-text-read-text-manual.https-expected.txt:
+
 2019-11-18  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Fix getTotalLength() and getPointAtLength() for optimized rect and ellipse renderers
index 09d339a..ba94822 100644 (file)
@@ -7,5 +7,5 @@ PASS navigator.clipboard.write(DOMString) fails (expect DataTransfer)
 PASS navigator.clipboard.writeText(DOMString) succeeds 
 PASS navigator.clipboard.writeText() fails (expect DOMString) 
 FAIL navigator.clipboard.read() succeeds assert_true: expected true got false
-FAIL navigator.clipboard.readText() succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+PASS navigator.clipboard.readText() succeeds 
 
index 1bd996f..89e4774 100644 (file)
@@ -1,6 +1,4 @@
 Note: This is a manual test because it writes/reads to the shared system clipboard and thus cannot be run async with other tests that might interact with the clipboard.
 
-Harness Error (TIMEOUT), message = null
-
-TIMEOUT Verify write and read clipboard (DOMString) Test timed out
+PASS Verify write and read clipboard (DOMString) 
 
index 445d244..123ccb1 100644 (file)
@@ -1295,6 +1295,8 @@ webkit.org/b/203078 imported/w3c/web-platform-tests/media-source/mediasource-red
 webkit.org/b/204112 editing/async-clipboard/clipboard-change-data-while-getting-type.html [ Crash ]
 webkit.org/b/204112 editing/async-clipboard/clipboard-change-data-while-reading.html [ Crash ]
 webkit.org/b/204112 editing/async-clipboard/clipboard-get-type-with-old-items.html [ Crash ]
+webkit.org/b/204112 editing/async-clipboard/clipboard-read-text-from-platform.html [ Crash ]
+webkit.org/b/204112 editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html [ Crash ]
 
 #////////////////////////////////////////////////////////////////////////////////////////
 # End of Crashing tests
index a280050..efa6eb2 100644 (file)
@@ -69,6 +69,9 @@ imported/w3c/web-platform-tests/html/semantics/forms/the-datalist-element [ Wont
 
 # DOM paste access requests are not implemented in WebKit1.
 editing/async-clipboard/clipboard-change-data-while-reading.html [ Skip ]
+editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html [ Skip ]
+editing/async-clipboard/clipboard-read-text-from-platform.html [ Skip ]
+editing/async-clipboard/clipboard-read-text-same-origin.html [ Skip ]
 
 imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.html [ Pass Failure ]
 imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.worker.html [ Pass Failure ]
index 47b50fd..eedb2c7 100644 (file)
@@ -1194,6 +1194,10 @@ webkit.org/b/203100 editing/async-clipboard/clipboard-change-data-while-writing.
 webkit.org/b/203100 editing/async-clipboard/clipboard-write-basic.html [ Skip ]
 webkit.org/b/203100 editing/async-clipboard/clipboard-write-items-twice.html [ Skip ]
 webkit.org/b/203100 editing/async-clipboard/clipboard-write-text.html [ Skip ]
+webkit.org/b/203100 editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html [ Skip ]
+webkit.org/b/203100 editing/async-clipboard/clipboard-read-text-from-platform.html [ Skip ]
+webkit.org/b/203100 editing/async-clipboard/clipboard-read-text-same-origin.html [ Skip ]
+webkit.org/b/203100 editing/async-clipboard/clipboard-read-text.html [ Skip ]
 
 webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ]
 webkit.org/b/140783 [ Debug ] editing/pasteboard/copy-standalone-image.html [ Skip ] # Debug Assertion
index 799953b..c532f96 100644 (file)
@@ -789,6 +789,8 @@ webkit.org/b/200534 fast/events/focus-anchor-with-tabindex-hang.html [ Crash ]
 webkit.org/b/204112 editing/async-clipboard/clipboard-change-data-while-getting-type.html [ Crash ]
 webkit.org/b/204112 editing/async-clipboard/clipboard-change-data-while-reading.html [ Crash ]
 webkit.org/b/204112 editing/async-clipboard/clipboard-get-type-with-old-items.html [ Crash ]
+webkit.org/b/204112 editing/async-clipboard/clipboard-read-text-from-platform.html [ Crash ]
+webkit.org/b/204112 editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html [ Crash ]
 
 #////////////////////////////////////////////////////////////////////////////////////////
 # 6. FLAKY TESTS
index b3d2eec..424f0e4 100644 (file)
@@ -1,3 +1,39 @@
+2019-11-19  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Add support for Clipboard.readText()
+        https://bugs.webkit.org/show_bug.cgi?id=204310
+        <rdar://problem/57292754>
+
+        Reviewed by Ryosuke Niwa.
+
+        Implements readText; see below for more detail.
+
+        Tests: editing/async-clipboard/clipboard-do-not-read-text-from-platform-if-text-changes.html
+               editing/async-clipboard/clipboard-read-text-from-platform.html
+               editing/async-clipboard/clipboard-read-text-same-origin.html
+               editing/async-clipboard/clipboard-read-text.html
+
+        * Modules/async-clipboard/Clipboard.cpp:
+        (WebCore::Clipboard::readText):
+
+        Implement the method. This works similarly to Clipboard::read, but immediately reads text data for the first
+        clipboard item with data for "text/plain", instead of exposing a list of clipboard items.
+
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::commitToPasteboard):
+
+        If the custom pasteboard data object is empty, then don't bother trying to write it to the platform pasteboard.
+        This avoids hitting an assertion in WebDragClient::beginDrag that checks to make sure there's no data on the
+        pasteboard right before beginning a drag in the UI process which was getting hit because we'd otherwise end up
+        writing just the pasteboard data origin; it also has an added bonus of avoiding an unnecessary sync IPC message.
+
+        * platform/mac/PlatformPasteboardMac.mm:
+        (WebCore::PlatformPasteboard::write):
+
+        Write the custom data type ("com.apple.WebKit.custom-pasteboard-data") when writing PasteboardCustomData to the
+        pasteboard on macOS, even when the custom pasteboard data only contains an origin. This allows DOM paste
+        requests to automatically accept when exchanging text data between the same origin via the async clipboard API.
+
 2019-11-19  Chris Dumez  <cdumez@apple.com>
 
         http/tests/navigation/page-cache-mediastream.html is a flaky crash
index 61d0db3..b5fc1c0 100644 (file)
@@ -97,7 +97,39 @@ ScriptExecutionContext* Clipboard::scriptExecutionContext() const
 
 void Clipboard::readText(Ref<DeferredPromise>&& promise)
 {
-    promise->reject(NotSupportedError);
+    auto frame = makeRefPtr(this->frame());
+    if (!frame) {
+        promise->reject(NotAllowedError);
+        return;
+    }
+
+    auto pasteboard = Pasteboard::createForCopyAndPaste();
+    auto changeCountAtStart = pasteboard->changeCount();
+    if (!frame->requestDOMPasteAccess()) {
+        promise->reject(NotAllowedError);
+        return;
+    }
+
+    auto allInfo = pasteboard->allPasteboardItemInfo();
+    if (!allInfo) {
+        promise->reject(NotAllowedError);
+        return;
+    }
+
+    String text;
+    for (size_t index = 0; index < allInfo->size(); ++index) {
+        if (allInfo->at(index).webSafeTypesByFidelity.contains("text/plain"_s)) {
+            PasteboardPlainText plainTextReader;
+            pasteboard->read(plainTextReader, PlainTextURLReadingPolicy::IgnoreURL, index);
+            text = WTFMove(plainTextReader.text);
+            break;
+        }
+    }
+
+    if (changeCountAtStart == pasteboard->changeCount())
+        promise->resolve<IDLDOMString>(WTFMove(text));
+    else
+        promise->reject(NotAllowedError);
 }
 
 void Clipboard::writeText(const String& data, Ref<DeferredPromise>&& promise)
index 521fa41..0954835 100644 (file)
@@ -425,6 +425,9 @@ void DataTransfer::commitToPasteboard(Pasteboard& nativePasteboard)
 {
     ASSERT(is<StaticPasteboard>(*m_pasteboard) && !is<StaticPasteboard>(nativePasteboard));
     PasteboardCustomData customData = downcast<StaticPasteboard>(*m_pasteboard).takeCustomData();
+    if (!customData.hasData())
+        return;
+
     if (RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
         customData.setOrigin(m_originIdentifier);
         nativePasteboard.writeCustomData({ customData });
index 31a2f7c..cc53655 100644 (file)
@@ -231,8 +231,8 @@ int64_t PlatformPasteboard::write(const PasteboardCustomData& data)
             [types addObject:platformType];
     });
 
-    bool hasSameOriginCustomData = data.hasSameOriginCustomData();
-    if (hasSameOriginCustomData)
+    bool shouldWriteCustomData = data.hasSameOriginCustomData() || !data.origin().isEmpty();
+    if (shouldWriteCustomData)
         [types addObject:@(PasteboardCustomData::cocoaType())];
 
     [m_pasteboard declareTypes:types owner:nil];
@@ -244,7 +244,7 @@ int64_t PlatformPasteboard::write(const PasteboardCustomData& data)
             [m_pasteboard setString:data forType:platformType];
     });
 
-    if (hasSameOriginCustomData) {
+    if (shouldWriteCustomData) {
         if (auto serializedCustomData = data.createSharedBuffer()->createNSData())
             [m_pasteboard setData:serializedCustomData.get() forType:@(PasteboardCustomData::cocoaType())];
     }