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