Bug 211521 - REGRESSION (r253267): issues on touchstart/touchend/touchmove (pointerdown/pointerup/pointermove) events
Summary: REGRESSION (r253267): issues on touchstart/touchend/touchmove (pointerdown/po...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: UI Events (show other bugs)
Version: Safari 13
Hardware: iPhone / iPad iOS 13
: P2 Critical
Assignee: Wenson Hsieh
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-05-06 11:26 PDT by juwagn
Modified: 2020-05-11 09:23 PDT (History)
8 users (show)

See Also:


Attachments
reproducer requested (2.46 KB, text/html)
2020-05-06 14:58 PDT, juwagn
no flags Details
Patch (17.02 KB, patch)
2020-05-10 23:00 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff
For EWS (16.87 KB, patch)
2020-05-11 08:50 PDT, Wenson Hsieh
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description juwagn 2020-05-06 11:26:09 PDT
Hello,

on latest iOS update 13.4.1 with Safari the bug with fast touch sequences came back once it was fixed on 2019-11-14, but now exactly same bug is back again!
In the similar ticket number 203786 the bug link contains already full description.
That breaks behavior of our software totally compared as example to Android browsers since touchstart/touchend gets detected in sequence, and by fast sequence when it gets detected as dblclick then touchstart and touchend stay unfired!
That can't be replaced by dblclick since in this sequence i need to move finger after non-fired touchstart event but since on new Safari it gets not reported the functionality gets broken.
There is in fact no need to create extra reproducer case since issue is reproducible always, touch the screen fast two times in sequence and only one event gets fired instead expected two.
Is there any chance to return back this functionality? Or at least register specific new event name that would be fired regardless of dblclick detection where i could recognize that finger was touched/untouched or moved while being fast touched two times in sequence?
I just did not expect that same issue would come back after being reported and fixed already!

https://bugs.webkit.org/show_bug.cgi?id=203786
--------
The touch sequence: finger touch > finger release > finger touch > finger move > finger release, where last 3 event types get not reported to event handling. 
On earlier iOS versions like iOS12 the sequence above fired following events:
1. touchstart
2. touchend 
3. touchstart (in fast sequence to previous touchend)
4. touchmove
5. touchend (when moving ended)

On new iOS 13 versions on tested iPad only first two
1. touchstart
2. touchend 
3. ---- not fired> touchstart  (in fast sequence to previous touchend) 
4. ---- not fired> touchmove
5. ---- not fired> touchend 
In such case not event dblclick gets fired.

Unfortunatelly unreported "dbl-touch and move" breaks functionality of our software. Pointer events have same issue like touch events, they are not propagated to DOM if detected by iOS as potential dblclick even if moved between.
-----
Comment 1 Antoine Quint 2020-05-06 12:53:07 PDT
This could well be a dupe of bug 211179.
Comment 2 Radar WebKit Bug Importer 2020-05-06 12:53:28 PDT
<rdar://problem/62942374>
Comment 3 Antoine Quint 2020-05-06 12:57:42 PDT
Hi juwagn. There is no test attached for either this bug nor bug 203786. It would help a great deal if you could provide us with one. Thanks!
Comment 4 juwagn 2020-05-06 14:58:42 PDT
Created attachment 398666 [details]
reproducer requested

How to reproduce

Safari on iOS 13.4.1 open bug_reproducer.html

1. finger touch (touchstart fired)
2. finger remove (touchend fired)
3. - execute next steps immediately like by double click -
4. finger touch (NO touchstart fired)
5. finger MOVE (NO touchmove fired)
6. finger remove (NO touchend fired)
In this scenario 4-6. steps are not anymore fired.

Same way Android Chrome fires 4.-6. steps correctly, and even more double touch increases on Android Chrome amount of fired touchstart/touchend events always by 2 event sequences(2start and 2end) as expected. But iOS 13.4.1 Safari fires always only one event sequence (1start and 1end).
This is serious bug in detection of "double touch move" gesture in our application.
Comment 5 juwagn 2020-05-06 15:12:58 PDT
Forgot to add, use "white" area for touching and use always one finger only!

In my description above "move event" won't be fired anyway, I didn't insert the extended handling for doing this, but that doesn't matter anyway, compared to Android Chrome the "6. finger remove (NO touchend fired)" will be fired by Android Chrome with noticeable change while Safari fires nothing here.
Expected would be firing of "touchstart" "touchend" "touchmove" events same way as on all common browsers like Android Chrome, Android FireFox etc.

I use "passive": false on addEventListener, so i don't care about scrolling acceleration since no page scrolling used, so "passive": false is wished behavior and should stay .preventDefault() preventable event.
Comment 6 Antoine Quint 2020-05-07 03:39:50 PDT
Thanks for the test case! I managed to track down the regression to r253267, the fix for bug 204664. We already fixed a regression related to this bug in bug 211179, but this seems to be another aspect of the original regression that wasn't dealt with yet.
Comment 7 Wenson Hsieh 2020-05-09 18:11:40 PDT
I’ve begun to investigate this.

One interesting thing I noticed is that the bug only seems to reproduce if the viewport is not responsive; adding something like:

<meta name="viewport" content="width=device-width, initial-scale=1">

seems to make the problem go away (at least, until the user manually pinches to zoom in).

This seems like bad interaction between the relatively new deferring gesture recognizers (WKDeferringGestureRecognizer) and the blocking double tap gesture recognizer (used when fast-clicking is disabled).
Comment 8 Wenson Hsieh 2020-05-10 23:00:37 PDT
Created attachment 398999 [details]
Patch
Comment 9 Darin Adler 2020-05-10 23:37:59 PDT
Comment on attachment 398999 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=398999&action=review

> Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:719
> +- (NSArray<WKDeferringGestureRecognizer *> *)_deferringGestureRecognizers

I think this needs to go inside:

    #if ENABLE(IOS_TOUCH_EVENTS)

> Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:728
> +    NSMutableArray *deferringGestureRecognizers = [NSMutableArray arrayWithCapacity:3];
> +    if (_deferringGestureRecognizerForImmediatelyResettableGestures)
> +        [deferringGestureRecognizers addObject:_deferringGestureRecognizerForImmediatelyResettableGestures.get()];
> +    if (_deferringGestureRecognizerForDelayedResettableGestures)
> +        [deferringGestureRecognizers addObject:_deferringGestureRecognizerForDelayedResettableGestures.get()];
> +    if (_deferringGestureRecognizerForSyntheticTapGestures)
> +        [deferringGestureRecognizers addObject:_deferringGestureRecognizerForSyntheticTapGestures.get()];
> +    return deferringGestureRecognizers;

There are more efficient ways to do this than using an NSMutableArray. The simplest I can think of is to use a C array. Something like this:

    WKDeferringGestureRecognizer *recognizers[3];
    NSUInteger count = 0;
    auto add = [&] (const RetainPtr<WKDeferringGestureRecognizer>& recognizer) {
        if (recognizer)
            recognizers[count++] = recognizer.get();
    };
    add(_deferringGestureRecognizerForImmediatelyResettableGestures);
    add(_deferringGestureRecognizerForDelayedResettableGestures);
    add(_deferringGestureRecognizerForSyntheticTapGestures);
    return [[NSArray arrayWithObjects:recognizers count:count];

That’s more lines of code, but it always seems better to me not to use a mutable array.
Comment 10 Wenson Hsieh 2020-05-11 08:11:28 PDT
Comment on attachment 398999 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=398999&action=review

>> Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:719
>> +- (NSArray<WKDeferringGestureRecognizer *> *)_deferringGestureRecognizers
> 
> I think this needs to go inside:
> 
>     #if ENABLE(IOS_TOUCH_EVENTS)

Oops! Yes, that’s correct.

>> Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:728
>> +    return deferringGestureRecognizers;
> 
> There are more efficient ways to do this than using an NSMutableArray. The simplest I can think of is to use a C array. Something like this:
> 
>     WKDeferringGestureRecognizer *recognizers[3];
>     NSUInteger count = 0;
>     auto add = [&] (const RetainPtr<WKDeferringGestureRecognizer>& recognizer) {
>         if (recognizer)
>             recognizers[count++] = recognizer.get();
>     };
>     add(_deferringGestureRecognizerForImmediatelyResettableGestures);
>     add(_deferringGestureRecognizerForDelayedResettableGestures);
>     add(_deferringGestureRecognizerForSyntheticTapGestures);
>     return [[NSArray arrayWithObjects:recognizers count:count];
> 
> That’s more lines of code, but it always seems better to me not to use a mutable array.

I’ll give this a shot — thanks!
Comment 11 Wenson Hsieh 2020-05-11 08:50:16 PDT
Created attachment 399022 [details]
For EWS
Comment 12 EWS 2020-05-11 09:23:01 PDT
Committed r261480: <https://trac.webkit.org/changeset/261480>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 399022 [details].