[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 39f28a56fc457c9ffa4a43aa03f7a5ff3e51b6b8..14657d445721700c0e58b6adb257e2cf3f0c728b 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 aa8272bcac094aced9f5fceadff18e5fb0ac5203..86122770a52ad8c8d943e9384ec6eb87001a790d 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 2e7c4fe40f43aae771411b30e7ee1eb2ccc2a6c2..51a2d5acadf1b94579ebc3f362810056b87d74f5 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 700e4287436b759ddaebeaec0fa3f8660a6ea13c..b6e4fd5d9f8af0e34bf794e39186c58be7056e2e 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 a4130759dcaa5cca988845b15b0f7861d3377a4d..9836cb3fdfc434c6910dc82ded233b5dbb925fd2 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 3db8ad4e0a223fb1f187c59d60dcfbb8ab15e69b..936701ae99d7136322a35588acd077f5100d77a5 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 3a4b6fedb69556e8df31c81296983644b45e1b98..2508fd1f1c4bb729a8cf3341dacade84afaa4ef8 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 8ae4d1fc2179dd092ccefb744c42bc2189e2daf0..d86269a71b6c662514ed32dbc09f1164e2cf2b2d 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 9eb1456e02d7de152657959ef1fe632f6cc5347b..78f50f0685f936547018216433c0d7295633687c 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 d39f76c435e667c85947d4c148604b02bf53a05f..5b2849e42719359b1bc7926d0271b411dc1a421b 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 38afafcdadc02784d7d8e06bb278bbb7d737657a..f641e07dd3883f2dc4d2632265a10ef901f45cca 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 c30007cab346da1ffd5ff5f421550fd9bb44a23d..4d801779ce02d112c6983d37d0d5650fcc82883c 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 f6297c956626aab83768719d0c0f6d938e6663c7..5696fae8fa8237339e5a1be62d42c5c4bddac954 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 62dcf5d9c15fd5e138cf35cec57366e55aff1a4d..07d1d0769ed20f43cc3c4af4a85c5f2b380e023c 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 6060b999be42f9e02b48f96bffdc02a597b5f38c..198b3fe2e528405dc5a450e8285375cd779cce5e 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 5e650381d33c8395cf7877546cdc8491e0974aa9..496f83fddb89904a282f0101773ecc970ddcb0e6 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 3f7fa98c0b2b4dda572c80253f5e8e8ff1ef1172..00a3a2df2f1935edc7172c38d675a080fa5cfd7a 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)