Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 8612f9f7a3cda362a6280a9ef0e0e687f4d360c1
      
https://github.com/WebKit/WebKit/commit/8612f9f7a3cda362a6280a9ef0e0e687f4d360c1
  Author: Wenson Hsieh <wenson_hs...@apple.com>
  Date:   2024-11-11 (Mon, 11 Nov 2024)

  Changed paths:
    A 
LayoutTests/fast/events/touch/ios/programmatic-scrolling-on-touchmove-expected.txt
    A LayoutTests/fast/events/touch/ios/programmatic-scrolling-on-touchmove.html
    M Source/WebCore/dom/ios/MouseEventIOS.cpp
    M Source/WebCore/dom/ios/PointerEventIOS.cpp
    M Source/WebCore/page/PointerCaptureController.cpp
    M Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm
    M Source/WebCore/platform/ios/ScrollAnimatorIOS.mm
    M Source/WebKit/Shared/WebEvent.serialization.in
    M Source/WebKit/Shared/WebEventConversion.cpp
    M Source/WebKit/Shared/WebTouchEvent.h
    M Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm
    M Source/WebKit/UIProcess/WebPageProxy.cpp
    M Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
    M Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
    M Source/WebKit/UIProcess/ios/WKTouchEventsGestureRecognizer.h
    M Source/WebKit/UIProcess/ios/WKTouchEventsGestureRecognizer.mm
    M Tools/TestWebKitAPI/Tests/ios/TouchEventTests.mm

  Log Message:
  -----------
  REGRESSION (265825@main): [iOS] europa.eu: Scroll position jitters when 
scrolling over interactive map
https://bugs.webkit.org/show_bug.cgi?id=282933
rdar://112427506

Reviewed by Abrar Rahman Protyasha.

The changes in 265825@main exacerbated an existing bug, regarding how our touch 
event handling logic
propagates the location of the user's touches from the UI process to the web 
process; this results
in scrolling on the immigration portal on europa.eu becoming extremely jittery 
(bouncing between the
minimum and maximum scroll positions in the main document) as the user performs 
an upwards swipe
over the interactive map to scroll down.

The interactive map on europa.eu intercepts and prevents all `touchstart` and 
`touchmove` events
that are dispatched over it. When the user attempts to scroll the page by 
swiping over the element
and `touchmove` is dispatched, their script attempts to adjust `pageYOffset` 
such that the location
of the user's touch relative to the document remains the same, before and after 
handling the
`touchmove` delta. In other words, the `touchmove` event listener simulates 
scrolling by keeping a
point in content coordinates fixed underneath the user's finger as they pan.

However, this doesn't quite work well in practice, especially after the changes 
in 265825@main
elided an extra CA commit that would otherwise more aggressively sync 
programmatic scrolling to UI-
side scroll content offset. That's because touch locations are computed in 
`WKContentView`
coordinates in the UI process (when receiving gesture recognizer subclass 
method calls from UIKit),
and then dispatched to the web process where they're asynchronously queued and 
delivered to event
listeners for processing. Throughout this process, the root view location of 
the touch remains
unchanged since it was computed in the UI process, which means that it ignores 
any changes to the
scroll position of the page that happened after the gesture was recognized. 
This is particularly
disastrous when combined with europa.eu's touch event handling logic, which 
constantly shifts the
scroll position when receiving `touchmove` events — the result is that the page 
can be scrolled
programmatically, but the root view coordinates of subsequent `touchmove` touch 
locations don't
reflect this scrolling at all, causing the event listener to try and move the 
`pageYOffset` in the
*opposite* direction to compensate. This error then compounds very quickly, 
causing the scroll
position to jump between min and max scroll positions on the page.

To fix this, we make some adjustments to propagate the user's touch location 
relative to the
viewport (unobscured content rect), and only map from the viewport back to root 
view coordinates at
the last possible moment before dispatching the event by shifting the touch 
delta back up, using the
main frame's current `contentsScrollPosition()`.

See below for more details.

* 
LayoutTests/fast/events/touch/ios/programmatic-scrolling-on-touchmove-expected.txt:
 Added.
* LayoutTests/fast/events/touch/ios/programmatic-scrolling-on-touchmove.html: 
Added.

Add a layout test to exercise the change, by swiping up in a reduced test case 
that emulates
europa.eu's logic for scrolling in response to `touchmove`, and verifying that 
the scroll position
always stays within reasonable limits. Without the fixes in this bug, the 
`pageYOffset` ends up
bouncing between negative values and values of up to 2000-3000.

* Source/WebCore/dom/ios/MouseEventIOS.cpp:
(WebCore::MouseEvent::create):
* Source/WebCore/dom/ios/PointerEventIOS.cpp:
(WebCore::PointerEvent::PointerEvent):
* Source/WebCore/page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
* Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm:
(WebCore::PlatformTouchPointBuilder::PlatformTouchPointBuilder):
(WebCore::PlatformTouchEventBuilder::PlatformTouchEventBuilder):

Pass `locationInViewport` through to `PlatformTouchPoint` on construction. This 
is optional since
we currently don't compute this for `UIWebView` (WebKitLegacy).

* Source/WebCore/platform/ios/ScrollAnimatorIOS.mm:

Adjust call sites, since `touchLocationAtIndex` is now renamed to 
`touchLocationInRootViewAtIndex`.

(WebCore::ScrollAnimatorIOS::handleTouchEvent):
* Source/WebKit/Shared/WebEvent.serialization.in:
* Source/WebKit/Shared/WebEventConversion.cpp:
(WebKit::WebKit2PlatformTouchPoint::WebKit2PlatformTouchPoint):
* Source/WebKit/Shared/WebTouchEvent.h:
(WebKit::WebPlatformTouchPoint::WebPlatformTouchPoint):
(WebKit::WebPlatformTouchPoint::locationInRootView const):
(WebKit::WebPlatformTouchPoint::locationInViewport const):
(WebKit::WebPlatformTouchPoint::location const): Deleted.

Rename `location` to `locationInRootView` (along with other related members), 
and plumb a new
`locationInViewport` point alongside the touch point.

* Source/WebKit/Shared/ios/NativeWebTouchEventIOS.mm:
(WebKit::NativeWebTouchEvent::extractWebTouchPoints):
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::updateTouchEventTracking):
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.h:
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:

Refactor `WKTouchEventsGestureRecognizer` to just directly take a 
`WKContentView`. Now that the
touch events gesture no longer needs to be generic for both WebKitLegacy and 
modern WebKit, there's
no benefit to maintaining a separate, WebKit-internal 
`WKTouchEventsGestureRecognizerDelegate` that
is only implemented by the content view.

This allows us to remove some unused code and unnecessary logic (such as the 
touch target and action
selector, as well as `-isAnyTouchOverActiveArea:`), but importantly allows us 
to call into the web
view to compute the unobscured content offset when determining the 
viewport-relative location for
each `WKTouchPoint`.

(-[WKContentView setUpInteraction]):
(-[WKContentView _touchEventsRecognized]):
(-[WKContentView _handleTouchActionsForTouchEvent:]):
(-[WKContentView _shouldIgnoreTouchEvent:]):
(-[WKContentView _touchEventsRecognized:]): Deleted.
(-[WKContentView gestureRecognizer:shouldIgnoreTouchEvent:]): Deleted.
(-[WKContentView isAnyTouchOverActiveArea:]): Deleted.
* Source/WebKit/UIProcess/ios/WKTouchEventsGestureRecognizer.h:
* Source/WebKit/UIProcess/ios/WKTouchEventsGestureRecognizer.mm:
(-[WKTouchEventsGestureRecognizer initWithContentView:]):
(mapRootViewToViewport):

Add a helper function to unadjust the given point in root view coordinates by 
the current unobscured
content offset.

(-[WKTouchEventsGestureRecognizer _touchEventForTouch:]):
(-[WKTouchEventsGestureRecognizer 
_recordTouches:type:coalescedTouches:predictedTouches:]):

Populate the new `locationInViewport` member on each touch point.

(-[WKTouchEventsGestureRecognizer performAction]):
(-[WKTouchEventsGestureRecognizer touchesBegan:withEvent:]):
(-[WKTouchEventsGestureRecognizer initWithTarget:action:touchDelegate:]): 
Deleted.
* Tools/TestWebKitAPI/Tests/ios/TouchEventTests.mm:

Canonical link: https://commits.webkit.org/286448@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to