Title: [239184] trunk
Revision
239184
Author
wenson_hs...@apple.com
Date
2018-12-13 15:25:20 -0800 (Thu, 13 Dec 2018)

Log Message

[iOS] Support dropping contact card data (public.vcard) in editable content
https://bugs.webkit.org/show_bug.cgi?id=192570
<rdar://problem/35626913>

Reviewed by Tim Horton.

Source/WebCore:

Adds support for accepting vCard (.vcf) data via drop on iOS. See below for more details.

Tests:  DragAndDropTests.ExternalSourceContactIntoEditableAreas
        DragAndDropTests.ExternalSourceMapItemAndContactToUploadArea
        DragAndDropTests.ExternalSourceMapItemIntoEditableAreas
        WKAttachmentTestsIOS.InsertDroppedContactAsAttachment
        WKAttachmentTestsIOS.InsertDroppedMapItemAsAttachment

* editing/WebContentReader.h:
* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::attachmentForFilePath):

Pull out logic to create an attachment from a file path out into a static helper. Use this in `readFilePaths`
as well as `readVirtualContactFile`.

(WebCore::WebContentReader::readFilePaths):
(WebCore::WebContentReader::readVirtualContactFile):

Add a pasteboard reading method that reads a vCard file (with an optional URL) as web content. The resulting
fragment consists of either an anchor and an attachment element, or just an attachment element if the URL is
empty. In the case of an `MKMapItem`, the URL is populated, so we generate both elements; when dragging a
contact, there is no associated URL, so we only have an attachment.

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

Augment this to take the current `PasteboardItemInfo` as well; use this item information to get a file path for
"public.vcard" data, which is then passed on to the web content reader. Additionally, by returning
`ReaderResult::DidNotReadType` here, we prevent the web content reader from extracting the plain text contents
of the vCard and dumping it as plain text in the editable element (this would otherwise happen, since
"public.vcard" conforms to "public.text").

(WebCore::Pasteboard::read):
(WebCore::Pasteboard::readRespectingUTIFidelities):
* platform/ios/WebItemProviderPasteboard.mm:
(-[NSItemProvider web_fileUploadContentTypes]):

Prevent the "com.apple.mapkit.map-item" UTI from being considered as file upload content. This special case is
tricky, since "com.apple.mapkit.map-item" conforms to "public.content", yet its corresponding data is only
suitable for deserialization into an `MKMapItem`.

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:

Add API tests to verify that registering `MKMapItem`s and `CNContact`s to item providers and dropping them in
attachment-enabled rich text editable areas inserts attachment elements (and in the case of `MKMapItem`,
additionally inserts a link).

* TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
(TestWebKitAPI::createMapItemForTesting):
(TestWebKitAPI::createContactItemForTesting):

Add API tests to verify that dropping map items and contact items into rich and plain editable areas behaves as
expected (in the case where a URL is present, e.g. dropping a map item, we insert the URL as an anchor, and when
there is no other suitable representation in the item provider, we do nothing at all, which is the case for the
dropped `CNContact`). Also, add a test to verify that drag and drop can be used to upload these items as .vcf
files.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (239183 => 239184)


--- trunk/Source/WebCore/ChangeLog	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/ChangeLog	2018-12-13 23:25:20 UTC (rev 239184)
@@ -1,3 +1,53 @@
+2018-12-13  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] Support dropping contact card data (public.vcard) in editable content
+        https://bugs.webkit.org/show_bug.cgi?id=192570
+        <rdar://problem/35626913>
+
+        Reviewed by Tim Horton.
+
+        Adds support for accepting vCard (.vcf) data via drop on iOS. See below for more details.
+
+        Tests:  DragAndDropTests.ExternalSourceContactIntoEditableAreas
+                DragAndDropTests.ExternalSourceMapItemAndContactToUploadArea
+                DragAndDropTests.ExternalSourceMapItemIntoEditableAreas
+                WKAttachmentTestsIOS.InsertDroppedContactAsAttachment
+                WKAttachmentTestsIOS.InsertDroppedMapItemAsAttachment
+
+        * editing/WebContentReader.h:
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::attachmentForFilePath):
+
+        Pull out logic to create an attachment from a file path out into a static helper. Use this in `readFilePaths`
+        as well as `readVirtualContactFile`.
+
+        (WebCore::WebContentReader::readFilePaths):
+        (WebCore::WebContentReader::readVirtualContactFile):
+
+        Add a pasteboard reading method that reads a vCard file (with an optional URL) as web content. The resulting
+        fragment consists of either an anchor and an attachment element, or just an attachment element if the URL is
+        empty. In the case of an `MKMapItem`, the URL is populated, so we generate both elements; when dragging a
+        contact, there is no associated URL, so we only have an attachment.
+
+        * platform/Pasteboard.h:
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::readPasteboardWebContentDataForType):
+
+        Augment this to take the current `PasteboardItemInfo` as well; use this item information to get a file path for
+        "public.vcard" data, which is then passed on to the web content reader. Additionally, by returning
+        `ReaderResult::DidNotReadType` here, we prevent the web content reader from extracting the plain text contents
+        of the vCard and dumping it as plain text in the editable element (this would otherwise happen, since
+        "public.vcard" conforms to "public.text").
+
+        (WebCore::Pasteboard::read):
+        (WebCore::Pasteboard::readRespectingUTIFidelities):
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[NSItemProvider web_fileUploadContentTypes]):
+
+        Prevent the "com.apple.mapkit.map-item" UTI from being considered as file upload content. This special case is
+        tricky, since "com.apple.mapkit.map-item" conforms to "public.content", yet its corresponding data is only
+        suitable for deserialization into an `MKMapItem`.
+
 2018-12-13  Devin Rousso  <drou...@apple.com>
 
         Web Inspector: remove DOM.BackendNodeId and associated commands/events

Modified: trunk/Source/WebCore/editing/WebContentReader.h (239183 => 239184)


--- trunk/Source/WebCore/editing/WebContentReader.h	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/editing/WebContentReader.h	2018-12-13 23:25:20 UTC (rev 239184)
@@ -77,6 +77,7 @@
     bool readRTF(SharedBuffer&) override;
     bool readImage(Ref<SharedBuffer>&&, const String& type) override;
     bool readURL(const URL&, const String& title) override;
+    bool readVirtualContactFile(const String& filePath, const URL&, const String& urlTitle) override;
 #endif
     bool readPlainText(const String&) override;
 };
@@ -94,6 +95,7 @@
 #if PLATFORM(COCOA)
     bool readWebArchive(SharedBuffer&) override;
     bool readFilePaths(const Vector<String>&) override { return false; }
+    bool readVirtualContactFile(const String&, const URL&, const String&) override { return false; }
     bool readHTML(const String&) override;
     bool readRTFD(SharedBuffer&) override;
     bool readRTF(SharedBuffer&) override;

Modified: trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm (239183 => 239184)


--- trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm	2018-12-13 23:25:20 UTC (rev 239184)
@@ -45,6 +45,7 @@
 #import "HTMLAttachmentElement.h"
 #import "HTMLBRElement.h"
 #import "HTMLBodyElement.h"
+#import "HTMLDivElement.h"
 #import "HTMLIFrameElement.h"
 #import "HTMLImageElement.h"
 #import "HTMLObjectElement.h"
@@ -714,6 +715,45 @@
     return fragment;
 }
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+
+static Ref<HTMLElement> attachmentForFilePath(Frame& frame, const String& path)
+{
+    auto document = makeRef(*frame.document());
+    auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
+    if (!supportsClientSideAttachmentData(frame)) {
+        attachment->setFile(File::create(path), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
+        return attachment.get();
+    }
+
+    String contentType;
+    std::optional<uint64_t> fileSizeForDisplay;
+    if (FileSystem::fileIsDirectory(path, FileSystem::ShouldFollowSymbolicLinks::Yes))
+        contentType = kUTTypeDirectory;
+    else {
+        long long fileSize;
+        FileSystem::getFileSize(path, fileSize);
+        fileSizeForDisplay = fileSize;
+        contentType = File::contentTypeForFile(path);
+        if (contentType.isEmpty())
+            contentType = kUTTypeData;
+    }
+
+    frame.editor().registerAttachmentIdentifier(attachment->ensureUniqueIdentifier(), contentType, path);
+
+    if (contentTypeIsSuitableForInlineImageRepresentation(contentType)) {
+        auto image = HTMLImageElement::create(document);
+        image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(path)));
+        image->setAttachmentElement(WTFMove(attachment));
+        return image.get();
+    }
+
+    attachment->updateAttributes(WTFMove(fileSizeForDisplay), contentType, FileSystem::pathGetFileName(path));
+    return attachment.get();
+}
+
+#endif // ENABLE(ATTACHMENT_ELEMENT)
+
 bool WebContentReader::readFilePaths(const Vector<String>& paths)
 {
     if (paths.isEmpty() || !frame.document())
@@ -725,36 +765,8 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
     if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled()) {
-        for (auto& path : paths) {
-            auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
-            if (supportsClientSideAttachmentData(frame)) {
-                String contentType;
-                std::optional<uint64_t> fileSizeForDisplay;
-                if (FileSystem::fileIsDirectory(path, FileSystem::ShouldFollowSymbolicLinks::Yes))
-                    contentType = kUTTypeDirectory;
-                else {
-                    long long fileSize;
-                    FileSystem::getFileSize(path, fileSize);
-                    fileSizeForDisplay = fileSize;
-                    contentType = File::contentTypeForFile(path);
-                    if (contentType.isEmpty())
-                        contentType = kUTTypeData;
-                }
-                frame.editor().registerAttachmentIdentifier(attachment->ensureUniqueIdentifier(), contentType, path);
-                if (contentTypeIsSuitableForInlineImageRepresentation(contentType)) {
-                    auto image = HTMLImageElement::create(document);
-                    image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(path)));
-                    image->setAttachmentElement(WTFMove(attachment));
-                    fragment->appendChild(image);
-                } else {
-                    attachment->updateAttributes(WTFMove(fileSizeForDisplay), contentType, FileSystem::pathGetFileName(path));
-                    fragment->appendChild(attachment);
-                }
-            } else {
-                attachment->setFile(File::create(path), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
-                fragment->appendChild(attachment);
-            }
-        }
+        for (auto& path : paths)
+            fragment->appendChild(attachmentForFilePath(frame, path));
     }
 #endif
 
@@ -761,6 +773,28 @@
     return true;
 }
 
+bool WebContentReader::readVirtualContactFile(const String& filePath, const URL& url, const String& urlTitle)
+{
+    if (filePath.isEmpty() || !frame.document())
+        return false;
+
+    auto& document = *frame.document();
+    if (!fragment)
+        fragment = document.createDocumentFragment();
+
+#if ENABLE(ATTACHMENT_ELEMENT)
+    if (!url.isEmpty())
+        readURL(url, urlTitle);
+
+    auto attachmentContainer = HTMLDivElement::create(*frame.document());
+    attachmentContainer->setInlineStyleProperty(CSSPropertyDisplay, CSSValueBlock, true);
+    attachmentContainer->appendChild(attachmentForFilePath(frame, filePath));
+    fragment->appendChild(WTFMove(attachmentContainer));
+#endif
+
+    return true;
+}
+
 bool WebContentReader::readURL(const URL& url, const String& title)
 {
     if (url.isEmpty())

Modified: trunk/Source/WebCore/platform/Pasteboard.h (239183 => 239184)


--- trunk/Source/WebCore/platform/Pasteboard.h	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/platform/Pasteboard.h	2018-12-13 23:25:20 UTC (rev 239184)
@@ -137,6 +137,7 @@
 #if PLATFORM(COCOA)
     virtual bool readWebArchive(SharedBuffer&) = 0;
     virtual bool readFilePaths(const Vector<String>&) = 0;
+    virtual bool readVirtualContactFile(const String& filePath, const URL&, const String& urlTitle) = 0;
     virtual bool readHTML(const String&) = 0;
     virtual bool readRTFD(SharedBuffer&) = 0;
     virtual bool readRTF(SharedBuffer&) = 0;
@@ -287,7 +288,7 @@
         DidNotReadType,
         PasteboardWasChangedExternally
     };
-    ReaderResult readPasteboardWebContentDataForType(PasteboardWebContentReader&, PasteboardStrategy&, NSString *type, int itemIndex);
+    ReaderResult readPasteboardWebContentDataForType(PasteboardWebContentReader&, PasteboardStrategy&, NSString *type, int itemIndex, const PasteboardItemInfo&);
 #endif
 
 #if PLATFORM(WIN)

Modified: trunk/Source/WebCore/platform/ios/PasteboardIOS.mm (239183 => 239184)


--- trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2018-12-13 23:25:20 UTC (rev 239184)
@@ -181,7 +181,7 @@
         || [type isEqualToString:(__bridge NSString *)kUTTypeFlatRTFD];
 }
 
-Pasteboard::ReaderResult Pasteboard::readPasteboardWebContentDataForType(PasteboardWebContentReader& reader, PasteboardStrategy& strategy, NSString *type, int itemIndex)
+Pasteboard::ReaderResult Pasteboard::readPasteboardWebContentDataForType(PasteboardWebContentReader& reader, PasteboardStrategy& strategy, NSString *type, int itemIndex, const PasteboardItemInfo& info)
 {
     if ([type isEqualToString:WebArchivePboardType] || [type isEqualToString:(__bridge NSString *)kUTTypeWebArchive]) {
         auto buffer = strategy.readBufferFromPasteboard(itemIndex, type, m_pasteboardName);
@@ -197,6 +197,28 @@
         return !htmlString.isNull() && reader.readHTML(htmlString) ? ReaderResult::ReadType : ReaderResult::DidNotReadType;
     }
 
+    if ([type isEqualToString:(__bridge NSString *)kUTTypeVCard]) {
+        bool canCreateAttachments = false;
+#if ENABLE(ATTACHMENT_ELEMENT)
+        if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled())
+            canCreateAttachments = true;
+#endif
+        if (canCreateAttachments) {
+            auto path = info.pathForContentType(kUTTypeVCard);
+            if (path.isEmpty())
+                return ReaderResult::DidNotReadType;
+
+            String title;
+            auto url = "" m_pasteboardName, title);
+            if (m_changeCount != changeCount())
+                return ReaderResult::PasteboardWasChangedExternally;
+
+            if (reader.readVirtualContactFile(path, url, title))
+                return ReaderResult::ReadType;
+        }
+        return ReaderResult::DidNotReadType;
+    }
+
 #if !PLATFORM(IOSMAC)
     if ([type isEqualToString:(__bridge NSString *)kUTTypeFlatRTFD]) {
         RefPtr<SharedBuffer> buffer = strategy.readBufferFromPasteboard(itemIndex, kUTTypeFlatRTFD, m_pasteboardName);
@@ -269,7 +291,7 @@
             if (!isTypeAllowedByReadingPolicy(type, policy))
                 continue;
 
-            auto itemResult = readPasteboardWebContentDataForType(reader, strategy, type, i);
+            auto itemResult = readPasteboardWebContentDataForType(reader, strategy, type, i, strategy.informationForItemAtIndex(i, m_pasteboardName));
             if (itemResult == ReaderResult::PasteboardWasChangedExternally)
                 return;
 
@@ -310,7 +332,7 @@
             if (!isTypeAllowedByReadingPolicy(type, policy))
                 continue;
 
-            result = readPasteboardWebContentDataForType(reader, strategy, type, index);
+            result = readPasteboardWebContentDataForType(reader, strategy, type, index, info);
             if (result == ReaderResult::PasteboardWasChangedExternally)
                 return;
             if (result == ReaderResult::ReadType)

Modified: trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm (239183 => 239184)


--- trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2018-12-13 23:25:20 UTC (rev 239184)
@@ -80,6 +80,12 @@
         if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeURL))
             continue;
 
+        if ([identifier isEqualToString:@"com.apple.mapkit.map-item"]) {
+            // This type conforms to "public.content", yet the corresponding data is only a serialization of MKMapItem and isn't suitable for file uploads.
+            // Ignore over this type representation for the purposes of file uploads, in favor of "public.vcard" data.
+            continue;
+        }
+
         if (typeConformsToTypes(identifier, Pasteboard::supportedFileUploadPasteboardTypes()))
             [types addObject:identifier];
     }

Modified: trunk/Tools/ChangeLog (239183 => 239184)


--- trunk/Tools/ChangeLog	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Tools/ChangeLog	2018-12-13 23:25:20 UTC (rev 239184)
@@ -1,3 +1,27 @@
+2018-12-13  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] Support dropping contact card data (public.vcard) in editable content
+        https://bugs.webkit.org/show_bug.cgi?id=192570
+        <rdar://problem/35626913>
+
+        Reviewed by Tim Horton.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+
+        Add API tests to verify that registering `MKMapItem`s and `CNContact`s to item providers and dropping them in
+        attachment-enabled rich text editable areas inserts attachment elements (and in the case of `MKMapItem`,
+        additionally inserts a link).
+
+        * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
+        (TestWebKitAPI::createMapItemForTesting):
+        (TestWebKitAPI::createContactItemForTesting):
+
+        Add API tests to verify that dropping map items and contact items into rich and plain editable areas behaves as
+        expected (in the case where a URL is present, e.g. dropping a map item, we insert the URL as an anchor, and when
+        there is no other suitable representation in the item provider, we do nothing at all, which is the case for the
+        dropped `CNContact`). Also, add a test to verify that drag and drop can be used to upload these items as .vcf
+        files.
+
 2018-12-13  Ross Kirsling  <ross.kirsl...@sony.com>
 
         Unreviewed -- update my status to "reviewer".

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm (239183 => 239184)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2018-12-13 23:25:20 UTC (rev 239184)
@@ -25,6 +25,8 @@
 
 #import "config.h"
 
+#if (PLATFORM(MAC) || PLATFORM(IOS)) && WK_API_ENABLED
+
 #import "DragAndDropSimulator.h"
 #import "PencilKitTestSPI.h"
 #import "PlatformUtilities.h"
@@ -31,20 +33,28 @@
 #import "TestNavigationDelegate.h"
 #import "TestWKWebView.h"
 #import "WKWebViewConfigurationExtras.h"
+#import <Contacts/Contacts.h>
+#import <MapKit/MapKit.h>
 #import <WebKit/WKPreferencesRefPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/WebArchive.h>
 #import <WebKit/WebKitPrivate.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/SoftLinking.h>
 
 #if PLATFORM(IOS_FAMILY)
 #import <MobileCoreServices/MobileCoreServices.h>
 #endif
 
+SOFT_LINK_FRAMEWORK(Contacts)
+SOFT_LINK_CLASS(Contacts, CNMutableContact)
+
+SOFT_LINK_FRAMEWORK(MapKit)
+SOFT_LINK_CLASS(MapKit, MKMapItem)
+SOFT_LINK_CLASS(MapKit, MKPlacemark)
+
 #define USES_MODERN_ATTRIBUTED_STRING_CONVERSION ((PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300))
 
-#if WK_API_ENABLED && !PLATFORM(WATCHOS) && !PLATFORM(TVOS)
-
 @interface AttachmentUpdateObserver : NSObject <WKUIDelegatePrivate>
 @property (nonatomic, readonly) NSArray *inserted;
 @property (nonatomic, readonly) NSArray *removed;
@@ -1808,6 +1818,56 @@
     [dragAndDropSimulator endDataTransfer];
 }
 
+TEST(WKAttachmentTestsIOS, InsertDroppedMapItemAsAttachment)
+{
+    auto placemark = adoptNS([allocMKPlacemarkInstance() initWithCoordinate:CLLocationCoordinate2DMake(37.3327, -122.0053)]);
+    auto mapItem = adoptNS([allocMKMapItemInstance() initWithPlacemark:placemark.get()]);
+    [mapItem setName:@"Apple Park"];
+
+    auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+    [itemProvider registerObject:mapItem.get() visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider setSuggestedName:[mapItem name]];
+
+    auto webView = webViewForTestingAttachments();
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+    [simulator runFrom:CGPointMake(25, 25) to:CGPointMake(100, 100)];
+
+    NSURL *droppedLinkURL = [NSURL URLWithString:[webView valueOfAttribute:@"href" forQuerySelector:@"a"]];
+    [webView expectElementTag:@"A" toComeBefore:@"ATTACHMENT"];
+    EXPECT_WK_STREQ("maps.apple.com", droppedLinkURL.host);
+    EXPECT_WK_STREQ("Apple Park.vcf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]);
+    EXPECT_WK_STREQ("text/vcard", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
+    EXPECT_EQ(1U, [simulator insertedAttachments].count);
+    _WKAttachmentInfo *info = [simulator insertedAttachments].firstObject.info;
+    EXPECT_WK_STREQ("Apple Park.vcf", info.name);
+    EXPECT_WK_STREQ("text/vcard", info.contentType);
+}
+
+TEST(WKAttachmentTestsIOS, InsertDroppedContactAsAttachment)
+{
+    auto contact = adoptNS([allocCNMutableContactInstance() init]);
+    [contact setGivenName:@"Foo"];
+    [contact setFamilyName:@"Bar"];
+
+    auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+    [itemProvider registerObject:contact.get() visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider setSuggestedName:@"Foo Bar"];
+
+    auto webView = webViewForTestingAttachments();
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+    [simulator runFrom:CGPointMake(25, 25) to:CGPointMake(100, 100)];
+
+    [webView expectElementCount:0 querySelector:@"a"];
+    EXPECT_WK_STREQ("Foo Bar.vcf", [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').title"]);
+    EXPECT_WK_STREQ("text/vcard", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
+    EXPECT_EQ(1U, [simulator insertedAttachments].count);
+    _WKAttachmentInfo *info = [simulator insertedAttachments].firstObject.info;
+    EXPECT_WK_STREQ("Foo Bar.vcf", info.name);
+    EXPECT_WK_STREQ("text/vcard", info.contentType);
+}
+
 #if HAVE(PENCILKIT)
 static BOOL forEachViewInHierarchy(UIView *view, void(^mapFunction)(UIView *subview, BOOL *stop))
 {
@@ -1882,4 +1942,4 @@
 
 } // namespace TestWebKitAPI
 
-#endif // WK_API_ENABLED && !PLATFORM(WATCHOS) && !PLATFORM(TVOS)
+#endif // (PLATFORM(MAC) || PLATFORM(IOS)) && WK_API_ENABLED

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm (239183 => 239184)


--- trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm	2018-12-13 23:20:35 UTC (rev 239183)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm	2018-12-13 23:25:20 UTC (rev 239184)
@@ -33,6 +33,8 @@
 #import "TestWKWebView.h"
 #import "UIKitSPI.h"
 #import "WKWebViewConfigurationExtras.h"
+#import <Contacts/Contacts.h>
+#import <MapKit/MapKit.h>
 #import <MobileCoreServices/MobileCoreServices.h>
 #import <UIKit/NSItemProvider+UIKitAdditions.h>
 #import <WebKit/WKPreferencesPrivate.h>
@@ -42,7 +44,15 @@
 #import <WebKit/WebItemProviderPasteboard.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 #import <wtf/Seconds.h>
+#import <wtf/SoftLinking.h>
 
+SOFT_LINK_FRAMEWORK(Contacts)
+SOFT_LINK_CLASS(Contacts, CNMutableContact)
+
+SOFT_LINK_FRAMEWORK(MapKit)
+SOFT_LINK_CLASS(MapKit, MKMapItem)
+SOFT_LINK_CLASS(MapKit, MKPlacemark)
+
 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
 typedef void (^NSItemProviderDataLoadCompletionBlock)(NSData *, NSError *);
@@ -187,8 +197,6 @@
         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
 }
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
-
 static void checkJSONWithLogging(NSString *jsonString, NSDictionary *expected)
 {
     BOOL success = TestWebKitAPI::Util::jsonMatchesExpectedValues(jsonString, expected);
@@ -251,8 +259,6 @@
     }
 }
 
-#endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
-
 namespace TestWebKitAPI {
 
 TEST(DragAndDropTests, ImageToContentEditable)
@@ -1061,8 +1067,77 @@
     EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
+static RetainPtr<NSItemProvider> createMapItemForTesting()
+{
+    auto placemark = adoptNS([allocMKPlacemarkInstance() initWithCoordinate:CLLocationCoordinate2DMake(37.3327, -122.0053)]);
+    auto item = adoptNS([allocMKMapItemInstance() initWithPlacemark:placemark.get()]);
+    [item setName:@"Apple Park"];
 
+    auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+    [itemProvider registerObject:item.get() visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider setSuggestedName:[item name]];
+
+    return itemProvider;
+}
+
+static RetainPtr<NSItemProvider> createContactItemForTesting()
+{
+    auto contact = adoptNS([allocCNMutableContactInstance() init]);
+    [contact setGivenName:@"Foo"];
+    [contact setFamilyName:@"Bar"];
+
+    auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+    [itemProvider registerObject:contact.get() visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider setSuggestedName:@"Foo Bar"];
+
+    return itemProvider;
+}
+
+TEST(DragAndDropTests, ExternalSourceMapItemIntoEditableAreas)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"];
+    [webView _synchronouslyExecuteEditCommand:@"Delete" argument:nil];
+
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setExternalItemProviders:@[ createMapItemForTesting().autorelease() ]];
+    [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(100, 100)];
+    EXPECT_WK_STREQ("Apple Park", [webView stringByEvaluatingJavaScript:@"document.querySelector('div[contenteditable]').textContent"]);
+    NSURL *firstURL = [NSURL URLWithString:[webView stringByEvaluatingJavaScript:@"document.querySelector('a').href"]];
+    EXPECT_WK_STREQ("maps.apple.com", firstURL.host);
+
+    [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(100, 300)];
+    NSURL *secondURL = [NSURL URLWithString:[webView stringByEvaluatingJavaScript:@"document.querySelector('textarea').value"]];
+    EXPECT_WK_STREQ("maps.apple.com", secondURL.host);
+}
+
+TEST(DragAndDropTests, ExternalSourceContactIntoEditableAreas)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-textarea"];
+    [webView _synchronouslyExecuteEditCommand:@"Delete" argument:nil];
+
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setExternalItemProviders:@[ createContactItemForTesting().autorelease() ]];
+    [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(100, 100)];
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"document.querySelector('div[contenteditable]').textContent"]);
+
+    [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(100, 300)];
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"document.querySelector('textarea').textContent"]);
+}
+
+TEST(DragAndDropTests, ExternalSourceMapItemAndContactToUploadArea)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setExternalItemProviders:@[ createMapItemForTesting().autorelease(), createContactItemForTesting().autorelease() ]];
+    [simulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 300)];
+
+    EXPECT_WK_STREQ("text/vcard, text/vcard", [webView stringByEvaluatingJavaScript:@"output.value"]);
+}
+
 static RetainPtr<TestWKWebView> setUpTestWebViewForDataTransferItems()
 {
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
@@ -1143,8 +1218,6 @@
     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
 }
 
-#endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
-
 TEST(DragAndDropTests, ExternalSourceOverrideDropInsertURL)
 {
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
@@ -1562,8 +1635,6 @@
     checkCGRectIsEqualToCGRectWithLogging({{0, 400}, {215, 174}}, [simulator liftPreviews][0].view.frame);
 }
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
-
 static NSData *testIconImageData()
 {
     return [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png" inDirectory:@"TestWebKitAPI.resources"]];
@@ -1987,8 +2058,6 @@
     TestWebKitAPI::Util::run(&done);
 }
 
-#endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
-
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(DRAG_SUPPORT) && PLATFORM(IOS_FAMILY) && WK_API_ENABLED
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to