[Clipboard API] Support writing multiple PasteboardCustomData with SharedBuffers...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Oct 2019 21:52:26 +0000 (21:52 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Oct 2019 21:52:26 +0000 (21:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202851

Reviewed by Darin Adler.

Source/WebCore:

This patch refactors some logic around WebCore::PasteboardCustomData, in preparation for implementing the async
clipboard API. There are two main goals of this refactoring:

1. Enable writing multiple items (each backed by PasteboardCustomData) to the platform pasteboard.
2. Enable writing platform data in the form of SharedBuffers to the platform pasteboard.

See below for more details; no tests, as there is no change in behavior yet.

* Headers.cmake:
* Sources.txt:
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:

Move PasteboardCustomData out of Pasteboard.h and into its own file.

* dom/DataTransfer.cpp:
(WebCore::DataTransfer::commitToPasteboard):
* editing/cocoa/EditorCocoa.mm:
(WebCore::Editor::getPasteboardTypesAndDataForAttachment):
* platform/Pasteboard.cpp:
(WebCore::PasteboardCustomData::createSharedBuffer const): Deleted.
(WebCore::PasteboardCustomData::fromSharedBuffer): Deleted.

Moved these method implementations to PasteboardCustomData.cpp.

* platform/Pasteboard.h:

Refactor PasteboardCustomData so that its member variables are now private, and encapsulated behind methods
Additionally, make it so that the only way to set data on PasteboardCustomData is to use the writeString,
writeData, and writeStringInCustomData methods, which ensure that the PasteboardCustomData is always in a
consistent state.

* platform/PasteboardCustomData.cpp: Added.
(WebCore::copyPlatformData):
(WebCore::PasteboardCustomData::Entry::Entry):
(WebCore::PasteboardCustomData::Entry::operator=):

Refactor the implementation of PasteboardCustomData, so that it contains a list of PasteboardCustomData entries
instead of individual Vectors and HashMaps.

(WebCore::PasteboardCustomData::PasteboardCustomData):
(WebCore::PasteboardCustomData::createSharedBuffer const):
(WebCore::PasteboardCustomData::fromSharedBuffer):
(WebCore::PasteboardCustomData::writeString):
(WebCore::PasteboardCustomData::writeData):
(WebCore::PasteboardCustomData::writeStringInCustomData):
(WebCore::PasteboardCustomData::addOrMoveEntryToEnd):

Move logic from StaticPasteboard into PasteboardCustomData, and refactor these methods to handle
Vector<PasteboardCustomData::Entry>.

(WebCore::PasteboardCustomData::clear):
(WebCore::PasteboardCustomData::operator=):
(WebCore::PasteboardCustomData::orderedTypes const):
(WebCore::PasteboardCustomData::hasData const):
(WebCore::PasteboardCustomData::hasSameOriginCustomData const):
(WebCore::PasteboardCustomData::sameOriginCustomStringData const):
(WebCore::PasteboardCustomData::readBuffer const):
(WebCore::PasteboardCustomData::readString const):
(WebCore::PasteboardCustomData::readStringInCustomData const):
(WebCore::PasteboardCustomData::forEachType const):
(WebCore::PasteboardCustomData::forEachPlatformString const):
(WebCore::PasteboardCustomData::forEachCustomString const):
(WebCore::PasteboardCustomData::forEachPlatformStringOrBuffer const):

Moved these method implementations from StaticPasteboard to PasteboardCustomData, and also introduced some new
methods to help iterate through types and data.

* platform/PasteboardCustomData.h: Added.
(WebCore::PasteboardCustomData::origin const):
(WebCore::PasteboardCustomData::setOrigin):
(WebCore::PasteboardCustomData::data const):
* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/SharedBuffer.cpp:
(WebCore::SharedBuffer::decoder const):
* platform/SharedBuffer.h:
* platform/StaticPasteboard.cpp:
(WebCore::StaticPasteboard::hasData):
(WebCore::StaticPasteboard::typesSafeForBindings):
(WebCore::StaticPasteboard::typesForLegacyUnsafeBindings):
(WebCore::StaticPasteboard::readString):
(WebCore::StaticPasteboard::readStringInCustomData):
(WebCore::StaticPasteboard::writeString):
(WebCore::StaticPasteboard::writeData):
(WebCore::StaticPasteboard::writeStringInCustomData):
(WebCore::StaticPasteboard::clear):
(WebCore::StaticPasteboard::takeCustomData):
(WebCore::StaticPasteboard::StaticPasteboard): Deleted.

Refactor StaticPasteboard to now contain a PasteboardCustomData; additionally, adjust several methods in
StaticPasteboard to simply call into PasteboardCustomData to write, read, or clear data.

(WebCore::updateTypes): Deleted.
* platform/StaticPasteboard.h:
* platform/cocoa/PasteboardCocoa.mm:
(WebCore::Pasteboard::readStringInCustomData):
(WebCore::Pasteboard::readOrigin):
(WebCore::PasteboardCustomData::cocoaType): Deleted.

Moved the implementation of PasteboardCustomData::cocoaType from PasteboardCocoa.mm to
PasteboardCustomDataCocoa.mm.

* platform/cocoa/PasteboardCustomDataCocoa.mm: Added.
(WebCore::PasteboardCustomData::cocoaType):
* platform/ios/AbstractPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::changeCount const):
(WebCore::registerItemsToPasteboard):
(WebCore::registerItemToPasteboard):
(WebCore::PlatformPasteboard::write):

Support writing multiple PasteboardCustomData objects to the platform pasteboard on iOS, by generating
NSItemProviders for each one. This refactors the existing `registerItemToPasteboard` helper to handle multiple
registration lists, renames it to `registerItemsToPasteboard` (plural), and then reimplements
`registerItemToPasteboard` in terms of `registerItemsToPasteboard`.

(WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
(WebCore::createItemProviderRegistrationList):

Adjust these to use getters on PasteboardCustomData instead of accessing the member variables directly.

* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard init]):
(-[WebItemProviderPasteboard stageRegistrationLists:]):
(-[WebItemProviderPasteboard clearRegistrationLists]):
(-[WebItemProviderPasteboard takeRegistrationLists]):

Refactor registration list staging on WebItemProviderPasteboard to support multiple registration lists, each
representing a single item provider.

(-[WebItemProviderPasteboard stageRegistrationList:]): Deleted.
(-[WebItemProviderPasteboard takeRegistrationList]): Deleted.
* platform/mac/PasteboardMac.mm:
(WebCore::Pasteboard::write):
* platform/mac/PasteboardWriter.mm:
(WebCore::createPasteboardWriter):
* platform/mac/PlatformPasteboardMac.mm:
(WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
(WebCore::PlatformPasteboard::write):

Support writing multiple PasteboardCustomData objects to the platform pasteboard on macOS, by creating and
setting NSPasteboardItems for each custom data. This means that instead of using legacy macOS pasteboard types,
we need to use the "modern" NSPasteboardTypes when writing each item. This is because NSPasteboardItem quietly
fails when attempting to set data for a legacy pasteboard type.

(WebCore::createPasteboardItem):

Source/WebKit:

See WebCore ChangeLog for more details.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<PasteboardCustomData::Entry>::encode):
(IPC::ArgumentCoder<PasteboardCustomData::Entry>::decode):

Add helpers to encode and decode PasteboardCustomData::Entry.

(IPC::ArgumentCoder<PasteboardCustomData>::encode):
(IPC::ArgumentCoder<PasteboardCustomData>::decode):
* Shared/WebCoreArgumentCoders.h:

Add support for encoding and decoding PasteboardCustomData by encoding and decoding each of its items (see
above).

* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::requestDOMPasteAccess):
* UIProcess/WebPasteboardProxy.h:
* UIProcess/WebPasteboardProxy.messages.in:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView canPerformActionForWebView:withSender:]):
(allPasteboardItemOriginsMatchOrigin):
(-[WKContentView _didHandleAdditionalDragItemsRequest:]):

Tweak several methods to use the new methods on PasteboardCustomData instead of accessing the member variables
directly.

(-[WKContentView cleanUpDragSourceSessionState]):
(-[WKContentView _prepareToDragPromisedAttachment:]):
(-[WKContentView _itemsForBeginningOrAddingToSessionWithRegistrationLists:stagedDragSource:]):
(-[WKContentView dragInteraction:itemsForBeginningSession:]):
(-[WKContentView _itemsForBeginningOrAddingToSessionWithRegistrationList:stagedDragSource:]): Deleted.

Adjust these methods to handle multiple staged item providers (for now, it remains that iOS drag and drop
codepaths will still only write a single item to the pasteboard).

Source/WebKitLegacy/mac:

See WebCore ChangeLog for more details.

* WebCoreSupport/WebPlatformStrategies.h:

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

34 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/Sources.txt
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/editing/cocoa/EditorCocoa.mm
Source/WebCore/platform/Pasteboard.cpp
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/PasteboardCustomData.cpp [new file with mode: 0644]
Source/WebCore/platform/PasteboardCustomData.h [new file with mode: 0644]
Source/WebCore/platform/PasteboardStrategy.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/SharedBuffer.cpp
Source/WebCore/platform/SharedBuffer.h
Source/WebCore/platform/StaticPasteboard.cpp
Source/WebCore/platform/StaticPasteboard.h
Source/WebCore/platform/cocoa/PasteboardCocoa.mm
Source/WebCore/platform/cocoa/PasteboardCustomDataCocoa.mm [new file with mode: 0644]
Source/WebCore/platform/ios/AbstractPasteboard.h
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebCore/platform/ios/WebItemProviderPasteboard.mm
Source/WebCore/platform/mac/PasteboardMac.mm
Source/WebCore/platform/mac/PasteboardWriter.mm
Source/WebCore/platform/mac/PlatformPasteboardMac.mm
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebCoreArgumentCoders.cpp
Source/WebKit/Shared/WebCoreArgumentCoders.h
Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
Source/WebKit/UIProcess/WebPasteboardProxy.h
Source/WebKit/UIProcess/WebPasteboardProxy.messages.in
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.h

index d83d776..1cbc88e 100644 (file)
@@ -1,3 +1,158 @@
+2019-10-14  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Support writing multiple PasteboardCustomData with SharedBuffers to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=202851
+
+        Reviewed by Darin Adler.
+
+        This patch refactors some logic around WebCore::PasteboardCustomData, in preparation for implementing the async
+        clipboard API. There are two main goals of this refactoring:
+
+        1. Enable writing multiple items (each backed by PasteboardCustomData) to the platform pasteboard.
+        2. Enable writing platform data in the form of SharedBuffers to the platform pasteboard.
+
+        See below for more details; no tests, as there is no change in behavior yet.
+
+        * Headers.cmake:
+        * Sources.txt:
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        Move PasteboardCustomData out of Pasteboard.h and into its own file.
+
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::commitToPasteboard):
+        * editing/cocoa/EditorCocoa.mm:
+        (WebCore::Editor::getPasteboardTypesAndDataForAttachment):
+        * platform/Pasteboard.cpp:
+        (WebCore::PasteboardCustomData::createSharedBuffer const): Deleted.
+        (WebCore::PasteboardCustomData::fromSharedBuffer): Deleted.
+
+        Moved these method implementations to PasteboardCustomData.cpp.
+
+        * platform/Pasteboard.h:
+
+        Refactor PasteboardCustomData so that its member variables are now private, and encapsulated behind methods
+        Additionally, make it so that the only way to set data on PasteboardCustomData is to use the writeString,
+        writeData, and writeStringInCustomData methods, which ensure that the PasteboardCustomData is always in a
+        consistent state.
+
+        * platform/PasteboardCustomData.cpp: Added.
+        (WebCore::copyPlatformData):
+        (WebCore::PasteboardCustomData::Entry::Entry):
+        (WebCore::PasteboardCustomData::Entry::operator=):
+
+        Refactor the implementation of PasteboardCustomData, so that it contains a list of PasteboardCustomData entries
+        instead of individual Vectors and HashMaps.
+
+        (WebCore::PasteboardCustomData::PasteboardCustomData):
+        (WebCore::PasteboardCustomData::createSharedBuffer const):
+        (WebCore::PasteboardCustomData::fromSharedBuffer):
+        (WebCore::PasteboardCustomData::writeString):
+        (WebCore::PasteboardCustomData::writeData):
+        (WebCore::PasteboardCustomData::writeStringInCustomData):
+        (WebCore::PasteboardCustomData::addOrMoveEntryToEnd):
+
+        Move logic from StaticPasteboard into PasteboardCustomData, and refactor these methods to handle
+        Vector<PasteboardCustomData::Entry>.
+
+        (WebCore::PasteboardCustomData::clear):
+        (WebCore::PasteboardCustomData::operator=):
+        (WebCore::PasteboardCustomData::orderedTypes const):
+        (WebCore::PasteboardCustomData::hasData const):
+        (WebCore::PasteboardCustomData::hasSameOriginCustomData const):
+        (WebCore::PasteboardCustomData::sameOriginCustomStringData const):
+        (WebCore::PasteboardCustomData::readBuffer const):
+        (WebCore::PasteboardCustomData::readString const):
+        (WebCore::PasteboardCustomData::readStringInCustomData const):
+        (WebCore::PasteboardCustomData::forEachType const):
+        (WebCore::PasteboardCustomData::forEachPlatformString const):
+        (WebCore::PasteboardCustomData::forEachCustomString const):
+        (WebCore::PasteboardCustomData::forEachPlatformStringOrBuffer const):
+
+        Moved these method implementations from StaticPasteboard to PasteboardCustomData, and also introduced some new
+        methods to help iterate through types and data.
+
+        * platform/PasteboardCustomData.h: Added.
+        (WebCore::PasteboardCustomData::origin const):
+        (WebCore::PasteboardCustomData::setOrigin):
+        (WebCore::PasteboardCustomData::data const):
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/SharedBuffer.cpp:
+        (WebCore::SharedBuffer::decoder const):
+        * platform/SharedBuffer.h:
+        * platform/StaticPasteboard.cpp:
+        (WebCore::StaticPasteboard::hasData):
+        (WebCore::StaticPasteboard::typesSafeForBindings):
+        (WebCore::StaticPasteboard::typesForLegacyUnsafeBindings):
+        (WebCore::StaticPasteboard::readString):
+        (WebCore::StaticPasteboard::readStringInCustomData):
+        (WebCore::StaticPasteboard::writeString):
+        (WebCore::StaticPasteboard::writeData):
+        (WebCore::StaticPasteboard::writeStringInCustomData):
+        (WebCore::StaticPasteboard::clear):
+        (WebCore::StaticPasteboard::takeCustomData):
+        (WebCore::StaticPasteboard::StaticPasteboard): Deleted.
+
+        Refactor StaticPasteboard to now contain a PasteboardCustomData; additionally, adjust several methods in
+        StaticPasteboard to simply call into PasteboardCustomData to write, read, or clear data.
+
+        (WebCore::updateTypes): Deleted.
+        * platform/StaticPasteboard.h:
+        * platform/cocoa/PasteboardCocoa.mm:
+        (WebCore::Pasteboard::readStringInCustomData):
+        (WebCore::Pasteboard::readOrigin):
+        (WebCore::PasteboardCustomData::cocoaType): Deleted.
+
+        Moved the implementation of PasteboardCustomData::cocoaType from PasteboardCocoa.mm to
+        PasteboardCustomDataCocoa.mm.
+
+        * platform/cocoa/PasteboardCustomDataCocoa.mm: Added.
+        (WebCore::PasteboardCustomData::cocoaType):
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::changeCount const):
+        (WebCore::registerItemsToPasteboard):
+        (WebCore::registerItemToPasteboard):
+        (WebCore::PlatformPasteboard::write):
+
+        Support writing multiple PasteboardCustomData objects to the platform pasteboard on iOS, by generating
+        NSItemProviders for each one. This refactors the existing `registerItemToPasteboard` helper to handle multiple
+        registration lists, renames it to `registerItemsToPasteboard` (plural), and then reimplements
+        `registerItemToPasteboard` in terms of `registerItemsToPasteboard`.
+
+        (WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
+        (WebCore::createItemProviderRegistrationList):
+
+        Adjust these to use getters on PasteboardCustomData instead of accessing the member variables directly.
+
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderPasteboard init]):
+        (-[WebItemProviderPasteboard stageRegistrationLists:]):
+        (-[WebItemProviderPasteboard clearRegistrationLists]):
+        (-[WebItemProviderPasteboard takeRegistrationLists]):
+
+        Refactor registration list staging on WebItemProviderPasteboard to support multiple registration lists, each
+        representing a single item provider.
+
+        (-[WebItemProviderPasteboard stageRegistrationList:]): Deleted.
+        (-[WebItemProviderPasteboard takeRegistrationList]): Deleted.
+        * platform/mac/PasteboardMac.mm:
+        (WebCore::Pasteboard::write):
+        * platform/mac/PasteboardWriter.mm:
+        (WebCore::createPasteboardWriter):
+        * platform/mac/PlatformPasteboardMac.mm:
+        (WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
+        (WebCore::PlatformPasteboard::write):
+
+        Support writing multiple PasteboardCustomData objects to the platform pasteboard on macOS, by creating and
+        setting NSPasteboardItems for each custom data. This means that instead of using legacy macOS pasteboard types,
+        we need to use the "modern" NSPasteboardTypes when writing each item. This is because NSPasteboardItem quietly
+        fails when attempting to set data for a legacy pasteboard type.
+
+        (WebCore::createPasteboardItem):
+
 2019-10-14  Truitt Savell  <tsavell@apple.com>
 
         Unreviewed, rolling out r251081.
index ae81fb5..9c2b204 100644 (file)
@@ -929,6 +929,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/PODIntervalTree.h
     platform/PODRedBlackTree.h
     platform/Pasteboard.h
+    platform/PasteboardCustomData.h
     platform/PasteboardItemInfo.h
     platform/PasteboardStrategy.h
     platform/PasteboardWriterData.h
index a3a3729..8a4983b 100644 (file)
@@ -1725,6 +1725,7 @@ platform/MIMETypeRegistry.cpp
 platform/MainThreadSharedTimer.cpp
 platform/NotImplemented.cpp
 platform/Pasteboard.cpp
+platform/PasteboardCustomData.cpp
 platform/PasteboardWriterData.cpp
 platform/PlatformKeyboardEvent.cpp
 platform/PlatformSpeechSynthesisUtterance.cpp
index d84847c..12ff11d 100644 (file)
@@ -198,6 +198,7 @@ platform/cocoa/MIMETypeRegistryCocoa.mm
 platform/cocoa/NetworkExtensionContentFilter.mm
 platform/cocoa/ParentalControlsContentFilter.mm
 platform/cocoa/PasteboardCocoa.mm
+platform/cocoa/PasteboardCustomDataCocoa.mm
 platform/cocoa/PlatformPasteboardCocoa.mm
 platform/cocoa/PlaybackSessionModelMediaElement.mm
 platform/cocoa/RuntimeApplicationChecksCocoa.mm
index 545ad58..cbd44b6 100644 (file)
                F4D43D662188038B00ECECAC /* SerializedAttachmentData.h in Headers */ = {isa = PBXBuildFile; fileRef = F4D43D64218802E600ECECAC /* SerializedAttachmentData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F4E57EDC213F3F5F004EA98E /* FontAttributeChanges.h in Headers */ = {isa = PBXBuildFile; fileRef = F4E57EDA213F3F5F004EA98E /* FontAttributeChanges.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F4E57EE1213F434A004EA98E /* WebCoreNSFontManagerExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = F4E57EDF213F434A004EA98E /* WebCoreNSFontManagerExtras.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               F4FB34FC2350C85D00F0094A /* PasteboardCustomData.h in Headers */ = {isa = PBXBuildFile; fileRef = F4FB34FA2350C85D00F0094A /* PasteboardCustomData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F50664F8157F52DC00AC226F /* FormController.h in Headers */ = {isa = PBXBuildFile; fileRef = F50664F6157F52DC00AC226F /* FormController.h */; };
                F513A3EA15FF4841001526DB /* ValidationMessageClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F513A3E915FF4841001526DB /* ValidationMessageClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F544F78915CFB2A800AF33A8 /* PlatformLocale.h in Headers */ = {isa = PBXBuildFile; fileRef = F544F78715CFB2A800AF33A8 /* PlatformLocale.h */; };
                F4E57EDA213F3F5F004EA98E /* FontAttributeChanges.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FontAttributeChanges.h; sourceTree = "<group>"; };
                F4E57EDF213F434A004EA98E /* WebCoreNSFontManagerExtras.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebCoreNSFontManagerExtras.h; sourceTree = "<group>"; };
                F4E57EE0213F434A004EA98E /* WebCoreNSFontManagerExtras.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreNSFontManagerExtras.mm; sourceTree = "<group>"; };
+               F4FB34FA2350C85D00F0094A /* PasteboardCustomData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteboardCustomData.h; sourceTree = "<group>"; };
+               F4FB34FB2350C85D00F0094A /* PasteboardCustomData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PasteboardCustomData.cpp; sourceTree = "<group>"; };
+               F4FB35002350C96200F0094A /* PasteboardCustomDataCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteboardCustomDataCocoa.mm; sourceTree = "<group>"; };
                F50664F5157F52DC00AC226F /* FormController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormController.cpp; sourceTree = "<group>"; };
                F50664F6157F52DC00AC226F /* FormController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormController.h; sourceTree = "<group>"; };
                F513A3E915FF4841001526DB /* ValidationMessageClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValidationMessageClient.h; sourceTree = "<group>"; };
                                A18890AD1AA13F250026C301 /* ParentalControlsContentFilter.h */,
                                A18890AC1AA13F250026C301 /* ParentalControlsContentFilter.mm */,
                                9BED2CAF1F7CC06200666018 /* PasteboardCocoa.mm */,
+                               F4FB35002350C96200F0094A /* PasteboardCustomDataCocoa.mm */,
                                F4628A9E234D3BBF00BC884C /* PlatformPasteboardCocoa.mm */,
                                52B0D4BD1C57FD1E0077CE53 /* PlatformView.h */,
                                CDA29A081CBD99F400901CCF /* PlaybackSessionInterface.h */,
                                4184F5151EAF059800F18BF0 /* OrientationNotifier.h */,
                                2EE02A1E1F7324280006AF72 /* Pasteboard.cpp */,
                                4B2708C50AF19EE40065127F /* Pasteboard.h */,
+                               F4FB34FB2350C85D00F0094A /* PasteboardCustomData.cpp */,
+                               F4FB34FA2350C85D00F0094A /* PasteboardCustomData.h */,
                                F49786871FF45FA500E060AB /* PasteboardItemInfo.h */,
                                C5F765B414E1D414006C899B /* PasteboardStrategy.h */,
                                1AF5E4D21E56735A004A1F01 /* PasteboardWriterData.cpp */,
                                536D5A23193E8E0C00CE4CAB /* ParsingUtilities.h in Headers */,
                                F55B3DCA1251F12D003EF269 /* PasswordInputType.h in Headers */,
                                4B2708C70AF19EE40065127F /* Pasteboard.h in Headers */,
+                               F4FB34FC2350C85D00F0094A /* PasteboardCustomData.h in Headers */,
                                F49786881FF45FA500E060AB /* PasteboardItemInfo.h in Headers */,
                                C598905714E9C28000E8D18B /* PasteboardStrategy.h in Headers */,
                                1AF5E4E31E5779B1004A1F01 /* PasteboardWriter.h in Headers */,
index 5c71b36..0d47b73 100644 (file)
@@ -426,15 +426,18 @@ void DataTransfer::commitToPasteboard(Pasteboard& nativePasteboard)
     ASSERT(is<StaticPasteboard>(*m_pasteboard) && !is<StaticPasteboard>(nativePasteboard));
     PasteboardCustomData customData = downcast<StaticPasteboard>(*m_pasteboard).takeCustomData();
     if (RuntimeEnabledFeatures::sharedFeatures().customPasteboardDataEnabled()) {
-        customData.origin = m_originIdentifier;
+        customData.setOrigin(m_originIdentifier);
         nativePasteboard.writeCustomData(customData);
         return;
     }
 
-    for (auto& entry : customData.platformData)
-        nativePasteboard.writeString(entry.key, entry.value);
-    for (auto& entry : customData.sameOriginCustomData)
-        nativePasteboard.writeString(entry.key, entry.value);
+    customData.forEachPlatformString([&] (auto& type, auto& string) {
+        nativePasteboard.writeString(type, string);
+    });
+
+    customData.forEachCustomString([&] (auto& type, auto& string) {
+        nativePasteboard.writeString(type, string);
+    });
 }
 
 #if !ENABLE(DRAG_SUPPORT)
index f25f28c..ea1be54 100644 (file)
@@ -94,7 +94,7 @@ void Editor::getPasteboardTypesAndDataForAttachment(Element& element, Vector<Str
     client()->getClientPasteboardDataForRange(elementRange.ptr(), outTypes, outData);
 
     outTypes.append(PasteboardCustomData::cocoaType());
-    outData.append(PasteboardCustomData { document.originIdentifierForPasteboard(), { }, { }, { } }.createSharedBuffer());
+    outData.append(PasteboardCustomData { document.originIdentifierForPasteboard(), { } }.createSharedBuffer());
 
     if (auto archive = LegacyWebArchive::create(elementRange.ptr())) {
         if (auto webArchiveData = archive->rawDataRepresentation()) {
index 8f9bab8..e734b38 100644 (file)
@@ -30,8 +30,6 @@
 #include "PlatformStrategies.h"
 #include "Settings.h"
 #include "SharedBuffer.h"
-#include <wtf/URLParser.h>
-#include <wtf/persistence/PersistentCoders.h>
 #include <wtf/text/StringHash.h>
 
 namespace WebCore {
@@ -51,40 +49,6 @@ bool Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(const String& urlS
     return url.protocolIsInHTTPFamily() || url.protocolIsBlob() || url.protocolIsData();
 }
 
-Ref<SharedBuffer> PasteboardCustomData::createSharedBuffer() const
-{
-    const static unsigned currentCustomDataSerializationVersion = 1;
-
-    WTF::Persistence::Encoder encoder;
-    encoder << currentCustomDataSerializationVersion;
-    encoder << origin;
-    encoder << sameOriginCustomData;
-    encoder << orderedTypes;
-    return SharedBuffer::create(encoder.buffer(), encoder.bufferSize());
-}
-
-PasteboardCustomData PasteboardCustomData::fromSharedBuffer(const SharedBuffer& buffer)
-{
-    const static unsigned maxSupportedDataSerializationVersionNumber = 1;
-
-    PasteboardCustomData result;
-    WTF::Persistence::Decoder decoder { reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size() };
-    unsigned version;
-    if (!decoder.decode(version) || version > maxSupportedDataSerializationVersionNumber)
-        return { };
-
-    if (!decoder.decode(result.origin))
-        return { };
-
-    if (!decoder.decode(result.sameOriginCustomData))
-        return { };
-
-    if (!decoder.decode(result.orderedTypes))
-        return { };
-
-    return result;
-}
-
 #if !PLATFORM(COCOA)
 
 Vector<String> Pasteboard::readAllStrings(const String& type)
index 6987ed2..cbffca2 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "DragImage.h"
+#include "PasteboardCustomData.h"
 #include "PasteboardItemInfo.h"
 #include <wtf/HashMap.h>
 #include <wtf/ListHashSet.h>
@@ -161,21 +162,6 @@ struct PasteboardFileReader {
     virtual void readBuffer(const String& filename, const String& type, Ref<SharedBuffer>&&) = 0;
 };
 
-// FIXME: We need to ensure that the contents of sameOriginCustomData are not accessible across different origins.
-struct PasteboardCustomData {
-    String origin;
-    Vector<String> orderedTypes;
-    HashMap<String, String> platformData;
-    HashMap<String, String> sameOriginCustomData;
-
-    WEBCORE_EXPORT Ref<SharedBuffer> createSharedBuffer() const;
-    WEBCORE_EXPORT static PasteboardCustomData fromSharedBuffer(const SharedBuffer&);
-
-#if PLATFORM(COCOA)
-    WEBCORE_EXPORT static const char* cocoaType();
-#endif
-};
-
 class Pasteboard {
     WTF_MAKE_NONCOPYABLE(Pasteboard); WTF_MAKE_FAST_ALLOCATED;
 public:
diff --git a/Source/WebCore/platform/PasteboardCustomData.cpp b/Source/WebCore/platform/PasteboardCustomData.cpp
new file mode 100644 (file)
index 0000000..d254665
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "PasteboardCustomData.h"
+
+#include "SharedBuffer.h"
+#include <wtf/URLParser.h>
+#include <wtf/persistence/PersistentCoders.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+static Variant<String, Ref<SharedBuffer>> copyPlatformData(const Variant<String, Ref<SharedBuffer>>& other)
+{
+    if (WTF::holds_alternative<String>(other))
+        return { WTF::get<String>(other) };
+
+    if (WTF::holds_alternative<Ref<SharedBuffer>>(other))
+        return { WTF::get<Ref<SharedBuffer>>(other).copyRef() };
+
+    return { };
+}
+
+PasteboardCustomData::Entry::Entry(const Entry& entry)
+    : type(entry.type)
+    , customData(entry.customData)
+    , platformData(copyPlatformData(entry.platformData))
+{
+}
+
+PasteboardCustomData::Entry::Entry(const String& dataType)
+    : type(dataType)
+{
+}
+
+PasteboardCustomData::Entry::Entry() = default;
+PasteboardCustomData::Entry::Entry(Entry&&) = default;
+
+PasteboardCustomData::Entry& PasteboardCustomData::Entry::operator=(const Entry& entry)
+{
+    type = entry.type;
+    customData = entry.customData;
+    platformData = copyPlatformData(entry.platformData);
+    return *this;
+}
+
+PasteboardCustomData::Entry& PasteboardCustomData::Entry::operator=(Entry&&) = default;
+
+PasteboardCustomData::PasteboardCustomData() = default;
+PasteboardCustomData::PasteboardCustomData(const PasteboardCustomData&) = default;
+PasteboardCustomData::PasteboardCustomData(PasteboardCustomData&&) = default;
+PasteboardCustomData::~PasteboardCustomData() = default;
+
+PasteboardCustomData::PasteboardCustomData(String&& origin, Vector<Entry>&& data)
+    : m_origin(WTFMove(origin))
+    , m_data(WTFMove(data))
+{
+}
+
+Ref<SharedBuffer> PasteboardCustomData::createSharedBuffer() const
+{
+    constexpr unsigned currentCustomDataSerializationVersion = 1;
+
+    WTF::Persistence::Encoder encoder;
+    encoder << currentCustomDataSerializationVersion;
+    encoder << m_origin;
+    encoder << sameOriginCustomStringData();
+    encoder << orderedTypes();
+    return SharedBuffer::create(encoder.buffer(), encoder.bufferSize());
+}
+
+PasteboardCustomData PasteboardCustomData::fromSharedBuffer(const SharedBuffer& buffer)
+{
+    constexpr unsigned maxSupportedDataSerializationVersionNumber = 1;
+
+    PasteboardCustomData result;
+    auto decoder = buffer.decoder();
+    unsigned version;
+    if (!decoder.decode(version) || version > maxSupportedDataSerializationVersionNumber)
+        return { };
+
+    if (!decoder.decode(result.m_origin))
+        return { };
+
+    HashMap<String, String> sameOriginCustomStringData;
+    if (!decoder.decode(sameOriginCustomStringData))
+        return { };
+
+    Vector<String> orderedTypes;
+    if (!decoder.decode(orderedTypes))
+        return { };
+
+    for (auto& type : orderedTypes)
+        result.writeStringInCustomData(type, sameOriginCustomStringData.get(type));
+
+    return result;
+}
+
+void PasteboardCustomData::writeString(const String& type, const String& value)
+{
+    addOrMoveEntryToEnd(type).platformData = { value };
+}
+
+void PasteboardCustomData::writeData(const String& type, Ref<SharedBuffer>&& data)
+{
+    addOrMoveEntryToEnd(type).platformData = { WTFMove(data) };
+}
+
+void PasteboardCustomData::writeStringInCustomData(const String& type, const String& value)
+{
+    addOrMoveEntryToEnd(type).customData = value;
+}
+
+PasteboardCustomData::Entry& PasteboardCustomData::addOrMoveEntryToEnd(const String& type)
+{
+    auto index = m_data.findMatching([&] (auto& entry) {
+        return entry.type == type;
+    });
+    auto entry = index == notFound ? Entry(type) : m_data[index];
+    if (index != notFound)
+        m_data.remove(index);
+    m_data.append(WTFMove(entry));
+    return m_data.last();
+}
+
+void PasteboardCustomData::clear()
+{
+    m_data.clear();
+}
+
+void PasteboardCustomData::clear(const String& type)
+{
+    m_data.removeFirstMatching([&] (auto& entry) {
+        return entry.type == type;
+    });
+}
+
+PasteboardCustomData& PasteboardCustomData::operator=(const PasteboardCustomData& other)
+{
+    m_origin = other.origin();
+    m_data = other.m_data;
+    return *this;
+}
+
+Vector<String> PasteboardCustomData::orderedTypes() const
+{
+    return m_data.map([&] (auto& entry) {
+        return entry.type;
+    });
+}
+
+bool PasteboardCustomData::hasData() const
+{
+    return !m_data.isEmpty();
+}
+
+bool PasteboardCustomData::hasSameOriginCustomData() const
+{
+    return notFound != m_data.findMatching([&] (auto& entry) {
+        return !entry.customData.isNull();
+    });
+}
+
+HashMap<String, String> PasteboardCustomData::sameOriginCustomStringData() const
+{
+    HashMap<String, String> customData;
+    for (auto& entry : m_data)
+        customData.set(entry.type, entry.customData);
+    return customData;
+}
+
+RefPtr<SharedBuffer> PasteboardCustomData::readBuffer(const String& type) const
+{
+    for (auto& entry : m_data) {
+        if (entry.type != type)
+            continue;
+
+        if (WTF::holds_alternative<Ref<SharedBuffer>>(entry.platformData))
+            return makeRefPtr(WTF::get<Ref<SharedBuffer>>(entry.platformData).get());
+
+        return nullptr;
+    }
+    return nullptr;
+}
+
+String PasteboardCustomData::readString(const String& type) const
+{
+    for (auto& entry : m_data) {
+        if (entry.type != type)
+            continue;
+
+        if (WTF::holds_alternative<String>(entry.platformData))
+            return WTF::get<String>(entry.platformData);
+
+        return { };
+    }
+    return { };
+}
+
+String PasteboardCustomData::readStringInCustomData(const String& type) const
+{
+    for (auto& entry : m_data) {
+        if (entry.type == type)
+            return entry.customData;
+    }
+    return { };
+}
+
+void PasteboardCustomData::forEachType(Function<void(const String&)>&& function) const
+{
+    for (auto& entry : m_data)
+        function(entry.type);
+}
+
+void PasteboardCustomData::forEachPlatformString(Function<void(const String& type, const String& data)>&& function) const
+{
+    for (auto& entry : m_data) {
+        if (!WTF::holds_alternative<String>(entry.platformData))
+            continue;
+
+        auto string = WTF::get<String>(entry.platformData);
+        if (!string.isNull())
+            function(entry.type, string);
+    }
+}
+
+void PasteboardCustomData::forEachCustomString(Function<void(const String& type, const String& data)>&& function) const
+{
+    for (auto& entry : m_data) {
+        if (!entry.customData.isNull())
+            function(entry.type, entry.customData);
+    }
+}
+
+void PasteboardCustomData::forEachPlatformStringOrBuffer(Function<void(const String& type, const Variant<String, Ref<SharedBuffer>>& data)>&& function) const
+{
+    for (auto& entry : m_data) {
+        auto& data = entry.platformData;
+        if ((WTF::holds_alternative<String>(data) && !WTF::get<String>(data).isNull()) || WTF::holds_alternative<Ref<SharedBuffer>>(data))
+            function(entry.type, data);
+    }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/PasteboardCustomData.h b/Source/WebCore/platform/PasteboardCustomData.h
new file mode 100644 (file)
index 0000000..f9c0e9a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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
+
+#include <wtf/Function.h>
+#include <wtf/HashMap.h>
+#include <wtf/Variant.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+class PasteboardCustomData {
+public:
+    struct Entry {
+        WEBCORE_EXPORT Entry();
+        WEBCORE_EXPORT Entry(const Entry&);
+        WEBCORE_EXPORT Entry(Entry&&);
+        WEBCORE_EXPORT Entry& operator=(const Entry& otherData);
+        WEBCORE_EXPORT Entry& operator=(Entry&& otherData);
+        Entry(const String& type);
+
+        String type;
+        String customData;
+        Variant<String, Ref<SharedBuffer>> platformData;
+    };
+
+    WEBCORE_EXPORT PasteboardCustomData();
+    WEBCORE_EXPORT PasteboardCustomData(String&& origin, Vector<Entry>&&);
+    WEBCORE_EXPORT PasteboardCustomData(PasteboardCustomData&&);
+    WEBCORE_EXPORT PasteboardCustomData(const PasteboardCustomData&);
+    WEBCORE_EXPORT ~PasteboardCustomData();
+
+    const String& origin() const { return m_origin; }
+    void setOrigin(const String& origin) { m_origin = origin; }
+
+    WEBCORE_EXPORT Ref<SharedBuffer> createSharedBuffer() const;
+    WEBCORE_EXPORT static PasteboardCustomData fromSharedBuffer(const SharedBuffer&);
+
+    String readString(const String& type) const;
+    RefPtr<SharedBuffer> readBuffer(const String& type) const;
+    String readStringInCustomData(const String& type) const;
+
+    void writeString(const String& type, const String& value);
+    void writeData(const String& type, Ref<SharedBuffer>&& data);
+    void writeStringInCustomData(const String& type, const String& value);
+
+    void clear();
+    void clear(const String& type);
+
+#if PLATFORM(COCOA)
+    WEBCORE_EXPORT static const char* cocoaType();
+#endif
+
+    void forEachType(Function<void(const String&)>&&) const;
+    void forEachPlatformString(Function<void(const String& type, const String& data)>&&) const;
+    void forEachPlatformStringOrBuffer(Function<void(const String& type, const Variant<String, Ref<SharedBuffer>>& data)>&&) const;
+    void forEachCustomString(Function<void(const String& type, const String& data)>&&) const;
+
+    bool hasData() const;
+    bool hasSameOriginCustomData() const;
+
+    Vector<String> orderedTypes() const;
+    WEBCORE_EXPORT PasteboardCustomData& operator=(const PasteboardCustomData& otherData);
+
+    const Vector<Entry>& data() const { return m_data; }
+
+private:
+    HashMap<String, String> sameOriginCustomStringData() const;
+    Entry& addOrMoveEntryToEnd(const String&);
+
+    String m_origin;
+    Vector<Entry> m_data;
+};
+
+} // namespace WebCore
index 577caf8..ed86085 100644 (file)
 namespace WebCore {
 
 class Color;
+class PasteboardCustomData;
 class SelectionData;
 class SharedBuffer;
 struct PasteboardImage;
 struct PasteboardItemInfo;
 struct PasteboardURL;
 struct PasteboardWebContent;
-struct PasteboardCustomData;
 
 class PasteboardStrategy {
 public:
index df0393e..70ab14e 100644 (file)
@@ -47,9 +47,9 @@ struct wpe_pasteboard;
 namespace WebCore {
 
 class Color;
+class PasteboardCustomData;
 class SelectionData;
 class SharedBuffer;
-struct PasteboardCustomData;
 struct PasteboardImage;
 struct PasteboardItemInfo;
 struct PasteboardURL;
@@ -96,7 +96,7 @@ public:
     WEBCORE_EXPORT URL readURL(size_t index, String& title) const;
     WEBCORE_EXPORT int count() const;
     WEBCORE_EXPORT int numberOfFiles() const;
-
+    WEBCORE_EXPORT void write(const Vector<PasteboardCustomData>&);
     WEBCORE_EXPORT long write(const PasteboardCustomData&);
     WEBCORE_EXPORT Vector<String> typesSafeForDOMToReadAndWrite(const String& origin) const;
 
index 61fd7c4..b56b718 100644 (file)
@@ -29,6 +29,7 @@
 #include "SharedBuffer.h"
 
 #include <algorithm>
+#include <wtf/persistence/PersistentCoders.h>
 #include <wtf/unicode/UTF8Conversion.h>
 
 namespace WebCore {
@@ -239,6 +240,11 @@ void SharedBuffer::hintMemoryNotNeededSoon() const
 }
 #endif
 
+WTF::Persistence::Decoder SharedBuffer::decoder() const
+{
+    return { reinterpret_cast<const uint8_t*>(data()), size() };
+}
+
 bool SharedBuffer::operator==(const SharedBuffer& other) const
 {
     if (this == &other)
index ec37134..aeb1911 100644 (file)
@@ -57,6 +57,12 @@ OBJC_CLASS NSArray;
 OBJC_CLASS NSData;
 #endif
 
+namespace WTF {
+namespace Persistence {
+class Decoder;
+}
+}
+
 namespace WebCore {
 
 class SharedBufferDataView;
@@ -190,6 +196,8 @@ public:
 
     void hintMemoryNotNeededSoon() const;
 
+    WTF::Persistence::Decoder decoder() const;
+
     bool operator==(const SharedBuffer&) const;
     bool operator!=(const SharedBuffer& other) const { return !operator==(other); }
 
index 17313e4..e480666 100644 (file)
 #include "config.h"
 #include "StaticPasteboard.h"
 
+#include "SharedBuffer.h"
+
 namespace WebCore {
 
-StaticPasteboard::StaticPasteboard()
+StaticPasteboard::StaticPasteboard() = default;
+StaticPasteboard::~StaticPasteboard() = default;
+
+bool StaticPasteboard::hasData()
 {
+    return m_customData.hasData();
 }
 
-bool StaticPasteboard::hasData()
+Vector<String> StaticPasteboard::typesSafeForBindings(const String&)
 {
-    return !m_platformData.isEmpty() || !m_customData.isEmpty();
+    return m_customData.orderedTypes();
+}
+
+Vector<String> StaticPasteboard::typesForLegacyUnsafeBindings()
+{
+    return m_customData.orderedTypes();
 }
 
 String StaticPasteboard::readString(const String& type)
 {
-    return m_platformData.get(type);
+    return m_customData.readString(type);
 }
 
 String StaticPasteboard::readStringInCustomData(const String& type)
 {
-    return m_customData.get(type);
+    return m_customData.readStringInCustomData(type);
 }
 
-static void updateTypes(Vector<String>& types, String type, bool moveToEnd)
+void StaticPasteboard::writeString(const String& type, const String& value)
 {
-    if (moveToEnd)
-        types.removeFirst(type);
-    ASSERT(!types.contains(type));
-    types.append(type);
+    m_customData.writeString(type, value);
 }
 
-void StaticPasteboard::writeString(const String& type, const String& value)
+void StaticPasteboard::writeData(const String& type, Ref<SharedBuffer>&& data)
 {
-    bool typeWasAlreadyPresent = !m_platformData.set(type, value).isNewEntry || m_customData.contains(type);
-    updateTypes(m_types, type, typeWasAlreadyPresent);
+    m_customData.writeData(type, WTFMove(data));
 }
 
 void StaticPasteboard::writeStringInCustomData(const String& type, const String& value)
 {
-    bool typeWasAlreadyPresent = !m_customData.set(type, value).isNewEntry || m_platformData.contains(type);
-    updateTypes(m_types, type, typeWasAlreadyPresent);
+    m_customData.writeStringInCustomData(type, value);
 }
 
 void StaticPasteboard::clear()
 {
     m_customData.clear();
-    m_platformData.clear();
-    m_types.clear();
 }
 
 void StaticPasteboard::clear(const String& type)
 {
-    if (!m_platformData.remove(type) && !m_customData.remove(type))
-        return;
-    m_types.removeFirst(type);
-    ASSERT(!m_types.contains(type));
+    m_customData.clear(type);
 }
 
 PasteboardCustomData StaticPasteboard::takeCustomData()
 {
-    return { { }, WTFMove(m_types), WTFMove(m_platformData), WTFMove(m_customData) };
+    return std::exchange(m_customData, { });
 }
 
 }
index eedd702..a56a472 100644 (file)
 
 namespace WebCore {
 
+class SharedBuffer;
+
 class StaticPasteboard final : public Pasteboard {
 public:
     StaticPasteboard();
+    ~StaticPasteboard();
 
     PasteboardCustomData takeCustomData();
 
     bool isStatic() const final { return true; }
 
     bool hasData() final;
-    Vector<String> typesSafeForBindings(const String&) final { return m_types; }
-    Vector<String> typesForLegacyUnsafeBindings() final { return m_types; }
+    Vector<String> typesSafeForBindings(const String&) final;
+    Vector<String> typesForLegacyUnsafeBindings() final;
     String readOrigin() final { return { }; }
     String readString(const String& type) final;
     String readStringInCustomData(const String& type) final;
 
     void writeString(const String& type, const String& data) final;
+    void writeData(const String& type, Ref<SharedBuffer>&& data);
     void writeStringInCustomData(const String& type, const String& data);
     void clear() final;
     void clear(const String& type) final;
@@ -72,9 +76,7 @@ public:
 #endif
 
 private:
-    Vector<String> m_types;
-    HashMap<String, String> m_platformData;
-    HashMap<String, String> m_customData;
+    PasteboardCustomData m_customData;
 };
 
 }
index c0fba4b..d0341be 100644 (file)
@@ -51,11 +51,6 @@ static NSBitmapImageFileType bitmapPNGFileType()
 PasteboardWebContent::PasteboardWebContent() = default;
 PasteboardWebContent::~PasteboardWebContent() = default;
 
-const char* PasteboardCustomData::cocoaType()
-{
-    return "com.apple.WebKit.custom-pasteboard-data";
-}
-
 enum class ImageType {
     Invalid = 0,
     TIFF,
@@ -260,12 +255,12 @@ String Pasteboard::readString(const String& type)
 
 String Pasteboard::readStringInCustomData(const String& type)
 {
-    return readCustomData().sameOriginCustomData.get(type);
+    return readCustomData().readStringInCustomData(type);
 }
 
 String Pasteboard::readOrigin()
 {
-    return readCustomData().origin;
+    return readCustomData().origin();
 }
 
 const PasteboardCustomData& Pasteboard::readCustomData()
diff --git a/Source/WebCore/platform/cocoa/PasteboardCustomDataCocoa.mm b/Source/WebCore/platform/cocoa/PasteboardCustomDataCocoa.mm
new file mode 100644 (file)
index 0000000..2621284
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 "PasteboardCustomData.h"
+
+#if PLATFORM(COCOA)
+
+namespace WebCore {
+
+const char* PasteboardCustomData::cocoaType()
+{
+    return "com.apple.WebKit.custom-pasteboard-data";
+}
+
+} // namespace WebCore
+
+#endif // PLATFORM(COCOA)
index ea56442..60714ec 100644 (file)
 
 NS_ASSUME_NONNULL_BEGIN
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
 @class WebItemProviderRegistrationInfoList;
-#endif
 
 @protocol AbstractPasteboard <NSObject>
 @required
 
 @property (readonly, nonatomic) NSInteger numberOfItems;
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
 @property (nonatomic, copy, nullable) NSArray<__kindof NSItemProvider *> *itemProviders;
-#endif
 
 - (NSArray<NSString *> *)pasteboardTypes;
 - (NSData *)dataForPasteboardType:(NSString *)pasteboardType;
@@ -49,10 +44,9 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSInteger)changeCount;
 
 @optional
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
-- (void)stageRegistrationList:(nullable WebItemProviderRegistrationInfoList *)info;
-- (nullable WebItemProviderRegistrationInfoList *)takeRegistrationList;
-#endif
+- (void)stageRegistrationLists:(NSArray<WebItemProviderRegistrationInfoList *> *)infoLists;
+- (void)clearRegistrationLists;
+- (NSArray<WebItemProviderRegistrationInfoList *> *)takeRegistrationLists;
 - (void)setItems:(NSArray<NSDictionary *> *)items;
 @property (readonly, nonatomic) NSInteger numberOfFiles;
 @property (readonly, nonatomic) NSArray<NSURL *> *allDroppedFileURLs;
index 916daeb..d163ad6 100644 (file)
@@ -266,7 +266,7 @@ long PlatformPasteboard::setStringForType(const String&, const String&)
 
 long PlatformPasteboard::changeCount() const
 {
-    return [(id<AbstractPasteboard>)m_pasteboard.get() changeCount];
+    return [m_pasteboard changeCount];
 }
 
 String PlatformPasteboard::uniqueName()
@@ -292,29 +292,41 @@ String PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite
 
 static NSString *webIOSPastePboardType = @"iOS rich content paste pasteboard type";
 
-static void registerItemToPasteboard(WebItemProviderRegistrationInfoList *representationsToRegister, id <AbstractPasteboard> pasteboard)
+static void registerItemsToPasteboard(NSArray<WebItemProviderRegistrationInfoList *> *itemLists, id <AbstractPasteboard> pasteboard)
 {
 #if PLATFORM(MACCATALYST)
     // In macCatalyst, -[UIPasteboard setItemProviders:] is not yet supported, so we fall back to setting an item dictionary when
     // populating the pasteboard upon copy.
     if ([pasteboard isKindOfClass:PAL::getUIPasteboardClass()]) {
-        auto itemDictionary = adoptNS([[NSMutableDictionary alloc] init]);
-        [representationsToRegister enumerateItems:[itemDictionary] (id <WebItemProviderRegistrar> item, NSUInteger) {
-            if ([item respondsToSelector:@selector(typeIdentifierForClient)] && [item respondsToSelector:@selector(dataForClient)])
-                [itemDictionary setObject:item.dataForClient forKey:item.typeIdentifierForClient];
-        }];
-        [pasteboard setItems:@[ itemDictionary.get() ]];
+        auto itemDictionaries = adoptNS([[NSMutableArray alloc] initWithCapacity:itemLists.count]);
+        for (WebItemProviderRegistrationInfoList *representationsToRegister in itemLists) {
+            auto itemDictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:representationsToRegister.numberOfItems]);
+            [representationsToRegister enumerateItems:[itemDictionary] (id <WebItemProviderRegistrar> item, NSUInteger) {
+                if ([item respondsToSelector:@selector(typeIdentifierForClient)] && [item respondsToSelector:@selector(dataForClient)])
+                    [itemDictionary setObject:item.dataForClient forKey:item.typeIdentifierForClient];
+            }];
+            [itemDictionaries addObject:itemDictionary.get()];
+        }
+        [pasteboard setItems:itemDictionaries.get()];
         return;
     }
 #endif // PLATFORM(MACCATALYST)
 
-    if (NSItemProvider *itemProvider = representationsToRegister.itemProvider)
-        [pasteboard setItemProviders:@[ itemProvider ]];
-    else
-        [pasteboard setItemProviders:@[ ]];
+    auto itemProviders = adoptNS([[NSMutableArray alloc] initWithCapacity:itemLists.count]);
+    for (WebItemProviderRegistrationInfoList *representationsToRegister in itemLists) {
+        if (auto *itemProvider = representationsToRegister.itemProvider)
+            [itemProviders addObject:itemProvider];
+    }
+
+    [pasteboard setItemProviders:itemProviders.get()];
 
-    if ([pasteboard respondsToSelector:@selector(stageRegistrationList:)])
-        [pasteboard stageRegistrationList:representationsToRegister];
+    if ([pasteboard respondsToSelector:@selector(stageRegistrationLists:)])
+        [pasteboard stageRegistrationLists:itemLists];
+}
+
+static void registerItemToPasteboard(WebItemProviderRegistrationInfoList *representationsToRegister, id <AbstractPasteboard> pasteboard)
+{
+    registerItemsToPasteboard(@[ representationsToRegister ], pasteboard);
 }
 
 long PlatformPasteboard::setColor(const Color& color)
@@ -393,7 +405,7 @@ void PlatformPasteboard::write(const PasteboardWebContent& content)
         addRepresentationsForPlainText(representationsToRegister.get(), content.dataInStringFormat);
 
     PasteboardCustomData customData;
-    customData.origin = content.contentOrigin;
+    customData.setOrigin(content.contentOrigin);
     [representationsToRegister addData:customData.createSharedBuffer()->createNSData().get() forType:@(PasteboardCustomData::cocoaType())];
 
     registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
@@ -516,8 +528,8 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
 
     if (NSData *serializedCustomData = [m_pasteboard dataForPasteboardType:@(PasteboardCustomData::cocoaType())]) {
         auto data = PasteboardCustomData::fromSharedBuffer(SharedBuffer::create(serializedCustomData).get());
-        if (data.origin == origin) {
-            for (auto& type : data.orderedTypes)
+        if (data.origin() == origin) {
+            for (auto& type : data.orderedTypes())
                 domPasteboardTypes.add(type);
         }
     }
@@ -548,12 +560,12 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
     return copyToVector(domPasteboardTypes);
 }
 
-long PlatformPasteboard::write(const PasteboardCustomData& data)
+static RetainPtr<WebItemProviderRegistrationInfoList> createItemProviderRegistrationList(const PasteboardCustomData& data)
 {
     auto representationsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
     [representationsToRegister setPreferredPresentationStyle:WebPreferredPresentationStyleInline];
 
-    if (data.sameOriginCustomData.size()) {
+    if (data.hasSameOriginCustomData() || !data.origin().isEmpty()) {
         if (auto serializedSharedBuffer = data.createSharedBuffer()->createNSData()) {
             // We stash the list of supplied pasteboard types in teamData here for compatibility with drag and drop.
             // Since the contents of item providers cannot be loaded prior to drop, but the pasteboard types are
@@ -562,29 +574,38 @@ long PlatformPasteboard::write(const PasteboardCustomData& data)
             // all of the custom types. We use the teamData property, available on NSItemProvider on iOS, to store
             // this information, since the contents of teamData are immediately available prior to the drop.
             NSMutableArray<NSString *> *typesAsNSArray = [NSMutableArray array];
-            for (auto& type : data.orderedTypes)
+            for (auto& type : data.orderedTypes())
                 [typesAsNSArray addObject:type];
-            [representationsToRegister setTeamData:securelyArchivedDataWithRootObject(@{ @(originKeyForTeamData) : data.origin, @(customTypesKeyForTeamData) : typesAsNSArray })];
+            [representationsToRegister setTeamData:securelyArchivedDataWithRootObject(@{ @(originKeyForTeamData) : data.origin(), @(customTypesKeyForTeamData) : typesAsNSArray })];
             [representationsToRegister addData:serializedSharedBuffer.get() forType:@(PasteboardCustomData::cocoaType())];
         }
     }
 
-    for (auto& type : data.orderedTypes) {
-        NSString *stringValue = data.platformData.get(type);
+    data.forEachPlatformString([&] (auto& type, auto& value) {
+        NSString *stringValue = value;
         if (!stringValue.length)
-            continue;
+            return;
 
-        auto cocoaType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type).createCFString();
+        auto cocoaType = PlatformPasteboard::platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type).createCFString();
         if (UTTypeConformsTo(cocoaType.get(), kUTTypeURL))
             [representationsToRegister addRepresentingObject:[NSURL URLWithString:stringValue]];
         else if (UTTypeConformsTo(cocoaType.get(), kUTTypePlainText))
             [representationsToRegister addRepresentingObject:stringValue];
         else
             [representationsToRegister addData:[stringValue dataUsingEncoding:NSUTF8StringEncoding] forType:(NSString *)cocoaType.get()];
-    }
+    });
 
-    registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
-    return [(id<AbstractPasteboard>)m_pasteboard.get() changeCount];
+    return representationsToRegister;
+}
+
+void PlatformPasteboard::write(const Vector<PasteboardCustomData>& itemData)
+{
+    auto registrationLists = adoptNS([[NSMutableArray alloc] initWithCapacity:itemData.size()]);
+    for (auto& data : itemData) {
+        if (auto itemList = createItemProviderRegistrationList(data))
+            [registrationLists addObject:itemList.get()];
+    }
+    registerItemsToPasteboard(registrationLists.get(), m_pasteboard.get());
 }
 
 #else
@@ -620,9 +641,8 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&)
     return { };
 }
 
-long PlatformPasteboard::write(const PasteboardCustomData&)
+void PlatformPasteboard::write(const Vector<PasteboardCustomData>&)
 {
-    return 0;
 }
 
 #endif
@@ -721,6 +741,12 @@ void PlatformPasteboard::updateSupportedTypeIdentifiers(const Vector<String>& ty
     [m_pasteboard updateSupportedTypeIdentifiers:typesArray];
 }
 
+long PlatformPasteboard::write(const PasteboardCustomData& data)
+{
+    write(Vector<PasteboardCustomData> { data });
+    return [m_pasteboard changeCount];
+}
+
 }
 
 #endif // PLATFORM(IOS_FAMILY)
index 43afbdd..7193b65 100644 (file)
@@ -462,7 +462,7 @@ static UIPreferredPresentationStyle uiPreferredPresentationStyle(WebPreferredPre
     // FIXME: These ivars should be refactored to be Vector<RetainPtr<Type>> instead of generic NSArrays.
     RetainPtr<NSArray> _itemProviders;
     RetainPtr<NSArray> _supportedTypeIdentifiers;
-    RetainPtr<WebItemProviderRegistrationInfoList> _stagedRegistrationInfoList;
+    RetainPtr<NSArray<WebItemProviderRegistrationInfoList *>> _stagedRegistrationInfoLists;
 
     Vector<RetainPtr<WebItemProviderLoadResult>> _loadResults;
 }
@@ -484,7 +484,7 @@ static UIPreferredPresentationStyle uiPreferredPresentationStyle(WebPreferredPre
         _changeCount = 0;
         _pendingOperationCount = 0;
         _supportedTypeIdentifiers = nil;
-        _stagedRegistrationInfoList = nil;
+        _stagedRegistrationInfoLists = nil;
         _loadResults = { };
     }
     return self;
@@ -853,16 +853,20 @@ static NSURL *linkTemporaryItemProviderFilesToDropStagingDirectory(NSURL *url, N
     [_itemProviders enumerateObjectsUsingBlock:block];
 }
 
-- (void)stageRegistrationList:(nullable WebItemProviderRegistrationInfoList *)info
+- (void)stageRegistrationLists:(NSArray<WebItemProviderRegistrationInfoList *> *)lists
 {
-    _stagedRegistrationInfoList = info.numberOfItems ? info : nil;
+    ASSERT(lists.count);
+    _stagedRegistrationInfoLists = lists;
 }
 
-- (WebItemProviderRegistrationInfoList *)takeRegistrationList
+- (void)clearRegistrationLists
 {
-    auto stagedRegistrationInfoList = _stagedRegistrationInfoList;
-    _stagedRegistrationInfoList = nil;
-    return stagedRegistrationInfoList.autorelease();
+    _stagedRegistrationInfoLists = nil;
+}
+
+- (NSArray<WebItemProviderRegistrationInfoList *> *)takeRegistrationLists
+{
+    return _stagedRegistrationInfoLists.autorelease();
 }
 
 @end
index 8eb15cf..c1ecef1 100644 (file)
@@ -161,7 +161,7 @@ void Pasteboard::write(const PasteboardWebContent& content)
         m_changeCount = platformStrategies()->pasteboardStrategy()->setStringForType(content.dataInStringFormat, legacyStringPasteboardType(), m_pasteboardName);
 
     PasteboardCustomData data;
-    data.origin = content.contentOrigin;
+    data.setOrigin(content.contentOrigin);
     m_changeCount = platformStrategies()->pasteboardStrategy()->setBufferForType(data.createSharedBuffer().ptr(), PasteboardCustomData::cocoaType(), m_pasteboardName);
 
 }
index 0fe505d..b19b52e 100644 (file)
@@ -118,7 +118,7 @@ RetainPtr<id <NSPasteboardWriting>> createPasteboardWriter(const PasteboardWrite
             [pasteboardItem setData:webContent->clientData[i]->createNSData().get() forType:toUTIUnlessAlreadyUTI(webContent->clientTypes[i]).get()];
 
         PasteboardCustomData customData;
-        customData.origin = webContent->contentOrigin;
+        customData.setOrigin(webContent->contentOrigin);
         [pasteboardItem setData:customData.createSharedBuffer()->createNSData().get() forType:toUTIUnlessAlreadyUTI(String(PasteboardCustomData::cocoaType())).get()];
     }
 
index 194addb..3e9f466 100644 (file)
@@ -198,8 +198,8 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
     ListHashSet<String> domPasteboardTypes;
     if (NSData *serializedCustomData = [m_pasteboard dataForType:@(PasteboardCustomData::cocoaType())]) {
         auto data = PasteboardCustomData::fromSharedBuffer(SharedBuffer::create(serializedCustomData).get());
-        if (data.origin == origin) {
-            for (auto& type : data.orderedTypes)
+        if (data.origin() == origin) {
+            for (auto& type : data.orderedTypes())
                 domPasteboardTypes.add(type);
         }
     }
@@ -225,21 +225,24 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
 long PlatformPasteboard::write(const PasteboardCustomData& data)
 {
     NSMutableArray *types = [NSMutableArray array];
-    for (auto& entry : data.platformData)
-        [types addObject:platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(entry.key)];
-    if (data.sameOriginCustomData.size())
+    data.forEachType([&] (auto& type) {
+        [types addObject:platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type)];
+    });
+
+    bool hasSameOriginCustomData = data.hasSameOriginCustomData();
+    if (hasSameOriginCustomData)
         [types addObject:@(PasteboardCustomData::cocoaType())];
 
     [m_pasteboard declareTypes:types owner:nil];
 
-    for (auto& entry : data.platformData) {
-        auto platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(entry.key);
+    data.forEachPlatformString([&] (auto& type, auto& data) {
+        auto platformType = platformPasteboardTypeForSafeTypeForDOMToReadAndWrite(type);
         ASSERT(!platformType.isEmpty());
         if (!platformType.isEmpty())
-            [m_pasteboard setString:entry.value forType:platformType];
-    }
+            [m_pasteboard setString:data forType:platformType];
+    });
 
-    if (data.sameOriginCustomData.size()) {
+    if (hasSameOriginCustomData) {
         if (auto serializedCustomData = data.createSharedBuffer()->createNSData())
             [m_pasteboard setData:serializedCustomData.get() forType:@(PasteboardCustomData::cocoaType())];
     }
@@ -463,6 +466,43 @@ int PlatformPasteboard::count() const
     return [m_pasteboard pasteboardItems].count;
 }
 
+static RetainPtr<NSPasteboardItem> createPasteboardItem(const PasteboardCustomData& data)
+{
+    auto item = adoptNS([[NSPasteboardItem alloc] init]);
+
+    if (data.hasSameOriginCustomData() || !data.origin().isEmpty()) {
+        if (auto serializedCustomData = data.createSharedBuffer()->createNSData())
+            [item setData:serializedCustomData.get() forType:@(PasteboardCustomData::cocoaType())];
+    }
+
+    data.forEachPlatformStringOrBuffer([&] (auto& type, auto& stringOrBuffer) {
+        auto platformType = modernPasteboardTypeForWebSafeMIMEType(type);
+        if (!platformType)
+            return;
+
+        if (WTF::holds_alternative<String>(stringOrBuffer)) {
+            [item setString:WTF::get<String>(stringOrBuffer) forType:platformType];
+            return;
+        }
+
+        if (WTF::holds_alternative<Ref<SharedBuffer>>(stringOrBuffer)) {
+            if (auto platformData = WTF::get<Ref<SharedBuffer>>(stringOrBuffer)->createNSData())
+                [item setData:platformData.get() forType:platformType];
+        }
+    });
+
+    return item;
+}
+
+void PlatformPasteboard::write(const Vector<PasteboardCustomData>& itemData)
+{
+    auto platformItems = adoptNS([[NSMutableArray alloc] initWithCapacity:itemData.size()]);
+    for (auto& data : itemData)
+        [platformItems addObject:createPasteboardItem(data).get()];
+    [m_pasteboard clearContents];
+    [m_pasteboard writeObjects:platformItems.get()];
+}
+
 PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(size_t index)
 {
     NSPasteboardItem *item = itemAtIndex(index);
index e84bf2e..a83fa8e 100644 (file)
@@ -1,3 +1,46 @@
+2019-10-14  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Support writing multiple PasteboardCustomData with SharedBuffers to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=202851
+
+        Reviewed by Darin Adler.
+
+        See WebCore ChangeLog for more details.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<PasteboardCustomData::Entry>::encode):
+        (IPC::ArgumentCoder<PasteboardCustomData::Entry>::decode):
+
+        Add helpers to encode and decode PasteboardCustomData::Entry.
+
+        (IPC::ArgumentCoder<PasteboardCustomData>::encode):
+        (IPC::ArgumentCoder<PasteboardCustomData>::decode):
+        * Shared/WebCoreArgumentCoders.h:
+
+        Add support for encoding and decoding PasteboardCustomData by encoding and decoding each of its items (see
+        above).
+
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::requestDOMPasteAccess):
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView canPerformActionForWebView:withSender:]):
+        (allPasteboardItemOriginsMatchOrigin):
+        (-[WKContentView _didHandleAdditionalDragItemsRequest:]):
+
+        Tweak several methods to use the new methods on PasteboardCustomData instead of accessing the member variables
+        directly.
+
+        (-[WKContentView cleanUpDragSourceSessionState]):
+        (-[WKContentView _prepareToDragPromisedAttachment:]):
+        (-[WKContentView _itemsForBeginningOrAddingToSessionWithRegistrationLists:stagedDragSource:]):
+        (-[WKContentView dragInteraction:itemsForBeginningSession:]):
+        (-[WKContentView _itemsForBeginningOrAddingToSessionWithRegistrationList:stagedDragSource:]): Deleted.
+
+        Adjust these methods to handle multiple staged item providers (for now, it remains that iOS drag and drop
+        codepaths will still only write a single item to the pasteboard).
+
 2019-10-14  Per Arne Vollan  <pvollan@apple.com>
 
         [macOS] Sandbox extensions should be created with audit tokens, not PIDs
index 222cdaf..17db825 100644 (file)
@@ -1636,28 +1636,80 @@ bool ArgumentCoder<DataListSuggestionInformation>::decode(Decoder& decoder, WebC
 }
 #endif
 
-void ArgumentCoder<PasteboardCustomData>::encode(Encoder& encoder, const PasteboardCustomData& data)
+template<> struct ArgumentCoder<PasteboardCustomData::Entry> {
+    static void encode(Encoder&, const PasteboardCustomData::Entry&);
+    static bool decode(Decoder&, PasteboardCustomData::Entry&);
+};
+
+void ArgumentCoder<PasteboardCustomData::Entry>::encode(Encoder& encoder, const PasteboardCustomData::Entry& data)
 {
-    encoder << data.origin;
-    encoder << data.orderedTypes;
-    encoder << data.platformData;
-    encoder << data.sameOriginCustomData;
+    encoder << data.type << data.customData;
+
+    auto& platformData = data.platformData;
+    bool hasString = WTF::holds_alternative<String>(platformData);
+    encoder << hasString;
+    if (hasString)
+        encoder << WTF::get<String>(platformData);
+
+    bool hasBuffer = WTF::holds_alternative<Ref<SharedBuffer>>(platformData);
+    encoder << hasBuffer;
+    if (hasBuffer)
+        encodeSharedBuffer(encoder, WTF::get<Ref<SharedBuffer>>(platformData).ptr());
 }
 
-bool ArgumentCoder<PasteboardCustomData>::decode(Decoder& decoder, PasteboardCustomData& data)
+bool ArgumentCoder<PasteboardCustomData::Entry>::decode(Decoder& decoder, PasteboardCustomData::Entry& data)
 {
-    if (!decoder.decode(data.origin))
+    if (!decoder.decode(data.type))
+        return false;
+
+    if (!decoder.decode(data.customData))
+        return false;
+
+    bool hasString;
+    if (!decoder.decode(hasString))
+        return false;
+
+    if (hasString) {
+        String value;
+        if (!decoder.decode(value))
+            return false;
+        data.platformData = { WTFMove(value) };
+    }
+
+    bool hasBuffer;
+    if (!decoder.decode(hasBuffer))
         return false;
 
-    if (!decoder.decode(data.orderedTypes))
+    if (hasString && hasBuffer)
         return false;
 
-    if (!decoder.decode(data.platformData))
+    if (hasBuffer) {
+        RefPtr<SharedBuffer> value;
+        if (!decodeSharedBuffer(decoder, value))
+            return false;
+        data.platformData = { value.releaseNonNull() };
+    }
+
+    return true;
+}
+
+void ArgumentCoder<PasteboardCustomData>::encode(Encoder& encoder, const PasteboardCustomData& data)
+{
+    encoder << data.origin();
+    encoder << data.data();
+}
+
+bool ArgumentCoder<PasteboardCustomData>::decode(Decoder& decoder, PasteboardCustomData& data)
+{
+    String origin;
+    if (!decoder.decode(origin))
         return false;
 
-    if (!decoder.decode(data.sameOriginCustomData))
+    Vector<PasteboardCustomData::Entry> items;
+    if (!decoder.decode(items))
         return false;
 
+    data = PasteboardCustomData(WTFMove(origin), WTFMove(items));
     return true;
 }
 
index 9d6cd34..015f896 100644 (file)
@@ -89,6 +89,7 @@ class LayoutSize;
 class LayoutPoint;
 class LinearTimingFunction;
 class Notification;
+class PasteboardCustomData;
 class Path;
 class ProtectionSpace;
 class Region;
@@ -117,7 +118,6 @@ struct Length;
 struct GrammarDetail;
 struct MimeClassInfo;
 struct PasteboardImage;
-struct PasteboardCustomData;
 struct PasteboardURL;
 struct PluginInfo;
 struct PromisedAttachmentInfo;
index e275b3c..75e19ae 100644 (file)
@@ -4318,7 +4318,7 @@ void WebViewImpl::requestDOMPasteAccess(const WebCore::IntRect&, const String& o
 
     NSData *data = [NSPasteboard.generalPasteboard dataForType:@(WebCore::PasteboardCustomData::cocoaType())];
     auto buffer = WebCore::SharedBuffer::create(data);
-    if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin == originIdentifier) {
+    if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin() == originIdentifier) {
         completion(WebCore::DOMPasteAccessResponse::GrantedForGesture);
         return;
     }
index adbc226..ad406f4 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace WebCore {
 class Color;
-struct PasteboardCustomData;
+class PasteboardCustomData;
 struct PasteboardImage;
 struct PasteboardItemInfo;
 struct PasteboardURL;
index 691d025..3b6625a 100644 (file)
@@ -29,7 +29,7 @@ messages -> WebPasteboardProxy {
     UpdateSupportedTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
 #endif
 
-    WriteCustomData(struct WebCore::PasteboardCustomData data, String pasteboardName) -> (uint64_t changeCount) Synchronous
+    WriteCustomData(WebCore::PasteboardCustomData data, String pasteboardName) -> (uint64_t changeCount) Synchronous
     TypesSafeForDOMToReadAndWrite(String pasteboardName, String origin) -> (Vector<String> types) Synchronous
     AllPasteboardItemInfo(String pasteboardName) -> (Vector<WebCore::PasteboardItemInfo> allInfo) Synchronous
     InformationForItemAtIndex(uint64_t index, String pasteboardName) -> (struct WebCore::PasteboardItemInfo info) Synchronous
index 7f9a05a..b2d5503 100644 (file)
@@ -3233,7 +3233,7 @@ WEBCORE_COMMAND_FOR_WEBVIEW(pasteAndMatchStyle);
         NSArray *allCustomPasteboardData = [pasteboard dataForPasteboardType:@(WebCore::PasteboardCustomData::cocoaType()) inItemSet:indices];
         for (NSData *data in allCustomPasteboardData) {
             auto buffer = WebCore::SharedBuffer::create(data);
-            if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin == focusedDocumentOrigin)
+            if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin() == focusedDocumentOrigin)
                 return YES;
         }
         return NO;
@@ -5731,7 +5731,7 @@ static BOOL allPasteboardItemOriginsMatchOrigin(UIPasteboard *pasteboard, const
             continue;
 
         auto buffer = WebCore::SharedBuffer::create(data);
-        if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin != originIdentifier)
+        if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin() != originIdentifier)
             return NO;
 
         foundAtLeastOneMatchingIdentifier = YES;
@@ -6706,15 +6706,15 @@ static BOOL shouldEnableDragInteractionForPolicy(_WKDragInteractionPolicy policy
     if (!completion)
         return;
 
-    WebItemProviderRegistrationInfoList *registrationList = [[WebItemProviderPasteboard sharedInstance] takeRegistrationList];
-    if (!added || !registrationList || !_dragDropInteractionState.hasStagedDragSource()) {
+    auto *registrationLists = [[WebItemProviderPasteboard sharedInstance] takeRegistrationLists];
+    if (!added || ![registrationLists count] || !_dragDropInteractionState.hasStagedDragSource()) {
         _dragDropInteractionState.clearStagedDragSource();
         completion(@[ ]);
         return;
     }
 
     auto stagedDragSource = _dragDropInteractionState.stagedDragSource();
-    NSArray *dragItemsToAdd = [self _itemsForBeginningOrAddingToSessionWithRegistrationList:registrationList stagedDragSource:stagedDragSource];
+    NSArray *dragItemsToAdd = [self _itemsForBeginningOrAddingToSessionWithRegistrationLists:registrationLists stagedDragSource:stagedDragSource];
 
     RELEASE_LOG(DragAndDrop, "Drag session: %p adding %tu items", _dragDropInteractionState.dragSession(), dragItemsToAdd.count);
     _dragDropInteractionState.clearStagedDragSource(dragItemsToAdd.count ? WebKit::DragDropInteractionState::DidBecomeActive::Yes : WebKit::DragDropInteractionState::DidBecomeActive::No);
@@ -6793,7 +6793,7 @@ static UIDropOperation dropOperationForWebCoreDragOperation(WebCore::DragOperati
         [[WebItemProviderPasteboard sharedInstance] setItemProviders:nil];
     }
 
-    [[WebItemProviderPasteboard sharedInstance] stageRegistrationList:nil];
+    [[WebItemProviderPasteboard sharedInstance] clearRegistrationLists];
     [self _restoreCalloutBarIfNeeded];
 
     [std::exchange(_visibleContentViewSnapshot, nil) removeFromSuperview];
@@ -6960,7 +6960,7 @@ static NSArray<NSItemProvider *> *extractItemProvidersFromDropSession(id <UIDrop
 
     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
     pasteboard.itemProviders = @[ [registrationList itemProvider] ];
-    [pasteboard stageRegistrationList:registrationList.get()];
+    [pasteboard stageRegistrationLists:@[ registrationList.get() ]];
 }
 
 - (WKDragDestinationAction)_dragDestinationActionForDropSession:(id <UIDropSession>)session
@@ -6999,26 +6999,38 @@ static NSArray<NSItemProvider *> *extractItemProvidersFromDropSession(id <UIDrop
     _shouldRestoreCalloutBarAfterDrop = NO;
 }
 
-- (NSArray<UIDragItem *> *)_itemsForBeginningOrAddingToSessionWithRegistrationList:(WebItemProviderRegistrationInfoList *)registrationList stagedDragSource:(const WebKit::DragSourceState&)stagedDragSource
+- (NSArray<UIDragItem *> *)_itemsForBeginningOrAddingToSessionWithRegistrationLists:(NSArray<WebItemProviderRegistrationInfoList *> *)registrationLists stagedDragSource:(const WebKit::DragSourceState&)stagedDragSource
 {
-    NSItemProvider *defaultItemProvider = registrationList.itemProvider;
-    if (!defaultItemProvider)
+    if (!registrationLists.count)
         return @[ ];
 
-    NSArray *adjustedItemProviders;
+    NSMutableArray *adjustedItemProviders = [NSMutableArray array];
     id <WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
     if ([uiDelegate respondsToSelector:@selector(_webView:adjustedDataInteractionItemProvidersForItemProvider:representingObjects:additionalData:)]) {
-        auto representingObjects = adoptNS([[NSMutableArray alloc] init]);
-        auto additionalData = adoptNS([[NSMutableDictionary alloc] init]);
-        [registrationList enumerateItems:[representingObjects, additionalData] (id <WebItemProviderRegistrar> item, NSUInteger) {
-            if ([item respondsToSelector:@selector(representingObjectForClient)])
-                [representingObjects addObject:item.representingObjectForClient];
-            if ([item respondsToSelector:@selector(typeIdentifierForClient)] && [item respondsToSelector:@selector(dataForClient)])
-                [additionalData setObject:item.dataForClient forKey:item.typeIdentifierForClient];
-        }];
-        adjustedItemProviders = [uiDelegate _webView:_webView adjustedDataInteractionItemProvidersForItemProvider:defaultItemProvider representingObjects:representingObjects.get() additionalData:additionalData.get()];
-    } else
-        adjustedItemProviders = @[ defaultItemProvider ];
+        // FIXME: We should consider a new UI delegate hook that accepts a list of item providers, so we don't need to invoke this delegate method repeatedly for multiple items.
+        for (WebItemProviderRegistrationInfoList *list in registrationLists) {
+            NSItemProvider *defaultItemProvider = list.itemProvider;
+            if (!defaultItemProvider)
+                continue;
+
+            auto representingObjects = adoptNS([[NSMutableArray alloc] init]);
+            auto additionalData = adoptNS([[NSMutableDictionary alloc] init]);
+            [list enumerateItems:[representingObjects, additionalData] (id <WebItemProviderRegistrar> item, NSUInteger) {
+                if ([item respondsToSelector:@selector(representingObjectForClient)])
+                    [representingObjects addObject:item.representingObjectForClient];
+                if ([item respondsToSelector:@selector(typeIdentifierForClient)] && [item respondsToSelector:@selector(dataForClient)])
+                    [additionalData setObject:item.dataForClient forKey:item.typeIdentifierForClient];
+            }];
+            NSArray *adjustedItems = [uiDelegate _webView:_webView adjustedDataInteractionItemProvidersForItemProvider:defaultItemProvider representingObjects:representingObjects.get() additionalData:additionalData.get()];
+            if (adjustedItems.count)
+                [adjustedItemProviders addObjectsFromArray:adjustedItems];
+        }
+    } else {
+        for (WebItemProviderRegistrationInfoList *list in registrationLists) {
+            if (auto *defaultItemProvider = list.itemProvider)
+                [adjustedItemProviders addObject:defaultItemProvider];
+        }
+    }
 
     NSMutableArray *dragItems = [NSMutableArray arrayWithCapacity:adjustedItemProviders.count];
     for (NSItemProvider *itemProvider in adjustedItemProviders) {
@@ -7261,8 +7273,8 @@ static Vector<WebCore::IntSize> sizesOfPlaceholderElementsToInsertWhenDroppingIt
     }
 
     auto stagedDragSource = _dragDropInteractionState.stagedDragSource();
-    WebItemProviderRegistrationInfoList *registrationList = [[WebItemProviderPasteboard sharedInstance] takeRegistrationList];
-    NSArray *dragItems = [self _itemsForBeginningOrAddingToSessionWithRegistrationList:registrationList stagedDragSource:stagedDragSource];
+    auto *registrationLists = [[WebItemProviderPasteboard sharedInstance] takeRegistrationLists];
+    NSArray *dragItems = [self _itemsForBeginningOrAddingToSessionWithRegistrationLists:registrationLists stagedDragSource:stagedDragSource];
     if (![dragItems count])
         _page->dragCancelled();
 
index 4ba71fb..ca0f6e2 100644 (file)
@@ -1,3 +1,14 @@
+2019-10-14  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Clipboard API] Support writing multiple PasteboardCustomData with SharedBuffers to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=202851
+
+        Reviewed by Darin Adler.
+
+        See WebCore ChangeLog for more details.
+
+        * WebCoreSupport/WebPlatformStrategies.h:
+
 2019-10-09  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [Clipboard API] Refactor Pasteboard item reading functions to work on both iOS and macOS
index 9f00399..3e880ab 100644 (file)
@@ -29,9 +29,9 @@
 #include <WebCore/PasteboardStrategy.h>
 #include <WebCore/PlatformStrategies.h>
 
+class PasteboardCustomData;
 struct PasteboardImage;
 struct PasteboardWebContent;
-struct PasteboardCustomData;
 
 class WebPlatformStrategies : public WebCore::PlatformStrategies, private WebCore::PasteboardStrategy {
 public: