[Extra zoom mode] Implement basic support for interacting with text form controls
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Feb 2018 23:17:22 +0000 (23:17 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Feb 2018 23:17:22 +0000 (23:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182401
<rdar://problem/35143035>

Reviewed by Tim Horton.

Add UI support for interacting with and editing text form controls when extra zoom mode is enabled. See below
for more details.

* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
(-[WKWebViewConfiguration init]):
(-[WKWebViewConfiguration encodeWithCoder:]):
(-[WKWebViewConfiguration initWithCoder:]):
(-[WKWebViewConfiguration copyWithZone:]):
(-[WKWebViewConfiguration _textInteractionGesturesEnabled]):
(-[WKWebViewConfiguration _setTextInteractionGesturesEnabled:]):
(-[WKWebViewConfiguration _longPressActionsEnabled]):
(-[WKWebViewConfiguration _setLongPressActionsEnabled:]):

Introduce two new web view configuration flags: `textInteractionGesturesEnabled` and `longPressActionsEnabled`.
The former determines whether text interaction gestures (i.e. text selection, moving the caret, showing UI for
IME, etc.) are enabled. The latter determines whether or not long press actions (i.e. touch callout, share
sheet, etc.) are enabled. These are disabled by default only in extra zoom mode.

* UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::setTextAsync):

Add a way to set the text value of a currently edited text form control. This will either set the text value of
an input, a. la. autofill, or overwrite the contents of a contenteditable area by selecting everything and
inserting the given text.

* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::focusNextAssistedNode):

Add a default argument for the completion callback.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setupInteraction]):
(-[WKContentView _displayFormNodeInputView]):
(-[WKContentView _actionForLongPressFromPositionInformation:]):
(-[WKContentView hasSelectablePositionAtPoint:]):
(-[WKContentView pointIsNearMarkedText:]):
(-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):
(-[WKContentView insertionPointColor]):

Respect the web view configuration flags above by bailing early from text interaction and long press action
sheet methods.

(-[WKContentView _startAssistingKeyboard]):
(-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:]):

Add a flag indicating whether we are in the process of changing focus from one node to another. We use this to
decide whether or not we want to present the text input view controller right away, or just reload the focused
form control overlay. When we stop "assisting" a node, we also keep the focused form control overlay up if we're
only changing focus to another form control.

(-[WKContentView _stopAssistingNode]):
(-[WKContentView presentFocusedFormControlViewController:]):
(-[WKContentView dismissFocusedFormControlViewController:]):
(-[WKContentView shouldPresentTextInputViewController:]):
(-[WKContentView presentTextInputViewController:]):
(-[WKContentView dismissTextInputViewController:]):

Introduce helpers for managing presentation of the focused form control overlay and text input view controller.
All -present and -dismiss helpers here are idempotent. These view controllers are presented from the content
view's view controller for fullscreen presentation.

(-[WKContentView textInputController:didCommitText:]):
(-[WKContentView textInputController:didRequestDismissalWithAction:]):
(-[WKContentView focusedFormControlControllerDidSubmit:]):
(-[WKContentView focusedFormControlControllerDidCancel:]):
(-[WKContentView focusedFormControlControllerDidBeginEditing:]):
(-[WKContentView highlightedRectForFocusedFormControlController:inCoordinateSpace:]):
(-[WKContentView actionNameForFocusedFormControlController:]):
(-[WKContentView focusedFormControlControllerDidRequestNextNode:]):
(-[WKContentView focusedFormControlControllerDidRequestPreviousNode:]):
(-[WKContentView hasNextNodeForFocusedFormControlController:]):
(-[WKContentView hasPreviousNodeForFocusedFormControlController:]):

Implement delegate methods for the focused form control and text input view controllers. This mainly involves
straightforward plumbing of pieces of AssistedNodeInformation on the content view.

(-[WKContentView pointIsInAssistedNode:]): Deleted.

Remove a method that was still implemented only for binary compatibility with iOS 10.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::setTextAsync):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227984 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in

index f31d7b4..2f47899 100644 (file)
@@ -1,3 +1,98 @@
+2018-02-01  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Extra zoom mode] Implement basic support for interacting with text form controls
+        https://bugs.webkit.org/show_bug.cgi?id=182401
+        <rdar://problem/35143035>
+
+        Reviewed by Tim Horton.
+
+        Add UI support for interacting with and editing text form controls when extra zoom mode is enabled. See below
+        for more details.
+
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        (-[WKWebViewConfiguration init]):
+        (-[WKWebViewConfiguration encodeWithCoder:]):
+        (-[WKWebViewConfiguration initWithCoder:]):
+        (-[WKWebViewConfiguration copyWithZone:]):
+        (-[WKWebViewConfiguration _textInteractionGesturesEnabled]):
+        (-[WKWebViewConfiguration _setTextInteractionGesturesEnabled:]):
+        (-[WKWebViewConfiguration _longPressActionsEnabled]):
+        (-[WKWebViewConfiguration _setLongPressActionsEnabled:]):
+
+        Introduce two new web view configuration flags: `textInteractionGesturesEnabled` and `longPressActionsEnabled`.
+        The former determines whether text interaction gestures (i.e. text selection, moving the caret, showing UI for
+        IME, etc.) are enabled. The latter determines whether or not long press actions (i.e. touch callout, share
+        sheet, etc.) are enabled. These are disabled by default only in extra zoom mode.
+
+        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::setTextAsync):
+
+        Add a way to set the text value of a currently edited text form control. This will either set the text value of
+        an input, a. la. autofill, or overwrite the contents of a contenteditable area by selecting everything and
+        inserting the given text.
+
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::focusNextAssistedNode):
+
+        Add a default argument for the completion callback.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView setupInteraction]):
+        (-[WKContentView _displayFormNodeInputView]):
+        (-[WKContentView _actionForLongPressFromPositionInformation:]):
+        (-[WKContentView hasSelectablePositionAtPoint:]):
+        (-[WKContentView pointIsNearMarkedText:]):
+        (-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):
+        (-[WKContentView insertionPointColor]):
+
+        Respect the web view configuration flags above by bailing early from text interaction and long press action
+        sheet methods.
+
+        (-[WKContentView _startAssistingKeyboard]):
+        (-[WKContentView _startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:]):
+
+        Add a flag indicating whether we are in the process of changing focus from one node to another. We use this to
+        decide whether or not we want to present the text input view controller right away, or just reload the focused
+        form control overlay. When we stop "assisting" a node, we also keep the focused form control overlay up if we're
+        only changing focus to another form control.
+
+        (-[WKContentView _stopAssistingNode]):
+        (-[WKContentView presentFocusedFormControlViewController:]):
+        (-[WKContentView dismissFocusedFormControlViewController:]):
+        (-[WKContentView shouldPresentTextInputViewController:]):
+        (-[WKContentView presentTextInputViewController:]):
+        (-[WKContentView dismissTextInputViewController:]):
+
+        Introduce helpers for managing presentation of the focused form control overlay and text input view controller.
+        All -present and -dismiss helpers here are idempotent. These view controllers are presented from the content
+        view's view controller for fullscreen presentation.
+
+        (-[WKContentView textInputController:didCommitText:]):
+        (-[WKContentView textInputController:didRequestDismissalWithAction:]):
+        (-[WKContentView focusedFormControlControllerDidSubmit:]):
+        (-[WKContentView focusedFormControlControllerDidCancel:]):
+        (-[WKContentView focusedFormControlControllerDidBeginEditing:]):
+        (-[WKContentView highlightedRectForFocusedFormControlController:inCoordinateSpace:]):
+        (-[WKContentView actionNameForFocusedFormControlController:]):
+        (-[WKContentView focusedFormControlControllerDidRequestNextNode:]):
+        (-[WKContentView focusedFormControlControllerDidRequestPreviousNode:]):
+        (-[WKContentView hasNextNodeForFocusedFormControlController:]):
+        (-[WKContentView hasPreviousNodeForFocusedFormControlController:]):
+
+        Implement delegate methods for the focused form control and text input view controllers. This mainly involves
+        straightforward plumbing of pieces of AssistedNodeInformation on the content view.
+
+        (-[WKContentView pointIsInAssistedNode:]): Deleted.
+
+        Remove a method that was still implemented only for binary compatibility with iOS 10.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::setTextAsync):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2018-02-01  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Shift + mouse scroll should scroll horizontally
index 14fea60..358184a 100644 (file)
@@ -130,6 +130,8 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     BOOL _inlineMediaPlaybackRequiresPlaysInlineAttribute;
     BOOL _allowsInlineMediaPlaybackAfterFullscreen;
     _WKDragLiftDelay _dragLiftDelay;
+    BOOL _textInteractionGesturesEnabled;
+    BOOL _longPressActionsEnabled;
 #endif
 
     BOOL _invisibleAutoplayNotPermitted;
@@ -225,7 +227,14 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
 #if PLATFORM(IOS)
     _selectionGranularity = WKSelectionGranularityDynamic;
     _dragLiftDelay = toDragLiftDelay([[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitDebugDragLiftDelay"]);
+#if ENABLE(EXTRA_ZOOM_MODE)
+    _textInteractionGesturesEnabled = NO;
+    _longPressActionsEnabled = NO;
+#else
+    _textInteractionGesturesEnabled = YES;
+    _longPressActionsEnabled = YES;
 #endif
+#endif // PLATFORM(IOS)
 
     _mediaContentTypesRequiringHardwareSupport = Settings::defaultMediaContentTypesRequiringHardwareSupport();
     _allowMediaContentTypesRequiringHardwareSupportAsFallback = YES;
@@ -265,6 +274,8 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     [coder encodeBool:self.allowsPictureInPictureMediaPlayback forKey:@"allowsPictureInPictureMediaPlayback"];
     [coder encodeBool:self.ignoresViewportScaleLimits forKey:@"ignoresViewportScaleLimits"];
     [coder encodeInteger:self._dragLiftDelay forKey:@"dragLiftDelay"];
+    [coder encodeBool:self._textInteractionGesturesEnabled forKey:@"textInteractionGesturesEnabled"];
+    [coder encodeBool:self._longPressActionsEnabled forKey:@"longPressActionsEnabled"];
 #else
     [coder encodeInteger:self.userInterfaceDirectionPolicy forKey:@"userInterfaceDirectionPolicy"];
 #endif
@@ -293,6 +304,8 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     self.allowsPictureInPictureMediaPlayback = [coder decodeBoolForKey:@"allowsPictureInPictureMediaPlayback"];
     self.ignoresViewportScaleLimits = [coder decodeBoolForKey:@"ignoresViewportScaleLimits"];
     self._dragLiftDelay = toDragLiftDelay([coder decodeIntegerForKey:@"dragLiftDelay"]);
+    self._textInteractionGesturesEnabled = [coder decodeBoolForKey:@"textInteractionGesturesEnabled"];
+    self._longPressActionsEnabled = [coder decodeBoolForKey:@"longPressActionsEnabled"];
 #else
     auto userInterfaceDirectionPolicyCandidate = static_cast<WKUserInterfaceDirectionPolicy>([coder decodeIntegerForKey:@"userInterfaceDirectionPolicy"]);
     if (userInterfaceDirectionPolicyCandidate == WKUserInterfaceDirectionPolicyContent || userInterfaceDirectionPolicyCandidate == WKUserInterfaceDirectionPolicySystem)
@@ -347,6 +360,8 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     configuration->_selectionGranularity = self->_selectionGranularity;
     configuration->_ignoresViewportScaleLimits = self->_ignoresViewportScaleLimits;
     configuration->_dragLiftDelay = self->_dragLiftDelay;
+    configuration->_textInteractionGesturesEnabled = self->_textInteractionGesturesEnabled;
+    configuration->_longPressActionsEnabled = self->_longPressActionsEnabled;
 #endif
 #if PLATFORM(MAC)
     configuration->_cpuLimit = self->_cpuLimit;
@@ -664,6 +679,28 @@ static NSString *defaultApplicationNameForUserAgent()
 {
     _dragLiftDelay = dragLiftDelay;
 }
+
+- (BOOL)_textInteractionGesturesEnabled
+{
+    return _textInteractionGesturesEnabled;
+}
+
+- (void)_setTextInteractionGesturesEnabled:(BOOL)enabled
+{
+    _textInteractionGesturesEnabled = enabled;
+}
+
+- (BOOL)_longPressActionsEnabled
+{
+    return _longPressActionsEnabled;
+}
+
+- (void)_setLongPressActionsEnabled:(BOOL)enabled
+{
+    _longPressActionsEnabled = enabled;
+}
+
+
 #endif // PLATFORM(IOS)
 
 - (BOOL)_invisibleAutoplayNotPermitted
index 9a01348..4e0a449 100644 (file)
@@ -76,6 +76,8 @@ typedef NS_ENUM(NSUInteger, _WKDragLiftDelay) {
 @property (nonatomic, setter=_setInlineMediaPlaybackRequiresPlaysInlineAttribute:) BOOL _inlineMediaPlaybackRequiresPlaysInlineAttribute WK_API_AVAILABLE(ios(10.0));
 @property (nonatomic, setter=_setAllowsInlineMediaPlaybackAfterFullscreen:) BOOL _allowsInlineMediaPlaybackAfterFullscreen  WK_API_AVAILABLE(ios(10.0));
 @property (nonatomic, setter=_setDragLiftDelay:) _WKDragLiftDelay _dragLiftDelay WK_API_AVAILABLE(ios(11.0));
+@property (nonatomic, setter=_setTextInteractionGesturesEnabled:) BOOL _textInteractionGesturesEnabled WK_API_AVAILABLE(ios(WK_IOS_TBA));
+@property (nonatomic, setter=_setLongPressActionsEnabled:) BOOL _longPressActionsEnabled WK_API_AVAILABLE(ios(WK_IOS_TBA));
 #else
 @property (nonatomic, setter=_setShowsURLsInToolTips:) BOOL _showsURLsInToolTips WK_API_AVAILABLE(macosx(10.12));
 @property (nonatomic, setter=_setServiceControlsEnabled:) BOOL _serviceControlsEnabled WK_API_AVAILABLE(macosx(10.12));
index cc3cf2f..f926b9e 100644 (file)
@@ -6560,6 +6560,12 @@ void WebPageProxy::addMIMETypeWithCustomContentProvider(const String& mimeType)
 
 #if PLATFORM(COCOA)
 
+void WebPageProxy::setTextAsync(const String& text)
+{
+    if (isValid())
+        process().send(Messages::WebPage::SetTextAsync(text), m_pageID);
+}
+
 void WebPageProxy::insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo, bool suppressSelectionUpdate)
 {
     if (!isValid())
index 943ad2b..cff18f5 100644 (file)
@@ -572,7 +572,7 @@ public:
 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 120000
     void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold);
 #endif
-    void focusNextAssistedNode(bool isForward, WTF::Function<void (CallbackBase::Error)>&&);
+    void focusNextAssistedNode(bool isForward, WTF::Function<void (CallbackBase::Error)>&& = [] (auto) { });
     void setAssistedNodeValue(const String&);
     void setAssistedNodeValueAsNumber(double);
     void setAssistedNodeSelectedIndex(uint32_t index, bool allowMultipleSelection = false);
@@ -638,6 +638,7 @@ public:
     void setAcceleratedCompositingRootLayer(LayerOrView*);
     LayerOrView* acceleratedCompositingRootLayer() const;
 
+    void setTextAsync(const String&);
     void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
     void getMarkedRangeAsync(WTF::Function<void (EditingRange, CallbackBase::Error)>&&);
     void getSelectedRangeAsync(WTF::Function<void (EditingRange, CallbackBase::Error)>&&);
index 39de2ef..cdfa61b 100644 (file)
@@ -83,8 +83,9 @@ class WebPageProxy;
 @class _UIHighlightView;
 @class _UIWebHighlightLongPressGestureRecognizer;
 
-#if ENABLE(DATA_INTERACTION)
-@class _UITextDragCaretView;
+#if ENABLE(EXTRA_ZOOM_MODE)
+@class WKFocusedFormControlViewController;
+@class WKTextInputViewController;
 #endif
 
 typedef void (^UIWKAutocorrectionCompletionHandler)(UIWKAutocorrectionRects *rectsForInput);
@@ -229,6 +230,7 @@ struct WKAutoCorrectionData {
     BOOL _becomingFirstResponder;
     BOOL _resigningFirstResponder;
     BOOL _needsDeferredEndScrollingSelectionUpdate;
+    BOOL _isChangingFocus;
 
 #if ENABLE(DATA_INTERACTION)
     WebKit::DragDropInteractionState _dragDropInteractionState;
@@ -239,6 +241,11 @@ struct WKAutoCorrectionData {
     RetainPtr<UIView> _visibleContentViewSnapshot;
     RetainPtr<_UITextDragCaretView> _editDropCaretView;
 #endif
+
+#if ENABLE(EXTRA_ZOOM_MODE)
+    RetainPtr<WKTextInputViewController> _textInputViewController;
+    RetainPtr<WKFocusedFormControlViewController> _focusedFormControlViewController;
+#endif
 }
 
 @end
index 8297b4f..f187226 100644 (file)
@@ -41,6 +41,7 @@
 #import "UIKitSPI.h"
 #import "WKActionSheetAssistant.h"
 #import "WKError.h"
+#import "WKFocusedFormControlViewController.h"
 #import "WKFormInputControl.h"
 #import "WKFormSelectControl.h"
 #import "WKImagePreviewViewController.h"
@@ -49,6 +50,7 @@
 #import "WKPreviewActionItemIdentifiers.h"
 #import "WKPreviewActionItemInternal.h"
 #import "WKPreviewElementInfoInternal.h"
+#import "WKTextInputViewController.h"
 #import "WKUIDelegatePrivate.h"
 #import "WKWebViewConfiguration.h"
 #import "WKWebViewConfigurationPrivate.h"
@@ -70,6 +72,7 @@
 #import <WebCore/Color.h>
 #import <WebCore/DataDetection.h>
 #import <WebCore/FloatQuad.h>
+#import <WebCore/LocalizedStrings.h>
 #import <WebCore/NotImplemented.h>
 #import <WebCore/Pasteboard.h>
 #import <WebCore/Path.h>
 
 @end
 
+#if ENABLE(EXTRA_ZOOM_MODE)
+
+@interface WKContentView (ExtraZoomMode) <WKTextFormControlViewControllerDelegate, WKFocusedFormControlViewControllerDelegate>
+@end
+
+#endif
+
 using namespace WebCore;
 using namespace WebKit;
 
@@ -626,6 +636,7 @@ static WKDragSessionContext *ensureLocalDragSessionContext(id <UIDragSession> se
     _isDoubleTapPending = NO;
     _showDebugTapHighlightsForFastClicking = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitShowFastClickDebugTapHighlights"];
     _needsDeferredEndScrollingSelectionUpdate = NO;
+    _isChangingFocus = NO;
 }
 
 - (void)cleanupInteraction
@@ -1205,13 +1216,13 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
     // In case user scaling is force enabled, do not use that scaling when zooming in with an input field.
     // Zooming above the page's default scale factor should only happen when the user performs it.
     [self _zoomToFocusRect:_assistedNodeInformation.elementRect
-             selectionRect:_didAccessoryTabInitiateFocus ? IntRect() : _assistedNodeInformation.selectionRect
-               insideFixed:_assistedNodeInformation.insideFixedPosition
-                  fontSize:_assistedNodeInformation.nodeFontSize
-              minimumScale:_assistedNodeInformation.minimumScaleFactor
-              maximumScale:_assistedNodeInformation.maximumScaleFactorIgnoringAlwaysScalable
-              allowScaling:(_assistedNodeInformation.allowsUserScalingIgnoringAlwaysScalable && !currentUserInterfaceIdiomIsPad())
-               forceScroll:[self requiresAccessoryView]];
+        selectionRect:_didAccessoryTabInitiateFocus ? IntRect() : _assistedNodeInformation.selectionRect
+        insideFixed:_assistedNodeInformation.insideFixedPosition
+        fontSize:_assistedNodeInformation.nodeFontSize
+        minimumScale:_assistedNodeInformation.minimumScaleFactor
+        maximumScale:_assistedNodeInformation.maximumScaleFactorIgnoringAlwaysScalable
+        allowScaling:_assistedNodeInformation.allowsUserScalingIgnoringAlwaysScalable && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone
+        forceScroll:[self requiresAccessoryView]];
 
     _didAccessoryTabInitiateFocus = NO;
     [self _ensureFormAccessoryView];
@@ -1323,6 +1334,9 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 
 - (SEL)_actionForLongPressFromPositionInformation:(const InteractionInformationAtPosition&)positionInformation
 {
+    if (!_webView.configuration._longPressActionsEnabled)
+        return nil;
+
     if (!positionInformation.touchCalloutEnabled)
         return nil;
 
@@ -1549,6 +1563,9 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 
 - (BOOL)hasSelectablePositionAtPoint:(CGPoint)point
 {
+    if (!_webView.configuration._textInteractionGesturesEnabled)
+        return NO;
+
     if (_inspectorNodeSearchEnabled)
         return NO;
 
@@ -1569,21 +1586,20 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 
 - (BOOL)pointIsNearMarkedText:(CGPoint)point
 {
+    if (!_webView.configuration._textInteractionGesturesEnabled)
+        return NO;
+
     InteractionInformationRequest request(roundedIntPoint(point));
     if (![self ensurePositionInformationIsUpToDate:request])
         return NO;
     return _positionInformation.isNearMarkedText;
 }
-#if __IPHONE_OS_VERSION_MAX_ALLOWED < 110000
-- (BOOL)pointIsInAssistedNode:(CGPoint)point
-{
-    // This method is still implemented for backwards compatibility with older UIKit versions.
-    return [self textInteractionGesture:UIWKGestureLoupe shouldBeginAtPoint:point];
-}
-#endif
 
 - (BOOL)textInteractionGesture:(UIWKGestureType)gesture shouldBeginAtPoint:(CGPoint)point
 {
+    if (!_webView.configuration._textInteractionGesturesEnabled)
+        return NO;
+
     InteractionInformationRequest request(roundedIntPoint(point));
     if (![self ensurePositionInformationIsUpToDate:request])
         return NO;
@@ -2103,6 +2119,9 @@ FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)
 
 - (UIColor *)insertionPointColor
 {
+    if (!_webView.configuration._textInteractionGesturesEnabled)
+        return [UIColor clearColor];
+
     if (!_page->editorState().isMissingPostLayoutData) {
         WebCore::Color caretColor = _page->editorState().postLayoutData().caretColor;
         if (caretColor.isValid())
@@ -3903,7 +3922,13 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
 - (void)_startAssistingKeyboard
 {
     [self useSelectionAssistantWithGranularity:WKSelectionGranularityCharacter];
+
+#if ENABLE(EXTRA_ZOOM_MODE)
+    if (!_isChangingFocus && [self shouldPresentTextInputViewController:_assistedNodeInformation])
+        [self presentTextInputViewController:YES];
+#else
     [self reloadInputViews];
+#endif
 }
 
 - (void)_stopAssistingKeyboard
@@ -3959,6 +3984,7 @@ static bool isAssistableInputType(InputType type)
 
 - (void)_startAssistingNode:(const AssistedNodeInformation&)information userIsInteracting:(BOOL)userIsInteracting blurPreviousNode:(BOOL)blurPreviousNode changingActivityState:(BOOL)changingActivityState userObject:(NSObject <NSSecureCoding> *)userObject
 {
+    SetForScope<BOOL> isChangingFocusForScope { _isChangingFocus, _assistedNodeInformation.elementType != InputType::None };
     _inputViewUpdateDeferrer = nullptr;
 
     id <_WKInputDelegate> inputDelegate = [_webView _inputDelegate];
@@ -3992,6 +4018,11 @@ static bool isAssistableInputType(InputType type)
     _assistedNodeInformation = information;
     _inputPeripheral = nil;
     _traits = nil;
+
+#if ENABLE(EXTRA_ZOOM_MODE)
+    [self presentFocusedFormControlViewController:NO];
+#endif
+
     if (![self isFirstResponder])
         [self becomeFirstResponder];
 
@@ -4015,6 +4046,11 @@ static bool isAssistableInputType(InputType type)
     
     [self _displayFormNodeInputView];
 
+#if ENABLE(EXTRA_ZOOM_MODE)
+    if (_isChangingFocus)
+        [_focusedFormControlViewController reloadData:YES];
+#endif
+
     // _inputPeripheral has been initialized in inputView called by reloadInputViews.
     [_inputPeripheral beginEditing];
 
@@ -4043,6 +4079,12 @@ static bool isAssistableInputType(InputType type)
     // The name is misleading, but this actually clears the selection views and removes any selection.
     [_webSelectionAssistant resignedFirstResponder];
 
+#if ENABLE(EXTRA_ZOOM_MODE)
+    [self dismissTextInputViewController:YES];
+    if (!_isChangingFocus)
+        [self dismissFocusedFormControlViewController:[_focusedFormControlViewController isVisible]];
+#endif
+
     // The custom fixed position rect behavior is affected by -isAssistingNode, so if that changes we need to recompute rects.
     if (editableChanged)
         [_webView _scheduleVisibleContentRectUpdate];
@@ -4050,6 +4092,140 @@ static bool isAssistableInputType(InputType type)
     [_webView didEndFormControlInteraction];
 }
 
+#if ENABLE(EXTRA_ZOOM_MODE)
+
+- (void)presentFocusedFormControlViewController:(BOOL)animated
+{
+    if (_focusedFormControlViewController)
+        return;
+
+    _focusedFormControlViewController = adoptNS([[WKFocusedFormControlViewController alloc] init]);
+    [_focusedFormControlViewController setDelegate:self];
+    [[UIViewController _viewControllerForFullScreenPresentationFromView:self] presentViewController:_focusedFormControlViewController.get() animated:animated completion:nil];
+}
+
+- (void)dismissFocusedFormControlViewController:(BOOL)animated
+{
+    if (!_focusedFormControlViewController)
+        return;
+
+    [_focusedFormControlViewController dismissViewControllerAnimated:animated completion:nil];
+    _focusedFormControlViewController = nil;
+}
+
+- (BOOL)shouldPresentTextInputViewController:(const AssistedNodeInformation&)info
+{
+    switch (info.elementType) {
+    case InputType::ContentEditable:
+    case InputType::Text:
+    case InputType::Password:
+    case InputType::TextArea:
+    case InputType::Search:
+    case InputType::Email:
+    case InputType::URL:
+        return true;
+    default:
+        return false;
+    }
+}
+
+- (void)presentTextInputViewController:(BOOL)animated
+{
+    if (_textInputViewController)
+        return;
+
+    _textInputViewController = adoptNS([[WKTextInputViewController alloc] initWithText:_assistedNodeInformation.value textSuggestions:@[ ]]);
+    [_textInputViewController setDelegate:self];
+    [_focusedFormControlViewController presentViewController:_textInputViewController.get() animated:animated completion:nil];
+}
+
+- (void)dismissTextInputViewController:(BOOL)animated
+{
+    if (!_textInputViewController)
+        return;
+
+    auto textInputViewController = WTFMove(_textInputViewController);
+    [textInputViewController dismissViewControllerAnimated:animated completion:nil];
+}
+
+- (void)textInputController:(WKTextFormControlViewController *)controller didCommitText:(NSString *)text
+{
+    // FIXME: Update cached AssistedNodeInformation state in the UI process.
+    _page->setTextAsync(text);
+}
+
+- (void)textInputController:(WKTextFormControlViewController *)controller didRequestDismissalWithAction:(WKFormControlAction)action
+{
+    if (action == WKFormControlActionCancel) {
+        _page->blurAssistedNode();
+        return;
+    }
+
+    if (_assistedNodeInformation.formAction.isEmpty() && !_assistedNodeInformation.hasNextNode && !_assistedNodeInformation.hasPreviousNode) {
+        // In this case, there's no point in collapsing down to the form control focus UI because there's nothing the user could potentially do
+        // besides dismiss the UI, so we just automatically dismiss the focused form control UI.
+        _page->blurAssistedNode();
+        return;
+    }
+
+    [_focusedFormControlViewController show:NO];
+    [self dismissTextInputViewController:YES];
+}
+
+- (void)focusedFormControlControllerDidSubmit:(WKFocusedFormControlViewController *)controller
+{
+    [self insertText:@"\n"];
+    _page->blurAssistedNode();
+}
+
+- (void)focusedFormControlControllerDidCancel:(WKFocusedFormControlViewController *)controller
+{
+    _page->blurAssistedNode();
+}
+
+- (void)focusedFormControlControllerDidBeginEditing:(WKFocusedFormControlViewController *)controller
+{
+    if ([self shouldPresentTextInputViewController:_assistedNodeInformation])
+        [self presentTextInputViewController:YES];
+}
+
+- (CGRect)highlightedRectForFocusedFormControlController:(WKFocusedFormControlViewController *)controller inCoordinateSpace:(id <UICoordinateSpace>)coordinateSpace
+{
+    return [self convertRect:_assistedNodeInformation.elementRect toCoordinateSpace:coordinateSpace];
+}
+
+- (NSString *)actionNameForFocusedFormControlController:(WKFocusedFormControlViewController *)controller
+{
+    if (_assistedNodeInformation.formAction.isEmpty())
+        return nil;
+
+    return _assistedNodeInformation.elementType == InputType::Search ? formControlSearchButtonTitle() : formControlGoButtonTitle();
+}
+
+- (void)focusedFormControlControllerDidRequestNextNode:(WKFocusedFormControlViewController *)controller
+{
+    if (_assistedNodeInformation.hasNextNode)
+        _page->focusNextAssistedNode(true);
+}
+
+- (void)focusedFormControlControllerDidRequestPreviousNode:(WKFocusedFormControlViewController *)controller
+{
+    if (_assistedNodeInformation.hasPreviousNode)
+        _page->focusNextAssistedNode(false);
+}
+
+- (BOOL)hasNextNodeForFocusedFormControlController:(WKFocusedFormControlViewController *)controller
+{
+    return _assistedNodeInformation.hasNextNode;
+}
+
+- (BOOL)hasPreviousNodeForFocusedFormControlController:(WKFocusedFormControlViewController *)controller
+{
+    return _assistedNodeInformation.hasPreviousNode;
+}
+
+#endif // ENABLE(EXTRA_ZOOM_MODE)
+
 - (void)_selectionChanged
 {
     _selectionNeedsUpdate = YES;
index e966d32..7c79b8d 100644 (file)
@@ -4590,6 +4590,21 @@ bool WebPage::shouldUseCustomContentProviderForResponse(const ResourceResponse&
 
 #if PLATFORM(COCOA)
 
+void WebPage::setTextAsync(const String& text)
+{
+    if (is<HTMLInputElement>(m_assistedNode.get())) {
+        downcast<HTMLInputElement>(*m_assistedNode).setValueForUser(text);
+        return;
+    }
+
+    auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
+    if (!frame->selection().selection().isContentEditable())
+        return;
+
+    frame->selection().selectAll();
+    frame->editor().insertText(text, nullptr, TextEventInputKeyboard);
+}
+
 void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
index 07d39d4..c1e8305 100644 (file)
@@ -708,6 +708,7 @@ public:
     
     void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput);
 
+    void setTextAsync(const String&);
     void insertTextAsync(const String& text, const EditingRange& replacementRange, bool registerUndoGroup = false, uint32_t editingRangeIsRelativeTo = (uint32_t)EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
     void getMarkedRangeAsync(CallbackID);
     void getSelectedRangeAsync(CallbackID);
index 7251b9a..1f13512 100644 (file)
@@ -390,6 +390,7 @@ messages -> WebPage LegacyReceiver {
     ShouldDelayWindowOrderingEvent(WebKit::WebMouseEvent event) -> (bool result)
     AcceptsFirstMouse(int eventNumber, WebKit::WebMouseEvent event) -> (bool result)
 
+    SetTextAsync(String text)
     InsertTextAsync(String text, struct WebKit::EditingRange replacementRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
     GetMarkedRangeAsync(WebKit::CallbackID callbackID)
     GetSelectedRangeAsync(WebKit::CallbackID callbackID)