51eeddae9b5dcfea95f278ada6bf765ea3c0af79
[WebKit-https.git] / Tools / TestWebKitAPI / ios / DataInteractionSimulator.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 #include "DataInteractionSimulator.h"
28
29 #if ENABLE(DATA_INTERACTION)
30
31 #import "InstanceMethodSwizzler.h"
32 #import "PlatformUtilities.h"
33 #import "UIKitSPI.h"
34
35 #import <UIKit/UIDragInteraction.h>
36 #import <UIKit/UIDragItem.h>
37 #import <UIKit/UIInteraction.h>
38
39 #if USE(APPLE_INTERNAL_SDK)
40 #import <UIKit/UIDragSession.h>
41 #import <UIKit/UIDragging.h>
42 #else
43
44 @protocol UIDraggingInfo <NSObject>
45 @end
46
47 @interface UIDraggingSession : NSObject <UIDraggingInfo>
48 @end
49
50 #endif
51
52 #import <WebKit/WKWebViewPrivate.h>
53 #import <WebKit/_WKFocusedElementInfo.h>
54 #import <WebKit/_WKFormInputSession.h>
55 #import <wtf/RetainPtr.h>
56 #import <wtf/SoftLinking.h>
57
58 SOFT_LINK_FRAMEWORK(UIKit)
59 SOFT_LINK(UIKit, UIApplicationInstantiateSingleton, void, (Class singletonClass), (singletonClass))
60
61 using namespace TestWebKitAPI;
62
63 @implementation WKWebView (DragAndDropTesting)
64
65 - (UIView *)_dragDropInteractionView
66 {
67     return [self valueForKey:@"_currentContentView"];
68 }
69
70 - (id <UIDropInteractionDelegate>)dropInteractionDelegate
71 {
72     return (id <UIDropInteractionDelegate>)self._dragDropInteractionView;
73 }
74
75 - (id <UIDragInteractionDelegate>)dragInteractionDelegate
76 {
77     return (id <UIDragInteractionDelegate>)self._dragDropInteractionView;
78 }
79
80 - (UIDropInteraction *)dropInteraction
81 {
82     UIView *interactionView = self._dragDropInteractionView;
83     for (id <UIInteraction> interaction in interactionView.interactions) {
84         if ([interaction isKindOfClass:[UIDropInteraction class]])
85             return (UIDropInteraction *)interaction;
86     }
87     return nil;
88 }
89
90 - (UIDragInteraction *)dragInteraction
91 {
92     UIView *interactionView = self._dragDropInteractionView;
93     for (id <UIInteraction> interaction in interactionView.interactions) {
94         if ([interaction isKindOfClass:[UIDragInteraction class]])
95             return (UIDragInteraction *)interaction;
96     }
97     return nil;
98 }
99
100 @end
101
102 @implementation MockDragDropSession
103
104 - (instancetype)initWithItems:(NSArray <UIDragItem *>*)items location:(CGPoint)locationInWindow window:(UIWindow *)window allowMove:(BOOL)allowMove
105 {
106     if (self = [super init]) {
107         _mockItems = items;
108         _mockLocationInWindow = locationInWindow;
109         _window = window;
110         _allowMove = allowMove;
111     }
112     return self;
113 }
114
115 - (BOOL)allowsMoveOperation
116 {
117     return _allowMove;
118 }
119
120 - (BOOL)isRestrictedToDraggingApplication
121 {
122     return NO;
123 }
124
125 - (BOOL)hasItemsConformingToTypeIdentifiers:(NSArray<NSString *> *)typeIdentifiers
126 {
127     for (NSString *typeIdentifier in typeIdentifiers) {
128         BOOL hasItemConformingToType = NO;
129         for (UIDragItem *item in self.items)
130             hasItemConformingToType |= [[item.itemProvider registeredTypeIdentifiers] containsObject:typeIdentifier];
131         if (!hasItemConformingToType)
132             return NO;
133     }
134     return YES;
135 }
136
137 - (BOOL)canLoadObjectsOfClass:(Class<UIItemProviderReading>)aClass
138 {
139     for (UIDragItem *item in self.items) {
140         if ([item.itemProvider canLoadObjectOfClass:aClass])
141             return YES;
142     }
143     return NO;
144 }
145
146 - (BOOL)canLoadObjectsOfClasses:(NSArray<Class<UIItemProviderReading>> *)classes
147 {
148     for (Class<UIItemProviderReading> aClass in classes) {
149         BOOL canLoad = NO;
150         for (UIDragItem *item in self.items)
151             canLoad |= [item.itemProvider canLoadObjectOfClass:aClass];
152         if (!canLoad)
153             return NO;
154     }
155     return YES;
156 }
157
158 - (NSArray<UIDragItem *> *)items
159 {
160     return _mockItems.get();
161 }
162
163 - (void)setItems:(NSArray<UIDragItem *> *)items
164 {
165     _mockItems = items;
166 }
167
168 - (void)addItems:(NSArray<UIDragItem *> *)items
169 {
170     if (![items count])
171         return;
172
173     if (![_mockItems count])
174         _mockItems = items;
175     else
176         _mockItems = [_mockItems arrayByAddingObjectsFromArray:items];
177 }
178
179 - (CGPoint)locationInView:(UIView *)view
180 {
181     return [_window convertPoint:_mockLocationInWindow toView:view];
182 }
183
184 @end
185
186 NSString * const DataInteractionEnterEventName = @"dragenter";
187 NSString * const DataInteractionOverEventName = @"dragover";
188 NSString * const DataInteractionPerformOperationEventName = @"drop";
189 NSString * const DataInteractionLeaveEventName = @"dragleave";
190 NSString * const DataInteractionStartEventName = @"dragstart";
191
192 @implementation MockDropSession
193
194 - (instancetype)initWithProviders:(NSArray<UIItemProvider *> *)providers location:(CGPoint)locationInWindow window:(UIWindow *)window allowMove:(BOOL)allowMove
195 {
196     auto items = adoptNS([[NSMutableArray alloc] init]);
197     for (UIItemProvider *itemProvider in providers)
198         [items addObject:[[[UIDragItem alloc] initWithItemProvider:itemProvider] autorelease]];
199
200     return [super initWithItems:items.get() location:locationInWindow window:window allowMove:allowMove];
201 }
202
203 - (UIDraggingSession *)session
204 {
205     return nil;
206 }
207
208 - (BOOL)isLocal
209 {
210     return YES;
211 }
212
213 - (NSProgress *)progress
214 {
215     return [NSProgress discreteProgressWithTotalUnitCount:100];
216 }
217
218 - (void)setProgressIndicatorStyle:(UIDropSessionProgressIndicatorStyle)progressIndicatorStyle
219 {
220 }
221
222 - (UIDropSessionProgressIndicatorStyle)progressIndicatorStyle
223 {
224     return UIDropSessionProgressIndicatorStyleNone;
225 }
226
227 - (NSUInteger)operationMask
228 {
229     return 0;
230 }
231
232 - (id <UIDragSession>)localDragSession
233 {
234     return nil;
235 }
236
237 - (BOOL)hasItemsConformingToTypeIdentifier:(NSString *)typeIdentifier
238 {
239     ASSERT_NOT_REACHED();
240     return NO;
241 }
242
243 - (BOOL)canCreateItemsOfClass:(Class<UIItemProviderReading>)aClass
244 {
245     ASSERT_NOT_REACHED();
246     return NO;
247 }
248
249 - (NSProgress *)loadObjectsOfClass:(Class<NSItemProviderReading>)aClass completion:(void(^)(NSArray<__kindof id <NSItemProviderReading>> *objects))completion
250 {
251     ASSERT_NOT_REACHED();
252     return nil;
253 }
254
255 @end
256
257 @implementation MockDragSession
258
259 - (instancetype)initWithWindow:(UIWindow *)window allowMove:(BOOL)allowMove
260 {
261     return [super initWithItems:@[ ] location:CGPointZero window:window allowMove:allowMove];
262 }
263
264 - (NSUInteger)localOperationMask
265 {
266     ASSERT_NOT_REACHED();
267     return 0;
268 }
269
270 - (NSUInteger)externalOperationMask
271 {
272     ASSERT_NOT_REACHED();
273     return 0;
274 }
275
276 - (id)session
277 {
278     return nil;
279 }
280
281 @end
282
283 static double progressIncrementStep = 0.033;
284 static double progressTimeStep = 0.016;
285 static NSString *TestWebKitAPISimulateCancelAllTouchesNotificationName = @"TestWebKitAPISimulateCancelAllTouchesNotificationName";
286
287 static NSArray *dataInteractionEventNames()
288 {
289     static NSArray *eventNames = nil;
290     static dispatch_once_t onceToken;
291     dispatch_once(&onceToken, ^() {
292         eventNames = @[ DataInteractionEnterEventName, DataInteractionOverEventName, DataInteractionPerformOperationEventName, DataInteractionLeaveEventName, DataInteractionStartEventName ];
293     });
294     return eventNames;
295 }
296
297 @interface DataInteractionSimulatorApplication : UIApplication
298 @end
299
300 @implementation DataInteractionSimulatorApplication
301 - (void)_cancelAllTouches
302 {
303     [[NSNotificationCenter defaultCenter] postNotificationName:TestWebKitAPISimulateCancelAllTouchesNotificationName object:nil];
304 }
305 @end
306
307 @implementation DataInteractionSimulator
308
309 - (instancetype)initWithWebView:(TestWKWebView *)webView
310 {
311     if (self = [super init]) {
312         _webView = webView;
313         _shouldEnsureUIApplication = NO;
314         _shouldAllowMoveOperation = YES;
315         _isDoneWaitingForInputSession = true;
316         [_webView setUIDelegate:self];
317         [_webView _setInputDelegate:self];
318     }
319     return self;
320 }
321
322 - (void)dealloc
323 {
324     if ([_webView UIDelegate] == self)
325         [_webView setUIDelegate:nil];
326
327     if ([_webView _inputDelegate] == self)
328         [_webView _setInputDelegate:nil];
329
330     [super dealloc];
331 }
332
333 - (void)_resetSimulatedState
334 {
335     _phase = DataInteractionBeginning;
336     _currentProgress = 0;
337     _isDoneWithCurrentRun = false;
338     _observedEventNames = adoptNS([[NSMutableArray alloc] init]);
339     _finalSelectionRects = @[ ];
340     _dragSession = nil;
341     _dropSession = nil;
342     _shouldPerformOperation = NO;
343     _lastKnownDragCaretRect = CGRectZero;
344     _remainingAdditionalItemRequestLocationsByProgress = nil;
345     _queuedAdditionalItemRequestLocations = adoptNS([[NSMutableArray alloc] init]);
346 }
347
348 - (NSArray *)observedEventNames
349 {
350     return _observedEventNames.get();
351 }
352
353 - (void)simulateAllTouchesCanceled:(NSNotification *)notification
354 {
355     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_advanceProgress) object:nil];
356     _phase = DataInteractionCancelled;
357     _currentProgress = 1;
358     _isDoneWithCurrentRun = true;
359     if (_dragSession)
360         [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] session:_dragSession.get() didEndWithOperation:UIDropOperationCopy];
361 }
362
363 - (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation
364 {
365     [self runFrom:startLocation to:endLocation additionalItemRequestLocations:nil];
366 }
367
368 - (void)runFrom:(CGPoint)startLocation to:(CGPoint)endLocation additionalItemRequestLocations:(ProgressToCGPointValueMap)additionalItemRequestLocations
369 {
370     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
371     [defaultCenter addObserver:self selector:@selector(simulateAllTouchesCanceled:) name:TestWebKitAPISimulateCancelAllTouchesNotificationName object:nil];
372
373     if (_shouldEnsureUIApplication)
374         UIApplicationInstantiateSingleton([DataInteractionSimulatorApplication class]);
375
376     [self _resetSimulatedState];
377
378     if (additionalItemRequestLocations)
379         _remainingAdditionalItemRequestLocationsByProgress = adoptNS([additionalItemRequestLocations mutableCopy]);
380
381     RetainPtr<DataInteractionSimulator> strongSelf = self;
382     for (NSString *eventName in dataInteractionEventNames()) {
383         DataInteractionSimulator *weakSelf = strongSelf.get();
384         [weakSelf->_webView performAfterReceivingMessage:eventName action:^() {
385             [weakSelf->_observedEventNames addObject:eventName];
386         }];
387     }
388
389     _startLocation = startLocation;
390     _endLocation = endLocation;
391
392     if (self.externalItemProviders.count) {
393         _dropSession = adoptNS([[MockDropSession alloc] initWithProviders:self.externalItemProviders location:_startLocation window:[_webView window] allowMove:self.shouldAllowMoveOperation]);
394         _phase = DataInteractionBegan;
395         [self _advanceProgress];
396     } else {
397         _dragSession = adoptNS([[MockDragSession alloc] initWithWindow:[_webView window] allowMove:self.shouldAllowMoveOperation]);
398         [_dragSession setMockLocationInWindow:_startLocation];
399         [(id <UIDragInteractionDelegate_ForWebKitOnly>)[_webView dragInteractionDelegate] _dragInteraction:[_webView dragInteraction] prepareForSession:_dragSession.get() completion:^() {
400             DataInteractionSimulator *weakSelf = strongSelf.get();
401             if (weakSelf->_phase == DataInteractionCancelled)
402                 return;
403
404             weakSelf->_phase = DataInteractionBeginning;
405             [weakSelf _advanceProgress];
406         }];
407     }
408
409     Util::run(&_isDoneWithCurrentRun);
410     [_webView clearMessageHandlers:dataInteractionEventNames()];
411     _finalSelectionRects = [_webView selectionRectsAfterPresentationUpdate];
412
413     [defaultCenter removeObserver:self];
414 }
415
416 - (NSArray *)finalSelectionRects
417 {
418     return _finalSelectionRects.get();
419 }
420
421 - (void)_concludeDataInteractionAndPerformOperationIfNecessary
422 {
423     _lastKnownDragCaretRect = [_webView _dragCaretRect];
424     if (_shouldPerformOperation) {
425         [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] performDrop:_dropSession.get()];
426         _phase = DataInteractionPerforming;
427     } else {
428         _isDoneWithCurrentRun = YES;
429         _phase = DataInteractionCancelled;
430     }
431
432     [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidEnd:_dropSession.get()];
433
434     if (_dragSession)
435         [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] session:_dragSession.get() didEndWithOperation:UIDropOperationCopy];
436 }
437
438 - (void)_enqueuePendingAdditionalItemRequestLocations
439 {
440     NSMutableArray *progressValuesToRemove = [NSMutableArray array];
441     for (NSNumber *progressValue in _remainingAdditionalItemRequestLocationsByProgress.get()) {
442         double progress = progressValue.doubleValue;
443         if (progress > _currentProgress)
444             continue;
445         [progressValuesToRemove addObject:progressValue];
446         [_queuedAdditionalItemRequestLocations addObject:[_remainingAdditionalItemRequestLocationsByProgress objectForKey:progressValue]];
447     }
448
449     for (NSNumber *progressToRemove in progressValuesToRemove)
450         [_remainingAdditionalItemRequestLocationsByProgress removeObjectForKey:progressToRemove];
451 }
452
453 - (BOOL)_sendQueuedAdditionalItemRequest
454 {
455     if (![_queuedAdditionalItemRequestLocations count])
456         return NO;
457
458     RetainPtr<NSValue> requestLocationValue = [_queuedAdditionalItemRequestLocations objectAtIndex:0];
459     [_queuedAdditionalItemRequestLocations removeObjectAtIndex:0];
460
461     auto requestLocation = [[_webView window] convertPoint:[requestLocationValue CGPointValue] toView:_webView.get()];
462     [(id <UIDragInteractionDelegate_Proposed_SPI_33146803>)[_webView dragInteractionDelegate] _dragInteraction:[_webView dragInteraction] itemsForAddingToSession:_dragSession.get() withTouchAtPoint:requestLocation completion:[dragSession = _dragSession, dropSession = _dropSession] (NSArray *items) {
463         [dragSession addItems:items];
464         [dropSession addItems:items];
465     }];
466     return YES;
467 }
468
469 - (void)_advanceProgress
470 {
471     [self _enqueuePendingAdditionalItemRequestLocations];
472     if ([self _sendQueuedAdditionalItemRequest]) {
473         [self _scheduleAdvanceProgress];
474         return;
475     }
476
477     _lastKnownDragCaretRect = [_webView _dragCaretRect];
478     _currentProgress += progressIncrementStep;
479     CGPoint locationInWindow = self._currentLocation;
480     [_dragSession setMockLocationInWindow:locationInWindow];
481     [_dropSession setMockLocationInWindow:locationInWindow];
482
483     if (_currentProgress >= 1) {
484         _currentProgress = 1;
485         [self _concludeDataInteractionAndPerformOperationIfNecessary];
486         return;
487     }
488
489     switch (_phase) {
490     case DataInteractionBeginning: {
491         NSMutableArray<UIItemProvider *> *itemProviders = [NSMutableArray array];
492         NSArray *items = [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] itemsForBeginningSession:_dragSession.get()];
493         if (!items.count) {
494             _phase = DataInteractionCancelled;
495             _currentProgress = 1;
496             _isDoneWithCurrentRun = true;
497             return;
498         }
499
500         for (UIDragItem *item in items) {
501             [itemProviders addObject:item.itemProvider];
502             UITargetedDragPreview *liftPreview = [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] previewForLiftingItem:item session:_dragSession.get()];
503             EXPECT_TRUE(!!liftPreview);
504         }
505
506         _dropSession = adoptNS([[MockDropSession alloc] initWithProviders:itemProviders location:self._currentLocation window:[_webView window] allowMove:self.shouldAllowMoveOperation]);
507         [_dragSession setItems:items];
508         _sourceItemProviders = itemProviders;
509         if (self.showCustomActionSheetBlock) {
510             // Defer progress until the custom action sheet is dismissed.
511             auto startLocationInView = [[_webView window] convertPoint:_startLocation toView:_webView.get()];
512             [_webView _simulateLongPressActionAtLocation:startLocationInView];
513             return;
514         }
515
516         [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] sessionWillBegin:_dragSession.get()];
517
518         RetainPtr<WKWebView> retainedWebView = _webView;
519         dispatch_async(dispatch_get_main_queue(), ^() {
520             [retainedWebView resignFirstResponder];
521         });
522
523         _phase = DataInteractionBegan;
524         break;
525     }
526     case DataInteractionBegan:
527         [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidEnter:_dropSession.get()];
528         _phase = DataInteractionEntered;
529         break;
530     case DataInteractionEntered: {
531         auto operation = static_cast<UIDropOperation>([[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidUpdate:_dropSession.get()].operation);
532         _shouldPerformOperation = operation == UIDropOperationCopy || ([_dropSession allowsMoveOperation] && operation != UIDropOperationCancel);
533         break;
534     }
535     default:
536         break;
537     }
538
539     [self _scheduleAdvanceProgress];
540 }
541
542 - (CGPoint)_currentLocation
543 {
544     CGFloat distanceX = _endLocation.x - _startLocation.x;
545     CGFloat distanceY = _endLocation.y - _startLocation.y;
546     return CGPointMake(_startLocation.x + _currentProgress * distanceX, _startLocation.y + _currentProgress * distanceY);
547 }
548
549 - (void)_scheduleAdvanceProgress
550 {
551     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_advanceProgress) object:nil];
552     [self performSelector:@selector(_advanceProgress) withObject:nil afterDelay:progressTimeStep];
553 }
554
555 - (NSArray *)sourceItemProviders
556 {
557     return _sourceItemProviders.get();
558 }
559
560 - (NSArray *)externalItemProviders
561 {
562     return _externalItemProviders.get();
563 }
564
565 - (void)setExternalItemProviders:(NSArray *)externalItemProviders
566 {
567     _externalItemProviders = adoptNS([externalItemProviders copy]);
568 }
569
570 - (DataInteractionPhase)phase
571 {
572     return _phase;
573 }
574
575 - (CGRect)lastKnownDragCaretRect
576 {
577     return _lastKnownDragCaretRect;
578 }
579
580 - (void)waitForInputSession
581 {
582     _isDoneWaitingForInputSession = false;
583
584     // Waiting for an input session implies that we should allow input sessions to begin.
585     self.allowsFocusToStartInputSession = YES;
586
587     Util::run(&_isDoneWaitingForInputSession);
588 }
589
590 #pragma mark - WKUIDelegatePrivate
591
592 - (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray<UIItemProvider *> *)itemProviders
593 {
594     _isDoneWithCurrentRun = true;
595
596     if (self.dataInteractionOperationCompletionBlock)
597         self.dataInteractionOperationCompletionBlock(handled, itemProviders);
598 }
599
600 - (NSUInteger)_webView:(WKWebView *)webView willUpdateDataInteractionOperationToOperation:(NSUInteger)operation forSession:(id)session
601 {
602     return self.overrideDataInteractionOperationBlock ? self.overrideDataInteractionOperationBlock(operation, session) : operation;
603 }
604
605 - (NSArray *)_webView:(WKWebView *)webView adjustedDataInteractionItemProvidersForItemProvider:(UIItemProvider *)itemProvider representingObjects:(NSArray *)representingObjects additionalData:(NSDictionary *)additionalData
606 {
607     return self.convertItemProvidersBlock ? self.convertItemProvidersBlock(itemProvider, representingObjects, additionalData) : @[ itemProvider ];
608 }
609
610 - (BOOL)_webView:(WKWebView *)webView showCustomSheetForElement:(_WKActivatedElementInfo *)element
611 {
612     if (!self.showCustomActionSheetBlock)
613         return NO;
614
615     RetainPtr<DataInteractionSimulator> strongSelf = self;
616     dispatch_async(dispatch_get_main_queue(), ^() {
617         DataInteractionSimulator *weakSelf = strongSelf.get();
618         [[weakSelf->_webView dragInteractionDelegate] dragInteraction:[weakSelf->_webView dragInteraction] sessionWillBegin:weakSelf->_dragSession.get()];
619         weakSelf->_phase = DataInteractionBegan;
620         [weakSelf _scheduleAdvanceProgress];
621     });
622
623     return self.showCustomActionSheetBlock(element);
624 }
625
626 - (NSArray<UIDragItem *> *)_webView:(WKWebView *)webView willPerformDropWithSession:(id <UIDropSession>)session
627 {
628     return self.overridePerformDropBlock ? self.overridePerformDropBlock(session) : session.items;
629 }
630
631 #pragma mark - _WKInputDelegate
632
633 - (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info
634 {
635     return _allowsFocusToStartInputSession;
636 }
637
638 - (void)_webView:(WKWebView *)webView didStartInputSession:(id <_WKFormInputSession>)inputSession
639 {
640     _isDoneWaitingForInputSession = true;
641 }
642
643 @end
644
645 #endif // ENABLE(DATA_INTERACTION)