Title: [176305] trunk/Source/WebKit2
Revision
176305
Author
[email protected]
Date
2014-11-18 21:06:58 -0800 (Tue, 18 Nov 2014)

Log Message

iOS8 new "slow tap" heuristic fires mouse compat events despite preventDefault on touchend
https://bugs.webkit.org/show_bug.cgi?id=137069
rdar://problem/18481464

Patch by Benjamin Poulain <[email protected]> on 2014-11-18
Reviewed by Simon Fraser.

On WebKit2, we let UIWebTouchEventsGestureRecognizer and _UIWebHighlightLongPressGestureRecognizer
run concurrently. This causes a race with an incorrect behavior:
1) If UIWebTouchEventsGestureRecognizer does not cancel the native gestures on start.
2) _UIWebHighlightLongPressGestureRecognizer starts after highlightDelay.
3) When the finger leaves the screen, both gestures end.
-> If the touch end sent to _javascript_ in [3] ask the priority over native events, that no longer stops
   the _UIWebHighlightLongPressGestureRecognizer.

The two gesture recognizers can run in any order, there is no guarantee on which one runs first.
To solve the bug, I must make sure the _UIWebHighlightLongPressGestureRecognizer never trigger a click
if the page wants the event.

To solve the order problem, I use the fact that event recognition goes in two phases for
non cancelled events:
1) Update the gesture recognizers.
2) Trigger the actions.

I do not know the order of recognizers in [1], but I know both have run before [2] is executed.
I use that to stop _UIWebHighlightLongPressGestureRecognizer from ending with a click in the case of the bug:
1) When _UIWebHighlightLongPressGestureRecognizer starts, I set _highlightLongPressCanClick signaling
   the gesture can end normally. This is done on a timer and not direct input so I don't really have to worry
   about a race here.
2) When processing the touch event for UIWebTouchEventsGestureRecognizer, I reset the flag _highlightLongPressCanClick
   if the page wants the event.
3) When the actions of _UIWebHighlightLongPressGestureRecognizer are processed, the touch event
   has already been processed by the page and the flag has been cleared if needed.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _webTouchEvent:preventsNativeGestures:]):
(-[WKContentView _highlightLongPressRecognized:]):

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (176304 => 176305)


--- trunk/Source/WebKit2/ChangeLog	2014-11-19 04:31:51 UTC (rev 176304)
+++ trunk/Source/WebKit2/ChangeLog	2014-11-19 05:06:58 UTC (rev 176305)
@@ -1,3 +1,43 @@
+2014-11-18  Benjamin Poulain  <[email protected]>
+
+        iOS8 new "slow tap" heuristic fires mouse compat events despite preventDefault on touchend
+        https://bugs.webkit.org/show_bug.cgi?id=137069
+        rdar://problem/18481464
+
+        Reviewed by Simon Fraser.
+
+        On WebKit2, we let UIWebTouchEventsGestureRecognizer and _UIWebHighlightLongPressGestureRecognizer
+        run concurrently. This causes a race with an incorrect behavior:
+        1) If UIWebTouchEventsGestureRecognizer does not cancel the native gestures on start.
+        2) _UIWebHighlightLongPressGestureRecognizer starts after highlightDelay.
+        3) When the finger leaves the screen, both gestures end.
+        -> If the touch end sent to _javascript_ in [3] ask the priority over native events, that no longer stops
+           the _UIWebHighlightLongPressGestureRecognizer.
+
+        The two gesture recognizers can run in any order, there is no guarantee on which one runs first.
+        To solve the bug, I must make sure the _UIWebHighlightLongPressGestureRecognizer never trigger a click
+        if the page wants the event.
+
+        To solve the order problem, I use the fact that event recognition goes in two phases for
+        non cancelled events:
+        1) Update the gesture recognizers.
+        2) Trigger the actions.
+
+        I do not know the order of recognizers in [1], but I know both have run before [2] is executed.
+        I use that to stop _UIWebHighlightLongPressGestureRecognizer from ending with a click in the case of the bug:
+        1) When _UIWebHighlightLongPressGestureRecognizer starts, I set _highlightLongPressCanClick signaling
+           the gesture can end normally. This is done on a timer and not direct input so I don't really have to worry
+           about a race here.
+        2) When processing the touch event for UIWebTouchEventsGestureRecognizer, I reset the flag _highlightLongPressCanClick
+           if the page wants the event.
+        3) When the actions of _UIWebHighlightLongPressGestureRecognizer are processed, the touch event
+           has already been processed by the page and the flag has been cleared if needed.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _webTouchEvent:preventsNativeGestures:]):
+        (-[WKContentView _highlightLongPressRecognized:]):
+
 2014-11-18  Ryosuke Niwa  <[email protected]>
 
         iOS build fix after r176299. This method is not defined in WKViewIOS.mm.

Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h (176304 => 176305)


--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h	2014-11-19 04:31:51 UTC (rev 176304)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h	2014-11-19 05:06:58 UTC (rev 176305)
@@ -136,6 +136,7 @@
     BOOL _hasValidPositionInformation;
     BOOL _isTapHighlightIDValid;
     BOOL _potentialTapInProgress;
+    BOOL _highlightLongPressCanClick;
     BOOL _hasTapHighlightForPotentialTap;
     BOOL _selectionNeedsUpdate;
     BOOL _shouldRestoreSelection;

Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (176304 => 176305)


--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm	2014-11-19 04:31:51 UTC (rev 176304)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm	2014-11-19 05:06:58 UTC (rev 176305)
@@ -537,6 +537,8 @@
 - (void)_webTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent preventsNativeGestures:(BOOL)preventsNativeGesture
 {
     if (preventsNativeGesture) {
+        _highlightLongPressCanClick = NO;
+
         _canSendTouchEventsAsynchronously = YES;
         [_touchEventGestureRecognizer setDefaultPrevented:YES];
     }
@@ -934,19 +936,22 @@
 
     switch ([gestureRecognizer state]) {
     case UIGestureRecognizerStateBegan:
+        _highlightLongPressCanClick = YES;
         cancelPotentialTapIfNecessary(self);
         _page->tapHighlightAtPosition([gestureRecognizer startPoint], ++_latestTapHighlightID);
         _isTapHighlightIDValid = YES;
         break;
     case UIGestureRecognizerStateEnded:
-        if (!_positionInformation.clickableElementName.isEmpty()) {
+        if (_highlightLongPressCanClick && !_positionInformation.clickableElementName.isEmpty()) {
             [self _attemptClickAtLocation:[gestureRecognizer startPoint]];
             [self _finishInteraction];
         } else
             [self _cancelInteraction];
+        _highlightLongPressCanClick = NO;
         break;
     case UIGestureRecognizerStateCancelled:
         [self _cancelInteraction];
+        _highlightLongPressCanClick = NO;
         break;
     default:
         break;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to