[iOS DnD] Support DataTransfer.getData and DataTransfer.setData when dragging or...
[WebKit-https.git] / Source / WebCore / platform / ios / WebItemProviderPasteboard.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 #import "WebItemProviderPasteboard.h"
28
29 #if ENABLE(DATA_INTERACTION)
30
31 #import <Foundation/NSItemProvider.h>
32 #import <Foundation/NSProgress.h>
33 #import <MobileCoreServices/MobileCoreServices.h>
34 #import <UIKit/NSItemProvider+UIKitAdditions.h>
35 #import <UIKit/UIColor.h>
36 #import <UIKit/UIImage.h>
37 #import <WebCore/FileSystem.h>
38 #import <WebCore/Pasteboard.h>
39 #import <pal/spi/ios/UIKitSPI.h>
40 #import <wtf/BlockPtr.h>
41 #import <wtf/OSObjectPtr.h>
42 #import <wtf/RetainPtr.h>
43 #import <wtf/SoftLinking.h>
44
45 SOFT_LINK_FRAMEWORK(UIKit)
46 SOFT_LINK_CLASS(UIKit, UIColor)
47 SOFT_LINK_CLASS(UIKit, UIImage)
48 SOFT_LINK_CLASS(UIKit, UIItemProvider)
49
50 using namespace WebCore;
51
52 typedef void(^ItemProviderDataLoadCompletionHandler)(NSData *, NSError *);
53 typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
54
55 @interface WebItemProviderRegistrationInfo ()
56 {
57     RetainPtr<id <UIItemProviderWriting>> _representingObject;
58     RetainPtr<NSString> _typeIdentifier;
59     RetainPtr<NSData> _data;
60 }
61 @end
62
63 @implementation WebItemProviderRegistrationInfo
64
65 - (instancetype)initWithRepresentingObject:(id <UIItemProviderWriting>)representingObject typeIdentifier:(NSString *)typeIdentifier data:(NSData *)data
66 {
67     if (representingObject)
68         ASSERT(!typeIdentifier && !data);
69     else
70         ASSERT(typeIdentifier && data);
71
72     if (self = [super init]) {
73         _representingObject = representingObject;
74         _typeIdentifier = typeIdentifier;
75         _data = data;
76     }
77     return self;
78 }
79
80 - (id <UIItemProviderWriting>)representingObject
81 {
82     return _representingObject.get();
83 }
84
85 - (NSString *)typeIdentifier
86 {
87     return _typeIdentifier.get();
88 }
89
90 - (NSData *)data
91 {
92     return _data.get();
93 }
94
95 @end
96
97 @interface WebItemProviderRegistrationInfoList ()
98 {
99     RetainPtr<NSMutableArray> _representations;
100 }
101 @end
102
103 @implementation WebItemProviderRegistrationInfoList
104
105 - (instancetype)init
106 {
107     if (self = [super init]) {
108         _representations = adoptNS([[NSMutableArray alloc] init]);
109         _preferredPresentationSize = CGSizeZero;
110         _preferredPresentationStyle = WebPreferredPresentationStyleUnspecified;
111     }
112
113     return self;
114 }
115
116 - (void)dealloc
117 {
118     [_suggestedName release];
119     [super dealloc];
120 }
121
122 - (void)addData:(NSData *)data forType:(NSString *)typeIdentifier
123 {
124     [_representations addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:nil typeIdentifier:typeIdentifier data:data] autorelease]];
125 }
126
127 - (void)addRepresentingObject:(id <UIItemProviderWriting>)object
128 {
129     ASSERT([object conformsToProtocol:@protocol(UIItemProviderWriting)]);
130     [_representations addObject:[[[WebItemProviderRegistrationInfo alloc] initWithRepresentingObject:object typeIdentifier:nil data:nil] autorelease]];
131 }
132
133 - (NSUInteger)numberOfItems
134 {
135     return [_representations count];
136 }
137
138 - (WebItemProviderRegistrationInfo *)itemAtIndex:(NSUInteger)index
139 {
140     if (index >= self.numberOfItems)
141         return nil;
142
143     return [_representations objectAtIndex:index];
144 }
145
146 - (void)enumerateItems:(void (^)(WebItemProviderRegistrationInfo *, NSUInteger))block
147 {
148     for (NSUInteger index = 0; index < self.numberOfItems; ++index)
149         block([self itemAtIndex:index], index);
150 }
151
152 static UIPreferredPresentationStyle uiPreferredPresentationStyle(WebPreferredPresentationStyle style)
153 {
154     switch (style) {
155     case WebPreferredPresentationStyleUnspecified:
156         return UIPreferredPresentationStyleUnspecified;
157     case WebPreferredPresentationStyleInline:
158         return UIPreferredPresentationStyleInline;
159     case WebPreferredPresentationStyleAttachment:
160         return UIPreferredPresentationStyleAttachment;
161     default:
162         ASSERT_NOT_REACHED();
163         return UIPreferredPresentationStyleUnspecified;
164     }
165 }
166
167 - (UIItemProvider *)itemProvider
168 {
169     if (!self.numberOfItems)
170         return nil;
171
172     auto itemProvider = adoptNS([allocUIItemProviderInstance() init]);
173     for (WebItemProviderRegistrationInfo *representation in _representations.get()) {
174         if (representation.representingObject) {
175             [itemProvider registerObject:representation.representingObject visibility:UIItemProviderRepresentationOptionsVisibilityAll];
176             continue;
177         }
178
179         if (!representation.typeIdentifier.length || !representation.data.length)
180             continue;
181
182         RetainPtr<NSData> itemData = representation.data;
183         [itemProvider registerDataRepresentationForTypeIdentifier:representation.typeIdentifier visibility:UIItemProviderRepresentationOptionsVisibilityAll loadHandler:[itemData] (ItemProviderDataLoadCompletionHandler completionHandler) -> NSProgress * {
184             completionHandler(itemData.get(), nil);
185             return nil;
186         }];
187     }
188     [itemProvider setPreferredPresentationSize:self.preferredPresentationSize];
189     [itemProvider setSuggestedName:self.suggestedName];
190     [itemProvider setPreferredPresentationStyle:uiPreferredPresentationStyle(self.preferredPresentationStyle)];
191     return itemProvider.autorelease();
192 }
193
194 - (NSString *)description
195 {
196     __block NSMutableString *description = [NSMutableString string];
197     [description appendFormat:@"<%@: %p", [self class], self];
198     [self enumerateItems:^(WebItemProviderRegistrationInfo *item, NSUInteger index) {
199         if (index)
200             [description appendString:@","];
201
202         if (item.representingObject)
203             [description appendFormat:@" (%@: %p)", [item.representingObject class], item.representingObject];
204         else
205             [description appendFormat:@" ('%@' => %tu bytes)", item.typeIdentifier, item.data.length];
206     }];
207     [description appendString:@">"];
208     return description;
209 }
210
211 @end
212
213 @interface WebItemProviderLoadResult : NSObject
214
215 + (instancetype)loadResultWithFileURLMap:(TypeToFileURLMap *)fileURLs presentationStyle:(UIPreferredPresentationStyle)presentationStyle;
216 + (instancetype)emptyLoadResult;
217
218 - (NSURL *)fileURLForType:(NSString *)type;
219 @property (nonatomic, readonly) NSArray<NSURL *> *loadedFileURLs;
220 @property (nonatomic, readonly) NSArray<NSString *> *loadedTypeIdentifiers;
221 @property (nonatomic, readonly) BOOL canBeRepresentedAsFileUpload;
222
223 @end
224
225 @implementation WebItemProviderLoadResult {
226     RetainPtr<TypeToFileURLMap> _fileURLs;
227 }
228
229 + (instancetype)emptyLoadResult
230 {
231     return [[[self alloc] initWithFileURLMap:@{ } presentationStyle:UIPreferredPresentationStyleUnspecified] autorelease];
232 }
233
234 + (instancetype)loadResultWithFileURLMap:(TypeToFileURLMap *)fileURLs presentationStyle:(UIPreferredPresentationStyle)presentationStyle
235 {
236     return [[[self alloc] initWithFileURLMap:fileURLs presentationStyle:presentationStyle] autorelease];
237 }
238
239 - (instancetype)initWithFileURLMap:(TypeToFileURLMap *)fileURLs presentationStyle:(UIPreferredPresentationStyle)presentationStyle
240 {
241     if (!(self = [super init]))
242         return nil;
243
244     _fileURLs = fileURLs;
245     _canBeRepresentedAsFileUpload = presentationStyle != UIPreferredPresentationStyleInline;
246
247     return self;
248 }
249
250 - (NSURL *)fileURLForType:(NSString *)type
251 {
252     return [_fileURLs objectForKey:type];
253 }
254
255 - (NSArray<NSURL *> *)loadedFileURLs
256 {
257     return [_fileURLs allValues];
258 }
259
260 - (NSArray<NSString *> *)loadedTypeIdentifiers
261 {
262     return [_fileURLs allKeys];
263 }
264
265 @end
266
267 @interface WebItemProviderPasteboard ()
268
269 @property (nonatomic) NSInteger numberOfItems;
270 @property (nonatomic) NSInteger changeCount;
271 @property (nonatomic) NSInteger pendingOperationCount;
272
273 @end
274
275 @implementation WebItemProviderPasteboard {
276     // FIXME: These ivars should be refactored to be Vector<RetainPtr<Type>> instead of generic NSArrays.
277     RetainPtr<NSArray> _itemProviders;
278     RetainPtr<NSArray> _supportedTypeIdentifiers;
279     RetainPtr<WebItemProviderRegistrationInfoList> _stagedRegistrationInfoList;
280
281     Vector<RetainPtr<WebItemProviderLoadResult>> _loadResults;
282 }
283
284 + (instancetype)sharedInstance
285 {
286     static WebItemProviderPasteboard *sharedPasteboard = nil;
287     static dispatch_once_t onceToken;
288     dispatch_once(&onceToken, ^() {
289         sharedPasteboard = [[WebItemProviderPasteboard alloc] init];
290     });
291     return sharedPasteboard;
292 }
293
294 - (instancetype)init
295 {
296     if (self = [super init]) {
297         _itemProviders = adoptNS([[NSArray alloc] init]);
298         _changeCount = 0;
299         _pendingOperationCount = 0;
300         _supportedTypeIdentifiers = nil;
301         _stagedRegistrationInfoList = nil;
302         _loadResults = { };
303     }
304     return self;
305 }
306
307 - (void)updateSupportedTypeIdentifiers:(NSArray<NSString *> *)types
308 {
309     _supportedTypeIdentifiers = types;
310 }
311
312 - (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index
313 {
314     return [self itemProviderAtIndex:index].registeredTypeIdentifiers ?: @[ ];
315 }
316
317 - (NSArray<NSString *> *)pasteboardTypes
318 {
319     NSMutableSet<NSString *> *allTypes = [NSMutableSet set];
320     NSMutableArray<NSString *> *allTypesInOrder = [NSMutableArray array];
321     for (UIItemProvider *provider in _itemProviders.get()) {
322         for (NSString *typeIdentifier in provider.registeredTypeIdentifiers) {
323             if ([allTypes containsObject:typeIdentifier])
324                 continue;
325
326             [allTypes addObject:typeIdentifier];
327             [allTypesInOrder addObject:typeIdentifier];
328         }
329     }
330     return allTypesInOrder;
331 }
332
333 - (NSArray<__kindof NSItemProvider *> *)itemProviders
334 {
335     return _itemProviders.get();
336 }
337
338 - (void)setItemProviders:(NSArray<__kindof NSItemProvider *> *)itemProviders
339 {
340     itemProviders = itemProviders ?: [NSArray array];
341     if (_itemProviders == itemProviders || [_itemProviders isEqualToArray:itemProviders])
342         return;
343
344     _itemProviders = itemProviders;
345     _changeCount++;
346 }
347
348 - (NSInteger)numberOfItems
349 {
350     return [_itemProviders count];
351 }
352
353 - (NSData *)_preLoadedDataConformingToType:(NSString *)typeIdentifier forItemProviderAtIndex:(NSUInteger)index
354 {
355     if (_loadResults.size() != [_itemProviders count]) {
356         ASSERT_NOT_REACHED();
357         return nil;
358     }
359
360     WebItemProviderLoadResult *loadResult = _loadResults[index].get();
361     for (NSString *loadedType in loadResult.loadedTypeIdentifiers) {
362         if (!UTTypeConformsTo((CFStringRef)loadedType, (CFStringRef)typeIdentifier))
363             continue;
364
365         // We've already loaded data relevant for this UTI type onto disk, so there's no need to ask the UIItemProvider for the same data again.
366         if (NSData *result = [NSData dataWithContentsOfURL:[loadResult fileURLForType:loadedType] options:NSDataReadingMappedIfSafe error:nil])
367             return result;
368     }
369     return nil;
370 }
371
372 - (NSArray *)dataForPasteboardType:(NSString *)pasteboardType inItemSet:(NSIndexSet *)itemSet
373 {
374     auto values = adoptNS([[NSMutableArray alloc] init]);
375     RetainPtr<WebItemProviderPasteboard> retainedSelf = self;
376     [itemSet enumerateIndexesUsingBlock:[retainedSelf, pasteboardType, values] (NSUInteger index, BOOL *) {
377         UIItemProvider *provider = [retainedSelf itemProviderAtIndex:index];
378         if (!provider)
379             return;
380
381         if (NSData *loadedData = [retainedSelf _preLoadedDataConformingToType:pasteboardType forItemProviderAtIndex:index])
382             [values addObject:loadedData];
383     }];
384     return values.autorelease();
385 }
386
387 static NSArray<Class<UIItemProviderReading>> *allLoadableClasses()
388 {
389     return @[ [getUIColorClass() class], [getUIImageClass() class], [NSURL class], [NSString class], [NSAttributedString class] ];
390 }
391
392 static Class classForTypeIdentifier(NSString *typeIdentifier, NSString *&outTypeIdentifierToLoad)
393 {
394     outTypeIdentifierToLoad = typeIdentifier;
395
396     // First, try to load a platform UIItemProviderReading-conformant object as-is.
397     for (Class<UIItemProviderReading> loadableClass in allLoadableClasses()) {
398         if ([[loadableClass readableTypeIdentifiersForItemProvider] containsObject:(NSString *)typeIdentifier])
399             return loadableClass;
400     }
401
402     // If we were unable to load any object, check if the given type identifier is still something
403     // WebKit knows how to handle.
404     if ([typeIdentifier isEqualToString:(NSString *)kUTTypeHTML]) {
405         // Load kUTTypeHTML as a plain text HTML string.
406         outTypeIdentifierToLoad = (NSString *)kUTTypePlainText;
407         return [NSString class];
408     }
409
410     return nil;
411 }
412
413 - (NSArray *)valuesForPasteboardType:(NSString *)pasteboardType inItemSet:(NSIndexSet *)itemSet
414 {
415     auto values = adoptNS([[NSMutableArray alloc] init]);
416     RetainPtr<WebItemProviderPasteboard> retainedSelf = self;
417     [itemSet enumerateIndexesUsingBlock:[retainedSelf, pasteboardType, values] (NSUInteger index, BOOL *) {
418         UIItemProvider *provider = [retainedSelf itemProviderAtIndex:index];
419         if (!provider)
420             return;
421
422         NSString *typeIdentifierToLoad;
423         Class readableClass = classForTypeIdentifier(pasteboardType, typeIdentifierToLoad);
424         if (!readableClass)
425             return;
426
427         NSData *preloadedData = [retainedSelf _preLoadedDataConformingToType:pasteboardType forItemProviderAtIndex:index];
428         if (!preloadedData)
429             return;
430
431         if (id <NSItemProviderReading> readObject = [readableClass objectWithItemProviderData:preloadedData typeIdentifier:(NSString *)typeIdentifierToLoad error:nil])
432             [values addObject:readObject];
433     }];
434
435     return values.autorelease();
436 }
437
438 - (NSInteger)changeCount
439 {
440     return _changeCount;
441 }
442
443 - (NSArray<NSURL *> *)droppedFileURLs
444 {
445     NSMutableArray<NSURL *> *fileURLs = [NSMutableArray array];
446     for (auto loadResult : _loadResults) {
447         if ([loadResult canBeRepresentedAsFileUpload])
448             [fileURLs addObjectsFromArray:[loadResult loadedFileURLs]];
449     }
450     return fileURLs;
451 }
452
453 static BOOL typeConformsToTypes(NSString *type, NSArray *conformsToTypes)
454 {
455     // A type is considered appropriate to load if it conforms to one or more supported types.
456     for (NSString *conformsToType in conformsToTypes) {
457         if (UTTypeConformsTo((CFStringRef)type, (CFStringRef)conformsToType))
458             return YES;
459     }
460     return NO;
461 }
462
463 - (NSInteger)numberOfFiles
464 {
465     NSArray *supportedFileTypes = Pasteboard::supportedFileUploadPasteboardTypes();
466     NSInteger numberOfFiles = 0;
467     for (UIItemProvider *itemProvider in _itemProviders.get()) {
468         if (itemProvider.preferredPresentationStyle == UIPreferredPresentationStyleInline)
469             continue;
470
471         for (NSString *identifier in itemProvider.registeredTypeIdentifiers) {
472             if (!typeConformsToTypes(identifier, supportedFileTypes))
473                 continue;
474             ++numberOfFiles;
475             break;
476         }
477     }
478     return numberOfFiles;
479 }
480
481 static NSURL *linkTemporaryItemProviderFilesToDropStagingDirectory(NSURL *url, NSString *suggestedName, NSString *typeIdentifier)
482 {
483     static NSString *defaultDropFolderName = @"folder";
484     static NSString *defaultDropFileName = @"file";
485     static NSString *dataInteractionDirectoryPrefix = @"data-interaction";
486     if (!url)
487         return nil;
488
489     NSString *temporaryDataInteractionDirectory = WebCore::createTemporaryDirectory(dataInteractionDirectoryPrefix);
490     if (!temporaryDataInteractionDirectory)
491         return nil;
492
493     NSURL *destination = nil;
494     BOOL isFolder = UTTypeConformsTo((CFStringRef)typeIdentifier, kUTTypeFolder);
495     NSFileManager *fileManager = [NSFileManager defaultManager];
496
497     if (!suggestedName)
498         suggestedName = url.lastPathComponent ?: (isFolder ? defaultDropFolderName : defaultDropFileName);
499
500     if (![suggestedName containsString:@"."] && !isFolder)
501         suggestedName = [suggestedName stringByAppendingPathExtension:url.pathExtension];
502
503     destination = [NSURL fileURLWithPath:[temporaryDataInteractionDirectory stringByAppendingPathComponent:suggestedName]];
504     return [fileManager linkItemAtURL:url toURL:destination error:nil] ? destination : nil;
505 }
506
507 - (NSString *)typeIdentifierToLoadForRegisteredTypeIdentfiers:(NSArray<NSString *> *)registeredTypeIdentifiers
508 {
509     NSString *highestFidelityContentType = nil;
510     for (NSString *registeredTypeIdentifier in registeredTypeIdentifiers) {
511         if (typeConformsToTypes(registeredTypeIdentifier, _supportedTypeIdentifiers.get()))
512             return registeredTypeIdentifier;
513
514         if (!highestFidelityContentType && UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, kUTTypeContent))
515             highestFidelityContentType = registeredTypeIdentifier;
516     }
517     return highestFidelityContentType;
518 }
519
520 - (void)doAfterLoadingProvidedContentIntoFileURLs:(WebItemProviderFileLoadBlock)action
521 {
522     [self doAfterLoadingProvidedContentIntoFileURLs:action synchronousTimeout:0];
523 }
524
525 - (void)doAfterLoadingProvidedContentIntoFileURLs:(WebItemProviderFileLoadBlock)action synchronousTimeout:(NSTimeInterval)synchronousTimeout
526 {
527     _loadResults.clear();
528
529     auto changeCountBeforeLoading = _changeCount;
530     auto loadResults = adoptNS([[NSMutableArray alloc] initWithCapacity:[_itemProviders count]]);
531
532     // First, figure out which item providers we want to try and load files from.
533     auto itemProvidersToLoad = adoptNS([[NSMutableArray alloc] init]);
534     auto typeIdentifiersToLoad = adoptNS([[NSMutableArray alloc] init]);
535     auto indicesOfitemProvidersToLoad = adoptNS([[NSMutableArray alloc] init]);
536     RetainPtr<WebItemProviderPasteboard> protectedSelf = self;
537     [_itemProviders enumerateObjectsUsingBlock:[protectedSelf, itemProvidersToLoad, typeIdentifiersToLoad, indicesOfitemProvidersToLoad, loadResults] (UIItemProvider *itemProvider, NSUInteger index, BOOL *) {
538         NSString *typeIdentifierToLoad = [protectedSelf typeIdentifierToLoadForRegisteredTypeIdentfiers:itemProvider.registeredTypeIdentifiers];
539         if (typeIdentifierToLoad) {
540             [itemProvidersToLoad addObject:itemProvider];
541             [typeIdentifiersToLoad addObject:typeIdentifierToLoad];
542             [indicesOfitemProvidersToLoad addObject:@(index)];
543         }
544         [loadResults addObject:[WebItemProviderLoadResult emptyLoadResult]];
545     }];
546
547     if (![itemProvidersToLoad count]) {
548         action(@[ ]);
549         return;
550     }
551
552     auto setFileURLsLock = adoptNS([[NSLock alloc] init]);
553     auto synchronousFileLoadingGroup = adoptOSObject(dispatch_group_create());
554     auto fileLoadingGroup = adoptOSObject(dispatch_group_create());
555     for (NSUInteger index = 0; index < [itemProvidersToLoad count]; ++index) {
556         RetainPtr<UIItemProvider> itemProvider = [itemProvidersToLoad objectAtIndex:index];
557         RetainPtr<NSString> typeIdentifier = [typeIdentifiersToLoad objectAtIndex:index];
558         NSUInteger indexInItemProviderArray = [[indicesOfitemProvidersToLoad objectAtIndex:index] unsignedIntegerValue];
559         RetainPtr<NSString> suggestedName = [itemProvider suggestedName];
560         auto presentationStyle = [itemProvider preferredPresentationStyle];
561         dispatch_group_enter(fileLoadingGroup.get());
562         dispatch_group_enter(synchronousFileLoadingGroup.get());
563         [itemProvider loadFileRepresentationForTypeIdentifier:typeIdentifier.get() completionHandler:[synchronousFileLoadingGroup, setFileURLsLock, indexInItemProviderArray, suggestedName, typeIdentifier, loadResults, fileLoadingGroup, presentationStyle] (NSURL *url, NSError *) {
564             // After executing this completion block, UIKit removes the file at the given URL. However, we need this data to persist longer for the web content process.
565             // To address this, we hard link the given URL to a new temporary file in the temporary directory. This follows the same flow as regular file upload, in
566             // WKFileUploadPanel.mm. The temporary files are cleaned up by the system at a later time.
567             if (NSURL *destination = linkTemporaryItemProviderFilesToDropStagingDirectory(url, suggestedName.get(), typeIdentifier.get())) {
568                 WebItemProviderLoadResult *loadResult = [WebItemProviderLoadResult loadResultWithFileURLMap:@{ typeIdentifier.get() : destination } presentationStyle:presentationStyle];
569                 [setFileURLsLock lock];
570                 [loadResults setObject:loadResult atIndexedSubscript:indexInItemProviderArray];
571                 [setFileURLsLock unlock];
572             }
573             dispatch_group_leave(fileLoadingGroup.get());
574             dispatch_group_leave(synchronousFileLoadingGroup.get());
575         }];
576     }
577
578     RetainPtr<WebItemProviderPasteboard> retainedSelf = self;
579     auto itemLoadCompletion = [retainedSelf, synchronousFileLoadingGroup, fileLoadingGroup, loadResults, completionBlock = makeBlockPtr(action), changeCountBeforeLoading] {
580         if (changeCountBeforeLoading == retainedSelf->_changeCount) {
581             for (WebItemProviderLoadResult *loadResult in loadResults.get())
582                 retainedSelf->_loadResults.append(loadResult);
583         }
584
585         completionBlock([retainedSelf droppedFileURLs]);
586     };
587
588     if (synchronousTimeout > 0 && !dispatch_group_wait(synchronousFileLoadingGroup.get(), dispatch_time(DISPATCH_TIME_NOW, synchronousTimeout * NSEC_PER_SEC))) {
589         itemLoadCompletion();
590         return;
591     }
592
593     dispatch_group_notify(fileLoadingGroup.get(), dispatch_get_main_queue(), itemLoadCompletion);
594 }
595
596 - (UIItemProvider *)itemProviderAtIndex:(NSUInteger)index
597 {
598     return index < [_itemProviders count] ? [_itemProviders objectAtIndex:index] : nil;
599 }
600
601 - (BOOL)hasPendingOperation
602 {
603     return _pendingOperationCount;
604 }
605
606 - (void)incrementPendingOperationCount
607 {
608     _pendingOperationCount++;
609 }
610
611 - (void)decrementPendingOperationCount
612 {
613     _pendingOperationCount--;
614 }
615
616 - (void)enumerateItemProvidersWithBlock:(void (^)(UIItemProvider *itemProvider, NSUInteger index, BOOL *stop))block
617 {
618     [_itemProviders enumerateObjectsUsingBlock:block];
619 }
620
621 - (void)stageRegistrationList:(nullable WebItemProviderRegistrationInfoList *)info
622 {
623     _stagedRegistrationInfoList = info.numberOfItems ? info : nil;
624 }
625
626 - (WebItemProviderRegistrationInfoList *)takeRegistrationList
627 {
628     auto stagedRegistrationInfoList = _stagedRegistrationInfoList;
629     _stagedRegistrationInfoList = nil;
630     return stagedRegistrationInfoList.autorelease();
631 }
632
633 @end
634
635 #endif // ENABLE(DATA_INTERACTION)