⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 252450 in webkit


Ignore:
Timestamp:
Nov 13, 2019, 10:39:08 PM (7 years ago)
Author:
Wenson Hsieh
Message:

[Clipboard API] Add support for Clipboard.write()
https://bugs.webkit.org/show_bug.cgi?id=204078
<rdar://problem/57087756>

Reviewed by Ryosuke Niwa.

Source/WebCore:

This patch adds support for the write() method on Clipboard, forgoing sanitization for now (this will be added
in the next patch). See below for more details.

Tests: editing/async-clipboard/clipboard-change-data-while-writing.html

editing/async-clipboard/clipboard-write-basic.html
editing/async-clipboard/clipboard-write-items-twice.html

  • Modules/async-clipboard/Clipboard.cpp:

(WebCore::Clipboard::~Clipboard):
(WebCore::shouldProceedWithClipboardWrite):
(WebCore::Clipboard::write):

Implement this method by creating a new ItemWriter and loading data from all the ClipboardItems that are being
written. If the previous writer is still in progress, make sure that we invalidate it first (rejecting the
promise) before proceeding.

(WebCore::Clipboard::didResolveOrReject):
(WebCore::Clipboard::ItemWriter::ItemWriter):
(WebCore::Clipboard::ItemWriter::write):
(WebCore::Clipboard::ItemWriter::invalidate):
(WebCore::Clipboard::ItemWriter::setData):
(WebCore::Clipboard::ItemWriter::didSetAllData):
(WebCore::Clipboard::ItemWriter::reject):

Introduce a private helper class to collect clipboard data for writing from a list of ClipboardItems, and
resolve or reject the given promise when finished.

  • Modules/async-clipboard/Clipboard.h:
  • platform/ios/PlatformPasteboardIOS.mm:

(WebCore::createItemProviderRegistrationList):

Fix a stray bug where the empty string could not be read back as plain text or URLs from the platform pasteboard
on iOS. This is exercised by the new layout test clipboard-write-basic.html.

  • platform/mac/PlatformPasteboardMac.mm:

(WebCore::PlatformPasteboard::write):

Address another issue where we would sometimes try and declare the empty string as a pasteboard type when
writing to the platform pasteboard. While benign in a real NSPasteboard, there's no reason to include it in this
list of declared pasteboard types.

Tools:

Make the LocalPasteboard in WebKitTestRunner compatible with calls to -writeObjects: with a list of pasteboard
items. Currently, attempts to -writeObjects: result in a crash, since NSPasteboard code will attempt to
communicate with pasted and fail. We fix this by implementing -writeObjects: and storing the array of
NSPasteboardItems in LocalPasteboard, the same way we do in DumpRenderTree's LocalPasteboard implementation.

  • DumpRenderTree/mac/DumpRenderTreePasteboard.mm:

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

Factor out logic to clear the pasteboard's content into a separate helper, and clear out the list of saved
pasteboard items here as well.

(-[LocalPasteboard clearContents]):

Implement -clearContents in DumpRenderTree's LocalPasteboard, so that we can test Clipboard.write() in WebKit1.

(-[LocalPasteboard writeObjects:]):

Also make it so that we save any NSPasteboardItems we write to the local pasteboard, so that we can return them
later in -pasteboardItems.

(-[LocalPasteboard pasteboardItems]):

  • WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm:

(-[LocalPasteboard initWithName:]):

Clean up this code a bit by replacing manual reference counting for typesArray and its neighboring data
structures with RetainPtr. Additionally, underscore-prefix the instance variables on LocalPasteboard to match
most of the other Objective-C objects in WebKit.

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

Clear out the NSPasteboardItem list here too.

(-[LocalPasteboard clearContents]):
(-[LocalPasteboard declareTypes:owner:]):
(-[LocalPasteboard addTypes:owner:]):
(-[LocalPasteboard _addTypesWithoutUpdatingChangeCount:owner:]):
(-[LocalPasteboard changeCount]):
(-[LocalPasteboard types]):
(-[LocalPasteboard availableTypeFromArray:]):
(-[LocalPasteboard setData:forType:]):
(-[LocalPasteboard dataForType:]):
(-[LocalPasteboard pasteboardItems]):
(-[LocalPasteboard writeObjects:]):

Implement this by porting over the implementation that currently exists in DumpRenderTree. Like in
DumpRenderTree, we want to also save the NSPasteboardItem array we're given here, so that we can return it in
-pasteboardItems.

(-[LocalPasteboard dealloc]): Deleted.

LayoutTests:

Adds several new layout tests to exercise the write method on Clipboard.

  • editing/async-clipboard/clipboard-change-data-while-writing-expected.txt: Added.
  • editing/async-clipboard/clipboard-change-data-while-writing.html: Added.

Verify that if the platform pasteboard contents change while the page attempts to write to the clipboard, we
will reject the promise for writing.

  • editing/async-clipboard/clipboard-write-basic-expected.txt: Added.
  • editing/async-clipboard/clipboard-write-basic.html: Added.

Verify that writing multiple ClipboardItems to the clipboard using write() works. Among these items, one of them
contains no types, and another only contains types that resolve to empty strings. The page should be able to
read all four items back using Clipboard.read().

  • editing/async-clipboard/clipboard-write-items-twice-expected.txt: Added.
  • editing/async-clipboard/clipboard-write-items-twice.html: Added.

Verify that attempting to write a clipboard item that resolves on a long delay, and then attempting to write
another item that resolves on a short delay before the previous clipboard item has finished writing does not
cause the latter call to Clipboard.write() to fail. Additionally, the clipboard should contain the contents of
the second set of clipboard items, rather than the first.

  • editing/async-clipboard/resources/async-clipboard-helpers.js:

(async.checkClipboardItemString):

Add a helper method to read a string for the given type, out of the given clipboard item, and compare it against
an expected result.

Location:
trunk
Files:
6 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r252444 r252450  
     12019-11-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Add support for Clipboard.write()
     4        https://bugs.webkit.org/show_bug.cgi?id=204078
     5        <rdar://problem/57087756>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Adds several new layout tests to exercise the write method on Clipboard.
     10
     11        * editing/async-clipboard/clipboard-change-data-while-writing-expected.txt: Added.
     12        * editing/async-clipboard/clipboard-change-data-while-writing.html: Added.
     13
     14        Verify that if the platform pasteboard contents change while the page attempts to write to the clipboard, we
     15        will reject the promise for writing.
     16
     17        * editing/async-clipboard/clipboard-write-basic-expected.txt: Added.
     18        * editing/async-clipboard/clipboard-write-basic.html: Added.
     19
     20        Verify that writing multiple ClipboardItems to the clipboard using write() works. Among these items, one of them
     21        contains no types, and another only contains types that resolve to empty strings. The page should be able to
     22        read all four items back using Clipboard.read().
     23
     24        * editing/async-clipboard/clipboard-write-items-twice-expected.txt: Added.
     25        * editing/async-clipboard/clipboard-write-items-twice.html: Added.
     26
     27        Verify that attempting to write a clipboard item that resolves on a long delay, and then attempting to write
     28        another item that resolves on a short delay before the previous clipboard item has finished writing does not
     29        cause the latter call to Clipboard.write() to fail. Additionally, the clipboard should contain the contents of
     30        the second set of clipboard items, rather than the first.
     31
     32        * editing/async-clipboard/resources/async-clipboard-helpers.js:
     33        (async.checkClipboardItemString):
     34
     35        Add a helper method to read a string for the given type, out of the given clipboard item, and compare it against
     36        an expected result.
     37
    1382019-11-13  Said Abou-Hallawa  <sabouhallawa@apple.com>
    239
  • trunk/LayoutTests/editing/async-clipboard/resources/async-clipboard-helpers.js

    r251377 r252450  
    8585    });
    8686}
     87
     88async function checkClipboardItemString(item, type, expectedString)
     89{
     90    const observedString = await loadText(await item.getType(type));
     91    if (observedString === expectedString)
     92        testPassed(`getType("${type}") resolved to "${expectedString}"`);
     93    else
     94        testFailed(`getType("${type}") resolved to "${observedString}; expected "${expectedString}"`);
     95}
  • trunk/LayoutTests/platform/win/TestExpectations

    r252441 r252450  
    11911191webkit.org/b/203100 editing/async-clipboard/clipboard-item-get-type-basic.html [ Skip ]
    11921192webkit.org/b/203100 editing/async-clipboard/clipboard-get-type-with-old-items.html [ Skip ]
     1193webkit.org/b/203100 editing/async-clipboard/clipboard-change-data-while-writing.html [ Skip ]
     1194webkit.org/b/203100 editing/async-clipboard/clipboard-write-basic.html [ Skip ]
     1195webkit.org/b/203100 editing/async-clipboard/clipboard-write-items-twice.html [ Skip ]
    11931196
    11941197webkit.org/b/140783 [ Release ] editing/pasteboard/copy-standalone-image.html [ Failure ImageOnlyFailure ]
  • trunk/Source/WebCore/ChangeLog

    r252444 r252450  
     12019-11-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Add support for Clipboard.write()
     4        https://bugs.webkit.org/show_bug.cgi?id=204078
     5        <rdar://problem/57087756>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        This patch adds support for the write() method on Clipboard, forgoing sanitization for now (this will be added
     10        in the next patch). See below for more details.
     11
     12        Tests: editing/async-clipboard/clipboard-change-data-while-writing.html
     13               editing/async-clipboard/clipboard-write-basic.html
     14               editing/async-clipboard/clipboard-write-items-twice.html
     15
     16        * Modules/async-clipboard/Clipboard.cpp:
     17        (WebCore::Clipboard::~Clipboard):
     18        (WebCore::shouldProceedWithClipboardWrite):
     19        (WebCore::Clipboard::write):
     20
     21        Implement this method by creating a new ItemWriter and loading data from all the ClipboardItems that are being
     22        written. If the previous writer is still in progress, make sure that we invalidate it first (rejecting the
     23        promise) before proceeding.
     24
     25        (WebCore::Clipboard::didResolveOrReject):
     26        (WebCore::Clipboard::ItemWriter::ItemWriter):
     27        (WebCore::Clipboard::ItemWriter::write):
     28        (WebCore::Clipboard::ItemWriter::invalidate):
     29        (WebCore::Clipboard::ItemWriter::setData):
     30        (WebCore::Clipboard::ItemWriter::didSetAllData):
     31        (WebCore::Clipboard::ItemWriter::reject):
     32
     33        Introduce a private helper class to collect clipboard data for writing from a list of ClipboardItems, and
     34        resolve or reject the given promise when finished.
     35
     36        * Modules/async-clipboard/Clipboard.h:
     37        * platform/ios/PlatformPasteboardIOS.mm:
     38        (WebCore::createItemProviderRegistrationList):
     39
     40        Fix a stray bug where the empty string could not be read back as plain text or URLs from the platform pasteboard
     41        on iOS. This is exercised by the new layout test clipboard-write-basic.html.
     42
     43        * platform/mac/PlatformPasteboardMac.mm:
     44        (WebCore::PlatformPasteboard::write):
     45
     46        Address another issue where we would sometimes try and declare the empty string as a pasteboard type when
     47        writing to the platform pasteboard. While benign in a real NSPasteboard, there's no reason to include it in this
     48        list of declared pasteboard types.
     49
    1502019-11-13  Said Abou-Hallawa  <sabouhallawa@apple.com>
    251
  • trunk/Source/WebCore/Modules/async-clipboard/Clipboard.cpp

    r251436 r252450  
    3434#include "Navigator.h"
    3535#include "Pasteboard.h"
     36#include "Settings.h"
    3637#include "SharedBuffer.h"
     38#include "UserGestureIndicator.h"
    3739#include "WebContentReader.h"
     40#include <wtf/CompletionHandler.h>
    3841#include <wtf/IsoMallocInlines.h>
    3942
     
    5255}
    5356
    54 Clipboard::~Clipboard() = default;
     57Clipboard::~Clipboard()
     58{
     59    if (auto writer = WTFMove(m_activeItemWriter))
     60        writer->invalidate();
     61}
    5562
    5663Navigator* Clipboard::navigator()
     
    180187}
    181188
     189static bool shouldProceedWithClipboardWrite(const Frame& frame)
     190{
     191    auto& settings = frame.settings();
     192    if (settings.javaScriptCanAccessClipboard())
     193        return true;
     194
     195    switch (settings.clipboardAccessPolicy()) {
     196    case ClipboardAccessPolicy::Allow:
     197        return true;
     198    case ClipboardAccessPolicy::RequiresUserGesture:
     199        return UserGestureIndicator::processingUserGesture();
     200    case ClipboardAccessPolicy::Deny:
     201        return false;
     202    }
     203
     204    ASSERT_NOT_REACHED();
     205    return false;
     206}
     207
    182208void Clipboard::write(const Vector<RefPtr<ClipboardItem>>& items, Ref<DeferredPromise>&& promise)
    183209{
    184     UNUSED_PARAM(items);
    185     promise->reject(NotSupportedError);
     210    auto frame = makeRefPtr(this->frame());
     211    if (!frame || !shouldProceedWithClipboardWrite(*frame)) {
     212        promise->reject(NotAllowedError);
     213        return;
     214    }
     215
     216    if (auto existingWriter = std::exchange(m_activeItemWriter, ItemWriter::create(*this, WTFMove(promise))))
     217        existingWriter->invalidate();
     218
     219    m_activeItemWriter->write(items);
     220}
     221
     222void Clipboard::didResolveOrReject(Clipboard::ItemWriter& writer)
     223{
     224    if (m_activeItemWriter == &writer)
     225        m_activeItemWriter = nullptr;
    186226}
    187227
     
    198238}
    199239
    200 }
     240Clipboard::ItemWriter::ItemWriter(Clipboard& clipboard, Ref<DeferredPromise>&& promise)
     241    : m_clipboard(makeWeakPtr(clipboard))
     242    , m_promise(WTFMove(promise))
     243    , m_pasteboard(Pasteboard::createForCopyAndPaste())
     244{
     245}
     246
     247Clipboard::ItemWriter::~ItemWriter() = default;
     248
     249void Clipboard::ItemWriter::write(const Vector<RefPtr<ClipboardItem>>& items)
     250{
     251    ASSERT(m_promise);
     252    ASSERT(m_clipboard);
     253#if PLATFORM(COCOA)
     254    m_changeCountAtStart = m_pasteboard->changeCount();
     255#endif
     256    m_dataToWrite.fill(WTF::nullopt, items.size());
     257    m_pendingItemCount = items.size();
     258    for (size_t index = 0; index < items.size(); ++index) {
     259        items[index]->collectDataForWriting(*m_clipboard, [this, protectedThis = makeRef(*this), index] (auto data) {
     260            protectedThis->setData(WTFMove(data), index);
     261            if (!--m_pendingItemCount)
     262                didSetAllData();
     263        });
     264    }
     265    if (items.isEmpty())
     266        didSetAllData();
     267}
     268
     269void Clipboard::ItemWriter::invalidate()
     270{
     271    if (m_promise)
     272        reject();
     273}
     274
     275void Clipboard::ItemWriter::setData(Optional<PasteboardCustomData>&& data, size_t index)
     276{
     277    if (index >= m_dataToWrite.size()) {
     278        ASSERT_NOT_REACHED();
     279        return;
     280    }
     281
     282    m_dataToWrite[index] = WTFMove(data);
     283}
     284
     285void Clipboard::ItemWriter::didSetAllData()
     286{
     287    if (!m_promise)
     288        return;
     289
     290#if PLATFORM(COCOA)
     291    auto newChangeCount = m_pasteboard->changeCount();
     292    if (m_changeCountAtStart != newChangeCount) {
     293        // FIXME: Instead of checking the changeCount here, send it over to the client (e.g. the UI process
     294        // in WebKit2) and perform it there.
     295        reject();
     296        return;
     297    }
     298#endif // PLATFORM(COCOA)
     299    auto dataToWrite = std::exchange(m_dataToWrite, { });
     300    Vector<PasteboardCustomData> customData;
     301    customData.reserveInitialCapacity(dataToWrite.size());
     302    for (auto data : dataToWrite) {
     303        if (!data) {
     304            reject();
     305            return;
     306        }
     307        customData.append(*data);
     308    }
     309
     310    m_pasteboard->writeCustomData(WTFMove(customData));
     311    m_promise->resolve();
     312    m_promise = nullptr;
     313
     314    if (auto clipboard = std::exchange(m_clipboard, nullptr))
     315        clipboard->didResolveOrReject(*this);
     316}
     317
     318void Clipboard::ItemWriter::reject()
     319{
     320    if (auto promise = std::exchange(m_promise, nullptr))
     321        promise->reject(NotAllowedError);
     322
     323    if (auto clipboard = std::exchange(m_clipboard, nullptr))
     324        clipboard->didResolveOrReject(*this);
     325}
     326
     327}
  • trunk/Source/WebCore/Modules/async-clipboard/Clipboard.h

    r251421 r252450  
    2828#include "EventTarget.h"
    2929#include <wtf/IsoMalloc.h>
     30#include <wtf/Optional.h>
    3031#include <wtf/Vector.h>
    3132#include <wtf/WeakPtr.h>
     
    3839class Navigator;
    3940class Pasteboard;
     41class PasteboardCustomData;
    4042
    4143class Clipboard final : public RefCounted<Clipboard>, public EventTargetWithInlineData, public CanMakeWeakPtr<Clipboard> {
     
    7678    Pasteboard& activePasteboard();
    7779
     80    class ItemWriter : public RefCounted<ItemWriter> {
     81    public:
     82        static Ref<ItemWriter> create(Clipboard& clipboard, Ref<DeferredPromise>&& promise)
     83        {
     84            return adoptRef(*new ItemWriter(clipboard, WTFMove(promise)));
     85        }
     86
     87        ~ItemWriter();
     88
     89        void write(const Vector<RefPtr<ClipboardItem>>&);
     90        void invalidate();
     91
     92    private:
     93        ItemWriter(Clipboard&, Ref<DeferredPromise>&&);
     94
     95        void setData(Optional<PasteboardCustomData>&&, size_t index);
     96        void didSetAllData();
     97        void reject();
     98
     99        WeakPtr<Clipboard> m_clipboard;
     100        Vector<Optional<PasteboardCustomData>> m_dataToWrite;
     101        RefPtr<DeferredPromise> m_promise;
     102        unsigned m_pendingItemCount;
     103        std::unique_ptr<Pasteboard> m_pasteboard;
     104#if PLATFORM(COCOA)
     105        int64_t m_changeCountAtStart { 0 };
     106#endif
     107    };
     108
     109    void didResolveOrReject(ItemWriter&);
     110
    78111    Optional<Session> m_activeSession;
    79112    WeakPtr<Navigator> m_navigator;
     113    Vector<Optional<PasteboardCustomData>> m_dataToWrite;
     114    RefPtr<ItemWriter> m_activeItemWriter;
    80115};
    81116
  • trunk/Source/WebCore/platform/ios/PlatformPasteboardIOS.mm

    r251421 r252450  
    600600
    601601    data.forEachPlatformString([&] (auto& type, auto& value) {
     602        if (!value)
     603            return;
     604
    602605        NSString *stringValue = value;
    603         if (!stringValue.length)
    604             return;
    605 
    606606        auto cocoaType = PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type).createCFString();
    607607        if (UTTypeConformsTo(cocoaType.get(), kUTTypeURL))
  • trunk/Source/WebCore/platform/mac/PlatformPasteboardMac.mm

    r251421 r252450  
    227227    NSMutableArray *types = [NSMutableArray array];
    228228    data.forEachType([&] (auto& type) {
    229         [types addObject:platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type)];
     229        NSString *platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type);
     230        if (platformType.length)
     231            [types addObject:platformType];
    230232    });
    231233
  • trunk/Tools/ChangeLog

    r252449 r252450  
     12019-11-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [Clipboard API] Add support for Clipboard.write()
     4        https://bugs.webkit.org/show_bug.cgi?id=204078
     5        <rdar://problem/57087756>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Make the LocalPasteboard in WebKitTestRunner compatible with calls to -writeObjects: with a list of pasteboard
     10        items. Currently, attempts to -writeObjects: result in a crash, since NSPasteboard code will attempt to
     11        communicate with pasted and fail. We fix this by implementing -writeObjects: and storing the array of
     12        NSPasteboardItems in LocalPasteboard, the same way we do in DumpRenderTree's LocalPasteboard implementation.
     13
     14        * DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
     15        (-[LocalPasteboard declareTypes:owner:]):
     16        (-[LocalPasteboard _clearContentsWithoutUpdatingChangeCount]):
     17
     18        Factor out logic to clear the pasteboard's content into a separate helper, and clear out the list of saved
     19        pasteboard items here as well.
     20
     21        (-[LocalPasteboard clearContents]):
     22
     23        Implement -clearContents in DumpRenderTree's LocalPasteboard, so that we can test Clipboard.write() in WebKit1.
     24
     25        (-[LocalPasteboard writeObjects:]):
     26
     27        Also make it so that we save any NSPasteboardItems we write to the local pasteboard, so that we can return them
     28        later in -pasteboardItems.
     29
     30        (-[LocalPasteboard pasteboardItems]):
     31        * WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm:
     32        (-[LocalPasteboard initWithName:]):
     33
     34        Clean up this code a bit by replacing manual reference counting for `typesArray` and its neighboring data
     35        structures with `RetainPtr`. Additionally, underscore-prefix the instance variables on LocalPasteboard to match
     36        most of the other Objective-C objects in WebKit.
     37
     38        (-[LocalPasteboard name]):
     39        (-[LocalPasteboard _clearContentsWithoutUpdatingChangeCount]):
     40
     41        Clear out the NSPasteboardItem list here too.
     42
     43        (-[LocalPasteboard clearContents]):
     44        (-[LocalPasteboard declareTypes:owner:]):
     45        (-[LocalPasteboard addTypes:owner:]):
     46        (-[LocalPasteboard _addTypesWithoutUpdatingChangeCount:owner:]):
     47        (-[LocalPasteboard changeCount]):
     48        (-[LocalPasteboard types]):
     49        (-[LocalPasteboard availableTypeFromArray:]):
     50        (-[LocalPasteboard setData:forType:]):
     51        (-[LocalPasteboard dataForType:]):
     52        (-[LocalPasteboard pasteboardItems]):
     53        (-[LocalPasteboard writeObjects:]):
     54
     55        Implement this by porting over the implementation that currently exists in DumpRenderTree. Like in
     56        DumpRenderTree, we want to also save the NSPasteboardItem array we're given here, so that we can return it in
     57        -pasteboardItems.
     58
     59        (-[LocalPasteboard dealloc]): Deleted.
     60
    1612019-11-13  Megan Gardner  <megan_gardner@apple.com>
    262
  • trunk/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm

    r251377 r252450  
    4646    RetainPtr<id> _owner;
    4747    RetainPtr<NSString> _pasteboardName;
     48    RetainPtr<NSMutableArray<NSPasteboardItem *>> _writtenPasteboardItems;
    4849    NSInteger _changeCount;
    4950
     
    121122- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
    122123{
    123     _types.clear();
    124     _data.clear();
     124    [self _clearContentsWithoutUpdatingChangeCount];
    125125
    126126    [self _addTypesWithoutUpdatingChangeCount:newTypes owner:newOwner];
     
    141141
    142142    return adoptCF(UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (__bridge CFStringRef)type, nullptr));
     143}
     144
     145- (void)_clearContentsWithoutUpdatingChangeCount
     146{
     147    _writtenPasteboardItems = nil;
     148    _types.clear();
     149    _data.clear();
     150}
     151
     152- (NSInteger)clearContents
     153{
     154    [self _clearContentsWithoutUpdatingChangeCount];
     155    return ++_changeCount;
    143156}
    144157
     
    227240- (BOOL)writeObjects:(NSArray<id <NSPasteboardWriting>> *)objects
    228241{
     242    _writtenPasteboardItems = adoptNS([[NSMutableArray<NSPasteboardItem *> alloc] initWithCapacity:objects.count]);
    229243    for (id <NSPasteboardWriting> object in objects) {
     244        ASSERT([object isKindOfClass:NSPasteboardItem.class]);
     245        [_writtenPasteboardItems addObject:(NSPasteboardItem *)object];
    230246        for (NSString *type in [object writableTypesForPasteboard:self]) {
    231             ASSERT(UTTypeIsDeclared((__bridge CFStringRef)type) || UTTypeIsDynamic((__bridge CFStringRef)type));
    232 
    233247            [self addTypes:@[ type ] owner:self];
    234248
     
    246260- (NSArray<NSPasteboardItem *> *)pasteboardItems
    247261{
     262    if (_writtenPasteboardItems)
     263        return _writtenPasteboardItems.get();
     264
    248265    auto item = adoptNS([[NSPasteboardItem alloc] init]);
    249266    for (const auto& typeAndData : _data) {
  • trunk/Tools/WebKitTestRunner/mac/WebKitTestRunnerPasteboard.mm

    r251377 r252450  
    3535@interface LocalPasteboard : NSPasteboard
    3636{
    37     NSMutableArray *typesArray;
    38     NSMutableSet *typesSet;
    39     NSMutableDictionary *dataByType;
    40     NSInteger changeCount;
    41     NSString *pasteboardName;
     37    RetainPtr<NSMutableArray> _typesArray;
     38    RetainPtr<NSMutableSet> _typesSet;
     39    RetainPtr<NSMutableArray<NSPasteboardItem *>> _writtenPasteboardItems;
     40    RetainPtr<NSMutableDictionary> _dataByType;
     41    NSInteger _changeCount;
     42    RetainPtr<NSString> _pasteboardName;
    4243}
    4344
     
    100101    if (!self)
    101102        return nil;
    102     typesArray = [[NSMutableArray alloc] init];
    103     typesSet = [[NSMutableSet alloc] init];
    104     dataByType = [[NSMutableDictionary alloc] init];
    105     pasteboardName = [name copy];
     103    _typesArray = adoptNS([[NSMutableArray alloc] init]);
     104    _typesSet = adoptNS([[NSMutableSet alloc] init]);
     105    _dataByType = adoptNS([[NSMutableDictionary alloc] init]);
     106    _pasteboardName = adoptNS([name copy]);
    106107    return self;
    107108}
    108109
    109 - (void)dealloc
    110 {
    111     [typesArray release];
    112     [typesSet release];
    113     [dataByType release];
    114     [pasteboardName release];
    115     [super dealloc];
    116 }
    117 
    118110- (NSString *)name
    119111{
    120     return pasteboardName;
     112    return _pasteboardName.get();
    121113}
    122114
     
    127119- (void)_clearContentsWithoutUpdatingChangeCount
    128120{
    129     [typesArray removeAllObjects];
    130     [typesSet removeAllObjects];
    131     [dataByType removeAllObjects];
     121    _writtenPasteboardItems = nil;
     122    [_typesArray removeAllObjects];
     123    [_typesSet removeAllObjects];
     124    [_dataByType removeAllObjects];
    132125}
    133126
     
    135128{
    136129    [self _clearContentsWithoutUpdatingChangeCount];
    137     return ++changeCount;
     130    return ++_changeCount;
    138131}
    139132
     
    142135    [self _clearContentsWithoutUpdatingChangeCount];
    143136    [self _addTypesWithoutUpdatingChangeCount:newTypes owner:newOwner];
    144     return ++changeCount;
     137    return ++_changeCount;
    145138}
    146139
     
    150143    // FIXME: Ideally, we would keep track of the current owner and only bump the change
    151144    // count if the new owner is different.
    152     return ++changeCount;
     145    return ++_changeCount;
    153146}
    154147
     
    159152    for (i = 0; i < count; ++i) {
    160153        NSString *type = [newTypes objectAtIndex:i];
    161         NSString *setType = [typesSet member:type];
     154        NSString *setType = [_typesSet member:type];
    162155        if (!setType) {
    163156            setType = [type copy];
    164             [typesArray addObject:setType];
    165             [typesSet addObject:setType];
     157            [_typesArray addObject:setType];
     158            [_typesSet addObject:setType];
    166159            [setType release];
    167160        }
     
    173166- (NSInteger)changeCount
    174167{
    175     return changeCount;
     168    return _changeCount;
    176169}
    177170
    178171- (NSArray *)types
    179172{
    180     return typesArray;
     173    return _typesArray.get();
    181174}
    182175
     
    184177{
    185178    for (NSString *type in types) {
    186         if (NSString *setType = [typesSet member:type])
     179        if (NSString *setType = [_typesSet member:type])
    187180            return setType;
    188181    }
     
    192185- (BOOL)setData:(NSData *)data forType:(NSString *)dataType
    193186{
    194     if (![typesSet containsObject:dataType])
     187    if (![_typesSet containsObject:dataType])
    195188        return NO;
    196189    if (!data)
    197190        data = [NSData data];
    198     [dataByType setObject:data forKey:dataType];
    199     ++changeCount;
     191    [_dataByType setObject:data forKey:dataType];
     192    ++_changeCount;
    200193    return YES;
    201194}
     
    203196- (NSData *)dataForType:(NSString *)dataType
    204197{
    205     return [dataByType objectForKey:dataType];
     198    return [_dataByType objectForKey:dataType];
    206199}
    207200
     
    221214- (NSArray<NSPasteboardItem *> *)pasteboardItems
    222215{
     216    if (_writtenPasteboardItems)
     217        return _writtenPasteboardItems.get();
     218
    223219    auto item = adoptNS([[NSPasteboardItem alloc] init]);
    224     for (NSString *type in dataByType)
    225         [item setData:dataByType[type] forType:[NSPasteboard _modernPasteboardType:type]];
     220    for (NSString *type in _typesArray.get()) {
     221        NSPasteboardType modernPasteboardType = [NSPasteboard _modernPasteboardType:type];
     222        if (NSData *dataForType = [_dataByType objectForKey:type] ?: [_dataByType objectForKey:modernPasteboardType])
     223            [item setData:dataForType forType:modernPasteboardType];
     224    }
    226225    return @[ item.get() ];
    227226}
    228227
     228- (BOOL)writeObjects:(NSArray<id <NSPasteboardWriting>> *)objects
     229{
     230    _writtenPasteboardItems = adoptNS([[NSMutableArray<NSPasteboardItem *> alloc] initWithCapacity:objects.count]);
     231    for (id <NSPasteboardWriting> object in objects) {
     232        ASSERT([object isKindOfClass:NSPasteboardItem.class]);
     233        [_writtenPasteboardItems addObject:(NSPasteboardItem *)object];
     234        NSArray<NSPasteboardType> *writableTypes = [object writableTypesForPasteboard:self];
     235        for (NSString *type in writableTypes) {
     236            [self addTypes:@[type] owner:self];
     237
     238            id propertyList = [object pasteboardPropertyListForType:type];
     239            if ([propertyList isKindOfClass:NSData.class])
     240                [self setData:propertyList forType:type];
     241            else
     242                ASSERT_NOT_REACHED();
     243        }
     244    }
     245
     246    return YES;
     247}
     248
    229249@end
Note: See TracChangeset for help on using the changeset viewer.