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