Title: [221751] trunk
Revision
221751
Author
[email protected]
Date
2017-09-07 13:12:18 -0700 (Thu, 07 Sep 2017)

Log Message

[Directory Upload] Extend drag and drop support to iOS
https://bugs.webkit.org/show_bug.cgi?id=176492
<rdar://problem/34291584>

Reviewed by Tim Horton.

Source/WebCore:

Adds support for accepting dropped folders on iOS.

Tests: DataInteractionTests.ExternalSourceDataTransferItemGetFolderAsEntry
       DataInteractionTests.ExternalSourceDataTransferItemGetPlainTextFileAsEntry

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

Add "public.folder" as a compatible pasteboard type for drops on iOS. This means file inputs and custom drop
targets that preventDefault() will, by default, be able to accept incoming folders.

* platform/ios/WebItemProviderPasteboard.mm:
(linkTemporaryItemProviderFilesToDropStagingDirectory):

Tweak temporaryFileURLForDataInteractionContent to also hard link UIKit's temporary files instead, and return
a non-null destination URL only if the necessary file operations succeeded. Also renames this helper to
linkTemporaryItemProviderFilesToDropStagingDirectory to better reflect its new purpose. This makes logic much
cleaner at the call site, which no longer checks against various conditions before proceeding to set the data
transfer URL.

(-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
(temporaryFileURLForDataInteractionContent): Deleted.

Tools:

Adds two new iOS drag and drop unit tests, which both exercise the DataTransferItem.webKitGetAsEntry codepath
upon drop. (...)GetFolderAsEntry creates a new folder in the temporary directory and uses it to generate an item
provider. This item provider is then dropped over a custom drop handling element, which writes information about
the exposed FileSystemEntries into a textarea. (...)ExternalSourceDataTransferItemGetPlainTextFileAsEntry does
something similar, except that it only drops a plain text file instead.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/DataTransferItem-getAsEntry.html: Added.

Introduce a new test page that dumps information about DataTransferItems' file system entries upon drop.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(runTestWithTemporaryTextFile):
(runTestWithTemporaryFolder):

Introduce helpers to set up and tear down temporary files and folders over the duration of a test.

(TestWebKitAPI::setUpTestWebViewForDataTransferItems):
(TestWebKitAPI::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (221750 => 221751)


--- trunk/Source/WebCore/ChangeLog	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Source/WebCore/ChangeLog	2017-09-07 20:12:18 UTC (rev 221751)
@@ -1,3 +1,34 @@
+2017-09-07  Wenson Hsieh  <[email protected]>
+
+        [Directory Upload] Extend drag and drop support to iOS
+        https://bugs.webkit.org/show_bug.cgi?id=176492
+        <rdar://problem/34291584>
+
+        Reviewed by Tim Horton.
+
+        Adds support for accepting dropped folders on iOS.
+
+        Tests: DataInteractionTests.ExternalSourceDataTransferItemGetFolderAsEntry
+               DataInteractionTests.ExternalSourceDataTransferItemGetPlainTextFileAsEntry
+
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::supportedFileUploadPasteboardTypes):
+
+        Add "public.folder" as a compatible pasteboard type for drops on iOS. This means file inputs and custom drop
+        targets that preventDefault() will, by default, be able to accept incoming folders.
+
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (linkTemporaryItemProviderFilesToDropStagingDirectory):
+
+        Tweak temporaryFileURLForDataInteractionContent to also hard link UIKit's temporary files instead, and return
+        a non-null destination URL only if the necessary file operations succeeded. Also renames this helper to
+        linkTemporaryItemProviderFilesToDropStagingDirectory to better reflect its new purpose. This makes logic much
+        cleaner at the call site, which no longer checks against various conditions before proceeding to set the data
+        transfer URL.
+
+        (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
+        (temporaryFileURLForDataInteractionContent): Deleted.
+
 2017-09-07  Alex Christensen  <[email protected]>
 
         Modernize Geolocation code

Modified: trunk/Source/WebCore/platform/ios/PasteboardIOS.mm (221750 => 221751)


--- trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2017-09-07 20:12:18 UTC (rev 221751)
@@ -306,7 +306,7 @@
 
 NSArray *Pasteboard::supportedFileUploadPasteboardTypes()
 {
-    return @[ (NSString *)kUTTypeContent, (NSString *)kUTTypeZipArchive ];
+    return @[ (NSString *)kUTTypeContent, (NSString *)kUTTypeZipArchive, (NSString *)kUTTypeFolder ];
 }
 
 bool Pasteboard::hasData()

Modified: trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm (221750 => 221751)


--- trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2017-09-07 20:12:18 UTC (rev 221751)
@@ -413,9 +413,10 @@
     return numberOfFiles;
 }
 
-static NSURL *temporaryFileURLForDataInteractionContent(NSURL *url, NSString *suggestedName)
+static NSURL *linkTemporaryItemProviderFilesToDropStagingDirectory(NSURL *url, NSString *suggestedName, NSString *typeIdentifier)
 {
-    static NSString *defaultDataInteractionFileName = @"file";
+    static NSString *defaultDropFolderName = @"folder";
+    static NSString *defaultDropFileName = @"file";
     static NSString *dataInteractionDirectoryPrefix = @"data-interaction";
     if (!url)
         return nil;
@@ -424,11 +425,18 @@
     if (!temporaryDataInteractionDirectory)
         return nil;
 
-    suggestedName = suggestedName ?: defaultDataInteractionFileName;
-    if (![suggestedName containsString:@"."])
+    NSURL *destination = nil;
+    BOOL isFolder = UTTypeConformsTo((CFStringRef)typeIdentifier, kUTTypeFolder);
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+
+    if (!suggestedName)
+        suggestedName = url.lastPathComponent ?: (isFolder ? defaultDropFolderName : defaultDropFileName);
+
+    if (![suggestedName containsString:@"."] && !isFolder)
         suggestedName = [suggestedName stringByAppendingPathExtension:url.pathExtension];
 
-    return [NSURL fileURLWithPath:[temporaryDataInteractionDirectory stringByAppendingPathComponent:suggestedName ?: url.lastPathComponent]];
+    destination = [NSURL fileURLWithPath:[temporaryDataInteractionDirectory stringByAppendingPathComponent:suggestedName]];
+    return [fileManager linkItemAtURL:url toURL:destination error:nil] ? destination : nil;
 }
 
 - (NSString *)typeIdentifierToLoadForRegisteredTypeIdentfiers:(NSArray<NSString *> *)registeredTypeIdentifiers
@@ -484,14 +492,13 @@
         RetainPtr<NSString> suggestedName = [itemProvider suggestedName];
         dispatch_group_enter(fileLoadingGroup.get());
         dispatch_group_enter(synchronousFileLoadingGroup.get());
-        [itemProvider loadFileRepresentationForTypeIdentifier:typeIdentifier.get() completionHandler:[synchronousFileLoadingGroup, setFileURLsLock, indexInItemProviderArray, suggestedName, typeIdentifier, typeToFileURLMaps, fileLoadingGroup] (NSURL *url, NSError *error) {
+        [itemProvider loadFileRepresentationForTypeIdentifier:typeIdentifier.get() completionHandler:[synchronousFileLoadingGroup, setFileURLsLock, indexInItemProviderArray, suggestedName, typeIdentifier, typeToFileURLMaps, fileLoadingGroup] (NSURL *url, NSError *) {
             // After executing this completion block, UIKit removes the file at the given URL. However, we need this data to persist longer for the web content process.
             // To address this, we hard link the given URL to a new temporary file in the temporary directory. This follows the same flow as regular file upload, in
             // WKFileUploadPanel.mm. The temporary files are cleaned up by the system at a later time.
-            RetainPtr<NSURL> destinationURL = temporaryFileURLForDataInteractionContent(url, suggestedName.get());
-            if (destinationURL && !error && [[NSFileManager defaultManager] linkItemAtURL:url toURL:destinationURL.get() error:nil]) {
+            if (NSURL *destination = linkTemporaryItemProviderFilesToDropStagingDirectory(url, suggestedName.get(), typeIdentifier.get())) {
                 [setFileURLsLock lock];
-                [typeToFileURLMaps setObject:[NSDictionary dictionaryWithObject:destinationURL.get() forKey:typeIdentifier.get()] atIndexedSubscript:indexInItemProviderArray];
+                [typeToFileURLMaps setObject:[NSDictionary dictionaryWithObject:destination forKey:typeIdentifier.get()] atIndexedSubscript:indexInItemProviderArray];
                 [setFileURLsLock unlock];
             }
             dispatch_group_leave(fileLoadingGroup.get());

Modified: trunk/Tools/ChangeLog (221750 => 221751)


--- trunk/Tools/ChangeLog	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Tools/ChangeLog	2017-09-07 20:12:18 UTC (rev 221751)
@@ -1,3 +1,31 @@
+2017-09-07  Wenson Hsieh  <[email protected]>
+
+        [Directory Upload] Extend drag and drop support to iOS
+        https://bugs.webkit.org/show_bug.cgi?id=176492
+        <rdar://problem/34291584>
+
+        Reviewed by Tim Horton.
+
+        Adds two new iOS drag and drop unit tests, which both exercise the DataTransferItem.webKitGetAsEntry codepath
+        upon drop. (...)GetFolderAsEntry creates a new folder in the temporary directory and uses it to generate an item
+        provider. This item provider is then dropped over a custom drop handling element, which writes information about
+        the exposed FileSystemEntries into a textarea. (...)ExternalSourceDataTransferItemGetPlainTextFileAsEntry does
+        something similar, except that it only drops a plain text file instead.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/DataTransferItem-getAsEntry.html: Added.
+
+        Introduce a new test page that dumps information about DataTransferItems' file system entries upon drop.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (runTestWithTemporaryTextFile):
+        (runTestWithTemporaryFolder):
+
+        Introduce helpers to set up and tear down temporary files and folders over the duration of a test.
+
+        (TestWebKitAPI::setUpTestWebViewForDataTransferItems):
+        (TestWebKitAPI::TEST):
+
 2017-09-07  Filip Pizlo  <[email protected]>
 
         WSL should check recursion

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (221750 => 221751)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-09-07 20:12:18 UTC (rev 221751)
@@ -676,6 +676,7 @@
 		F44D06451F395C26001A0E29 /* editor-state-test-harness.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */; };
 		F44D06471F39627A001A0E29 /* EditorStateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44D06461F395C4D001A0E29 /* EditorStateTests.mm */; };
 		F44D064A1F3962F2001A0E29 /* EditingTestHarness.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44D06491F3962E3001A0E29 /* EditingTestHarness.mm */; };
+		F4512E131F60C44600BB369E /* DataTransferItem-getAsEntry.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4512E121F60C43400BB369E /* DataTransferItem-getAsEntry.html */; };
 		F4538EF71E8473E600B5C953 /* large-red-square.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4538EF01E846B4100B5C953 /* large-red-square.png */; };
 		F45B63FB1F197F4A009D38B9 /* image-map.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F45B63FA1F197F33009D38B9 /* image-map.html */; };
 		F45B63FE1F19D410009D38B9 /* ActionSheetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */; };
@@ -815,6 +816,7 @@
 				5C2936961D5C00ED00DEAB1E /* CookieMessage.html in Copy Resources */,
 				7AEAD4811E20122700416EFE /* CrossPartitionFileSchemeAccess.html in Copy Resources */,
 				290F4275172A221C00939FF0 /* custom-protocol-sync-xhr.html in Copy Resources */,
+				F4512E131F60C44600BB369E /* DataTransferItem-getAsEntry.html in Copy Resources */,
 				C07E6CB213FD73930038B22B /* devicePixelRatio.html in Copy Resources */,
 				0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */,
 				F41AB9A21EF4696B0083FA08 /* div-and-large-image.html in Copy Resources */,
@@ -1706,6 +1708,7 @@
 		F44D06461F395C4D001A0E29 /* EditorStateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorStateTests.mm; sourceTree = "<group>"; };
 		F44D06481F3962E3001A0E29 /* EditingTestHarness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingTestHarness.h; sourceTree = "<group>"; };
 		F44D06491F3962E3001A0E29 /* EditingTestHarness.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditingTestHarness.mm; sourceTree = "<group>"; };
+		F4512E121F60C43400BB369E /* DataTransferItem-getAsEntry.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "DataTransferItem-getAsEntry.html"; sourceTree = "<group>"; };
 		F4538EF01E846B4100B5C953 /* large-red-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "large-red-square.png"; sourceTree = "<group>"; };
 		F45B63FA1F197F33009D38B9 /* image-map.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "image-map.html"; sourceTree = "<group>"; };
 		F45B63FC1F19D410009D38B9 /* ActionSheetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ActionSheetTests.mm; sourceTree = "<group>"; };
@@ -2152,6 +2155,7 @@
 				F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */,
 				A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */,
 				5C2936941D5BFD1900DEAB1E /* CookieMessage.html */,
+				F4512E121F60C43400BB369E /* DataTransferItem-getAsEntry.html */,
 				0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */,
 				F41AB99E1EF4692C0083FA08 /* div-and-large-image.html */,
 				837A35F01D9A1E6400663C57 /* DownloadRequestBlobURL.html */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataTransferItem-getAsEntry.html (0 => 221751)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataTransferItem-getAsEntry.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/DataTransferItem-getAsEntry.html	2017-09-07 20:12:18 UTC (rev 221751)
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+html, body {
+    font-family: -apple-system;
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    font-size: 1em;
+}
+
+#droparea {
+    margin-top: 1em;
+    width: 100%;
+    height: 200px;
+    top: 0;
+    left: 0;
+}
+
+#output {
+    width: 100%;
+    height: calc(100% - 200px);
+    font-family: monospace;
+}
+</style>
+
+<div id="droparea">
+    <div>To manually test, drop something into this area and observe the output below.</div>
+</div>
+<textarea id="output"></textarea>
+
+<script>
+    function getChildEntries(entry) {
+        if (!entry.isDirectory)
+            return Promise.resolve([]);
+
+        return new Promise((resolve, reject) => {
+            let result = [];
+            let reader = entry.createReader();
+            let doBatch = () => {
+                reader.readEntries(entries => {
+                    if (entries.length > 0) {
+                        entries.forEach(e => result.push(e));
+                        doBatch();
+                    } else
+                        resolve(result);
+                }, reject);
+            };
+            doBatch();
+        });
+    }
+
+    droparea.addEventListener("dragenter", event => event.preventDefault());
+    droparea.addEventListener("dragover", event => event.preventDefault());
+    droparea.addEventListener("drop", handleDrop);
+
+    async function handleDrop(event)
+    {
+        await logItemAndFileEntryInformation(event.dataTransfer.items);
+        event.preventDefault();
+        webkit.messageHandlers.testHandler.postMessage("dropped");
+    }
+
+    function fileFromFileSystemFileEntry(fileEntry)
+    {
+        return new Promise(resolve => fileEntry.file(file => resolve(file)));
+    }
+
+    async function representationForFileSystemEntry(entry)
+    {
+        let representation = "";
+        if (entry.isDirectory) {
+            representation += `DIR: ${entry.fullPath}\n`;
+            for (let child of await getChildEntries(entry))
+                representation += await representationForFileSystemEntry(child);
+        } else if (entry.isFile) {
+            let file = await fileFromFileSystemFileEntry(entry);
+            representation += `FILE: ${entry.fullPath} ('${file.type}', ${file.size} bytes)\n`;
+        }
+        return representation;
+    }
+
+    async function logItemAndFileEntryInformation(items)
+    {
+        output.value = "";
+        for (let index = 0; index < items.length; index++) {
+            let item = items.item(index);
+            output.value += `Found data transfer item (kind: '${item.kind}', type: '${item.type}')\n`;
+            let entry = item.webkitGetAsEntry();
+            if (entry)
+                output.value += await representationForFileSystemEntry(entry);
+        }
+    }
+</script>
+</html>

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (221750 => 221751)


--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-09-07 19:56:03 UTC (rev 221750)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-09-07 20:12:18 UTC (rev 221751)
@@ -34,6 +34,7 @@
 #import <MobileCoreServices/MobileCoreServices.h>
 #import <UIKit/NSItemProvider+UIKitAdditions.h>
 #import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKPreferencesRefPrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WebItemProviderPasteboard.h>
@@ -164,6 +165,55 @@
         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
 }
 
+static void runTestWithTemporaryTextFile(void(^runTest)(NSURL *fileURL))
+{
+    NSString *fileName = [NSString stringWithFormat:@"drag-drop-text-file-%@.txt", [NSUUID UUID].UUIDString];
+    RetainPtr<NSURL> temporaryFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName] isDirectory:NO];
+    [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
+
+    NSError *error = nil;
+    [@"This is a tiny blob of text." writeToURL:temporaryFile.get() atomically:YES encoding:NSUTF8StringEncoding error:&error];
+
+    if (error)
+        NSLog(@"Error writing temporary file: %@", error);
+
+    @try {
+        runTest(temporaryFile.get());
+    } @finally {
+        [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
+    }
+}
+
+static void runTestWithTemporaryFolder(void(^runTest)(NSURL *folderURL))
+{
+    NSString *folderName = [NSString stringWithFormat:@"some.directory-%@", [NSUUID UUID].UUIDString];
+    RetainPtr<NSURL> temporaryFolder = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:folderName] isDirectory:YES];
+    [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
+
+    NSError *error = nil;
+    NSFileManager *defaultManager = [NSFileManager defaultManager];
+    [defaultManager createDirectoryAtURL:temporaryFolder.get() withIntermediateDirectories:NO attributes:nil error:&error];
+    [UIImagePNGRepresentation(testIconImage()) writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"icon.png" isDirectory:NO] atomically:YES];
+    [testZIPArchive() writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"archive.zip" isDirectory:NO] atomically:YES];
+
+    NSURL *firstSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory1" isDirectory:YES];
+    [defaultManager createDirectoryAtURL:firstSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
+    [@"I am a text file in the first subdirectory." writeToURL:[firstSubdirectory URLByAppendingPathComponent:@"text-file-1.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
+
+    NSURL *secondSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory2" isDirectory:YES];
+    [defaultManager createDirectoryAtURL:secondSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
+    [@"I am a text file in the second subdirectory." writeToURL:[secondSubdirectory URLByAppendingPathComponent:@"text-file-2.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
+
+    if (error)
+        NSLog(@"Error writing temporary file: %@", error);
+
+    @try {
+        runTest(temporaryFolder.get());
+    } @finally {
+        [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
+    }
+}
+
 namespace TestWebKitAPI {
 
 TEST(DataInteractionTests, ImageToContentEditable)
@@ -877,6 +927,88 @@
     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
 }
 
+static RetainPtr<TestWKWebView> setUpTestWebViewForDataTransferItems()
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"DataTransferItem-getAsEntry"];
+
+    auto preferences = (WKPreferencesRef)[[webView configuration] preferences];
+    WKPreferencesSetDataTransferItemsEnabled(preferences, true);
+    WKPreferencesSetDirectoryUploadEnabled(preferences, true);
+
+    return webView;
+}
+
+TEST(DataInteractionTests, ExternalSourceDataTransferItemGetFolderAsEntry)
+{
+    NSArray<NSString *> *expectedOutput = @[
+        @"Found data transfer item (kind: 'string', type: 'text/plain')",
+        @"Found data transfer item (kind: 'file', type: '')",
+        @"DIR: /somedirectory",
+        @"FILE: /somedirectory/icon.png ('image/png', 42130 bytes)",
+        @"DIR: /somedirectory/subdirectory1",
+        @"FILE: /somedirectory/subdirectory1/text-file-1.txt ('text/plain', 43 bytes)",
+        @"FILE: /somedirectory/archive.zip ('application/zip', 988 bytes)",
+        @"DIR: /somedirectory/subdirectory2",
+        @"FILE: /somedirectory/subdirectory2/text-file-2.txt ('text/plain', 44 bytes)",
+        @""
+    ];
+
+    auto webView = setUpTestWebViewForDataTransferItems();
+    __block bool done = false;
+    [webView performAfterReceivingMessage:@"dropped" action:^() {
+        done = true;
+    }];
+
+    runTestWithTemporaryFolder(^(NSURL *folderURL) {
+        auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+        [itemProvider setSuggestedName:@"somedirectory"];
+        [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeFolder fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFolderURL = retainPtr(folderURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
+            completionHandler(capturedFolderURL.get(), NO, nil);
+            return nil;
+        }];
+
+        auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+        [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
+        [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
+    });
+
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
+}
+
+TEST(DataInteractionTests, ExternalSourceDataTransferItemGetPlainTextFileAsEntry)
+{
+    NSArray<NSString *> *expectedOutput = @[
+        @"Found data transfer item (kind: 'string', type: 'text/plain')",
+        @"Found data transfer item (kind: 'file', type: 'text/plain')",
+        @"FILE: /foo.txt ('text/plain', 28 bytes)",
+        @""
+    ];
+
+    auto webView = setUpTestWebViewForDataTransferItems();
+    __block bool done = false;
+    [webView performAfterReceivingMessage:@"dropped" action:^() {
+        done = true;
+    }];
+
+    runTestWithTemporaryTextFile(^(NSURL *fileURL) {
+        auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
+        [itemProvider setSuggestedName:@"foo"];
+        [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFileURL = retainPtr(fileURL)](FileLoadCompletionBlock completionHandler) -> NSProgress * {
+            completionHandler(capturedFileURL.get(), NO, nil);
+            return nil;
+        }];
+
+        auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+        [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
+        [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
+    });
+
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
+}
+
 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
 {
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to