Changeset 251279 in webkit


Ignore:
Timestamp:
Oct 18, 2019 7:24:07 AM (5 years ago)
Author:
Wenson Hsieh
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.
Location:
trunk
Files:
6 added
27 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r251275 r251279  
     12019-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Support navigator.clipboard.read()
     4        https://bugs.webkit.org/show_bug.cgi?id=203021
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * editing/async-clipboard/clipboard-change-data-while-reading-expected.txt: Added.
     9        * editing/async-clipboard/clipboard-change-data-while-reading.html: Added.
     10
     11        Add a new layout test to verify that if the platform pasteboard changes in the middle of a DOM paste access
     12        request, the promise returned by Clipboard.read() should reject, and the page should not receive any clipboard
     13        items.
     14
     15        * editing/async-clipboard/clipboard-read-basic-expected.txt: Added.
     16        * editing/async-clipboard/clipboard-read-basic.html: Added.
     17
     18        Add a new layout test to exercise Clipboard.read(). Since we don't support reading data from clipboard items
     19        yet, this only checks the types of each pasteboard item. This test additionally ensures that the ClipboardItems
     20        returned from the API are the same between calls to Clipboard.read() if the data hasn't changed.
     21
     22        * editing/async-clipboard/resources/async-clipboard-helpers.js:
     23        (writeToClipboardUsingDataTransfer):
     24
     25        Add a new helper to synchronously write data to the clipboard using execCommand and DataTransfer API.
     26
     27        (async.triggerProgrammaticPaste):
     28
     29        Add a new helper to trigger programmatic paste by activating the given element or location. Also receives an
     30        array of options (which, for now, just supports a single option to change the pasteboard when granting DOM paste
     31        access).
     32
     33        * platform/ios-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
     34        * platform/mac-wk1/TestExpectations: Skip clipboard-change-data-while-reading.html for now in WebKit1.
     35        * platform/win/TestExpectations: Skip the new layout tests on Windows for now.
     36
    1372019-10-17  Chris Dumez  <cdumez@apple.com>
    238
  • trunk/LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js

    r251134 r251279  
    3030    });
    3131}
     32
     33function writeToClipboardUsingDataTransfer(data) {
     34    const input = document.createElement("input");
     35    document.body.appendChild(input);
     36    input.value = "a";
     37    input.setSelectionRange(0, 1);
     38    input.addEventListener("copy", event => {
     39        for (const type of Object.keys(data))
     40            event.clipboardData.setData(type, data[type]);
     41        event.preventDefault();
     42    }, { once: true });
     43    document.execCommand("copy");
     44    input.remove();
     45}
     46
     47
     48async function triggerProgrammaticPaste(locationOrElement, options = []) {
     49    let x, y;
     50    if (locationOrElement instanceof Element)
     51        [x, y] = [locationOrElement.offsetLeft + locationOrElement.offsetWidth / 2, locationOrElement.offsetTop + locationOrElement.offsetHeight / 2];
     52    else
     53        [x, y] = [locationOrElement.x, locationOrElement.y];
     54
     55    return new Promise(resolve => {
     56        testRunner.runUIScript(`
     57            (() => {
     58                doneCount = 0;
     59                function checkDone() {
     60                    if (++doneCount === 3)
     61                        uiController.uiScriptComplete();
     62                }
     63
     64                uiController.didHideMenuCallback = checkDone;
     65
     66                function resolveDOMPasteRequest() {
     67                    if (${options.includes("ChangePasteboardWhenGrantingAccess")})
     68                        uiController.copyText("*** this text should never appear in a passing layout test ***");
     69                    uiController.chooseMenuAction("Paste", checkDone);
     70                }
     71
     72                if (uiController.isShowingMenu)
     73                    resolveDOMPasteRequest();
     74                else
     75                    uiController.didShowMenuCallback = resolveDOMPasteRequest;
     76
     77                uiController.activateAtPoint(${x}, ${y}, checkDone);
     78            })()`, resolve);
     79    });
     80}
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r251253 r251279  
     12019-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Support navigator.clipboard.read()
     4        https://bugs.webkit.org/show_bug.cgi?id=203021
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Rebaseline a web platform test, now that Clipboard.read() no longer immediately rejects.
     9
     10        * web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt:
     11
    1122019-10-17  Rob Buis  <rbuis@igalia.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/clipboard-apis/async-navigator-clipboard-basics.https-expected.txt

    r250856 r251279  
    77FAIL navigator.clipboard.writeText(DOMString) succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
    88PASS navigator.clipboard.writeText() fails (expect DOMString)
    9 FAIL navigator.clipboard.read() succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
     9FAIL navigator.clipboard.read() succeeds assert_true: expected true got false
    1010FAIL navigator.clipboard.readText() succeeds promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
    1111
  • trunk/LayoutTests/platform/ios-wk1/TestExpectations

    r251149 r251279  
    3131fast/forms/datalist [ WontFix ]
    3232imported/w3c/web-platform-tests/html/semantics/forms/the-datalist-element [ WontFix ]
     33
     34# DOM paste access requests are not implemented in WebKit1.
     35editing/async-clipboard/clipboard-change-data-while-reading.html [ Skip ]
    3336
    3437# testRunner.queueLoad() does not support loading data URLs in iOS WK1
  • trunk/LayoutTests/platform/mac-wk1/TestExpectations

    r251149 r251279  
    6565fast/forms/datalist [ WontFix ]
    6666imported/w3c/web-platform-tests/html/semantics/forms/the-datalist-element [ WontFix ]
     67
     68# DOM paste access requests are not implemented in WebKit1.
     69editing/async-clipboard/clipboard-change-data-while-reading.html [ Skip ]
    6770
    6871imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.html [ Pass Failure ]
  • trunk/LayoutTests/platform/win/TestExpectations

    r251149 r251279  
    11891189http/tests/security/clipboard/copy-paste-html-cross-origin-iframe-in-same-origin.html [ Skip ]
    11901190http/tests/security/clipboard/copy-paste-html-across-origin-strips-mso-list.html [ Skip ]
     1191
     1192webkit.org/b/203100 editing/async-clipboard/clipboard-read-basic.html [ Skip ]
     1193webkit.org/b/203100 editing/async-clipboard/clipboard-change-data-while-reading.html [ Skip ]
    11911194
    11921195webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ]
  • trunk/Source/WebCore/ChangeLog

    r251275 r251279  
     12019-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Support navigator.clipboard.read()
     4        https://bugs.webkit.org/show_bug.cgi?id=203021
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Add support for navigator.clipboard.read(), which returns a promise that resolves to a list of ClipboardItems.
     9        See below for more details.
     10
     11        Tests: editing/async-clipboard/clipboard-change-data-while-reading.html
     12               editing/async-clipboard/clipboard-read-basic.html
     13
     14        * Modules/async-clipboard/Clipboard.cpp:
     15        (WebCore::Clipboard::read):
     16
     17        Implement read(). This makes two calls to the platform pasteboard: the first to get the current change count,
     18        and if the change count is different from the changeCount used for the last read() call (or there are no
     19        existing clipboard items being tracked), then we request pasteboard item information for all items on the
     20        pasteboard, and use this information to create new clipboard items. Otherwise, if the changeCount is still valid
     21        for the current list of clipboard items, simply return these clipboard items.
     22
     23        If the changeCount ends up being different in between the initial changeCount request and when the pasteboard
     24        item information is received, we immediately bail with a NotAllowedError. The new layout test
     25        clipboard-change-data-while-reading.html exercises this scenario.
     26
     27        (WebCore::Clipboard::getType):
     28        (WebCore::Clipboard::frame const):
     29        * Modules/async-clipboard/Clipboard.h:
     30        * Modules/async-clipboard/ClipboardItem.cpp:
     31        (WebCore::ClipboardItem::blobFromString):
     32        (WebCore::ClipboardItem::ClipboardItem):
     33        (WebCore::ClipboardItem::create):
     34        (WebCore::ClipboardItem::navigator):
     35
     36        Refactor this so that each clipboard item itself has a WeakPtr to its Navigator. This avoids having to follow
     37        the weak pointer to the Clipboard to get to the Clipboard's navigator during garbage collection when computing
     38        reachability from opaque roots, since this may happen on a background (GC) thread.
     39
     40        (WebCore::ClipboardItem::clipboard):
     41        * Modules/async-clipboard/ClipboardItem.h:
     42        * Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp:
     43        (WebCore::ClipboardItemBindingsDataSource::getType):
     44        (WebCore::blobFromString): Deleted.
     45
     46        Move this to ClipboardItem, and make it a static method.
     47
     48        * Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp:
     49        (WebCore::ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource):
     50        (WebCore::ClipboardItemPasteboardDataSource::getType):
     51        * Modules/async-clipboard/ClipboardItemPasteboardDataSource.h:
     52
     53        Move a couple of member variables (index and changeCount) out of ClipboardItem. Instead of having each
     54        ClipboardItem keep track of this information, have the Clipboard that owns the ClipboardItem keep this
     55        information. This means that reading data from ClipboardItem will (in a future patch) work by having the item
     56        ask its Clipboard object to read data on its behalf.
     57
     58        * platform/Pasteboard.cpp:
     59        (WebCore::Pasteboard::allPasteboardItemInfo const):
     60        (WebCore::Pasteboard::pasteboardItemInfo const):
     61        (WebCore::Pasteboard::readString):
     62        (WebCore::Pasteboard::readBuffer):
     63        (WebCore::Pasteboard::readURL):
     64
     65        Add some null checks to handle the case where there is no pasteboard strategy.
     66
    1672019-10-17  Chris Dumez  <cdumez@apple.com>
    268
  • trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp

    r250824 r251279  
    2727#include "Clipboard.h"
    2828
     29#include "Blob.h"
    2930#include "ClipboardItem.h"
     31#include "Frame.h"
     32#include "JSClipboardItem.h"
    3033#include "JSDOMPromise.h"
    3134#include "JSDOMPromiseDeferred.h"
    3235#include "Navigator.h"
     36#include "Pasteboard.h"
    3337#include <wtf/IsoMallocInlines.h>
    3438
     
    4650{
    4751}
     52
     53Clipboard::~Clipboard() = default;
    4854
    4955Navigator* Clipboard::navigator()
     
    7581void Clipboard::read(Ref<DeferredPromise>&& promise)
    7682{
     83    auto rejectPromiseAndClearActiveSession = [&] {
     84        m_activeSession = WTF::nullopt;
     85        promise->reject(NotAllowedError);
     86    };
     87
     88    auto frame = makeRefPtr(this->frame());
     89    if (!frame) {
     90        rejectPromiseAndClearActiveSession();
     91        return;
     92    }
     93
     94    auto pasteboard = Pasteboard::createForCopyAndPaste();
     95    int changeCountAtStart = pasteboard->changeCount();
     96
     97    if (!frame->requestDOMPasteAccess()) {
     98        rejectPromiseAndClearActiveSession();
     99        return;
     100    }
     101
     102    if (!m_activeSession || m_activeSession->changeCount != changeCountAtStart) {
     103        auto allInfo = pasteboard->allPasteboardItemInfo();
     104        if (allInfo.isEmpty()) {
     105            rejectPromiseAndClearActiveSession();
     106            return;
     107        }
     108
     109        Vector<Ref<ClipboardItem>> clipboardItems;
     110        clipboardItems.reserveInitialCapacity(allInfo.size());
     111        for (auto& itemInfo : allInfo) {
     112            // FIXME: This should be refactored such that the initial changeCount is delivered to the client, where it is then checked
     113            // against the current changeCount of the platform pasteboard. For instance, in WebKit2, this would relocate the changeCount
     114            // check to the UI process instead of the web content process.
     115            if (itemInfo.changeCount != changeCountAtStart) {
     116                rejectPromiseAndClearActiveSession();
     117                return;
     118            }
     119            clipboardItems.uncheckedAppend(ClipboardItem::create(*this, itemInfo));
     120        }
     121        m_activeSession = {{ WTFMove(pasteboard), WTFMove(clipboardItems), changeCountAtStart }};
     122    }
     123
     124    promise->resolve<IDLSequence<IDLInterface<ClipboardItem>>>(m_activeSession->items);
     125}
     126
     127void Clipboard::getType(ClipboardItem& item, const String& type, Ref<DeferredPromise>&& promise)
     128{
     129    UNUSED_PARAM(item);
     130    UNUSED_PARAM(type);
    77131    promise->reject(NotSupportedError);
    78132}
     
    84138}
    85139
     140Frame* Clipboard::frame() const
     141{
     142    return m_navigator ? m_navigator->frame() : nullptr;
    86143}
     144
     145}
  • trunk/Source/WebCore/Modules/async-clipboard/Clipboard.h

    r251134 r251279  
    3535class ClipboardItem;
    3636class DeferredPromise;
     37class Frame;
    3738class Navigator;
     39class Pasteboard;
    3840
    3941class Clipboard final : public RefCounted<Clipboard>, public EventTargetWithInlineData, public CanMakeWeakPtr<Clipboard> {
     
    4143public:
    4244    static Ref<Clipboard> create(Navigator&);
     45    ~Clipboard();
    4346
    4447    EventTargetInterface eventTargetInterface() const final;
    4548    ScriptExecutionContext* scriptExecutionContext() const final;
    4649
     50    Frame* frame() const;
    4751    Navigator* navigator();
    4852
     
    5660    void write(const Vector<RefPtr<ClipboardItem>>& data, Ref<DeferredPromise>&&);
    5761
     62    void getType(ClipboardItem&, const String& type, Ref<DeferredPromise>&&);
     63
    5864private:
    5965    Clipboard(Navigator&);
     66
     67    struct Session {
     68        std::unique_ptr<Pasteboard> pasteboard;
     69        Vector<Ref<ClipboardItem>> items;
     70        int changeCount;
     71    };
    6072
    6173    void refEventTarget() final { ref(); }
    6274    void derefEventTarget() final { deref(); }
    6375
     76    Optional<Session> m_activeSession;
    6477    WeakPtr<Navigator> m_navigator;
    6578};
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.cpp

    r251134 r251279  
    2727#include "ClipboardItem.h"
    2828
     29#include "Blob.h"
    2930#include "ClipboardItemBindingsDataSource.h"
    3031#include "ClipboardItemPasteboardDataSource.h"
    3132#include "Navigator.h"
    3233#include "PasteboardItemInfo.h"
     34#include "SharedBuffer.h"
    3335
    3436namespace WebCore {
    3537
    3638ClipboardItem::~ClipboardItem() = default;
     39
     40Ref<Blob> ClipboardItem::blobFromString(const String& stringData, const String& type)
     41{
     42    auto utf8 = stringData.utf8();
     43    return Blob::create(SharedBuffer::create(utf8.data(), utf8.length()), Blob::normalizedContentType(type));
     44}
    3745
    3846static ClipboardItem::PresentationStyle clipboardItemPresentationStyle(const PasteboardItemInfo& info)
     
    5664}
    5765
    58 ClipboardItem::ClipboardItem(Clipboard& clipboard, const PasteboardItemInfo& info, size_t index)
     66ClipboardItem::ClipboardItem(Clipboard& clipboard, const PasteboardItemInfo& info)
    5967    : m_clipboard(makeWeakPtr(clipboard))
    60     , m_dataSource(makeUnique<ClipboardItemPasteboardDataSource>(*this, info, index))
     68    , m_navigator(makeWeakPtr(clipboard.navigator()))
     69    , m_dataSource(makeUnique<ClipboardItemPasteboardDataSource>(*this, info))
    6170    , m_presentationStyle(clipboardItemPresentationStyle(info))
    6271{
     
    6877}
    6978
    70 Ref<ClipboardItem> ClipboardItem::create(Clipboard& clipboard, const PasteboardItemInfo& info, size_t index)
     79Ref<ClipboardItem> ClipboardItem::create(Clipboard& clipboard, const PasteboardItemInfo& info)
    7180{
    72     return adoptRef(*new ClipboardItem(clipboard, info, index));
     81    return adoptRef(*new ClipboardItem(clipboard, info));
    7382}
    7483
     
    8594Navigator* ClipboardItem::navigator()
    8695{
    87     return m_clipboard ? m_clipboard->navigator() : nullptr;
     96    return m_navigator.get();
     97}
     98
     99Clipboard* ClipboardItem::clipboard()
     100{
     101    return m_clipboard.get();
    88102}
    89103
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItem.h

    r251134 r251279  
    5454
    5555    static Ref<ClipboardItem> create(Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&&, const Options&);
    56     static Ref<ClipboardItem> create(Clipboard&, const PasteboardItemInfo&, size_t index);
     56    static Ref<ClipboardItem> create(Clipboard&, const PasteboardItemInfo&);
     57    static Ref<Blob> blobFromString(const String& stringData, const String& type);
    5758
    5859    Vector<String> types() const;
     
    6162    PresentationStyle presentationStyle() const { return m_presentationStyle; };
    6263    Navigator* navigator();
    63 
    64 protected:
    65     WeakPtr<Clipboard> m_clipboard;
     64    Clipboard* clipboard();
    6665
    6766private:
    6867    ClipboardItem(Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&&, const Options&);
    69     ClipboardItem(Clipboard&, const PasteboardItemInfo&, size_t index);
     68    ClipboardItem(Clipboard&, const PasteboardItemInfo&);
    7069
     70    WeakPtr<Clipboard> m_clipboard;
     71    WeakPtr<Navigator> m_navigator;
    7172    std::unique_ptr<ClipboardItemDataSource> m_dataSource;
    7273    PresentationStyle m_presentationStyle { PresentationStyle::Unspecified };
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemBindingsDataSource.cpp

    r251134 r251279  
    3535
    3636namespace WebCore {
    37 
    38 static Ref<Blob> blobFromString(const String& stringData, const String& type)
    39 {
    40     auto utf8 = stringData.utf8();
    41     return Blob::create(SharedBuffer::create(utf8.data(), utf8.length()), Blob::normalizedContentType(type));
    42 }
    4337
    4438ClipboardItemBindingsDataSource::ClipboardItemBindingsDataSource(ClipboardItem& item, Vector<KeyValuePair<String, RefPtr<DOMPromise>>>&& itemPromises)
     
    8478        result.getString(itemPromise->globalObject()->globalExec(), string);
    8579        if (!string.isNull()) {
    86             promise->resolve<IDLInterface<Blob>>(blobFromString(string, type));
     80            promise->resolve<IDLInterface<Blob>>(ClipboardItem::blobFromString(string, type));
    8781            return;
    8882        }
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.cpp

    r251134 r251279  
    3131namespace WebCore {
    3232
    33 ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource(ClipboardItem& item, const PasteboardItemInfo& info, size_t itemIndex)
     33ClipboardItemPasteboardDataSource::ClipboardItemPasteboardDataSource(ClipboardItem& item, const PasteboardItemInfo& info)
    3434    : ClipboardItemDataSource(item)
    3535    , m_types(info.webSafeTypesByFidelity)
    36     , m_itemIndex(itemIndex)
    37     , m_initialChangeCount(info.changeCount)
    3836{
    3937}
     
    4846void ClipboardItemPasteboardDataSource::getType(const String& type, Ref<DeferredPromise>&& promise)
    4947{
    50     // FIXME: Not implemented.
    51     UNUSED_PARAM(m_initialChangeCount);
    52     UNUSED_PARAM(m_itemIndex);
    53     UNUSED_PARAM(type);
    54     promise->reject(NotSupportedError);
     48    if (auto clipboard = makeRefPtr(m_item.clipboard()))
     49        clipboard->getType(m_item, type, WTFMove(promise));
     50    else
     51        promise->reject(NotAllowedError);
    5552}
    5653
  • trunk/Source/WebCore/Modules/async-clipboard/ClipboardItemPasteboardDataSource.h

    r251134 r251279  
    3535    WTF_MAKE_FAST_ALLOCATED;
    3636public:
    37     ClipboardItemPasteboardDataSource(ClipboardItem&, const PasteboardItemInfo&, size_t itemIndex);
     37    ClipboardItemPasteboardDataSource(ClipboardItem&, const PasteboardItemInfo&);
    3838    ~ClipboardItemPasteboardDataSource();
    3939
     
    4343
    4444    Vector<String> m_types;
    45     size_t m_itemIndex { 0 };
    46     int m_initialChangeCount { 0 };
    4745};
    4846
  • trunk/Source/WebCore/platform/Pasteboard.cpp

    r251100 r251279  
    6565Vector<PasteboardItemInfo> Pasteboard::allPasteboardItemInfo() const
    6666{
    67     return platformStrategies()->pasteboardStrategy()->allPasteboardItemInfo(name());
     67    if (auto* strategy = platformStrategies()->pasteboardStrategy())
     68        return strategy->allPasteboardItemInfo(name());
     69    return { };
    6870}
    6971
    7072PasteboardItemInfo Pasteboard::pasteboardItemInfo(size_t index) const
    7173{
    72     return platformStrategies()->pasteboardStrategy()->informationForItemAtIndex(index, name());
     74    if (auto* strategy = platformStrategies()->pasteboardStrategy())
     75        return strategy->informationForItemAtIndex(index, name());
     76    return { };
    7377}
    7478
    7579String Pasteboard::readString(size_t index, const String& type)
    7680{
    77     return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(index, type, name());
     81    if (auto* strategy = platformStrategies()->pasteboardStrategy())
     82        return strategy->readStringFromPasteboard(index, type, name());
     83    return { };
    7884}
    7985
    8086RefPtr<WebCore::SharedBuffer> Pasteboard::readBuffer(size_t index, const String& type)
    8187{
    82     return platformStrategies()->pasteboardStrategy()->readBufferFromPasteboard(index, type, name());
     88    if (auto* strategy = platformStrategies()->pasteboardStrategy())
     89        return strategy->readBufferFromPasteboard(index, type, name());
     90    return nullptr;
    8391}
    8492
    8593URL Pasteboard::readURL(size_t index, String& title)
    8694{
    87     return platformStrategies()->pasteboardStrategy()->readURLFromPasteboard(index, name(), title);
     95    if (auto* strategy = platformStrategies()->pasteboardStrategy())
     96        return strategy->readURLFromPasteboard(index, name(), title);
     97    return { };
    8898}
    8999
  • trunk/Tools/ChangeLog

    r251263 r251279  
     12019-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Support navigator.clipboard.read()
     4        https://bugs.webkit.org/show_bug.cgi?id=203021
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Make adjustments to WebKitTestRunner and DumpRenderTree to support the new layout tests. See below for more
     9        details.
     10
     11        * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
     12        * DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
     13        (-[LocalPasteboard pasteboardItems]):
     14
     15        Fixes an existing issue with the mock NSPasteboard used for layout tests. Currently, our logic for converting
     16        the contents of the platform pasteboard to NSPasteboardItem simply writes the pasteboard data as-is to
     17        NSPasteboardItems. However, these pasteboard types may be legacy pasteboard types, in which case
     18        NSPasteboardItem will simply handle the call to `-setData:forType:` as a no-op. AppKit has logic in this
     19        scenario to canonicalize these legacy pasteboard types to their modern counterparts, but this is absent in
     20        DumpRenderTreePasteboard and WebKitTestRunnerPasteboard.
     21
     22        Address this by teaching the mock pasteboards to convert legacy types to modern types when generating platform
     23        pasteboard items.
     24
     25        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
     26        * TestRunnerShared/UIScriptContext/UIScriptController.h:
     27        (WTR::UIScriptController::copyText):
     28
     29        Add a new UIScriptController method to write a string to the platform pasteboard. This patch adds support for
     30        this new testing hook on macOS and iOS, in WebKit2 (WebKitTestRunner).
     31
     32        * TestRunnerShared/mac/NSPasteboardAdditions.h: Copied from Tools/WebKitTestRunner/mac/UIScriptControllerMac.h.
     33        * TestRunnerShared/mac/NSPasteboardAdditions.mm: Added.
     34        (+[NSPasteboard _modernPasteboardType:]):
     35
     36        Add a helper to convert legacy pasteboard types (and dynamic UTIs that map to legacy pasteboard types) to
     37        modern pasteboard types, suitable for writing to NSPasteboardItems on macOS.
     38
     39        * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
     40        * WebKitTestRunner/ios/UIScriptControllerIOS.h:
     41        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
     42        (WTR::UIScriptControllerIOS::copyText):
     43        * WebKitTestRunner/mac/UIScriptControllerMac.h:
     44        * WebKitTestRunner/mac/UIScriptControllerMac.mm:
     45        (WTR::UIScriptControllerMac::copyText):
     46        * WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm:
     47
     48        Apply the same fix for WebKitTestRunner's mock NSPasteboard.
     49
     50        (-[LocalPasteboard _clearContentsWithoutUpdatingChangeCount]):
     51        (-[LocalPasteboard clearContents]):
     52
     53        Make -clearContents clear out all the contents on the mock pasteboard, instead of crashing in AppKit.
     54
     55        (-[LocalPasteboard declareTypes:owner:]):
     56        (-[LocalPasteboard pasteboardItems]):
     57
    1582019-10-17  Mark Lam  <mark.lam@apple.com>
    259
  • trunk/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj

    r249675 r251279  
    162162                F4C3578D20E8444E00FA0748 /* LayoutTestSpellChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C3578820E8442700FA0748 /* LayoutTestSpellChecker.mm */; };
    163163                F4D423611DD5048200678290 /* TextInputControllerIOS.m in Sources */ = {isa = PBXBuildFile; fileRef = F4D4235F1DD5045300678290 /* TextInputControllerIOS.m */; };
     164                F4FED32023582158003C139C /* NSPasteboardAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */; };
    164165/* End PBXBuildFile section */
    165166
     
    434435                F4D4235F1DD5045300678290 /* TextInputControllerIOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TextInputControllerIOS.m; path = ios/TextInputControllerIOS.m; sourceTree = "<group>"; };
    435436                F4D423601DD5046900678290 /* TextInputController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextInputController.h; sourceTree = "<group>"; };
     437                F4FED31E23582158003C139C /* NSPasteboardAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPasteboardAdditions.h; path = mac/NSPasteboardAdditions.h; sourceTree = "<group>"; };
     438                F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSPasteboardAdditions.mm; path = mac/NSPasteboardAdditions.mm; sourceTree = "<group>"; };
    436439/* End PBXFileReference section */
    437440
     
    707710                        children = (
    708711                                F4B6C31820E84382008AC225 /* cocoa */,
     712                                F4FED31623581EF3003C139C /* mac */,
    709713                                A17A5A2B22A880D80065C5F0 /* spi */,
    710714                                3148A0551E6F90F400D3B316 /* IOSLayoutTestCommunication.cpp */,
     
    874878                        );
    875879                        name = ios;
     880                        sourceTree = "<group>";
     881                };
     882                F4FED31623581EF3003C139C /* mac */ = {
     883                        isa = PBXGroup;
     884                        children = (
     885                                F4FED31E23582158003C139C /* NSPasteboardAdditions.h */,
     886                                F4FED31F23582158003C139C /* NSPasteboardAdditions.mm */,
     887                        );
     888                        name = mac;
    876889                        sourceTree = "<group>";
    877890                };
     
    11861199                                31117B3D15D9A56A00163BC8 /* MockWebNotificationProvider.mm in Sources */,
    11871200                                BCA18B720C9B08DB00114369 /* NavigationController.m in Sources */,
     1201                                F4FED32023582158003C139C /* NSPasteboardAdditions.mm in Sources */,
    11881202                                BCA18B320C9B01B400114369 /* ObjCController.m in Sources */,
    11891203                                BCA18B7E0C9B08F100114369 /* ObjCPlugin.m in Sources */,
  • trunk/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm

    r239266 r251279  
    3535
    3636#import "DumpRenderTreeMac.h"
     37#import "NSPasteboardAdditions.h"
     38#import <WebCore/LegacyNSPasteboardTypes.h>
    3739#import <WebKit/WebTypesInternal.h>
    3840#import <objc/runtime.h>
     
    244246        NSData *data = (__bridge NSData *)typeAndData.value.get();
    245247        NSString *type = (__bridge NSString *)typeAndData.key.get();
    246         [item setData:data forType:type];
     248        [item setData:data forType:[NSPasteboard _modernPasteboardType:type]];
    247249    }
    248250    return @[ item.get() ];
  • trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl

    r250973 r251279  
    263263    readonly attribute boolean isPresentingModally;
    264264
     265    void copyText(DOMString text);
     266
    265267    readonly attribute double contentOffsetX;
    266268    readonly attribute double contentOffsetY;
  • trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h

    r250973 r251279  
    106106    virtual void resignFirstResponder() { notImplemented(); }
    107107
     108    virtual void copyText(JSStringRef) { notImplemented(); }
     109
    108110    virtual void chooseMenuAction(JSStringRef, JSValueRef);
    109111    virtual void dismissMenu();
  • trunk/Tools/TestRunnerShared/mac/NSPasteboardAdditions.h

    r251278 r251279  
    2626#pragma once
    2727
    28 #include "ClipboardItemDataSource.h"
     28#if PLATFORM(MAC)
    2929
    30 namespace WebCore {
     30#import <AppKit/AppKit.h>
    3131
    32 struct PasteboardItemInfo;
     32@interface NSPasteboard (TestRunnerAdditions)
    3333
    34 class ClipboardItemPasteboardDataSource : public ClipboardItemDataSource {
    35     WTF_MAKE_FAST_ALLOCATED;
    36 public:
    37     ClipboardItemPasteboardDataSource(ClipboardItem&, const PasteboardItemInfo&, size_t itemIndex);
    38     ~ClipboardItemPasteboardDataSource();
     34+ (NSPasteboardType)_modernPasteboardType:(NSString *)type;
    3935
    40 private:
    41     Vector<String> types() const final;
    42     void getType(const String&, Ref<DeferredPromise>&&) final;
     36@end
    4337
    44     Vector<String> m_types;
    45     size_t m_itemIndex { 0 };
    46     int m_initialChangeCount { 0 };
    47 };
    48 
    49 } // namespace WebCore
     38#endif // PLATFORM(MAC)
  • trunk/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj

    r248308 r251279  
    156156                F46240B1217013E500917B16 /* UIScriptControllerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = F46240AF2170128300917B16 /* UIScriptControllerCocoa.mm */; };
    157157                F4C3578C20E8444600FA0748 /* LayoutTestSpellChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C3578A20E8444000FA0748 /* LayoutTestSpellChecker.mm */; };
     158                F4FED324235823A3003C139C /* NSPasteboardAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */; };
    158159/* End PBXBuildFile section */
    159160
     
    413414                F4C3578A20E8444000FA0748 /* LayoutTestSpellChecker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = LayoutTestSpellChecker.mm; path = ../TestRunnerShared/cocoa/LayoutTestSpellChecker.mm; sourceTree = "<group>"; };
    414415                F4C3578B20E8444000FA0748 /* LayoutTestSpellChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LayoutTestSpellChecker.h; path = ../TestRunnerShared/cocoa/LayoutTestSpellChecker.h; sourceTree = "<group>"; };
     416                F4FED3212358215E003C139C /* NSPasteboardAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSPasteboardAdditions.h; path = ../TestRunnerShared/mac/NSPasteboardAdditions.h; sourceTree = "<group>"; };
     417                F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSPasteboardAdditions.mm; path = ../TestRunnerShared/mac/NSPasteboardAdditions.mm; sourceTree = "<group>"; };
    415418/* End PBXFileReference section */
    416419
     
    523526                                0F18E71B1D6BC4E60027E547 /* Bindings */,
    524527                                F4B6C31620E84369008AC225 /* cocoa */,
     528                                F4FED31D23582120003C139C /* mac */,
    525529                                0F73B5471BA782FE004B3EF4 /* UIScriptContext */,
    526530                                3148A0531E6F85B600D3B316 /* IOSLayoutTestCommunication.cpp */,
     
    889893                        );
    890894                        name = cocoa;
     895                        sourceTree = "<group>";
     896                };
     897                F4FED31D23582120003C139C /* mac */ = {
     898                        isa = PBXGroup;
     899                        children = (
     900                                F4FED3212358215E003C139C /* NSPasteboardAdditions.h */,
     901                                F4FED3222358215E003C139C /* NSPasteboardAdditions.mm */,
     902                        );
     903                        name = mac;
    891904                        sourceTree = "<group>";
    892905                };
     
    11411154                                5670B8281386FCA5002EB355 /* EventSenderProxy.mm in Sources */,
    11421155                                BC793400118F7C84005EA8E2 /* main.mm in Sources */,
     1156                                F4FED324235823A3003C139C /* NSPasteboardAdditions.mm in Sources */,
    11431157                                BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */,
    11441158                                E1C642C317CBCC7300D66A3C /* PoseAsClass.mm in Sources */,
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h

    r250973 r251279  
    135135    void setHardwareKeyboardAttached(bool) override;
    136136    void setAllowsViewportShrinkToFit(bool) override;
     137    void copyText(JSStringRef) override;
    137138
    138139    void setDidStartFormControlInteractionCallback(JSValueRef) override;
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

    r250973 r251279  
    12091209}
    12101210
     1211void UIScriptControllerIOS::copyText(JSStringRef text)
     1212{
     1213    UIPasteboard.generalPasteboard.string = text->string();
     1214}
     1215
    12111216}
    12121217
  • trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.h

    r250973 r251279  
    5353    NSView *platformContentView() const override;
    5454    void clearAllCallbacks() override;
     55    void copyText(JSStringRef) override;
    5556
    5657    void chooseMenuAction(JSStringRef, JSValueRef) override;
  • trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm

    r250973 r251279  
    226226}
    227227
     228void UIScriptControllerMac::copyText(JSStringRef text)
     229{
     230    NSPasteboard *pasteboard = NSPasteboard.generalPasteboard;
     231    [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
     232    [pasteboard setString:text->string() forType:NSPasteboardTypeString];
     233}
     234
    228235} // namespace WTR
  • trunk/Tools/WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm

    r235837 r251279  
    2626 */
    2727
    28 #include "config.h"
    29 #include "WebKitTestRunnerPasteboard.h"
    30 
    31 #include <objc/runtime.h>
    32 #include <wtf/RetainPtr.h>
     28#import "config.h"
     29#import "WebKitTestRunnerPasteboard.h"
     30
     31#import "NSPasteboardAdditions.h"
     32#import <objc/runtime.h>
     33#import <wtf/RetainPtr.h>
    3334
    3435@interface LocalPasteboard : NSPasteboard
     
    124125}
    125126
    126 - (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
     127- (void)_clearContentsWithoutUpdatingChangeCount
    127128{
    128129    [typesArray removeAllObjects];
    129130    [typesSet removeAllObjects];
    130131    [dataByType removeAllObjects];
     132}
     133
     134- (NSInteger)clearContents
     135{
     136    [self _clearContentsWithoutUpdatingChangeCount];
     137    return ++changeCount;
     138}
     139
     140- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
     141{
     142    [self _clearContentsWithoutUpdatingChangeCount];
    131143    return [self addTypes:newTypes owner:newOwner];
    132144}
     
    203215    auto item = adoptNS([[NSPasteboardItem alloc] init]);
    204216    for (NSString *type in dataByType)
    205         [item setData:dataByType[type] forType:type];
     217        [item setData:dataByType[type] forType:[NSPasteboard _modernPasteboardType:type]];
    206218    return @[ item.get() ];
    207219}
Note: See TracChangeset for help on using the changeset viewer.