[iOS] Implement a faster click detection that intercepts double-tap-to-zoom if possible
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Mar 2019 23:43:04 +0000 (23:43 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Mar 2019 23:43:04 +0000 (23:43 +0000)
commit34a3a0d72d5352eaf6573fb33efe8652d1496d28
treedec9a72b6012bf8b6069f27c7138ef72c12388e4
parentc331f29f3385e171411770e9fd1b8bef76e2a183
[iOS] Implement a faster click detection that intercepts double-tap-to-zoom if possible
https://bugs.webkit.org/show_bug.cgi?id=195473
<rdar://problem/48718396>

Reviewed by Wenson Hsieh (with some help from Dan Bates).

Source/WebKit:

Adds a new algorithm, behind a flag FasterClicksEnabled, that can trigger a click
event without waiting to see if a double tap will occur. It does this by examining
the amount of zoom that would be triggered if it was a double tap, and if that value
doesn't exceed a set threshold, commits to the click event instead.

This is implemented by having the Web Process respond to the potential click with
some geometry information. If the UI Process receives the information before the
second tap in a double tap, it can decide to trigger a click.

* Shared/WebPreferences.yaml: New internal feature so this can be toggled in
    a UI for testing.

* SourcesCocoa.txt: Renamed WKSyntheticTapGestureRecognizer.
* WebKit.xcodeproj/project.pbxproj: Ditto.

* UIProcess/ios/WKSyntheticTapGestureRecognizer.h:
* UIProcess/ios/WKSyntheticTapGestureRecognizer.m:
(-[WKSyntheticTapGestureRecognizer setGestureIdentifiedTarget:action:]):
(-[WKSyntheticTapGestureRecognizer setGestureFailedTarget:action:]):
(-[WKSyntheticTapGestureRecognizer setResetTarget:action:]):
(-[WKSyntheticTapGestureRecognizer setState:]):
(-[WKSyntheticTapGestureRecognizer reset]):  Renamed WKSyntheticClickTapGestureRecognizer to
    WKSyntheticTapGestureRecognizer, changed the signature of the main function to be a bit
    more clear about what it does, and added a gesture failed target.

* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _initialScaleFactor]):
(-[WKWebView _contentZoomScale]):
(-[WKWebView _targetContentZoomScaleForRect:currentScale:fitEntireRect:minimumScale:maximumScale:]):
    Exposed the initial content scale, the current scale and added a declaration that
    was missing from the .h.

* UIProcess/WebPageProxy.messages.in: Add a new message,
    HandleSmartMagnificationInformationForPotentialTap, to
    communicate the geometry of the clicked node to the UI Process.

* UIProcess/PageClient.h: Pure virtual function for the geometry message response.
* UIProcess/WebPageProxy.h: Ditto.

* UIProcess/ios/PageClientImplIOS.h: Calls into the WKContentView.
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::handleSmartMagnificationInformationForPotentialTap):

* UIProcess/ios/SmartMagnificationController.h:
* UIProcess/ios/SmartMagnificationController.mm:
(WebKit::SmartMagnificationController::calculatePotentialZoomParameters): A new method that
    asks the WKContentView to work out what the zoom factor will be for a potential double
    tap at a location.
(WebKit::SmartMagnificationController::smartMagnificationTargetRectAndZoomScales): New implementation
    of this function to avoid multiple out-arguments.

* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _initialScaleFactor]):
(-[WKContentView _contentZoomScale]):
(-[WKContentView _targetContentZoomScaleForRect:currentScale:fitEntireRect:minimumScale:maximumScale:]):
    Exposed the initial content scale, the current scale and the target zoom scale. These
    all just call into the WKWebView implementation.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _createAndConfigureDoubleTapGestureRecognizer]): Use a WKSyntheticTapGestureRecognizer instead
    of a generic one, so we can capture the failure.
(-[WKContentView setupInteraction]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _handleSmartMagnificationInformationForPotentialTap:origin:renderRect:fitEntireRect:viewportMinimumScale:viewportMaximumScale:]):
    New method that responds to the incoming Web Process message, and decides if any
    potential zoom would be "significant".
(-[WKContentView _singleTapIdentified:]):
(-[WKContentView _doubleTapDidFail:]):
(-[WKContentView _didCompleteSyntheticClick]):
(-[WKContentView _singleTapRecognized:]):
(-[WKContentView _doubleTapRecognized:]):
    Add some release logging.
(-[WKContentView _singleTapCommited:]): Deleted.

* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::potentialTapAtPosition):
(WebKit::WebPageProxy::handleSmartMagnificationInformationForPotentialTap):
* WebProcess/WebPage/ViewGestureGeometryCollector.h:
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
    Removed an unused parameter from the existing message.

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::potentialTapAtPosition): Calculates the geometry of the element
if requested, and sends it to the UIProcess.

LayoutTests:

Implement a test (iPad only) that sets up a page with zoomable content
but not quite at a significant scale, meaning we should dispatch a click
event rather than Double Tap To Zoom.

In order to do this, a humanSpeedDoubleTapAt() method was added to
UIHelper that sleeps a bit between taps, otherwise the double tap
gesture is recognized before the Web Process has had a chance to
evaluate the potential click.

* fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt: Added.
* fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html: Added.
* platform/ios/TestExpectations:
* platform/ipad/TestExpectations:
* resources/ui-helper.js:
(window.UIHelper.humanSpeedDoubleTapAt):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242757 268f45cc-cd09-0410-ab3c-d52691b4dbfc
29 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
LayoutTests/resources/ui-helper.js
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebPreferences.yaml
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h
Source/WebKit/UIProcess/PageClient.h
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/ios/PageClientImplIOS.h
Source/WebKit/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit/UIProcess/ios/SmartMagnificationController.h
Source/WebKit/UIProcess/ios/SmartMagnificationController.mm
Source/WebKit/UIProcess/ios/WKContentView.h
Source/WebKit/UIProcess/ios/WKContentView.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.h [moved from Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.h with 73% similarity]
Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.m [moved from Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m with 69% similarity]
Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/WebPage/ViewGestureGeometryCollector.h
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm