Replace InteractionInformationAtPosition.nodeAtPositionIsFocusedElement with an eleme...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Oct 2019 02:34:20 +0000 (02:34 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Oct 2019 02:34:20 +0000 (02:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=203498

Reviewed by Tim Horton.

Refactors InteractionInformationAtPosition, such that it doesn't need a special flag to indicate whether there
is a focused element at the position. This is a followup to webkit.org/b/203264; no new tests, as there should
be no change in behavior.

* Shared/FocusedElementInformation.cpp:
(WebKit::FocusedElementInformation::encode const):
(WebKit::FocusedElementInformation::decode):
* Shared/FocusedElementInformation.h:

Add an elementContext to FocusedElementInformation to represent the focused element; then, instead of checking
whether there is a focused element underneath the request position, simply check that the position information's
element context matches the FocusedElementInformation's element context.

Additionally, rename elementRect in FocusedElementInformation to interactionRect, to draw a distinction between
this rect and the new ElementContext's boundingRect.

* Shared/ios/InteractionInformationAtPosition.h:
* Shared/ios/InteractionInformationAtPosition.mm:
(WebKit::InteractionInformationAtPosition::encode const):
(WebKit::InteractionInformationAtPosition::decode):

Remove the nodeAtPositionIsFocusedElement flag.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _didGetTapHighlightForRequest:color:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:nodeHasBuiltInClickHandling:]):
(-[WKContentView _zoomToRevealFocusedElement]):
(-[WKContentView _selectionClipRect]):
(-[WKContentView gestureRecognizerShouldBegin:]):
(-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):

In various places that consult nodeAtPositionIsFocusedElement, instead check that the position information's
hit-tested element context is the same as the focused element, via FocusedElementInformation.

(-[WKContentView _didCommitLoadForMainFrame]):

Nuke the cached position information data upon navigation; without this tweak, we will fail when running several
iOS layout tests back-to-back, that tap in exactly the same location.

(rectToRevealWhenZoomingToFocusedElement):
(-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):
(-[WKContentView _elementDidBlur]):
(-[WKContentView rectForFocusedFormControlView:]):
(-[WKContentView _didChangeFocusedElementRect:toRect:]): Deleted.

Remove code to invalidate cached position information when changing the focused element rect.

* UIProcess/ios/forms/WKFormPopover.mm:
(-[WKRotatingPopover presentPopoverAnimated:]):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::positionInformation):
(WebKit::WebPage::getFocusedElementInformation):

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

Source/WebKit/ChangeLog
Source/WebKit/Shared/FocusedElementInformation.cpp
Source/WebKit/Shared/FocusedElementInformation.h
Source/WebKit/Shared/ios/InteractionInformationAtPosition.h
Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/UIProcess/ios/forms/WKFormPopover.mm
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

index 21bbb25..692c19c 100644 (file)
@@ -1,3 +1,62 @@
+2019-10-28  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Replace InteractionInformationAtPosition.nodeAtPositionIsFocusedElement with an element context
+        https://bugs.webkit.org/show_bug.cgi?id=203498
+
+        Reviewed by Tim Horton.
+
+        Refactors InteractionInformationAtPosition, such that it doesn't need a special flag to indicate whether there
+        is a focused element at the position. This is a followup to webkit.org/b/203264; no new tests, as there should
+        be no change in behavior.
+
+        * Shared/FocusedElementInformation.cpp:
+        (WebKit::FocusedElementInformation::encode const):
+        (WebKit::FocusedElementInformation::decode):
+        * Shared/FocusedElementInformation.h:
+
+        Add an elementContext to FocusedElementInformation to represent the focused element; then, instead of checking
+        whether there is a focused element underneath the request position, simply check that the position information's
+        element context matches the FocusedElementInformation's element context.
+
+        Additionally, rename elementRect in FocusedElementInformation to interactionRect, to draw a distinction between
+        this rect and the new ElementContext's boundingRect.
+
+        * Shared/ios/InteractionInformationAtPosition.h:
+        * Shared/ios/InteractionInformationAtPosition.mm:
+        (WebKit::InteractionInformationAtPosition::encode const):
+        (WebKit::InteractionInformationAtPosition::decode):
+
+        Remove the nodeAtPositionIsFocusedElement flag.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _didGetTapHighlightForRequest:color:quads:topLeftRadius:topRightRadius:bottomLeftRadius:bottomRightRadius:nodeHasBuiltInClickHandling:]):
+        (-[WKContentView _zoomToRevealFocusedElement]):
+        (-[WKContentView _selectionClipRect]):
+        (-[WKContentView gestureRecognizerShouldBegin:]):
+        (-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):
+
+        In various places that consult nodeAtPositionIsFocusedElement, instead check that the position information's
+        hit-tested element context is the same as the focused element, via FocusedElementInformation.
+
+        (-[WKContentView _didCommitLoadForMainFrame]):
+
+        Nuke the cached position information data upon navigation; without this tweak, we will fail when running several
+        iOS layout tests back-to-back, that tap in exactly the same location.
+
+        (rectToRevealWhenZoomingToFocusedElement):
+        (-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):
+        (-[WKContentView _elementDidBlur]):
+        (-[WKContentView rectForFocusedFormControlView:]):
+        (-[WKContentView _didChangeFocusedElementRect:toRect:]): Deleted.
+
+        Remove code to invalidate cached position information when changing the focused element rect.
+
+        * UIProcess/ios/forms/WKFormPopover.mm:
+        (-[WKRotatingPopover presentPopoverAnimated:]):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::positionInformation):
+        (WebKit::WebPage::getFocusedElementInformation):
+
 2019-10-28  Adrian Perez de Castro  <aperez@igalia.com>
 
         [GTK][WPE] Fix various non-unified build issues introduced since r251436
index 32dbbdd..d5aa31d 100644 (file)
@@ -63,7 +63,8 @@ Optional<OptionItem> OptionItem::decode(IPC::Decoder& decoder)
 
 void FocusedElementInformation::encode(IPC::Encoder& encoder) const
 {
-    encoder << elementRect;
+    encoder << interactionRect;
+    encoder << elementContext;
     encoder << lastInteractionLocation;
     encoder << minimumScaleFactor;
     encoder << maximumScaleFactor;
@@ -113,7 +114,10 @@ void FocusedElementInformation::encode(IPC::Encoder& encoder) const
 
 bool FocusedElementInformation::decode(IPC::Decoder& decoder, FocusedElementInformation& result)
 {
-    if (!decoder.decode(result.elementRect))
+    if (!decoder.decode(result.interactionRect))
+        return false;
+
+    if (!decoder.decode(result.elementContext))
         return false;
 
     if (!decoder.decode(result.lastInteractionLocation))
index d3d288c..5facfe1 100644 (file)
@@ -29,6 +29,7 @@
 #include <WebCore/AutocapitalizeTypes.h>
 #include <WebCore/Autofill.h>
 #include <WebCore/Color.h>
+#include <WebCore/ElementContext.h>
 #include <WebCore/GraphicsLayer.h>
 #include <WebCore/InputMode.h>
 #include <WebCore/IntRect.h>
@@ -96,7 +97,8 @@ struct OptionItem {
 using FocusedElementIdentifier = uint64_t;
 
 struct FocusedElementInformation {
-    WebCore::IntRect elementRect;
+    WebCore::IntRect interactionRect;
+    WebCore::ElementContext elementContext;
     WebCore::IntPoint lastInteractionLocation;
     double minimumScaleFactor { -INFINITY };
     double maximumScaleFactor { INFINITY };
index 5307d25..5de58d9 100644 (file)
@@ -51,7 +51,6 @@ struct InteractionInformationAtPosition {
     InteractionInformationRequest request;
 
     bool canBeValid { true };
-    bool nodeAtPositionIsFocusedElement { false };
     bool nodeAtPositionHasDoubleClickHandler { false };
 #if ENABLE(DATA_INTERACTION)
     bool hasSelectionAtPosition { false };
index 9c01309..bc72d1f 100644 (file)
@@ -44,7 +44,6 @@ void InteractionInformationAtPosition::encode(IPC::Encoder& encoder) const
     encoder << request;
 
     encoder << canBeValid;
-    encoder << nodeAtPositionIsFocusedElement;
     encoder << nodeAtPositionHasDoubleClickHandler;
 #if ENABLE(DATA_INTERACTION)
     encoder << hasSelectionAtPosition;
@@ -96,9 +95,6 @@ bool InteractionInformationAtPosition::decode(IPC::Decoder& decoder, Interaction
     if (!decoder.decode(result.canBeValid))
         return false;
 
-    if (!decoder.decode(result.nodeAtPositionIsFocusedElement))
-        return false;
-
     if (!decoder.decode(result.nodeAtPositionHasDoubleClickHandler))
         return false;
 
index e4c3d46..8957227 100644 (file)
@@ -1696,7 +1696,7 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
     if (!_isTapHighlightIDValid || _latestTapID != requestID)
         return;
 
-    if (hasFocusedElement(_focusedElementInformation) && _positionInformation.nodeAtPositionIsFocusedElement)
+    if (hasFocusedElement(_focusedElementInformation) && _positionInformation.elementContext == _focusedElementInformation.elementContext)
         return;
 
     _isTapHighlightIDValid = NO;
@@ -1871,7 +1871,7 @@ 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:_focusedElementInformation.elementRect
+    [self _zoomToFocusRect:_focusedElementInformation.interactionRect
         selectionRect:_didAccessoryTabInitiateFocus ? WebCore::FloatRect() : rectToRevealWhenZoomingToFocusedElement(_focusedElementInformation, _page->editorState())
         insideFixed:_focusedElementInformation.insideFixedPosition
         fontSize:_focusedElementInformation.nodeFontSize
@@ -1922,7 +1922,7 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
         return CGRectNull;
 
     if (_page->waitingForPostLayoutEditorStateUpdateAfterFocusingElement())
-        return _focusedElementInformation.elementRect;
+        return _focusedElementInformation.interactionRect;
 
     return _page->editorState().postLayoutData().focusedElementRect;
 }
@@ -2268,7 +2268,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
             // If the focused element is the same, prevent the gesture.
             if (![self ensurePositionInformationIsUpToDate:WebKit::InteractionInformationRequest(WebCore::roundedIntPoint(point))])
                 return NO;
-            if (_positionInformation.nodeAtPositionIsFocusedElement)
+            if (_positionInformation.elementContext == _focusedElementInformation.elementContext)
                 return NO;
         }
     }
@@ -2314,7 +2314,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 
         if (hasFocusedElement(_focusedElementInformation)) {
             // Prevent the gesture if it is the same node.
-            if (_positionInformation.nodeAtPositionIsFocusedElement)
+            if (_positionInformation.elementContext == _focusedElementInformation.elementContext)
                 return NO;
         } else {
             // Prevent the gesture if there is no action for the node.
@@ -2449,7 +2449,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 
     // If we're currently focusing an editable element, only allow the selection to move within that focused element.
     if (self.isFocusingElement)
-        return _positionInformation.nodeAtPositionIsFocusedElement;
+        return _positionInformation.elementContext == _focusedElementInformation.elementContext;
 
     // If we're selecting something, don't activate highlight.
     if (gesture == UIWKGestureLoupe && [self hasSelectablePositionAtPoint:point])
@@ -4150,6 +4150,9 @@ static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoi
     [self _cancelLongPressGestureRecognizer];
     [self _hideContextMenuHintContainer];
     [_webView _didCommitLoadForMainFrame];
+
+    _hasValidPositionInformation = NO;
+    _positionInformation = { };
 }
 
 #if !USE(UIKIT_KEYBOARD_ADDITIONS)
@@ -5401,7 +5404,7 @@ static bool shouldShowKeyboardForElement(const WebKit::FocusedElementInformation
 static WebCore::FloatRect rectToRevealWhenZoomingToFocusedElement(const WebKit::FocusedElementInformation& elementInfo, const WebKit::EditorState& editorState)
 {
     WebCore::IntRect elementInteractionRect;
-    if (elementInfo.elementRect.contains(elementInfo.lastInteractionLocation))
+    if (elementInfo.interactionRect.contains(elementInfo.lastInteractionLocation))
         elementInteractionRect = { elementInfo.lastInteractionLocation, { 1, 1 } };
 
     if (!mayContainSelectableText(elementInfo.elementType))
@@ -5423,7 +5426,7 @@ static WebCore::FloatRect rectToRevealWhenZoomingToFocusedElement(const WebKit::
     } else
         selectionBoundingRect = postLayoutData.caretRectAtStart;
 
-    selectionBoundingRect.intersect(elementInfo.elementRect);
+    selectionBoundingRect.intersect(elementInfo.interactionRect);
     return selectionBoundingRect;
 }
 
@@ -5524,7 +5527,7 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
 
     // FIXME: We should remove this check when we manage to send ElementDidFocus from the WebProcess
     // only when it is truly time to show the keyboard.
-    if (_focusedElementInformation.elementType == information.elementType && _focusedElementInformation.elementRect == information.elementRect) {
+    if (_focusedElementInformation.elementType == information.elementType && _focusedElementInformation.interactionRect == information.interactionRect) {
         if (_inputPeripheral) {
             if (!self.isFirstResponder)
                 [self becomeFirstResponder];
@@ -5556,7 +5559,6 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
     if (delegateImplementsWillStartInputSession)
         [inputDelegate _webView:_webView willStartInputSession:_formInputSession.get()];
 
-    auto previousElementRect = _isChangingFocus ? _focusedElementInformation.elementRect : WebCore::IntRect();
     BOOL isSelectable = mayContainSelectableText(information.elementType);
     BOOL editableChanged = [self setIsEditable:isSelectable];
     _focusedElementInformation = information;
@@ -5603,8 +5605,6 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
         [inputDelegate _webView:_webView didStartInputSession:_formInputSession.get()];
     
     [_webView didStartFormControlInteraction];
-
-    [self _didChangeFocusedElementRect:previousElementRect toRect:_focusedElementInformation.elementRect];
 }
 
 - (void)_elementDidBlur
@@ -5628,7 +5628,6 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
 #endif
 
     BOOL editableChanged = [self setIsEditable:NO];
-    auto previousElementRect = _focusedElementInformation.elementRect;
     // FIXME: We should completely invalidate _focusedElementInformation here, instead of a subset of individual members.
     _focusedElementInformation.elementType = WebKit::InputType::None;
     _focusedElementInformation.shouldSynthesizeKeyEventsForEditing = false;
@@ -5662,23 +5661,8 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
         _page->setIsShowingInputViewForFocusedElement(false);
     }
 
-    if (!_isChangingFocus) {
+    if (!_isChangingFocus)
         _didAccessoryTabInitiateFocus = NO;
-        [self _didChangeFocusedElementRect:previousElementRect toRect:WebCore::IntRect()];
-    }
-}
-
-- (void)_didChangeFocusedElementRect:(const WebCore::IntRect&)previousRect toRect:(const WebCore::IntRect&)newRect
-{
-    if (previousRect == newRect)
-        return;
-
-    if (newRect.isEmpty() && !_positionInformation.nodeAtPositionIsFocusedElement)
-        return;
-
-    // If the focused element rect changed, the cached position information's nodeAtPositionIsFocusedElement may be stale.
-    _hasValidPositionInformation = NO;
-    _positionInformation = { };
 }
 
 - (void)_updateInputContextAfterBlurringAndRefocusingElement
@@ -5989,7 +5973,7 @@ static BOOL allPasteboardItemOriginsMatchOrigin(UIPasteboard *pasteboard, const
 
 - (CGRect)rectForFocusedFormControlView:(WKFocusedFormControlView *)view
 {
-    return [self convertRect:_focusedElementInformation.elementRect toView:view];
+    return [self convertRect:_focusedElementInformation.interactionRect toView:view];
 }
 
 - (CGRect)nextRectForFocusedFormControlView:(WKFocusedFormControlView *)view
index a4c4ac3..09866ea 100644 (file)
@@ -142,7 +142,7 @@ ALLOW_DEPRECATED_DECLARATIONS_BEGIN
                           permittedArrowDirections:directions
                                           animated:animated];
     } else {
-        CGRect boundingBoxOfDOMNode = _view.focusedElementInformation.elementRect;
+        CGRect boundingBoxOfDOMNode = _view.focusedElementInformation.interactionRect;
         [_popoverController presentPopoverFromRect:CGRectIntegral(boundingBoxOfDOMNode)
                                             inView:_view
                           permittedArrowDirections:directions
index 6673d63..d623810 100644 (file)
@@ -2780,7 +2780,6 @@ InteractionInformationAtPosition WebPage::positionInformation(const InteractionI
     FloatPoint adjustedPoint;
     auto* nodeRespondingToClickEvents = m_page->mainFrame().nodeRespondingToClickEvents(request.point, adjustedPoint);
 
-    info.nodeAtPositionIsFocusedElement = nodeRespondingToClickEvents == m_focusedElement;
     info.adjustedPointForNodeRespondingToClickEvents = adjustedPoint;
     info.nodeAtPositionHasDoubleClickHandler = m_page->mainFrame().nodeRespondingToDoubleClickEvent(request.point, adjustedPoint);
 
@@ -2905,9 +2904,11 @@ void WebPage::getFocusedElementInformation(FocusedElementInformation& informatio
     layoutIfNeeded();
 
     information.lastInteractionLocation = m_lastInteractionLocation;
+    if (auto elementContext = contextForElement(*m_focusedElement))
+        information.elementContext = WTFMove(*elementContext);
 
     if (auto* renderer = m_focusedElement->renderer()) {
-        information.elementRect = rootViewInteractionBoundsForElement(*m_focusedElement);
+        information.interactionRect = rootViewInteractionBoundsForElement(*m_focusedElement);
         information.nodeFontSize = renderer->style().fontDescription().computedSize();
 
         bool inFixed = false;
@@ -2915,7 +2916,7 @@ void WebPage::getFocusedElementInformation(FocusedElementInformation& informatio
         information.insideFixedPosition = inFixed;
         information.isRTL = renderer->style().direction() == TextDirection::RTL;
     } else
-        information.elementRect = IntRect();
+        information.interactionRect = { };
 
     if (is<HTMLElement>(m_focusedElement))
         information.isSpellCheckingEnabled = downcast<HTMLElement>(*m_focusedElement).spellcheck();