[iOS DnD] Support DataTransfer.getData and DataTransfer.setData when dragging or...
[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
44 typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
45 typedef void (^DataLoadCompletionBlock)(NSData *, NSError *);
46 typedef void (^UIItemProviderDataLoadCompletionBlock)(NSData *, NSError *);
47
48 #if !USE(APPLE_INTERNAL_SDK)
49
50 @interface UIItemProviderRepresentationOptions : NSObject
51 @end
52
53 #endif
54
55 @interface UIItemProvider()
56 + (UIItemProvider *)itemProviderWithURL:(NSURL *)url title:(NSString *)title;
57 - (void) registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier options:(UIItemProviderRepresentationOptions*)options loadHandler:(NSProgress * (^)(void (^UIItemProviderDataLoadCompletionBlock)(NSData *item, NSError *error))) loadHandler;
58 @end
59
60 static NSString *InjectedBundlePasteboardDataType = @"org.webkit.data";
61
62 static UIImage *testIconImage()
63 {
64     return [UIImage imageNamed:@"TestWebKitAPI.resources/icon.png"];
65 }
66
67 static NSData *testZIPArchive()
68 {
69     NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"];
70     return [NSData dataWithContentsOfURL:zipFileURL];
71 }
72
73 @implementation UIItemProvider (DataInteractionTests)
74
75 - (void)registerDataRepresentationForTypeIdentifier:(NSString *)typeIdentifier withData:(NSData *)data
76 {
77     RetainPtr<NSData> retainedData = data;
78     [self registerDataRepresentationForTypeIdentifier:typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler: [retainedData] (DataLoadCompletionBlock block) -> NSProgress * {
79         block(retainedData.get(), nil);
80         return [NSProgress discreteProgressWithTotalUnitCount:100];
81     }];
82 }
83
84 @end
85
86 @implementation TestWKWebView (DataInteractionTests)
87
88 - (BOOL)editorContainsImageElement
89 {
90     return [self stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"].boolValue;
91 }
92
93 - (NSString *)editorValue
94 {
95     return [self stringByEvaluatingJavaScript:@"editor.value"];
96 }
97
98 @end
99
100 static NSValue *makeCGRectValue(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
101 {
102     return [NSValue valueWithCGRect:CGRectMake(x, y, width, height)];
103 }
104
105 static void checkCGRectIsEqualToCGRectWithLogging(CGRect expected, CGRect observed)
106 {
107     BOOL isEqual = CGRectEqualToRect(expected, observed);
108     EXPECT_TRUE(isEqual);
109     if (!isEqual)
110         NSLog(@"Expected: %@ but observed: %@", NSStringFromCGRect(expected), NSStringFromCGRect(observed));
111 }
112
113 static void checkSelectionRectsWithLogging(NSArray *expected, NSArray *observed)
114 {
115     if (![expected isEqualToArray:observed])
116         NSLog(@"Expected selection rects: %@ but observed: %@", expected, observed);
117     EXPECT_TRUE([expected isEqualToArray:observed]);
118 }
119
120 static void checkTypeIdentifierPrecedesOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
121 {
122     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
123     EXPECT_TRUE([registeredTypes containsObject:firstType]);
124     EXPECT_TRUE([registeredTypes containsObject:secondType]);
125     EXPECT_TRUE([registeredTypes indexOfObject:firstType] < [registeredTypes indexOfObject:secondType]);
126 }
127
128 static void checkTypeIdentifierAndIsNotOtherTypeIdentifier(DataInteractionSimulator *simulator, NSString *firstType, NSString *secondType)
129 {
130     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
131     EXPECT_TRUE([registeredTypes containsObject:firstType]);
132     EXPECT_FALSE([registeredTypes containsObject:secondType]);
133 }
134
135 static void checkTypeIdentifierIsRegisteredAtIndex(DataInteractionSimulator *simulator, NSString *type, NSUInteger index)
136 {
137     NSArray *registeredTypes = [simulator.sourceItemProviders.firstObject registeredTypeIdentifiers];
138     EXPECT_GT(registeredTypes.count, index);
139     EXPECT_WK_STREQ(type.UTF8String, [registeredTypes[index] UTF8String]);
140 }
141
142 static void checkEstimatedSize(DataInteractionSimulator *simulator, CGSize estimatedSize)
143 {
144     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
145     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
146     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
147 }
148
149 static void checkSuggestedNameAndEstimatedSize(DataInteractionSimulator *simulator, NSString *suggestedName, CGSize estimatedSize)
150 {
151     UIItemProvider *sourceItemProvider = [simulator sourceItemProviders].firstObject;
152     EXPECT_WK_STREQ(suggestedName.UTF8String, sourceItemProvider.suggestedName.UTF8String);
153     EXPECT_EQ(estimatedSize.width, sourceItemProvider.preferredPresentationSize.width);
154     EXPECT_EQ(estimatedSize.height, sourceItemProvider.preferredPresentationSize.height);
155 }
156
157 static void checkStringArraysAreEqual(NSArray<NSString *> *expected, NSArray<NSString *> *observed)
158 {
159     EXPECT_EQ(expected.count, observed.count);
160     for (NSUInteger index = 0; index < expected.count; ++index) {
161         NSString *expectedString = [expected objectAtIndex:index];
162         NSString *observedString = [observed objectAtIndex:index];
163         EXPECT_WK_STREQ(expectedString, observedString);
164         if (![expectedString isEqualToString:observedString])
165             NSLog(@"Expected observed string: %@ to match expected string: %@ at index: %tu", observedString, expectedString, index);
166     }
167 }
168
169 static void checkDragCaretRectIsContainedInRect(CGRect caretRect, CGRect containerRect)
170 {
171     BOOL contained = CGRectContainsRect(containerRect, caretRect);
172     EXPECT_TRUE(contained);
173     if (!contained)
174         NSLog(@"Expected caret rect: %@ to fit within container rect: %@", NSStringFromCGRect(caretRect), NSStringFromCGRect(containerRect));
175 }
176
177 static void runTestWithTemporaryTextFile(void(^runTest)(NSURL *fileURL))
178 {
179     NSString *fileName = [NSString stringWithFormat:@"drag-drop-text-file-%@.txt", [NSUUID UUID].UUIDString];
180     RetainPtr<NSURL> temporaryFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName] isDirectory:NO];
181     [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
182
183     NSError *error = nil;
184     [@"This is a tiny blob of text." writeToURL:temporaryFile.get() atomically:YES encoding:NSUTF8StringEncoding error:&error];
185
186     if (error)
187         NSLog(@"Error writing temporary file: %@", error);
188
189     @try {
190         runTest(temporaryFile.get());
191     } @finally {
192         [[NSFileManager defaultManager] removeItemAtURL:temporaryFile.get() error:nil];
193     }
194 }
195
196 static void runTestWithTemporaryFolder(void(^runTest)(NSURL *folderURL))
197 {
198     NSString *folderName = [NSString stringWithFormat:@"some.directory-%@", [NSUUID UUID].UUIDString];
199     RetainPtr<NSURL> temporaryFolder = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:folderName] isDirectory:YES];
200     [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
201
202     NSError *error = nil;
203     NSFileManager *defaultManager = [NSFileManager defaultManager];
204     [defaultManager createDirectoryAtURL:temporaryFolder.get() withIntermediateDirectories:NO attributes:nil error:&error];
205     [UIImagePNGRepresentation(testIconImage()) writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"icon.png" isDirectory:NO] atomically:YES];
206     [testZIPArchive() writeToURL:[temporaryFolder.get() URLByAppendingPathComponent:@"archive.zip" isDirectory:NO] atomically:YES];
207
208     NSURL *firstSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory1" isDirectory:YES];
209     [defaultManager createDirectoryAtURL:firstSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
210     [@"I am a text file in the first subdirectory." writeToURL:[firstSubdirectory URLByAppendingPathComponent:@"text-file-1.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
211
212     NSURL *secondSubdirectory = [temporaryFolder.get() URLByAppendingPathComponent:@"subdirectory2" isDirectory:YES];
213     [defaultManager createDirectoryAtURL:secondSubdirectory withIntermediateDirectories:NO attributes:nil error:&error];
214     [@"I am a text file in the second subdirectory." writeToURL:[secondSubdirectory URLByAppendingPathComponent:@"text-file-2.txt" isDirectory:NO] atomically:YES encoding:NSUTF8StringEncoding error:&error];
215
216     if (error)
217         NSLog(@"Error writing temporary file: %@", error);
218
219     @try {
220         runTest(temporaryFolder.get());
221     } @finally {
222         [[NSFileManager defaultManager] removeItemAtURL:temporaryFolder.get() error:nil];
223     }
224 }
225
226 namespace TestWebKitAPI {
227
228 TEST(DataInteractionTests, ImageToContentEditable)
229 {
230     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
231     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
232
233     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
234     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
235
236     EXPECT_TRUE([webView editorContainsImageElement]);
237
238     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
239     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
240     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
241     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
242     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
243     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
244     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
245 }
246
247 TEST(DataInteractionTests, CanStartDragOnEnormousImage)
248 {
249     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
250     [webView synchronouslyLoadHTMLString:@"<img src='enormous.svg'></img>"];
251
252     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
253     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
254
255     NSArray *registeredTypes = [[dataInteractionSimulator sourceItemProviders].firstObject registeredTypeIdentifiers];
256     EXPECT_WK_STREQ((NSString *)kUTTypeScalableVectorGraphics, [registeredTypes firstObject]);
257 }
258
259 TEST(DataInteractionTests, ImageToTextarea)
260 {
261     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
262     [webView synchronouslyLoadTestPageNamed:@"image-and-textarea"];
263
264     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
265     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
266
267     EXPECT_WK_STREQ("", [webView editorValue]);
268
269     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
270     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
271     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
272     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
273     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
274     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
275 }
276
277 TEST(DataInteractionTests, ImageInLinkToInput)
278 {
279     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
280     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
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("https://www.apple.com/", [webView editorValue].UTF8String);
286     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
287     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"icon.png", { 215, 174 });
288     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
289 }
290
291 TEST(DataInteractionTests, ImageInLinkWithoutHREFToInput)
292 {
293     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
294     [webView synchronouslyLoadTestPageNamed:@"image-in-link-and-input"];
295     [webView stringByEvaluatingJavaScript:@"link.href = ''"];
296
297     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
298     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
299
300     EXPECT_WK_STREQ("", [webView editorValue]);
301     checkEstimatedSize(dataInteractionSimulator.get(), { 215, 174 });
302     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, 0);
303 }
304
305 TEST(DataInteractionTests, ImageDoesNotUseElementSizeAsEstimatedSize)
306 {
307     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
308     [webView synchronouslyLoadTestPageNamed:@"gif-and-file-input"];
309
310     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
311     [dataInteractionSimulator runFrom: { 100, 100 } to: { 100, 300 }];
312
313     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeGIF, 0);
314     checkSuggestedNameAndEstimatedSize(dataInteractionSimulator.get(), @"apple.gif", { 52, 64 });
315     EXPECT_WK_STREQ("apple.gif (image/gif)", [webView stringByEvaluatingJavaScript:@"output.textContent"]);
316 }
317
318 TEST(DataInteractionTests, ContentEditableToContentEditable)
319 {
320     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
321     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
322
323     [webView loadTestPageNamed:@"autofocus-contenteditable"];
324     [dataInteractionSimulator waitForInputSession];
325     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
326
327     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
328     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
329
330     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
331     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
332     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
333     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
334     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [dataInteractionSimulator finalSelectionRects]);
335     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
336 }
337
338 TEST(DataInteractionTests, ContentEditableToTextarea)
339 {
340     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
341     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
342
343     [webView loadTestPageNamed:@"contenteditable-and-textarea"];
344     [dataInteractionSimulator waitForInputSession];
345     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
346
347     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.textContent"].length, 0UL);
348     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
349
350     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
351     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
352     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
353     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
354     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
355     checkTypeIdentifierPrecedesOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypeRTFD, (NSString *)kUTTypeUTF8PlainText);
356 }
357
358 TEST(DataInteractionTests, ContentEditableMoveParagraphs)
359 {
360     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
361     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
362
363     [webView loadTestPageNamed:@"two-paragraph-contenteditable"];
364     [dataInteractionSimulator waitForInputSession];
365     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 450)];
366
367     NSString *finalTextContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
368     NSUInteger firstParagraphOffset = [finalTextContent rangeOfString:@"This is the first paragraph"].location;
369     NSUInteger secondParagraphOffset = [finalTextContent rangeOfString:@"This is the second paragraph"].location;
370
371     EXPECT_FALSE(firstParagraphOffset == NSNotFound);
372     EXPECT_FALSE(secondParagraphOffset == NSNotFound);
373     EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
374     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
375 }
376
377 TEST(DataInteractionTests, DragImageFromContentEditable)
378 {
379     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
380     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
381
382     [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-target"];
383     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 300)];
384
385     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
386 }
387
388 TEST(DataInteractionTests, TextAreaToInput)
389 {
390     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
391     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
392
393     [webView loadTestPageNamed:@"textarea-to-input"];
394     [dataInteractionSimulator waitForInputSession];
395     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
396
397     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
398     EXPECT_WK_STREQ("Hello world", [webView editorValue].UTF8String);
399     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 990, 232) ], [dataInteractionSimulator finalSelectionRects]);
400 }
401
402 TEST(DataInteractionTests, SinglePlainTextWordTypeIdentifiers)
403 {
404     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
405     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
406
407     [webView loadTestPageNamed:@"textarea-to-input"];
408     [dataInteractionSimulator waitForInputSession];
409     [webView stringByEvaluatingJavaScript:@"source.value = 'pneumonoultramicroscopicsilicovolcanoconiosis'"];
410     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
411     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
412     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
413
414     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
415     NSArray *registeredTypes = [itemProvider registeredTypeIdentifiers];
416     EXPECT_EQ(1UL, registeredTypes.count);
417     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.firstObject UTF8String]);
418     EXPECT_EQ([webView stringByEvaluatingJavaScript:@"source.value"].length, 0UL);
419     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
420     EXPECT_WK_STREQ("pneumonoultramicroscopicsilicovolcanoconiosis", [webView editorValue].UTF8String);
421 }
422
423 TEST(DataInteractionTests, SinglePlainTextURLTypeIdentifiers)
424 {
425     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
426     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
427
428     [webView loadTestPageNamed:@"textarea-to-input"];
429     [dataInteractionSimulator waitForInputSession];
430     [webView stringByEvaluatingJavaScript:@"source.value = 'https://webkit.org/'"];
431     [webView stringByEvaluatingJavaScript:@"source.selectionStart = 0"];
432     [webView stringByEvaluatingJavaScript:@"source.selectionEnd = source.value.length"];
433     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
434
435     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
436     NSArray *registeredTypes = [itemProvider registeredTypeIdentifiers];
437     EXPECT_EQ(2UL, registeredTypes.count);
438     EXPECT_WK_STREQ([(NSString *)kUTTypeURL UTF8String], [registeredTypes.firstObject UTF8String]);
439     EXPECT_WK_STREQ([(NSString *)kUTTypeUTF8PlainText UTF8String], [registeredTypes.lastObject UTF8String]);
440     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"source.value"].length);
441     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
442     EXPECT_WK_STREQ("https://webkit.org/", [webView editorValue].UTF8String);
443 }
444
445 TEST(DataInteractionTests, LinkToInput)
446 {
447     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
448     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
449
450     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
451     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
452
453     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
454
455     __block bool doneLoadingURL = false;
456     UIItemProvider *sourceItemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
457     [sourceItemProvider loadObjectOfClass:[NSURL class] completionHandler:^(id object, NSError *error) {
458         NSURL *url = object;
459         EXPECT_WK_STREQ("Hello world", url._title.UTF8String ?: "");
460         doneLoadingURL = true;
461     }];
462     TestWebKitAPI::Util::run(&doneLoadingURL);
463
464     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
465     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
466     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
467     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
468     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 273, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
469     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
470 }
471
472 TEST(DataInteractionTests, BackgroundImageLinkToInput)
473 {
474     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
475     [webView synchronouslyLoadTestPageNamed:@"background-image-link-and-input"];
476
477     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
478     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
479
480     EXPECT_WK_STREQ("https://www.apple.com/", [webView editorValue].UTF8String);
481
482     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
483     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
484     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
485     EXPECT_TRUE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
486     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [dataInteractionSimulator finalSelectionRects]);
487     checkTypeIdentifierIsRegisteredAtIndex(dataInteractionSimulator.get(), (NSString *)kUTTypeURL, 0);
488 }
489
490 TEST(DataInteractionTests, CanPreventStart)
491 {
492     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
493     [webView synchronouslyLoadTestPageNamed:@"prevent-start"];
494
495     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
496     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
497
498     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
499     EXPECT_FALSE([webView editorContainsImageElement]);
500
501     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
502     EXPECT_FALSE([observedEventNames containsObject:DataInteractionEnterEventName]);
503     EXPECT_FALSE([observedEventNames containsObject:DataInteractionOverEventName]);
504     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
505 }
506
507 TEST(DataInteractionTests, CanPreventOperation)
508 {
509     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
510     [webView synchronouslyLoadTestPageNamed:@"prevent-operation"];
511
512     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
513     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
514
515     EXPECT_FALSE([webView editorContainsImageElement]);
516
517     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
518     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
519     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
520     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
521 }
522
523 TEST(DataInteractionTests, EnterAndLeaveEvents)
524 {
525     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
526     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
527
528     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
529     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 450)];
530
531     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
532
533     NSArray *observedEventNames = [dataInteractionSimulator observedEventNames];
534     EXPECT_TRUE([observedEventNames containsObject:DataInteractionEnterEventName]);
535     EXPECT_TRUE([observedEventNames containsObject:DataInteractionOverEventName]);
536     EXPECT_TRUE([observedEventNames containsObject:DataInteractionLeaveEventName]);
537     EXPECT_FALSE([observedEventNames containsObject:DataInteractionPerformOperationEventName]);
538     checkSelectionRectsWithLogging(@[ ], [dataInteractionSimulator finalSelectionRects]);
539 }
540
541 TEST(DataInteractionTests, CanStartDragOnDivWithDraggableAttribute)
542 {
543     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
544     [webView synchronouslyLoadTestPageNamed:@"custom-draggable-div"];
545
546     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
547     [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 250)];
548
549     EXPECT_GT([dataInteractionSimulator sourceItemProviders].count, 0UL);
550     NSItemProvider *itemProvider = [dataInteractionSimulator sourceItemProviders].firstObject;
551     EXPECT_EQ(UIPreferredPresentationStyleInline, itemProvider.preferredPresentationStyle);
552     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!destination.querySelector('#item')"]);
553     EXPECT_WK_STREQ(@"PASS", [webView stringByEvaluatingJavaScript:@"item.textContent"]);
554 }
555
556 TEST(DataInteractionTests, ExternalSourcePlainTextToIFrame)
557 {
558     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
559     [webView synchronouslyLoadTestPageNamed:@"contenteditable-in-iframe"];
560
561     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
562     [itemProvider registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
563
564     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
565     [simulator setExternalItemProviders:@[ itemProvider.get() ]];
566     [simulator runFrom:CGPointMake(0, 0) to:CGPointMake(160, 250)];
567
568     auto containerLeft = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().left"].floatValue;
569     auto containerTop = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().top"].floatValue;
570     auto containerWidth = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().width"].floatValue;
571     auto containerHeight = [webView stringByEvaluatingJavaScript:@"container.getBoundingClientRect().height"].floatValue;
572     checkDragCaretRectIsContainedInRect([simulator lastKnownDragCaretRect], CGRectMake(containerLeft, containerTop, containerWidth, containerHeight));
573 }
574
575 TEST(DataInteractionTests, ExternalSourceInlineTextToFileInput)
576 {
577     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
578     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
579
580     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
581     [simulatedItemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleInline];
582     [simulatedItemProvider registerObject:@"This item provider requested inline presentation style." visibility:NSItemProviderRepresentationVisibilityAll];
583
584     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
585     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
586     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
587
588     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
589 }
590
591 TEST(DataInteractionTests, ExternalSourceJSONToFileInput)
592 {
593     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
594     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
595
596     auto simulatedJSONItemProvider = adoptNS([[UIItemProvider alloc] init]);
597     NSData *jsonData = [@"{ \"foo\": \"bar\",  \"bar\": \"baz\" }" dataUsingEncoding:NSUTF8StringEncoding];
598     [simulatedJSONItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJSON withData:jsonData];
599
600     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
601     [dataInteractionSimulator setExternalItemProviders:@[ simulatedJSONItemProvider.get() ]];
602     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
603
604     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
605 }
606
607 TEST(DataInteractionTests, ExternalSourceImageToFileInput)
608 {
609     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
610     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
611
612     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
613     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
614     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
615
616     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
617     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get() ]];
618     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
619
620     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
621     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
622 }
623
624 TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
625 {
626     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
627     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
628
629     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
630     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
631     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
632
633     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
634     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
635     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
636     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
637
638     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
639     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
640 }
641
642 TEST(DataInteractionTests, ExternalSourceMoveOperationNotAllowed)
643 {
644     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
645     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
646     [webView stringByEvaluatingJavaScript:@"upload.dropEffect = 'move'"];
647
648     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
649     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
650     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
651
652     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
653     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
654     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get() ]];
655     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
656
657     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
658 }
659
660 TEST(DataInteractionTests, ExternalSourceZIPArchiveAndURLToSingleFileInput)
661 {
662     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
663     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
664
665     auto archiveProvider = adoptNS([[UIItemProvider alloc] init]);
666     [archiveProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
667
668     auto urlProvider = adoptNS([[UIItemProvider alloc] init]);
669     [urlProvider registerObject:[NSURL URLWithString:@"https://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
670
671     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
672     [dataInteractionSimulator setExternalItemProviders:@[ archiveProvider.get(), urlProvider.get() ]];
673     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
674
675     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
676     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
677 }
678
679 TEST(DataInteractionTests, ExternalSourceZIPArchiveToUploadArea)
680 {
681     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
682     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
683
684     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
685     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeZipArchive withData:testZIPArchive()];
686
687     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
688     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
689     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
690
691     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
692     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
693 }
694
695 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToSingleFileInput)
696 {
697     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
698     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
699
700     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
701     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
702     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
703
704     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
705     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
706     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
707
708     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
709     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
710     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
711
712     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
713     EXPECT_WK_STREQ("", outputValue.UTF8String);
714 }
715
716 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToMultipleFileInput)
717 {
718     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
719     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
720     [webView stringByEvaluatingJavaScript:@"input.setAttribute('multiple', '')"];
721
722     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
723     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
724     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
725
726     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
727     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
728     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
729
730     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
731     [dataInteractionSimulator setExternalItemProviders:@[ simulatedHTMLItemProvider.get(), simulatedImageItemProvider.get() ]];
732     [dataInteractionSimulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
733
734     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
735     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
736 }
737
738 TEST(DataInteractionTests, ExternalSourceImageAndHTMLToUploadArea)
739 {
740     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
741     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
742
743     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
744     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
745     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
746
747     auto firstSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
748     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
749     [firstSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
750
751     auto secondSimulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
752     NSData *secondHTMLData = [@"<html><body>hello world</body></html>" dataUsingEncoding:NSUTF8StringEncoding];
753     [secondSimulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:secondHTMLData];
754
755     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
756     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
757     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), firstSimulatedHTMLItemProvider.get(), secondSimulatedHTMLItemProvider.get() ]];
758     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
759
760     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
761     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
762 }
763
764 TEST(DataInteractionTests, ExternalSourceHTMLToContentEditable)
765 {
766     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
767     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
768     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
769
770     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
771     auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
772     NSData *htmlData = [@"<h1>This is a test</h1>" dataUsingEncoding:NSUTF8StringEncoding];
773     [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
774     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
775     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
776
777     NSString *textContent = [webView stringByEvaluatingJavaScript:@"editor.textContent"];
778     EXPECT_WK_STREQ("This is a test", textContent.UTF8String);
779     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('h1')"].boolValue);
780 }
781
782 TEST(DataInteractionTests, ExternalSourceBoldSystemAttributedStringToContentEditable)
783 {
784     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
785     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
786     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
787
788     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
789     NSDictionary *textAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:20] };
790     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
791     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
792     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
793     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
794
795     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
796 }
797
798 TEST(DataInteractionTests, ExternalSourceColoredAttributedStringToContentEditable)
799 {
800     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
801     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
802     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
803
804     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
805     NSDictionary *textAttributes = @{ NSForegroundColorAttributeName: [UIColor redColor] };
806     NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"This is a test" attributes:textAttributes];
807     auto itemProvider = adoptNS([[UIItemProvider alloc] initWithObject:richText]);
808     [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
809     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
810
811     EXPECT_WK_STREQ("rgb(255, 0, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('p')).color"]);
812     EXPECT_WK_STREQ("This is a test", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
813 }
814
815 TEST(DataInteractionTests, ExternalSourceMultipleURLsToContentEditable)
816 {
817     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
818     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
819     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
820
821     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
822     auto firstItem = adoptNS([[UIItemProvider alloc] init]);
823     [firstItem registerObject:[NSURL URLWithString:@"https://www.apple.com/iphone/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
824     auto secondItem = adoptNS([[UIItemProvider alloc] init]);
825     [secondItem registerObject:[NSURL URLWithString:@"https://www.apple.com/mac/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
826     auto thirdItem = adoptNS([[UIItemProvider alloc] init]);
827     [thirdItem registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
828     [dataInteractionSimulator setExternalItemProviders:@[ firstItem.get(), secondItem.get(), thirdItem.get() ]];
829     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
830
831     NSArray *separatedLinks = [[webView stringByEvaluatingJavaScript:@"editor.textContent"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
832     EXPECT_EQ(3UL, separatedLinks.count);
833     EXPECT_WK_STREQ("https://www.apple.com/iphone/", separatedLinks[0]);
834     EXPECT_WK_STREQ("https://www.apple.com/mac/", separatedLinks[1]);
835     EXPECT_WK_STREQ("https://webkit.org/", separatedLinks[2]);
836 }
837
838 TEST(DataInteractionTests, RespectsExternalSourceFidelityRankings)
839 {
840     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
841     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
842     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
843
844     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
845
846     // Here, our source item provider vends two representations: plain text, and then an image. If we don't respect the
847     // fidelity order requested by the source, we'll end up assuming that the image is a higher fidelity representation
848     // than the plain text, and erroneously insert the image. If we respect source fidelities, we'll insert text rather
849     // than an image.
850     auto simulatedItemProviderWithTextFirst = adoptNS([[UIItemProvider alloc] init]);
851     [simulatedItemProviderWithTextFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
852     [simulatedItemProviderWithTextFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
853     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithTextFirst.get() ]];
854
855     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
856     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
857     EXPECT_FALSE([webView editorContainsImageElement]);
858     [webView stringByEvaluatingJavaScript:@"editor.innerHTML = ''"];
859
860     // Now we register the item providers in reverse, and expect the image to be inserted instead of text.
861     auto simulatedItemProviderWithImageFirst = adoptNS([[UIItemProvider alloc] init]);
862     [simulatedItemProviderWithImageFirst registerObject:testIconImage() visibility:UIItemProviderRepresentationOptionsVisibilityAll];
863     [simulatedItemProviderWithImageFirst registerObject:@"Hello world" visibility:UIItemProviderRepresentationOptionsVisibilityAll];
864     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProviderWithImageFirst.get() ]];
865
866     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
867     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
868     EXPECT_TRUE([webView editorContainsImageElement]);
869 }
870
871 TEST(DataInteractionTests, ExternalSourceUTF8PlainTextOnly)
872 {
873     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
874     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
875
876     NSString *textPayload = @"Ceci n'est pas une string";
877     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
878     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
879     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
880     {
881         completionBlock([textPayload dataUsingEncoding:NSUTF8StringEncoding], nil);
882         return [NSProgress discreteProgressWithTotalUnitCount:100];
883     }];
884     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
885     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
886     EXPECT_WK_STREQ(textPayload.UTF8String, [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
887     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 1936, 227) ], [dataInteractionSimulator finalSelectionRects]);
888 }
889
890 TEST(DataInteractionTests, ExternalSourceJPEGOnly)
891 {
892     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
893     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
894
895     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
896     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
897     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(__bridge NSString *)kUTTypeJPEG options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
898     {
899         completionBlock(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
900         return [NSProgress discreteProgressWithTotalUnitCount:100];
901     }];
902     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
903     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
904     EXPECT_TRUE([webView editorContainsImageElement]);
905     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [dataInteractionSimulator finalSelectionRects]);
906 }
907
908 TEST(DataInteractionTests, ExternalSourceTitledNSURL)
909 {
910     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
911     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
912     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
913
914     NSURL *titledURL = [NSURL URLWithString:@"https://www.apple.com"];
915     titledURL._title = @"Apple";
916     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
917     [simulatedItemProvider registerObject:titledURL visibility:UIItemProviderRepresentationOptionsVisibilityAll];
918
919     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
920     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
921     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
922
923     EXPECT_WK_STREQ("Apple", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').textContent"]);
924     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
925 }
926
927 TEST(DataInteractionTests, ExternalSourceFileURL)
928 {
929     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
930     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
931     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
932
933     NSURL *URL = [NSURL URLWithString:@"file:///some/file/that/is/not/real"];
934     UIItemProvider *simulatedItemProvider = [UIItemProvider itemProviderWithURL:URL title:@""];
935
936     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
937     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider ]];
938     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
939
940     EXPECT_FALSE([[webView stringByEvaluatingJavaScript:@"!!editor.querySelector('a')"] boolValue]);
941     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
942 }
943
944 TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
945 {
946     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
947     [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
948
949     auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
950     NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
951     [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
952
953     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
954     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
955     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
956
957     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
958     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
959     {
960         EXPECT_EQ(2UL, session.items.count);
961         UIDragItem *firstItem = session.items[0];
962         UIDragItem *secondItem = session.items[1];
963         EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
964         EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
965         return @[ secondItem ];
966     }];
967     [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
968     [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
969
970     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
971     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
972 }
973
974 static RetainPtr<TestWKWebView> setUpTestWebViewForDataTransferItems()
975 {
976     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
977     [webView synchronouslyLoadTestPageNamed:@"DataTransferItem-getAsEntry"];
978
979     auto preferences = (WKPreferencesRef)[[webView configuration] preferences];
980     WKPreferencesSetDataTransferItemsEnabled(preferences, true);
981     WKPreferencesSetDirectoryUploadEnabled(preferences, true);
982
983     return webView;
984 }
985
986 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetFolderAsEntry)
987 {
988     // The expected output is sorted by alphabetical order here for consistent behavior across different test environments.
989     // See DataTransferItem-getAsEntry.html for more details.
990     NSArray<NSString *> *expectedOutput = @[
991         @"Found data transfer item (kind: 'string', type: 'text/plain')",
992         @"Found data transfer item (kind: 'file', type: '')",
993         @"DIR: /somedirectory",
994         @"DIR: /somedirectory/subdirectory1",
995         @"DIR: /somedirectory/subdirectory2",
996         @"FILE: /somedirectory/archive.zip ('application/zip', 988 bytes)",
997         @"FILE: /somedirectory/icon.png ('image/png', 42130 bytes)",
998         @"FILE: /somedirectory/subdirectory1/text-file-1.txt ('text/plain', 43 bytes)",
999         @"FILE: /somedirectory/subdirectory2/text-file-2.txt ('text/plain', 44 bytes)"
1000     ];
1001
1002     auto webView = setUpTestWebViewForDataTransferItems();
1003     __block bool done = false;
1004     [webView performAfterReceivingMessage:@"dropped" action:^() {
1005         done = true;
1006     }];
1007
1008     runTestWithTemporaryFolder(^(NSURL *folderURL) {
1009         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
1010         [itemProvider setSuggestedName:@"somedirectory"];
1011         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeFolder fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFolderURL = retainPtr(folderURL)] (FileLoadCompletionBlock completionHandler) -> NSProgress * {
1012             completionHandler(capturedFolderURL.get(), NO, nil);
1013             return nil;
1014         }];
1015
1016         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1017         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
1018         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
1019     });
1020
1021     TestWebKitAPI::Util::run(&done);
1022     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
1023 }
1024
1025 TEST(DataInteractionTests, ExternalSourceDataTransferItemGetPlainTextFileAsEntry)
1026 {
1027     NSArray<NSString *> *expectedOutput = @[
1028         @"Found data transfer item (kind: 'string', type: 'text/plain')",
1029         @"Found data transfer item (kind: 'file', type: 'text/plain')",
1030         @"FILE: /foo.txt ('text/plain', 28 bytes)"
1031     ];
1032
1033     auto webView = setUpTestWebViewForDataTransferItems();
1034     __block bool done = false;
1035     [webView performAfterReceivingMessage:@"dropped" action:^() {
1036         done = true;
1037     }];
1038
1039     runTestWithTemporaryTextFile(^(NSURL *fileURL) {
1040         auto itemProvider = adoptNS([[NSItemProvider alloc] init]);
1041         [itemProvider setSuggestedName:@"foo"];
1042         [itemProvider registerFileRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText fileOptions:0 visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[capturedFileURL = retainPtr(fileURL)](FileLoadCompletionBlock completionHandler) -> NSProgress * {
1043             completionHandler(capturedFileURL.get(), NO, nil);
1044             return nil;
1045         }];
1046
1047         auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1048         [dataInteractionSimulator setExternalItemProviders:@[ itemProvider.get() ]];
1049         [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(150, 50)];
1050     });
1051
1052     TestWebKitAPI::Util::run(&done);
1053     EXPECT_WK_STREQ([expectedOutput componentsJoinedByString:@"\n"], [webView stringByEvaluatingJavaScript:@"output.value"]);
1054 }
1055
1056 TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
1057 {
1058     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1059     [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
1060     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1061
1062     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1063     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
1064     {
1065         NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
1066         for (UIDragItem *item in session.items) {
1067             if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
1068                 [allowedItems addObject:item];
1069         }
1070         EXPECT_EQ(1UL, allowedItems.count);
1071         return allowedItems;
1072     }];
1073
1074     auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
1075     [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1076     auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
1077     [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
1078     [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
1079     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1080
1081     EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1082 }
1083
1084 TEST(DataInteractionTests, OverrideDataInteractionOperation)
1085 {
1086     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1087     [webView synchronouslyLoadTestPageNamed:@"simple"];
1088
1089     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1090     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:[@"<body></body>" dataUsingEncoding:NSUTF8StringEncoding]];
1091
1092     __block bool finishedLoadingData = false;
1093     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1094     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1095     [dataInteractionSimulator setOverrideDataInteractionOperationBlock:^NSUInteger(NSUInteger operation, id session)
1096     {
1097         EXPECT_EQ(0U, operation);
1098         return 1;
1099     }];
1100     [dataInteractionSimulator setDataInteractionOperationCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
1101         EXPECT_FALSE(handled);
1102         [itemProviders.firstObject loadDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML completionHandler:^(NSData *data, NSError *error) {
1103             NSString *text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
1104             EXPECT_WK_STREQ("<body></body>", text.UTF8String);
1105             EXPECT_FALSE(!!error);
1106             finishedLoadingData = true;
1107         }];
1108     }];
1109     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1110     TestWebKitAPI::Util::run(&finishedLoadingData);
1111 }
1112
1113 TEST(DataInteractionTests, InjectedBundleOverridePerformTwoStepDrop)
1114 {
1115     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1116     [configuration.processPool _setObject:@YES forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1117
1118     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1119     [webView loadTestPageNamed:@"autofocus-contenteditable"];
1120     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1121
1122     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1123     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1124     {
1125         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1126         return [NSProgress discreteProgressWithTotalUnitCount:100];
1127     }];
1128
1129     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1130     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1131     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1132
1133     EXPECT_EQ(0UL, [webView stringByEvaluatingJavaScript:@"editor.textContent"].length);
1134 }
1135
1136 TEST(DataInteractionTests, InjectedBundleAllowPerformTwoStepDrop)
1137 {
1138     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1139     [configuration.processPool _setObject:@NO forBundleParameter:@"BundleOverridePerformTwoStepDrop"];
1140
1141     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1142     [webView loadTestPageNamed:@"autofocus-contenteditable"];
1143     [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
1144
1145     auto simulatedItemProvider = adoptNS([[UIItemProvider alloc] init]);
1146     [simulatedItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1147     {
1148         completionBlock([@"Hello world" dataUsingEncoding:NSUTF8StringEncoding], nil);
1149         return [NSProgress discreteProgressWithTotalUnitCount:100];
1150     }];
1151
1152     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1153     [dataInteractionSimulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
1154     [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
1155
1156     EXPECT_WK_STREQ("Hello world", [webView stringByEvaluatingJavaScript:@"editor.textContent"].UTF8String);
1157 }
1158
1159 TEST(DataInteractionTests, InjectedBundleImageElementData)
1160 {
1161     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1162     [configuration _setAttachmentElementEnabled:YES];
1163     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1164     [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
1165
1166     __block RetainPtr<NSString> injectedString;
1167     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1168     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1169     {
1170         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1171         return @[ itemProvider ];
1172     }];
1173
1174     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
1175
1176     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1177 }
1178
1179 TEST(DataInteractionTests, InjectedBundleAttachmentElementData)
1180 {
1181     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"];
1182     [configuration _setAttachmentElementEnabled:YES];
1183     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration]);
1184     [webView synchronouslyLoadTestPageNamed:@"attachment-element"];
1185
1186     __block RetainPtr<NSString> injectedString;
1187     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1188     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *data)
1189     {
1190         injectedString = adoptNS([[NSString alloc] initWithData:data[InjectedBundlePasteboardDataType] encoding:NSUTF8StringEncoding]);
1191         return @[ itemProvider ];
1192     }];
1193
1194     [dataInteractionSimulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400)];
1195
1196     EXPECT_WK_STREQ("hello", [injectedString UTF8String]);
1197     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"getSelection().isCollapsed"].boolValue);
1198 }
1199
1200 TEST(DataInteractionTests, LargeImageToTargetDiv)
1201 {
1202     auto testWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1203     [[testWebViewConfiguration preferences] _setLargeImageAsyncDecodingEnabled:NO];
1204
1205     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:testWebViewConfiguration.get()]);
1206     [webView synchronouslyLoadTestPageNamed:@"div-and-large-image"];
1207
1208     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1209     [dataInteractionSimulator runFrom:CGPointMake(200, 400) to:CGPointMake(200, 150)];
1210     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1211     checkTypeIdentifierAndIsNotOtherTypeIdentifier(dataInteractionSimulator.get(), (NSString *)kUTTypePNG, (NSString *)kUTTypeFileURL);
1212     checkEstimatedSize(dataInteractionSimulator.get(), { 2000, 2000 });
1213 }
1214
1215 TEST(DataInteractionTests, LinkWithEmptyHREF)
1216 {
1217     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1218     [webView synchronouslyLoadTestPageNamed:@"link-and-input"];
1219     [webView stringByEvaluatingJavaScript:@"document.querySelector('a').href = ''"];
1220
1221     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1222     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1223
1224     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1225     EXPECT_WK_STREQ("", [webView editorValue].UTF8String);
1226 }
1227
1228 TEST(DataInteractionTests, CancelledLiftDoesNotCauseSubsequentDragsToFail)
1229 {
1230     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1231     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1232
1233     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1234     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *, NSArray *, NSDictionary *)
1235     {
1236         return @[ ];
1237     }];
1238     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1239     EXPECT_EQ(DataInteractionCancelled, [dataInteractionSimulator phase]);
1240     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1241     NSString *outputText = [webView stringByEvaluatingJavaScript:@"output.textContent"];
1242     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1243
1244     [webView stringByEvaluatingJavaScript:@"output.innerHTML = ''"];
1245     [dataInteractionSimulator setConvertItemProvidersBlock:^NSArray *(UIItemProvider *itemProvider, NSArray *, NSDictionary *)
1246     {
1247         return @[ itemProvider ];
1248     }];
1249     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1250     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
1251     [webView stringByEvaluatingJavaScript:@"output.textContent"];
1252     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
1253 }
1254
1255 static void testDragAndDropOntoTargetElements(TestWKWebView *webView)
1256 {
1257     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView]);
1258     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 250)];
1259     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target1).backgroundColor"]);
1260     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target1.textContent"]);
1261
1262     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 50)];
1263     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target2).backgroundColor"]);
1264     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target2.textContent"]);
1265
1266     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(250, 250)];
1267     EXPECT_WK_STREQ("rgb(0, 128, 0)", [webView stringByEvaluatingJavaScript:@"getComputedStyle(target3).backgroundColor"]);
1268     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target3.textContent"]);
1269 }
1270
1271 TEST(DataInteractionTests, DragEventClientCoordinatesBasic)
1272 {
1273     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1274     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1275
1276     testDragAndDropOntoTargetElements(webView.get());
1277 }
1278
1279 TEST(DataInteractionTests, DragEventClientCoordinatesWithScrollOffset)
1280 {
1281     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1282     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1283     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1284     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1285     [webView waitForNextPresentationUpdate];
1286
1287     testDragAndDropOntoTargetElements(webView.get());
1288 }
1289
1290 TEST(DataInteractionTests, DragEventPageCoordinatesBasic)
1291 {
1292     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1293     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1294     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1295
1296     testDragAndDropOntoTargetElements(webView.get());
1297 }
1298
1299 TEST(DataInteractionTests, DragEventPageCoordinatesWithScrollOffset)
1300 {
1301     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1302     [webView synchronouslyLoadTestPageNamed:@"drop-targets"];
1303     [webView stringByEvaluatingJavaScript:@"document.body.style.margin = '1000px 0'"];
1304     [webView stringByEvaluatingJavaScript:@"document.scrollingElement.scrollTop = 1000"];
1305     [webView stringByEvaluatingJavaScript:@"window.usePageCoordinates = true"];
1306     [webView waitForNextPresentationUpdate];
1307
1308     testDragAndDropOntoTargetElements(webView.get());
1309 }
1310
1311 TEST(DataInteractionTests, DoNotCrashWhenSelectionIsClearedInDragStart)
1312 {
1313     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1314     [webView synchronouslyLoadTestPageNamed:@"dragstart-clear-selection"];
1315
1316     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1317     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1318
1319     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"paragraph.textContent"]);
1320 }
1321
1322 TEST(DataInteractionTests, CustomActionSheetPopover)
1323 {
1324     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1325     [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
1326
1327     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1328     [dataInteractionSimulator setShouldEnsureUIApplication:YES];
1329
1330     __block BOOL didInvokeCustomActionSheet = NO;
1331     [dataInteractionSimulator setShowCustomActionSheetBlock:^BOOL(_WKActivatedElementInfo *element)
1332     {
1333         EXPECT_EQ(_WKActivatedElementTypeLink, element.type);
1334         EXPECT_WK_STREQ("Hello world", element.title.UTF8String);
1335         didInvokeCustomActionSheet = YES;
1336         return YES;
1337     }];
1338     [dataInteractionSimulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
1339     EXPECT_TRUE(didInvokeCustomActionSheet);
1340     EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"].UTF8String);
1341 }
1342
1343 TEST(DataInteractionTests, UnresponsivePageDoesNotHangUI)
1344 {
1345     _WKProcessPoolConfiguration *processPoolConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease];
1346     processPoolConfiguration.ignoreSynchronousMessagingTimeoutsForTesting = YES;
1347
1348     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:[[[WKWebViewConfiguration alloc] init] autorelease] processPoolConfiguration:processPoolConfiguration]);
1349     [webView synchronouslyLoadTestPageNamed:@"simple"];
1350     [webView evaluateJavaScript:@"while(1);" completionHandler:nil];
1351
1352     // The test passes if we can prepare for data interaction without timing out.
1353     auto dragSession = adoptNS([[MockDragSession alloc] init]);
1354     [(id <UIDragInteractionDelegate_ForWebKitOnly>)[webView dragInteractionDelegate] _dragInteraction:[webView dragInteraction] prepareForSession:dragSession.get() completion:^() { }];
1355 }
1356
1357 TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
1358 {
1359     static NSString *fastString = @"This data loads quickly";
1360     static NSString *slowString = @"This data loads slowly";
1361
1362     WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
1363     auto fastItem = adoptNS([[UIItemProvider alloc] init]);
1364     [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1365     {
1366         completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
1367         return nil;
1368     }];
1369
1370     auto slowItem = adoptNS([[UIItemProvider alloc] init]);
1371     [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
1372     {
1373         sleep(2);
1374         completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
1375         return nil;
1376     }];
1377
1378     __block bool hasRunFirstCompletionBlock = false;
1379     pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
1380     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1381         EXPECT_EQ(2UL, urls.count);
1382         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1383         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1384         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1385         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1386         hasRunFirstCompletionBlock = true;
1387     } synchronousTimeout:600];
1388     EXPECT_TRUE(hasRunFirstCompletionBlock);
1389
1390     __block bool hasRunSecondCompletionBlock = false;
1391     [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
1392         EXPECT_EQ(2UL, urls.count);
1393         auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
1394         auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
1395         EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
1396         EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
1397         hasRunSecondCompletionBlock = true;
1398     } synchronousTimeout:0];
1399     EXPECT_FALSE(hasRunSecondCompletionBlock);
1400     TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
1401 }
1402
1403 TEST(DataInteractionTests, DoNotCrashWhenSelectionMovesOffscreenAfterDragStart)
1404 {
1405     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1406     [webView synchronouslyLoadTestPageNamed:@"dragstart-change-selection-offscreen"];
1407
1408     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1409     [simulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 100)];
1410
1411     EXPECT_WK_STREQ("FAR OFFSCREEN", [webView stringByEvaluatingJavaScript:@"getSelection().getRangeAt(0).toString()"]);
1412 }
1413
1414 TEST(DataInteractionTests, AdditionalItemsCanBePreventedOnDragStart)
1415 {
1416     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1417     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1418     [webView stringByEvaluatingJavaScript:@"link.addEventListener('dragstart', e => e.preventDefault())"];
1419     [webView stringByEvaluatingJavaScript:@"image.addEventListener('dragstart', e => e.preventDefault())"];
1420
1421     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1422     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1423         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1424         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1425     }];
1426     EXPECT_WK_STREQ("ABCD", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1427 }
1428
1429 TEST(DataInteractionTests, AdditionalLinkAndImageIntoContentEditable)
1430 {
1431     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1432     [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
1433
1434     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1435     [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
1436         @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
1437         @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
1438     }];
1439     EXPECT_WK_STREQ("ABCD A link", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
1440     EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"]);
1441     EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
1442 }
1443
1444 TEST(DataInteractionTests, DragLiftPreviewDataTransferSetDragImage)
1445 {
1446     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
1447     [webView synchronouslyLoadTestPageNamed:@"DataTransfer-setDragImage"];
1448     auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
1449
1450     // Use DataTransfer.setDragImage to specify an existing image element in the DOM.
1451     [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(250, 50)];
1452     checkCGRectIsEqualToCGRectWithLogging({{100, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1453
1454     // Use DataTransfer.setDragImage to specify an existing image element in the DOM, with x and y offsets.
1455     [simulator runFrom:CGPointMake(10, 150) to:CGPointMake(250, 150)];
1456     checkCGRectIsEqualToCGRectWithLogging({{-90, 50}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1457
1458     // Use DataTransfer.setDragImage to specify a newly created Image, disconnected from the DOM.
1459     [simulator runFrom:CGPointMake(100, 250) to:CGPointMake(250, 250)];
1460     checkCGRectIsEqualToCGRectWithLogging({{100, 250}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1461
1462     // Don't use DataTransfer.setDragImage and fall back to snapshotting the dragged element.
1463     [simulator runFrom:CGPointMake(50, 350) to:CGPointMake(250, 350)];
1464     checkCGRectIsEqualToCGRectWithLogging({{0, 300}, {300, 100}}, [simulator liftPreviews][0].view.frame);
1465
1466     // Perform a normal drag on an image.
1467     [simulator runFrom:CGPointMake(50, 450) to:CGPointMake(250, 450)];
1468     checkCGRectIsEqualToCGRectWithLogging({{0, 400}, {215, 174}}, [simulator liftPreviews][0].view.frame);
1469 }
1470
1471 } // namespace TestWebKitAPI
1472
1473 #endif // ENABLE(DATA_INTERACTION)