[Extra zoom mode] Form control values are stale after dismissing and representing...
[WebKit-https.git] / Source / WebKit / UIProcess / ios / WKContentViewInteraction.mm
1 /*
2  * Copyright (C) 2012-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 #import "config.h"
27 #import "WKContentViewInteraction.h"
28
29 #if PLATFORM(IOS)
30
31 #import "APIUIClient.h"
32 #import "EditingRange.h"
33 #import "InputViewUpdateDeferrer.h"
34 #import "Logging.h"
35 #import "ManagedConfigurationSPI.h"
36 #import "NativeWebKeyboardEvent.h"
37 #import "NativeWebTouchEvent.h"
38 #import "RemoteLayerTreeDrawingAreaProxy.h"
39 #import "SmartMagnificationController.h"
40 #import "TextInputSPI.h"
41 #import "UIKitSPI.h"
42 #import "WKActionSheetAssistant.h"
43 #import "WKDatePickerViewController.h"
44 #import "WKError.h"
45 #import "WKFocusedFormControlViewController.h"
46 #import "WKFormInputControl.h"
47 #import "WKFormSelectControl.h"
48 #import "WKImagePreviewViewController.h"
49 #import "WKInspectorNodeSearchGestureRecognizer.h"
50 #import "WKNSURLExtras.h"
51 #import "WKNumberPadViewController.h"
52 #import "WKPreviewActionItemIdentifiers.h"
53 #import "WKPreviewActionItemInternal.h"
54 #import "WKPreviewElementInfoInternal.h"
55 #import "WKSelectMenuViewController.h"
56 #import "WKTextInputViewController.h"
57 #import "WKTimePickerViewController.h"
58 #import "WKUIDelegatePrivate.h"
59 #import "WKWebViewConfiguration.h"
60 #import "WKWebViewConfigurationPrivate.h"
61 #import "WKWebViewInternal.h"
62 #import "WKWebViewPrivate.h"
63 #import "WeakObjCPtr.h"
64 #import "WebEvent.h"
65 #import "WebIOSEventFactory.h"
66 #import "WebPageMessages.h"
67 #import "WebProcessProxy.h"
68 #import "_WKActivatedElementInfoInternal.h"
69 #import "_WKElementAction.h"
70 #import "_WKFocusedElementInfo.h"
71 #import "_WKFormInputSession.h"
72 #import "_WKInputDelegate.h"
73 #import <CoreText/CTFont.h>
74 #import <CoreText/CTFontDescriptor.h>
75 #import <MobileCoreServices/UTCoreTypes.h>
76 #import <WebCore/Color.h>
77 #import <WebCore/DataDetection.h>
78 #import <WebCore/FloatQuad.h>
79 #import <WebCore/LocalizedStrings.h>
80 #import <WebCore/NotImplemented.h>
81 #import <WebCore/Pasteboard.h>
82 #import <WebCore/Path.h>
83 #import <WebCore/PathUtilities.h>
84 #import <WebCore/PromisedBlobInfo.h>
85 #import <WebCore/RuntimeApplicationChecks.h>
86 #import <WebCore/Scrollbar.h>
87 #import <WebCore/TextIndicator.h>
88 #import <WebCore/VisibleSelection.h>
89 #import <WebCore/WebCoreNSURLExtras.h>
90 #import <WebCore/WebEvent.h>
91 #import <WebKit/WebSelectionRect.h> // FIXME: WK2 should not include WebKit headers!
92 #import <pal/spi/cg/CoreGraphicsSPI.h>
93 #import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
94 #import <pal/spi/ios/DataDetectorsUISPI.h>
95 #import <wtf/Optional.h>
96 #import <wtf/RetainPtr.h>
97 #import <wtf/SetForScope.h>
98 #import <wtf/SoftLinking.h>
99 #import <wtf/text/TextStream.h>
100
101 #if ENABLE(DRAG_SUPPORT)
102 #import <WebCore/DragData.h>
103 #import <WebCore/DragItem.h>
104 #import <WebCore/PlatformPasteboard.h>
105 #import <WebCore/WebItemProviderPasteboard.h>
106 #endif
107
108 @interface UIEvent(UIEventInternal)
109 @property (nonatomic, assign) UIKeyboardInputFlags _inputFlags;
110 @end
111
112 @interface WKWebEvent : WebEvent
113 @property (nonatomic, retain) UIEvent *uiEvent;
114 @end
115
116 @implementation WKWebEvent
117
118 - (void)dealloc
119 {
120     [_uiEvent release];
121     [super dealloc];
122 }
123
124 @end
125
126 #if ENABLE(EXTRA_ZOOM_MODE)
127
128 @interface WKContentView (ExtraZoomMode) <WKTextFormControlViewControllerDelegate, WKFocusedFormControlViewControllerDelegate, WKSelectMenuViewControllerDelegate>
129 @end
130
131 #endif
132
133 using namespace WebCore;
134 using namespace WebKit;
135
136 namespace WebKit {
137
138 WKSelectionDrawingInfo::WKSelectionDrawingInfo()
139     : type(SelectionType::None)
140 {
141 }
142
143 WKSelectionDrawingInfo::WKSelectionDrawingInfo(const EditorState& editorState)
144 {
145     if (editorState.selectionIsNone) {
146         type = SelectionType::None;
147         return;
148     }
149
150     if (editorState.isInPlugin) {
151         type = SelectionType::Plugin;
152         return;
153     }
154
155     type = SelectionType::Range;
156     auto& postLayoutData = editorState.postLayoutData();
157     caretRect = postLayoutData.caretRectAtEnd;
158     selectionRects = postLayoutData.selectionRects;
159 }
160
161 inline bool operator==(const WKSelectionDrawingInfo& a, const WKSelectionDrawingInfo& b)
162 {
163     if (a.type != b.type)
164         return false;
165
166     if (a.type == WKSelectionDrawingInfo::SelectionType::Range) {
167         if (a.caretRect != b.caretRect)
168             return false;
169
170         if (a.selectionRects.size() != b.selectionRects.size())
171             return false;
172
173         for (unsigned i = 0; i < a.selectionRects.size(); ++i) {
174             if (a.selectionRects[i].rect() != b.selectionRects[i].rect())
175                 return false;
176         }
177     }
178
179     return true;
180 }
181
182 inline bool operator!=(const WKSelectionDrawingInfo& a, const WKSelectionDrawingInfo& b)
183 {
184     return !(a == b);
185 }
186
187 static TextStream& operator<<(TextStream& stream, WKSelectionDrawingInfo::SelectionType type)
188 {
189     switch (type) {
190     case WKSelectionDrawingInfo::SelectionType::None: stream << "none"; break;
191     case WKSelectionDrawingInfo::SelectionType::Plugin: stream << "plugin"; break;
192     case WKSelectionDrawingInfo::SelectionType::Range: stream << "range"; break;
193     }
194     
195     return stream;
196 }
197
198 TextStream& operator<<(TextStream& stream, const WKSelectionDrawingInfo& info)
199 {
200     TextStream::GroupScope group(stream);
201     stream.dumpProperty("type", info.type);
202     stream.dumpProperty("caret rect", info.caretRect);
203     stream.dumpProperty("selection rects", info.selectionRects);
204     return stream;
205 }
206
207 } // namespace WebKit
208
209 static const float highlightDelay = 0.12;
210 static const float tapAndHoldDelay  = 0.75;
211 const CGFloat minimumTapHighlightRadius = 2.0;
212
213 @interface WKTextRange : UITextRange {
214     CGRect _startRect;
215     CGRect _endRect;
216     BOOL _isNone;
217     BOOL _isRange;
218     BOOL _isEditable;
219     NSArray *_selectionRects;
220     NSUInteger _selectedTextLength;
221 }
222 @property (nonatomic) CGRect startRect;
223 @property (nonatomic) CGRect endRect;
224 @property (nonatomic) BOOL isNone;
225 @property (nonatomic) BOOL isRange;
226 @property (nonatomic) BOOL isEditable;
227 @property (nonatomic) NSUInteger selectedTextLength;
228 @property (copy, nonatomic) NSArray *selectionRects;
229
230 + (WKTextRange *)textRangeWithState:(BOOL)isNone isRange:(BOOL)isRange isEditable:(BOOL)isEditable startRect:(CGRect)startRect endRect:(CGRect)endRect selectionRects:(NSArray *)selectionRects selectedTextLength:(NSUInteger)selectedTextLength;
231
232 @end
233
234 @interface WKTextPosition : UITextPosition {
235     CGRect _positionRect;
236 }
237
238 @property (nonatomic) CGRect positionRect;
239
240 + (WKTextPosition *)textPositionWithRect:(CGRect)positionRect;
241
242 @end
243
244 @interface WKTextSelectionRect : UITextSelectionRect
245
246 @property (nonatomic, retain) WebSelectionRect *webRect;
247
248 + (NSArray *)textSelectionRectsWithWebRects:(NSArray *)webRects;
249
250 @end
251
252 @interface WKAutocorrectionRects : UIWKAutocorrectionRects
253 + (WKAutocorrectionRects *)autocorrectionRectsWithRects:(CGRect)firstRect lastRect:(CGRect)lastRect;
254 @end
255
256 @interface WKAutocorrectionContext : UIWKAutocorrectionContext
257 + (WKAutocorrectionContext *)autocorrectionContextWithData:(NSString *)beforeText markedText:(NSString *)markedText selectedText:(NSString *)selectedText afterText:(NSString *)afterText selectedRangeInMarkedText:(NSRange)range;
258 @end
259
260 @interface UITextInteractionAssistant (UITextInteractionAssistant_Internal)
261 // FIXME: this needs to be moved from the internal header to the private.
262 - (id)initWithView:(UIResponder <UITextInput> *)view;
263 - (void)selectWord;
264 - (void)scheduleReanalysis;
265 @end
266
267 @interface UIView (UIViewInternalHack)
268 + (BOOL)_addCompletion:(void(^)(BOOL))completion;
269 @end
270
271 @protocol UISelectionInteractionAssistant;
272
273 @interface WKFocusedElementInfo : NSObject <_WKFocusedElementInfo>
274 - (instancetype)initWithAssistedNodeInformation:(const AssistedNodeInformation&)information isUserInitiated:(BOOL)isUserInitiated userObject:(NSObject <NSSecureCoding> *)userObject;
275 @end
276
277 @interface WKFormInputSession : NSObject <_WKFormInputSession>
278
279 - (instancetype)initWithContentView:(WKContentView *)view focusedElementInfo:(WKFocusedElementInfo *)elementInfo;
280 - (void)invalidate;
281
282 @end
283
284 @implementation WKFormInputSession {
285     WKContentView *_contentView;
286     RetainPtr<WKFocusedElementInfo> _focusedElementInfo;
287     RetainPtr<UIView> _customInputView;
288     RetainPtr<NSArray<UITextSuggestion *>> _suggestions;
289     BOOL _accessoryViewShouldNotShow;
290     BOOL _forceSecureTextEntry;
291 }
292
293 - (instancetype)initWithContentView:(WKContentView *)view focusedElementInfo:(WKFocusedElementInfo *)elementInfo
294 {
295     if (!(self = [super init]))
296         return nil;
297
298     _contentView = view;
299     _focusedElementInfo = elementInfo;
300
301     return self;
302 }
303
304 - (id <_WKFocusedElementInfo>)focusedElementInfo
305 {
306     return _focusedElementInfo.get();
307 }
308
309 - (NSObject <NSSecureCoding> *)userObject
310 {
311     return [_focusedElementInfo userObject];
312 }
313
314 - (BOOL)isValid
315 {
316     return _contentView != nil;
317 }
318
319 - (NSString *)accessoryViewCustomButtonTitle
320 {
321     return [[[_contentView formAccessoryView] _autofill] title];
322 }
323
324 - (void)setAccessoryViewCustomButtonTitle:(NSString *)title
325 {
326     if (title.length)
327         [[_contentView formAccessoryView] showAutoFillButtonWithTitle:title];
328     else
329         [[_contentView formAccessoryView] hideAutoFillButton];
330     if (currentUserInterfaceIdiomIsPad())
331         [_contentView reloadInputViews];
332 }
333
334 - (BOOL)accessoryViewShouldNotShow
335 {
336     return _accessoryViewShouldNotShow;
337 }
338
339 - (void)setAccessoryViewShouldNotShow:(BOOL)accessoryViewShouldNotShow
340 {
341     if (_accessoryViewShouldNotShow == accessoryViewShouldNotShow)
342         return;
343
344     _accessoryViewShouldNotShow = accessoryViewShouldNotShow;
345     [_contentView reloadInputViews];
346 }
347
348 - (BOOL)forceSecureTextEntry
349 {
350     return _forceSecureTextEntry;
351 }
352
353 - (void)setForceSecureTextEntry:(BOOL)forceSecureTextEntry
354 {
355     if (_forceSecureTextEntry == forceSecureTextEntry)
356         return;
357
358     _forceSecureTextEntry = forceSecureTextEntry;
359     [_contentView reloadInputViews];
360 }
361
362 - (UIView *)customInputView
363 {
364     return _customInputView.get();
365 }
366
367 - (void)setCustomInputView:(UIView *)customInputView
368 {
369     if (customInputView == _customInputView)
370         return;
371
372     _customInputView = customInputView;
373     [_contentView reloadInputViews];
374 }
375
376 - (NSArray<UITextSuggestion *> *)suggestions
377 {
378     return _suggestions.get();
379 }
380
381 - (void)setSuggestions:(NSArray<UITextSuggestion *> *)suggestions
382 {
383     id <UITextInputSuggestionDelegate> suggestionDelegate = (id <UITextInputSuggestionDelegate>)_contentView.inputDelegate;
384     _suggestions = adoptNS([suggestions copy]);
385     [suggestionDelegate setSuggestions:suggestions];
386 }
387
388 - (void)invalidate
389 {
390     id <UITextInputSuggestionDelegate> suggestionDelegate = (id <UITextInputSuggestionDelegate>)_contentView.inputDelegate;
391     [suggestionDelegate setSuggestions:nil];
392     _contentView = nil;
393 }
394
395 @end
396
397 @implementation WKFocusedElementInfo {
398     WKInputType _type;
399     RetainPtr<NSString> _value;
400     BOOL _isUserInitiated;
401     RetainPtr<NSObject <NSSecureCoding>> _userObject;
402 }
403
404 - (instancetype)initWithAssistedNodeInformation:(const AssistedNodeInformation&)information isUserInitiated:(BOOL)isUserInitiated userObject:(NSObject <NSSecureCoding> *)userObject
405 {
406     if (!(self = [super init]))
407         return nil;
408
409     switch (information.elementType) {
410     case WebKit::InputType::ContentEditable:
411         _type = WKInputTypeContentEditable;
412         break;
413     case WebKit::InputType::Text:
414         _type = WKInputTypeText;
415         break;
416     case WebKit::InputType::Password:
417         _type = WKInputTypePassword;
418         break;
419     case WebKit::InputType::TextArea:
420         _type = WKInputTypeTextArea;
421         break;
422     case WebKit::InputType::Search:
423         _type = WKInputTypeSearch;
424         break;
425     case WebKit::InputType::Email:
426         _type = WKInputTypeEmail;
427         break;
428     case WebKit::InputType::URL:
429         _type = WKInputTypeURL;
430         break;
431     case WebKit::InputType::Phone:
432         _type = WKInputTypePhone;
433         break;
434     case WebKit::InputType::Number:
435         _type = WKInputTypeNumber;
436         break;
437     case WebKit::InputType::NumberPad:
438         _type = WKInputTypeNumberPad;
439         break;
440     case WebKit::InputType::Date:
441         _type = WKInputTypeDate;
442         break;
443     case WebKit::InputType::DateTime:
444         _type = WKInputTypeDateTime;
445         break;
446     case WebKit::InputType::DateTimeLocal:
447         _type = WKInputTypeDateTimeLocal;
448         break;
449     case WebKit::InputType::Month:
450         _type = WKInputTypeMonth;
451         break;
452     case WebKit::InputType::Week:
453         _type = WKInputTypeWeek;
454         break;
455     case WebKit::InputType::Time:
456         _type = WKInputTypeTime;
457         break;
458     case WebKit::InputType::Select:
459         _type = WKInputTypeSelect;
460         break;
461     case WebKit::InputType::None:
462         _type = WKInputTypeNone;
463         break;
464     }
465     _value = information.value;
466     _isUserInitiated = isUserInitiated;
467     _userObject = userObject;
468     return self;
469 }
470
471 - (WKInputType)type
472 {
473     return _type;
474 }
475
476 - (NSString *)value
477 {
478     return _value.get();
479 }
480
481 - (BOOL)isUserInitiated
482 {
483     return _isUserInitiated;
484 }
485
486 - (NSObject <NSSecureCoding> *)userObject
487 {
488     return _userObject.get();
489 }
490 @end
491
492 #if ENABLE(DRAG_SUPPORT)
493
494 @interface WKDragSessionContext : NSObject
495 - (void)addTemporaryDirectory:(NSString *)temporaryDirectory;
496 - (void)cleanUpTemporaryDirectories;
497 @end
498
499 @implementation WKDragSessionContext {
500     RetainPtr<NSMutableArray> _temporaryDirectories;
501 }
502
503 - (void)addTemporaryDirectory:(NSString *)temporaryDirectory
504 {
505     if (!_temporaryDirectories)
506         _temporaryDirectories = adoptNS([NSMutableArray new]);
507     [_temporaryDirectories addObject:temporaryDirectory];
508 }
509
510 - (void)cleanUpTemporaryDirectories
511 {
512     for (NSString *directory in _temporaryDirectories.get()) {
513         NSError *error = nil;
514         [[NSFileManager defaultManager] removeItemAtPath:directory error:&error];
515         RELEASE_LOG(DragAndDrop, "Removed temporary download directory: %@ with error: %@", directory, error);
516     }
517     _temporaryDirectories = nil;
518 }
519
520 @end
521
522 static WKDragSessionContext *existingLocalDragSessionContext(id <UIDragSession> session)
523 {
524     return [session.localContext isKindOfClass:[WKDragSessionContext class]] ? (WKDragSessionContext *)session.localContext : nil;
525 }
526
527 static WKDragSessionContext *ensureLocalDragSessionContext(id <UIDragSession> session)
528 {
529     if (WKDragSessionContext *existingContext = existingLocalDragSessionContext(session))
530         return existingContext;
531
532     if (session.localContext) {
533         RELEASE_LOG(DragAndDrop, "Overriding existing local context: %@ on session: %@", session.localContext, session);
534         ASSERT_NOT_REACHED();
535     }
536
537     session.localContext = [[[WKDragSessionContext alloc] init] autorelease];
538     return (WKDragSessionContext *)session.localContext;
539 }
540
541 #endif // ENABLE(DRAG_SUPPORT)
542
543 @interface WKContentView (WKInteractionPrivate)
544 - (void)accessibilitySpeakSelectionSetContent:(NSString *)string;
545 - (NSArray *)webSelectionRectsForSelectionRects:(const Vector<WebCore::SelectionRect>&)selectionRects;
546 - (void)_accessibilityDidGetSelectionRects:(NSArray *)selectionRects withGranularity:(UITextGranularity)granularity atOffset:(NSInteger)offset;
547 @end
548
549 @implementation WKContentView (WKInteraction)
550
551 - (void)_createAndConfigureDoubleTapGestureRecognizer
552 {
553     _doubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_doubleTapRecognized:)]);
554     [_doubleTapGestureRecognizer setNumberOfTapsRequired:2];
555     [_doubleTapGestureRecognizer setDelegate:self];
556     [self addGestureRecognizer:_doubleTapGestureRecognizer.get()];
557     [_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTapGestureRecognizer.get()];
558 }
559
560 - (void)_createAndConfigureLongPressGestureRecognizer
561 {
562     _longPressGestureRecognizer = adoptNS([[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_longPressRecognized:)]);
563     [_longPressGestureRecognizer setDelay:tapAndHoldDelay];
564     [_longPressGestureRecognizer setDelegate:self];
565     [_longPressGestureRecognizer _setRequiresQuietImpulse:YES];
566     [self addGestureRecognizer:_longPressGestureRecognizer.get()];
567 }
568
569 - (void)setupInteraction
570 {
571     if (!_interactionViewsContainerView) {
572         _interactionViewsContainerView = adoptNS([[UIView alloc] init]);
573         [_interactionViewsContainerView layer].name = @"InteractionViewsContainer";
574         [_interactionViewsContainerView setOpaque:NO];
575         [_interactionViewsContainerView layer].anchorPoint = CGPointZero;
576         [self.superview addSubview:_interactionViewsContainerView.get()];
577     }
578
579     [self.layer addObserver:self forKeyPath:@"transform" options:NSKeyValueObservingOptionInitial context:nil];
580
581     _touchEventGestureRecognizer = adoptNS([[UIWebTouchEventsGestureRecognizer alloc] initWithTarget:self action:@selector(_webTouchEventsRecognized:) touchDelegate:self]);
582     [_touchEventGestureRecognizer setDelegate:self];
583     [self addGestureRecognizer:_touchEventGestureRecognizer.get()];
584
585     _singleTapGestureRecognizer = adoptNS([[WKSyntheticClickTapGestureRecognizer alloc] initWithTarget:self action:@selector(_singleTapCommited:)]);
586     [_singleTapGestureRecognizer setDelegate:self];
587     [_singleTapGestureRecognizer setGestureRecognizedTarget:self action:@selector(_singleTapRecognized:)];
588     [_singleTapGestureRecognizer setResetTarget:self action:@selector(_singleTapDidReset:)];
589     [self addGestureRecognizer:_singleTapGestureRecognizer.get()];
590
591     _nonBlockingDoubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_nonBlockingDoubleTapRecognized:)]);
592     [_nonBlockingDoubleTapGestureRecognizer setNumberOfTapsRequired:2];
593     [_nonBlockingDoubleTapGestureRecognizer setDelegate:self];
594     [_nonBlockingDoubleTapGestureRecognizer setEnabled:NO];
595     [self addGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
596
597     [self _createAndConfigureDoubleTapGestureRecognizer];
598
599     _twoFingerDoubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_twoFingerDoubleTapRecognized:)]);
600     [_twoFingerDoubleTapGestureRecognizer setNumberOfTapsRequired:2];
601     [_twoFingerDoubleTapGestureRecognizer setNumberOfTouchesRequired:2];
602     [_twoFingerDoubleTapGestureRecognizer setDelegate:self];
603     [self addGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
604
605     _highlightLongPressGestureRecognizer = adoptNS([[_UIWebHighlightLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_highlightLongPressRecognized:)]);
606     [_highlightLongPressGestureRecognizer setDelay:highlightDelay];
607     [_highlightLongPressGestureRecognizer setDelegate:self];
608     [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
609
610     [self _createAndConfigureLongPressGestureRecognizer];
611
612 #if ENABLE(DATA_INTERACTION)
613     [self setupDataInteractionDelegates];
614 #endif
615
616     _twoFingerSingleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_twoFingerSingleTapGestureRecognized:)]);
617     [_twoFingerSingleTapGestureRecognizer setAllowableMovement:60];
618     [_twoFingerSingleTapGestureRecognizer _setAllowableSeparation:150];
619     [_twoFingerSingleTapGestureRecognizer setNumberOfTapsRequired:1];
620     [_twoFingerSingleTapGestureRecognizer setNumberOfTouchesRequired:2];
621     [_twoFingerSingleTapGestureRecognizer setDelaysTouchesEnded:NO];
622     [_twoFingerSingleTapGestureRecognizer setDelegate:self];
623     [self addGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
624
625 #if HAVE(LINK_PREVIEW)
626     [self _registerPreview];
627 #endif
628
629     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_resetShowingTextStyle:) name:UIMenuControllerDidHideMenuNotification object:nil];
630     _showingTextStyleOptions = NO;
631
632     // FIXME: This should be called when we get notified that loading has completed.
633     [self useSelectionAssistantWithGranularity:_webView._selectionGranularity];
634     
635     _actionSheetAssistant = adoptNS([[WKActionSheetAssistant alloc] initWithView:self]);
636     [_actionSheetAssistant setDelegate:self];
637     _smartMagnificationController = std::make_unique<SmartMagnificationController>(self);
638     _isExpectingFastSingleTapCommit = NO;
639     _potentialTapInProgress = NO;
640     _isDoubleTapPending = NO;
641     _showDebugTapHighlightsForFastClicking = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitShowFastClickDebugTapHighlights"];
642     _needsDeferredEndScrollingSelectionUpdate = NO;
643     _isChangingFocus = NO;
644 }
645
646 - (void)cleanupInteraction
647 {
648     _webSelectionAssistant = nil;
649     _textSelectionAssistant = nil;
650     
651     [_actionSheetAssistant cleanupSheet];
652     _actionSheetAssistant = nil;
653     
654     _smartMagnificationController = nil;
655     _didAccessoryTabInitiateFocus = NO;
656     _isExpectingFastSingleTapCommit = NO;
657     _needsDeferredEndScrollingSelectionUpdate = NO;
658     [_formInputSession invalidate];
659     _formInputSession = nil;
660     [_highlightView removeFromSuperview];
661     _outstandingPositionInformationRequest = std::nullopt;
662
663     if (_interactionViewsContainerView) {
664         [self.layer removeObserver:self forKeyPath:@"transform"];
665         [_interactionViewsContainerView removeFromSuperview];
666         _interactionViewsContainerView = nil;
667     }
668
669     [_touchEventGestureRecognizer setDelegate:nil];
670     [self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
671
672     [_singleTapGestureRecognizer setDelegate:nil];
673     [_singleTapGestureRecognizer setGestureRecognizedTarget:nil action:nil];
674     [_singleTapGestureRecognizer setResetTarget:nil action:nil];
675     [self removeGestureRecognizer:_singleTapGestureRecognizer.get()];
676
677     [_highlightLongPressGestureRecognizer setDelegate:nil];
678     [self removeGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
679
680     [_longPressGestureRecognizer setDelegate:nil];
681     [self removeGestureRecognizer:_longPressGestureRecognizer.get()];
682
683     [_doubleTapGestureRecognizer setDelegate:nil];
684     [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
685
686     [_nonBlockingDoubleTapGestureRecognizer setDelegate:nil];
687     [self removeGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
688
689     [_twoFingerDoubleTapGestureRecognizer setDelegate:nil];
690     [self removeGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
691
692     [_twoFingerSingleTapGestureRecognizer setDelegate:nil];
693     [self removeGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
694
695     _layerTreeTransactionIdAtLastTouchStart = 0;
696
697 #if ENABLE(DATA_INTERACTION)
698     [existingLocalDragSessionContext(_dragDropInteractionState.dragSession()) cleanUpTemporaryDirectories];
699     [self teardownDataInteractionDelegates];
700 #endif
701
702     _inspectorNodeSearchEnabled = NO;
703     if (_inspectorNodeSearchGestureRecognizer) {
704         [_inspectorNodeSearchGestureRecognizer setDelegate:nil];
705         [self removeGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
706         _inspectorNodeSearchGestureRecognizer = nil;
707     }
708
709 #if HAVE(LINK_PREVIEW)
710     [self _unregisterPreview];
711 #endif
712
713     if (_fileUploadPanel) {
714         [_fileUploadPanel setDelegate:nil];
715         [_fileUploadPanel dismiss];
716         _fileUploadPanel = nil;
717     }
718     
719     _inputViewUpdateDeferrer = nullptr;
720     _assistedNodeInformation = { };
721 }
722
723 - (void)_removeDefaultGestureRecognizers
724 {
725     [self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
726     [self removeGestureRecognizer:_singleTapGestureRecognizer.get()];
727     [self removeGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
728     [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
729     [self removeGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
730     [self removeGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
731     [self removeGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
732 }
733
734 - (void)_addDefaultGestureRecognizers
735 {
736     [self addGestureRecognizer:_touchEventGestureRecognizer.get()];
737     [self addGestureRecognizer:_singleTapGestureRecognizer.get()];
738     [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
739     [self addGestureRecognizer:_doubleTapGestureRecognizer.get()];
740     [self addGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
741     [self addGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
742     [self addGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
743 }
744
745 - (UIView*)unscaledView
746 {
747     return _interactionViewsContainerView.get();
748 }
749
750 - (CGFloat)inverseScale
751 {
752     return 1 / [[self layer] transform].m11;
753 }
754
755 - (UIScrollView *)_scroller
756 {
757     return [_webView scrollView];
758 }
759
760 - (CGRect)unobscuredContentRect
761 {
762     return _page->unobscuredContentRect();
763 }
764
765
766 #pragma mark - UITextAutoscrolling
767 - (void)startAutoscroll:(CGPoint)pointInDocument
768 {
769     _page->startAutoscrollAtPosition(pointInDocument);
770 }
771
772 - (void)cancelAutoscroll
773 {
774     _page->cancelAutoscroll();
775 }
776
777 - (void)scrollSelectionToVisible:(BOOL)animated
778 {
779     // Used to scroll selection on keyboard up; we already scroll to visible.
780 }
781
782
783 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
784 {
785     ASSERT([keyPath isEqualToString:@"transform"]);
786     ASSERT(object == self.layer);
787
788     if ([UIView _isInAnimationBlock] && _page->editorState().selectionIsNone) {
789         // If the utility views are not already visible, we don't want them to become visible during the animation since
790         // they could not start from a reasonable state.
791         // This is not perfect since views could also get updated during the animation, in practice this is rare and the end state
792         // remains correct.
793         [self _cancelInteraction];
794         [_interactionViewsContainerView setHidden:YES];
795         [UIView _addCompletion:^(BOOL){ [_interactionViewsContainerView setHidden:NO]; }];
796     }
797
798     _selectionNeedsUpdate = YES;
799     [self _updateChangedSelection:YES];
800     [self _updateTapHighlight];
801 }
802
803 - (void)_enableInspectorNodeSearch
804 {
805     _inspectorNodeSearchEnabled = YES;
806
807     [self _cancelInteraction];
808
809     [self _removeDefaultGestureRecognizers];
810     _inspectorNodeSearchGestureRecognizer = adoptNS([[WKInspectorNodeSearchGestureRecognizer alloc] initWithTarget:self action:@selector(_inspectorNodeSearchRecognized:)]);
811     [self addGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
812 }
813
814 - (void)_disableInspectorNodeSearch
815 {
816     _inspectorNodeSearchEnabled = NO;
817
818     [self _addDefaultGestureRecognizers];
819     [self removeGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
820     _inspectorNodeSearchGestureRecognizer = nil;
821 }
822
823 - (UIView *)hitTest:(CGPoint)point withEvent:(::UIEvent *)event
824 {
825     for (UIView *subView in [_interactionViewsContainerView.get() subviews]) {
826         UIView *hitView = [subView hitTest:[subView convertPoint:point fromView:self] withEvent:event];
827         if (hitView)
828             return hitView;
829     }
830     return [super hitTest:point withEvent:event];
831 }
832
833 - (const InteractionInformationAtPosition&)positionInformation
834 {
835     return _positionInformation;
836 }
837
838 - (void)setInputDelegate:(id <UITextInputDelegate>)inputDelegate
839 {
840     _inputDelegate = inputDelegate;
841 }
842
843 - (id <UITextInputDelegate>)inputDelegate
844 {
845     return _inputDelegate;
846 }
847
848 - (CGPoint)lastInteractionLocation
849 {
850     return _lastInteractionLocation;
851 }
852
853 - (BOOL)shouldHideSelectionWhenScrolling
854 {
855     if (_isEditable)
856         return _assistedNodeInformation.insideFixedPosition;
857
858     auto& editorState = _page->editorState();
859     return !editorState.isMissingPostLayoutData && editorState.postLayoutData().insideFixedPosition;
860 }
861
862 - (BOOL)isEditable
863 {
864     return _isEditable;
865 }
866
867 - (BOOL)setIsEditable:(BOOL)isEditable
868 {
869     if (isEditable == _isEditable)
870         return NO;
871
872     _isEditable = isEditable;
873     return YES;
874 }
875
876 - (BOOL)canBecomeFirstResponder
877 {
878     return _becomingFirstResponder;
879 }
880
881 - (BOOL)canBecomeFirstResponderForWebView
882 {
883     if (_resigningFirstResponder)
884         return NO;
885     // We might want to return something else
886     // if we decide to enable/disable interaction programmatically.
887     return YES;
888 }
889
890 - (BOOL)becomeFirstResponder
891 {
892     return [_webView becomeFirstResponder];
893 }
894
895 - (BOOL)becomeFirstResponderForWebView
896 {
897     if (_resigningFirstResponder)
898         return NO;
899
900     BOOL didBecomeFirstResponder;
901     {
902         SetForScope<BOOL> becomingFirstResponder { _becomingFirstResponder, YES };
903         didBecomeFirstResponder = [super becomeFirstResponder];
904     }
905     if (didBecomeFirstResponder && !self.suppressAssistantSelectionView)
906         [_textSelectionAssistant activateSelection];
907
908     return didBecomeFirstResponder;
909 }
910
911 - (BOOL)resignFirstResponder
912 {
913     return [_webView resignFirstResponder];
914 }
915
916 - (BOOL)resignFirstResponderForWebView
917 {
918     // FIXME: Maybe we should call resignFirstResponder on the superclass
919     // and do nothing if the return value is NO.
920
921     _resigningFirstResponder = YES;
922     if (!_webView->_activeFocusedStateRetainCount) {
923         // We need to complete the editing operation before we blur the element.
924         [_inputPeripheral endEditing];
925         _page->blurAssistedNode();
926     }
927
928     [self _cancelInteraction];
929     [_webSelectionAssistant resignedFirstResponder];
930     [_textSelectionAssistant deactivateSelection];
931     
932     _inputViewUpdateDeferrer = nullptr;
933
934     bool superDidResign = [super resignFirstResponder];
935
936     _resigningFirstResponder = NO;
937
938     return superDidResign;
939 }
940
941 - (void)_webTouchEventsRecognized:(UIWebTouchEventsGestureRecognizer *)gestureRecognizer
942 {
943     if (!_page->isValid())
944         return;
945
946     const _UIWebTouchEvent* lastTouchEvent = gestureRecognizer.lastTouchEvent;
947
948     _lastInteractionLocation = lastTouchEvent->locationInDocumentCoordinates;
949     if (lastTouchEvent->type == UIWebTouchEventTouchBegin)
950         _layerTreeTransactionIdAtLastTouchStart = downcast<RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).lastCommittedLayerTreeTransactionID();
951
952 #if ENABLE(TOUCH_EVENTS)
953     NativeWebTouchEvent nativeWebTouchEvent(lastTouchEvent);
954     nativeWebTouchEvent.setCanPreventNativeGestures(!_canSendTouchEventsAsynchronously || [gestureRecognizer isDefaultPrevented]);
955
956     if (_canSendTouchEventsAsynchronously)
957         _page->handleTouchEventAsynchronously(nativeWebTouchEvent);
958     else
959         _page->handleTouchEventSynchronously(nativeWebTouchEvent);
960
961     if (nativeWebTouchEvent.allTouchPointsAreReleased())
962         _canSendTouchEventsAsynchronously = NO;
963 #endif
964 }
965
966 - (void)_inspectorNodeSearchRecognized:(UIGestureRecognizer *)gestureRecognizer
967 {
968     ASSERT(_inspectorNodeSearchEnabled);
969     [self _resetIsDoubleTapPending];
970
971     CGPoint point = [gestureRecognizer locationInView:self];
972
973     switch (gestureRecognizer.state) {
974     case UIGestureRecognizerStateBegan:
975     case UIGestureRecognizerStateChanged:
976         _page->inspectorNodeSearchMovedToPosition(point);
977         break;
978     case UIGestureRecognizerStateEnded:
979     case UIGestureRecognizerStateCancelled:
980     default: // To ensure we turn off node search.
981         _page->inspectorNodeSearchEndedAtPosition(point);
982         break;
983     }
984 }
985
986 static FloatQuad inflateQuad(const FloatQuad& quad, float inflateSize)
987 {
988     // We sort the output points like this (as expected by the highlight view):
989     //  p2------p3
990     //  |       |
991     //  p1------p4
992
993     // 1) Sort the points horizontally.
994     FloatPoint points[4] = { quad.p1(), quad.p4(), quad.p2(), quad.p3() };
995     if (points[0].x() > points[1].x())
996         std::swap(points[0], points[1]);
997     if (points[2].x() > points[3].x())
998         std::swap(points[2], points[3]);
999
1000     if (points[0].x() > points[2].x())
1001         std::swap(points[0], points[2]);
1002     if (points[1].x() > points[3].x())
1003         std::swap(points[1], points[3]);
1004
1005     if (points[1].x() > points[2].x())
1006         std::swap(points[1], points[2]);
1007
1008     // 2) Swap them vertically to have the output points [p2, p1, p3, p4].
1009     if (points[1].y() < points[0].y())
1010         std::swap(points[0], points[1]);
1011     if (points[3].y() < points[2].y())
1012         std::swap(points[2], points[3]);
1013
1014     // 3) Adjust the positions.
1015     points[0].move(-inflateSize, -inflateSize);
1016     points[1].move(-inflateSize, inflateSize);
1017     points[2].move(inflateSize, -inflateSize);
1018     points[3].move(inflateSize, inflateSize);
1019
1020     return FloatQuad(points[1], points[0], points[2], points[3]);
1021 }
1022
1023 #if ENABLE(TOUCH_EVENTS)
1024 - (void)_webTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent preventsNativeGestures:(BOOL)preventsNativeGesture
1025 {
1026     if (preventsNativeGesture) {
1027         _highlightLongPressCanClick = NO;
1028
1029         _canSendTouchEventsAsynchronously = YES;
1030         [_touchEventGestureRecognizer setDefaultPrevented:YES];
1031     }
1032 }
1033 #endif
1034
1035 static inline bool highlightedQuadsAreSmallerThanRect(const Vector<FloatQuad>& quads, const FloatRect& rect)
1036 {
1037     for (size_t i = 0; i < quads.size(); ++i) {
1038         FloatRect boundingBox = quads[i].boundingBox();
1039         if (boundingBox.width() > rect.width() || boundingBox.height() > rect.height())
1040             return false;
1041     }
1042     return true;
1043 }
1044
1045 static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius, CGFloat borderRadiusScale)
1046 {
1047     return [NSValue valueWithCGSize:CGSizeMake((borderRadius.width() * borderRadiusScale) + minimumTapHighlightRadius, (borderRadius.height() * borderRadiusScale) + minimumTapHighlightRadius)];
1048 }
1049
1050 - (void)_updateTapHighlight
1051 {
1052     if (![_highlightView superview])
1053         return;
1054
1055     {
1056         RetainPtr<UIColor> highlightUIKitColor = adoptNS([[UIColor alloc] initWithCGColor:cachedCGColor(_tapHighlightInformation.color)]);
1057         [_highlightView setColor:highlightUIKitColor.get()];
1058     }
1059
1060     CGFloat selfScale = self.layer.transform.m11;
1061     bool allHighlightRectsAreRectilinear = true;
1062     float deviceScaleFactor = _page->deviceScaleFactor();
1063     const Vector<WebCore::FloatQuad>& highlightedQuads = _tapHighlightInformation.quads;
1064     const size_t quadCount = highlightedQuads.size();
1065     RetainPtr<NSMutableArray> rects = adoptNS([[NSMutableArray alloc] initWithCapacity:static_cast<const NSUInteger>(quadCount)]);
1066     for (size_t i = 0; i < quadCount; ++i) {
1067         const FloatQuad& quad = highlightedQuads[i];
1068         if (quad.isRectilinear()) {
1069             FloatRect boundingBox = quad.boundingBox();
1070             boundingBox.scale(selfScale);
1071             boundingBox.inflate(minimumTapHighlightRadius);
1072             CGRect pixelAlignedRect = static_cast<CGRect>(encloseRectToDevicePixels(boundingBox, deviceScaleFactor));
1073             [rects addObject:[NSValue valueWithCGRect:pixelAlignedRect]];
1074         } else {
1075             allHighlightRectsAreRectilinear = false;
1076             rects.clear();
1077             break;
1078         }
1079     }
1080
1081     if (allHighlightRectsAreRectilinear)
1082         [_highlightView setFrames:rects.get() boundaryRect:_page->exposedContentRect()];
1083     else {
1084         RetainPtr<NSMutableArray> quads = adoptNS([[NSMutableArray alloc] initWithCapacity:static_cast<const NSUInteger>(quadCount)]);
1085         for (size_t i = 0; i < quadCount; ++i) {
1086             FloatQuad quad = highlightedQuads[i];
1087             quad.scale(selfScale);
1088             FloatQuad extendedQuad = inflateQuad(quad, minimumTapHighlightRadius);
1089             [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p1()]];
1090             [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p2()]];
1091             [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p3()]];
1092             [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p4()]];
1093         }
1094         [_highlightView setQuads:quads.get() boundaryRect:_page->exposedContentRect()];
1095     }
1096
1097     RetainPtr<NSMutableArray> borderRadii = adoptNS([[NSMutableArray alloc] initWithCapacity:4]);
1098     [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.topLeftRadius, selfScale)];
1099     [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.topRightRadius, selfScale)];
1100     [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.bottomLeftRadius, selfScale)];
1101     [borderRadii addObject:nsSizeForTapHighlightBorderRadius(_tapHighlightInformation.bottomRightRadius, selfScale)];
1102     [_highlightView setCornerRadii:borderRadii.get()];
1103 }
1104
1105 - (void)_showTapHighlight
1106 {
1107     if (!highlightedQuadsAreSmallerThanRect(_tapHighlightInformation.quads, _page->unobscuredContentRect()) && !_showDebugTapHighlightsForFastClicking)
1108         return;
1109
1110     if (!_highlightView) {
1111         _highlightView = adoptNS([[_UIHighlightView alloc] initWithFrame:CGRectZero]);
1112         [_highlightView setUserInteractionEnabled:NO];
1113         [_highlightView setOpaque:NO];
1114         [_highlightView setCornerRadius:minimumTapHighlightRadius];
1115     }
1116     [_highlightView layer].opacity = 1;
1117     [_interactionViewsContainerView addSubview:_highlightView.get()];
1118     [self _updateTapHighlight];
1119 }
1120
1121 - (void)_didGetTapHighlightForRequest:(uint64_t)requestID color:(const WebCore::Color&)color quads:(const Vector<WebCore::FloatQuad>&)highlightedQuads topLeftRadius:(const WebCore::IntSize&)topLeftRadius topRightRadius:(const WebCore::IntSize&)topRightRadius bottomLeftRadius:(const WebCore::IntSize&)bottomLeftRadius bottomRightRadius:(const WebCore::IntSize&)bottomRightRadius
1122 {
1123     if (!_isTapHighlightIDValid || _latestTapID != requestID)
1124         return;
1125
1126     _isTapHighlightIDValid = NO;
1127
1128     _tapHighlightInformation.quads = highlightedQuads;
1129     _tapHighlightInformation.topLeftRadius = topLeftRadius;
1130     _tapHighlightInformation.topRightRadius = topRightRadius;
1131     _tapHighlightInformation.bottomLeftRadius = bottomLeftRadius;
1132     _tapHighlightInformation.bottomRightRadius = bottomRightRadius;
1133     if (_showDebugTapHighlightsForFastClicking)
1134         _tapHighlightInformation.color = [self _tapHighlightColorForFastClick:![_doubleTapGestureRecognizer isEnabled]];
1135     else
1136         _tapHighlightInformation.color = color;
1137
1138     if (_potentialTapInProgress) {
1139         _hasTapHighlightForPotentialTap = YES;
1140         return;
1141     }
1142
1143     [self _showTapHighlight];
1144     if (_isExpectingFastSingleTapCommit) {
1145         [self _finishInteraction];
1146         if (!_potentialTapInProgress)
1147             _isExpectingFastSingleTapCommit = NO;
1148     }
1149 }
1150
1151 - (BOOL)_mayDisableDoubleTapGesturesDuringSingleTap
1152 {
1153     return _potentialTapInProgress;
1154 }
1155
1156 - (void)_disableDoubleTapGesturesDuringTapIfNecessary:(uint64_t)requestID
1157 {
1158     if (_latestTapID != requestID)
1159         return;
1160
1161     [self _setDoubleTapGesturesEnabled:NO];
1162 }
1163
1164 - (void)_cancelLongPressGestureRecognizer
1165 {
1166     [_highlightLongPressGestureRecognizer cancel];
1167 }
1168
1169 - (void)_didScroll
1170 {
1171     [self _cancelLongPressGestureRecognizer];
1172     [self _cancelInteraction];
1173 }
1174
1175 - (void)_overflowScrollingWillBegin
1176 {
1177     [_webSelectionAssistant willStartScrollingOverflow];
1178     [_textSelectionAssistant willStartScrollingOverflow];    
1179 }
1180
1181 - (void)_overflowScrollingDidEnd
1182 {
1183     // If scrolling ends before we've received a selection update,
1184     // we postpone showing the selection until the update is received.
1185     if (!_selectionNeedsUpdate) {
1186         _shouldRestoreSelection = YES;
1187         return;
1188     }
1189     [self _updateChangedSelection];
1190     [_webSelectionAssistant didEndScrollingOverflow];
1191     [_textSelectionAssistant didEndScrollingOverflow];
1192 }
1193
1194 - (BOOL)_requiresKeyboardWhenFirstResponder
1195 {
1196     // FIXME: We should add the logic to handle keyboard visibility during focus redirects.
1197     switch (_assistedNodeInformation.elementType) {
1198     case InputType::None:
1199         return NO;
1200     case InputType::Select:
1201         return !currentUserInterfaceIdiomIsPad();
1202     case InputType::Date:
1203     case InputType::Month:
1204     case InputType::DateTimeLocal:
1205     case InputType::Time:
1206         return !currentUserInterfaceIdiomIsPad();
1207     default:
1208         return !_assistedNodeInformation.isReadOnly;
1209     }
1210     return NO;
1211 }
1212
1213 - (BOOL)_requiresKeyboardResetOnReload
1214 {
1215     return YES;
1216 }
1217
1218 - (void)_displayFormNodeInputView
1219 {
1220     // In case user scaling is force enabled, do not use that scaling when zooming in with an input field.
1221     // Zooming above the page's default scale factor should only happen when the user performs it.
1222     [self _zoomToFocusRect:_assistedNodeInformation.elementRect
1223         selectionRect:_didAccessoryTabInitiateFocus ? IntRect() : _assistedNodeInformation.selectionRect
1224         insideFixed:_assistedNodeInformation.insideFixedPosition
1225         fontSize:_assistedNodeInformation.nodeFontSize
1226         minimumScale:_assistedNodeInformation.minimumScaleFactor
1227         maximumScale:_assistedNodeInformation.maximumScaleFactorIgnoringAlwaysScalable
1228         allowScaling:_assistedNodeInformation.allowsUserScalingIgnoringAlwaysScalable && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone
1229         forceScroll:[self requiresAccessoryView]];
1230
1231     _didAccessoryTabInitiateFocus = NO;
1232     [self _ensureFormAccessoryView];
1233     [self _updateAccessory];
1234 }
1235
1236 - (UIView *)inputView
1237 {
1238     if (_assistedNodeInformation.elementType == InputType::None)
1239         return nil;
1240
1241     if (!_inputPeripheral)
1242         _inputPeripheral = adoptNS(_assistedNodeInformation.elementType == InputType::Select ? [[WKFormSelectControl alloc] initWithView:self] : [[WKFormInputControl alloc] initWithView:self]);
1243     else
1244         [self _displayFormNodeInputView];
1245
1246     return [_formInputSession customInputView] ?: [_inputPeripheral assistantView];
1247 }
1248
1249 - (CGRect)_selectionClipRect
1250 {
1251     if (_assistedNodeInformation.elementType == InputType::None)
1252         return CGRectNull;
1253     return _page->editorState().postLayoutData().selectionClipRect;
1254 }
1255
1256 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
1257 {
1258     // A long-press gesture can not be recognized while panning, but a pan can be recognized
1259     // during a long-press gesture.
1260     BOOL shouldNotPreventScrollViewGestures = preventingGestureRecognizer == _highlightLongPressGestureRecognizer || preventingGestureRecognizer == _longPressGestureRecognizer;
1261     return !(shouldNotPreventScrollViewGestures
1262         && ([preventedGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")] || [preventedGestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPinchGestureRecognizer")]));
1263 }
1264
1265 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer {
1266     // Don't allow the highlight to be prevented by a selection gesture. Press-and-hold on a link should highlight the link, not select it.
1267     if ((preventingGestureRecognizer == _textSelectionAssistant.get().loupeGesture || [_webSelectionAssistant isSelectionGestureRecognizer:preventingGestureRecognizer])
1268         && (preventedGestureRecognizer == _highlightLongPressGestureRecognizer || preventedGestureRecognizer == _longPressGestureRecognizer)) {
1269         return NO;
1270     }
1271
1272     return YES;
1273 }
1274
1275 static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UIGestureRecognizer *x, UIGestureRecognizer *y)
1276 {
1277     return (a == x && b == y) || (b == x && a == y);
1278 }
1279
1280 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
1281 {
1282     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _longPressGestureRecognizer.get()))
1283         return YES;
1284
1285     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _webSelectionAssistant.get().selectionLongPressRecognizer))
1286         return YES;
1287
1288     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _singleTapGestureRecognizer.get(), _textSelectionAssistant.get().singleTapGesture))
1289         return YES;
1290
1291     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _singleTapGestureRecognizer.get(), _nonBlockingDoubleTapGestureRecognizer.get()))
1292         return YES;
1293
1294     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _nonBlockingDoubleTapGestureRecognizer.get()))
1295         return YES;
1296
1297     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _previewSecondaryGestureRecognizer.get()))
1298         return YES;
1299
1300     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _previewGestureRecognizer.get()))
1301         return YES;
1302
1303     return NO;
1304 }
1305
1306 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
1307 {
1308     if (gestureRecognizer == _touchEventGestureRecognizer && [_webView _isNavigationSwipeGestureRecognizer:otherGestureRecognizer])
1309         return YES;
1310
1311     return NO;
1312 }
1313
1314 - (void)_showImageSheet
1315 {
1316     [_actionSheetAssistant showImageSheet];
1317 }
1318
1319 - (void)_showAttachmentSheet
1320 {
1321     id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView UIDelegate]);
1322     if (![uiDelegate respondsToSelector:@selector(_webView:showCustomSheetForElement:)])
1323         return;
1324
1325     auto element = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeAttachment URL:(NSURL *)_positionInformation.url location:_positionInformation.request.point title:_positionInformation.title ID:_positionInformation.idAttribute rect:_positionInformation.bounds image:nil]);
1326     [uiDelegate _webView:_webView showCustomSheetForElement:element.get()];
1327 }
1328
1329 - (void)_showLinkSheet
1330 {
1331     [_actionSheetAssistant showLinkSheet];
1332 }
1333
1334 - (void)_showDataDetectorsSheet
1335 {
1336     [_actionSheetAssistant showDataDetectorsSheet];
1337 }
1338
1339 - (SEL)_actionForLongPressFromPositionInformation:(const InteractionInformationAtPosition&)positionInformation
1340 {
1341     if (!_webView.configuration._longPressActionsEnabled)
1342         return nil;
1343
1344     if (!positionInformation.touchCalloutEnabled)
1345         return nil;
1346
1347     if (positionInformation.isImage)
1348         return @selector(_showImageSheet);
1349
1350     if (positionInformation.isLink) {
1351 #if ENABLE(DATA_DETECTION)
1352         if (DataDetection::canBePresentedByDataDetectors(positionInformation.url))
1353             return @selector(_showDataDetectorsSheet);
1354 #endif
1355         return @selector(_showLinkSheet);
1356     }
1357     if (positionInformation.isAttachment)
1358         return @selector(_showAttachmentSheet);
1359
1360     return nil;
1361 }
1362
1363 - (SEL)_actionForLongPress
1364 {
1365     return [self _actionForLongPressFromPositionInformation:_positionInformation];
1366 }
1367
1368 - (InteractionInformationAtPosition)currentPositionInformation
1369 {
1370     return _positionInformation;
1371 }
1372
1373 - (void)doAfterPositionInformationUpdate:(void (^)(InteractionInformationAtPosition))action forRequest:(InteractionInformationRequest)request
1374 {
1375     if ([self _currentPositionInformationIsValidForRequest:request]) {
1376         // If the most recent position information is already valid, invoke the given action block immediately.
1377         action(_positionInformation);
1378         return;
1379     }
1380
1381     _pendingPositionInformationHandlers.append(InteractionInformationRequestAndCallback(request, action));
1382
1383     if (![self _hasValidOutstandingPositionInformationRequest:request])
1384         [self requestAsynchronousPositionInformationUpdate:request];
1385 }
1386
1387 - (BOOL)ensurePositionInformationIsUpToDate:(WebKit::InteractionInformationRequest)request
1388 {
1389     if ([self _currentPositionInformationIsValidForRequest:request])
1390         return YES;
1391
1392     auto* connection = _page->process().connection();
1393     if (!connection)
1394         return NO;
1395
1396     if ([self _hasValidOutstandingPositionInformationRequest:request]) {
1397         return connection->waitForAndDispatchImmediately<Messages::WebPageProxy::DidReceivePositionInformation>(_page->pageID(), Seconds::infinity(), IPC::WaitForOption::InterruptWaitingIfSyncMessageArrives);
1398     }
1399
1400     _page->process().sendSync(Messages::WebPage::GetPositionInformation(request), Messages::WebPage::GetPositionInformation::Reply(_positionInformation), _page->pageID());
1401
1402     _hasValidPositionInformation = YES;
1403     [self _invokeAndRemovePendingHandlersValidForCurrentPositionInformation];
1404
1405     return YES;
1406 }
1407
1408 - (void)requestAsynchronousPositionInformationUpdate:(WebKit::InteractionInformationRequest)request
1409 {
1410     if ([self _currentPositionInformationIsValidForRequest:request])
1411         return;
1412
1413     _outstandingPositionInformationRequest = request;
1414
1415     _page->requestPositionInformation(request);
1416 }
1417
1418 - (BOOL)_currentPositionInformationIsValidForRequest:(const InteractionInformationRequest&)request
1419 {
1420     return _hasValidPositionInformation && _positionInformation.request.isValidForRequest(request);
1421 }
1422
1423 - (BOOL)_hasValidOutstandingPositionInformationRequest:(const InteractionInformationRequest&)request
1424 {
1425     return _outstandingPositionInformationRequest && _outstandingPositionInformationRequest->isValidForRequest(request);
1426 }
1427
1428 - (void)_invokeAndRemovePendingHandlersValidForCurrentPositionInformation
1429 {
1430     ASSERT(_hasValidPositionInformation);
1431
1432     ++_positionInformationCallbackDepth;
1433     auto updatedPositionInformation = _positionInformation;
1434
1435     for (size_t index = 0; index < _pendingPositionInformationHandlers.size(); ++index) {
1436         auto requestAndHandler = _pendingPositionInformationHandlers[index];
1437         if (!requestAndHandler)
1438             continue;
1439
1440         if (![self _currentPositionInformationIsValidForRequest:requestAndHandler->first])
1441             continue;
1442
1443         _pendingPositionInformationHandlers[index] = std::nullopt;
1444
1445         if (requestAndHandler->second)
1446             requestAndHandler->second(updatedPositionInformation);
1447     }
1448
1449     if (--_positionInformationCallbackDepth)
1450         return;
1451
1452     for (int index = _pendingPositionInformationHandlers.size() - 1; index >= 0; --index) {
1453         if (!_pendingPositionInformationHandlers[index])
1454             _pendingPositionInformationHandlers.remove(index);
1455     }
1456 }
1457
1458 #if ENABLE(DATA_DETECTION)
1459 - (NSArray *)_dataDetectionResults
1460 {
1461     return _page->dataDetectionResults();
1462 }
1463 #endif
1464
1465 - (NSArray<NSValue *> *)_uiTextSelectionRects
1466 {
1467     NSMutableArray *textSelectionRects = [NSMutableArray array];
1468
1469     if (_textSelectionAssistant) {
1470         for (WKTextSelectionRect *selectionRect in [_textSelectionAssistant valueForKeyPath:@"selectionView.selection.selectionRects"])
1471             [textSelectionRects addObject:[NSValue valueWithCGRect:selectionRect.webRect.rect]];
1472     } else if (_webSelectionAssistant) {
1473         for (WebSelectionRect *selectionRect in [_webSelectionAssistant valueForKeyPath:@"selectionView.selectionRects"])
1474             [textSelectionRects addObject:[NSValue valueWithCGRect:selectionRect.rect]];
1475     }
1476
1477     return textSelectionRects;
1478 }
1479
1480 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
1481 {
1482     CGPoint point = [gestureRecognizer locationInView:self];
1483
1484     if (gestureRecognizer == _highlightLongPressGestureRecognizer
1485         || gestureRecognizer == _doubleTapGestureRecognizer
1486         || gestureRecognizer == _nonBlockingDoubleTapGestureRecognizer
1487         || gestureRecognizer == _twoFingerDoubleTapGestureRecognizer
1488         || gestureRecognizer == _singleTapGestureRecognizer) {
1489
1490         if (_textSelectionAssistant) {
1491             // Request information about the position with sync message.
1492             // If the assisted node is the same, prevent the gesture.
1493             if (![self ensurePositionInformationIsUpToDate:InteractionInformationRequest(roundedIntPoint(point))])
1494                 return NO;
1495             if (_positionInformation.nodeAtPositionIsAssistedNode)
1496                 return NO;
1497         }
1498     }
1499
1500     if (gestureRecognizer == _highlightLongPressGestureRecognizer) {
1501         if (_textSelectionAssistant) {
1502             // This is a different node than the assisted one.
1503             // Prevent the gesture if there is no node.
1504             // Allow the gesture if it is a node that wants highlight or if there is an action for it.
1505             if (!_positionInformation.isElement)
1506                 return NO;
1507             return [self _actionForLongPress] != nil;
1508         } else {
1509             // We still have no idea about what is at the location.
1510             // Send and async message to find out.
1511             _hasValidPositionInformation = NO;
1512             InteractionInformationRequest request(roundedIntPoint(point));
1513
1514             // If 3D Touch is enabled, asynchronously collect snapshots in the hopes that
1515             // they'll arrive before we have to synchronously request them in
1516             // _interactionShouldBeginFromPreviewItemController.
1517             if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
1518                 request.includeSnapshot = true;
1519                 request.includeLinkIndicator = true;
1520             }
1521
1522             [self requestAsynchronousPositionInformationUpdate:request];
1523             return YES;
1524         }
1525     }
1526
1527     if (gestureRecognizer == _longPressGestureRecognizer) {
1528         // Use the information retrieved with one of the previous calls
1529         // to gestureRecognizerShouldBegin.
1530         // Force a sync call if not ready yet.
1531         InteractionInformationRequest request(roundedIntPoint(point));
1532         if (![self ensurePositionInformationIsUpToDate:request])
1533             return NO;
1534
1535         if (_textSelectionAssistant) {
1536             // Prevent the gesture if it is the same node.
1537             if (_positionInformation.nodeAtPositionIsAssistedNode)
1538                 return NO;
1539         } else {
1540             // Prevent the gesture if there is no action for the node.
1541             return [self _actionForLongPress] != nil;
1542         }
1543     }
1544
1545     return YES;
1546 }
1547
1548 - (void)_cancelInteraction
1549 {
1550     _isTapHighlightIDValid = NO;
1551     [_highlightView removeFromSuperview];
1552 }
1553
1554 - (void)_finishInteraction
1555 {
1556     _isTapHighlightIDValid = NO;
1557     CGFloat tapHighlightFadeDuration = _showDebugTapHighlightsForFastClicking ? 0.25 : 0.1;
1558     [UIView animateWithDuration:tapHighlightFadeDuration
1559                      animations:^{
1560                          [_highlightView layer].opacity = 0;
1561                      }
1562                      completion:^(BOOL finished){
1563                          if (finished)
1564                              [_highlightView removeFromSuperview];
1565                      }];
1566 }
1567
1568 - (BOOL)hasSelectablePositionAtPoint:(CGPoint)point
1569 {
1570     if (!_webView.configuration._textInteractionGesturesEnabled)
1571         return NO;
1572
1573     if (_inspectorNodeSearchEnabled)
1574         return NO;
1575
1576     InteractionInformationRequest request(roundedIntPoint(point));
1577     if (![self ensurePositionInformationIsUpToDate:request])
1578         return NO;
1579
1580 #if ENABLE(DATA_INTERACTION)
1581     if (_positionInformation.hasSelectionAtPosition) {
1582         // If the position might initiate a data interaction, we don't want to consider the content at this position to be selectable.
1583         // FIXME: This should be renamed to something more precise, such as textSelectionShouldRecognizeGestureAtPoint:
1584         return NO;
1585     }
1586 #endif
1587
1588     return _positionInformation.isSelectable;
1589 }
1590
1591 - (BOOL)pointIsNearMarkedText:(CGPoint)point
1592 {
1593     if (!_webView.configuration._textInteractionGesturesEnabled)
1594         return NO;
1595
1596     InteractionInformationRequest request(roundedIntPoint(point));
1597     if (![self ensurePositionInformationIsUpToDate:request])
1598         return NO;
1599     return _positionInformation.isNearMarkedText;
1600 }
1601
1602 - (BOOL)textInteractionGesture:(UIWKGestureType)gesture shouldBeginAtPoint:(CGPoint)point
1603 {
1604     if (!_webView.configuration._textInteractionGesturesEnabled)
1605         return NO;
1606
1607     InteractionInformationRequest request(roundedIntPoint(point));
1608     if (![self ensurePositionInformationIsUpToDate:request])
1609         return NO;
1610
1611 #if ENABLE(DATA_INTERACTION)
1612     if (_positionInformation.hasSelectionAtPosition && gesture == UIWKGestureLoupe) {
1613         // If the position might initiate data interaction, we don't want to change the selection.
1614         return NO;
1615     }
1616 #endif
1617
1618     // If we're currently editing an assisted node, only allow the selection to move within that assisted node.
1619     if (self.isAssistingNode)
1620         return _positionInformation.nodeAtPositionIsAssistedNode;
1621
1622     // Otherwise, if we're using a text interaction assistant outside of editing purposes (e.g. the selection mode
1623     // is character granularity) then allow text selection.
1624     return YES;
1625 }
1626
1627 - (NSArray *)webSelectionRectsForSelectionRects:(const Vector<WebCore::SelectionRect>&)selectionRects
1628 {
1629     unsigned size = selectionRects.size();
1630     if (!size)
1631         return nil;
1632
1633     NSMutableArray *webRects = [NSMutableArray arrayWithCapacity:size];
1634     for (unsigned i = 0; i < size; i++) {
1635         const WebCore::SelectionRect& coreRect = selectionRects[i];
1636         WebSelectionRect *webRect = [WebSelectionRect selectionRect];
1637         webRect.rect = coreRect.rect();
1638         webRect.writingDirection = coreRect.direction() == LTR ? WKWritingDirectionLeftToRight : WKWritingDirectionRightToLeft;
1639         webRect.isLineBreak = coreRect.isLineBreak();
1640         webRect.isFirstOnLine = coreRect.isFirstOnLine();
1641         webRect.isLastOnLine = coreRect.isLastOnLine();
1642         webRect.containsStart = coreRect.containsStart();
1643         webRect.containsEnd = coreRect.containsEnd();
1644         webRect.isInFixedPosition = coreRect.isInFixedPosition();
1645         webRect.isHorizontal = coreRect.isHorizontal();
1646         [webRects addObject:webRect];
1647     }
1648
1649     return webRects;
1650 }
1651
1652 - (NSArray *)webSelectionRects
1653 {
1654     if (_page->editorState().selectionIsNone)
1655         return nil;
1656     const auto& selectionRects = _page->editorState().postLayoutData().selectionRects;
1657     return [self webSelectionRectsForSelectionRects:selectionRects];
1658 }
1659
1660 - (void)_highlightLongPressRecognized:(UILongPressGestureRecognizer *)gestureRecognizer
1661 {
1662     ASSERT(gestureRecognizer == _highlightLongPressGestureRecognizer);
1663     [self _resetIsDoubleTapPending];
1664
1665     _lastInteractionLocation = gestureRecognizer.startPoint;
1666
1667     switch ([gestureRecognizer state]) {
1668     case UIGestureRecognizerStateBegan:
1669         _highlightLongPressCanClick = YES;
1670         cancelPotentialTapIfNecessary(self);
1671         _page->tapHighlightAtPosition([gestureRecognizer startPoint], ++_latestTapID);
1672         _isTapHighlightIDValid = YES;
1673         break;
1674     case UIGestureRecognizerStateEnded:
1675         if (_highlightLongPressCanClick && _positionInformation.isElement) {
1676             [self _attemptClickAtLocation:[gestureRecognizer startPoint]];
1677             [self _finishInteraction];
1678         } else
1679             [self _cancelInteraction];
1680         _highlightLongPressCanClick = NO;
1681         break;
1682     case UIGestureRecognizerStateCancelled:
1683         [self _cancelInteraction];
1684         _highlightLongPressCanClick = NO;
1685         break;
1686     default:
1687         break;
1688     }
1689 }
1690
1691 - (void)_twoFingerSingleTapGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer
1692 {
1693     _isTapHighlightIDValid = YES;
1694     _isExpectingFastSingleTapCommit = YES;
1695     _page->handleTwoFingerTapAtPoint(roundedIntPoint(gestureRecognizer.centroid), ++_latestTapID);
1696 }
1697
1698 - (void)_longPressRecognized:(UILongPressGestureRecognizer *)gestureRecognizer
1699 {
1700     ASSERT(gestureRecognizer == _longPressGestureRecognizer);
1701     [self _resetIsDoubleTapPending];
1702
1703     _lastInteractionLocation = gestureRecognizer.startPoint;
1704
1705     if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
1706         SEL action = [self _actionForLongPress];
1707         if (action) {
1708             [self performSelector:action];
1709             [self _cancelLongPressGestureRecognizer];
1710         }
1711     }
1712 }
1713
1714 - (void)_endPotentialTapAndEnableDoubleTapGesturesIfNecessary
1715 {
1716     if (_webView._allowsDoubleTapGestures)
1717         [self _setDoubleTapGesturesEnabled:YES];
1718
1719     _potentialTapInProgress = NO;
1720 }
1721
1722 - (void)_singleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
1723 {
1724     ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
1725     ASSERT(!_potentialTapInProgress);
1726     [self _resetIsDoubleTapPending];
1727
1728     _page->potentialTapAtPosition(gestureRecognizer.location, ++_latestTapID);
1729     _potentialTapInProgress = YES;
1730     _isTapHighlightIDValid = YES;
1731     _isExpectingFastSingleTapCommit = !_doubleTapGestureRecognizer.get().enabled;
1732 }
1733
1734 static void cancelPotentialTapIfNecessary(WKContentView* contentView)
1735 {
1736     if (contentView->_potentialTapInProgress) {
1737         [contentView _endPotentialTapAndEnableDoubleTapGesturesIfNecessary];
1738         [contentView _cancelInteraction];
1739         contentView->_page->cancelPotentialTap();
1740     }
1741 }
1742
1743 - (void)_singleTapDidReset:(UITapGestureRecognizer *)gestureRecognizer
1744 {
1745     ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
1746     cancelPotentialTapIfNecessary(self);
1747 }
1748
1749 - (void)_commitPotentialTapFailed
1750 {
1751     [self _cancelInteraction];
1752     
1753     _inputViewUpdateDeferrer = nullptr;
1754 }
1755
1756 - (void)_didNotHandleTapAsClick:(const WebCore::IntPoint&)point
1757 {
1758     _inputViewUpdateDeferrer = nullptr;
1759
1760     // FIXME: we should also take into account whether or not the UI delegate
1761     // has handled this notification.
1762 #if ENABLE(DATA_DETECTION)
1763     if (_hasValidPositionInformation && point == _positionInformation.request.point && _positionInformation.isDataDetectorLink) {
1764         [self _showDataDetectorsSheet];
1765         return;
1766     }
1767 #endif
1768
1769     if (!_isDoubleTapPending)
1770         return;
1771
1772     _smartMagnificationController->handleSmartMagnificationGesture(_lastInteractionLocation);
1773     _isDoubleTapPending = NO;
1774 }
1775
1776 - (void)_didCompleteSyntheticClick
1777 {
1778     _inputViewUpdateDeferrer = nullptr;
1779 }
1780
1781 - (void)_singleTapCommited:(UITapGestureRecognizer *)gestureRecognizer
1782 {
1783     ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
1784
1785     if (![self isFirstResponder]) {
1786         if (!_inputViewUpdateDeferrer)
1787             _inputViewUpdateDeferrer = std::make_unique<InputViewUpdateDeferrer>();
1788         [self becomeFirstResponder];
1789     }
1790
1791     if (_webSelectionAssistant && ![_webSelectionAssistant shouldHandleSingleTapAtPoint:gestureRecognizer.location]) {
1792         [self _singleTapDidReset:gestureRecognizer];
1793         return;
1794     }
1795
1796     ASSERT(_potentialTapInProgress);
1797
1798     // We don't want to clear the selection if it is in editable content.
1799     // The selection could have been set by autofocusing on page load and not
1800     // reflected in the UI process since the user was not interacting with the page.
1801     if (!_page->editorState().isContentEditable)
1802         [_webSelectionAssistant clearSelection];
1803
1804     _lastInteractionLocation = gestureRecognizer.location;
1805
1806     [self _endPotentialTapAndEnableDoubleTapGesturesIfNecessary];
1807
1808     if (_hasTapHighlightForPotentialTap) {
1809         [self _showTapHighlight];
1810         _hasTapHighlightForPotentialTap = NO;
1811     }
1812
1813     [_inputPeripheral endEditing];
1814     _page->commitPotentialTap(_layerTreeTransactionIdAtLastTouchStart);
1815
1816     if (!_isExpectingFastSingleTapCommit)
1817         [self _finishInteraction];
1818 }
1819
1820 - (void)_doubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
1821 {
1822     [self _resetIsDoubleTapPending];
1823     _lastInteractionLocation = gestureRecognizer.location;
1824
1825     _smartMagnificationController->handleSmartMagnificationGesture(gestureRecognizer.location);
1826 }
1827
1828 - (void)_resetIsDoubleTapPending
1829 {
1830     _isDoubleTapPending = NO;
1831 }
1832
1833 - (void)_nonBlockingDoubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
1834 {
1835     _lastInteractionLocation = gestureRecognizer.location;
1836     _isDoubleTapPending = YES;
1837 }
1838
1839 - (void)_twoFingerDoubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
1840 {
1841     [self _resetIsDoubleTapPending];
1842     _lastInteractionLocation = gestureRecognizer.location;
1843
1844     _smartMagnificationController->handleResetMagnificationGesture(gestureRecognizer.location);
1845 }
1846
1847 - (void)_attemptClickAtLocation:(CGPoint)location
1848 {
1849     if (![self isFirstResponder]) {
1850         if (!_inputViewUpdateDeferrer)
1851             _inputViewUpdateDeferrer = std::make_unique<InputViewUpdateDeferrer>();
1852         [self becomeFirstResponder];
1853     }
1854
1855     [_inputPeripheral endEditing];
1856     _page->handleTap(location, _layerTreeTransactionIdAtLastTouchStart);
1857 }
1858
1859 - (void)useSelectionAssistantWithGranularity:(WKSelectionGranularity)selectionGranularity
1860 {
1861     if (selectionGranularity == WKSelectionGranularityDynamic) {
1862         if (_textSelectionAssistant) {
1863             [_textSelectionAssistant deactivateSelection];
1864             _textSelectionAssistant = nil;
1865         }
1866         if (!_webSelectionAssistant)
1867             _webSelectionAssistant = adoptNS([[UIWKSelectionAssistant alloc] initWithView:self]);
1868     } else if (selectionGranularity == WKSelectionGranularityCharacter) {
1869         if (_webSelectionAssistant)
1870             _webSelectionAssistant = nil;
1871
1872         if (!_textSelectionAssistant)
1873             _textSelectionAssistant = adoptNS([[UIWKTextInteractionAssistant alloc] initWithView:self]);
1874         else {
1875             // Reset the gesture recognizers in case editibility has changed.
1876             [_textSelectionAssistant setGestureRecognizers];
1877         }
1878
1879         if (self.isFirstResponder && !self.suppressAssistantSelectionView)
1880             [_textSelectionAssistant activateSelection];
1881     }
1882 }
1883
1884 - (void)clearSelection
1885 {
1886     _page->clearSelection();
1887 }
1888
1889 - (void)_positionInformationDidChange:(const InteractionInformationAtPosition&)info
1890 {
1891     _outstandingPositionInformationRequest = std::nullopt;
1892
1893     InteractionInformationAtPosition newInfo = info;
1894     newInfo.mergeCompatibleOptionalInformation(_positionInformation);
1895
1896     _positionInformation = newInfo;
1897     _hasValidPositionInformation = YES;
1898     if (_actionSheetAssistant)
1899         [_actionSheetAssistant updateSheetPosition];
1900     [self _invokeAndRemovePendingHandlersValidForCurrentPositionInformation];
1901 }
1902
1903 - (void)_willStartScrollingOrZooming
1904 {
1905     [_webSelectionAssistant willStartScrollingOrZoomingPage];
1906     [_textSelectionAssistant willStartScrollingOverflow];
1907     _page->setIsScrollingOrZooming(true);
1908 }
1909
1910 - (void)scrollViewWillStartPanOrPinchGesture
1911 {
1912     _page->hideValidationMessage();
1913
1914     _canSendTouchEventsAsynchronously = YES;
1915 }
1916
1917 - (void)_didEndScrollingOrZooming
1918 {
1919     if (!_needsDeferredEndScrollingSelectionUpdate) {
1920         [_webSelectionAssistant didEndScrollingOrZoomingPage];
1921         [_textSelectionAssistant didEndScrollingOverflow];
1922     }
1923     _page->setIsScrollingOrZooming(false);
1924 }
1925
1926 - (BOOL)requiresAccessoryView
1927 {
1928     if ([_formInputSession accessoryViewShouldNotShow])
1929         return NO;
1930
1931     switch (_assistedNodeInformation.elementType) {
1932     case InputType::None:
1933         return NO;
1934     case InputType::Text:
1935     case InputType::Password:
1936     case InputType::Search:
1937     case InputType::Email:
1938     case InputType::URL:
1939     case InputType::Phone:
1940     case InputType::Number:
1941     case InputType::NumberPad:
1942     case InputType::ContentEditable:
1943     case InputType::TextArea:
1944     case InputType::Select:
1945     case InputType::Date:
1946     case InputType::DateTime:
1947     case InputType::DateTimeLocal:
1948     case InputType::Month:
1949     case InputType::Week:
1950     case InputType::Time:
1951         return !currentUserInterfaceIdiomIsPad();
1952     }
1953 }
1954
1955 - (void)_ensureFormAccessoryView
1956 {
1957     if (_formAccessoryView)
1958         return;
1959
1960     _formAccessoryView = adoptNS([[UIWebFormAccessory alloc] initWithInputAssistantItem:self.inputAssistantItem]);
1961     [_formAccessoryView setDelegate:self];
1962 }
1963
1964 - (UIView *)inputAccessoryView
1965 {
1966     if (![self requiresAccessoryView])
1967         return nil;
1968
1969     return self.formAccessoryView;
1970 }
1971
1972 - (NSArray *)supportedPasteboardTypesForCurrentSelection
1973 {
1974     if (_page->editorState().selectionIsNone)
1975         return nil;
1976     
1977     static NSMutableArray *richTypes = nil;
1978     static NSMutableArray *plainTextTypes = nil;
1979     if (!plainTextTypes) {
1980         plainTextTypes = [[NSMutableArray alloc] init];
1981         [plainTextTypes addObject:(id)kUTTypeURL];
1982         [plainTextTypes addObjectsFromArray:UIPasteboardTypeListString];
1983
1984         richTypes = [[NSMutableArray alloc] init];
1985         [richTypes addObject:WebArchivePboardType];
1986         [richTypes addObjectsFromArray:UIPasteboardTypeListImage];
1987         [richTypes addObjectsFromArray:plainTextTypes];
1988     }
1989
1990     return (_page->editorState().isContentRichlyEditable) ? richTypes : plainTextTypes;
1991 }
1992
1993 #define FORWARD_ACTION_TO_WKWEBVIEW(_action) \
1994     - (void)_action:(id)sender \
1995     { \
1996         [_webView _action:sender]; \
1997     }
1998
1999 FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)
2000
2001 #undef FORWARD_ACTION_TO_WKWEBVIEW
2002
2003 - (void)_lookupForWebView:(id)sender
2004 {
2005     RetainPtr<WKContentView> view = self;
2006     _page->getSelectionContext([view](const String& selectedText, const String& textBefore, const String& textAfter, CallbackBase::Error error) {
2007         if (error != CallbackBase::Error::None)
2008             return;
2009         if (!selectedText)
2010             return;
2011
2012         auto& editorState = view->_page->editorState();
2013         auto& postLayoutData = editorState.postLayoutData();
2014         CGRect presentationRect;
2015         if (editorState.selectionIsRange && !postLayoutData.selectionRects.isEmpty())
2016             presentationRect = postLayoutData.selectionRects[0].rect();
2017         else
2018             presentationRect = postLayoutData.caretRectAtStart;
2019         
2020         String selectionContext = textBefore + selectedText + textAfter;
2021         NSRange selectedRangeInContext = NSMakeRange(textBefore.length(), selectedText.length());
2022
2023         if (auto textSelectionAssistant = view->_textSelectionAssistant)
2024             [textSelectionAssistant lookup:selectionContext withRange:selectedRangeInContext fromRect:presentationRect];
2025         else
2026             [view->_webSelectionAssistant lookup:selectionContext withRange:selectedRangeInContext fromRect:presentationRect];
2027     });
2028 }
2029
2030 - (void)_shareForWebView:(id)sender
2031 {
2032     RetainPtr<WKContentView> view = self;
2033     _page->getSelectionOrContentsAsString([view](const String& string, CallbackBase::Error error) {
2034         if (error != CallbackBase::Error::None)
2035             return;
2036         if (!string)
2037             return;
2038
2039         CGRect presentationRect = view->_page->editorState().postLayoutData().selectionRects[0].rect();
2040
2041         if (view->_textSelectionAssistant)
2042             [view->_textSelectionAssistant showShareSheetFor:string fromRect:presentationRect];
2043         else if (view->_webSelectionAssistant)
2044             [view->_webSelectionAssistant showShareSheetFor:string fromRect:presentationRect];
2045     });
2046 }
2047
2048 - (void)_addShortcutForWebView:(id)sender
2049 {
2050     if (_textSelectionAssistant)
2051         [_textSelectionAssistant showTextServiceFor:[self selectedText] fromRect:_page->editorState().postLayoutData().selectionRects[0].rect()];
2052     else if (_webSelectionAssistant)
2053         [_webSelectionAssistant showTextServiceFor:[self selectedText] fromRect:_page->editorState().postLayoutData().selectionRects[0].rect()];
2054 }
2055
2056 - (NSString *)selectedText
2057 {
2058     return (NSString *)_page->editorState().postLayoutData().wordAtSelection;
2059 }
2060
2061 - (BOOL)isReplaceAllowed
2062 {
2063     return _page->editorState().postLayoutData().isReplaceAllowed;
2064 }
2065
2066 - (void)replaceText:(NSString *)text withText:(NSString *)word
2067 {
2068     _page->replaceSelectedText(text, word);
2069 }
2070
2071 - (void)selectWordBackward
2072 {
2073     _page->selectWordBackward();
2074 }
2075
2076 - (void)_promptForReplaceForWebView:(id)sender
2077 {
2078     const auto& wordAtSelection = _page->editorState().postLayoutData().wordAtSelection;
2079     if (wordAtSelection.isEmpty())
2080         return;
2081
2082     [_textSelectionAssistant scheduleReplacementsForText:wordAtSelection];
2083 }
2084
2085 - (void)_transliterateChineseForWebView:(id)sender
2086 {
2087     [_textSelectionAssistant scheduleChineseTransliterationForText:_page->editorState().postLayoutData().wordAtSelection];
2088 }
2089
2090 - (void)_reanalyzeForWebView:(id)sender
2091 {
2092     [_textSelectionAssistant scheduleReanalysis];
2093 }
2094
2095 - (void)replaceForWebView:(id)sender
2096 {
2097     [[UIKeyboardImpl sharedInstance] replaceText:sender];
2098 }
2099
2100 - (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
2101 {
2102     if (!position || !_page->editorState().isContentRichlyEditable)
2103         return nil;
2104
2105     NSMutableDictionary* result = [NSMutableDictionary dictionary];
2106
2107     auto typingAttributes = _page->editorState().postLayoutData().typingAttributes;
2108     CTFontSymbolicTraits symbolicTraits = 0;
2109     if (typingAttributes & AttributeBold)
2110         symbolicTraits |= kCTFontBoldTrait;
2111     if (typingAttributes & AttributeItalics)
2112         symbolicTraits |= kCTFontTraitItalic;
2113
2114     // We chose a random font family and size.
2115     // What matters are the traits but the caller expects a font object
2116     // in the dictionary for NSFontAttributeName.
2117     RetainPtr<CTFontDescriptorRef> fontDescriptor = adoptCF(CTFontDescriptorCreateWithNameAndSize(CFSTR("Helvetica"), 10));
2118     if (symbolicTraits)
2119         fontDescriptor = adoptCF(CTFontDescriptorCreateCopyWithSymbolicTraits(fontDescriptor.get(), symbolicTraits, symbolicTraits));
2120     
2121     RetainPtr<CTFontRef> font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor.get(), 10, nullptr));
2122     if (font)
2123         [result setObject:(id)font.get() forKey:NSFontAttributeName];
2124     
2125     if (typingAttributes & AttributeUnderline)
2126         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
2127
2128     return result;
2129 }
2130
2131 - (UIColor *)insertionPointColor
2132 {
2133     if (!_webView.configuration._textInteractionGesturesEnabled)
2134         return [UIColor clearColor];
2135
2136     if (!_page->editorState().isMissingPostLayoutData) {
2137         WebCore::Color caretColor = _page->editorState().postLayoutData().caretColor;
2138         if (caretColor.isValid())
2139             return [UIColor colorWithCGColor:cachedCGColor(caretColor)];
2140     }
2141     return [UIColor insertionPointColor];
2142 }
2143
2144 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
2145 {
2146     return [_webView canPerformAction:action withSender:sender];
2147 }
2148
2149 - (BOOL)canPerformActionForWebView:(SEL)action withSender:(id)sender
2150 {
2151     BOOL hasWebSelection = _webSelectionAssistant && !CGRectIsEmpty(_webSelectionAssistant.get().selectionFrame);
2152
2153     if (action == @selector(_arrowKey:))
2154         return [self isFirstResponder];
2155         
2156     if (action == @selector(_showTextStyleOptions:))
2157         return _page->editorState().isContentRichlyEditable && _page->editorState().selectionIsRange && !_showingTextStyleOptions;
2158     if (_showingTextStyleOptions)
2159         return (action == @selector(toggleBoldface:) || action == @selector(toggleItalics:) || action == @selector(toggleUnderline:));
2160     if (action == @selector(toggleBoldface:) || action == @selector(toggleItalics:) || action == @selector(toggleUnderline:))
2161         return _page->editorState().isContentRichlyEditable;
2162     if (action == @selector(cut:))
2163         return !_page->editorState().isInPasswordField && _page->editorState().isContentEditable && _page->editorState().selectionIsRange;
2164     
2165     if (action == @selector(paste:)) {
2166         if (_page->editorState().selectionIsNone || !_page->editorState().isContentEditable)
2167             return NO;
2168         UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
2169         NSArray *types = [self supportedPasteboardTypesForCurrentSelection];
2170         NSIndexSet *indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pasteboard numberOfItems])];
2171         return [pasteboard containsPasteboardTypes:types inItemSet:indices];
2172     }
2173
2174     if (action == @selector(copy:)) {
2175         if (_page->editorState().isInPasswordField)
2176             return NO;
2177         return hasWebSelection || _page->editorState().selectionIsRange;
2178     }
2179
2180     if (action == @selector(_define:)) {
2181         if (_page->editorState().isInPasswordField || !(hasWebSelection || _page->editorState().selectionIsRange))
2182             return NO;
2183
2184         NSUInteger textLength = _page->editorState().postLayoutData().selectedTextLength;
2185         // FIXME: We should be calling UIReferenceLibraryViewController to check if the length is
2186         // acceptable, but the interface takes a string.
2187         // <rdar://problem/15254406>
2188         if (!textLength || textLength > 200)
2189             return NO;
2190
2191         if ([[getMCProfileConnectionClass() sharedConnection] effectiveBoolValueForSetting:MCFeatureDefinitionLookupAllowed] == MCRestrictedBoolExplicitNo)
2192             return NO;
2193             
2194         return YES;
2195     }
2196
2197     if (action == @selector(_lookup:)) {
2198         if (_page->editorState().isInPasswordField)
2199             return NO;
2200         
2201         if ([[getMCProfileConnectionClass() sharedConnection] effectiveBoolValueForSetting:MCFeatureDefinitionLookupAllowed] == MCRestrictedBoolExplicitNo)
2202             return NO;
2203         
2204         return YES;
2205     }
2206
2207     if (action == @selector(_share:)) {
2208         if (_page->editorState().isInPasswordField || !(hasWebSelection || _page->editorState().selectionIsRange))
2209             return NO;
2210
2211         return _page->editorState().postLayoutData().selectedTextLength > 0;
2212     }
2213
2214     if (action == @selector(_addShortcut:)) {
2215         if (_page->editorState().isInPasswordField || !(hasWebSelection || _page->editorState().selectionIsRange))
2216             return NO;
2217
2218         NSString *selectedText = [self selectedText];
2219         if (![selectedText length])
2220             return NO;
2221
2222         if (!UIKeyboardEnabledInputModesAllowOneToManyShortcuts())
2223             return NO;
2224         if (![selectedText _containsCJScripts])
2225             return NO;
2226         return YES;
2227     }
2228
2229     if (action == @selector(_promptForReplace:)) {
2230         if (!_page->editorState().selectionIsRange || !_page->editorState().postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
2231             return NO;
2232         if ([[self selectedText] _containsCJScriptsOnly])
2233             return NO;
2234         return YES;
2235     }
2236
2237     if (action == @selector(_transliterateChinese:)) {
2238         if (!_page->editorState().selectionIsRange || !_page->editorState().postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
2239             return NO;
2240         return UIKeyboardEnabledInputModesAllowChineseTransliterationForText([self selectedText]);
2241     }
2242
2243     if (action == @selector(_reanalyze:)) {
2244         if (!_page->editorState().selectionIsRange || !_page->editorState().postLayoutData().isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
2245             return NO;
2246         return UIKeyboardCurrentInputModeAllowsChineseOrJapaneseReanalysisForText([self selectedText]);
2247     }
2248
2249     if (action == @selector(select:)) {
2250         // Disable select in password fields so that you can't see word boundaries.
2251         return !_page->editorState().isInPasswordField && [self hasContent] && !_page->editorState().selectionIsNone && !_page->editorState().selectionIsRange;
2252     }
2253
2254     if (action == @selector(selectAll:)) {
2255         if (_page->editorState().selectionIsNone || ![self hasContent])
2256             return NO;
2257         if (!_page->editorState().selectionIsRange)
2258             return YES;
2259         // Enable selectAll for non-editable text, where the user can't access
2260         // this command via long-press to get a caret.
2261         if (_page->editorState().isContentEditable)
2262             return NO;
2263         // Don't attempt selectAll with general web content.
2264         if (hasWebSelection)
2265             return NO;
2266         // FIXME: Only enable if the selection doesn't already span the entire document.
2267         return YES;
2268     }
2269
2270     if (action == @selector(replace:))
2271         return _page->editorState().isContentEditable && !_page->editorState().isInPasswordField;
2272
2273     return [super canPerformAction:action withSender:sender];
2274 }
2275
2276 - (id)targetForAction:(SEL)action withSender:(id)sender
2277 {
2278     return [_webView targetForAction:action withSender:sender];
2279 }
2280
2281 - (id)targetForActionForWebView:(SEL)action withSender:(id)sender
2282 {
2283     return [super targetForAction:action withSender:sender];
2284 }
2285
2286 - (void)_resetShowingTextStyle:(NSNotification *)notification
2287 {
2288     _showingTextStyleOptions = NO;
2289     [_textSelectionAssistant hideTextStyleOptions];
2290 }
2291
2292 - (void)copyForWebView:(id)sender
2293 {
2294     _page->executeEditCommand(ASCIILiteral("copy"));
2295 }
2296
2297 - (void)cutForWebView:(id)sender
2298 {
2299     _page->executeEditCommand(ASCIILiteral("cut"));
2300 }
2301
2302 - (void)pasteForWebView:(id)sender
2303 {
2304     _page->executeEditCommand(ASCIILiteral("paste"));
2305 }
2306
2307 - (void)selectForWebView:(id)sender
2308 {
2309     [_textSelectionAssistant selectWord];
2310     // We cannot use selectWord command, because we want to be able to select the word even when it is the last in the paragraph.
2311     _page->extendSelection(WordGranularity);
2312 }
2313
2314 - (void)selectAllForWebView:(id)sender
2315 {
2316     [_textSelectionAssistant selectAll:sender];
2317     _page->executeEditCommand(ASCIILiteral("selectAll"));
2318 }
2319
2320 - (void)toggleBoldfaceForWebView:(id)sender
2321 {
2322     if (!_page->editorState().isContentRichlyEditable)
2323         return;
2324
2325     [self executeEditCommandWithCallback:@"toggleBold"];
2326 }
2327
2328 - (void)toggleItalicsForWebView:(id)sender
2329 {
2330     if (!_page->editorState().isContentRichlyEditable)
2331         return;
2332
2333     [self executeEditCommandWithCallback:@"toggleItalic"];
2334 }
2335
2336 - (void)toggleUnderlineForWebView:(id)sender
2337 {
2338     if (!_page->editorState().isContentRichlyEditable)
2339         return;
2340
2341     [self executeEditCommandWithCallback:@"toggleUnderline"];
2342 }
2343
2344 - (void)_showTextStyleOptionsForWebView:(id)sender
2345 {
2346     _showingTextStyleOptions = YES;
2347     [_textSelectionAssistant showTextStyleOptions];
2348 }
2349
2350 - (void)_showDictionary:(NSString *)text
2351 {
2352     CGRect presentationRect = _page->editorState().postLayoutData().selectionRects[0].rect();
2353     if (_textSelectionAssistant)
2354         [_textSelectionAssistant showDictionaryFor:text fromRect:presentationRect];
2355     else
2356         [_webSelectionAssistant showDictionaryFor:text fromRect:presentationRect];
2357 }
2358
2359 - (void)_defineForWebView:(id)sender
2360 {
2361     if ([[getMCProfileConnectionClass() sharedConnection] effectiveBoolValueForSetting:MCFeatureDefinitionLookupAllowed] == MCRestrictedBoolExplicitNo)
2362         return;
2363
2364     RetainPtr<WKContentView> view = self;
2365     _page->getSelectionOrContentsAsString([view](const String& string, WebKit::CallbackBase::Error error) {
2366         if (error != WebKit::CallbackBase::Error::None)
2367             return;
2368         if (!string)
2369             return;
2370
2371         [view _showDictionary:string];
2372     });
2373 }
2374
2375 - (void)accessibilityRetrieveSpeakSelectionContent
2376 {
2377     RetainPtr<WKContentView> view = self;
2378     RetainPtr<WKWebView> webView = _webView;
2379     _page->getSelectionOrContentsAsString([view, webView](const String& string, WebKit::CallbackBase::Error error) {
2380         if (error != WebKit::CallbackBase::Error::None)
2381             return;
2382         [webView _accessibilityDidGetSpeakSelectionContent:string];
2383         if ([view respondsToSelector:@selector(accessibilitySpeakSelectionSetContent:)])
2384             [view accessibilitySpeakSelectionSetContent:string];
2385     });
2386 }
2387
2388 - (void)_accessibilityRetrieveRectsEnclosingSelectionOffset:(NSInteger)offset withGranularity:(UITextGranularity)granularity
2389 {
2390     RetainPtr<WKContentView> view = self;
2391     _page->requestRectsForGranularityWithSelectionOffset(toWKTextGranularity(granularity), offset , [view, offset, granularity](const Vector<WebCore::SelectionRect>& selectionRects, CallbackBase::Error error) {
2392         if (error != WebKit::CallbackBase::Error::None)
2393             return;
2394         if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
2395             [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionRects:selectionRects] withGranularity:granularity atOffset:offset];
2396     });
2397 }
2398
2399 - (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text
2400 {
2401     [self _accessibilityRetrieveRectsAtSelectionOffset:offset withText:text completionHandler:nil];
2402 }
2403
2404 - (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text completionHandler:(void (^)(const Vector<SelectionRect>& rects))completionHandler
2405 {
2406     RetainPtr<WKContentView> view = self;
2407     _page->requestRectsAtSelectionOffsetWithText(offset, text, [view, offset, capturedCompletionHandler = makeBlockPtr(completionHandler)](const Vector<SelectionRect>& selectionRects, CallbackBase::Error error) {
2408         if (capturedCompletionHandler)
2409             capturedCompletionHandler(selectionRects);
2410
2411         if (error != WebKit::CallbackBase::Error::None)
2412             return;
2413         if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
2414             [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionRects:selectionRects] withGranularity:UITextGranularityWord atOffset:offset];
2415     });
2416 }
2417
2418 - (void)_accessibilityStoreSelection
2419 {
2420     _page->storeSelectionForAccessibility(true);
2421 }
2422
2423 - (void)_accessibilityClearSelection
2424 {
2425     _page->storeSelectionForAccessibility(false);
2426 }
2427
2428 // UIWKInteractionViewProtocol
2429
2430 static inline GestureType toGestureType(UIWKGestureType gestureType)
2431 {
2432     switch (gestureType) {
2433     case UIWKGestureLoupe:
2434         return GestureType::Loupe;
2435     case UIWKGestureOneFingerTap:
2436         return GestureType::OneFingerTap;
2437     case UIWKGestureTapAndAHalf:
2438         return GestureType::TapAndAHalf;
2439     case UIWKGestureDoubleTap:
2440         return GestureType::DoubleTap;
2441     case UIWKGestureTapAndHalf:
2442         return GestureType::TapAndHalf;
2443     case UIWKGestureDoubleTapInUneditable:
2444         return GestureType::DoubleTapInUneditable;
2445     case UIWKGestureOneFingerTapInUneditable:
2446         return GestureType::OneFingerTapInUneditable;
2447     case UIWKGestureOneFingerTapSelectsAll:
2448         return GestureType::OneFingerTapSelectsAll;
2449     case UIWKGestureOneFingerDoubleTap:
2450         return GestureType::OneFingerDoubleTap;
2451     case UIWKGestureOneFingerTripleTap:
2452         return GestureType::OneFingerTripleTap;
2453     case UIWKGestureTwoFingerSingleTap:
2454         return GestureType::TwoFingerSingleTap;
2455     case UIWKGestureTwoFingerRangedSelectGesture:
2456         return GestureType::TwoFingerRangedSelectGesture;
2457     case UIWKGestureTapOnLinkWithGesture:
2458         return GestureType::TapOnLinkWithGesture;
2459     case UIWKGestureMakeWebSelection:
2460         return GestureType::MakeWebSelection;
2461     case UIWKGesturePhraseBoundary:
2462         return GestureType::PhraseBoundary;
2463     }
2464     ASSERT_NOT_REACHED();
2465     return GestureType::Loupe;
2466 }
2467
2468 static inline UIWKGestureType toUIWKGestureType(GestureType gestureType)
2469 {
2470     switch (gestureType) {
2471     case GestureType::Loupe:
2472         return UIWKGestureLoupe;
2473     case GestureType::OneFingerTap:
2474         return UIWKGestureOneFingerTap;
2475     case GestureType::TapAndAHalf:
2476         return UIWKGestureTapAndAHalf;
2477     case GestureType::DoubleTap:
2478         return UIWKGestureDoubleTap;
2479     case GestureType::TapAndHalf:
2480         return UIWKGestureTapAndHalf;
2481     case GestureType::DoubleTapInUneditable:
2482         return UIWKGestureDoubleTapInUneditable;
2483     case GestureType::OneFingerTapInUneditable:
2484         return UIWKGestureOneFingerTapInUneditable;
2485     case GestureType::OneFingerTapSelectsAll:
2486         return UIWKGestureOneFingerTapSelectsAll;
2487     case GestureType::OneFingerDoubleTap:
2488         return UIWKGestureOneFingerDoubleTap;
2489     case GestureType::OneFingerTripleTap:
2490         return UIWKGestureOneFingerTripleTap;
2491     case GestureType::TwoFingerSingleTap:
2492         return UIWKGestureTwoFingerSingleTap;
2493     case GestureType::TwoFingerRangedSelectGesture:
2494         return UIWKGestureTwoFingerRangedSelectGesture;
2495     case GestureType::TapOnLinkWithGesture:
2496         return UIWKGestureTapOnLinkWithGesture;
2497     case GestureType::MakeWebSelection:
2498         return UIWKGestureMakeWebSelection;
2499     case GestureType::PhraseBoundary:
2500         return UIWKGesturePhraseBoundary;
2501     }
2502 }
2503
2504 static inline SelectionTouch toSelectionTouch(UIWKSelectionTouch touch)
2505 {
2506     switch (touch) {
2507     case UIWKSelectionTouchStarted:
2508         return SelectionTouch::Started;
2509     case UIWKSelectionTouchMoved:
2510         return SelectionTouch::Moved;
2511     case UIWKSelectionTouchEnded:
2512         return SelectionTouch::Ended;
2513     case UIWKSelectionTouchEndedMovingForward:
2514         return SelectionTouch::EndedMovingForward;
2515     case UIWKSelectionTouchEndedMovingBackward:
2516         return SelectionTouch::EndedMovingBackward;
2517     case UIWKSelectionTouchEndedNotMoving:
2518         return SelectionTouch::EndedNotMoving;
2519     }
2520     ASSERT_NOT_REACHED();
2521     return SelectionTouch::Ended;
2522 }
2523
2524 static inline UIWKSelectionTouch toUIWKSelectionTouch(SelectionTouch touch)
2525 {
2526     switch (touch) {
2527     case SelectionTouch::Started:
2528         return UIWKSelectionTouchStarted;
2529     case SelectionTouch::Moved:
2530         return UIWKSelectionTouchMoved;
2531     case SelectionTouch::Ended:
2532         return UIWKSelectionTouchEnded;
2533     case SelectionTouch::EndedMovingForward:
2534         return UIWKSelectionTouchEndedMovingForward;
2535     case SelectionTouch::EndedMovingBackward:
2536         return UIWKSelectionTouchEndedMovingBackward;
2537     case SelectionTouch::EndedNotMoving:
2538         return UIWKSelectionTouchEndedNotMoving;
2539     }
2540 }
2541
2542 static inline GestureRecognizerState toGestureRecognizerState(UIGestureRecognizerState state)
2543 {
2544     switch (state) {
2545     case UIGestureRecognizerStatePossible:
2546         return GestureRecognizerState::Possible;
2547     case UIGestureRecognizerStateBegan:
2548         return GestureRecognizerState::Began;
2549     case UIGestureRecognizerStateChanged:
2550         return GestureRecognizerState::Changed;
2551     case UIGestureRecognizerStateCancelled:
2552         return GestureRecognizerState::Cancelled;
2553     case UIGestureRecognizerStateEnded:
2554         return GestureRecognizerState::Ended;
2555     case UIGestureRecognizerStateFailed:
2556         return GestureRecognizerState::Failed;
2557     }
2558 }
2559
2560 static inline UIGestureRecognizerState toUIGestureRecognizerState(GestureRecognizerState state)
2561 {
2562     switch (state) {
2563     case GestureRecognizerState::Possible:
2564         return UIGestureRecognizerStatePossible;
2565     case GestureRecognizerState::Began:
2566         return UIGestureRecognizerStateBegan;
2567     case GestureRecognizerState::Changed:
2568         return UIGestureRecognizerStateChanged;
2569     case GestureRecognizerState::Cancelled:
2570         return UIGestureRecognizerStateCancelled;
2571     case GestureRecognizerState::Ended:
2572         return UIGestureRecognizerStateEnded;
2573     case GestureRecognizerState::Failed:
2574         return UIGestureRecognizerStateFailed;
2575     }
2576 }
2577
2578 static inline UIWKSelectionFlags toUIWKSelectionFlags(SelectionFlags flags)
2579 {
2580     NSInteger uiFlags = UIWKNone;
2581     if (flags & WordIsNearTap)
2582         uiFlags |= UIWKWordIsNearTap;
2583     if (flags & PhraseBoundaryChanged)
2584         uiFlags |= UIWKPhraseBoundaryChanged;
2585
2586     return static_cast<UIWKSelectionFlags>(uiFlags);
2587 }
2588
2589 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
2590 static inline SelectionHandlePosition toSelectionHandlePosition(UIWKHandlePosition position)
2591 {
2592     switch (position) {
2593     case UIWKHandleTop:
2594         return SelectionHandlePosition::Top;
2595     case UIWKHandleRight:
2596         return SelectionHandlePosition::Right;
2597     case UIWKHandleBottom:
2598         return SelectionHandlePosition::Bottom;
2599     case UIWKHandleLeft:
2600         return SelectionHandlePosition::Left;
2601     }
2602 }
2603 #endif
2604
2605 static inline WebCore::TextGranularity toWKTextGranularity(UITextGranularity granularity)
2606 {
2607     switch (granularity) {
2608     case UITextGranularityCharacter:
2609         return CharacterGranularity;
2610     case UITextGranularityWord:
2611         return WordGranularity;
2612     case UITextGranularitySentence:
2613         return SentenceGranularity;
2614     case UITextGranularityParagraph:
2615         return ParagraphGranularity;
2616     case UITextGranularityLine:
2617         return LineGranularity;
2618     case UITextGranularityDocument:
2619         return DocumentGranularity;
2620     }
2621 }
2622
2623 static inline WebCore::SelectionDirection toWKSelectionDirection(UITextDirection direction)
2624 {
2625     switch (direction) {
2626     case UITextLayoutDirectionDown:
2627     case UITextLayoutDirectionRight:
2628         return DirectionRight;
2629     case UITextLayoutDirectionUp:
2630     case UITextLayoutDirectionLeft:
2631         return DirectionLeft;
2632     default:
2633         // UITextDirection is not an enum, but we only want to accept values from UITextLayoutDirection.
2634         ASSERT_NOT_REACHED();
2635         return DirectionRight;
2636     }
2637 }
2638
2639 static void selectionChangedWithGesture(WKContentView *view, const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t flags, WebKit::CallbackBase::Error error)
2640 {
2641     if (error != WebKit::CallbackBase::Error::None) {
2642         ASSERT_NOT_REACHED();
2643         return;
2644     }
2645     if ([view webSelectionAssistant])
2646         [(UIWKSelectionAssistant *)[view webSelectionAssistant] selectionChangedWithGestureAt:(CGPoint)point withGesture:toUIWKGestureType((GestureType)gestureType) withState:toUIGestureRecognizerState(static_cast<GestureRecognizerState>(gestureState)) withFlags:(toUIWKSelectionFlags((SelectionFlags)flags))];
2647     else
2648         [(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithGestureAt:(CGPoint)point withGesture:toUIWKGestureType((GestureType)gestureType) withState:toUIGestureRecognizerState(static_cast<GestureRecognizerState>(gestureState)) withFlags:(toUIWKSelectionFlags((SelectionFlags)flags))];
2649 }
2650
2651 static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoint& point, uint32_t touch, uint32_t flags, WebKit::CallbackBase::Error error)
2652 {
2653     if (error != WebKit::CallbackBase::Error::None) {
2654         ASSERT_NOT_REACHED();
2655         return;
2656     }
2657     if ([view webSelectionAssistant])
2658         [(UIWKSelectionAssistant *)[view webSelectionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((SelectionTouch)touch) withFlags:static_cast<UIWKSelectionFlags>(flags)];
2659     else
2660         [(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((SelectionTouch)touch) withFlags:static_cast<UIWKSelectionFlags>(flags)];
2661 }
2662
2663 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
2664 - (void)_didUpdateBlockSelectionWithTouch:(SelectionTouch)touch withFlags:(SelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold
2665 {
2666     [_webSelectionAssistant blockSelectionChangedWithTouch:toUIWKSelectionTouch(touch) withFlags:toUIWKSelectionFlags(flags) growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
2667     if (touch != SelectionTouch::Started && touch != SelectionTouch::Moved)
2668         _usingGestureForSelection = NO;
2669 }
2670 #endif
2671
2672 - (BOOL)_isInteractingWithAssistedNode
2673 {
2674     return _textSelectionAssistant != nil;
2675 }
2676
2677 - (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(UIWKGestureType)gestureType withState:(UIGestureRecognizerState)state
2678 {
2679     [self changeSelectionWithGestureAt:point withGesture:gestureType withState:state withFlags:UIWKNone];
2680 }
2681
2682 - (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(UIWKGestureType)gestureType withState:(UIGestureRecognizerState)state withFlags:(UIWKSelectionFlags)flags
2683 {
2684     _usingGestureForSelection = YES;
2685     _page->selectWithGesture(WebCore::IntPoint(point), CharacterGranularity, static_cast<uint32_t>(toGestureType(gestureType)), static_cast<uint32_t>(toGestureRecognizerState(state)), [self _isInteractingWithAssistedNode], [self, state, flags](const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t innerFlags, WebKit::CallbackBase::Error error) {
2686         selectionChangedWithGesture(self, point, gestureType, gestureState, flags | innerFlags, error);
2687         if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled)
2688             _usingGestureForSelection = NO;
2689     });
2690 }
2691
2692 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
2693 - (void)changeSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch baseIsStart:(BOOL)baseIsStart
2694 {
2695     [self changeSelectionWithTouchAt:point withSelectionTouch:touch baseIsStart:baseIsStart withFlags:UIWKNone];
2696 }
2697 #endif
2698
2699 - (void)changeSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch baseIsStart:(BOOL)baseIsStart withFlags:(UIWKSelectionFlags)flags
2700 {
2701     _usingGestureForSelection = YES;
2702     _page->updateSelectionWithTouches(WebCore::IntPoint(point), static_cast<uint32_t>(toSelectionTouch(touch)), baseIsStart, [self, flags](const WebCore::IntPoint& point, uint32_t touch, uint32_t innerFlags, WebKit::CallbackBase::Error error) {
2703         selectionChangedWithTouch(self, point, touch, flags | innerFlags, error);
2704         if (touch != UIWKSelectionTouchStarted && touch != UIWKSelectionTouchMoved)
2705             _usingGestureForSelection = NO;
2706     });
2707 }
2708
2709 - (void)changeSelectionWithTouchesFrom:(CGPoint)from to:(CGPoint)to withGesture:(UIWKGestureType)gestureType withState:(UIGestureRecognizerState)gestureState
2710 {
2711     _usingGestureForSelection = YES;
2712     _page->selectWithTwoTouches(WebCore::IntPoint(from), WebCore::IntPoint(to), static_cast<uint32_t>(toGestureType(gestureType)), static_cast<uint32_t>(toGestureRecognizerState(gestureState)), [self](const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t flags, WebKit::CallbackBase::Error error) {
2713         selectionChangedWithGesture(self, point, gestureType, gestureState, flags, error);
2714         if (gestureState == UIGestureRecognizerStateEnded || gestureState == UIGestureRecognizerStateCancelled)
2715             _usingGestureForSelection = NO;
2716     });
2717 }
2718
2719 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
2720 - (void)changeBlockSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch forHandle:(UIWKHandlePosition)handle
2721 {
2722     // This was only readded to avoid a crash due to incompatibilities with certain version of UIKit.
2723     // This should be removed ASAP.
2724     // The selection will be properly updated with the next update, selection still functions
2725     // without this function doing anything.
2726     
2727     _usingGestureForSelection = YES;
2728     _page->updateBlockSelectionWithTouch(WebCore::IntPoint(point), static_cast<uint32_t>(toSelectionTouch(touch)), static_cast<uint32_t>(toSelectionHandlePosition(handle)));
2729 }
2730 #endif
2731
2732 - (void)moveByOffset:(NSInteger)offset
2733 {
2734     if (!offset)
2735         return;
2736     
2737     [self beginSelectionChange];
2738     RetainPtr<WKContentView> view = self;
2739     _page->moveSelectionByOffset(offset, [view](WebKit::CallbackBase::Error) {
2740         [view endSelectionChange];
2741     });
2742 }
2743
2744 - (const WKAutoCorrectionData&)autocorrectionData
2745 {
2746     return _autocorrectionData;
2747 }
2748
2749 // The completion handler can pass nil if input does not match the actual text preceding the insertion point.
2750 - (void)requestAutocorrectionRectsForString:(NSString *)input withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForInput))completionHandler
2751 {
2752     if (!input || ![input length]) {
2753         completionHandler(nil);
2754         return;
2755     }
2756
2757     RetainPtr<WKContentView> view = self;
2758     _autocorrectionData.autocorrectionHandler = [completionHandler copy];
2759     _page->requestAutocorrectionData(input, [view](const Vector<FloatRect>& rects, const String& fontName, double fontSize, uint64_t traits, WebKit::CallbackBase::Error) {
2760         CGRect firstRect = CGRectZero;
2761         CGRect lastRect = CGRectZero;
2762         if (rects.size()) {
2763             firstRect = rects[0];
2764             lastRect = rects[rects.size() - 1];
2765         }
2766         
2767         view->_autocorrectionData.fontName = fontName;
2768         view->_autocorrectionData.fontSize = fontSize;
2769         view->_autocorrectionData.fontTraits = traits;
2770         view->_autocorrectionData.textFirstRect = firstRect;
2771         view->_autocorrectionData.textLastRect = lastRect;
2772
2773         view->_autocorrectionData.autocorrectionHandler(rects.size() ? [WKAutocorrectionRects autocorrectionRectsWithRects:firstRect lastRect:lastRect] : nil);
2774         [view->_autocorrectionData.autocorrectionHandler release];
2775         view->_autocorrectionData.autocorrectionHandler = nil;
2776     });
2777 }
2778
2779 - (void)selectPositionAtPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
2780 {
2781     _usingGestureForSelection = YES;
2782     UIWKSelectionCompletionHandler selectionHandler = [completionHandler copy];
2783     RetainPtr<WKContentView> view = self;
2784     
2785     _page->selectPositionAtPoint(WebCore::IntPoint(point), [self _isInteractingWithAssistedNode], [view, selectionHandler](WebKit::CallbackBase::Error error) {
2786         selectionHandler();
2787         view->_usingGestureForSelection = NO;
2788         [selectionHandler release];
2789     });
2790 }
2791
2792 - (void)selectPositionAtBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction fromPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
2793 {
2794     _usingGestureForSelection = YES;
2795     UIWKSelectionCompletionHandler selectionHandler = [completionHandler copy];
2796     RetainPtr<WKContentView> view = self;
2797     
2798     _page->selectPositionAtBoundaryWithDirection(WebCore::IntPoint(point), toWKTextGranularity(granularity), toWKSelectionDirection(direction), [self _isInteractingWithAssistedNode], [view, selectionHandler](WebKit::CallbackBase::Error error) {
2799         selectionHandler();
2800         view->_usingGestureForSelection = NO;
2801         [selectionHandler release];
2802     });
2803 }
2804
2805 - (void)moveSelectionAtBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction completionHandler:(void (^)(void))completionHandler
2806 {
2807     _usingGestureForSelection = YES;
2808     UIWKSelectionCompletionHandler selectionHandler = [completionHandler copy];
2809     RetainPtr<WKContentView> view = self;
2810     
2811     _page->moveSelectionAtBoundaryWithDirection(toWKTextGranularity(granularity), toWKSelectionDirection(direction), [view, selectionHandler](WebKit::CallbackBase::Error error) {
2812         selectionHandler();
2813         view->_usingGestureForSelection = NO;
2814         [selectionHandler release];
2815     });
2816 }
2817
2818 - (void)selectTextWithGranularity:(UITextGranularity)granularity atPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
2819 {
2820     _usingGestureForSelection = YES;
2821     UIWKSelectionCompletionHandler selectionHandler = [completionHandler copy];
2822     RetainPtr<WKContentView> view = self;
2823
2824     _page->selectTextWithGranularityAtPoint(WebCore::IntPoint(point), toWKTextGranularity(granularity), [self _isInteractingWithAssistedNode], [view, selectionHandler](WebKit::CallbackBase::Error error) {
2825         selectionHandler();
2826         view->_usingGestureForSelection = NO;
2827         [selectionHandler release];
2828     });
2829 }
2830
2831 - (void)beginSelectionInDirection:(UITextDirection)direction completionHandler:(void (^)(BOOL endIsMoving))completionHandler
2832 {
2833     UIWKSelectionWithDirectionCompletionHandler selectionHandler = [completionHandler copy];
2834
2835     _page->beginSelectionInDirection(toWKSelectionDirection(direction), [selectionHandler](bool endIsMoving, WebKit::CallbackBase::Error error) {
2836         selectionHandler(endIsMoving);
2837         [selectionHandler release];
2838     });
2839 }
2840
2841 - (void)updateSelectionWithExtentPoint:(CGPoint)point completionHandler:(void (^)(BOOL endIsMoving))completionHandler
2842 {
2843     UIWKSelectionWithDirectionCompletionHandler selectionHandler = [completionHandler copy];
2844     
2845     _page->updateSelectionWithExtentPoint(WebCore::IntPoint(point), [self _isInteractingWithAssistedNode], [selectionHandler](bool endIsMoving, WebKit::CallbackBase::Error error) {
2846         selectionHandler(endIsMoving);
2847         [selectionHandler release];
2848     });
2849 }
2850
2851 - (void)updateSelectionWithExtentPoint:(CGPoint)point withBoundary:(UITextGranularity)granularity completionHandler:(void (^)(BOOL selectionEndIsMoving))completionHandler
2852 {
2853     UIWKSelectionWithDirectionCompletionHandler selectionHandler = [completionHandler copy];
2854     
2855     _page->updateSelectionWithExtentPointAndBoundary(WebCore::IntPoint(point), toWKTextGranularity(granularity), [self _isInteractingWithAssistedNode], [selectionHandler](bool endIsMoving, WebKit::CallbackBase::Error error) {
2856         selectionHandler(endIsMoving);
2857         [selectionHandler release];
2858     });
2859 }
2860
2861 - (UTF32Char)_characterBeforeCaretSelection
2862 {
2863     return _page->editorState().postLayoutData().characterBeforeSelection;
2864 }
2865
2866 - (UTF32Char)_characterInRelationToCaretSelection:(int)amount
2867 {
2868     switch (amount) {
2869     case 0:
2870         return _page->editorState().postLayoutData().characterAfterSelection;
2871     case -1:
2872         return _page->editorState().postLayoutData().characterBeforeSelection;
2873     case -2:
2874         return _page->editorState().postLayoutData().twoCharacterBeforeSelection;
2875     default:
2876         return 0;
2877     }
2878 }
2879
2880 - (BOOL)_selectionAtDocumentStart
2881 {
2882     return !_page->editorState().postLayoutData().characterBeforeSelection;
2883 }
2884
2885 - (CGRect)textFirstRect
2886 {
2887     return (_page->editorState().hasComposition) ? _page->editorState().firstMarkedRect : _autocorrectionData.textFirstRect;
2888 }
2889
2890 - (CGRect)textLastRect
2891 {
2892     return (_page->editorState().hasComposition) ? _page->editorState().lastMarkedRect : _autocorrectionData.textLastRect;
2893 }
2894
2895 - (void)replaceDictatedText:(NSString*)oldText withText:(NSString *)newText
2896 {
2897     _page->replaceDictatedText(oldText, newText);
2898 }
2899
2900 - (void)requestDictationContext:(void (^)(NSString *selectedText, NSString *beforeText, NSString *afterText))completionHandler
2901 {
2902     UIWKDictationContextHandler dictationHandler = [completionHandler copy];
2903
2904     _page->requestDictationContext([dictationHandler](const String& selectedText, const String& beforeText, const String& afterText, WebKit::CallbackBase::Error) {
2905         dictationHandler(selectedText, beforeText, afterText);
2906         [dictationHandler release];
2907     });
2908 }
2909
2910 // The completion handler should pass the rect of the correction text after replacing the input text, or nil if the replacement could not be performed.
2911 - (void)applyAutocorrection:(NSString *)correction toString:(NSString *)input withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForCorrection))completionHandler
2912 {
2913     // FIXME: Remove the synchronous call when <rdar://problem/16207002> is fixed.
2914     const bool useSyncRequest = true;
2915
2916     if (useSyncRequest) {
2917         completionHandler(_page->applyAutocorrection(correction, input) ? [WKAutocorrectionRects autocorrectionRectsWithRects:_autocorrectionData.textFirstRect lastRect:_autocorrectionData.textLastRect] : nil);
2918         return;
2919     }
2920     _autocorrectionData.autocorrectionHandler = [completionHandler copy];
2921     RetainPtr<WKContentView> view = self;
2922     _page->applyAutocorrection(correction, input, [view](const String& string, WebKit::CallbackBase::Error error) {
2923         view->_autocorrectionData.autocorrectionHandler(!string.isNull() ? [WKAutocorrectionRects autocorrectionRectsWithRects:view->_autocorrectionData.textFirstRect lastRect:view->_autocorrectionData.textLastRect] : nil);
2924         [view->_autocorrectionData.autocorrectionHandler release];
2925         view->_autocorrectionData.autocorrectionHandler = nil;
2926     });
2927 }
2928
2929 - (void)requestAutocorrectionContextWithCompletionHandler:(void (^)(UIWKAutocorrectionContext *autocorrectionContext))completionHandler
2930 {
2931     // FIXME: Remove the synchronous call when <rdar://problem/16207002> is fixed.
2932     const bool useSyncRequest = true;
2933
2934     if (useSyncRequest) {
2935         String beforeText;
2936         String markedText;
2937         String selectedText;
2938         String afterText;
2939         uint64_t location;
2940         uint64_t length;
2941         _page->getAutocorrectionContext(beforeText, markedText, selectedText, afterText, location, length);
2942         completionHandler([WKAutocorrectionContext autocorrectionContextWithData:beforeText markedText:markedText selectedText:selectedText afterText:afterText selectedRangeInMarkedText:NSMakeRange(location, length)]);
2943     } else {
2944         _autocorrectionData.autocorrectionContextHandler = [completionHandler copy];
2945         RetainPtr<WKContentView> view = self;
2946         _page->requestAutocorrectionContext([view](const String& beforeText, const String& markedText, const String& selectedText, const String& afterText, uint64_t location, uint64_t length, WebKit::CallbackBase::Error) {
2947             view->_autocorrectionData.autocorrectionContextHandler([WKAutocorrectionContext autocorrectionContextWithData:beforeText markedText:markedText selectedText:selectedText afterText:afterText selectedRangeInMarkedText:NSMakeRange(location, length)]);
2948         });
2949     }
2950 }
2951
2952 // UIWebFormAccessoryDelegate
2953 - (void)accessoryDone
2954 {
2955     [self resignFirstResponder];
2956 }
2957
2958 - (NSArray *)keyCommands
2959 {
2960     static NSArray* nonEditableKeyCommands = [@[
2961        [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:0 action:@selector(_arrowKey:)],
2962        [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:0 action:@selector(_arrowKey:)],
2963        [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:0 action:@selector(_arrowKey:)],
2964        [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:0 action:@selector(_arrowKey:)],
2965        
2966        [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierCommand action:@selector(_arrowKey:)],
2967        [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierCommand action:@selector(_arrowKey:)],
2968        
2969        [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
2970        [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
2971        [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
2972        [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
2973        
2974        [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
2975        [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
2976        [UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
2977        [UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow modifierFlags:UIKeyModifierAlternate action:@selector(_arrowKey:)],
2978        
2979        [UIKeyCommand keyCommandWithInput:@" " modifierFlags:0 action:@selector(_arrowKey:)],
2980        [UIKeyCommand keyCommandWithInput:@" " modifierFlags:UIKeyModifierShift action:@selector(_arrowKey:)],
2981        
2982        [UIKeyCommand keyCommandWithInput:UIKeyInputPageDown modifierFlags:0 action:@selector(_arrowKey:)],
2983        [UIKeyCommand keyCommandWithInput:UIKeyInputPageDown modifierFlags:0 action:@selector(_arrowKey:)],
2984     ] retain];
2985
2986     static NSArray* editableKeyCommands = [@[
2987        [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(_nextAccessoryTab:)],
2988        [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(_prevAccessoryTab:)]
2989     ] retain];
2990     
2991     return (_page->editorState().isContentEditable) ? editableKeyCommands : nonEditableKeyCommands;
2992 }
2993
2994 - (void)_arrowKeyForWebView:(id)sender
2995 {
2996     UIKeyCommand* command = sender;
2997     [self handleKeyEvent:command._triggeringEvent];
2998 }
2999
3000 - (void)_nextAccessoryTab:(id)sender
3001 {
3002     [self accessoryTab:YES];
3003 }
3004
3005 - (void)_prevAccessoryTab:(id)sender
3006 {
3007     [self accessoryTab:NO];
3008 }
3009
3010 - (void)accessoryTab:(BOOL)isNext
3011 {
3012     [_inputPeripheral endEditing];
3013     _inputPeripheral = nil;
3014
3015     _didAccessoryTabInitiateFocus = YES; // Will be cleared in either -_displayFormNodeInputView or -cleanupInteraction.
3016     [self beginSelectionChange];
3017     RetainPtr<WKContentView> view = self;
3018     _page->focusNextAssistedNode(isNext, [view](WebKit::CallbackBase::Error) {
3019         [view endSelectionChange];
3020         [view reloadInputViews];
3021     });
3022
3023 }
3024
3025 - (void)_becomeFirstResponderWithSelectionMovingForward:(BOOL)selectingForward completionHandler:(void (^)(BOOL didBecomeFirstResponder))completionHandler
3026 {
3027     auto completionHandlerCopy = Block_copy(completionHandler);
3028     RetainPtr<WKContentView> view = self;
3029     _page->setInitialFocus(selectingForward, false, WebKit::WebKeyboardEvent(), [view, completionHandlerCopy](WebKit::CallbackBase::Error) {
3030         BOOL didBecomeFirstResponder = view->_assistedNodeInformation.elementType != InputType::None && [view becomeFirstResponder];
3031         completionHandlerCopy(didBecomeFirstResponder);
3032         Block_release(completionHandlerCopy);
3033     });
3034 }
3035
3036 - (WebCore::Color)_tapHighlightColorForFastClick:(BOOL)forFastClick
3037 {
3038     ASSERT(_showDebugTapHighlightsForFastClicking);
3039     return forFastClick ? WebCore::Color(0, 225, 0, 127) : WebCore::Color(225, 0, 0, 127);
3040 }
3041
3042 - (void)_setDoubleTapGesturesEnabled:(BOOL)enabled
3043 {
3044     if (enabled && ![_doubleTapGestureRecognizer isEnabled]) {
3045         // The first tap recognized after re-enabling double tap gestures will not wait for the
3046         // second tap before committing. To fix this, we use a new double tap gesture recognizer.
3047         [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
3048         [_doubleTapGestureRecognizer setDelegate:nil];
3049         [self _createAndConfigureDoubleTapGestureRecognizer];
3050     }
3051
3052     if (_showDebugTapHighlightsForFastClicking && !enabled)
3053         _tapHighlightInformation.color = [self _tapHighlightColorForFastClick:YES];
3054
3055     [_doubleTapGestureRecognizer setEnabled:enabled];
3056     [_nonBlockingDoubleTapGestureRecognizer setEnabled:!enabled];
3057     [self _resetIsDoubleTapPending];
3058 }
3059
3060 - (void)accessoryAutoFill
3061 {
3062     id <_WKInputDelegate> inputDelegate = [_webView _inputDelegate];
3063     if ([inputDelegate respondsToSelector:@selector(_webView:accessoryViewCustomButtonTappedInFormInputSession:)])
3064         [inputDelegate _webView:_webView accessoryViewCustomButtonTappedInFormInputSession:_formInputSession.get()];
3065 }
3066
3067 - (void)accessoryClear
3068 {
3069     _page->setAssistedNodeValue(String());
3070 }
3071
3072 - (void)_updateAccessory
3073 {
3074     [_formAccessoryView setNextEnabled:_assistedNodeInformation.hasNextNode];
3075     [_formAccessoryView setPreviousEnabled:_assistedNodeInformation.hasPreviousNode];
3076
3077     if (currentUserInterfaceIdiomIsPad())
3078         [_formAccessoryView setClearVisible:NO];
3079     else {
3080         switch (_assistedNodeInformation.elementType) {
3081         case InputType::Date:
3082         case InputType::Month:
3083         case InputType::DateTimeLocal:
3084         case InputType::Time:
3085             [_formAccessoryView setClearVisible:YES];
3086             break;
3087         default:
3088             [_formAccessoryView setClearVisible:NO];
3089             break;
3090         }
3091     }
3092
3093     // FIXME: hide or show the AutoFill button as needed.
3094 }
3095
3096 // Keyboard interaction
3097 // UITextInput protocol implementation
3098
3099 - (BOOL)_allowAnimatedUpdateSelectionRectViews
3100 {
3101     return NO;
3102 }
3103
3104 - (void)beginSelectionChange
3105 {
3106     [self.inputDelegate selectionWillChange:self];
3107 }
3108
3109 - (void)endSelectionChange
3110 {
3111     [self.inputDelegate selectionDidChange:self];
3112 }
3113
3114 - (void)insertTextSuggestion:(UITextSuggestion *)textSuggestion
3115 {
3116     // FIXME: Replace NSClassFromString with actual class as soon as UIKit submitted the new class into the iOS SDK.
3117     if ([textSuggestion isKindOfClass:NSClassFromString(@"UITextAutofillSuggestion")]) {
3118         _page->autofillLoginCredentials([(UITextAutofillSuggestion *)textSuggestion username], [(UITextAutofillSuggestion *)textSuggestion password]);
3119         return;
3120     }
3121     id <_WKInputDelegate> inputDelegate = [_webView _inputDelegate];
3122     if ([inputDelegate respondsToSelector:@selector(_webView:insertTextSuggestion:inInputSession:)])
3123         [inputDelegate _webView:_webView insertTextSuggestion:textSuggestion inInputSession:_formInputSession.get()];
3124 }
3125
3126 - (NSString *)textInRange:(UITextRange *)range
3127 {
3128     return nil;
3129 }
3130
3131 - (void)replaceRange:(UITextRange *)range withText:(NSString *)text
3132 {
3133 }
3134
3135 - (UITextRange *)selectedTextRange
3136 {
3137     if (_page->editorState().selectionIsNone || _page->editorState().isMissingPostLayoutData)
3138         return nil;
3139     auto& postLayoutEditorStateData = _page->editorState().postLayoutData();
3140     FloatRect startRect = postLayoutEditorStateData.caretRectAtStart;
3141     FloatRect endRect = postLayoutEditorStateData.caretRectAtEnd;
3142     double inverseScale = [self inverseScale];
3143     // We want to keep the original caret width, while the height scales with
3144     // the content taking orientation into account.
3145     // We achieve this by scaling the width with the inverse
3146     // scale factor. This way, when it is converted from the content view
3147     // the width remains unchanged.
3148     if (startRect.width() < startRect.height())
3149         startRect.setWidth(startRect.width() * inverseScale);
3150     else
3151         startRect.setHeight(startRect.height() * inverseScale);
3152     if (endRect.width() < endRect.height()) {
3153         double delta = endRect.width();
3154         endRect.setWidth(endRect.width() * inverseScale);
3155         delta = endRect.width() - delta;
3156         endRect.move(delta, 0);
3157     } else {
3158         double delta = endRect.height();
3159         endRect.setHeight(endRect.height() * inverseScale);
3160         delta = endRect.height() - delta;
3161         endRect.move(0, delta);
3162     }
3163     return [WKTextRange textRangeWithState:_page->editorState().selectionIsNone
3164                                    isRange:_page->editorState().selectionIsRange
3165                                 isEditable:_page->editorState().isContentEditable
3166                                  startRect:startRect
3167                                    endRect:endRect
3168                             selectionRects:[self webSelectionRects]
3169                         selectedTextLength:postLayoutEditorStateData.selectedTextLength];
3170 }
3171
3172 - (CGRect)caretRectForPosition:(UITextPosition *)position
3173 {
3174     return ((WKTextPosition *)position).positionRect;
3175 }
3176
3177 - (NSArray *)selectionRectsForRange:(UITextRange *)range
3178 {
3179     return [WKTextSelectionRect textSelectionRectsWithWebRects:((WKTextRange *)range).selectionRects];
3180 }
3181
3182 - (void)setSelectedTextRange:(UITextRange *)range
3183 {
3184     if (_textSelectionAssistant && !range)
3185         [self clearSelection];
3186 }
3187
3188 - (BOOL)hasMarkedText
3189 {
3190     return [_markedText length];
3191 }
3192
3193 - (NSString *)markedText
3194 {
3195     return _markedText.get();
3196 }
3197
3198 - (UITextRange *)markedTextRange
3199 {
3200     return nil;
3201 }
3202
3203 - (NSDictionary *)markedTextStyle
3204 {
3205     return nil;
3206 }
3207
3208 - (void)setMarkedTextStyle:(NSDictionary *)styleDictionary
3209 {
3210 }
3211
3212 - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
3213 {
3214     _markedText = markedText;
3215     _page->setCompositionAsync(markedText, Vector<WebCore::CompositionUnderline>(), selectedRange, EditingRange());
3216 }
3217
3218 - (void)unmarkText
3219 {
3220     _markedText = nil;
3221     _page->confirmCompositionAsync();
3222 }
3223
3224 - (UITextPosition *)beginningOfDocument
3225 {
3226     return nil;
3227 }
3228
3229 - (UITextPosition *)endOfDocument
3230 {
3231     return nil;
3232 }
3233
3234 - (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
3235 {
3236     return nil;
3237 }
3238
3239 - (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset
3240 {
3241     return nil;
3242 }
3243
3244 - (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
3245 {
3246     return nil;
3247 }
3248
3249 - (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other
3250 {
3251     return NSOrderedSame;
3252 }
3253
3254 - (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition
3255 {
3256     return 0;
3257 }
3258
3259 - (id <UITextInputTokenizer>)tokenizer
3260 {
3261     return nil;
3262 }
3263
3264 - (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
3265 {
3266     return nil;
3267 }
3268
3269 - (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
3270 {
3271     return nil;
3272 }
3273
3274 - (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
3275 {
3276     return UITextWritingDirectionLeftToRight;
3277 }
3278
3279 - (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range
3280 {
3281 }
3282
3283 - (CGRect)firstRectForRange:(UITextRange *)range
3284 {
3285     return CGRectZero;
3286 }
3287
3288 /* Hit testing. */
3289 - (UITextPosition *)closestPositionToPoint:(CGPoint)point
3290 {
3291     return nil;
3292 }
3293
3294 - (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range
3295 {
3296     return nil;
3297 }
3298
3299 - (UITextRange *)characterRangeAtPoint:(CGPoint)point
3300 {
3301     return nil;
3302 }
3303
3304 - (void)deleteBackward
3305 {
3306     _page->executeEditCommand(ASCIILiteral("deleteBackward"));
3307 }
3308
3309 // Inserts the given string, replacing any selected or marked text.
3310 - (void)insertText:(NSString *)aStringValue
3311 {
3312     _page->insertTextAsync(aStringValue, EditingRange());
3313 }
3314
3315 - (BOOL)hasText
3316 {
3317     auto& editorState = _page->editorState();
3318     return !editorState.isMissingPostLayoutData && editorState.postLayoutData().hasPlainText;
3319 }
3320
3321 // end of UITextInput protocol implementation
3322
3323 static UITextAutocapitalizationType toUITextAutocapitalize(AutocapitalizeType webkitType)
3324 {
3325     switch (webkitType) {
3326     case AutocapitalizeTypeDefault:
3327         return UITextAutocapitalizationTypeSentences;
3328     case AutocapitalizeTypeNone:
3329         return UITextAutocapitalizationTypeNone;
3330     case AutocapitalizeTypeWords:
3331         return UITextAutocapitalizationTypeWords;
3332     case AutocapitalizeTypeSentences:
3333         return UITextAutocapitalizationTypeSentences;
3334     case AutocapitalizeTypeAllCharacters:
3335         return UITextAutocapitalizationTypeAllCharacters;
3336     }
3337
3338     return UITextAutocapitalizationTypeSentences;
3339 }
3340
3341 static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
3342 {
3343     switch (fieldName) {
3344     case WebCore::AutofillFieldName::Name:
3345         return UITextContentTypeName;
3346     case WebCore::AutofillFieldName::HonorificPrefix:
3347         return UITextContentTypeNamePrefix;
3348     case WebCore::AutofillFieldName::GivenName:
3349         return UITextContentTypeMiddleName;
3350     case WebCore::AutofillFieldName::AdditionalName:
3351         return UITextContentTypeMiddleName;
3352     case WebCore::AutofillFieldName::FamilyName:
3353         return UITextContentTypeFamilyName;
3354     case WebCore::AutofillFieldName::HonorificSuffix:
3355         return UITextContentTypeNameSuffix;
3356     case WebCore::AutofillFieldName::Nickname:
3357         return UITextContentTypeNickname;
3358     case WebCore::AutofillFieldName::OrganizationTitle:
3359         return UITextContentTypeJobTitle;
3360     case WebCore::AutofillFieldName::Organization:
3361         return UITextContentTypeOrganizationName;
3362     case WebCore::AutofillFieldName::StreetAddress:
3363         return UITextContentTypeFullStreetAddress;
3364     case WebCore::AutofillFieldName::AddressLine1:
3365         return UITextContentTypeStreetAddressLine1;
3366     case WebCore::AutofillFieldName::AddressLine2:
3367         return UITextContentTypeStreetAddressLine2;
3368     case WebCore::AutofillFieldName::AddressLevel3:
3369         return UITextContentTypeSublocality;
3370     case WebCore::AutofillFieldName::AddressLevel2:
3371         return UITextContentTypeAddressCity;
3372     case WebCore::AutofillFieldName::AddressLevel1:
3373         return UITextContentTypeAddressState;
3374     case WebCore::AutofillFieldName::CountryName:
3375         return UITextContentTypeCountryName;
3376     case WebCore::AutofillFieldName::PostalCode:
3377         return UITextContentTypePostalCode;
3378     case WebCore::AutofillFieldName::Tel:
3379         return UITextContentTypeTelephoneNumber;
3380     case WebCore::AutofillFieldName::Email:
3381         return UITextContentTypeEmailAddress;
3382     case WebCore::AutofillFieldName::URL:
3383         return UITextContentTypeURL;
3384     case WebCore::AutofillFieldName::None:
3385     case WebCore::AutofillFieldName::Username:
3386     case WebCore::AutofillFieldName::NewPassword:</