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)]);