[iOS] Multiple links in Mail are dropped in a single line, and are difficult to tell...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / ios / DataInteractionTests.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(DATA_INTERACTION)
29
30 #import "DataInteractionSimulator.h"
31 #import "PlatformUtilities.h"
32 #import "TestWKWebView.h"
33 #import "UIKitSPI.h"
34 #import "WKWebViewConfigurationExtras.h"
35 #import <MobileCoreServices/MobileCoreServices.h>
36 #import <UIKit/NSItemProvider+UIKitAdditions.h>
37 #import <WebKit/WKPreferencesPrivate.h>
38 #import <WebKit/WKPreferencesRefPrivate.h>
39 #import <WebKit/WKProcessPoolPrivate.h>
40 #import <WebKit/WKWebViewConfigurationPrivate.h>
41 #import <WebKit/WebItemProviderPasteboard.h>
42 #import <WebKit/_WKProcessPoolConfiguration.h>
43 #import <wtf/Seconds.h>
44
45 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
46 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
47 typedef void (^UIItemProviderDataLoadCompletionBlock)(NSData *, NSError *);
48
49 #if !USE(APPLE_INTERNAL_SDK)
50
51 @interface UIItemProviderRepresentationOptions : NSObject
52 @end
53
54 #endif
55
56 @interface UIItemProvider()
57 + (UIItemProvider *)itemProviderWithURL:(NSURL *)url title:(NSString *)title;
58 - (void) registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier options:(UIItemProviderRepresentationOptions*)options loadHandler:(NSProgress * (^)(void (^UIItemProviderDataLoadCompletionBlock)(NSData *item, NSError *error))) loadHandler;
59 @end
60
61 static NSString *InjectedBundlePasteboardDataType = @"org.webkit.data";
62
63 static UIImage *testIconImage()
64 {
65     return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
66 }
67
68 static NSData *testZIPArchive()
69 {
70     NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"];
71     return [NSData dataWithContentsOfURL:zipFileURL];
72 }
73
74 @implementation UIItemProvider (DataInteractionTests)
75
76 - (void)registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data
77 {
78     RetainPtr<NSData> retainedData = data;
79     [self registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler: [retainedData] (DataLoadCompletionBlock block) -> NSProgress * {
80         block(retainedData.get(), nil);
81         return [NSProgress discreteProgressWithTotalUnitCount:100];
82     }];
83 }
84
85 @end
86
87 @implementation TestWKWebView (DataInteractionTests)
88
89 - (BOOL)editorContainsImageElement
90 {
91     return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
92 }
93
94 - (NSString *)editorValue
95 {
96     return [self stringByEvaluatingJavaScript:@"editor.value"];
97 }
98
99 @end
100
101 static NSValue *makeCGRectValue(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
102 {
103     return [NSValue valueWithCGRect:CGRectMake(x, y, width, height)];
104 }
105
106 static void checkCGRectIsEqualToCGRectWithLogging(CGRect expected, CGRect observed)
107 {
108     BOOL isEqual = CGRectEqualToRect(expected, observed);
109     EXPECT_TRUE(isEqual);
110     if (!isEqual)
111         NSLog(@"Expected: %@ but observed: %@", NSStringFromCGRect(expected), NSStringFromCGRect(observed));
112 }
113
114 static void checkSelectionRectsWithLogging(NSArray *expected, NSArray *observed)
115 {
116     if (![expected isEqualToArray:observed])
117         NSLog(@"Expected selection rects: %@ but observed: %@", expected, observed);
118     EXPECT_TRUE([expected isEqualToArray:observed]);
119 }
120
121 static void checkTypeIdentifierPrecedesOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
122 {
123     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
124     EXPECT_TRUE([registeredTypes containsObject:firstType]);
125     EXPECT_TRUE([registeredTypes containsObject:secondType]);
126     EXPECT_TRUE([registeredTypes indexOfObject:firstType] < [registeredTypes indexOfObject:secondType]);
127 }
128
129 static void checkFirstTypeIsPresentAndSecondTypeIsMissing(DataInteractionSimulator *simulator, CFStringRef firstType, CFStringRef secondType)
130 {
131     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
132     EXPECT_TRUE([registeredTypes containsObject:(NSString *)firstType]);
133     EXPECT_FALSE([registeredTypes containsObject:(NSString *)secondType]);
134 }
135
136 static void checkTypeIdentifierIsRegisteredAtIndex(DataInteractionSimulator *simulator, NSString *type, NSUInteger index)
137 {
138     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
139     EXPECT_GT(registeredTypes.count, index);
140     EXPECT_WK_STREQ(type.UTF8String, [registeredTypes[index] UTF8String]);
141 }
142
143 static void checkEstimatedSize(DataInteractionSimulator *simulator, CGSize estimatedSize)
144 {
145     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
146     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
147     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
148 }
149
150 static void checkSuggestedNameAndEstimatedSize(DataInteractionSimulator *simulator, NSString *suggestedName, CGSize estimatedSize)
151 {
152     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
153     EXPECT_WK_STREQ(suggestedName.UTF8String, sourceItemProvider.suggestedName.UTF8String);
154     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
155     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
156 }
157
158 static void checkStringArraysAreEqual(NSArray<NSString *> *expected, NSArray<NSString *> *observed)
159 {
160     EXPECT_EQ(expected.count, observed.count);
161     for (NSUInteger index = 0; index < expected.count; ++index) {
162         NSString *expectedString = [expected objectAtIndex:index];
163         NSString *observedString = [observed objectAtIndex:index];
164         EXPECT_WK_STREQ(expectedString, observedString);
165         if (![expectedString isEqualToString:observedString])
166             NSLog(@"Expected observed string: %@ to match expected string: %@ at index: %tu", observedString, expectedString, index);
167     }
168 }
169
170 static void checkDragCaretRectIsContainedInRect(CGRect caretRect, CGRect containerRect)
171 {
172     BOOL contained = CGRectContainsRect(containerRect, caretRect);
173     EXPECT_TRUE(contained);
174     if (!contained)
175         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
176 }
177
178 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
179
180 static void checkJSONWithLogging(NSString *jsonString, NSDictionary *expected)
181 {
182     BOOL success = TestWebKitAPI::Util::jsonMatchesExpectedValues(jsonString, expected);
183     EXPECT_TRUE(success);
184     if (!success)
185         NSLog(@"Expected JSON: %@ to match values: %@", jsonString, expected);
186 }
187
188 static NSData *testIconImageData()
189 {
190     return [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"icon" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"]];
191 }
192
193 static void runTestWithTemporaryTextFile(void(^runTest)(NSURL *fileURL))
194 {
195     NSString *fileName = [NSString stringWithFormat:@"drag-drop-text-file-%@.txt", [NSUUID UUID].UUIDString];
196     RetainPtr<NSURL> temporaryFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName] isDirectory:NO];
197     [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
198
199     NSError *error = nil;
200     [@"This is a tiny blob of text." writeToURL:temporaryFile.get() atomically:YES encoding:NSUTF8StringEncoding error:&error];
201
202     if (error)
203         NSLog(@"Error writing temporary file: %@", error);
204
205     @try {
206         runTest(temporaryFile.get());
207     } @finally {
208         [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
209     }
210 }
211
212 static void runTestWithTemporaryFolder(void(^runTest)(NSURL *folderURL))
213 {
214     NSString *folderName = [NSString stringWithFormat:@"some.directory-%@", [NSUUID UUID].UUIDString];
215     RetainPtr<NSURL> temporaryFolder = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:folderName] isDirectory:YES];
216     [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
217
218     NSError *error = nil;
219     NSFileManager *defaultManager = [NSFileManager defaultManager];
220     [defaultManager createDirectoryAtURL:temporaryFolder.get() withIntermediateDirectories:NO attributes:nil error:&error];
221     [testIconImageData() writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"icon.png" isDirectory:NO] atomically:YES];
222     [testZIPArchive() writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"archive.zip" isDirectory:NO] atomically:YES];
223
224     NSURL *firstSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory1" isDirectory:YES];
225     [defaultManager createDirectoryAtURL:firstSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
226     [@"I am a text file in the first subdirectory." writeToURL:[firstSubdirectory URLByAppendingPathComponent:@"text-file-1.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
227
228     NSURL *secondSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory2" isDirectory:YES];
229     [defaultManager createDirectoryAtURL:secondSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
230     [@"I am a text file in the second subdirectory." writeToURL:[secondSubdirectory URLByAppendingPathComponent:@"text-file-2.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
231
232     if (error)
233         NSLog(@"Error writing temporary file: %@", error);
234
235     @try {
236         runTest(temporaryFolder.get());
237     } @finally {
238         [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
239     }
240 }
241
242 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
243
244 namespace TestWebKitAPI {
245
246 TEST(DataInteractionTests, ImageToContentEditable)
247 {
248     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
249     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
250
251     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
252     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
253
254     EXPECT_TRUE([webView editorContainsImageElement]);
255
256     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
257     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
258     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
259     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
260     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
261     checkFirstTypeIsPresentAndSecondTypeIsMissing(dataInteractionSimulator.get(), kUTTypePNG, kUTTypeFileURL);
262     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
263 }
264
265 TEST(DataInteractionTests, CanStartDragOnEnormousImage)
266 {
267     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
268     [webView synchronouslyLoadHTMLString:@"<img src='enormous.svg'></img>"];
269
270     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
271     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
272
273     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
274     EXPECT_WK_STREQ((NSString *)kUTTypeScalableVectorGraphics, [registeredTypes firstObject]);
275 }
276
277 TEST(DataInteractionTests, ImageToTextarea)
278 {
279     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
280     [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
281
282     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
283     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
284
285     EXPECT_WK_STREQ("", [webView editorValue]);
286
287     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
288     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
289     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
290     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
291     checkFirstTypeIsPresentAndSecondTypeIsMissing(dataInteractionSimulator.get(), kUTTypePNG, kUTTypeFileURL);
292     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
293 }
294
295 TEST(DataInteractionTests, ImageInLinkToInput)
296 {
297     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
298     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
299
300     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
301     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
302
303     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
304     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
305     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
306     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
307 }
308
309 TEST(DataInteractionTests, ImageInLinkWithoutHREFToInput)
310 {
311     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
312     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
313     [webView stringByEvaluatingJavaScript:@"link.href = ''"];
314
315     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
316     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
317
318     EXPECT_WK_STREQ("", [webView editorValue]);
319     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
320     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
321 }
322
323 TEST(DataInteractionTests, ImageDoesNotUseElementSizeAsEstimatedSize)
324 {
325     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
326     [webView synchronouslyLoadTestPageNamed:@"gif-and-file-input"];
327
328     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
329     [dataInteractionSimulator runFrom: { 100, 100 } to: { 100, 300 }];
330
331     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeGIF, 0);
332     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"apple.gif", { 52, 64 });
333     EXPECT_WK_STREQ("apple.gif (image/gif)", [webView stringByEvaluatingJavaScript:@"output.textContent"]);
334 }
335
336 TEST(DataInteractionTests, ContentEditableToContentEditable)
337 {
338     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
339     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
340
341     [webView loadTestPageNamed:@"autofocus-contenteditable"];
342     [dataInteractionSimulator waitForInputSession];
343     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
344
345     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
346     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
347
348     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
349     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
350     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
351     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
352     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
353 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000
354     NSString *richTextTypeIdentifier = (NSString *)kUTTypeRTF;
355 #else
356     NSString *richTextTypeIdentifier = (NSString *)kUTTypeRTFD;
357 #endif
358     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), richTextTypeIdentifier, (NSString *)kUTTypeUTF8PlainText);
359 }
360
361 TEST(DataInteractionTests, ContentEditableToTextarea)
362 {
363     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
364     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
365
366     [webView loadTestPageNamed:@"contenteditable-and-textarea"];
367     [dataInteractionSimulator waitForInputSession];
368     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
369
370     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
371     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
372
373     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
374     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
375     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
376     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
377     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
378 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000
379     NSString *richTextTypeIdentifier = (NSString *)kUTTypeRTF;
380 #else
381     NSString *richTextTypeIdentifier = (NSString *)kUTTypeRTFD;
382 #endif
383     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), richTextTypeIdentifier, (NSString *)kUTTypeUTF8PlainText);
384 }
385
386 TEST(DataInteractionTests, ContentEditableMoveParagraphs)
387 {
388     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
389     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
390
391     [webView loadTestPageNamed:@"two-paragraph-contenteditable"];
392     [dataInteractionSimulator waitForInputSession];
393     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)];
394
395     NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
396     NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location;
397     NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location;
398
399     EXPECT_FALSE(firstParagraphOffset == NSNotFound);
400     EXPECT_FALSE(secondParagraphOffset == NSNotFound);
401     EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
402     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
403 }
404
405 TEST(DataInteractionTests, DragImageFromContentEditable)
406 {
407     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
408     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
409
410     [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-target"];
411     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 300)];
412
413     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
414 }
415
416 TEST(DataInteractionTests, TextAreaToInput)
417 {
418     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
419     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
420
421     [webView loadTestPageNamed:@"textarea-to-input"];
422     [dataInteractionSimulator waitForInputSession];
423     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
424
425     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
426     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
427     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
428 }
429
430 TEST(DataInteractionTests, SinglePlainTextWordTypeIdentifiers)
431 {
432     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
433     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
434
435     [webView loadTestPageNamed:@"textarea-to-input"];
436     [dataInteractionSimulator waitForInputSession];
437     [webView stringByEvaluatingJavaScript:@"source.value = 'pneumonoultramicroscopicsilicovolcanoconiosis'"];
438     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
439     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
440     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
441
442     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
443     NSArray *registeredTypes = [itemProvider registeredTypeIdentifiers];
444     EXPECT_EQ(1UL, registeredTypes.count);
445     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.firstObject UTF8String]);
446     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
447     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
448     EXPECT_WK_STREQ("pneumonoultramicroscopicsilicovolcanoconiosis", [webView editorValue].UTF8String);
449 }
450
451 TEST(DataInteractionTests, SinglePlainTextURLTypeIdentifiers)
452 {
453     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
454     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
455
456     [webView loadTestPageNamed:@"textarea-to-input"];
457     [dataInteractionSimulator waitForInputSession];
458     [webView stringByEvaluatingJavaScript:@"source.value = 'https://webkit.org/'"];
459     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
460     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
461     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
462
463     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
464     NSArray *registeredTypes = [itemProvider registeredTypeIdentifiers];
465     EXPECT_EQ(2UL, registeredTypes.count);
466     EXPECT_WK_STREQ([(NSString *)kUTTypeURL UTF8String], [registeredTypes.firstObject UTF8String]);
467     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.lastObject UTF8String]);
468     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"source.value"].length);
469     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
470     EXPECT_WK_STREQ("https://webkit.org/", [webView editorValue].UTF8String);
471 }
472
473 TEST(DataInteractionTests, LinkToInput)
474 {
475     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
476     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
477
478     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
479     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
480
481     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
482
483     __block bool doneLoadingURL = false;
484     UIItemProvider *sourceItemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
485     [sourceItemProvider loadObjectOfClass:[NSURL class] completionHandler:^(id object, NSError *error) {
486         NSURL *url = object;
487         EXPECT_WK_STREQ("Hello world", url._title.UTF8String ?: "");
488         doneLoadingURL = true;
489     }];
490     TestWebKitAPI::Util::run(&doneLoadingURL);
491
492     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
493     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
494     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
495     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
496     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 273, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
497     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
498 }
499
500 TEST(DataInteractionTests, BackgroundImageLinkToInput)
501 {
502     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
503     [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
504
505     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
506     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
507
508     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
509
510     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
511     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
512     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
513     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
514     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
515     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
516 }
517
518 TEST(DataInteractionTests, CanPreventStart)
519 {
520     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
521     [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
522
523     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
524     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
525
526     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
527     EXPECT_FALSE([webView editorContainsImageElement]);
528
529     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
530     EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
531     EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
532     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
533 }
534
535 TEST(DataInteractionTests, CanPreventOperation)
536 {
537     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
538     [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
539
540     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
541     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
542
543     EXPECT_FALSE([webView editorContainsImageElement]);
544
545     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
546     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
547     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
548     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
549 }
550
551 TEST(DataInteractionTests, EnterAndLeaveEvents)
552 {
553     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
554     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
555
556     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
557     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
558
559     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
560
561     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
562     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
563     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
564     EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
565     EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
566     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
567 }
568
569 TEST(DataInteractionTests, CanStartDragOnDivWithDraggableAttribute)
570 {
571     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
572     [webView synchronouslyLoadTestPageNamed:@"custom-draggable-div"];
573
574     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
575     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 250)];
576
577     EXPECT_GT([dataInteractionSimulator sourceItemProviders].count, 0UL);
578     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
579     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
580     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!destination.querySelector('#item')"]);
581     EXPECT_WK_STREQ(@"PASS", [webView stringByEvaluatingJavaScript:@"item.textContent"]);
582 }
583
584 TEST(DataInteractionTests, ExternalSourcePlainTextToIFrame)
585 {
586     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
587     [webView synchronouslyLoadTestPageNamed:@"contenteditable-in-iframe"];
588
589     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
590     [itemProvider registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
591
592     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
593     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
594     [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(160, 250)];
595
596     auto containerLeft = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().left"].floatValue;
597     auto containerTop = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().top"].floatValue;
598     auto containerWidth = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().width"].floatValue;
599     auto containerHeight = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().height"].floatValue;
600     checkDragCaretRectIsContainedInRect([simulator lastKnownDragCaretRect], CGRectMake(containerLeft, containerTop, containerWidth, containerHeight));
601 }
602
603 TEST(DataInteractionTests, ExternalSourceInlineTextToFileInput)
604 {
605     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
606     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
607
608     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
609     [simulatedItemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleInline];
610     [simulatedItemProvider registerObject:@"This item provider requested inline presentation style." visibility:NSItemProviderRepresentationVisibilityAll];
611
612     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
613     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
614     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
615
616     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
617 }
618
619 TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
620 {
621     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
622     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
623
624     auto simulatedJSONItemProvider = adoptNS([[UIItemProvider alloc] init]);
625     NSData *jsonData = [@"{ \"foo\": \"bar\",  \"bar\": \"baz\" }" dataUsingEncoding:NSUTF8StringEncoding];
626     [simulatedJSONItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJSON withData:jsonData];
627
628     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
629     [dataInteractionSimulator setExternalItemProviders:@[ simulatedJSONItemProvider.get() ]];
630     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
631
632     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
633 }
634
635 TEST(DataInteractionTests, ExternalSourceImageToFileInput)
636 {
637     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
638     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
639
640     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
641     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
642     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
643
644     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
645     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
646     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
647
648     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
649     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
650 }
651
652 TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
653 {
654     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
655     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
656
657     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
658     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
659     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
660
661     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
662     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
663     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
664     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
665
666     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
667     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
668 }
669
670 TEST(DataInteractionTests, ExternalSourceMoveOperationNotAllowed)
671 {
672     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
673     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
674     [webView stringByEvaluatingJavaScript:@"upload.dropEffect = 'move'"];
675
676     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
677     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
678     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
679
680     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
681     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
682     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
683     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
684
685     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
686 }
687
688 TEST(DataInteractionTests, ExternalSourceZIPArchiveAndURLToSingleFileInput)
689 {
690     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
691     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
692
693     auto archiveProvider = adoptNS([[UIItemProvider alloc] init]);
694     [archiveProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
695
696     auto urlProvider = adoptNS([[UIItemProvider alloc] init]);
697     [urlProvider registerObject:[NSURL URLWithString:@"https://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
698
699     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
700     [dataInteractionSimulator setExternalItemProviders:@[ archiveProvider.get(), urlProvider.get() ]];
701     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
702
703     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
704     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
705 }
706
707 TEST(DataInteractionTests, ExternalSourceZIPArchiveToUploadArea)
708 {
709     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
710     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
711
712     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
713     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
714
715     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
716     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
717     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
718
719     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
720     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
721 }
722
723 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
724 {
725     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
726     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
727
728     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
729     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
730     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
731
732     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
733     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
734     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
735
736     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
737     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
738     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
739
740     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
741     EXPECT_WK_STREQ("", outputValue.UTF8String);
742 }
743
744 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
745 {
746     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
747     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
748     [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
749
750     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
751     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
752     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
753
754     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
755     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
756     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
757
758     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
759     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
760     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
761
762     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
763     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
764 }
765
766 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
767 {
768     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
769     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
770
771     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
772     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
773     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
774
775     auto firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
776     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
777     [firstSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
778
779     auto secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
780     NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
781     [secondSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData];
782
783     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
784     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
785     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
786     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
787
788     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
789     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
790 }
791
792 TEST(DataInteractionTests, ExternalSourceHTMLToContentEditable)
793 {
794     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
795     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
796     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
797
798     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
799     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
800     NSData *htmlData = [@"<h1>This is a test</h1>" dataUsingEncoding:NSUTF8StringEncoding];
801     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
802     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
803     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
804
805     NSString *textContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
806     EXPECT_WK_STREQ("This is a test", textContent.UTF8String);
807     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('h1')"].boolValue);
808 }
809
810 TEST(DataInteractionTests, ExternalSourceBoldSystemAttributedStringToContentEditable)
811 {
812     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
813     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
814     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
815
816     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
817     NSDictionary *textAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:20] };
818     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
819     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
820     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
821     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
822
823     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
824 }
825
826 TEST(DataInteractionTests, ExternalSourceColoredAttributedStringToContentEditable)
827 {
828     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
829     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
830     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
831
832     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
833     NSDictionary *textAttributes = @{ NSForegroundColorAttributeName: [UIColor redColor] };
834     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
835     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
836     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
837     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
838
839     EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('p')).color"]);
840     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
841 }
842
843 TEST(DataInteractionTests, ExternalSourceMultipleURLsToContentEditable)
844 {
845     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
846     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
847     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
848
849     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
850     auto firstItem = adoptNS([[UIItemProvider alloc] init]);
851     [firstItem registerObject:[NSURL URLWithString:@"https://www.apple.com/iphone/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
852     auto secondItem = adoptNS([[UIItemProvider alloc] init]);
853     [secondItem registerObject:[NSURL URLWithString:@"https://www.apple.com/mac/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
854     auto thirdItem = adoptNS([[UIItemProvider alloc] init]);
855     [thirdItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
856     [dataInteractionSimulator setExternalItemProviders:@[ firstItem.get(), secondItem.get(), thirdItem.get() ]];
857     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
858
859     NSArray *droppedURLs = [webView objectByEvaluatingJavaScript:@"Array.from(editor.querySelectorAll('a')).map(a => a.href)"];
860     EXPECT_EQ(3UL, droppedURLs.count);
861     EXPECT_WK_STREQ("https://www.apple.com/iphone/", droppedURLs[0]);
862     EXPECT_WK_STREQ("https://www.apple.com/mac/", droppedURLs[1]);
863     EXPECT_WK_STREQ("https://webkit.org/", droppedURLs[2]);
864
865     NSArray *linksSeparatedByLine = [[webView objectByEvaluatingJavaScript:@"editor.innerText"] componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
866     EXPECT_EQ(3UL, linksSeparatedByLine.count);
867     EXPECT_WK_STREQ("https://www.apple.com/iphone/", linksSeparatedByLine[0]);
868     EXPECT_WK_STREQ("https://www.apple.com/mac/", linksSeparatedByLine[1]);
869     EXPECT_WK_STREQ("https://webkit.org/", linksSeparatedByLine[2]);
870 }
871
872 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
873 {
874     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
875     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
876     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
877
878     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
879
880     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
881     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
882     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
883     // than an image.
884     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
885     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
886     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
887     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
888
889     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
890     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
891     EXPECT_FALSE([webView editorContainsImageElement]);
892     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
893
894     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
895     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
896     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
897     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
898     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
899
900     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
901     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
902     EXPECT_TRUE([webView editorContainsImageElement]);
903 }
904
905 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
906 {
907     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
908     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
909
910     NSString *textPayload = @"Ceci n'est pas une string";
911     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
912     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
913     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
914     {
915         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
916         return [NSProgress discreteProgressWithTotalUnitCount:100];
917     }];
918     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
919     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
920     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
921     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
922 }
923
924 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
925 {
926     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
927     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
928
929     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
930     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
931     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
932     {
933         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
934         return [NSProgress discreteProgressWithTotalUnitCount:100];
935     }];
936     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
937     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
938     EXPECT_TRUE([webView editorContainsImageElement]);
939     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
940 }
941
942 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
943 {
944     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
945     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
946     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
947
948     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
949     titledURL._title = @"Apple";
950     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
951     [simulatedItemProvider registerObject:titledURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
952
953     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
954     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
955     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
956
957     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
958     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
959 }
960
961 TEST(DataInteractionTests, ExternalSourceFileURL)
962 {
963     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
964     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
965     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
966
967     NSURL *URL = [NSURL URLWithString:@"file:///some/file/that/is/not/real"];
968     UIItemProvider *simulatedItemProvider = [UIItemProvider itemProviderWithURL:URL title:@""];
969
970     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
971     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider ]];
972     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
973
974     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"!!editor.querySelector('a')"] boolValue]);
975     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
976 }
977
978 TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
979 {
980     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
981     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
982
983     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
984     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
985     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
986
987     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
988     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
989     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
990
991     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
992     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
993     {
994         EXPECT_EQ(2UL, session.items.count);
995         UIDragItem *firstItem = session.items[0];
996         UIDragItem *secondItem = session.items[1];
997         EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
998         EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
999         return @[ secondItem ];
1000     }];
1001     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
1002     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
1003
1004     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
1005     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
1006 }
1007
1008 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
1009
1010 static RetainPtr<TestWKWebView> setUpTestWebViewForDataTransferItems()
1011 {
1012     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1013     [webView synchronouslyLoadTestPageNamed:@"DataTransferItem-getAsEntry"];
1014
1015     auto preferences = (WKPreferencesRef)[[webView configuration] preferences];
1016     WKPreferencesSetDataTransferItemsEnabled(preferences, true);
1017     WKPreferencesSetDirectoryUploadEnabled(preferences, true);
1018
1019     return webView;
1020 }
1021
1022 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetFolderAsEntry)
1023 {
1024     // The expected output is sorted by alphabetical order here for consistent behavior across different test environments.
1025     // See DataTransferItem-getAsEntry.html for more details.
1026     NSArray<NSString *> *expectedOutput = @[
1027         @"Found data transfer item (kind: 'file', type: '')",
1028         @"DIR: /somedirectory",
1029         @"DIR: /somedirectory/subdirectory1",
1030         @"DIR: /somedirectory/subdirectory2",
1031         [NSString stringWithFormat:@"FILE: /somedirectory/archive.zip ('application/zip', %tu bytes)", testZIPArchive().length],
1032         [NSString stringWithFormat:@"FILE: /somedirectory/icon.png ('image/png', %tu bytes)", testIconImageData().length],
1033         @"FILE: /somedirectory/subdirectory1/text-file-1.txt ('text/plain', 43 bytes)",
1034         @"FILE: /somedirectory/subdirectory2/text-file-2.txt ('text/plain', 44 bytes)"
1035     ];
1036
1037     auto webView = setUpTestWebViewForDataTransferItems();
1038     __block bool done = false;
1039     [webView performAfterReceivingMessage:@"dropped" action:^() {
1040         done = true;
1041     }];
1042
1043     runTestWithTemporaryFolder(^(NSURL *folderURL) {
1044         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
1045         [itemProvider setSuggestedName:@"somedirectory"];
1046         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeFolder fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFolderURL = retainPtr(folderURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
1047             completionHandler(capturedFolderURL.get(), NO, nil);
1048             return nil;
1049         }];
1050
1051         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1052         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
1053         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
1054     });
1055
1056     TestWebKitAPI::Util::run(&done);
1057     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
1058 }
1059
1060 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetPlainTextFileAsEntry)
1061 {
1062     NSArray<NSString *> *expectedOutput = @[
1063         @"Found data transfer item (kind: 'file', type: 'text/plain')",
1064         @"FILE: /foo.txt ('text/plain', 28 bytes)"
1065     ];
1066
1067     auto webView = setUpTestWebViewForDataTransferItems();
1068     __block bool done = false;
1069     [webView performAfterReceivingMessage:@"dropped" action:^() {
1070         done = true;
1071     }];
1072
1073     runTestWithTemporaryTextFile(^(NSURL *fileURL) {
1074         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
1075         [itemProvider setSuggestedName:@"foo"];
1076         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFileURL = retainPtr(fileURL)](FileLoadCompletionBlock completionHandler) -> NSProgress * {
1077             completionHandler(capturedFileURL.get(), NO, nil);
1078             return nil;
1079         }];
1080
1081         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1082         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
1083         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
1084     });
1085
1086     TestWebKitAPI::Util::run(&done);
1087     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
1088 }
1089
1090 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
1091
1092 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
1093 {
1094     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1095     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
1096     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1097
1098     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1099     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1100     {
1101         NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
1102         for (UIDragItem *item in session.items) {
1103             if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
1104                 [allowedItems addObject:item];
1105         }
1106         EXPECT_EQ(1UL, allowedItems.count);
1107         return allowedItems;
1108     }];
1109
1110     auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
1111     [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1112     auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
1113     [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1114     [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
1115     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1116
1117     EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1118 }
1119
1120 TEST(DataInteractionTests, OverrideDataInteractionOperation)
1121 {
1122     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1123     [webView synchronouslyLoadTestPageNamed:@"simple"];
1124
1125     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1126     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
1127
1128     __block bool finishedLoadingData = false;
1129     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1130     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1131     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
1132     {
1133         EXPECT_EQ(0U, operation);
1134         return UIDropOperationCopy;
1135     }];
1136     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
1137         EXPECT_FALSE(handled);
1138         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
1139             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
1140             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
1141             EXPECT_FALSE(!!error);
1142             finishedLoadingData = true;
1143         }];
1144     }];
1145     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1146     TestWebKitAPI::Util::run(&finishedLoadingData);
1147 }
1148
1149 TEST(DataInteractionTests, InjectedBundleOverridePerformTwoStepDrop)
1150 {
1151     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1152     [configuration.processPool _setObject:@YES forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1153
1154     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1155     [webView loadTestPageNamed:@"autofocus-contenteditable"];
1156     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1157
1158     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1159     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1160     {
1161         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1162         return [NSProgress discreteProgressWithTotalUnitCount:100];
1163     }];
1164
1165     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1166     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1167     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1168
1169     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"editor.textContent"].length);
1170 }
1171
1172 TEST(DataInteractionTests, InjectedBundleAllowPerformTwoStepDrop)
1173 {
1174     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1175     [configuration.processPool _setObject:@NO forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1176
1177     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1178     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
1179     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1180
1181     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1182     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1183     {
1184         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1185         return [NSProgress discreteProgressWithTotalUnitCount:100];
1186     }];
1187
1188     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1189     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1190     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1191
1192     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
1193 }
1194
1195 TEST(DataInteractionTests, InjectedBundleImageElementData)
1196 {
1197     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1198     [configuration _setAttachmentElementEnabled:YES];
1199     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1200     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
1201
1202     __block RetainPtr<NSString> injectedString;
1203     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1204     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1205     {
1206         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1207         return @[ itemProvider ];
1208     }];
1209
1210     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
1211
1212     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1213 }
1214
1215 TEST(DataInteractionTests, InjectedBundleAttachmentElementData)
1216 {
1217     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1218     [configuration _setAttachmentElementEnabled:YES];
1219     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1220     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
1221
1222     __block RetainPtr<NSString> injectedString;
1223     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1224     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1225     {
1226         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1227         return @[ itemProvider ];
1228     }];
1229
1230     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
1231
1232     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1233     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"getSelection().isCollapsed"].boolValue);
1234 }
1235
1236 TEST(DataInteractionTests, LargeImageToTargetDiv)
1237 {
1238     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1239     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
1240
1241     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
1242     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
1243
1244     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1245     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
1246     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1247     checkFirstTypeIsPresentAndSecondTypeIsMissing(dataInteractionSimulator.get(), kUTTypePNG, kUTTypeFileURL);
1248     checkEstimatedSize(dataInteractionSimulator.get(), { 2000, 2000 });
1249 }
1250
1251 TEST(DataInteractionTests, LinkWithEmptyHREF)
1252 {
1253     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1254     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
1255     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
1256
1257     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1258     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1259
1260     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1261     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
1262 }
1263
1264 TEST(DataInteractionTests, CancelledLiftDoesNotCauseSubsequentDragsToFail)
1265 {
1266     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1267     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1268
1269     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1270     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *, NSArray *, NSDictionary *)
1271     {
1272         return @[ ];
1273     }];
1274     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1275     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1276     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1277     NSString *outputText = [webView stringByEvaluatingJavaScript:@"output.textContent"];
1278     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1279
1280     [webView stringByEvaluatingJavaScript:@"output.innerHTML = ''"];
1281     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *)
1282     {
1283         return @[ itemProvider ];
1284     }];
1285     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1286     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1287     [webView stringByEvaluatingJavaScript:@"output.textContent"];
1288     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1289 }
1290
1291 static void testDragAndDropOntoTargetElements(TestWKWebView *webView)
1292 {
1293     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView]);
1294     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 250)];
1295     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target1).backgroundColor"]);
1296     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target1.textContent"]);
1297
1298     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 50)];
1299     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target2).backgroundColor"]);
1300     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target2.textContent"]);
1301
1302     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 250)];
1303     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target3).backgroundColor"]);
1304     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target3.textContent"]);
1305 }
1306
1307 TEST(DataInteractionTests, DragEventClientCoordinatesBasic)
1308 {
1309     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1310     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1311
1312     testDragAndDropOntoTargetElements(webView.get());
1313 }
1314
1315 TEST(DataInteractionTests, DragEventClientCoordinatesWithScrollOffset)
1316 {
1317     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1318     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1319     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1320     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1321     [webView waitForNextPresentationUpdate];
1322
1323     testDragAndDropOntoTargetElements(webView.get());
1324 }
1325
1326 TEST(DataInteractionTests, DragEventPageCoordinatesBasic)
1327 {
1328     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1329     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1330     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1331
1332     testDragAndDropOntoTargetElements(webView.get());
1333 }
1334
1335 TEST(DataInteractionTests, DragEventPageCoordinatesWithScrollOffset)
1336 {
1337     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1338     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1339     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1340     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1341     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1342     [webView waitForNextPresentationUpdate];
1343
1344     testDragAndDropOntoTargetElements(webView.get());
1345 }
1346
1347 TEST(DataInteractionTests, DoNotCrashWhenSelectionIsClearedInDragStart)
1348 {
1349     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1350     [webView synchronouslyLoadTestPageNamed:@"dragstart-clear-selection"];
1351
1352     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1353     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1354
1355     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"paragraph.textContent"]);
1356 }
1357
1358 TEST(DataInteractionTests, CustomActionSheetPopover)
1359 {
1360     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1361     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1362
1363     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1364     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
1365
1366     __block BOOL didInvokeCustomActionSheet = NO;
1367     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
1368     {
1369         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
1370         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
1371         didInvokeCustomActionSheet = YES;
1372         return YES;
1373     }];
1374     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1375     EXPECT_TRUE(didInvokeCustomActionSheet);
1376     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1377 }
1378
1379 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
1380 {
1381     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
1382     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
1383
1384     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
1385     [webView synchronouslyLoadTestPageNamed:@"simple"];
1386     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
1387
1388     // The test passes if we can prepare for data interaction without timing out.
1389     auto dragSession = adoptNS([[MockDragSession alloc] init]);
1390     [(id <UIDragInteractionDelegate_ForWebKitOnly>)[webView dragInteractionDelegate] _dragInteraction:[webView dragInteraction] prepareForSession:dragSession.get() completion:^() { }];
1391 }
1392
1393 TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
1394 {
1395     static NSString *fastString = @"This data loads quickly";
1396     static NSString *slowString = @"This data loads slowly";
1397
1398     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
1399     auto fastItem = adoptNS([[UIItemProvider alloc] init]);
1400     [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1401     {
1402         completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
1403         return nil;
1404     }];
1405
1406     auto slowItem = adoptNS([[UIItemProvider alloc] init]);
1407     [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1408     {
1409         sleep(2_s);
1410         completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
1411         return nil;
1412     }];
1413
1414     __block bool hasRunFirstCompletionBlock = false;
1415     pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
1416     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1417         EXPECT_EQ(2UL, urls.count);
1418         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1419         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1420         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1421         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1422         hasRunFirstCompletionBlock = true;
1423     } synchronousTimeout:600];
1424     EXPECT_TRUE(hasRunFirstCompletionBlock);
1425
1426     __block bool hasRunSecondCompletionBlock = false;
1427     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1428         EXPECT_EQ(2UL, urls.count);
1429         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1430         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1431         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1432         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1433         hasRunSecondCompletionBlock = true;
1434     } synchronousTimeout:0];
1435     EXPECT_FALSE(hasRunSecondCompletionBlock);
1436     TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
1437 }
1438
1439 TEST(DataInteractionTests, DoNotCrashWhenSelectionMovesOffscreenAfterDragStart)
1440 {
1441     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1442     [webView synchronouslyLoadTestPageNamed:@"dragstart-change-selection-offscreen"];
1443
1444     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1445     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1446
1447     EXPECT_WK_STREQ("FAR OFFSCREEN", [webView stringByEvaluatingJavaScript:@"getSelection().getRangeAt(0).toString()"]);
1448 }
1449
1450 TEST(DataInteractionTests, AdditionalItemsCanBePreventedOnDragStart)
1451 {
1452     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1453     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1454     [webView stringByEvaluatingJavaScript:@"link.addEventListener('dragstart', e => e.preventDefault())"];
1455     [webView stringByEvaluatingJavaScript:@"image.addEventListener('dragstart', e => e.preventDefault())"];
1456
1457     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1458     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1459         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1460         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1461     }];
1462     EXPECT_WK_STREQ("ABCD", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1463 }
1464
1465 TEST(DataInteractionTests, AdditionalLinkAndImageIntoContentEditable)
1466 {
1467     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1468     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1469
1470     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1471     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1472         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1473         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1474     }];
1475     EXPECT_WK_STREQ("ABCDA link", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1476     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"]);
1477     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
1478 }
1479
1480 TEST(DataInteractionTests, DragLiftPreviewDataTransferSetDragImage)
1481 {
1482     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1483     [webView synchronouslyLoadTestPageNamed:@"DataTransfer-setDragImage"];
1484     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1485
1486     // Use DataTransfer.setDragImage to specify an existing image element in the DOM.
1487     [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 50)];
1488     checkCGRectIsEqualToCGRectWithLogging({{100, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1489
1490     // Use DataTransfer.setDragImage to specify an existing image element in the DOM, with x and y offsets.
1491     [simulator runFrom:CGPointMake(10, 150) to:CGPointMake(250, 150)];
1492     checkCGRectIsEqualToCGRectWithLogging({{-90, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1493
1494     // Use DataTransfer.setDragImage to specify a newly created Image, disconnected from the DOM.
1495     [simulator runFrom:CGPointMake(100, 250) to:CGPointMake(250, 250)];
1496     checkCGRectIsEqualToCGRectWithLogging({{100, 250}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1497
1498     // Don't use DataTransfer.setDragImage and fall back to snapshotting the dragged element.
1499     [simulator runFrom:CGPointMake(50, 350) to:CGPointMake(250, 350)];
1500     checkCGRectIsEqualToCGRectWithLogging({{0, 300}, {300, 100}}, [simulator liftPreviews][0].view.frame);
1501
1502     // Perform a normal drag on an image.
1503     [simulator runFrom:CGPointMake(50, 450) to:CGPointMake(250, 450)];
1504     checkCGRectIsEqualToCGRectWithLogging({{0, 400}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1505 }
1506
1507 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
1508
1509 static NSData *testIconImageData()
1510 {
1511     return [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png" inDirectory:@"TestWebKitAPI.resources"]];
1512 }
1513
1514 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingImageAndMarkup)
1515 {
1516     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1517     WKPreferencesSetCustomPasteboardDataEnabled((WKPreferencesRef)[webView configuration].preferences, true);
1518     [webView synchronouslyLoadTestPageNamed:@"DataTransfer"];
1519
1520     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1521     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
1522     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypePNG withData:testIconImageData()];
1523     NSString *markupString = @"<script>bar()</script><strong onmousedown=javascript:void(0)>HELLO WORLD</strong>";
1524     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[markupString dataUsingEncoding:NSUTF8StringEncoding]];
1525     [itemProvider setSuggestedName:@"icon"];
1526     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
1527     [simulator runFrom:CGPointZero to:CGPointMake(50, 100)];
1528
1529     EXPECT_WK_STREQ("Files, text/html", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
1530     EXPECT_WK_STREQ("(STRING, text/html), (FILE, image/png)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
1531     EXPECT_WK_STREQ("('icon.png', image/png)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
1532     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
1533     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
1534     EXPECT_WK_STREQ("HELLO WORLD", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
1535     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"rawHTMLData.textContent"] containsString:@"script"]);
1536 }
1537
1538 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingPlainText)
1539 {
1540     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1541     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1542     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1543
1544     [webView stringByEvaluatingJavaScript:@"select(plain)"];
1545     [simulator runFrom:CGPointMake(50, 75) to:CGPointMake(50, 375)];
1546     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1547         @"dragover": @{ @"text/plain" : @"" },
1548         @"drop": @{ @"text/plain" : @"Plain text" }
1549     });
1550 }
1551
1552 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingCustomData)
1553 {
1554     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1555     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1556     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1557
1558     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1559     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1560     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1561     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1562         @"dragover" : @{
1563             @"text/plain" : @"",
1564             @"foo/plain" : @"",
1565             @"text/html" : @"",
1566             @"bar/html" : @"",
1567             @"text/uri-list" : @"",
1568             @"baz/uri-list" : @""
1569         },
1570         @"drop" : @{
1571             @"text/plain" : @"ben bitdiddle",
1572             @"foo/plain" : @"eva lu ator",
1573             @"text/html" : @"<b>bold text</b>",
1574             @"bar/html" : @"<i>italic text</i>",
1575             @"text/uri-list" : @"https://www.apple.com",
1576             @"baz/uri-list" : @"https://www.webkit.org"
1577         }
1578     });
1579 }
1580
1581 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingURL)
1582 {
1583     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1584     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1585     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1586
1587     [webView stringByEvaluatingJavaScript:@"rich.innerHTML = '<a href=\"https://www.apple.com/\">This is a link.</a>'"];
1588     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1589     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1590         @"dragover": @{
1591             @"text/uri-list" : @"",
1592             @"text/plain" : @""
1593         },
1594         @"drop": @{
1595             @"text/uri-list" : @"https://www.apple.com/",
1596             @"text/plain" : @"https://www.apple.com/"
1597         }
1598     });
1599 }
1600
1601 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingImageWithFileURL)
1602 {
1603     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1604     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1605     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1606
1607     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
1608     NSURL *iconURL = [[NSBundle mainBundle] URLForResource:@"icon" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"];
1609     [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypePNG fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[protectedIconURL = retainPtr(iconURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
1610         completionHandler(protectedIconURL.get(), NO, nil);
1611         return nil;
1612     }];
1613     [itemProvider registerObject:iconURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1614     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
1615
1616     [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
1617
1618     // File URLs should never be exposed directly to web content, so DataTransfer.getData should return an empty string here.
1619     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1620         @"dragover": @{ @"Files": @"", @"text/uri-list": @"" },
1621         @"drop": @{ @"Files": @"", @"text/uri-list": @"" }
1622     });
1623 }
1624
1625 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingImageWithHTTPURL)
1626 {
1627     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1628     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1629     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1630
1631     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
1632     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
1633     {
1634         completionHandler(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
1635         return nil;
1636     }];
1637     [itemProvider registerObject:[NSURL URLWithString:@"http://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1638     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
1639
1640     [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
1641     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1642         @"dragover": @{ @"Files": @"", @"text/uri-list": @"" },
1643         @"drop": @{ @"Files": @"", @"text/uri-list": @"http://webkit.org/" }
1644     });
1645 }
1646
1647 TEST(DataInteractionTests, DataTransferGetDataWhenDroppingRespectsPresentationStyle)
1648 {
1649     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1650     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1651     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1652
1653     runTestWithTemporaryTextFile(^(NSURL *fileURL) {
1654         auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
1655         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[protectedFileURL = retainPtr(fileURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
1656             completionHandler(protectedFileURL.get(), NO, nil);
1657             return nil;
1658         }];
1659         [simulator setExternalItemProviders:@[ itemProvider.get() ]];
1660
1661         [itemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
1662         [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
1663         checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1664             @"dragover": @{ @"Files" : @"" },
1665             @"drop": @{ @"Files" : @"" }
1666         });
1667
1668         [itemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleInline];
1669         [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
1670         checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1671             @"dragover": @{ @"text/plain" : @"" },
1672             @"drop": @{ @"text/plain" : @"This is a tiny blob of text." }
1673         });
1674     });
1675 }
1676
1677 TEST(DataInteractionTests, DataTransferSetDataCannotWritePlatformTypes)
1678 {
1679     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1680     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1681     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1682
1683     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1684     [webView stringByEvaluatingJavaScript:@"customData = { 'text/plain' : 'foo', 'com.adobe.pdf' : 'try and decode me!' }"];
1685     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1686
1687     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1688     checkFirstTypeIsPresentAndSecondTypeIsMissing(simulator.get(), kUTTypeUTF8PlainText, kUTTypePDF);
1689     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1690         @"dragover": @{
1691             @"text/plain": @"",
1692             @"com.adobe.pdf": @""
1693         },
1694         @"drop": @{
1695             @"text/plain": @"foo",
1696             @"com.adobe.pdf": @"try and decode me!"
1697         }
1698     });
1699 }
1700
1701 TEST(DataInteractionTests, DataTransferGetDataCannotReadPrivateArbitraryTypes)
1702 {
1703     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1704     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1705     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1706
1707     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
1708     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeMP3 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
1709     {
1710         completionHandler([@"this is a test" dataUsingEncoding:NSUTF8StringEncoding], nil);
1711         return nil;
1712     }];
1713     [itemProvider registerDataRepresentationForTypeIdentifier:@"org.WebKit.TestWebKitAPI.custom-pasteboard-type" visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
1714     {
1715         completionHandler([@"this is another test" dataUsingEncoding:NSUTF8StringEncoding], nil);
1716         return nil;
1717     }];
1718     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
1719     [itemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleInline];
1720     [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
1721     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1722         @"dragover": @{ },
1723         @"drop": @{ }
1724     });
1725 }
1726
1727 TEST(DataInteractionTests, DataTransferSetDataValidURL)
1728 {
1729     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1730     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1731     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1732
1733     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1734     [webView stringByEvaluatingJavaScript:@"customData = { 'url' : 'https://webkit.org/b/123' }"];
1735     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1736
1737     __block bool done = false;
1738     [simulator.get() setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1739     {
1740         EXPECT_EQ(1UL, session.items.count);
1741         auto *item = session.items[0].itemProvider;
1742         EXPECT_TRUE([item.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL]);
1743         EXPECT_TRUE([item canLoadObjectOfClass: [NSURL class]]);
1744         [item loadObjectOfClass:[NSURL class] completionHandler:^(id<NSItemProviderReading> url, NSError *error) {
1745             EXPECT_TRUE([url isKindOfClass: [NSURL class]]);
1746             EXPECT_WK_STREQ([(NSURL *)url absoluteString], @"https://webkit.org/b/123");
1747             done = true;
1748         }];
1749         return session.items;
1750     }];
1751     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1752
1753     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1754         @"dragover": @{
1755             @"text/uri-list": @"",
1756         },
1757         @"drop": @{
1758             @"text/uri-list": @"https://webkit.org/b/123",
1759         }
1760     });
1761     TestWebKitAPI::Util::run(&done);
1762 }
1763
1764 TEST(DataInteractionTests, DataTransferSetDataUnescapedURL)
1765 {
1766     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1767     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1768     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1769
1770     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1771     [webView stringByEvaluatingJavaScript:@"customData = { 'url' : 'http://webkit.org/b/\u4F60\u597D;?x=8 + 6' }"];
1772     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1773
1774     __block bool done = false;
1775     [simulator.get() setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1776     {
1777         EXPECT_EQ(1UL, session.items.count);
1778         auto *item = session.items[0].itemProvider;
1779         EXPECT_TRUE([item.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL]);
1780         EXPECT_TRUE([item canLoadObjectOfClass: [NSURL class]]);
1781         [item loadObjectOfClass:[NSURL class] completionHandler:^(id<NSItemProviderReading> url, NSError *error) {
1782             EXPECT_TRUE([url isKindOfClass: [NSURL class]]);
1783             EXPECT_WK_STREQ([(NSURL *)url absoluteString], @"http://webkit.org/b/%E4%BD%A0%E5%A5%BD;?x=8%20+%206");
1784             done = true;
1785         }];
1786         return session.items;
1787     }];
1788     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1789
1790     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1791         @"dragover": @{
1792             @"text/uri-list": @"",
1793         },
1794         @"drop": @{
1795             @"text/uri-list": @"http://webkit.org/b/\u4F60\u597D;?x=8 + 6",
1796         }
1797     });
1798     TestWebKitAPI::Util::run(&done);
1799 }
1800
1801 TEST(DataInteractionTests, DataTransferSetDataInvalidURL)
1802 {
1803     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1804     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1805     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1806
1807     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1808     [webView stringByEvaluatingJavaScript:@"customData = { 'url' : 'some random string' }"];
1809     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1810
1811     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1812     NSArray *registeredTypes = [simulator.get().sourceItemProviders.firstObject registeredTypeIdentifiers];
1813     EXPECT_FALSE([registeredTypes containsObject:(NSString *)kUTTypeURL]);
1814     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1815         @"dragover": @{
1816             @"text/uri-list": @"",
1817         },
1818         @"drop": @{
1819             @"text/uri-list": @"some random string",
1820         }
1821     });
1822 }
1823
1824 TEST(DataInteractionTests, DataTransferSanitizeHTML)
1825 {
1826     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1827     [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
1828     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1829
1830     [webView stringByEvaluatingJavaScript:@"select(rich)"];
1831     [webView stringByEvaluatingJavaScript:@"customData = { 'text/html' : '<meta content=\"secret\">"
1832         "<b onmouseover=\"dangerousCode()\">hello</b><!-- secret-->, world<script>dangerousCode()</script>' }"];
1833     [webView stringByEvaluatingJavaScript:@"writeCustomData = true"];
1834
1835     __block bool done = false;
1836     [simulator.get() setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1837     {
1838         EXPECT_EQ(1UL, session.items.count);
1839         auto *item = session.items[0].itemProvider;
1840         EXPECT_TRUE([item.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeHTML]);
1841         [item loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
1842             NSString *markup = [[[NSString alloc] initWithData:(NSData *)data encoding:NSUTF8StringEncoding] autorelease];
1843             EXPECT_TRUE([markup containsString:@"hello"]);
1844             EXPECT_TRUE([markup containsString:@", world"]);
1845             EXPECT_FALSE([markup containsString:@"secret"]);
1846             EXPECT_FALSE([markup containsString:@"dangerousCode"]);
1847             done = true;
1848         }];
1849         return session.items;
1850     }];
1851     [simulator runFrom:CGPointMake(50, 225) to:CGPointMake(50, 375)];
1852
1853     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
1854         @"dragover": @{
1855             @"text/html": @"",
1856         },
1857         @"drop": @{
1858             @"text/html": @"<meta content=\"secret\"><b onmouseover=\"dangerousCode()\">hello</b><!-- secret-->, world<script>dangerousCode()</script>",
1859         }
1860     });
1861     TestWebKitAPI::Util::run(&done);
1862 }
1863
1864 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
1865
1866 } // namespace TestWebKitAPI
1867
1868 #endif // ENABLE(DATA_INTERACTION)