Title: [245839] trunk
Revision
245839
Author
[email protected]
Date
2019-05-28 19:56:09 -0700 (Tue, 28 May 2019)

Log Message

[iOS] Respect NSItemProvider's registered types when dropping files that are loaded in-place
https://bugs.webkit.org/show_bug.cgi?id=198315
<rdar://problem/51183762>

Reviewed by Tim Horton.

Source/WebCore:

Currently, logic in PasteboardIOS.mm and WebContentReaderCocoa.mm attempts to deduce the content type from the
file path when dropping attachments on iOS. Instead, we should be plumbing the content type through to the
reader.

Test: WKAttachmentTestsIOS.InsertDroppedImageWithNonImageFileExtension

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

Add a helper method to determine which type to use in attachment elements. This makes the paste
(attachmentForData) and drop (attachmentForFilePaths) behave the same way, with respect to the type attribute
used to represent the attachment.

(WebCore::attachmentForFilePath):

Use the content type, if specified; otherwise, fall back to deducing it from the file path.

(WebCore::attachmentForData):
(WebCore::WebContentReader::readFilePath):
* platform/Pasteboard.h:
(WebCore::PasteboardWebContentReader::readFilePath):

Pass the highest fidelity representation's content type to the web content reader.

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

Tools:

Adds a new API test to verify that when dropping a file that is loaded in-place with a file extension that is
not a .png (but was registered to the item provider as "public.png"), the resulting attachment is contained in
an image element, and the resulting attachment info indicates that the dropped attachment is a png file.

Additionally, rebaseline some existing tests.

* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(runTestWithTemporaryImageFile):
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (245838 => 245839)


--- trunk/Source/WebCore/ChangeLog	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Source/WebCore/ChangeLog	2019-05-29 02:56:09 UTC (rev 245839)
@@ -1,3 +1,39 @@
+2019-05-28  Wenson Hsieh  <[email protected]>
+
+        [iOS] Respect NSItemProvider's registered types when dropping files that are loaded in-place
+        https://bugs.webkit.org/show_bug.cgi?id=198315
+        <rdar://problem/51183762>
+
+        Reviewed by Tim Horton.
+
+        Currently, logic in PasteboardIOS.mm and WebContentReaderCocoa.mm attempts to deduce the content type from the
+        file path when dropping attachments on iOS. Instead, we should be plumbing the content type through to the
+        reader.
+
+        Test: WKAttachmentTestsIOS.InsertDroppedImageWithNonImageFileExtension
+
+        * editing/WebContentReader.h:
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::typeForAttachmentElement):
+
+        Add a helper method to determine which type to use in attachment elements. This makes the paste
+        (attachmentForData) and drop (attachmentForFilePaths) behave the same way, with respect to the type attribute
+        used to represent the attachment.
+
+        (WebCore::attachmentForFilePath):
+
+        Use the content type, if specified; otherwise, fall back to deducing it from the file path.
+
+        (WebCore::attachmentForData):
+        (WebCore::WebContentReader::readFilePath):
+        * platform/Pasteboard.h:
+        (WebCore::PasteboardWebContentReader::readFilePath):
+
+        Pass the highest fidelity representation's content type to the web content reader.
+
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::readRespectingUTIFidelities):
+
 2019-05-28  Myles C. Maxfield  <[email protected]>
 
         Move idempotent text autosizing to StyleTreeResolver

Modified: trunk/Source/WebCore/editing/WebContentReader.h (245838 => 245839)


--- trunk/Source/WebCore/editing/WebContentReader.h	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Source/WebCore/editing/WebContentReader.h	2019-05-29 02:56:09 UTC (rev 245839)
@@ -71,7 +71,7 @@
 private:
 #if PLATFORM(COCOA)
     bool readWebArchive(SharedBuffer&) override;
-    bool readFilePath(const String&, Optional<FloatSize> preferredPresentationSize = { }) override;
+    bool readFilePath(const String&, Optional<FloatSize> preferredPresentationSize = { }, const String& contentType = { }) override;
     bool readFilePaths(const Vector<String>&) override;
     bool readHTML(const String&) override;
     bool readRTFD(SharedBuffer&) override;
@@ -95,7 +95,7 @@
 private:
 #if PLATFORM(COCOA)
     bool readWebArchive(SharedBuffer&) override;
-    bool readFilePath(const String&, Optional<FloatSize> = { }) override { return false; }
+    bool readFilePath(const String&, Optional<FloatSize> = { }, const String& = { }) override { return false; }
     bool readFilePaths(const Vector<String>&) override { return false; }
     bool readHTML(const String&) override;
     bool readRTFD(SharedBuffer&) override;

Modified: trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm (245838 => 245839)


--- trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm	2019-05-29 02:56:09 UTC (rev 245839)
@@ -695,8 +695,17 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
-static Ref<HTMLElement> attachmentForFilePath(Frame& frame, const String& path, Optional<FloatSize> preferredSize)
+static String typeForAttachmentElement(const String& contentType)
 {
+    if (contentType.isEmpty())
+        return { };
+
+    auto mimeType = mimeTypeFromContentType(contentType);
+    return mimeType.isEmpty() ? contentType : mimeType;
+}
+
+static Ref<HTMLElement> attachmentForFilePath(Frame& frame, const String& path, Optional<FloatSize> preferredSize, const String& explicitContentType)
+{
     auto document = makeRef(*frame.document());
     auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
     if (!supportsClientSideAttachmentData(frame)) {
@@ -704,17 +713,23 @@
         return attachment;
     }
 
-    String contentType;
+    bool isDirectory = FileSystem::fileIsDirectory(path, FileSystem::ShouldFollowSymbolicLinks::Yes);
+    String contentType = typeForAttachmentElement(explicitContentType);
+    if (contentType.isEmpty()) {
+        if (isDirectory)
+            contentType = kUTTypeDirectory;
+        else {
+            contentType = File::contentTypeForFile(path);
+            if (contentType.isEmpty())
+                contentType = kUTTypeData;
+        }
+    }
+
     Optional<uint64_t> fileSizeForDisplay;
-    if (FileSystem::fileIsDirectory(path, FileSystem::ShouldFollowSymbolicLinks::Yes))
-        contentType = kUTTypeDirectory;
-    else {
+    if (!isDirectory) {
         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);
@@ -738,8 +753,7 @@
 {
     auto document = makeRef(*frame.document());
     auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
-    auto mimeType = mimeTypeFromContentType(contentType);
-    auto typeForAttachmentElement = mimeType.isEmpty() ? contentType : mimeType;
+    auto attachmentType = typeForAttachmentElement(contentType);
 
     // FIXME: We should instead ask CoreServices for a preferred name corresponding to the given content type.
     static const char* defaultAttachmentName = "file";
@@ -751,15 +765,15 @@
         fileName = name;
 
     if (!supportsClientSideAttachmentData(frame)) {
-        attachment->setFile(File::create(Blob::create(buffer, WTFMove(typeForAttachmentElement)), fileName));
+        attachment->setFile(File::create(Blob::create(buffer, WTFMove(attachmentType)), fileName));
         return attachment;
     }
 
-    frame.editor().registerAttachmentIdentifier(attachment->ensureUniqueIdentifier(), typeForAttachmentElement, fileName, buffer);
+    frame.editor().registerAttachmentIdentifier(attachment->ensureUniqueIdentifier(), attachmentType, fileName, buffer);
 
-    if (contentTypeIsSuitableForInlineImageRepresentation(typeForAttachmentElement)) {
+    if (contentTypeIsSuitableForInlineImageRepresentation(attachmentType)) {
         auto image = HTMLImageElement::create(document);
-        image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(Blob::create(buffer, WTFMove(typeForAttachmentElement)), WTFMove(fileName))));
+        image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(Blob::create(buffer, WTFMove(attachmentType)), WTFMove(fileName))));
         image->setAttachmentElement(WTFMove(attachment));
         if (preferredSize) {
             image->setAttributeWithoutSynchronization(HTMLNames::widthAttr, AtomicString::number(preferredSize->width()));
@@ -768,13 +782,13 @@
         return image;
     }
 
-    attachment->updateAttributes({ buffer.size() }, WTFMove(typeForAttachmentElement), WTFMove(fileName));
+    attachment->updateAttributes({ buffer.size() }, WTFMove(attachmentType), WTFMove(fileName));
     return attachment;
 }
 
 #endif // ENABLE(ATTACHMENT_ELEMENT)
 
-bool WebContentReader::readFilePath(const String& path, Optional<FloatSize> preferredPresentationSize)
+bool WebContentReader::readFilePath(const String& path, Optional<FloatSize> preferredPresentationSize, const String& contentType)
 {
     if (path.isEmpty() || !frame.document())
         return false;
@@ -785,7 +799,7 @@
 
 #if ENABLE(ATTACHMENT_ELEMENT)
     if (RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled())
-        fragment->appendChild(attachmentForFilePath(frame, path, preferredPresentationSize));
+        fragment->appendChild(attachmentForFilePath(frame, path, preferredPresentationSize, contentType));
 #endif
 
     return true;

Modified: trunk/Source/WebCore/platform/Pasteboard.h (245838 => 245839)


--- trunk/Source/WebCore/platform/Pasteboard.h	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Source/WebCore/platform/Pasteboard.h	2019-05-29 02:56:09 UTC (rev 245839)
@@ -136,7 +136,7 @@
 
 #if PLATFORM(COCOA)
     virtual bool readWebArchive(SharedBuffer&) = 0;
-    virtual bool readFilePath(const String&, Optional<FloatSize> preferredPresentationSize = { }) = 0;
+    virtual bool readFilePath(const String&, Optional<FloatSize> preferredPresentationSize = { }, const String& contentType = { }) = 0;
     virtual bool readFilePaths(const Vector<String>&) = 0;
     virtual bool readHTML(const String&) = 0;
     virtual bool readRTFD(SharedBuffer&) = 0;

Modified: trunk/Source/WebCore/platform/ios/PasteboardIOS.mm (245838 => 245839)


--- trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2019-05-29 02:56:09 UTC (rev 245839)
@@ -345,9 +345,10 @@
         auto info = strategy.informationForItemAtIndex(index, m_pasteboardName);
         auto attachmentFilePath = info.pathForHighestFidelityItem();
         bool canReadAttachment = policy == WebContentReadingPolicy::AnyType && RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() && !attachmentFilePath.isEmpty();
+        auto contentType = info.contentTypeForHighestFidelityItem();
         if (canReadAttachment && prefersAttachmentRepresentation(info)) {
-            readURLAlongsideAttachmentIfNecessary(reader, strategy, info.contentTypeForHighestFidelityItem(), m_pasteboardName, index);
-            reader.readFilePath(WTFMove(attachmentFilePath), info.preferredPresentationSize);
+            readURLAlongsideAttachmentIfNecessary(reader, strategy, contentType, m_pasteboardName, index);
+            reader.readFilePath(WTFMove(attachmentFilePath), info.preferredPresentationSize, contentType);
             continue;
         }
 #endif
@@ -366,7 +367,7 @@
         }
 #if ENABLE(ATTACHMENT_ELEMENT)
         if (canReadAttachment && result == ReaderResult::DidNotReadType)
-            reader.readFilePath(WTFMove(attachmentFilePath), info.preferredPresentationSize);
+            reader.readFilePath(WTFMove(attachmentFilePath), info.preferredPresentationSize, contentType);
 #endif
     }
 }

Modified: trunk/Tools/ChangeLog (245838 => 245839)


--- trunk/Tools/ChangeLog	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Tools/ChangeLog	2019-05-29 02:56:09 UTC (rev 245839)
@@ -1,3 +1,21 @@
+2019-05-28  Wenson Hsieh  <[email protected]>
+
+        [iOS] Respect NSItemProvider's registered types when dropping files that are loaded in-place
+        https://bugs.webkit.org/show_bug.cgi?id=198315
+        <rdar://problem/51183762>
+
+        Reviewed by Tim Horton.
+
+        Adds a new API test to verify that when dropping a file that is loaded in-place with a file extension that is
+        not a .png (but was registered to the item provider as "public.png"), the resulting attachment is contained in
+        an image element, and the resulting attachment info indicates that the dropped attachment is a png file.
+
+        Additionally, rebaseline some existing tests.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+        (runTestWithTemporaryImageFile):
+        (TestWebKitAPI::TEST):
+
 2019-05-28  Yusuke Suzuki  <[email protected]>
 
         GCHeapInspector should accept weird filename

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm (245838 => 245839)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2019-05-29 02:27:20 UTC (rev 245838)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm	2019-05-29 02:56:09 UTC (rev 245839)
@@ -410,6 +410,24 @@
     }
 }
 
+#if PLATFORM(IOS_FAMILY)
+
+static void runTestWithTemporaryImageFile(NSString *fileName, void(^runTest)(NSURL *fileURL))
+{
+    NSFileManager *defaultManager = [NSFileManager defaultManager];
+    auto temporaryFilePath = retainPtr([NSTemporaryDirectory() stringByAppendingPathComponent:fileName]);
+    auto temporaryFileURL = retainPtr([NSURL fileURLWithPath:temporaryFilePath.get()]);
+    [defaultManager removeItemAtURL:temporaryFileURL.get() error:nil];
+    [testImageData() writeToFile:temporaryFilePath.get() atomically:YES];
+    @try {
+        runTest(temporaryFileURL.get());
+    } @finally {
+        [defaultManager removeItemAtURL:temporaryFileURL.get() error:nil];
+    }
+}
+
+#endif // PLATFORM(IOS_FAMILY)
+
 static void simulateFolderDragWithURL(DragAndDropSimulator *simulator, NSURL *folderURL)
 {
 #if PLATFORM(MAC)
@@ -788,8 +806,13 @@
 
         TestWKWebView *webView = [simulator webView];
         auto attachment = retainPtr([simulator insertedAttachments].firstObject);
+#if PLATFORM(IOS_FAMILY)
+        NSString *expectedType = (__bridge NSString *)kUTTypeFolder;
+#else
+        NSString *expectedType = (__bridge NSString *)kUTTypeDirectory;
+#endif
         EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]);
-        EXPECT_WK_STREQ((__bridge NSString *)kUTTypeDirectory, [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
+        EXPECT_WK_STREQ(expectedType, [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]);
         EXPECT_WK_STREQ(folderURL.lastPathComponent, [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]);
 
         NSFileWrapper *image = [attachment info].fileWrapper.fileWrappers[@"image.png"];
@@ -1704,9 +1727,9 @@
 
     [webView expectElementCount:2 querySelector:@"ATTACHMENT"];
     EXPECT_WK_STREQ("hello.rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]);
-    EXPECT_WK_STREQ("text/rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
+    EXPECT_WK_STREQ((__bridge NSString *)kUTTypeFlatRTFD, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     EXPECT_WK_STREQ("world.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]);
-    EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
+    EXPECT_WK_STREQ((__bridge NSString *)kUTTypeUTF8PlainText, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
 }
 
 TEST(WKAttachmentTestsIOS, InsertDroppedZipArchiveAsAttachment)
@@ -1763,7 +1786,7 @@
     [webView expectElementTagsInOrder:@[ @"ATTACHMENT", @"A", @"ATTACHMENT" ]];
 
     EXPECT_WK_STREQ("first.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]);
-    EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
+    EXPECT_WK_STREQ((__bridge NSString *)kUTTypeUTF8PlainText, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]);
     EXPECT_WK_STREQ([appleURL absoluteString], [webView valueOfAttribute:@"href" forQuerySelector:@"a"]);
     EXPECT_WK_STREQ("second.pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]);
     EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]);
@@ -1966,6 +1989,32 @@
     EXPECT_TRUE([webView canPerformAction:@selector(paste:) withSender:nil]);
 }
 
+TEST(WKAttachmentTestsIOS, InsertDroppedImageWithNonImageFileExtension)
+{
+    runTestWithTemporaryImageFile(@"image.hello", ^(NSURL *fileURL) {
+        auto item = adoptNS([[NSItemProvider alloc] init]);
+        [item setSuggestedName:@"image.hello"];
+        [item registerFileRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypePNG fileOptions:NSItemProviderFileOptionOpenInPlace visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(void (^callback)(NSURL *, BOOL, NSError *))
+        {
+            callback(fileURL, YES, nil);
+            return nil;
+        }];
+
+        auto webView = webViewForTestingAttachments();
+        auto dragAndDropSimulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+        [dragAndDropSimulator setExternalItemProviders:@[ item.get() ]];
+        [dragAndDropSimulator runFrom:CGPointZero to:CGPointMake(50, 50)];
+
+        EXPECT_EQ(1U, [dragAndDropSimulator insertedAttachments].count);
+        _WKAttachment *attachment = [dragAndDropSimulator insertedAttachments].firstObject;
+        _WKAttachmentInfo *info = attachment.info;
+        EXPECT_WK_STREQ("image/png", info.contentType);
+        EXPECT_WK_STREQ("image.hello", info.filePath.lastPathComponent);
+        EXPECT_WK_STREQ("image.hello", info.name);
+        [webView expectElementCount:1 querySelector:@"IMG"];
+    });
+}
+
 #if HAVE(PENCILKIT)
 static BOOL forEachViewInHierarchy(UIView *view, void(^mapFunction)(UIView *subview, BOOL *stop))
 {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to