Title: [251279] trunk
Revision
251279
Author
wenson_hs...@apple.com
Date
2019-10-18 07:24:07 -0700 (Fri, 18 Oct 2019)

Log Message

[Clipboard API] Support navigator.clipboard.read()
https://bugs.webkit.org/show_bug.cgi?id=203021

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Rebaseline a web platform test, now that Clipboard.read() no longer immediately rejects.

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

Source/WebCore:

Add support for navigator.clipboard.read(), which returns a promise that resolves to a list of ClipboardItems.
See below for more details.

Tests: editing/async-clipboard/clipboard-change-data-while-reading.html
       editing/async-clipboard/clipboard-read-basic.html

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

Implement read(). This makes two calls to the platform pasteboard: the first to get the current change count,
and if the change count is different from the changeCount used for the last read() call (or there are no
existing clipboard items being tracked), then we request pasteboard item information for all items on the
pasteboard, and use this information to create new clipboard items. Otherwise, if the changeCount is still valid
for the current list of clipboard items, simply return these clipboard items.

If the changeCount ends up being different in between the initial changeCount request and when the pasteboard
item information is received, we immediately bail with a NotAllowedError. The new layout test
clipboard-change-data-while-reading.html exercises this scenario.

(WebCore::Clipboard::getType):
(WebCore::Clipboard::frame const):
* Modules/async-clipboard/Clipboard.h:
* Modules/async-clipboard/ClipboardItem.cpp:
(WebCore::ClipboardItem::blobFromString):
(WebCore::ClipboardItem::ClipboardItem):
(WebCore::ClipboardItem::create):
(WebCore::ClipboardItem::navigator):

Refactor this so that each clipboard item itself has a WeakPtr to its Navigator. This avoids having to follow
the weak pointer to the Clipboard to get to the Clipboard's navigator during garbage collection when computing
reachability from opaque roots, since this may happen on a background (GC) thread.

(WebCore::ClipboardItem::clipboard):
* Modules/async-clipboard/ClipboardItem.h:
* Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp:
(WebCore::ClipboardItemBindingsDataSource::getType):
(WebCore::blobFromString): Deleted.

Move this to ClipboardItem, and make it a static method.

* Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp:
(WebCore::ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource):
(WebCore::ClipboardItemPasteboardDataSource::getType):
* Modules/async-clipboard/ClipboardItemPasteboardDataSource.h:

Move a couple of member variables (index and changeCount) out of ClipboardItem. Instead of having each
ClipboardItem keep track of this information, have the Clipboard that owns the ClipboardItem keep this
information. This means that reading data from ClipboardItem will (in a future patch) work by having the item
ask its Clipboard object to read data on its behalf.

* platform/Pasteboard.cpp:
(WebCore::Pasteboard::allPasteboardItemInfo const):
(WebCore::Pasteboard::pasteboardItemInfo const):
(WebCore::Pasteboard::readString):
(WebCore::Pasteboard::readBuffer):
(WebCore::Pasteboard::readURL):

Add some null checks to handle the case where there is no pasteboard strategy.

Tools:

Make adjustments to WebKitTestRunner and DumpRenderTree to support the new layout tests. See below for more
details.

* DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
* DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
(-[LocalPasteboard pasteboardItems]):

Fixes an existing issue with the mock NSPasteboard used for layout tests. Currently, our logic for converting
the contents of the platform pasteboard to NSPasteboardItem simply writes the pasteboard data as-is to
NSPasteboardItems. However, these pasteboard types may be legacy pasteboard types, in which case
NSPasteboardItem will simply handle the call to `-setData:forType:` as a no-op. AppKit has logic in this
scenario to canonicalize these legacy pasteboard types to their modern counterparts, but this is absent in
DumpRenderTreePasteboard and WebKitTestRunnerPasteboard.

Address this by teaching the mock pasteboards to convert legacy types to modern types when generating platform
pasteboard items.

* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.h:
(WTR::UIScriptController::copyText):

Add a new UIScriptController method to write a string to the platform pasteboard. This patch adds support for
this new testing hook on macOS and iOS, in WebKit2 (WebKitTestRunner).

* TestRunnerShared/mac/NSPasteboardAdditions.h: Copied from Tools/WebKitTestRunner/mac/UIScriptControllerMac.h.
* TestRunnerShared/mac/NSPasteboardAdditions.mm: Added.
(+[NSPasteboard _modernPasteboardType:]):

Add a helper to convert legacy pasteboard types (and dynamic UTIs that map to legacy pasteboard types) to
modern pasteboard types, suitable for writing to NSPasteboardItems on macOS.

* WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
* WebKitTestRunner/ios/UIScriptControllerIOS.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptControllerIOS::copyText):
* WebKitTestRunner/mac/UIScriptControllerMac.h:
* WebKitTestRunner/mac/UIScriptControllerMac.mm:
(WTR::UIScriptControllerMac::copyText):
* WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm:

Apply the same fix for WebKitTestRunner's mock NSPasteboard.

(-[LocalPasteboard _clearContentsWithoutUpdatingChangeCount]):
(-[LocalPasteboard clearContents]):

Make -clearContents clear out all the contents on the mock pasteboard, instead of crashing in AppKit.

(-[LocalPasteboard declareTypes:owner:]):
(-[LocalPasteboard pasteboardItems]):

LayoutTests:

* editing/async-clipboard/clipboard-change-data-while-reading-expected.txt: Added.
* editing/async-clipboard/clipboard-change-data-while-reading.html: Added.

Add a new layout test to verify that if the platform pasteboard changes in the middle of a DOM paste access
request, the promise returned by Clipboard.read() should reject, and the page should not receive any clipboard
items.

* editing/async-clipboard/clipboard-read-basic-expected.txt: Added.
* editing/async-clipboard/clipboard-read-basic.html: Added.

Add a new layout test to exercise Clipboard.read(). Since we don't support reading data from clipboard items
yet, this only checks the types of each pasteboard item. This test additionally ensures that the ClipboardItems
returned from the API are the same between calls to Clipboard.read() if the data hasn't changed.

* editing/async-clipboard/resources/async-clipboard-helpers.js:
(writeToClipboardUsingDataTransfer):

Add a new helper to synchronously write data to the clipboard using execCommand and DataTransfer API.

(async.triggerProgrammaticPaste):

Add a new helper to trigger programmatic paste by activating the given element or location. Also receives an
array of options (which, for now, just supports a single option to change the pasteboard when granting DOM paste
access).

* platform/ios-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
* platform/mac-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
* platform/win/TestExpectations: Skip the new layout tests on Windows for now.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (251278 => 251279)


--- trunk/LayoutTests/ChangeLog	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/ChangeLog	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1,3 +1,39 @@
+2019-10-17  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Clipboard API] Support navigator.clipboard.read()
+        https://bugs.webkit.org/show_bug.cgi?id=203021
+
+        Reviewed by Ryosuke Niwa.
+
+        * editing/async-clipboard/clipboard-change-data-while-reading-expected.txt: Added.
+        * editing/async-clipboard/clipboard-change-data-while-reading.html: Added.
+
+        Add a new layout test to verify that if the platform pasteboard changes in the middle of a DOM paste access
+        request, the promise returned by Clipboard.read() should reject, and the page should not receive any clipboard
+        items.
+
+        * editing/async-clipboard/clipboard-read-basic-expected.txt: Added.
+        * editing/async-clipboard/clipboard-read-basic.html: Added.
+
+        Add a new layout test to exercise Clipboard.read(). Since we don't support reading data from clipboard items
+        yet, this only checks the types of each pasteboard item. This test additionally ensures that the ClipboardItems
+        returned from the API are the same between calls to Clipboard.read() if the data hasn't changed.
+
+        * editing/async-clipboard/resources/async-clipboard-helpers.js:
+        (writeToClipboardUsingDataTransfer):
+
+        Add a new helper to synchronously write data to the clipboard using execCommand and DataTransfer API.
+
+        (async.triggerProgrammaticPaste):
+
+        Add a new helper to trigger programmatic paste by activating the given element or location. Also receives an
+        array of options (which, for now, just supports a single option to change the pasteboard when granting DOM paste
+        access).
+
+        * platform/ios-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
+        * platform/mac-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
+        * platform/win/TestExpectations: Skip the new layout tests on Windows for now.
+
 2019-10-17  Chris Dumez  <cdu...@apple.com>
 
         Don't put pages that have not reached the non-visually empty layout milestone in the back/forward cache

Added: trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading-expected.txt (0 => 251279)


--- trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading-expected.txt	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,10 @@
+This test verifies that if platform pasteboard contents are changed immediately after granting programmatic clipboard access during Clipboard.read(), the promise should be rejected. This test needs to be run in WebKitTestRunner or DumpRenderTree.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Failed to read clipboard items with NotAllowedError.
+PASS finishedReading became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading.html (0 => 251279)


--- trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading.html	                        (rev 0)
+++ trunk/LayoutTests/editing/async-clipboard/clipboard-change-data-while-reading.html	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,64 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ domPasteAllowed=false 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=""
+        <script src=""
+        <script src=""
+        <style>
+            button {
+                width: 100%;
+                height: 100px;
+            }
+
+            iframe {
+                width: 100%;
+                height: 100px;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+        finishedReading = false;
+
+        async function runTest() {
+            description("This test verifies that if platform pasteboard contents are changed immediately after granting programmatic clipboard access during Clipboard.read(), the promise should be rejected. This test needs to be run in WebKitTestRunner or DumpRenderTree.");
+
+            const copyElement = document.getElementById("copy");
+            const pasteElement = document.getElementById("paste");
+            pasteElement.addEventListener("click", async event => {
+                try {
+                    testFailed(`Did not expect to read ${(await navigator.clipboard.read()).length} item(s).`);
+                } catch (exception) {
+                    testPassed(`Failed to read clipboard items with ${exception.name}.`);
+                } finally {
+                    finishedReading = true;
+                }
+            });
+
+            await UIHelper.activateElement(copyElement);
+            await triggerProgrammaticPaste(pasteElement, ["ChangePasteboardWhenGrantingAccess"]);
+            await new Promise(resolve => shouldBecomeEqual("finishedReading", "true", resolve));
+
+            [pasteElement, copyElement].map(element => element.remove());
+            finishJSTest();
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <iframe id="copy" src="" id='copy' style='text-align: center; font-size: 24px; width: 100%; height: 100%; line-height: 80px;'>Click here to copy</button>
+        <p id='text' style='text-align: center; font-size: 24px; width: 100%; height: 100%; line-height: 80px;'>This is some text to copy.</p>
+        <script>
+        copy.addEventListener('click', () => {
+            getSelection().selectAllChildren(text);
+            document.execCommand('Copy');
+            getSelection().removeAllRanges();
+        });
+        </script>"></iframe>
+        <div><button id="paste">Paste</button></div>
+        <div id="description"></div>
+        <div id="console"></div>
+    </body>
+</html>

Added: trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic-expected.txt (0 => 251279)


--- trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic-expected.txt	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,21 @@
+This test verifies that clipboard items can be read with their expected types, and that the wrapper for clipboard items is the same between calls to Clipboard.read. This test requires WebKitTestRunner or DumpRenderTree.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS sortedTypes.length is 3
+PASS sortedTypes[0] is "text/html"
+PASS sortedTypes[1] is "text/plain"
+PASS sortedTypes[2] is "text/uri-list"
+PASS item.foo is undefined
+PASS readCount became 1
+PASS sortedTypes.length is 3
+PASS sortedTypes[0] is "text/html"
+PASS sortedTypes[1] is "text/plain"
+PASS sortedTypes[2] is "text/uri-list"
+PASS item.foo is "bar"
+PASS readCount became 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic.html (0 => 251279)


--- trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic.html	                        (rev 0)
+++ trunk/LayoutTests/editing/async-clipboard/clipboard-read-basic.html	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,74 @@
+<!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=""
+        <script src=""
+        <script src=""
+        <style>
+            button {
+                width: 100px;
+                padding: 1em;
+            }
+        </style>
+    </head>
+    <script>
+        jsTestIsAsync = true;
+
+        description("This test verifies that clipboard items can be read with their expected types, and that the wrapper for clipboard items is the same between calls to Clipboard.read. This test requires WebKitTestRunner or DumpRenderTree.");
+
+        async function runTest() {
+            const copyButton = document.getElementById("copy");
+            const pasteButton = document.getElementById("paste");
+            copyButton.addEventListener("click", event => {
+                writeToClipboardUsingDataTransfer({
+                    "text/html": "<a href=''>apple.com</a>",
+                    "text/plain": "apple.com",
+                    "text/uri-list": "https://apple.com/",
+                });
+                event.preventDefault();
+            });
+
+            pasteButton.addEventListener("click", async event => {
+                for (const item of await navigator.clipboard.read()) {
+                    window.item = item;
+                    window.sortedTypes = item.types.slice(0);
+                    sortedTypes.sort();
+                    shouldBe("sortedTypes.length", "3");
+                    shouldBeEqualToString("sortedTypes[0]", "text/html");
+                    shouldBeEqualToString("sortedTypes[1]", "text/plain");
+                    shouldBeEqualToString("sortedTypes[2]", "text/uri-list");
+                    if (isFirstTimeReading)
+                        shouldBe("item.foo", "undefined");
+                    else
+                        shouldBeEqualToString("item.foo", "bar");
+                    item.foo = "bar";
+                    window.item = window.sortedTypes = null;
+                }
+                ++readCount;
+            });
+
+            readCount = 0;
+            isFirstTimeReading = true;
+            await UIHelper.activateElement(copyButton);
+            await UIHelper.activateElement(pasteButton);
+            await new Promise(resolve => shouldBecomeEqual("readCount", "1", resolve));
+
+            GCController.collect();
+
+            isFirstTimeReading = false;
+            await UIHelper.activateElement(pasteButton);
+            await new Promise(resolve => shouldBecomeEqual("readCount", "2", resolve));
+
+            [pasteButton, copyButton].map(button => button.remove());
+            finishJSTest();
+        }
+
+        addEventListener("load", runTest);
+    </script>
+    <body>
+        <button id="copy">Copy</button>
+        <button id="paste">Paste</button>
+    </body>
+</html>

Modified: trunk/LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js (251278 => 251279)


--- trunk/LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js	2019-10-18 14:24:07 UTC (rev 251279)
@@ -29,3 +29,52 @@
         image.src = ""
     });
 }
+
+function writeToClipboardUsingDataTransfer(data) {
+    const input = document.createElement("input");
+    document.body.appendChild(input);
+    input.value = "a";
+    input.setSelectionRange(0, 1);
+    input.addEventListener("copy", event => {
+        for (const type of Object.keys(data))
+            event.clipboardData.setData(type, data[type]);
+        event.preventDefault();
+    }, { once: true });
+    document.execCommand("copy");
+    input.remove();
+}
+
+
+async function triggerProgrammaticPaste(locationOrElement, options = []) {
+    let x, y;
+    if (locationOrElement instanceof Element)
+        [x, y] = [locationOrElement.offsetLeft + locationOrElement.offsetWidth / 2, locationOrElement.offsetTop + locationOrElement.offsetHeight / 2];
+    else
+        [x, y] = [locationOrElement.x, locationOrElement.y];
+
+    return new Promise(resolve => {
+        testRunner.runUIScript(`
+            (() => {
+                doneCount = 0;
+                function checkDone() {
+                    if (++doneCount === 3)
+                        uiController.uiScriptComplete();
+                }
+
+                uiController.didHideMenuCallback = checkDone;
+
+                function resolveDOMPasteRequest() {
+                    if (${options.includes("ChangePasteboardWhenGrantingAccess")})
+                        uiController.copyText("*** this text should never appear in a passing layout test ***");
+                    uiController.chooseMenuAction("Paste", checkDone);
+                }
+
+                if (uiController.isShowingMenu)
+                    resolveDOMPasteRequest();
+                else
+                    uiController.didShowMenuCallback = resolveDOMPasteRequest;
+
+                uiController.activateAtPoint(${x}, ${y}, checkDone);
+            })()`, resolve);
+    });
+}

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (251278 => 251279)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1,3 +1,14 @@
+2019-10-17  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Clipboard API] Support navigator.clipboard.read()
+        https://bugs.webkit.org/show_bug.cgi?id=203021
+
+        Reviewed by Ryosuke Niwa.
+
+        Rebaseline a web platform test, now that Clipboard.read() no longer immediately rejects.
+
+        * web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt:
+
 2019-10-17  Rob Buis  <rb...@igalia.com>
 
         Remove duplicate MathML tests

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt (251278 => 251279)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt	2019-10-18 14:24:07 UTC (rev 251279)
@@ -6,6 +6,6 @@
 PASS navigator.clipboard.write(DOMString) fails (expect DataTransfer) 
 FAIL navigator.clipboard.writeText(DOMString) succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
 PASS navigator.clipboard.writeText() fails (expect DOMString) 
-FAIL navigator.clipboard.read() succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
+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."
 

Modified: trunk/LayoutTests/platform/ios-wk1/TestExpectations (251278 => 251279)


--- trunk/LayoutTests/platform/ios-wk1/TestExpectations	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/platform/ios-wk1/TestExpectations	2019-10-18 14:24:07 UTC (rev 251279)
@@ -31,6 +31,9 @@
 fast/forms/datalist [ WontFix ]
 imported/w3c/web-platform-tests/html/semantics/forms/the-datalist-element [ WontFix ]
 
+# DOM paste access requests are not implemented in WebKit1.
+editing/async-clipboard/clipboard-change-data-while-reading.html [ Skip ]
+
 # testRunner.queueLoad() does not support loading data URLs in iOS WK1
 http/tests/security/contentSecurityPolicy/navigate-self-to-data-url.html [ Skip ]
 

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (251278 => 251279)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2019-10-18 14:24:07 UTC (rev 251279)
@@ -65,6 +65,9 @@
 fast/forms/datalist [ WontFix ]
 imported/w3c/web-platform-tests/html/semantics/forms/the-datalist-element [ WontFix ]
 
+# DOM paste access requests are not implemented in WebKit1.
+editing/async-clipboard/clipboard-change-data-while-reading.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 ]
 imported/w3c/web-platform-tests/websockets/binary/001.html [ Pass Failure ]

Modified: trunk/LayoutTests/platform/win/TestExpectations (251278 => 251279)


--- trunk/LayoutTests/platform/win/TestExpectations	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/LayoutTests/platform/win/TestExpectations	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1189,6 +1189,9 @@
 http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-in-same-origin.html [ Skip ]
 http/tests/security/clipboard/copy-paste-html-across-origin-strips-mso-list.html [ Skip ]
 
+webkit.org/b/203100 editing/async-clipboard/clipboard-read-basic.html [ Skip ]
+webkit.org/b/203100 editing/async-clipboard/clipboard-change-data-while-reading.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
 webkit.org/b/140786 editing/pasteboard/copy-backslash-with-euc.html [ Skip ] # Causes later tests to fail

Modified: trunk/Source/WebCore/ChangeLog (251278 => 251279)


--- trunk/Source/WebCore/ChangeLog	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/ChangeLog	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1,3 +1,69 @@
+2019-10-17  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Clipboard API] Support navigator.clipboard.read()
+        https://bugs.webkit.org/show_bug.cgi?id=203021
+
+        Reviewed by Ryosuke Niwa.
+
+        Add support for navigator.clipboard.read(), which returns a promise that resolves to a list of ClipboardItems.
+        See below for more details.
+
+        Tests: editing/async-clipboard/clipboard-change-data-while-reading.html
+               editing/async-clipboard/clipboard-read-basic.html
+
+        * Modules/async-clipboard/Clipboard.cpp:
+        (WebCore::Clipboard::read):
+
+        Implement read(). This makes two calls to the platform pasteboard: the first to get the current change count,
+        and if the change count is different from the changeCount used for the last read() call (or there are no
+        existing clipboard items being tracked), then we request pasteboard item information for all items on the
+        pasteboard, and use this information to create new clipboard items. Otherwise, if the changeCount is still valid
+        for the current list of clipboard items, simply return these clipboard items.
+
+        If the changeCount ends up being different in between the initial changeCount request and when the pasteboard
+        item information is received, we immediately bail with a NotAllowedError. The new layout test
+        clipboard-change-data-while-reading.html exercises this scenario.
+
+        (WebCore::Clipboard::getType):
+        (WebCore::Clipboard::frame const):
+        * Modules/async-clipboard/Clipboard.h:
+        * Modules/async-clipboard/ClipboardItem.cpp:
+        (WebCore::ClipboardItem::blobFromString):
+        (WebCore::ClipboardItem::ClipboardItem):
+        (WebCore::ClipboardItem::create):
+        (WebCore::ClipboardItem::navigator):
+
+        Refactor this so that each clipboard item itself has a WeakPtr to its Navigator. This avoids having to follow
+        the weak pointer to the Clipboard to get to the Clipboard's navigator during garbage collection when computing
+        reachability from opaque roots, since this may happen on a background (GC) thread.
+
+        (WebCore::ClipboardItem::clipboard):
+        * Modules/async-clipboard/ClipboardItem.h:
+        * Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp:
+        (WebCore::ClipboardItemBindingsDataSource::getType):
+        (WebCore::blobFromString): Deleted.
+
+        Move this to ClipboardItem, and make it a static method.
+
+        * Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp:
+        (WebCore::ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource):
+        (WebCore::ClipboardItemPasteboardDataSource::getType):
+        * Modules/async-clipboard/ClipboardItemPasteboardDataSource.h:
+
+        Move a couple of member variables (index and changeCount) out of ClipboardItem. Instead of having each
+        ClipboardItem keep track of this information, have the Clipboard that owns the ClipboardItem keep this
+        information. This means that reading data from ClipboardItem will (in a future patch) work by having the item
+        ask its Clipboard object to read data on its behalf.
+
+        * platform/Pasteboard.cpp:
+        (WebCore::Pasteboard::allPasteboardItemInfo const):
+        (WebCore::Pasteboard::pasteboardItemInfo const):
+        (WebCore::Pasteboard::readString):
+        (WebCore::Pasteboard::readBuffer):
+        (WebCore::Pasteboard::readURL):
+
+        Add some null checks to handle the case where there is no pasteboard strategy.
+
 2019-10-17  Chris Dumez  <cdu...@apple.com>
 
         Don't put pages that have not reached the non-visually empty layout milestone in the back/forward cache

Modified: trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp	2019-10-18 14:24:07 UTC (rev 251279)
@@ -26,10 +26,14 @@
 #include "config.h"
 #include "Clipboard.h"
 
+#include "Blob.h"
 #include "ClipboardItem.h"
+#include "Frame.h"
+#include "JSClipboardItem.h"
 #include "JSDOMPromise.h"
 #include "JSDOMPromiseDeferred.h"
 #include "Navigator.h"
+#include "Pasteboard.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -46,6 +50,8 @@
 {
 }
 
+Clipboard::~Clipboard() = default;
+
 Navigator* Clipboard::navigator()
 {
     return m_navigator.get();
@@ -74,6 +80,54 @@
 
 void Clipboard::read(Ref<DeferredPromise>&& promise)
 {
+    auto rejectPromiseAndClearActiveSession = [&] {
+        m_activeSession = WTF::nullopt;
+        promise->reject(NotAllowedError);
+    };
+
+    auto frame = makeRefPtr(this->frame());
+    if (!frame) {
+        rejectPromiseAndClearActiveSession();
+        return;
+    }
+
+    auto pasteboard = Pasteboard::createForCopyAndPaste();
+    int changeCountAtStart = pasteboard->changeCount();
+
+    if (!frame->requestDOMPasteAccess()) {
+        rejectPromiseAndClearActiveSession();
+        return;
+    }
+
+    if (!m_activeSession || m_activeSession->changeCount != changeCountAtStart) {
+        auto allInfo = pasteboard->allPasteboardItemInfo();
+        if (allInfo.isEmpty()) {
+            rejectPromiseAndClearActiveSession();
+            return;
+        }
+
+        Vector<Ref<ClipboardItem>> clipboardItems;
+        clipboardItems.reserveInitialCapacity(allInfo.size());
+        for (auto& itemInfo : allInfo) {
+            // FIXME: This should be refactored such that the initial changeCount is delivered to the client, where it is then checked
+            // against the current changeCount of the platform pasteboard. For instance, in WebKit2, this would relocate the changeCount
+            // check to the UI process instead of the web content process.
+            if (itemInfo.changeCount != changeCountAtStart) {
+                rejectPromiseAndClearActiveSession();
+                return;
+            }
+            clipboardItems.uncheckedAppend(ClipboardItem::create(*this, itemInfo));
+        }
+        m_activeSession = {{ WTFMove(pasteboard), WTFMove(clipboardItems), changeCountAtStart }};
+    }
+
+    promise->resolve<IDLSequence<IDLInterface<ClipboardItem>>>(m_activeSession->items);
+}
+
+void Clipboard::getType(ClipboardItem& item, const String& type, Ref<DeferredPromise>&& promise)
+{
+    UNUSED_PARAM(item);
+    UNUSED_PARAM(type);
     promise->reject(NotSupportedError);
 }
 
@@ -83,4 +137,9 @@
     promise->reject(NotSupportedError);
 }
 
+Frame* Clipboard::frame() const
+{
+    return m_navigator ? m_navigator->frame() : nullptr;
 }
+
+}

Modified: trunk/Source/WebCore/Modules/async-clipboard/Clipboard.h (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/Clipboard.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/Clipboard.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -34,16 +34,20 @@
 
 class ClipboardItem;
 class DeferredPromise;
+class Frame;
 class Navigator;
+class Pasteboard;
 
 class Clipboard final : public RefCounted<Clipboard>, public EventTargetWithInlineData, public CanMakeWeakPtr<Clipboard> {
     WTF_MAKE_ISO_ALLOCATED(Clipboard);
 public:
     static Ref<Clipboard> create(Navigator&);
+    ~Clipboard();
 
     EventTargetInterface eventTargetInterface() const final;
     ScriptExecutionContext* scriptExecutionContext() const final;
 
+    Frame* frame() const;
     Navigator* navigator();
 
     using RefCounted::ref;
@@ -55,12 +59,21 @@
     void read(Ref<DeferredPromise>&&);
     void write(const Vector<RefPtr<ClipboardItem>>& data, Ref<DeferredPromise>&&);
 
+    void getType(ClipboardItem&, const String& type, Ref<DeferredPromise>&&);
+
 private:
     Clipboard(Navigator&);
 
+    struct Session {
+        std::unique_ptr<Pasteboard> pasteboard;
+        Vector<Ref<ClipboardItem>> items;
+        int changeCount;
+    };
+
     void refEventTarget() final { ref(); }
     void derefEventTarget() final { deref(); }
 
+    Optional<Session> m_activeSession;
     WeakPtr<Navigator> m_navigator;
 };
 

Modified: trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.cpp (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.cpp	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.cpp	2019-10-18 14:24:07 UTC (rev 251279)
@@ -26,15 +26,23 @@
 #include "config.h"
 #include "ClipboardItem.h"
 
+#include "Blob.h"
 #include "ClipboardItemBindingsDataSource.h"
 #include "ClipboardItemPasteboardDataSource.h"
 #include "Navigator.h"
 #include "PasteboardItemInfo.h"
+#include "SharedBuffer.h"
 
 namespace WebCore {
 
 ClipboardItem::~ClipboardItem() = default;
 
+Ref<Blob> ClipboardItem::blobFromString(const String& stringData, const String& type)
+{
+    auto utf8 = stringData.utf8();
+    return Blob::create(SharedBuffer::create(utf8.data(), utf8.length()), Blob::normalizedContentType(type));
+}
+
 static ClipboardItem::PresentationStyle clipboardItemPresentationStyle(const PasteboardItemInfo& info)
 {
     switch (info.preferredPresentationStyle) {
@@ -55,9 +63,10 @@
 {
 }
 
-ClipboardItem::ClipboardItem(Clipboard& clipboard, const PasteboardItemInfo& info, size_t index)
+ClipboardItem::ClipboardItem(Clipboard& clipboard, const PasteboardItemInfo& info)
     : m_clipboard(makeWeakPtr(clipboard))
-    , m_dataSource(makeUnique<ClipboardItemPasteboardDataSource>(*this, info, index))
+    , m_navigator(makeWeakPtr(clipboard.navigator()))
+    , m_dataSource(makeUnique<ClipboardItemPasteboardDataSource>(*this, info))
     , m_presentationStyle(clipboardItemPresentationStyle(info))
 {
 }
@@ -67,9 +76,9 @@
     return adoptRef(*new ClipboardItem(WTFMove(data), options));
 }
 
-Ref<ClipboardItem> ClipboardItem::create(Clipboard& clipboard, const PasteboardItemInfo& info, size_t index)
+Ref<ClipboardItem> ClipboardItem::create(Clipboard& clipboard, const PasteboardItemInfo& info)
 {
-    return adoptRef(*new ClipboardItem(clipboard, info, index));
+    return adoptRef(*new ClipboardItem(clipboard, info));
 }
 
 Vector<String> ClipboardItem::types() const
@@ -84,7 +93,12 @@
 
 Navigator* ClipboardItem::navigator()
 {
-    return m_clipboard ? m_clipboard->navigator() : nullptr;
+    return m_navigator.get();
 }
 
+Clipboard* ClipboardItem::clipboard()
+{
+    return m_clipboard.get();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.h (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -53,7 +53,8 @@
     };
 
     static Ref<ClipboardItem> create(Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&&, const Options&);
-    static Ref<ClipboardItem> create(Clipboard&, const PasteboardItemInfo&, size_t index);
+    static Ref<ClipboardItem> create(Clipboard&, const PasteboardItemInfo&);
+    static Ref<Blob> blobFromString(const String& stringData, const String& type);
 
     Vector<String> types() const;
     void getType(const String&, Ref<DeferredPromise>&&);
@@ -60,14 +61,14 @@
 
     PresentationStyle presentationStyle() const { return m_presentationStyle; };
     Navigator* navigator();
+    Clipboard* clipboard();
 
-protected:
-    WeakPtr<Clipboard> m_clipboard;
-
 private:
     ClipboardItem(Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&&, const Options&);
-    ClipboardItem(Clipboard&, const PasteboardItemInfo&, size_t index);
+    ClipboardItem(Clipboard&, const PasteboardItemInfo&);
 
+    WeakPtr<Clipboard> m_clipboard;
+    WeakPtr<Navigator> m_navigator;
     std::unique_ptr<ClipboardItemDataSource> m_dataSource;
     PresentationStyle m_presentationStyle { PresentationStyle::Unspecified };
 };

Modified: trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp	2019-10-18 14:24:07 UTC (rev 251279)
@@ -35,12 +35,6 @@
 
 namespace WebCore {
 
-static Ref<Blob> blobFromString(const String& stringData, const String& type)
-{
-    auto utf8 = stringData.utf8();
-    return Blob::create(SharedBuffer::create(utf8.data(), utf8.length()), Blob::normalizedContentType(type));
-}
-
 ClipboardItemBindingsDataSource::ClipboardItemBindingsDataSource(ClipboardItem& item, Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&& itemPromises)
     : ClipboardItemDataSource(item)
     , m_itemPromises(WTFMove(itemPromises))
@@ -83,7 +77,7 @@
         String string;
         result.getString(itemPromise->globalObject()->globalExec(), string);
         if (!string.isNull()) {
-            promise->resolve<IDLInterface<Blob>>(blobFromString(string, type));
+            promise->resolve<IDLInterface<Blob>>(ClipboardItem::blobFromString(string, type));
             return;
         }
 

Modified: trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp	2019-10-18 14:24:07 UTC (rev 251279)
@@ -30,11 +30,9 @@
 
 namespace WebCore {
 
-ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource(ClipboardItem& item, const PasteboardItemInfo& info, size_t itemIndex)
+ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource(ClipboardItem& item, const PasteboardItemInfo& info)
     : ClipboardItemDataSource(item)
     , m_types(info.webSafeTypesByFidelity)
-    , m_itemIndex(itemIndex)
-    , m_initialChangeCount(info.changeCount)
 {
 }
 
@@ -47,11 +45,10 @@
 
 void ClipboardItemPasteboardDataSource::getType(const String& type, Ref<DeferredPromise>&& promise)
 {
-    // FIXME: Not implemented.
-    UNUSED_PARAM(m_initialChangeCount);
-    UNUSED_PARAM(m_itemIndex);
-    UNUSED_PARAM(type);
-    promise->reject(NotSupportedError);
+    if (auto clipboard = makeRefPtr(m_item.clipboard()))
+        clipboard->getType(m_item, type, WTFMove(promise));
+    else
+        promise->reject(NotAllowedError);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.h (251278 => 251279)


--- trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -34,7 +34,7 @@
 class ClipboardItemPasteboardDataSource : public ClipboardItemDataSource {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    ClipboardItemPasteboardDataSource(ClipboardItem&, const PasteboardItemInfo&, size_t itemIndex);
+    ClipboardItemPasteboardDataSource(ClipboardItem&, const PasteboardItemInfo&);
     ~ClipboardItemPasteboardDataSource();
 
 private:
@@ -42,8 +42,6 @@
     void getType(const String&, Ref<DeferredPromise>&&) final;
 
     Vector<String> m_types;
-    size_t m_itemIndex { 0 };
-    int m_initialChangeCount { 0 };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/Pasteboard.cpp (251278 => 251279)


--- trunk/Source/WebCore/platform/Pasteboard.cpp	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Source/WebCore/platform/Pasteboard.cpp	2019-10-18 14:24:07 UTC (rev 251279)
@@ -64,27 +64,37 @@
 
 Vector<PasteboardItemInfo> Pasteboard::allPasteboardItemInfo() const
 {
-    return platformStrategies()->pasteboardStrategy()->allPasteboardItemInfo(name());
+    if (auto* strategy = platformStrategies()->pasteboardStrategy())
+        return strategy->allPasteboardItemInfo(name());
+    return { };
 }
 
 PasteboardItemInfo Pasteboard::pasteboardItemInfo(size_t index) const
 {
-    return platformStrategies()->pasteboardStrategy()->informationForItemAtIndex(index, name());
+    if (auto* strategy = platformStrategies()->pasteboardStrategy())
+        return strategy->informationForItemAtIndex(index, name());
+    return { };
 }
 
 String Pasteboard::readString(size_t index, const String& type)
 {
-    return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(index, type, name());
+    if (auto* strategy = platformStrategies()->pasteboardStrategy())
+        return strategy->readStringFromPasteboard(index, type, name());
+    return { };
 }
 
 RefPtr<WebCore::SharedBuffer> Pasteboard::readBuffer(size_t index, const String& type)
 {
-    return platformStrategies()->pasteboardStrategy()->readBufferFromPasteboard(index, type, name());
+    if (auto* strategy = platformStrategies()->pasteboardStrategy())
+        return strategy->readBufferFromPasteboard(index, type, name());
+    return nullptr;
 }
 
 URL Pasteboard::readURL(size_t index, String& title)
 {
-    return platformStrategies()->pasteboardStrategy()->readURLFromPasteboard(index, name(), title);
+    if (auto* strategy = platformStrategies()->pasteboardStrategy())
+        return strategy->readURLFromPasteboard(index, name(), title);
+    return { };
 }
 
 };

Modified: trunk/Tools/ChangeLog (251278 => 251279)


--- trunk/Tools/ChangeLog	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/ChangeLog	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1,3 +1,60 @@
+2019-10-17  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [Clipboard API] Support navigator.clipboard.read()
+        https://bugs.webkit.org/show_bug.cgi?id=203021
+
+        Reviewed by Ryosuke Niwa.
+
+        Make adjustments to WebKitTestRunner and DumpRenderTree to support the new layout tests. See below for more
+        details.
+
+        * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+        * DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
+        (-[LocalPasteboard pasteboardItems]):
+
+        Fixes an existing issue with the mock NSPasteboard used for layout tests. Currently, our logic for converting
+        the contents of the platform pasteboard to NSPasteboardItem simply writes the pasteboard data as-is to
+        NSPasteboardItems. However, these pasteboard types may be legacy pasteboard types, in which case
+        NSPasteboardItem will simply handle the call to `-setData:forType:` as a no-op. AppKit has logic in this
+        scenario to canonicalize these legacy pasteboard types to their modern counterparts, but this is absent in
+        DumpRenderTreePasteboard and WebKitTestRunnerPasteboard.
+
+        Address this by teaching the mock pasteboards to convert legacy types to modern types when generating platform
+        pasteboard items.
+
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        (WTR::UIScriptController::copyText):
+
+        Add a new UIScriptController method to write a string to the platform pasteboard. This patch adds support for
+        this new testing hook on macOS and iOS, in WebKit2 (WebKitTestRunner).
+
+        * TestRunnerShared/mac/NSPasteboardAdditions.h: Copied from Tools/WebKitTestRunner/mac/UIScriptControllerMac.h.
+        * TestRunnerShared/mac/NSPasteboardAdditions.mm: Added.
+        (+[NSPasteboard _modernPasteboardType:]):
+
+        Add a helper to convert legacy pasteboard types (and dynamic UTIs that map to legacy pasteboard types) to
+        modern pasteboard types, suitable for writing to NSPasteboardItems on macOS.
+
+        * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptControllerIOS::copyText):
+        * WebKitTestRunner/mac/UIScriptControllerMac.h:
+        * WebKitTestRunner/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptControllerMac::copyText):
+        * WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm:
+
+        Apply the same fix for WebKitTestRunner's mock NSPasteboard.
+
+        (-[LocalPasteboard _clearContentsWithoutUpdatingChangeCount]):
+        (-[LocalPasteboard clearContents]):
+
+        Make -clearContents clear out all the contents on the mock pasteboard, instead of crashing in AppKit.
+
+        (-[LocalPasteboard declareTypes:owner:]):
+        (-[LocalPasteboard pasteboardItems]):
+
 2019-10-17  Mark Lam  <mark....@apple.com>
 
         Use constexpr in more places and remove some unnecessary external linkage.

Modified: trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj (251278 => 251279)


--- trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj	2019-10-18 14:24:07 UTC (rev 251279)
@@ -161,6 +161,7 @@
 		F44A531E21B89A5000DBB99C /* InstanceMethodSwizzler.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44A531C21B89A4500DBB99C /* InstanceMethodSwizzler.mm */; };
 		F4C3578D20E8444E00FA0748 /* LayoutTestSpellChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C3578820E8442700FA0748 /* LayoutTestSpellChecker.mm */; };
 		F4D423611DD5048200678290 /* TextInputControllerIOS.m in Sources */ = {isa = PBXBuildFile; fileRef = F4D4235F1DD5045300678290 /* TextInputControllerIOS.m */; };
+		F4FED32023582158003C139C /* NSPasteboardAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -433,6 +434,8 @@
 		F4C3578920E8442700FA0748 /* LayoutTestSpellChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutTestSpellChecker.h; sourceTree = "<group>"; };
 		F4D4235F1DD5045300678290 /* TextInputControllerIOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TextInputControllerIOS.m; path = ios/TextInputControllerIOS.m; sourceTree = "<group>"; };
 		F4D423601DD5046900678290 /* TextInputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextInputController.h; sourceTree = "<group>"; };
+		F4FED31E23582158003C139C /* NSPasteboardAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPasteboardAdditions.h; path = mac/NSPasteboardAdditions.h; sourceTree = "<group>"; };
+		F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSPasteboardAdditions.mm; path = mac/NSPasteboardAdditions.mm; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -706,6 +709,7 @@
 			isa = PBXGroup;
 			children = (
 				F4B6C31820E84382008AC225 /* cocoa */,
+				F4FED31623581EF3003C139C /* mac */,
 				A17A5A2B22A880D80065C5F0 /* spi */,
 				3148A0551E6F90F400D3B316 /* IOSLayoutTestCommunication.cpp */,
 				3148A0561E6F90F400D3B316 /* IOSLayoutTestCommunication.h */,
@@ -875,6 +879,15 @@
 			name = ios;
 			sourceTree = "<group>";
 		};
+		F4FED31623581EF3003C139C /* mac */ = {
+			isa = PBXGroup;
+			children = (
+				F4FED31E23582158003C139C /* NSPasteboardAdditions.h */,
+				F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */,
+			);
+			name = mac;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -1185,6 +1198,7 @@
 				E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */,
 				31117B3D15D9A56A00163BC8 /* MockWebNotificationProvider.mm in Sources */,
 				BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */,
+				F4FED32023582158003C139C /* NSPasteboardAdditions.mm in Sources */,
 				BCA18B320C9B01B400114369 /* ObjCController.m in Sources */,
 				BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */,
 				BCA18B800C9B08F100114369 /* ObjCPluginFunction.m in Sources */,

Modified: trunk/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm (251278 => 251279)


--- trunk/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm	2019-10-18 14:24:07 UTC (rev 251279)
@@ -34,6 +34,8 @@
 #if PLATFORM(MAC)
 
 #import "DumpRenderTreeMac.h"
+#import "NSPasteboardAdditions.h"
+#import <WebCore/LegacyNSPasteboardTypes.h>
 #import <WebKit/WebTypesInternal.h>
 #import <objc/runtime.h>
 #import <wtf/Assertions.h>
@@ -243,7 +245,7 @@
     for (const auto& typeAndData : _data) {
         NSData *data = "" NSData *)typeAndData.value.get();
         NSString *type = (__bridge NSString *)typeAndData.key.get();
-        [item setData:data forType:type];
+        [item setData:data forType:[NSPasteboard _modernPasteboardType:type]];
     }
     return @[ item.get() ];
 }

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (251278 => 251279)


--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl	2019-10-18 14:24:07 UTC (rev 251279)
@@ -262,6 +262,8 @@
     void resignFirstResponder();
     readonly attribute boolean isPresentingModally;
 
+    void copyText(DOMString text);
+
     readonly attribute double contentOffsetX;
     readonly attribute double contentOffsetY;
 

Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (251278 => 251279)


--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -105,6 +105,8 @@
     virtual void becomeFirstResponder() { notImplemented(); }
     virtual void resignFirstResponder() { notImplemented(); }
 
+    virtual void copyText(JSStringRef) { notImplemented(); }
+
     virtual void chooseMenuAction(JSStringRef, JSValueRef);
     virtual void dismissMenu();
 

Copied: trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.h (from rev 251278, trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.h) (0 => 251279)


--- trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.h	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if PLATFORM(MAC)
+
+#import <AppKit/AppKit.h>
+
+@interface NSPasteboard (TestRunnerAdditions)
+
++ (NSPasteboardType)_modernPasteboardType:(NSString *)type;
+
+@end
+
+#endif // PLATFORM(MAC)

Added: trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.mm (0 => 251279)


--- trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.mm	                        (rev 0)
+++ trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.mm	2019-10-18 14:24:07 UTC (rev 251279)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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 met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "NSPasteboardAdditions.h"
+
+#if PLATFORM(MAC)
+
+#import <CoreServices/CoreServices.h>
+#import <WebCore/LegacyNSPasteboardTypes.h>
+#import <wtf/RetainPtr.h>
+
+@implementation NSPasteboard (TestRunnerAdditions)
+
++ (NSPasteboardType)_modernPasteboardType:(NSString *)type
+{
+    if (UTTypeIsDynamic((__bridge CFStringRef)type)) {
+        if (auto legacyType = adoptNS((__bridge NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)type, kUTTagClassNSPboardType)))
+            type = legacyType.autorelease();
+    }
+
+    if ([type isEqualToString:WebCore::legacyStringPasteboardType()])
+        return NSPasteboardTypeString;
+
+    if ([type isEqualToString:WebCore::legacyHTMLPasteboardType()])
+        return NSPasteboardTypeHTML;
+
+    if ([type isEqualToString:WebCore::legacyTIFFPasteboardType()])
+        return NSPasteboardTypeTIFF;
+
+    if ([type isEqualToString:WebCore::legacyURLPasteboardType()])
+        return NSPasteboardTypeURL;
+
+    if ([type isEqualToString:WebCore::legacyPDFPasteboardType()])
+        return NSPasteboardTypePDF;
+
+    if ([type isEqualToString:WebCore::legacyRTFDPasteboardType()])
+        return NSPasteboardTypeRTFD;
+
+    if ([type isEqualToString:WebCore::legacyRTFPasteboardType()])
+        return NSPasteboardTypeRTF;
+
+    if ([type isEqualToString:WebCore::legacyColorPasteboardType()])
+        return NSPasteboardTypeColor;
+
+    if ([type isEqualToString:WebCore::legacyFontPasteboardType()])
+        return NSPasteboardTypeFont;
+
+    return type;
+}
+
+@end
+
+#endif // PLATFORM(MAC)

Modified: trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj	2019-10-18 14:24:07 UTC (rev 251279)
@@ -155,6 +155,7 @@
 		F44A531821B899E500DBB99C /* InstanceMethodSwizzler.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44A531621B899DA00DBB99C /* InstanceMethodSwizzler.mm */; };
 		F46240B1217013E500917B16 /* UIScriptControllerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = F46240AF2170128300917B16 /* UIScriptControllerCocoa.mm */; };
 		F4C3578C20E8444600FA0748 /* LayoutTestSpellChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C3578A20E8444000FA0748 /* LayoutTestSpellChecker.mm */; };
+		F4FED324235823A3003C139C /* NSPasteboardAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -412,6 +413,8 @@
 		F46240AF2170128300917B16 /* UIScriptControllerCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UIScriptControllerCocoa.mm; sourceTree = "<group>"; };
 		F4C3578A20E8444000FA0748 /* LayoutTestSpellChecker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = LayoutTestSpellChecker.mm; path = ../TestRunnerShared/cocoa/LayoutTestSpellChecker.mm; sourceTree = "<group>"; };
 		F4C3578B20E8444000FA0748 /* LayoutTestSpellChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LayoutTestSpellChecker.h; path = ../TestRunnerShared/cocoa/LayoutTestSpellChecker.h; sourceTree = "<group>"; };
+		F4FED3212358215E003C139C /* NSPasteboardAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPasteboardAdditions.h; path = ../TestRunnerShared/mac/NSPasteboardAdditions.h; sourceTree = "<group>"; };
+		F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSPasteboardAdditions.mm; path = ../TestRunnerShared/mac/NSPasteboardAdditions.mm; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -522,6 +525,7 @@
 			children = (
 				0F18E71B1D6BC4E60027E547 /* Bindings */,
 				F4B6C31620E84369008AC225 /* cocoa */,
+				F4FED31D23582120003C139C /* mac */,
 				0F73B5471BA782FE004B3EF4 /* UIScriptContext */,
 				3148A0531E6F85B600D3B316 /* IOSLayoutTestCommunication.cpp */,
 				3148A0541E6F85B600D3B316 /* IOSLayoutTestCommunication.h */,
@@ -890,6 +894,15 @@
 			name = cocoa;
 			sourceTree = "<group>";
 		};
+		F4FED31D23582120003C139C /* mac */ = {
+			isa = PBXGroup;
+			children = (
+				F4FED3212358215E003C139C /* NSPasteboardAdditions.h */,
+				F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */,
+			);
+			name = mac;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -1140,6 +1153,7 @@
 			files = (
 				5670B8281386FCA5002EB355 /* EventSenderProxy.mm in Sources */,
 				BC793400118F7C84005EA8E2 /* main.mm in Sources */,
+				F4FED324235823A3003C139C /* NSPasteboardAdditions.mm in Sources */,
 				BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */,
 				E1C642C317CBCC7300D66A3C /* PoseAsClass.mm in Sources */,
 				BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */,

Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -134,6 +134,7 @@
     JSObjectRef calendarType() const override;
     void setHardwareKeyboardAttached(bool) override;
     void setAllowsViewportShrinkToFit(bool) override;
+    void copyText(JSStringRef) override;
 
     void setDidStartFormControlInteractionCallback(JSValueRef) override;
     void setDidEndFormControlInteractionCallback(JSValueRef) override;

Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm	2019-10-18 14:24:07 UTC (rev 251279)
@@ -1208,6 +1208,11 @@
     });
 }
 
+void UIScriptControllerIOS::copyText(JSStringRef text)
+{
+    UIPasteboard.generalPasteboard.string = text->string();
 }
 
+}
+
 #endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.h (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.h	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.h	2019-10-18 14:24:07 UTC (rev 251279)
@@ -52,6 +52,7 @@
     void toggleCapsLock(JSValueRef) override;
     NSView *platformContentView() const override;
     void clearAllCallbacks() override;
+    void copyText(JSStringRef) override;
 
     void chooseMenuAction(JSStringRef, JSValueRef) override;
 

Modified: trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm	2019-10-18 14:24:07 UTC (rev 251279)
@@ -225,4 +225,11 @@
     });
 }
 
+void UIScriptControllerMac::copyText(JSStringRef text)
+{
+    NSPasteboard *pasteboard = NSPasteboard.generalPasteboard;
+    [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
+    [pasteboard setString:text->string() forType:NSPasteboardTypeString];
+}
+
 } // namespace WTR

Modified: trunk/Tools/WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm (251278 => 251279)


--- trunk/Tools/WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm	2019-10-18 10:40:34 UTC (rev 251278)
+++ trunk/Tools/WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm	2019-10-18 14:24:07 UTC (rev 251279)
@@ -25,11 +25,12 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
-#include "WebKitTestRunnerPasteboard.h"
+#import "config.h"
+#import "WebKitTestRunnerPasteboard.h"
 
-#include <objc/runtime.h>
-#include <wtf/RetainPtr.h>
+#import "NSPasteboardAdditions.h"
+#import <objc/runtime.h>
+#import <wtf/RetainPtr.h>
 
 @interface LocalPasteboard : NSPasteboard
 {
@@ -123,11 +124,22 @@
 {
 }
 
-- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
+- (void)_clearContentsWithoutUpdatingChangeCount
 {
     [typesArray removeAllObjects];
     [typesSet removeAllObjects];
     [dataByType removeAllObjects];
+}
+
+- (NSInteger)clearContents
+{
+    [self _clearContentsWithoutUpdatingChangeCount];
+    return ++changeCount;
+}
+
+- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
+{
+    [self _clearContentsWithoutUpdatingChangeCount];
     return [self addTypes:newTypes owner:newOwner];
 }
 
@@ -202,7 +214,7 @@
 {
     auto item = adoptNS([[NSPasteboardItem alloc] init]);
     for (NSString *type in dataByType)
-        [item setData:dataByType[type] forType:type];
+        [item setData:dataByType[type] forType:[NSPasteboard _modernPasteboardType:type]];
     return @[ item.get() ];
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to