[iOS] Respect type fidelities when copying image elements to the pasteboard
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Aug 2017 18:34:15 +0000 (18:34 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Aug 2017 18:34:15 +0000 (18:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175638
<rdar://problem/26556043>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Ensures that we respect type fidelities when copying on iOS, by unifying pasteboard writing codepaths across
dragging and copying. When dragging and copying, we now generate and set UIItemProviders on the UIPasteboard.

Tests: ActionSheetTests.CopyImageElementWithHREF
       ActionSheetTests.CopyImageElementWithoutHREF

* platform/PlatformPasteboard.h:

Remove all variants of the writeObjectRepresentations helper method. Now that both paths for writing to the
pasteboard are unified, it's no longer useful to separate out item-provider-based pasteboard logic.

* platform/ios/AbstractPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:

Replaces -setItemsUsingRegistrationInfoLists: with -setRegistrationInfoLists:. Rather than have a helper that
both sets up item providers and item registration lists, split this functionality out into two setters. This is
because UIPasteboard does not need to know about the registration info lists used to set up the item providers
in the first place, but internal drag-and-drop clients require this information immediately when starting a drag
in order to construct custom drag previews.

(WebCore::richTextRepresentationsForPasteboardWebContent):
(WebCore::registerItemToPasteboard):

Add a new helper to register item providers to the pasteboard, given an WebItemProviderRegistrationInfoList.

(WebCore::PlatformPasteboard::write):
(WebCore::PlatformPasteboard::writeObjectRepresentations): Deleted.

Refactors PlatformPasteboard::write to always generate and set item providers, unless we're building for an SDK
prior to iOS 11. For images, strings and URLs, we can simply transition to using the new item-provider-based
codepaths used for drag and drop. For web content, we add two additional UTIs that were present when copying,
but not when dragging: flat RTFD and a string constant used to indicate to UIKit that the pasteboard contains
rich text.

* platform/ios/WebItemProviderPasteboard.h:
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderRegistrationInfoList init]):
(-[WebItemProviderRegistrationInfoList addData:forType:]):
(-[WebItemProviderRegistrationInfoList addRepresentingObject:]):
(-[WebItemProviderRegistrationInfoList numberOfItems]):
(-[WebItemProviderRegistrationInfoList itemAtIndex:]):
(-[WebItemProviderRegistrationInfoList itemProvider]):
(-[WebItemProviderRegistrationInfoList description]):

Make some small tweaks in WebItemProviderPasteboard (and related classes):
1. Transition to preferredPresentationSize from estimatedDisplayedSize, which is now deprecated.
2. Remove calls to -initWithItemProviderData:typeIdentifier:error:, which is deprecated.
3. Rename _items to _representations to better reflect the role of WebItemProviderRegistrationInfo.
4. Implement -description for WebItemProviderRegistrationInfoList for debugging purposes.

(-[WebItemProviderPasteboard valuesForPasteboardType:inItemSet:]):
(-[WebItemProviderPasteboard setRegistrationInfoLists:]):
(-[WebItemProviderPasteboard setItemsUsingRegistrationInfoLists:]): Deleted.

Source/WebCore/PAL:

Replace -estimatedDisplayedSize with its non-deprecated counterpart, -preferredPresentationSize.

* pal/spi/ios/UIKitSPI.h:

Source/WebKit:

Currently, we treat the case when copying an image enclosed by a link by only writing a URL to the pasteboard.
This patch tweaks logic in WebPage::performActionOnElement to write both an image and a link to the pasteboard
if the hit-tested image element is enclosed by an anchor.

* Platform/spi/ios/UIKitSPI.h:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::containingLinkElement):

Tweak this helper to be more restrictive when finding an enclosing 'link' -- only return an element if isLink()
is true, and it is an HTMLAnchorElement. Currently, the isLink() also matches HTMLLinkElements, but this isn't
the intention here.

(WebKit::WebPage::performActionOnElement):

Tools:

Add API tests that simulate copying an image element using the action sheet, and verifying that the pasteboard
contains UTIs in order of fidelity (image type before URL). Also pulls out UIKit SPI (UIApplicationInitialize)
used in UIPasteboardTests and ActionSheetTests into a common UIKitSPI header.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/ios/ActionSheetTests.mm:
(-[ActionSheetObserver _webView:actionsForElement:defaultActions:]):
(TestWebKitAPI::TEST):
(TestWebKitAPI::presentActionSheetAndChooseAction):
(-[ActionSheetObserver waitForActionSheetAfterBlock:]): Deleted.
* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(checkEstimatedSize):
(checkSuggestedNameAndEstimatedSize):

Replace -estimatedDisplayedSize with its non-deprecated counterpart, -preferredPresentationSize.

* TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/UIKitSPI.h: Added.

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/ios/UIKitSPI.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/ios/AbstractPasteboard.h
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebCore/platform/ios/WebItemProviderPasteboard.h
Source/WebCore/platform/ios/WebItemProviderPasteboard.mm
Source/WebKit/ChangeLog
Source/WebKit/Platform/spi/ios/UIKitSPI.h
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/ios/ActionSheetTests.mm
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
Tools/TestWebKitAPI/Tests/ios/UIPasteboardTests.mm
Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
Tools/TestWebKitAPI/ios/UIKitSPI.h [new file with mode: 0644]

index 39f28a5..14657d4 100644 (file)
@@ -1,3 +1,65 @@
+2017-08-17  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Respect type fidelities when copying image elements to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=175638
+        <rdar://problem/26556043>
+
+        Reviewed by Ryosuke Niwa.
+
+        Ensures that we respect type fidelities when copying on iOS, by unifying pasteboard writing codepaths across
+        dragging and copying. When dragging and copying, we now generate and set UIItemProviders on the UIPasteboard.
+
+        Tests: ActionSheetTests.CopyImageElementWithHREF
+               ActionSheetTests.CopyImageElementWithoutHREF
+
+        * platform/PlatformPasteboard.h:
+
+        Remove all variants of the writeObjectRepresentations helper method. Now that both paths for writing to the
+        pasteboard are unified, it's no longer useful to separate out item-provider-based pasteboard logic.
+
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/PlatformPasteboardIOS.mm:
+
+        Replaces -setItemsUsingRegistrationInfoLists: with -setRegistrationInfoLists:. Rather than have a helper that
+        both sets up item providers and item registration lists, split this functionality out into two setters. This is
+        because UIPasteboard does not need to know about the registration info lists used to set up the item providers
+        in the first place, but internal drag-and-drop clients require this information immediately when starting a drag
+        in order to construct custom drag previews.
+
+        (WebCore::richTextRepresentationsForPasteboardWebContent):
+        (WebCore::registerItemToPasteboard):
+
+        Add a new helper to register item providers to the pasteboard, given an WebItemProviderRegistrationInfoList.
+
+        (WebCore::PlatformPasteboard::write):
+        (WebCore::PlatformPasteboard::writeObjectRepresentations): Deleted.
+
+        Refactors PlatformPasteboard::write to always generate and set item providers, unless we're building for an SDK
+        prior to iOS 11. For images, strings and URLs, we can simply transition to using the new item-provider-based
+        codepaths used for drag and drop. For web content, we add two additional UTIs that were present when copying,
+        but not when dragging: flat RTFD and a string constant used to indicate to UIKit that the pasteboard contains
+        rich text.
+
+        * platform/ios/WebItemProviderPasteboard.h:
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderRegistrationInfoList init]):
+        (-[WebItemProviderRegistrationInfoList addData:forType:]):
+        (-[WebItemProviderRegistrationInfoList addRepresentingObject:]):
+        (-[WebItemProviderRegistrationInfoList numberOfItems]):
+        (-[WebItemProviderRegistrationInfoList itemAtIndex:]):
+        (-[WebItemProviderRegistrationInfoList itemProvider]):
+        (-[WebItemProviderRegistrationInfoList description]):
+
+        Make some small tweaks in WebItemProviderPasteboard (and related classes):
+        1. Transition to preferredPresentationSize from estimatedDisplayedSize, which is now deprecated.
+        2. Remove calls to -initWithItemProviderData:typeIdentifier:error:, which is deprecated.
+        3. Rename _items to _representations to better reflect the role of WebItemProviderRegistrationInfo.
+        4. Implement -description for WebItemProviderRegistrationInfoList for debugging purposes.
+
+        (-[WebItemProviderPasteboard valuesForPasteboardType:inItemSet:]):
+        (-[WebItemProviderPasteboard setRegistrationInfoLists:]):
+        (-[WebItemProviderPasteboard setItemsUsingRegistrationInfoLists:]): Deleted.
+
 2017-08-17  Youenn Fablet  <youenn@apple.com>
 
         Add a DOMPromiseDeferred method to handle ExceptionOr<> results
index aa8272b..8612277 100644 (file)
@@ -1,3 +1,15 @@
+2017-08-17  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Respect type fidelities when copying image elements to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=175638
+        <rdar://problem/26556043>
+
+        Reviewed by Ryosuke Niwa.
+
+        Replace -estimatedDisplayedSize with its non-deprecated counterpart, -preferredPresentationSize.
+
+        * pal/spi/ios/UIKitSPI.h:
+
 2017-08-17  Don Olmstead  <don.olmstead@sony.com>
 
         [PAL] Move SessionID into PAL
index 2e7c4fe..51a2d5a 100644 (file)
@@ -95,7 +95,7 @@ NS_ASSUME_NONNULL_END
 NS_ASSUME_NONNULL_BEGIN
 
 @interface UIItemProvider : NSItemProvider
-@property (nonatomic) CGSize estimatedDisplayedSize;
+@property (nonatomic) CGSize preferredPresentationSize;
 @end
 
 #define UIItemProviderRepresentationOptionsVisibilityAll NSItemProviderRepresentationVisibilityAll
index 700e428..b6e4fd5 100644 (file)
@@ -98,10 +98,6 @@ public:
 
 private:
 #if PLATFORM(IOS)
-    WEBCORE_EXPORT void writeObjectRepresentations(const PasteboardWebContent&);
-    WEBCORE_EXPORT void writeObjectRepresentations(const PasteboardImage&);
-    WEBCORE_EXPORT void writeObjectRepresentations(const String& pasteboardType, const String& text);
-    WEBCORE_EXPORT void writeObjectRepresentations(const PasteboardURL&);
     bool allowReadingURLAtIndex(const URL&, int index) const;
 #endif
 
index a413075..9836cb3 100644 (file)
 
 NS_ASSUME_NONNULL_BEGIN
 
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+@class WebItemProviderRegistrationInfoList;
+#endif
+
 @protocol AbstractPasteboard <NSObject>
 @required
 
@@ -44,7 +48,9 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSInteger)changeCount;
 
 @optional
-- (void)setItemsUsingRegistrationInfoLists:(NSArray *)itemLists;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+- (void)setRegistrationInfoLists:(NSArray <WebItemProviderRegistrationInfoList *> *)info;
+#endif
 - (void)setItems:(NSArray<NSDictionary *> *)items;
 - (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index;
 @property (readonly, nonatomic) NSInteger numberOfFiles;
index 3db8ad4..936701a 100644 (file)
@@ -173,6 +173,10 @@ String PlatformPasteboard::uniqueName()
     return String();
 }
 
+static NSString *webIOSPastePboardType = @"iOS rich content paste pasteboard type";
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
+
 static RetainPtr<NSDictionary> richTextRepresentationsForPasteboardWebContent(const PasteboardWebContent& content)
 {
     RetainPtr<NSMutableDictionary> representations = adoptNS([[NSMutableDictionary alloc] init]);
@@ -184,7 +188,6 @@ static RetainPtr<NSDictionary> richTextRepresentationsForPasteboardWebContent(co
     if (content.dataInWebArchiveFormat) {
         [representations setValue:(NSData *)content.dataInWebArchiveFormat->createNSData().get() forKey:WebArchivePboardType];
         // Flag for UIKit to know that this copy contains rich content. This will trigger a two-step paste.
-        NSString *webIOSPastePboardType = @"iOS rich content paste pasteboard type";
         [representations setValue:webIOSPastePboardType forKey:webIOSPastePboardType];
     }
 
@@ -196,6 +199,23 @@ static RetainPtr<NSDictionary> richTextRepresentationsForPasteboardWebContent(co
     return representations;
 }
 
+#else
+
+static void registerItemToPasteboard(WebItemProviderRegistrationInfoList *representationsToRegister, id <AbstractPasteboard> pasteboard)
+{
+    UIItemProvider *itemProvider = [representationsToRegister itemProvider];
+    if (!itemProvider) {
+        [pasteboard setItemProviders:@[ ]];
+        return;
+    }
+
+    [pasteboard setItemProviders:@[ itemProvider ]];
+    if ([pasteboard respondsToSelector:@selector(setRegistrationInfoLists:)])
+        [pasteboard setRegistrationInfoLists:@[ representationsToRegister ]];
+}
+
+#endif
+
 #if ENABLE(DATA_INTERACTION)
 
 static void addRepresentationsForPlainText(WebItemProviderRegistrationInfoList *itemsToRegister, const String& plainText)
@@ -230,68 +250,74 @@ bool PlatformPasteboard::allowReadingURLAtIndex(const URL&, int) const
 
 #endif
 
-void PlatformPasteboard::writeObjectRepresentations(const PasteboardWebContent& content)
+void PlatformPasteboard::write(const PasteboardWebContent& content)
 {
-#if ENABLE(DATA_INTERACTION)
-    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
+    RetainPtr<NSMutableDictionary> representations = adoptNS([[NSMutableDictionary alloc] init]);
+    [representations addEntriesFromDictionary:richTextRepresentationsForPasteboardWebContent(content).autorelease()];
+
+    NSString *textAsString = content.dataInStringFormat;
+    [representations setValue:[textAsString dataUsingEncoding:NSUTF8StringEncoding] forKey:(NSString *)kUTTypeUTF8PlainText];
+    [representations setValue:[textAsString dataUsingEncoding:NSUTF16StringEncoding] forKey:(NSString *)kUTTypeUTF16PlainText];
+    // FIXME: We vend "public.text" here for backwards compatibility with pre-iOS 11 apps. In the future, we should stop vending this UTI,
+    // and instead set data for concrete plain text types. See <https://bugs.webkit.org/show_bug.cgi?id=173317>.
+    [representations setValue:textAsString forKey:(NSString *)kUTTypeText];
+
+    // Explicitly cast m_pasteboard to UIPasteboard * to work around rdar://problem/33383354.
+    ASSERT([m_pasteboard isKindOfClass:getUIPasteboardClass()]);
+    [(UIPasteboard *)m_pasteboard setItems:@[representations.get()]];
+#else
+    auto representationsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+
+    [representationsToRegister addData:[webIOSPastePboardType dataUsingEncoding:NSUTF8StringEncoding] forType:webIOSPastePboardType];
 
     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]];
+        [representationsToRegister addData:content.clientData[i]->createNSData().get() forType:content.clientTypes[i]];
 
     if (content.dataInWebArchiveFormat)
-        [itemsToRegister addData:content.dataInWebArchiveFormat->createNSData().get() forType:WebArchivePboardType];
+        [representationsToRegister addData:content.dataInWebArchiveFormat->createNSData().get() forType:WebArchivePboardType];
 
     if (content.dataInAttributedStringFormat) {
         NSAttributedString *attributedString = [NSKeyedUnarchiver unarchiveObjectWithData:content.dataInAttributedStringFormat->createNSData().get()];
         if (attributedString)
-            [itemsToRegister addRepresentingObject:attributedString];
+            [representationsToRegister addRepresentingObject:attributedString];
     }
 
+    if (content.dataInRTFDFormat)
+        [representationsToRegister addData:content.dataInRTFDFormat->createNSData().get() forType:(NSString *)kUTTypeFlatRTFD];
+
     if (content.dataInRTFFormat)
-        [itemsToRegister addData:content.dataInRTFFormat->createNSData().get() forType:(NSString *)kUTTypeRTF];
+        [representationsToRegister addData:content.dataInRTFFormat->createNSData().get() forType:(NSString *)kUTTypeRTF];
 
     if (!content.dataInStringFormat.isEmpty())
-        addRepresentationsForPlainText(itemsToRegister.get(), content.dataInStringFormat);
+        addRepresentationsForPlainText(representationsToRegister.get(), content.dataInStringFormat);
 
-    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
-#else
-    UNUSED_PARAM(content);
+    registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
 #endif
 }
 
-void PlatformPasteboard::write(const PasteboardWebContent& content)
+void PlatformPasteboard::write(const PasteboardImage& pasteboardImage)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
-        writeObjectRepresentations(content);
-        return;
-    }
-
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
     RetainPtr<NSMutableDictionary> representations = adoptNS([[NSMutableDictionary alloc] init]);
-    [representations addEntriesFromDictionary:richTextRepresentationsForPasteboardWebContent(content).autorelease()];
-
-    NSString *textAsString = content.dataInStringFormat;
-    [representations setValue:[textAsString dataUsingEncoding:NSUTF8StringEncoding] forKey:(NSString *)kUTTypeUTF8PlainText];
-    [representations setValue:[textAsString dataUsingEncoding:NSUTF16StringEncoding] forKey:(NSString *)kUTTypeUTF16PlainText];
-    // FIXME: We vend "public.text" here for backwards compatibility with pre-iOS 11 apps. In the future, we should stop vending this UTI,
-    // and instead set data for concrete plain text types. See <https://bugs.webkit.org/show_bug.cgi?id=173317>.
-    [representations setValue:textAsString forKey:(NSString *)kUTTypeText];
+    if (!pasteboardImage.resourceMIMEType.isNull()) {
+        [representations setObject:pasteboardImage.resourceData->createNSData().get() forKey:pasteboardImage.resourceMIMEType];
+        if (!pasteboardImage.url.url.isNull())
+            [representations setObject:(NSURL *)pasteboardImage.url.url forKey:(NSString *)kUTTypeURL];
+    }
 
     // Explicitly cast m_pasteboard to UIPasteboard * to work around rdar://problem/33383354.
     ASSERT([m_pasteboard isKindOfClass:getUIPasteboardClass()]);
     [(UIPasteboard *)m_pasteboard setItems:@[representations.get()]];
-}
-
-void PlatformPasteboard::writeObjectRepresentations(const PasteboardImage& pasteboardImage)
-{
-#if ENABLE(DATA_INTERACTION)
-    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+#else
+    auto representationsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
 
     auto& types = pasteboardImage.clientTypes;
     auto& data = pasteboardImage.clientData;
     ASSERT(types.size() == data.size());
     for (size_t i = 0, size = types.size(); i < size; ++i)
-        [itemsToRegister addData:data[i]->createNSData().get() forType:types[i]];
+        [representationsToRegister addData:data[i]->createNSData().get() forType:types[i]];
 
     if (pasteboardImage.resourceData && !pasteboardImage.resourceMIMEType.isEmpty()) {
         auto utiOrMIMEType = pasteboardImage.resourceMIMEType;
@@ -299,67 +325,26 @@ void PlatformPasteboard::writeObjectRepresentations(const PasteboardImage& paste
             utiOrMIMEType = UTIFromMIMEType(utiOrMIMEType);
 
         auto imageData = pasteboardImage.resourceData->createNSData();
-        [itemsToRegister addData:imageData.get() forType:(NSString *)utiOrMIMEType];
-        [itemsToRegister setEstimatedDisplayedSize:pasteboardImage.imageSize];
-        [itemsToRegister setSuggestedName:pasteboardImage.suggestedName];
+        [representationsToRegister addData:imageData.get() forType:(NSString *)utiOrMIMEType];
+        [representationsToRegister setPreferredPresentationSize:pasteboardImage.imageSize];
+        [representationsToRegister setSuggestedName:pasteboardImage.suggestedName];
     }
 
+    // FIXME: When writing a PasteboardImage, we currently always place the image data at a higer fidelity than the
+    // associated image URL. However, in the case of an image enclosed by an anchor, we might want to consider the
+    // the URL (i.e. the anchor's href attribute) to be a higher fidelity representation.
     if (!pasteboardImage.url.url.isEmpty()) {
-        NSURL *nsURL = pasteboardImage.url.url;
-        if (nsURL)
-            [itemsToRegister addRepresentingObject:nsURL];
+        if (NSURL *nsURL = pasteboardImage.url.url)
+            [representationsToRegister addRepresentingObject:nsURL];
     }
 
-    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
-#else
-    UNUSED_PARAM(pasteboardImage);
-#endif
-}
-
-void PlatformPasteboard::write(const PasteboardImage& pasteboardImage)
-{
-    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
-        writeObjectRepresentations(pasteboardImage);
-        return;
-    }
-
-    RetainPtr<NSMutableDictionary> representations = adoptNS([[NSMutableDictionary alloc] init]);
-    if (!pasteboardImage.resourceMIMEType.isNull()) {
-        [representations setObject:pasteboardImage.resourceData->createNSData().get() forKey:pasteboardImage.resourceMIMEType];
-        if (!pasteboardImage.url.url.isNull())
-            [representations setObject:(NSURL *)pasteboardImage.url.url forKey:(NSString *)kUTTypeURL];
-    }
-
-    // Explicitly cast m_pasteboard to UIPasteboard * to work around rdar://problem/33383354.
-    ASSERT([m_pasteboard isKindOfClass:getUIPasteboardClass()]);
-    [(UIPasteboard *)m_pasteboard setItems:@[representations.get()]];
-}
-
-void PlatformPasteboard::writeObjectRepresentations(const String& pasteboardType, const String& text)
-{
-#if ENABLE(DATA_INTERACTION)
-    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
-
-    NSString *pasteboardTypeAsNSString = pasteboardType;
-    if (!text.isEmpty() && pasteboardTypeAsNSString.length) {
-        if (UTTypeConformsTo((__bridge CFStringRef)pasteboardTypeAsNSString, kUTTypeURL) || UTTypeConformsTo((__bridge CFStringRef)pasteboardTypeAsNSString, kUTTypeText))
-            addRepresentationsForPlainText(itemsToRegister.get(), text);
-    }
-
-    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
-#else
-    UNUSED_PARAM(pasteboardType);
-    UNUSED_PARAM(text);
+    registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
 #endif
 }
 
 void PlatformPasteboard::write(const String& pasteboardType, const String& text)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
-        writeObjectRepresentations(pasteboardType, text);
-        return;
-    }
-
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
     RetainPtr<NSDictionary> representations = adoptNS([[NSMutableDictionary alloc] init]);
 
     NSString *textAsString = text;
@@ -378,33 +363,37 @@ void PlatformPasteboard::write(const String& pasteboardType, const String& text)
     // Explicitly cast m_pasteboard to UIPasteboard * to work around rdar://problem/33383354.
     ASSERT([m_pasteboard isKindOfClass:getUIPasteboardClass()]);
     [(UIPasteboard *)m_pasteboard setItems:@[representations.get()]];
-}
-
-void PlatformPasteboard::writeObjectRepresentations(const PasteboardURL& url)
-{
-#if ENABLE(DATA_INTERACTION)
-    RetainPtr<WebItemProviderRegistrationInfoList> itemsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+#else
+    auto representationsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
 
-    if (NSURL *nsURL = url.url) {
-        [itemsToRegister addRepresentingObject:nsURL];
-        if (!url.title.isEmpty())
-            nsURL._title = url.title;
+    NSString *pasteboardTypeAsNSString = pasteboardType;
+    if (!text.isEmpty() && pasteboardTypeAsNSString.length) {
+        auto pasteboardTypeAsCFString = (CFStringRef)pasteboardTypeAsNSString;
+        if (UTTypeConformsTo(pasteboardTypeAsCFString, kUTTypeURL) || UTTypeConformsTo(pasteboardTypeAsCFString, kUTTypeText))
+            addRepresentationsForPlainText(representationsToRegister.get(), text);
+        else
+            [representationsToRegister addData:[pasteboardTypeAsNSString dataUsingEncoding:NSUTF8StringEncoding] forType:pasteboardType];
     }
 
-    [m_pasteboard setItemsUsingRegistrationInfoLists:@[ itemsToRegister.get() ]];
-#else
-    UNUSED_PARAM(url);
+    registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
 #endif
 }
 
 void PlatformPasteboard::write(const PasteboardURL& url)
 {
-    if ([m_pasteboard respondsToSelector:@selector(setItemsUsingRegistrationInfoLists:)]) {
-        writeObjectRepresentations(url);
-        return;
+#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
+    write(kUTTypeURL, url.url.string());
+#else
+    auto representationsToRegister = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
+
+    if (NSURL *nsURL = url.url) {
+        if (!url.title.isEmpty())
+            nsURL._title = url.title;
+        [representationsToRegister addRepresentingObject:nsURL];
     }
 
-    write(kUTTypeURL, url.url.string());
+    registerItemToPasteboard(representationsToRegister.get(), m_pasteboard.get());
+#endif
 }
 
 int PlatformPasteboard::count()
index 3a4b6fe..2508fd1 100644 (file)
@@ -60,8 +60,9 @@ WEBCORE_EXPORT @interface WebItemProviderRegistrationInfoList : NSObject
 - (void)addRepresentingObject:(id <UIItemProviderWriting>)object;
 - (void)addData:(NSData *)data forType:(NSString *)typeIdentifier;
 
-@property (nonatomic) CGSize estimatedDisplayedSize;
+@property (nonatomic) CGSize preferredPresentationSize;
 @property (nonatomic, copy) NSString *suggestedName;
+@property (nonatomic, readonly, nullable) UIItemProvider *itemProvider;
 
 - (NSUInteger)numberOfItems;
 - (nullable WebItemProviderRegistrationInfo *)itemAtIndex:(NSUInteger)index;
index 8ae4d1f..d86269a 100644 (file)
 
 #if ENABLE(DATA_INTERACTION)
 
+#import <Foundation/NSItemProvider.h>
 #import <Foundation/NSProgress.h>
 #import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/NSItemProvider+UIKitAdditions.h>
 #import <UIKit/UIColor.h>
 #import <UIKit/UIImage.h>
 #import <WebCore/FileSystemIOS.h>
@@ -45,12 +47,6 @@ SOFT_LINK_CLASS(UIKit, UIColor)
 SOFT_LINK_CLASS(UIKit, UIImage)
 SOFT_LINK_CLASS(UIKit, UIItemProvider)
 
-// FIXME: Remove once +objectWithItemProviderData:typeIdentifier:error: is available in the public SDK.
-@interface NSObject (Foundation_NSItemProvider_Staging)
-+ (id <NSItemProviderReading>)objectWithItemProviderData:(NSData *)data typeIdentifier:(NSString *)typeIdentifier error:(NSError **)outError;
-- (id <NSItemProviderReading>)initWithItemProviderData:(NSData *)data typeIdentifier:(NSString *)typeIdentifier error:(NSError **)outError;
-@end
-
 using namespace WebCore;
 
 typedef void(^ItemProviderDataLoadCompletionHandler)(NSData *, NSError *);
@@ -100,7 +96,7 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
 
 @interface WebItemProviderRegistrationInfoList ()
 {
-    RetainPtr<NSMutableArray> _items;
+    RetainPtr<NSMutableArray> _representations;
 }
 @end
 
@@ -109,8 +105,8 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
 - (instancetype)init
 {
     if (self = [super init]) {
-        _items = adoptNS([[NSMutableArray alloc] init]);
-        _estimatedDisplayedSize = CGSizeZero;
+        _representations = adoptNS([[NSMutableArray alloc] init]);
+        _preferredPresentationSize = CGSizeZero;
     }
 
     return self;
@@ -124,18 +120,18 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
 
 - (void)addData:(NSData *)data forType:(NSString *)typeIdentifier
 {
-    [_items addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:nil typeIdentifier:typeIdentifier data:data] autorelease]];
+    [_representations 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]];
+    [_representations addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:object typeIdentifier:nil data:nil] autorelease]];
 }
 
 - (NSUInteger)numberOfItems
 {
-    return [_items count];
+    return [_representations count];
 }
 
 - (WebItemProviderRegistrationInfo *)itemAtIndex:(NSUInteger)index
@@ -143,7 +139,7 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
     if (index >= self.numberOfItems)
         return nil;
 
-    return [_items objectAtIndex:index];
+    return [_representations objectAtIndex:index];
 }
 
 - (void)enumerateItems:(void (^)(WebItemProviderRegistrationInfo *, NSUInteger))block
@@ -152,6 +148,49 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
         block([self itemAtIndex:index], index);
 }
 
+- (UIItemProvider *)itemProvider
+{
+    if (!self.numberOfItems)
+        return nil;
+
+    auto itemProvider = adoptNS([allocUIItemProviderInstance() init]);
+    for (WebItemProviderRegistrationInfo *representation in _representations.get()) {
+        if (representation.representingObject) {
+            [itemProvider registerObject:representation.representingObject visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+            continue;
+        }
+
+        if (!representation.typeIdentifier.length || !representation.data.length)
+            continue;
+
+        RetainPtr<NSData> itemData = representation.data;
+        [itemProvider registerDataRepresentationForTypeIdentifier:representation.typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler:[itemData] (ItemProviderDataLoadCompletionHandler completionHandler) -> NSProgress * {
+            completionHandler(itemData.get(), nil);
+            return nil;
+        }];
+    }
+    [itemProvider setPreferredPresentationSize:self.preferredPresentationSize];
+    [itemProvider setSuggestedName:self.suggestedName];
+    return itemProvider.autorelease();
+}
+
+- (NSString *)description
+{
+    __block NSMutableString *description = [NSMutableString string];
+    [description appendFormat:@"<%@: %p", [self class], self];
+    [self enumerateItems:^(WebItemProviderRegistrationInfo *item, NSUInteger index) {
+        if (index)
+            [description appendString:@","];
+
+        if (item.representingObject)
+            [description appendFormat:@" (%@: %p)", [item.representingObject class], item.representingObject];
+        else
+            [description appendFormat:@" ('%@' => %tu bytes)", item.typeIdentifier, item.data.length];
+    }];
+    [description appendString:@">"];
+    return description;
+}
+
 @end
 
 @interface WebItemProviderPasteboard ()
@@ -251,41 +290,6 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
     return [_itemProviders count];
 }
 
-- (void)setItemsUsingRegistrationInfoLists:(NSArray<WebItemProviderRegistrationInfoList *> *)itemLists
-{
-    NSMutableArray *providers = [NSMutableArray array];
-    for (WebItemProviderRegistrationInfoList *itemList in itemLists) {
-        if (!itemList.numberOfItems)
-            continue;
-
-        auto itemProvider = adoptNS([allocUIItemProviderInstance() init]);
-        [itemList enumerateItems:[itemProvider] (WebItemProviderRegistrationInfo *item, NSUInteger) {
-            if (item.representingObject) {
-                [itemProvider registerObject:item.representingObject visibility:UIItemProviderRepresentationOptionsVisibilityAll];
-                return;
-            }
-
-            if (!item.typeIdentifier.length || !item.data.length)
-                return;
-
-            RetainPtr<NSData> itemData = item.data;
-            [itemProvider registerDataRepresentationForTypeIdentifier:item.typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler:[itemData] (ItemProviderDataLoadCompletionHandler completionHandler) -> NSProgress * {
-                completionHandler(itemData.get(), nil);
-                return nil;
-            }];
-        }];
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-        [itemProvider setEstimatedDisplayedSize:itemList.estimatedDisplayedSize];
-#pragma clang diagnostic pop
-        [itemProvider setSuggestedName:itemList.suggestedName];
-        [providers addObject:itemProvider.get()];
-    }
-
-    self.itemProviders = providers;
-    _registrationInfoLists = itemLists;
-}
-
 - (NSData *)_preLoadedDataConformingToType:(NSString *)typeIdentifier forItemProviderAtIndex:(NSUInteger)index
 {
     if ([_typeToFileURLMaps count] != [_itemProviders count]) {
@@ -364,13 +368,8 @@ static Class classForTypeIdentifier(NSString *typeIdentifier, NSString *&outType
         if (!preloadedData)
             return;
 
-        if ([readableClass respondsToSelector:@selector(objectWithItemProviderData:typeIdentifier:error:)]) {
-            if (id <NSItemProviderReading> readObject = [readableClass objectWithItemProviderData:preloadedData typeIdentifier:(NSString *)typeIdentifierToLoad error:nil])
-                [values addObject:readObject];
-        } else {
-            if (auto readObject = adoptNS([[readableClass alloc] initWithItemProviderData:preloadedData typeIdentifier:(NSString *)typeIdentifierToLoad error:nil]))
-                [values addObject:readObject.get()];
-        }
+        if (id <NSItemProviderReading> readObject = [readableClass objectWithItemProviderData:preloadedData typeIdentifier:(NSString *)typeIdentifierToLoad error:nil])
+            [values addObject:readObject];
     }];
 
     return values.autorelease();
@@ -546,6 +545,11 @@ static NSURL *temporaryFileURLForDataInteractionContent(NSURL *url, NSString *su
     [_itemProviders enumerateObjectsUsingBlock:block];
 }
 
+- (void)setRegistrationInfoLists:(NSArray <WebItemProviderRegistrationInfoList *> *)infoLists
+{
+    _registrationInfoLists = infoLists;
+}
+
 @end
 
 #endif // ENABLE(DATA_INTERACTION)
index 9eb1456..78f50f0 100644 (file)
@@ -1,3 +1,25 @@
+2017-08-17  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Respect type fidelities when copying image elements to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=175638
+        <rdar://problem/26556043>
+
+        Reviewed by Ryosuke Niwa.
+
+        Currently, we treat the case when copying an image enclosed by a link by only writing a URL to the pasteboard.
+        This patch tweaks logic in WebPage::performActionOnElement to write both an image and a link to the pasteboard
+        if the hit-tested image element is enclosed by an anchor.
+
+        * Platform/spi/ios/UIKitSPI.h:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::containingLinkElement):
+
+        Tweak this helper to be more restrictive when finding an enclosing 'link' -- only return an element if isLink()
+        is true, and it is an HTMLAnchorElement. Currently, the isLink() also matches HTMLLinkElements, but this isn't
+        the intention here.
+
+        (WebKit::WebPage::performActionOnElement):
+
 2017-08-17  Jacobo Aragunde PĂ©rez  <jaragunde@igalia.com>
 
         [WPE][GTK] Ensure proper casting of data in gvariants
index d39f76c..5b2849e 100644 (file)
@@ -876,7 +876,7 @@ typedef enum {
 #if ENABLE(DRAG_SUPPORT)
 
 @interface UIItemProvider : NSItemProvider
-@property (nonatomic) CGSize estimatedDisplayedSize;
+@property (nonatomic) CGSize preferredPresentationSize;
 @end
 
 WTF_EXTERN_C_BEGIN
index 38afafc..f641e07 100644 (file)
@@ -2410,11 +2410,11 @@ void WebPage::getAutocorrectionContext(String& contextBefore, String& markedText
     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
 }
 
-static Element* containingLinkElement(Element* element)
+static HTMLAnchorElement* containingLinkElement(Element* element)
 {
     for (auto& currentElement : elementLineage(element)) {
-        if (currentElement.isLink())
-            return &currentElement;
+        if (currentElement.isLink() && is<HTMLAnchorElement>(currentElement))
+            return downcast<HTMLAnchorElement>(&currentElement);
     }
     return nullptr;
 }
@@ -2627,11 +2627,16 @@ void WebPage::performActionOnElement(uint32_t action)
 
     if (static_cast<SheetAction>(action) == SheetAction::Copy) {
         if (is<RenderImage>(*element.renderer())) {
-            Element* linkElement = containingLinkElement(&element);
-            if (!linkElement)
-                m_interactionNode->document().frame()->editor().writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), element, URL(), String());
-            else
-                m_interactionNode->document().frame()->editor().copyURL(linkElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkElement->attributeWithoutSynchronization(HTMLNames::hrefAttr))), linkElement->textContent());
+            URL url;
+            String title;
+            if (auto* linkElement = containingLinkElement(&element)) {
+                url = linkElement->href();
+                title = linkElement->attributeWithoutSynchronization(HTMLNames::titleAttr);
+                if (!title.length())
+                    title = linkElement->textContent();
+                title = stripLeadingAndTrailingHTMLSpaces(title);
+            }
+            m_interactionNode->document().frame()->editor().writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), element, url, title);
         } else if (element.isLink()) {
             m_interactionNode->document().frame()->editor().copyURL(element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.attributeWithoutSynchronization(HTMLNames::hrefAttr))), element.textContent());
         }
index c30007c..4d80177 100644 (file)
@@ -1,3 +1,32 @@
+2017-08-17  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Respect type fidelities when copying image elements to the pasteboard
+        https://bugs.webkit.org/show_bug.cgi?id=175638
+        <rdar://problem/26556043>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add API tests that simulate copying an image element using the action sheet, and verifying that the pasteboard
+        contains UTIs in order of fidelity (image type before URL). Also pulls out UIKit SPI (UIApplicationInitialize)
+        used in UIPasteboardTests and ActionSheetTests into a common UIKitSPI header.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/ios/ActionSheetTests.mm:
+        (-[ActionSheetObserver _webView:actionsForElement:defaultActions:]):
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::presentActionSheetAndChooseAction):
+        (-[ActionSheetObserver waitForActionSheetAfterBlock:]): Deleted.
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (checkEstimatedSize):
+        (checkSuggestedNameAndEstimatedSize):
+
+        Replace -estimatedDisplayedSize with its non-deprecated counterpart, -preferredPresentationSize.
+
+        * TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/ios/DataInteractionSimulator.h:
+        * TestWebKitAPI/ios/UIKitSPI.h: Added.
+
 2017-08-17  Jonathan Bedard  <jbedard@apple.com>
 
         Recursively create resource load statistics folder for testing
index f6297c9..5696fae 100644 (file)
                F47D30EB1ED28619000482E1 /* apple.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = apple.gif; sourceTree = "<group>"; };
                F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
                F4856CA21E6498A8009D7EE7 /* attachment-element.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "attachment-element.html"; sourceTree = "<group>"; };
+               F493247C1F44DF8D006F4336 /* UIKitSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIKitSPI.h; sourceTree = "<group>"; };
                F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-change-selection-offscreen.html"; sourceTree = "<group>"; };
                F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-in-iframe.html"; sourceTree = "<group>"; };
                F4B825D61EF4DBD4006E417F /* compressed-files.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "compressed-files.zip"; sourceTree = "<group>"; };
                                F4D4F3B51E4E2BCB00BB2767 /* DataInteractionSimulator.h */,
                                F4D4F3B41E4E2BCB00BB2767 /* DataInteractionSimulator.mm */,
                                2E7765CC16C4D80A00BA2BB1 /* mainIOS.mm */,
+                               F493247C1F44DF8D006F4336 /* UIKitSPI.h */,
                        );
                        path = ios;
                        sourceTree = "<group>";
index 62dcf5d..07d1d07 100644 (file)
 #import "InstanceMethodSwizzler.h"
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
+#import "UIKitSPI.h"
+#import <MobileCoreServices/MobileCoreServices.h>
 #import <WebKit/WKUIDelegatePrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKActivatedElementInfo.h>
+#import <WebKit/_WKElementAction.h>
+#import <wtf/BlockPtr.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/SoftLinking.h>
 
 @interface ActionSheetObserver : NSObject<WKUIDelegatePrivate>
-@property (nonatomic) BOOL presentedActionSheet;
+@property (nonatomic) BlockPtr<NSArray *(_WKActivatedElementInfo *, NSArray *)> presentationHandler;
 @end
 
 @implementation ActionSheetObserver
 
-- (BOOL)waitForActionSheetAfterBlock:(dispatch_block_t)block
+- (NSArray *)_webView:(WKWebView *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray<_WKElementAction *> *)defaultActions
 {
-    _presentedActionSheet = NO;
-    block();
-    while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) {
-        if (_presentedActionSheet)
-            break;
-    }
-    return _presentedActionSheet;
-}
-
-- (NSArray *)_webView:(ActionSheetObserver *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray<_WKElementAction *> *)defaultActions
-{
-    _presentedActionSheet = YES;
-    return defaultActions;
+    return _presentationHandler ? _presentationHandler(element, defaultActions) : defaultActions;
 }
 
 @end
@@ -87,12 +80,100 @@ TEST(ActionSheetTests, ImageMapDoesNotDestroySelection)
     [webView stringByEvaluatingJavaScript:@"selectTextNode(h1.childNodes[0])"];
 
     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"getSelection().toString()"]);
-    [observer waitForActionSheetAfterBlock:^() {
-        [webView _simulateLongPressActionAtLocation:CGPointMake(200, 200)];
+
+    __block bool done = false;
+    [observer setPresentationHandler:^(_WKActivatedElementInfo *element, NSArray *actions) {
+        done = true;
+        return actions;
     }];
+    [webView _simulateLongPressActionAtLocation:CGPointMake(200, 200)];
+    TestWebKitAPI::Util::run(&done);
+
     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"getSelection().toString()"]);
 }
 
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+
+static void presentActionSheetAndChooseAction(WKWebView *webView, ActionSheetObserver *observer, CGPoint location, _WKElementActionType actionType)
+{
+    __block RetainPtr<_WKElementAction> copyAction;
+    __block RetainPtr<_WKActivatedElementInfo> copyElement;
+    __block bool done = false;
+    [observer setPresentationHandler:^(_WKActivatedElementInfo *element, NSArray *actions) {
+        copyElement = element;
+        for (_WKElementAction *action in actions) {
+            if (action.type == actionType)
+                copyAction = action;
+        }
+        done = true;
+        return @[ copyAction.get() ];
+    }];
+    [webView _simulateLongPressActionAtLocation:location];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_TRUE(!!copyAction);
+    EXPECT_TRUE(!!copyElement);
+    [copyAction runActionWithElementInfo:copyElement.get()];
+}
+
+TEST(ActionSheetTests, CopyImageElementWithHREF)
+{
+    UIApplicationInitialize();
+    [UIPasteboard generalPasteboard].items = @[ ];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    auto observer = adoptNS([[ActionSheetObserver alloc] init]);
+    [webView setUIDelegate:observer.get()];
+    [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
+
+    presentActionSheetAndChooseAction(webView.get(), observer.get(), CGPointMake(100, 50), _WKElementActionTypeCopy);
+
+    __block bool done = false;
+    [webView _doAfterNextPresentationUpdate:^() {
+        NSArray <NSString *> *pasteboardTypes = [[UIPasteboard generalPasteboard] pasteboardTypes];
+        EXPECT_EQ(2UL, pasteboardTypes.count);
+        EXPECT_WK_STREQ((NSString *)kUTTypePNG, pasteboardTypes.firstObject);
+        EXPECT_WK_STREQ((NSString *)kUTTypeURL, pasteboardTypes.lastObject);
+        NSArray <NSItemProvider *> *itemProviders = [[UIPasteboard generalPasteboard] itemProviders];
+        EXPECT_EQ(1UL, itemProviders.count);
+        NSItemProvider *itemProvider = itemProviders.firstObject;
+        EXPECT_EQ(2UL, itemProvider.registeredTypeIdentifiers.count);
+        EXPECT_WK_STREQ((NSString *)kUTTypePNG, itemProvider.registeredTypeIdentifiers.firstObject);
+        EXPECT_WK_STREQ((NSString *)kUTTypeURL, itemProvider.registeredTypeIdentifiers.lastObject);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
+TEST(ActionSheetTests, CopyImageElementWithoutHREF)
+{
+    UIApplicationInitialize();
+    [UIPasteboard generalPasteboard].items = @[ ];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    auto observer = adoptNS([[ActionSheetObserver alloc] init]);
+    [webView setUIDelegate:observer.get()];
+    [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
+
+    presentActionSheetAndChooseAction(webView.get(), observer.get(), CGPointMake(100, 100), _WKElementActionTypeCopy);
+
+    __block bool done = false;
+    [webView _doAfterNextPresentationUpdate:^() {
+        NSArray <NSString *> *pasteboardTypes = [[UIPasteboard generalPasteboard] pasteboardTypes];
+        EXPECT_EQ(1UL, pasteboardTypes.count);
+        EXPECT_WK_STREQ((NSString *)kUTTypePNG, pasteboardTypes.firstObject);
+        NSArray <NSItemProvider *> *itemProviders = [[UIPasteboard generalPasteboard] itemProviders];
+        EXPECT_EQ(1UL, itemProviders.count);
+        NSItemProvider *itemProvider = itemProviders.firstObject;
+        EXPECT_EQ(1UL, itemProvider.registeredTypeIdentifiers.count);
+        EXPECT_WK_STREQ((NSString *)kUTTypePNG, itemProvider.registeredTypeIdentifiers.firstObject);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
+#endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
+
 } // namespace TestWebKitAPI
 
 #endif // PLATFORM(IOS)
index 6060b99..198b3fe 100644 (file)
@@ -32,6 +32,7 @@
 #import "TestWKWebView.h"
 #import "WKWebViewConfigurationExtras.h"
 #import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/NSItemProvider+UIKitAdditions.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
@@ -131,16 +132,16 @@ static void checkTypeIdentifierIsRegisteredAtIndex(DataInteractionSimulator *sim
 static void checkEstimatedSize(DataInteractionSimulator *simulator, CGSize estimatedSize)
 {
     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
-    EXPECT_EQ(estimatedSize.width, sourceItemProvider.estimatedDisplayedSize.width);
-    EXPECT_EQ(estimatedSize.height, sourceItemProvider.estimatedDisplayedSize.height);
+    EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
+    EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
 }
 
 static void checkSuggestedNameAndEstimatedSize(DataInteractionSimulator *simulator, NSString *suggestedName, CGSize estimatedSize)
 {
     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
     EXPECT_WK_STREQ(suggestedName.UTF8String, sourceItemProvider.suggestedName.UTF8String);
-    EXPECT_EQ(estimatedSize.width, sourceItemProvider.estimatedDisplayedSize.width);
-    EXPECT_EQ(estimatedSize.height, sourceItemProvider.estimatedDisplayedSize.height);
+    EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
+    EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
 }
 
 static void checkStringArraysAreEqual(NSArray<NSString *> *expected, NSArray<NSString *> *observed)
index 5e65038..496f83f 100644 (file)
 
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
+#import "UIKitSPI.h"
 #import <MobileCoreServices/MobileCoreServices.h>
 #import <UIKit/UIPasteboard.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <wtf/SoftLinking.h>
 
-SOFT_LINK_FRAMEWORK(UIKit)
-SOFT_LINK(UIKit, UIApplicationInitialize, void, (void), ())
-
 namespace TestWebKitAPI {
 
 NSData *dataForPasteboardType(CFStringRef type)
@@ -69,9 +67,7 @@ TEST(UIPasteboardTests, CopyPlainTextWritesConcreteTypes)
     [webView stringByEvaluatingJavaScript:@"document.execCommand('copy')"];
 
     auto utf8Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF8PlainText) encoding:NSUTF8StringEncoding]);
-    auto utf16Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF16PlainText) encoding:NSUTF16StringEncoding]);
     EXPECT_WK_STREQ("Hello world", [utf8Result UTF8String]);
-    EXPECT_WK_STREQ("Hello world", [utf16Result UTF8String]);
 }
 
 TEST(UIPasteboardTests, CopyRichTextWritesConcreteTypes)
@@ -81,9 +77,7 @@ TEST(UIPasteboardTests, CopyRichTextWritesConcreteTypes)
     [webView stringByEvaluatingJavaScript:@"document.execCommand('copy')"];
 
     auto utf8Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF8PlainText) encoding:NSUTF8StringEncoding]);
-    auto utf16Result = adoptNS([[NSString alloc] initWithData:dataForPasteboardType(kUTTypeUTF16PlainText) encoding:NSUTF16StringEncoding]);
     EXPECT_WK_STREQ("Hello world", [utf8Result UTF8String]);
-    EXPECT_WK_STREQ("Hello world", [utf16Result UTF8String]);
 }
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
index 3f7fa98..00a3a2d 100644 (file)
 @property (nonatomic, copy, setter=_setTitle:) NSString *_title;
 @end
 
-@interface UIItemProvider : NSItemProvider
-@property (nonatomic) CGSize estimatedDisplayedSize;
-@end
-
 #define UIItemProviderRepresentationOptionsVisibilityAll NSItemProviderRepresentationVisibilityAll
 
 @protocol UIItemProviderReading <NSItemProviderReading>
diff --git a/Tools/TestWebKitAPI/ios/UIKitSPI.h b/Tools/TestWebKitAPI/ios/UIKitSPI.h
new file mode 100644 (file)
index 0000000..bb0a81d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#if PLATFORM(IOS)
+
+#if USE(APPLE_INTERNAL_SDK)
+
+#import <UIKit/UIApplication_Private.h>
+
+#else
+
+WTF_EXTERN_C_BEGIN
+
+void UIApplicationInitialize(void);
+
+WTF_EXTERN_C_END
+
+#endif
+
+#endif // PLATFORM(IOS)