Respect fidelity order when reading web content from item providers
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Apr 2017 02:35:02 +0000 (02:35 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Apr 2017 02:35:02 +0000 (02:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171155
<rdar://problem/31356937>

Reviewed by Tim Horton.

Source/WebCore:

Currently, when reading web content from pasteboards, we assume the old UIPasteboard/NSPasteboard model wherein
the destination must determine which of the items is considered to have the highest fidelity for the purposes of
inserting into an editable area. This destination-side fidelity ranking is determined solely by the NSArray
returned from Pasteboard::supportedPasteboardTypes, which lists compatible types in order from highest fidelity
to lowest fidelity. Pasteboard::read effectively iterates over this list of types in order, attempting to read
highest fidelity types and bailing when it first successfully reads data.

However, when our pasteboard is backed by UIItemProviders, we should instead read pasteboard types in order of
fidelity as specified by the source rather than the destination. To accomplish this, we introduce an alternate
codepath, Pasteboard::readRespectingUTIFidelities, which we take if Pasteboard::respectsUTIFidelities is true
(currently, this only applies for the purposes of data interaction). This version follows a different flow:
for each item in the pasteboard, we ask for just the UTIs for that item, in order of fidelity. For each item,
we then call readPasteboardWebContentDataForType to try and read data for that type, continuing until either
all UTIs have been attempted, or reading was successful.

This patch makes two additional adjustments. First, we introduce Pasteboard::getTypesByFidelityForItemAtIndex,
which is used by Pasteboard::readRespectingUTIFidelities when querying the list of supported UTIs for each
pasteboard item, sorted by highest to lowest fidelity.

Secondly, we refactor logic to write to the item provider pasteboard in PlatformPasteboardIOS. Since we are
now respecting fidelity rankings on the destination, the source must also register UTI types in the right
fidelity order. While this was mostly achieved using our existing method of writing a list of object
representations to the pasteboard and then all of the contents of a NSString => NSData dictionary containing
private UTI data, this approach has two flaws:
1.  We are unable to register high-priority custom types, followed by representing objects, followed by more
    lower-priority custom types, since we assume that all custom types follow all representing objects.
2.  Since we're just iterating over a dictionary of NSString => NSData when registering custom UTI
    representations to the item provider, there cannot inherently be any fidelity ordering for custom types.

To address both of these issues, we introduce two new objects that encapsulate how we register data to the item
provider pasteboard. WebItemProviderRegistrationInfo represents some data that can be registered to an item
provider (either an object conforming to UIItemProviderWriting, or an NSString and NSData).
WebItemProviderRegistrationInfoList represents a list of WebItemProviderRegistrationInfos in order of highest to
lowest fidelity. In PlatformPasteboardIOS, we transform PasteboardWebContent, PasteboardImage, and PasteboardURL
into a WebItemProviderRegistrationInfoList, which we then pass along to the WebItemProviderPasteboard. In
WebItemProviderPasteboard, we traverse the list of WebItemProviderRegistrationInfos in the list and register
each WebItemProviderRegistrationInfo's representing object or data to the item provider.

Test: DataInteractionTests.RespectsExternalSourceFidelityRankings.

* WebCore.xcodeproj/project.pbxproj:
* platform/Pasteboard.h:
* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/ios/AbstractPasteboard.h:
* platform/ios/AbstractPasteboard.mm: Removed.

Moves WebItemProviderData, formerly implemented in AbstractPasteboard.mm, into WebItemProviderPasteboard.mm.
We can delete AbstractPasteboard.mm as a result.

* platform/ios/PasteboardIOS.mm:
(WebCore::readPasteboardWebContentDataForType):

Pull out common logic for reading data given a UTI type from the pasteboard into the PasteboardWebContentReader.
This is invoked from both the existing Pasteboard::read codepath, as well as the readRespectingUTIFidelities
codepath.

(WebCore::Pasteboard::read):

Refactored to call the new readPasteboardWebContentDataForType helper. Behavior should not have changed, unless
the pasteboard supports UTI fidelities.

(WebCore::Pasteboard::respectsUTIFidelities):
(WebCore::Pasteboard::readRespectingUTIFidelities):

An alternative to Pasteboard::read that considers source-side fidelity rankings of UTIs.

* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::getTypesByFidelityForItemAtIndex):
(WebCore::PlatformPasteboard::writeObjectRepresentations):

Refactored to build a WebItemProviderRegistrationInfoList and pass it to the WebItemProviderPasteboard to
register items and data.

(WebCore::PlatformPasteboard::write):
* platform/ios/WebItemProviderPasteboard.h:
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderRegistrationInfo initWithRepresentingObject:typeIdentifier:data:]):
(-[WebItemProviderRegistrationInfo representingObject]):
(-[WebItemProviderRegistrationInfo typeIdentifier]):
(-[WebItemProviderRegistrationInfo data]):

Represents a single calls to register data onto the item provider pasteboard. See
WebItemProviderPasteboard.h header comments for more info.

(-[WebItemProviderRegistrationInfoList init]):
(-[WebItemProviderRegistrationInfoList addData:forType:]):
(-[WebItemProviderRegistrationInfoList addRepresentingObject:]):
(-[WebItemProviderRegistrationInfoList numberOfItems]):
(-[WebItemProviderRegistrationInfoList itemAtIndex:]):
(-[WebItemProviderRegistrationInfoList enumerateItems:]):

Represents a series of calls to register representations onto the item provider pasteboard. See
WebItemProviderPasteboard.h header comments for more info.

(-[WebItemProviderPasteboard pasteboardTypesByFidelityForItemAtIndex:]):
(-[WebItemProviderPasteboard setItemsUsingRegistrationInfoLists:]):
(-[WebItemProviderPasteboard setItemsFromObjectRepresentations:]): Deleted.

Source/WebKit/mac:

Adjusts for changes in WebCore (see WebCore/ChangeLog for more details).

* WebCoreSupport/WebPlatformStrategies.h:
* WebCoreSupport/WebPlatformStrategies.mm:
(WebPlatformStrategies::getTypesByFidelityForItemAtIndex):

Source/WebKit2:

Adjusts for changes in WebCore by adding plumbing to support Pasteboard::getTypesByFidelityForItemAtIndex. See
WebCore/ChangeLog for more details.

* UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
(WebKit::WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex):
* UIProcess/WebPasteboardProxy.h:
* UIProcess/WebPasteboardProxy.messages.in:
* WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
(WebKit::WebPlatformStrategies::getTypesByFidelityForItemAtIndex):
* WebProcess/WebCoreSupport/WebPlatformStrategies.h:

Tools:

Adds a new unit test (DataInteractionTests.RespectsExternalSourceFidelityRankings). See WebCore ChangeLog for
more details.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):

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

22 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/PasteboardStrategy.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/ios/AbstractPasteboard.h
Source/WebCore/platform/ios/AbstractPasteboard.mm [deleted file]
Source/WebCore/platform/ios/PasteboardIOS.mm
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebCore/platform/ios/WebItemProviderPasteboard.h
Source/WebCore/platform/ios/WebItemProviderPasteboard.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebPlatformStrategies.h
Source/WebKit/mac/WebCoreSupport/WebPlatformStrategies.mm
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
Source/WebKit2/UIProcess/WebPasteboardProxy.h
Source/WebKit2/UIProcess/WebPasteboardProxy.messages.in
Source/WebKit2/WebProcess/WebCoreSupport/WebPlatformStrategies.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebPlatformStrategies.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm

index 898a540..bf80398 100644 (file)
@@ -1,3 +1,110 @@
+2017-04-24  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Respect fidelity order when reading web content from item providers
+        https://bugs.webkit.org/show_bug.cgi?id=171155
+        <rdar://problem/31356937>
+
+        Reviewed by Tim Horton.
+
+        Currently, when reading web content from pasteboards, we assume the old UIPasteboard/NSPasteboard model wherein
+        the destination must determine which of the items is considered to have the highest fidelity for the purposes of
+        inserting into an editable area. This destination-side fidelity ranking is determined solely by the NSArray
+        returned from Pasteboard::supportedPasteboardTypes, which lists compatible types in order from highest fidelity
+        to lowest fidelity. Pasteboard::read effectively iterates over this list of types in order, attempting to read
+        highest fidelity types and bailing when it first successfully reads data.
+
+        However, when our pasteboard is backed by UIItemProviders, we should instead read pasteboard types in order of
+        fidelity as specified by the source rather than the destination. To accomplish this, we introduce an alternate
+        codepath, Pasteboard::readRespectingUTIFidelities, which we take if Pasteboard::respectsUTIFidelities is true
+        (currently, this only applies for the purposes of data interaction). This version follows a different flow:
+        for each item in the pasteboard, we ask for just the UTIs for that item, in order of fidelity. For each item,
+        we then call readPasteboardWebContentDataForType to try and read data for that type, continuing until either
+        all UTIs have been attempted, or reading was successful.
+
+        This patch makes two additional adjustments. First, we introduce Pasteboard::getTypesByFidelityForItemAtIndex,
+        which is used by Pasteboard::readRespectingUTIFidelities when querying the list of supported UTIs for each
+        pasteboard item, sorted by highest to lowest fidelity.
+
+        Secondly, we refactor logic to write to the item provider pasteboard in PlatformPasteboardIOS. Since we are
+        now respecting fidelity rankings on the destination, the source must also register UTI types in the right
+        fidelity order. While this was mostly achieved using our existing method of writing a list of object
+        representations to the pasteboard and then all of the contents of a NSString => NSData dictionary containing
+        private UTI data, this approach has two flaws:
+        1.  We are unable to register high-priority custom types, followed by representing objects, followed by more
+            lower-priority custom types, since we assume that all custom types follow all representing objects.
+        2.  Since we're just iterating over a dictionary of NSString => NSData when registering custom UTI
+            representations to the item provider, there cannot inherently be any fidelity ordering for custom types.
+
+        To address both of these issues, we introduce two new objects that encapsulate how we register data to the item
+        provider pasteboard. WebItemProviderRegistrationInfo represents some data that can be registered to an item
+        provider (either an object conforming to UIItemProviderWriting, or an NSString and NSData).
+        WebItemProviderRegistrationInfoList represents a list of WebItemProviderRegistrationInfos in order of highest to
+        lowest fidelity. In PlatformPasteboardIOS, we transform PasteboardWebContent, PasteboardImage, and PasteboardURL
+        into a WebItemProviderRegistrationInfoList, which we then pass along to the WebItemProviderPasteboard. In
+        WebItemProviderPasteboard, we traverse the list of WebItemProviderRegistrationInfos in the list and register
+        each WebItemProviderRegistrationInfo's representing object or data to the item provider.
+
+        Test: DataInteractionTests.RespectsExternalSourceFidelityRankings.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/Pasteboard.h:
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/AbstractPasteboard.mm: Removed.
+
+        Moves WebItemProviderData, formerly implemented in AbstractPasteboard.mm, into WebItemProviderPasteboard.mm.
+        We can delete AbstractPasteboard.mm as a result.
+
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::readPasteboardWebContentDataForType):
+
+        Pull out common logic for reading data given a UTI type from the pasteboard into the PasteboardWebContentReader.
+        This is invoked from both the existing Pasteboard::read codepath, as well as the readRespectingUTIFidelities
+        codepath.
+
+        (WebCore::Pasteboard::read):
+
+        Refactored to call the new readPasteboardWebContentDataForType helper. Behavior should not have changed, unless
+        the pasteboard supports UTI fidelities.
+
+        (WebCore::Pasteboard::respectsUTIFidelities):
+        (WebCore::Pasteboard::readRespectingUTIFidelities):
+
+        An alternative to Pasteboard::read that considers source-side fidelity rankings of UTIs.
+
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::getTypesByFidelityForItemAtIndex):
+        (WebCore::PlatformPasteboard::writeObjectRepresentations):
+
+        Refactored to build a WebItemProviderRegistrationInfoList and pass it to the WebItemProviderPasteboard to
+        register items and data.
+
+        (WebCore::PlatformPasteboard::write):
+        * platform/ios/WebItemProviderPasteboard.h:
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderRegistrationInfo initWithRepresentingObject:typeIdentifier:data:]):
+        (-[WebItemProviderRegistrationInfo representingObject]):
+        (-[WebItemProviderRegistrationInfo typeIdentifier]):
+        (-[WebItemProviderRegistrationInfo data]):
+
+        Represents a single calls to register data onto the item provider pasteboard. See
+        WebItemProviderPasteboard.h header comments for more info.
+
+        (-[WebItemProviderRegistrationInfoList init]):
+        (-[WebItemProviderRegistrationInfoList addData:forType:]):
+        (-[WebItemProviderRegistrationInfoList addRepresentingObject:]):
+        (-[WebItemProviderRegistrationInfoList numberOfItems]):
+        (-[WebItemProviderRegistrationInfoList itemAtIndex:]):
+        (-[WebItemProviderRegistrationInfoList enumerateItems:]):
+
+        Represents a series of calls to register representations onto the item provider pasteboard. See
+        WebItemProviderPasteboard.h header comments for more info.
+
+        (-[WebItemProviderPasteboard pasteboardTypesByFidelityForItemAtIndex:]):
+        (-[WebItemProviderPasteboard setItemsUsingRegistrationInfoLists:]):
+        (-[WebItemProviderPasteboard setItemsFromObjectRepresentations:]): Deleted.
+
 2017-04-24  Chris Dumez  <cdumez@apple.com>
 
         Regression(r204605): support for "cp874" charset alias was inadvertently dropped which may cause issues on certain Thai sites
index 8dd2603..1f55b1d 100644 (file)
                F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F48223121E386E240066FC79 /* AbstractPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F4BFB9851E1DDF9B00862C24 /* DumpEditingHistory.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */; };
                F4BFB9861E1DDF9B00862C24 /* EditingHistoryUtil.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = F48389841E1DDF2B0076B7EA /* EditingHistoryUtil.js */; };
-               F4D831621E908C0700941174 /* AbstractPasteboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D831611E908C0700941174 /* AbstractPasteboard.mm */; };
                F50664F7157F52DC00AC226F /* FormController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F50664F5157F52DC00AC226F /* FormController.cpp */; };
                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, ); }; };
                F48223121E386E240066FC79 /* AbstractPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractPasteboard.h; sourceTree = "<group>"; };
                F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = DumpEditingHistory.js; path = Scripts/DumpEditingHistory.js; sourceTree = "<group>"; };
                F48389841E1DDF2B0076B7EA /* EditingHistoryUtil.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = EditingHistoryUtil.js; path = Scripts/EditingHistoryUtil.js; sourceTree = "<group>"; };
-               F4D831611E908C0700941174 /* AbstractPasteboard.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AbstractPasteboard.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>"; };
                        children = (
                                A148328B187F506800DA63A6 /* wak */,
                                F48223121E386E240066FC79 /* AbstractPasteboard.h */,
-                               F4D831611E908C0700941174 /* AbstractPasteboard.mm */,
                                2655414B1489AA2B000DFC5D /* CursorIOS.cpp */,
                                A1ED778A1BE3293F00DC1791 /* Device.cpp */,
                                A1ED778B1BE3294000DC1791 /* Device.h */,
                                A6148A7812E41E3B0044A784 /* JSHTMLKeygenElement.cpp in Sources */,
                                1AE2AB210A1CE63B00B42B25 /* JSHTMLLabelElement.cpp in Sources */,
                                1AE2AB230A1CE63B00B42B25 /* JSHTMLLegendElement.cpp in Sources */,
-                               F4D831621E908C0700941174 /* AbstractPasteboard.mm in Sources */,
                                1AE2AB250A1CE63B00B42B25 /* JSHTMLLIElement.cpp in Sources */,
                                A80E7B100A19D606007FB8C5 /* JSHTMLLinkElement.cpp in Sources */,
                                1AE2AB270A1CE63B00B42B25 /* JSHTMLMapElement.cpp in Sources */,
index b94d70a..429e1af 100644 (file)
@@ -217,6 +217,11 @@ public:
 #endif
 
 private:
+#if PLATFORM(IOS)
+    bool respectsUTIFidelities() const;
+    void readRespectingUTIFidelities(PasteboardWebContentReader&);
+#endif
+
 #if PLATFORM(WIN)
     void finishCreatingPasteboard();
     void writeRangeToDataObject(Range&, Frame&); // FIXME: Layering violation.
index c2a6347..7d59cd5 100644 (file)
@@ -52,6 +52,7 @@ public:
     virtual RefPtr<SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) = 0;
     virtual URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) = 0;
     virtual void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) = 0;
+    virtual void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) = 0;
 #endif // PLATFORM(IOS)
 #if PLATFORM(COCOA)
     virtual void getTypes(Vector<String>& types, const String& pasteboardName) = 0;
index 7923c2f..53b2cd9 100644 (file)
@@ -56,6 +56,7 @@ public:
 #if PLATFORM(IOS)
     WEBCORE_EXPORT PlatformPasteboard();
     WEBCORE_EXPORT Vector<String> filenamesForDataInteraction();
+    WEBCORE_EXPORT void getTypesByFidelityForItemAtIndex(Vector<String>& types, int index);
 #endif
     WEBCORE_EXPORT static String uniqueName();
 
index b7e1a50..19f3193 100644 (file)
 
 #if TARGET_OS_IPHONE
 
-WEBCORE_EXPORT @interface WebPasteboardItemData : NSObject
-
-+ (instancetype)itemWithRepresentingObjects:(NSArray *)representingObjects additionalData:(NSDictionary *)additionalData;
-
-@property (nonatomic, readonly, strong) NSArray *representingObjects;
-@property (nonatomic, readonly, strong) NSDictionary *additionalData;
-
-@end
+NS_ASSUME_NONNULL_BEGIN
 
 @protocol AbstractPasteboard <NSObject>
 @required
@@ -47,11 +40,14 @@ WEBCORE_EXPORT @interface WebPasteboardItemData : NSObject
 - (NSInteger)changeCount;
 
 @optional
-- (void)setItemsFromObjectRepresentations:(NSArray<WebPasteboardItemData *> *)itemData;
+- (void)setItemsUsingRegistrationInfoLists:(NSArray *)itemLists;
 - (void)setItems:(NSArray<NSDictionary *> *)items;
+- (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index;
 @property (readonly, nonatomic) NSInteger numberOfFiles;
 @property (readonly, nonatomic) NSArray<NSURL *> *filenamesForDataInteraction;
 
 @end
 
+NS_ASSUME_NONNULL_END
+
 #endif // TARGET_OS_IPHONE
diff --git a/Source/WebCore/platform/ios/AbstractPasteboard.mm b/Source/WebCore/platform/ios/AbstractPasteboard.mm
deleted file mode 100644 (file)
index 27a2a57..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 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 "AbstractPasteboard.h"
-
-#import <wtf/RetainPtr.h>
-
-#if PLATFORM(IOS)
-
-@interface WebPasteboardItemData ()
-{
-    RetainPtr<NSArray> _representingObjects;
-    RetainPtr<NSDictionary> _additionalData;
-}
-
-@end
-
-@implementation WebPasteboardItemData
-
-+ (instancetype)itemWithRepresentingObjects:(NSArray *)representingObjects additionalData:(NSDictionary *)additionalData
-{
-    return [[[self alloc] initWithRepresentingObjects:representingObjects additionalData:additionalData] autorelease];
-}
-
-- (instancetype)initWithRepresentingObjects:(NSArray *)representingObjects additionalData:(NSDictionary *)additionalData
-{
-    if (self = [super init]) {
-        _representingObjects = representingObjects;
-        _additionalData = additionalData;
-    }
-    return self;
-}
-
-- (NSArray *)representingObjects
-{
-    return _representingObjects.get();
-}
-
-- (NSDictionary *)additionalData
-{
-    return _additionalData.get();
-}
-
-@end
-
-#endif // PLATFORM(IOS)
index 8135e23..39ca57b 100644 (file)
@@ -165,8 +165,53 @@ static NSArray* supportedImageTypes()
     return @[(id)kUTTypePNG, (id)kUTTypeTIFF, (id)kUTTypeJPEG, (id)kUTTypeGIF];
 }
 
+static bool readPasteboardWebContentDataForType(PasteboardWebContentReader& reader, PasteboardStrategy& strategy, NSString *type, int itemIndex, const String& pasteboardName)
+{
+    if ([type isEqualToString:WebArchivePboardType]) {
+        RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, WebArchivePboardType, pasteboardName);
+        return reader.readWebArchive(buffer.get());
+    }
+
+    if ([type isEqualToString:(NSString *)kUTTypeHTML]) {
+        String htmlString = strategy.readStringFromPasteboard(itemIndex, kUTTypeHTML, pasteboardName);
+        return !htmlString.isNull() && reader.readHTML(htmlString);
+    }
+
+    if ([type isEqualToString:(NSString *)kUTTypeFlatRTFD]) {
+        RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeFlatRTFD, pasteboardName);
+        return buffer && reader.readRTFD(*buffer);
+    }
+
+    if ([type isEqualToString:(NSString *)kUTTypeRTF]) {
+        RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeRTF, pasteboardName);
+        return buffer && reader.readRTF(*buffer);
+    }
+
+    if ([supportedImageTypes() containsObject:type]) {
+        RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, type, pasteboardName);
+        return buffer && reader.readImage(buffer.releaseNonNull(), type);
+    }
+
+    if ([type isEqualToString:(NSString *)kUTTypeURL]) {
+        URL url = strategy.readURLFromPasteboard(itemIndex, kUTTypeURL, pasteboardName);
+        return !url.isNull() && reader.readURL(url, String());
+    }
+
+    if (UTTypeConformsTo((CFStringRef)type, kUTTypeText)) {
+        String string = strategy.readStringFromPasteboard(itemIndex, kUTTypeText, pasteboardName);
+        return !string.isNull() && reader.readPlainText(string);
+    }
+
+    return false;
+}
+
 void Pasteboard::read(PasteboardWebContentReader& reader)
 {
+    if (respectsUTIFidelities()) {
+        readRespectingUTIFidelities(reader);
+        return;
+    }
+
     PasteboardStrategy& strategy = *platformStrategies()->pasteboardStrategy();
 
     int numberOfItems = strategy.getPasteboardItemsCount(m_pasteboardName);
@@ -179,54 +224,32 @@ void Pasteboard::read(PasteboardWebContentReader& reader)
 
     for (int i = 0; i < numberOfItems; i++) {
         for (int typeIndex = 0; typeIndex < numberOfTypes; typeIndex++) {
-            NSString *type = [types objectAtIndex:typeIndex];
-
-            if ([type isEqualToString:WebArchivePboardType]) {
-                if (RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(i, WebArchivePboardType, m_pasteboardName)) {
-                    if (reader.readWebArchive(buffer.get()))
-                        break;
-                }
-            }
-
-            if ([type isEqualToString:(NSString *)kUTTypeHTML]) {
-                String htmlString = strategy.readStringFromPasteboard(i, kUTTypeHTML, m_pasteboardName);
-                if (!htmlString.isNull() && reader.readHTML(htmlString))
-                    break;
-            }
-
-            if ([type isEqualToString:(NSString *)kUTTypeFlatRTFD]) {
-                if (RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(i, kUTTypeFlatRTFD, m_pasteboardName)) {
-                    if (reader.readRTFD(*buffer))
-                        break;
-                }
-            }
-
-            if ([type isEqualToString:(NSString *)kUTTypeRTF]) {
-                if (RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(i, kUTTypeRTF, m_pasteboardName)) {
-                    if (reader.readRTF(*buffer))
-                        break;
-                }
-            }
-
-            if ([supportedImageTypes() containsObject:type]) {
-                if (RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(i, type, m_pasteboardName)) {
-                    if (reader.readImage(buffer.releaseNonNull(), type))
-                        break;
-                }
+            if (readPasteboardWebContentDataForType(reader, strategy, [types objectAtIndex:typeIndex], i, m_pasteboardName))
+                break;
         }
+    }
+}
 
-            if ([type isEqualToString:(NSString *)kUTTypeURL]) {
-                URL url = strategy.readURLFromPasteboard(i, kUTTypeURL, m_pasteboardName);
-                if (!url.isNull() && reader.readURL(url, String()))
-                    break;
-            }
-            
-            if ([type isEqualToString:(NSString *)kUTTypeText]) {
-                String string = strategy.readStringFromPasteboard(i, kUTTypeText, m_pasteboardName);
-                if (!string.isNull() && reader.readPlainText(string))
-                    break;
-            }
+bool Pasteboard::respectsUTIFidelities() const
+{
+    // For now, data interaction is the only feature that uses item-provider-based pasteboard representations.
+    // In the future, we may need to consult the client layer to determine whether or not the pasteboard supports
+    // item types ranked by fidelity.
+    return m_pasteboardName == "data interaction pasteboard";
+}
 
+void Pasteboard::readRespectingUTIFidelities(PasteboardWebContentReader& reader)
+{
+    ASSERT(respectsUTIFidelities());
+    auto& strategy = *platformStrategies()->pasteboardStrategy();
+    for (NSUInteger index = 0, numberOfItems = strategy.getPasteboardItemsCount(m_pasteboardName); index < numberOfItems; ++index) {
+        // Try to read data from each type identifier that this pasteboard item supports, and WebKit also recognizes. Type identifiers are
+        // read in order of fidelity, as specified by each pasteboard item.
+        Vector<String> typesForItemInOrderOfFidelity;
+        strategy.getTypesByFidelityForItemAtIndex(typesForItemInOrderOfFidelity, index, m_pasteboardName);
+        for (auto& type : typesForItemInOrderOfFidelity) {
+            if (readPasteboardWebContentDataForType(reader, strategy, type, index, m_pasteboardName))
+                break;
         }
     }
 }
index ab1be83..d265b16 100644 (file)
 #import <UIKit/UIPasteboard.h>
 
 #if ENABLE(DATA_INTERACTION)
+#import <UIKit/NSAttributedString+UIItemProvider.h>
+#import <UIKit/NSString+UIItemProvider.h>
 #import <UIKit/NSURL+UIItemProvider.h>
+#import <UIKit/UIImage+UIItemProvider.h>
 #endif
 
 SOFT_LINK_FRAMEWORK(UIKit)
@@ -73,6 +76,16 @@ void PlatformPasteboard::getTypes(Vector<String>& types)
         types.append(pasteboardType);
 }
 
+void PlatformPasteboard::getTypesByFidelityForItemAtIndex(Vector<String>& types, int index)
+{
+    if (index >= [m_pasteboard numberOfItems] || ![m_pasteboard respondsToSelector:@selector(pasteboardTypesByFidelityForItemAtIndex:)])
+        return;
+
+    NSArray *pasteboardTypesByFidelity = [m_pasteboard pasteboardTypesByFidelityForItemAtIndex:index];
+    for (NSString *typeIdentifier in pasteboardTypesByFidelity)
+        types.append(typeIdentifier);
+}
+
 RefPtr<SharedBuffer> PlatformPasteboard::bufferForType(const String&)
 {
     return nullptr;
@@ -187,24 +200,37 @@ static RetainPtr<NSDictionary> richTextRepresentationsForPasteboardWebContent(co
 
 void PlatformPasteboard::writeObjectRepresentations(const PasteboardWebContent& content)
 {
-    RetainPtr<NSMutableArray> objectRepresentations = adoptNS([[NSMutableArray alloc] init]);
-    RetainPtr<NSDictionary> additionalData = richTextRepresentationsForPasteboardWebContent(content);
+#if ENABLE(DATA_INTERACTION)
+    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+
+    ASSERT(content.clientTypes.size() == content.clientData.size());
+    for (size_t i = 0, size = content.clientTypes.size(); i < size; ++i)
+        [itemsToRegister addData:content.clientData[i]->createNSData().get() forType:content.clientTypes[i]];
+
+    if (content.dataInWebArchiveFormat)
+        [itemsToRegister addData:content.dataInWebArchiveFormat->createNSData().get() forType:WebArchivePboardType];
 
     if (content.dataInAttributedStringFormat) {
         NSAttributedString *attributedString = [NSKeyedUnarchiver unarchiveObjectWithData:content.dataInAttributedStringFormat->createNSData().get()];
         if (attributedString)
-            [objectRepresentations addObject:attributedString];
+            [itemsToRegister addRepresentingObject:attributedString];
     }
 
+    if (content.dataInRTFFormat)
+        [itemsToRegister addData:content.dataInRTFFormat->createNSData().get() forType:(NSString *)kUTTypeRTF];
+
     if (!content.dataInStringFormat.isEmpty())
-        [objectRepresentations addObject:(NSString *)content.dataInStringFormat];
+        [itemsToRegister addRepresentingObject:(NSString *)content.dataInStringFormat];
 
-    [m_pasteboard setItemsFromObjectRepresentations:@[[WebPasteboardItemData itemWithRepresentingObjects:objectRepresentations.get() additionalData:additionalData.get()]]];
+    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
+#else
+    UNUSED_PARAM(content);
+#endif
 }
 
 void PlatformPasteboard::write(const PasteboardWebContent& content)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsFromObjectRepresentations:)]) {
+    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
         writeObjectRepresentations(content);
         return;
     }
@@ -218,30 +244,33 @@ void PlatformPasteboard::write(const PasteboardWebContent& content)
 
 void PlatformPasteboard::writeObjectRepresentations(const PasteboardImage& pasteboardImage)
 {
-    RetainPtr<NSMutableArray> objectRepresentations = adoptNS([[NSMutableArray alloc] init]);
-    RetainPtr<NSMutableDictionary> additionalData = adoptNS([[NSMutableDictionary alloc] init]);
+#if ENABLE(DATA_INTERACTION)
+    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+
+    if (!pasteboardImage.resourceMIMEType.isNull())
+        [itemsToRegister addData:pasteboardImage.resourceData->createNSData().get() forType:pasteboardImage.resourceMIMEType];
 
     if (auto nativeImage = pasteboardImage.image->nativeImage()) {
         UIImage *uiImage = (UIImage *)[getUIImageClass() imageWithCGImage:nativeImage.get()];
         if (uiImage)
-            [objectRepresentations addObject:uiImage];
+            [itemsToRegister addRepresentingObject:uiImage];
     }
 
     if (!pasteboardImage.url.url.isEmpty()) {
         NSURL *nsURL = pasteboardImage.url.url;
         if (nsURL)
-            [objectRepresentations addObject:nsURL];
+            [itemsToRegister addRepresentingObject:nsURL];
     }
 
-    if (!pasteboardImage.resourceMIMEType.isNull())
-        [additionalData setObject:pasteboardImage.resourceData->createNSData().get() forKey:pasteboardImage.resourceMIMEType];
-
-    [m_pasteboard setItemsFromObjectRepresentations:@[[WebPasteboardItemData itemWithRepresentingObjects:objectRepresentations.get() additionalData:additionalData.get()]]];
+    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
+#else
+    UNUSED_PARAM(pasteboardImage);
+#endif
 }
 
 void PlatformPasteboard::write(const PasteboardImage& pasteboardImage)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsFromObjectRepresentations:)]) {
+    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
         writeObjectRepresentations(pasteboardImage);
         return;
     }
@@ -256,27 +285,29 @@ void PlatformPasteboard::write(const PasteboardImage& pasteboardImage)
 
 void PlatformPasteboard::writeObjectRepresentations(const String& pasteboardType, const String& text)
 {
-    RetainPtr<NSMutableArray> objectRepresentations = adoptNS([[NSMutableArray alloc] init]);
-    RetainPtr<NSMutableDictionary> additionalData = adoptNS([[NSMutableDictionary alloc] init]);
+#if ENABLE(DATA_INTERACTION)
+    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
 
     NSString *pasteboardTypeAsNSString = pasteboardType;
     NSString *textAsNSString = text;
     if (textAsNSString && pasteboardTypeAsNSString.length) {
         if (UTTypeConformsTo((__bridge CFStringRef)pasteboardTypeAsNSString, kUTTypeURL))
-            [objectRepresentations addObject:[[[NSURL alloc] initWithString:textAsNSString] autorelease]];
+            [itemsToRegister addRepresentingObject:[[[NSURL alloc] initWithString:textAsNSString] autorelease]];
 
         if (UTTypeConformsTo((__bridge CFStringRef)pasteboardTypeAsNSString, kUTTypeText))
-            [objectRepresentations addObject:textAsNSString];
-        else
-            [additionalData setObject:textAsNSString forKey:pasteboardTypeAsNSString];
+            [itemsToRegister addRepresentingObject:textAsNSString];
     }
 
-    [m_pasteboard setItemsFromObjectRepresentations:@[[WebPasteboardItemData itemWithRepresentingObjects:objectRepresentations.get() additionalData:additionalData.get()]]];
+    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
+#else
+    UNUSED_PARAM(pasteboardType);
+    UNUSED_PARAM(text);
+#endif
 }
 
 void PlatformPasteboard::write(const String& pasteboardType, const String& text)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsFromObjectRepresentations:)]) {
+    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
         writeObjectRepresentations(pasteboardType, text);
         return;
     }
@@ -293,22 +324,24 @@ void PlatformPasteboard::write(const String& pasteboardType, const String& text)
 
 void PlatformPasteboard::writeObjectRepresentations(const PasteboardURL& url)
 {
-    auto objectRepresentations = adoptNS([[NSMutableArray alloc] init]);
+#if ENABLE(DATA_INTERACTION)
+    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
 
     if (NSURL *nsURL = url.url) {
-        [objectRepresentations addObject:nsURL];
-#if ENABLE(DATA_INTERACTION)
+        [itemsToRegister addRepresentingObject:nsURL];
         if (!url.title.isEmpty())
             nsURL._title = url.title;
-#endif
     }
 
-    [m_pasteboard setItemsFromObjectRepresentations:@[[WebPasteboardItemData itemWithRepresentingObjects:objectRepresentations.get() additionalData:nil]]];
+    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
+#else
+    UNUSED_PARAM(url);
+#endif
 }
 
 void PlatformPasteboard::write(const PasteboardURL& url)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsFromObjectRepresentations:)]) {
+    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
         writeObjectRepresentations(url);
         return;
     }
index 8323e72..47f5964 100644 (file)
 #if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
 
 @class UIItemProvider;
+@protocol UIItemProviderWriting;
 
 NS_ASSUME_NONNULL_BEGIN
 
+/*! A WebItemProviderRegistrationInfo represents a single call to register something to an item provider.
+ @discussion Either the representing object exists and the type identifier and data are nil, or the
+ representing object is nil and the type identifier and data exist. The former represents a call to
+ register an entire UIItemProviderWriting-conformant object to the item provider, while the latter
+ represents a call to register only a data representation for the given type identifier.
+ */
+WEBCORE_EXPORT @interface WebItemProviderRegistrationInfo : NSObject
+
+@property (nonatomic, readonly, nullable, strong) id <UIItemProviderWriting> representingObject;
+@property (nonatomic, readonly, nullable, strong) NSString *typeIdentifier;
+@property (nonatomic, readonly, nullable, strong) NSData *data;
+
+@end
+
+/*! A WebItemProviderRegistrationInfoList represents a series of registration calls used to set up a
+ @discussion single item provider. The order of items specified in the list (lowest indices first) is
+ the order in which objects or data are registered to the item provider, and therefore indicates the
+ relative fidelity of each item. Private UTI types, such as those vended through the injected editing
+ bundle SPI, are considered to be higher fidelity than the other default types.
+ */
+WEBCORE_EXPORT @interface WebItemProviderRegistrationInfoList : NSObject
+
+- (void)addRepresentingObject:(id <UIItemProviderWriting>)object;
+- (void)addData:(NSData *)data forType:(NSString *)typeIdentifier;
+
+- (NSUInteger)numberOfItems;
+- (nullable WebItemProviderRegistrationInfo *)itemAtIndex:(NSUInteger)index;
+- (void)enumerateItems:(void(^)(WebItemProviderRegistrationInfo *item, NSUInteger index))block;
+
+@end
+
 typedef void (^WebItemProviderFileLoadBlock)(NSArray<NSURL *> *);
 
 WEBCORE_EXPORT @interface WebItemProviderPasteboard : NSObject<AbstractPasteboard>
index 060f52c..cd7639a 100644 (file)
@@ -76,6 +76,96 @@ static BOOL isImageType(NSString *type)
     return MATCHES_UTI_TYPE(type, PNG) || MATCHES_UTI_TYPE(type, JPEG) || MATCHES_UTI_TYPE(type, GIF) || MATCHES_UIKIT_TYPE(type, image);
 }
 
+@interface WebItemProviderRegistrationInfo ()
+{
+    RetainPtr<id <UIItemProviderWriting>> _representingObject;
+    RetainPtr<NSString> _typeIdentifier;
+    RetainPtr<NSData> _data;
+}
+@end
+
+@implementation WebItemProviderRegistrationInfo
+
+- (instancetype)initWithRepresentingObject:(id <UIItemProviderWriting>)representingObject typeIdentifier:(NSString *)typeIdentifier data:(NSData *)data
+{
+    if (representingObject)
+        ASSERT(!typeIdentifier && !data);
+    else
+        ASSERT(typeIdentifier && data);
+
+    if (self = [super init]) {
+        _representingObject = representingObject;
+        _typeIdentifier = typeIdentifier;
+        _data = data;
+    }
+    return self;
+}
+
+- (id <UIItemProviderWriting>)representingObject
+{
+    return _representingObject.get();
+}
+
+- (NSString *)typeIdentifier
+{
+    return _typeIdentifier.get();
+}
+
+- (NSData *)data
+{
+    return _data.get();
+}
+
+@end
+
+@interface WebItemProviderRegistrationInfoList ()
+{
+    RetainPtr<NSMutableArray> _items;
+}
+@end
+
+@implementation WebItemProviderRegistrationInfoList
+
+- (instancetype)init
+{
+    if (self = [super init])
+        _items = adoptNS([[NSMutableArray alloc] init]);
+
+    return self;
+}
+
+- (void)addData:(NSData *)data forType:(NSString *)typeIdentifier
+{
+    [_items addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:nil typeIdentifier:typeIdentifier data:data] autorelease]];
+}
+
+- (void)addRepresentingObject:(id <UIItemProviderWriting>)object
+{
+    ASSERT([object conformsToProtocol:@protocol(UIItemProviderWriting)]);
+    [_items addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:object typeIdentifier:nil data:nil] autorelease]];
+}
+
+- (NSUInteger)numberOfItems
+{
+    return [_items count];
+}
+
+- (WebItemProviderRegistrationInfo *)itemAtIndex:(NSUInteger)index
+{
+    if (index >= self.numberOfItems)
+        return nil;
+
+    return [_items objectAtIndex:index];
+}
+
+- (void)enumerateItems:(void (^)(WebItemProviderRegistrationInfo *, NSUInteger))block
+{
+    for (NSUInteger index = 0; index < self.numberOfItems; ++index)
+        block([self itemAtIndex:index], index);
+}
+
+@end
+
 @interface WebItemProviderPasteboard ()
 
 @property (nonatomic) NSInteger numberOfItems;
@@ -111,6 +201,11 @@ static BOOL isImageType(NSString *type)
     return self;
 }
 
+- (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index
+{
+    return [self itemProviderAtIndex:index].registeredTypeIdentifiers ?: @[ ];
+}
+
 - (NSArray<NSString *> *)pasteboardTypes
 {
     if (_cachedTypeIdentifiers)
@@ -153,34 +248,29 @@ static BOOL isImageType(NSString *type)
     return [_itemProviders count];
 }
 
-- (void)setItemsFromObjectRepresentations:(NSArray<WebPasteboardItemData *> *)itemData
+- (void)setItemsUsingRegistrationInfoLists:(NSArray<WebItemProviderRegistrationInfoList *> *)itemLists
 {
     NSMutableArray *providers = [NSMutableArray array];
-    for (WebPasteboardItemData *data in itemData) {
-        if (!data.representingObjects.count && !data.additionalData.count)
+    for (WebItemProviderRegistrationInfoList *itemList in itemLists) {
+        if (!itemList.numberOfItems)
             continue;
 
-        RetainPtr<UIItemProvider> itemProvider = adoptNS([[getUIItemProviderClass() alloc] init]);
-        // First, register all platform objects, prioritizing objects at the beginning of the array.
-        for (id representingObject in data.representingObjects) {
-            if (![representingObject conformsToProtocol:@protocol(UIItemProviderWriting)])
-                continue;
+        auto itemProvider = adoptNS([[getUIItemProviderClass() alloc] init]);
+        [itemList enumerateItems:[itemProvider] (WebItemProviderRegistrationInfo *item, NSUInteger) {
+            if (item.representingObject) {
+                [itemProvider registerObject:item.representingObject visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+                return;
+            }
 
-            [itemProvider registerObject:(id <UIItemProviderWriting>)representingObject visibility:UIItemProviderRepresentationOptionsVisibilityAll];
-        }
+            if (!item.typeIdentifier.length || !item.data.length)
+                return;
 
-        // Next, register other custom data representations for type identifiers.
-        NSDictionary <NSString *, NSData *> *additionalData = data.additionalData;
-        for (NSString *typeIdentifier in additionalData) {
-            if (![additionalData[typeIdentifier] isKindOfClass:[NSData class]])
-                continue;
-
-            [itemProvider registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler:^NSProgress *(ItemProviderDataLoadCompletionHandler completionHandler)
-            {
-                completionHandler(additionalData[typeIdentifier], nil);
-                return [NSProgress discreteProgressWithTotalUnitCount:100];
+            RetainPtr<NSData> itemData = item.data;
+            [itemProvider registerDataRepresentationForTypeIdentifier:item.typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler:[itemData] (ItemProviderDataLoadCompletionHandler completionHandler) -> NSProgress * {
+                completionHandler(itemData.get(), nil);
+                return nil;
             }];
-        }
+        }];
         [providers addObject:itemProvider.get()];
     }
 
index 0fa459b..5718ad8 100644 (file)
@@ -1,3 +1,17 @@
+2017-04-24  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Respect fidelity order when reading web content from item providers
+        https://bugs.webkit.org/show_bug.cgi?id=171155
+        <rdar://problem/31356937>
+
+        Reviewed by Tim Horton.
+
+        Adjusts for changes in WebCore (see WebCore/ChangeLog for more details).
+
+        * WebCoreSupport/WebPlatformStrategies.h:
+        * WebCoreSupport/WebPlatformStrategies.mm:
+        (WebPlatformStrategies::getTypesByFidelityForItemAtIndex):
+
 2017-04-24  Alex Christensen  <achristensen@webkit.org>
 
         Reduce copies and allocations in SharedBuffer::append
index 0436b33..fa38348 100644 (file)
@@ -67,6 +67,7 @@ private:
     RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
+    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
 #endif
     int getNumberOfFiles(const String& pasteboardName) override;
     void getTypes(Vector<String>& types, const String& pasteboardName) override;
index 7e9bb44..af40e17 100644 (file)
@@ -186,6 +186,11 @@ int WebPlatformStrategies::getNumberOfFiles(const String& pasteboardName)
 }
 
 #if PLATFORM(IOS)
+void WebPlatformStrategies::getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName)
+{
+    PlatformPasteboard(pasteboardName).getTypesByFidelityForItemAtIndex(types, index);
+}
+
 void WebPlatformStrategies::writeToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
     PlatformPasteboard(pasteboardName).write(url);
index 0c67f4a..74cb8f7 100644 (file)
@@ -1,3 +1,22 @@
+2017-04-24  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Respect fidelity order when reading web content from item providers
+        https://bugs.webkit.org/show_bug.cgi?id=171155
+        <rdar://problem/31356937>
+
+        Reviewed by Tim Horton.
+
+        Adjusts for changes in WebCore by adding plumbing to support Pasteboard::getTypesByFidelityForItemAtIndex. See
+        WebCore/ChangeLog for more details.
+
+        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
+        (WebKit::WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex):
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
+        (WebKit::WebPlatformStrategies::getTypesByFidelityForItemAtIndex):
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
+
 2017-04-24  Brady Eidson  <beidson@apple.com>
 
         WebProcessPools should always have a WebsiteDataStore
index b836516..c968197 100644 (file)
@@ -140,6 +140,11 @@ void WebPasteboardProxy::getNumberOfFiles(const String& pasteboardName, uint64_t
 }
 
 #if PLATFORM(IOS)
+void WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex(uint64_t index, const String& pasteboardName, Vector<String>& types)
+{
+    PlatformPasteboard(pasteboardName).getTypesByFidelityForItemAtIndex(types, index);
+}
+
 void WebPasteboardProxy::writeURLToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
     PlatformPasteboard(pasteboardName).write(url);
index 86b902d..bf946c4 100644 (file)
@@ -69,6 +69,7 @@ private:
     void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override;
 
 #if PLATFORM(IOS)
+    void getPasteboardTypesByFidelityForItemAtIndex(uint64_t index, const String& pasteboardName, Vector<String>& types);
     void writeURLToPasteboard(const WebCore::PasteboardURL&, const String& pasteboardName);
     void writeWebContentToPasteboard(const WebCore::PasteboardWebContent&, const String& pasteboardName);
     void writeImageToPasteboard(const WebCore::PasteboardImage&, const String& pasteboardName);
index 2140f64..8a936c5 100644 (file)
@@ -31,6 +31,7 @@ messages -> WebPasteboardProxy {
     ReadBufferFromPasteboard(uint64_t index, String pasteboardType, String pasteboardName) -> (WebKit::SharedMemory::Handle handle, uint64_t size)
     GetPasteboardItemsCount(String pasteboardName) -> (uint64_t itemsCount)
     GetFilenamesForDataInteraction(String pasteboardName) -> (Vector<String> filenames)
+    GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types)
 #endif
 
 #if PLATFORM(COCOA)
index 8ba733a..3d4f960 100644 (file)
@@ -287,6 +287,11 @@ int WebPlatformStrategies::getNumberOfFiles(const String& pasteboardName)
 }
 
 #if PLATFORM(IOS)
+void WebPlatformStrategies::getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName)
+{
+    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex(index, pasteboardName), Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex::Reply(types), 0);
+}
+
 void WebPlatformStrategies::writeToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteURLToPasteboard(url, pasteboardName), 0);
index 7fe3492..23b4fec 100644 (file)
@@ -68,6 +68,7 @@ private:
     RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
+    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
 #endif
 #if PLATFORM(COCOA)
     int getNumberOfFiles(const String& pasteboardName) override;
index 73097f3..f8e5fd3 100644 (file)
@@ -1,3 +1,17 @@
+2017-04-24  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Respect fidelity order when reading web content from item providers
+        https://bugs.webkit.org/show_bug.cgi?id=171155
+        <rdar://problem/31356937>
+
+        Reviewed by Tim Horton.
+
+        Adds a new unit test (DataInteractionTests.RespectsExternalSourceFidelityRankings). See WebCore ChangeLog for
+        more details.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
 2017-04-24  Carlos Alberto Lopez Perez  <clopez@igalia.com>
 
         SyntaxError fix after r215702.
index eb2d346..f40d6be 100644 (file)
@@ -32,7 +32,9 @@
 #import "TestWKWebView.h"
 #import "WKWebViewConfigurationExtras.h"
 #import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/NSString+UIItemProvider.h>
 #import <UIKit/NSURL+UIItemProvider.h>
+#import <UIKit/UIImage+UIItemProvider.h>
 #import <UIKit/UIItemProvider_Private.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
@@ -462,6 +464,39 @@ TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
     cleanUpDataInteractionTemporaryPath();
 }
 
+TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+    [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
+
+    auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+    // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
+    // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
+    // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
+    // than an image.
+    auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
+    [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
+    [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:NSItemProviderRepresentationVisibilityAll];
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
+
+    [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
+    EXPECT_FALSE([webView editorContainsImageElement]);
+    [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
+
+    // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
+    auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
+    [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:NSItemProviderRepresentationVisibilityAll];
+    [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
+
+    [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
+    EXPECT_TRUE([webView editorContainsImageElement]);
+}
+
 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);