Diff
Modified: trunk/LayoutTests/ChangeLog (242756 => 242757)
--- trunk/LayoutTests/ChangeLog 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/LayoutTests/ChangeLog 2019-03-11 23:43:04 UTC (rev 242757)
@@ -1,3 +1,27 @@
+2019-03-11 Dean Jackson <[email protected]>
+
+ [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).
+
+ 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):
+
2019-03-11 Wenson Hsieh <[email protected]>
[macOS] Dispatching reentrant "contextmenu" events may cause crashes
Added: trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt (0 => 242757)
--- trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt 2019-03-11 23:43:04 UTC (rev 242757)
@@ -0,0 +1,2 @@
+PASS: Click fired on element with handler.
+This document doesn't have fast clicks because it sets a viewport width. However, it doesn't have a large amount of zoom on double tap, so double tapping on the rectangle above should send a click event.
Property changes on: trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom-expected.txt
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Date Revision
\ No newline at end of property
Added: svn:mime-type
+text/plain
\ No newline at end of property
Added: trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html (0 => 242757)
--- trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html (rev 0)
+++ trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html 2019-03-11 23:43:04 UTC (rev 242757)
@@ -0,0 +1,55 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+
+<html>
+<meta name="viewport" content="width=500">
+<head>
+ <style>
+ body {
+ font-family: system-ui;
+ line-height: 1.4;
+ padding: 10px 10px;
+ width: 500px;
+ margin: 0;
+ }
+ </style>
+ <script src=""
+ <script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ async function runTest()
+ {
+ document.getElementById("target").addEventListener("click", handleClick, false);
+
+ if (!window.testRunner)
+ return;
+ await UIHelper.humanSpeedDoubleTapAt(30, 30);
+ }
+
+ function handleClick(event)
+ {
+ document.getElementById("target").textContent = "PASS: Click fired on element with handler.";
+ testRunner.notifyDone();
+ }
+ </script>
+ <style>
+ body {
+ margin: 0;
+ }
+ #target {
+ height: 100px;
+ width: 100px;
+ background-color: silver;
+ }
+ </style>
+</head>
+<body _onload_="runTest()">
+<div id="target"></div>
+<div id="description">This document doesn't have fast clicks because
+ it sets a viewport width. However, it doesn't have a large amount of
+ zoom on double tap, so double tapping on the rectangle
+ above should send a click event.</div>
+</body>
+</html>
Property changes on: trunk/LayoutTests/fast/events/ios/ipad/fast-click-double-tap-sends-click-on-insignificant-zoom.html
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Date Revision
\ No newline at end of property
Added: svn:mime-type
+text/html
\ No newline at end of property
Modified: trunk/LayoutTests/platform/ios/TestExpectations (242756 => 242757)
--- trunk/LayoutTests/platform/ios/TestExpectations 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/LayoutTests/platform/ios/TestExpectations 2019-03-11 23:43:04 UTC (rev 242757)
@@ -23,6 +23,9 @@
# End platform-specific directories.
#//////////////////////////////////////////////////////////////////////////////////////////
+# iPad-specific tests skipped here and re-enabled in platform/ipad
+fast/events/ios/ipad [ Skip ]
+
###
# Unsupported and disabled features
##
Modified: trunk/LayoutTests/resources/ui-helper.js (242756 => 242757)
--- trunk/LayoutTests/resources/ui-helper.js 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/LayoutTests/resources/ui-helper.js 2019-03-11 23:43:04 UTC (rev 242757)
@@ -74,6 +74,31 @@
});
}
+ static humanSpeedDoubleTapAt(x, y)
+ {
+ console.assert(this.isIOS());
+
+ if (!this.isWebKit2()) {
+ // FIXME: Add a sleep in here.
+ eventSender.addTouchPoint(x, y);
+ eventSender.touchStart();
+ eventSender.releaseTouchPoint(0);
+ eventSender.touchEnd();
+ eventSender.addTouchPoint(x, y);
+ eventSender.touchStart();
+ eventSender.releaseTouchPoint(0);
+ eventSender.touchEnd();
+ return Promise.resolve();
+ }
+
+ return new Promise(async (resolve) => {
+ await UIHelper.tapAt(x, y);
+ await new Promise(resolveAfterDelay => setTimeout(resolveAfterDelay, 120));
+ await UIHelper.tapAt(x, y);
+ resolve();
+ });
+ }
+
static zoomByDoubleTappingAt(x, y)
{
console.assert(this.isIOS());
Modified: trunk/Source/WebKit/ChangeLog (242756 => 242757)
--- trunk/Source/WebKit/ChangeLog 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/ChangeLog 2019-03-11 23:43:04 UTC (rev 242757)
@@ -1,3 +1,100 @@
+2019-03-11 Dean Jackson <[email protected]>
+
+ [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).
+
+ 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.
+
2019-03-11 Per Arne Vollan <[email protected]>
Unreviewed build fix after r242745.
Modified: trunk/Source/WebKit/Shared/WebPreferences.yaml (242756 => 242757)
--- trunk/Source/WebKit/Shared/WebPreferences.yaml 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/Shared/WebPreferences.yaml 2019-03-11 23:43:04 UTC (rev 242757)
@@ -1470,6 +1470,15 @@
category: internal
webcoreName: selectionAcrossShadowBoundariesEnabled
+FasterClicksEnabled:
+ type: bool
+ defaultValue: true
+ condition: PLATFORM(IOS_FAMILY)
+ humanReadableName: "Faster clicks"
+ humanReadableDescription: "Support faster clicks on zoomable pages"
+ webcoreBinding: none
+ category: internal
+
InputTypeColorEnabled:
type: bool
defaultValue: DEFAULT_INPUT_TYPE_COLOR_ENABLED
Modified: trunk/Source/WebKit/SourcesCocoa.txt (242756 => 242757)
--- trunk/Source/WebKit/SourcesCocoa.txt 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/SourcesCocoa.txt 2019-03-11 23:43:04 UTC (rev 242757)
@@ -411,8 +411,8 @@
UIProcess/ios/WKPDFPageNumberIndicator.mm
UIProcess/ios/WKPDFView.mm
UIProcess/ios/WKScrollView.mm
-UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m
UIProcess/ios/WKSyntheticFlagsChangedWebEvent.mm
+UIProcess/ios/WKSyntheticTapGestureRecognizer.m
UIProcess/ios/WKSystemPreviewView.mm
UIProcess/ios/WKWebEvent.mm
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -2455,8 +2455,18 @@
[_scrollView _zoomToCenter:newCenter scale:scale duration:formControlZoomAnimationDuration force:YES];
}
-- (CGFloat)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale
+- (double)_initialScaleFactor
{
+ return _initialScaleFactor;
+}
+
+- (double)_contentZoomScale
+{
+ return contentZoomScale(self);
+}
+
+- (double)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale
+{
WebCore::FloatSize unobscuredContentSize([self _contentRectForUserInteraction].size);
double horizontalScale = unobscuredContentSize.width() * currentScale / targetRect.width();
double verticalScale = unobscuredContentSize.height() * currentScale / targetRect.height();
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -99,6 +99,9 @@
- (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin;
- (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance;
+- (double)_initialScaleFactor;
+- (double)_contentZoomScale;
+- (double)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale;
- (void)_zoomToFocusRect:(const WebCore::FloatRect&)focusedElementRect selectionRect:(const WebCore::FloatRect&)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll;
- (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance;
- (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated;
Modified: trunk/Source/WebKit/UIProcess/PageClient.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/PageClient.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/PageClient.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -379,6 +379,7 @@
virtual void saveImageToLibrary(Ref<WebCore::SharedBuffer>&&) = 0;
virtual void showPlaybackTargetPicker(bool hasVideo, const WebCore::IntRect& elementRect, WebCore::RouteSharingPolicy, const String&) = 0;
virtual void disableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID) = 0;
+ virtual void handleSmartMagnificationInformationForPotentialTap(uint64_t requestID, const WebCore::FloatRect& renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale) = 0;
virtual double minimumZoomScale() const = 0;
virtual WebCore::FloatRect documentRect() const = 0;
virtual void scrollingNodeScrollViewWillStartPanGesture() = 0;
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -678,6 +678,7 @@
void didNotHandleTapAsClick(const WebCore::IntPoint&);
void didCompleteSyntheticClick();
void disableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID);
+ void handleSmartMagnificationInformationForPotentialTap(uint64_t requestID, const WebCore::FloatRect& renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale);
void contentSizeCategoryDidChange(const String& contentSizeCategory);
void getSelectionContext(WTF::Function<void(const String&, const String&, const String&, CallbackBase::Error)>&&);
void handleTwoFingerTapAtPoint(const WebCore::IntPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t requestID);
@@ -1178,7 +1179,7 @@
#if PLATFORM(IOS_FAMILY)
void willStartUserTriggeredZooming();
- void potentialTapAtPosition(const WebCore::FloatPoint&, uint64_t& requestID);
+ void potentialTapAtPosition(const WebCore::FloatPoint&, bool shouldRequestMagnificationInformation, uint64_t& requestID);
void commitPotentialTap(OptionSet<WebKit::WebEvent::Modifier>, uint64_t layerTreeTransactionIdAtLastTouchStart);
void cancelPotentialTap();
void tapHighlightAtPosition(const WebCore::FloatPoint&, uint64_t& requestID);
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in 2019-03-11 23:43:04 UTC (rev 242757)
@@ -195,6 +195,7 @@
DidNotHandleTapAsClick(WebCore::IntPoint point)
DidCompleteSyntheticClick()
DisableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID)
+ HandleSmartMagnificationInformationForPotentialTap(uint64_t requestID, WebCore::FloatRect renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale)
DrawToPDFCallback(IPC::DataReference pdfData, WebKit::CallbackID callbackID)
SelectionRectsCallback(Vector<WebCore::SelectionRect> selectionRects, WebKit::CallbackID callbackID);
#endif
Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -161,6 +161,8 @@
bool showShareSheet(const WebCore::ShareDataWithParsedURL&, WTF::CompletionHandler<void(bool)>&&) override;
void disableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID) override;
+ void handleSmartMagnificationInformationForPotentialTap(uint64_t requestID, const WebCore::FloatRect& renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale) override;
+
double minimumZoomScale() const override;
WebCore::FloatRect documentRect() const override;
Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -238,6 +238,11 @@
[m_contentView _disableDoubleTapGesturesDuringTapIfNecessary:requestID];
}
+void PageClientImpl::handleSmartMagnificationInformationForPotentialTap(uint64_t requestID, const WebCore::FloatRect& renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale)
+{
+ [m_contentView _handleSmartMagnificationInformationForPotentialTap:requestID renderRect:renderRect fitEntireRect:fitEntireRect viewportMinimumScale:viewportMinimumScale viewportMaximumScale:viewportMaximumScale];
+}
+
double PageClientImpl::minimumZoomScale() const
{
if (UIScrollView *scroller = [m_webView scrollView])
Modified: trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -48,6 +48,8 @@
void handleSmartMagnificationGesture(WebCore::FloatPoint origin);
void handleResetMagnificationGesture(WebCore::FloatPoint origin);
+ double zoomFactorForTargetRect(WebCore::FloatRect targetRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale);
+
private:
// IPC::MessageReceiver.
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
@@ -55,7 +57,7 @@
void didCollectGeometryForSmartMagnificationGesture(WebCore::FloatPoint origin, WebCore::FloatRect renderRect, WebCore::FloatRect visibleContentBounds, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale);
void magnify(WebCore::FloatPoint origin, WebCore::FloatRect targetRect, WebCore::FloatRect visibleContentRect, double viewportMinimumScale, double viewportMaximumScale);
void scrollToRect(WebCore::FloatPoint origin, WebCore::FloatRect targetRect);
- void adjustSmartMagnificationTargetRectAndZoomScales(bool addMagnificationPadding, WebCore::FloatRect& targetRect, double& minimumScale, double& maximumScale);
+ std::tuple<WebCore::FloatRect, double, double> smartMagnificationTargetRectAndZoomScales(WebCore::FloatRect targetRect, double minimumScale, double maximumScale, bool addMagnificationPadding);
WebPageProxy& m_webPageProxy;
WKContentView *m_contentView;
Modified: trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/SmartMagnificationController.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -76,17 +76,41 @@
[m_contentView _zoomOutWithOrigin:origin];
}
-void SmartMagnificationController::adjustSmartMagnificationTargetRectAndZoomScales(bool addMagnificationPadding, WebCore::FloatRect& targetRect, double& minimumScale, double& maximumScale)
+std::tuple<FloatRect, double, double> SmartMagnificationController::smartMagnificationTargetRectAndZoomScales(FloatRect targetRect, double minimumScale, double maximumScale, bool addMagnificationPadding)
{
+ FloatRect outTargetRect = targetRect;
+ double outMinimumScale = minimumScale;
+ double outMaximumScale = maximumScale;
+
if (addMagnificationPadding) {
- targetRect.inflateX(smartMagnificationElementPadding * targetRect.width());
- targetRect.inflateY(smartMagnificationElementPadding * targetRect.height());
+ outTargetRect.inflateX(smartMagnificationElementPadding * outTargetRect.width());
+ outTargetRect.inflateY(smartMagnificationElementPadding * outTargetRect.height());
}
- minimumScale = std::max(minimumScale, smartMagnificationMinimumScale);
- maximumScale = std::min(maximumScale, smartMagnificationMaximumScale);
+ outMinimumScale = std::max(outMinimumScale, smartMagnificationMinimumScale);
+ outMaximumScale = std::min(outMaximumScale, smartMagnificationMaximumScale);
+
+ return { outTargetRect, outMinimumScale, outMaximumScale };
}
+double SmartMagnificationController::zoomFactorForTargetRect(FloatRect targetRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale)
+{
+ // FIXME: Share some of this code with didCollectGeometryForSmartMagnificationGesture?
+
+ FloatRect adjustedTargetRect;
+ double minimumScale = viewportMinimumScale;
+ double maximumScale = viewportMaximumScale;
+ std::tie(adjustedTargetRect, minimumScale, maximumScale) = smartMagnificationTargetRectAndZoomScales(targetRect, viewportMinimumScale, viewportMaximumScale, !fitEntireRect);
+
+ double currentScale = [m_contentView _contentZoomScale];
+ double targetScale = [m_contentView _targetContentZoomScaleForRect:adjustedTargetRect currentScale:currentScale fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale];
+
+ if (targetScale == currentScale)
+ targetScale = [m_contentView _initialScaleFactor];
+
+ return targetScale;
+}
+
void SmartMagnificationController::didCollectGeometryForSmartMagnificationGesture(FloatPoint origin, FloatRect targetRect, FloatRect visibleContentRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale)
{
if (targetRect.isEmpty()) {
@@ -94,9 +118,10 @@
[m_contentView _zoomToInitialScaleWithOrigin:origin];
return;
}
+ FloatRect adjustedTargetRect;
double minimumScale = viewportMinimumScale;
double maximumScale = viewportMaximumScale;
- adjustSmartMagnificationTargetRectAndZoomScales(!fitEntireRect, targetRect, minimumScale, maximumScale);
+ std::tie(adjustedTargetRect, minimumScale, maximumScale) = smartMagnificationTargetRectAndZoomScales(targetRect, viewportMinimumScale, viewportMaximumScale, !fitEntireRect);
// FIXME: Check if text selection wants to consume the double tap before we attempt magnification.
@@ -113,7 +138,7 @@
// For replaced elements like images, we want to fit the whole element
// in the view, so scale it down enough to make both dimensions fit if possible.
// For other elements, try to fit them horizontally.
- if ([m_contentView _zoomToRect:targetRect withOrigin:origin fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:minimumScrollDistance])
+ if ([m_contentView _zoomToRect:adjustedTargetRect withOrigin:origin fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:minimumScrollDistance])
return;
// FIXME: If we still don't zoom, send the tap along to text selection (see <rdar://problem/6810344>).
@@ -122,10 +147,12 @@
void SmartMagnificationController::magnify(FloatPoint origin, FloatRect targetRect, FloatRect visibleContentRect, double viewportMinimumScale, double viewportMaximumScale)
{
+ FloatRect adjustedTargetRect;
double maximumScale = viewportMaximumScale;
double minimumScale = viewportMinimumScale;
- adjustSmartMagnificationTargetRectAndZoomScales(true, targetRect, minimumScale, maximumScale);
- [m_contentView _zoomToRect:targetRect withOrigin:origin fitEntireRect:NO minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:0];
+ std::tie(adjustedTargetRect, minimumScale, maximumScale) = smartMagnificationTargetRectAndZoomScales(targetRect, viewportMinimumScale, viewportMaximumScale, true);
+
+ [m_contentView _zoomToRect:adjustedTargetRect withOrigin:origin fitEntireRect:NO minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:0];
}
void SmartMagnificationController::scrollToRect(FloatPoint origin, FloatRect targetRect)
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKContentView.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -38,6 +38,7 @@
}
namespace WebCore {
+class FloatRect;
struct Highlight;
}
@@ -108,5 +109,8 @@
- (BOOL)_zoomToRect:(CGRect)targetRect withOrigin:(CGPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(CGFloat)minimumScrollDistance;
- (void)_zoomOutWithOrigin:(CGPoint)origin;
- (void)_zoomToInitialScaleWithOrigin:(CGPoint)origin;
+- (double)_initialScaleFactor;
+- (double)_contentZoomScale;
+- (double)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale;
@end
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKContentView.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -641,6 +641,21 @@
return [_webView _zoomToInitialScaleWithOrigin:origin animated:YES];
}
+- (double)_initialScaleFactor
+{
+ return [_webView _initialScaleFactor];
+}
+
+- (double)_contentZoomScale
+{
+ return [_webView _contentZoomScale];
+}
+
+- (double)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale
+{
+ return [_webView _targetContentZoomScaleForRect:targetRect currentScale:currentScale fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale];
+}
+
- (void)_applicationWillResignActive:(NSNotification*)notification
{
_page->applicationWillResignActive();
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -43,7 +43,7 @@
#import "WKFormPeripheral.h"
#import "WKKeyboardScrollingAnimator.h"
#import "WKShareSheet.h"
-#import "WKSyntheticClickTapGestureRecognizer.h"
+#import "WKSyntheticTapGestureRecognizer.h"
#import "_WKFormInputSession.h"
#import <UIKit/UIView.h>
#import <WebCore/Color.h>
@@ -202,10 +202,10 @@
BOOL _preventsPanningInYAxis;
#endif
- RetainPtr<WKSyntheticClickTapGestureRecognizer> _singleTapGestureRecognizer;
+ RetainPtr<WKSyntheticTapGestureRecognizer> _singleTapGestureRecognizer;
RetainPtr<_UIWebHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer;
RetainPtr<UILongPressGestureRecognizer> _longPressGestureRecognizer;
- RetainPtr<UITapGestureRecognizer> _doubleTapGestureRecognizer;
+ RetainPtr<WKSyntheticTapGestureRecognizer> _doubleTapGestureRecognizer;
RetainPtr<UITapGestureRecognizer> _nonBlockingDoubleTapGestureRecognizer;
RetainPtr<UITapGestureRecognizer> _twoFingerDoubleTapGestureRecognizer;
RetainPtr<UITapGestureRecognizer> _twoFingerSingleTapGestureRecognizer;
@@ -405,6 +405,7 @@
- (BOOL)_mayDisableDoubleTapGesturesDuringSingleTap;
- (void)_disableDoubleTapGesturesDuringTapIfNecessary:(uint64_t)requestID;
+- (void)_handleSmartMagnificationInformationForPotentialTap:(uint64_t)requestID renderRect:(const WebCore::FloatRect&)renderRect fitEntireRect:(BOOL)fitEntireRect viewportMinimumScale:(double)viewportMinimumScale viewportMaximumScale:(double)viewportMaximumScale;
- (void)_elementDidFocus:(const WebKit::FocusedElementInformation&)information userIsInteracting:(BOOL)userIsInteracting blurPreviousNode:(BOOL)blurPreviousNode changingActivityState:(BOOL)changingActivityState userObject:(NSObject <NSSecureCoding> *)userObject;
- (void)_elementDidBlur;
- (void)_didUpdateInputMode:(WebCore::InputMode)mode;
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -228,9 +228,10 @@
} // namespace WebKit
-static const float highlightDelay = 0.12;
-static const float tapAndHoldDelay = 0.75;
-const CGFloat minimumTapHighlightRadius = 2.0;
+constexpr float highlightDelay = 0.12;
+constexpr float tapAndHoldDelay = 0.75;
+constexpr CGFloat minimumTapHighlightRadius = 2.0;
+constexpr double fasterTapSignificantZoomThreshold = 0.8;
@interface WKTextRange : UITextRange {
CGRect _startRect;
@@ -645,7 +646,8 @@
- (void)_createAndConfigureDoubleTapGestureRecognizer
{
- _doubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_doubleTapRecognized:)]);
+ _doubleTapGestureRecognizer = adoptNS([[WKSyntheticTapGestureRecognizer alloc] initWithTarget:self action:@selector(_doubleTapRecognized:)]);
+ [_doubleTapGestureRecognizer setGestureFailedTarget:self action:@selector(_doubleTapDidFail:)];
[_doubleTapGestureRecognizer setNumberOfTapsRequired:2];
[_doubleTapGestureRecognizer setDelegate:self];
[self addGestureRecognizer:_doubleTapGestureRecognizer.get()];
@@ -694,9 +696,9 @@
#endif
- _singleTapGestureRecognizer = adoptNS([[WKSyntheticClickTapGestureRecognizer alloc] initWithTarget:self action:@selector(_singleTapCommited:)]);
+ _singleTapGestureRecognizer = adoptNS([[WKSyntheticTapGestureRecognizer alloc] initWithTarget:self action:@selector(_singleTapRecognized:)]);
[_singleTapGestureRecognizer setDelegate:self];
- [_singleTapGestureRecognizer setGestureRecognizedTarget:self action:@selector(_singleTapRecognized:)];
+ [_singleTapGestureRecognizer setGestureIdentifiedTarget:self action:@selector(_singleTapIdentified:)];
[_singleTapGestureRecognizer setResetTarget:self action:@selector(_singleTapDidReset:)];
[self addGestureRecognizer:_singleTapGestureRecognizer.get()];
@@ -813,7 +815,7 @@
#endif
[_singleTapGestureRecognizer setDelegate:nil];
- [_singleTapGestureRecognizer setGestureRecognizedTarget:nil action:nil];
+ [_singleTapGestureRecognizer setGestureIdentifiedTarget:nil action:nil];
[_singleTapGestureRecognizer setResetTarget:nil action:nil];
[self removeGestureRecognizer:_singleTapGestureRecognizer.get()];
@@ -1491,6 +1493,23 @@
[self _setDoubleTapGesturesEnabled:NO];
}
+- (void)_handleSmartMagnificationInformationForPotentialTap:(uint64_t)requestID renderRect:(const WebCore::FloatRect&)renderRect fitEntireRect:(BOOL)fitEntireRect viewportMinimumScale:(double)viewportMinimumScale viewportMaximumScale:(double)viewportMaximumScale
+{
+ ASSERT(_page->preferences().fasterClicksEnabled());
+ if (!_potentialTapInProgress)
+ return;
+
+ auto targetScale = _smartMagnificationController->zoomFactorForTargetRect(renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale);
+
+ auto initialScale = [self _initialScaleFactor];
+ if (std::min(targetScale, initialScale) / std::max(targetScale, initialScale) > fasterTapSignificantZoomThreshold) {
+ RELEASE_LOG(ViewGestures, "Potential tap would not cause a significant zoom. Trigger click. (%p)", self);
+ [self _setDoubleTapGesturesEnabled:NO];
+ return;
+ }
+ RELEASE_LOG(ViewGestures, "Potential tap may cause significant zoom. Wait. (%p)", self);
+}
+
- (void)_cancelLongPressGestureRecognizer
{
[_highlightLongPressGestureRecognizer cancel];
@@ -2176,13 +2195,17 @@
_potentialTapInProgress = NO;
}
-- (void)_singleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
+- (void)_singleTapIdentified:(UITapGestureRecognizer *)gestureRecognizer
{
ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
ASSERT(!_potentialTapInProgress);
[self _resetIsDoubleTapPending];
- _page->potentialTapAtPosition(gestureRecognizer.location, ++_latestTapID);
+ bool shouldRequestMagnificationInformation = _page->preferences().fasterClicksEnabled();
+ if (shouldRequestMagnificationInformation)
+ RELEASE_LOG(ViewGestures, "Single tap identified. Request details on potential zoom. (%p)", self);
+
+ _page->potentialTapAtPosition(gestureRecognizer.location, shouldRequestMagnificationInformation, ++_latestTapID);
_potentialTapInProgress = YES;
_isTapHighlightIDValid = YES;
_isExpectingFastSingleTapCommit = !_doubleTapGestureRecognizer.get().enabled;
@@ -2203,6 +2226,12 @@
cancelPotentialTapIfNecessary(self);
}
+- (void)_doubleTapDidFail:(UITapGestureRecognizer *)gestureRecognizer
+{
+ RELEASE_LOG(ViewGestures, "Double tap was not recognized. (%p)", self);
+ ASSERT(gestureRecognizer == _doubleTapGestureRecognizer);
+}
+
- (void)_commitPotentialTapFailed
{
[self _cancelInteraction];
@@ -2232,10 +2261,11 @@
- (void)_didCompleteSyntheticClick
{
+ RELEASE_LOG(ViewGestures, "Synthetic click completed. (%p)", self);
[self _resetInputViewDeferral];
}
-- (void)_singleTapCommited:(UITapGestureRecognizer *)gestureRecognizer
+- (void)_singleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
{
ASSERT(gestureRecognizer == _singleTapGestureRecognizer);
@@ -2260,6 +2290,9 @@
}
[_inputPeripheral endEditing];
+
+ RELEASE_LOG(ViewGestures, "Single tap recognized - commit potential tap (%p)", self);
+
_page->commitPotentialTap(WebKit::webEventModifierFlags(gestureRecognizerModifierFlags(gestureRecognizer)), _layerTreeTransactionIdAtLastTouchStart);
if (!_isExpectingFastSingleTapCommit)
@@ -2268,6 +2301,8 @@
- (void)_doubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
{
+ RELEASE_LOG(ViewGestures, "Identified a double tap (%p)", self);
+
[self _resetIsDoubleTapPending];
_lastInteractionLocation = gestureRecognizer.location;
Deleted: trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.h (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if PLATFORM(IOS_FAMILY)
-
-#import "UIKitSPI.h"
-
-@interface WKSyntheticClickTapGestureRecognizer : UITapGestureRecognizer
-- (void)setGestureRecognizedTarget:(id)target action:(SEL)action;
-- (void)setResetTarget:(id)target action:(SEL)action;
-@end
-
-#endif
Deleted: trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m 2019-03-11 23:43:04 UTC (rev 242757)
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "WKSyntheticClickTapGestureRecognizer.h"
-
-#if PLATFORM(IOS_FAMILY)
-
-#import <UIKit/UIGestureRecognizerSubclass.h>
-
-@implementation WKSyntheticClickTapGestureRecognizer {
- id _gestureRecognizedTarget;
- SEL _gestureRecognizedAction;
- id _resetTarget;
- SEL _resetAction;
-}
-
-- (void)setGestureRecognizedTarget:(id)target action:(SEL)action
-{
- _gestureRecognizedTarget = target;
- _gestureRecognizedAction = action;
-}
-
-- (void)setResetTarget:(id)target action:(SEL)action
-{
- _resetTarget = target;
- _resetAction = action;
-}
-
-- (void)setState:(UIGestureRecognizerState)state
-{
- if (state == UIGestureRecognizerStateEnded)
- [_gestureRecognizedTarget performSelector:_gestureRecognizedAction withObject:self];
- [super setState:state];
-}
-
-- (void)reset
-{
- [super reset];
- [_resetTarget performSelector:_resetAction withObject:self];
-}
-
-@end
-
-#endif
Copied: trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.h (from rev 242756, trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.h) (0 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 - 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if PLATFORM(IOS_FAMILY)
+
+#import "UIKitSPI.h"
+
+// The purpose of this class is to call a target/action when
+// the gesture is recognized, as well as the typical time when
+// a gesture should be handled. This allows it to be used while
+// it is waiting for another gesture recognizer to fail.
+@interface WKSyntheticTapGestureRecognizer : UITapGestureRecognizer
+- (void)setGestureIdentifiedTarget:(id)target action:(SEL)action;
+- (void)setGestureFailedTarget:(id)target action:(SEL)action;
+- (void)setResetTarget:(id)target action:(SEL)action;
+@end
+
+#endif
Property changes: trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.h
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Date Author Id Revision HeadURL
\ No newline at end of property
Copied: trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.m (from rev 242756, trunk/Source/WebKit/UIProcess/ios/WKSyntheticClickTapGestureRecognizer.m) (0 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.m (rev 0)
+++ trunk/Source/WebKit/UIProcess/ios/WKSyntheticTapGestureRecognizer.m 2019-03-11 23:43:04 UTC (rev 242757)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 - 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "WKSyntheticTapGestureRecognizer.h"
+
+#if PLATFORM(IOS_FAMILY)
+
+#import <UIKit/UIGestureRecognizerSubclass.h>
+
+@implementation WKSyntheticTapGestureRecognizer {
+ id _gestureIdentifiedTarget;
+ SEL _gestureIdentifiedAction;
+ id _gestureFailedTarget;
+ SEL _gestureFailedAction;
+ id _resetTarget;
+ SEL _resetAction;
+}
+
+- (void)setGestureIdentifiedTarget:(id)target action:(SEL)action
+{
+ _gestureIdentifiedTarget = target;
+ _gestureIdentifiedAction = action;
+}
+
+- (void)setGestureFailedTarget:(id)target action:(SEL)action
+{
+ _gestureFailedTarget = target;
+ _gestureFailedAction = action;
+}
+
+- (void)setResetTarget:(id)target action:(SEL)action
+{
+ _resetTarget = target;
+ _resetAction = action;
+}
+
+- (void)setState:(UIGestureRecognizerState)state
+{
+ if (state == UIGestureRecognizerStateEnded)
+ [_gestureIdentifiedTarget performSelector:_gestureIdentifiedAction withObject:self];
+ else if (state == UIGestureRecognizerStateFailed)
+ [_gestureFailedTarget performSelector:_gestureFailedAction withObject:self];
+ [super setState:state];
+}
+
+- (void)reset
+{
+ [super reset];
+ [_resetTarget performSelector:_resetAction withObject:self];
+}
+
+@end
+
+#endif
Modified: trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm (242756 => 242757)
--- trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -812,10 +812,10 @@
process().send(Messages::WebPage::WillStartUserTriggeredZooming(), m_pageID);
}
-void WebPageProxy::potentialTapAtPosition(const WebCore::FloatPoint& position, uint64_t& requestID)
+void WebPageProxy::potentialTapAtPosition(const WebCore::FloatPoint& position, bool shouldRequestMagnificationInformation, uint64_t& requestID)
{
hideValidationMessage();
- process().send(Messages::WebPage::PotentialTapAtPosition(requestID, position), m_pageID);
+ process().send(Messages::WebPage::PotentialTapAtPosition(requestID, position, shouldRequestMagnificationInformation), m_pageID);
}
void WebPageProxy::commitPotentialTap(OptionSet<WebEvent::Modifier> modifiers, uint64_t layerTreeTransactionIdAtLastTouchStart)
@@ -1032,6 +1032,11 @@
pageClient().disableDoubleTapGesturesDuringTapIfNecessary(requestID);
}
+void WebPageProxy::handleSmartMagnificationInformationForPotentialTap(uint64_t requestID, const WebCore::FloatRect& renderRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale)
+{
+ pageClient().handleSmartMagnificationInformationForPotentialTap(requestID, renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale);
+}
+
uint32_t WebPageProxy::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintInfo& printInfo, DrawToPDFCallback::CallbackFunction&& callback)
{
if (!isValid()) {
Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (242756 => 242757)
--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-03-11 23:43:04 UTC (rev 242757)
@@ -415,8 +415,8 @@
2684054418B85A630022C38B /* VisibleContentRectUpdateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2684054218B85A630022C38B /* VisibleContentRectUpdateInfo.h */; };
2684055218B86ED60022C38B /* ViewUpdateDispatcherMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2684055018B86ED60022C38B /* ViewUpdateDispatcherMessageReceiver.cpp */; };
2684055318B86ED60022C38B /* ViewUpdateDispatcherMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 2684055118B86ED60022C38B /* ViewUpdateDispatcherMessages.h */; };
- 26F10BE819187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 26F10BE619187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.h */; };
- 26F10BE919187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 26F10BE719187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.m */; };
+ 26F10BE819187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 26F10BE619187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.h */; };
+ 26F10BE919187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 26F10BE719187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.m */; };
26F9A83B18A3468100AEB88A /* WKWebViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 26F9A83A18A3463F00AEB88A /* WKWebViewPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC4BEEAA120A0A5F00FBA0C7 /* InjectedBundleNodeHandle.cpp */; };
2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC33E0D012408E8600360F3F /* InjectedBundleRangeHandle.cpp */; };
@@ -2445,8 +2445,8 @@
2684054A18B866FF0022C38B /* VisibleContentRectUpdateInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VisibleContentRectUpdateInfo.cpp; sourceTree = "<group>"; };
2684055018B86ED60022C38B /* ViewUpdateDispatcherMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ViewUpdateDispatcherMessageReceiver.cpp; path = DerivedSources/WebKit2/ViewUpdateDispatcherMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
2684055118B86ED60022C38B /* ViewUpdateDispatcherMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewUpdateDispatcherMessages.h; path = DerivedSources/WebKit2/ViewUpdateDispatcherMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
- 26F10BE619187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKSyntheticClickTapGestureRecognizer.h; path = ios/WKSyntheticClickTapGestureRecognizer.h; sourceTree = "<group>"; };
- 26F10BE719187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WKSyntheticClickTapGestureRecognizer.m; path = ios/WKSyntheticClickTapGestureRecognizer.m; sourceTree = "<group>"; };
+ 26F10BE619187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKSyntheticTapGestureRecognizer.h; path = ios/WKSyntheticTapGestureRecognizer.h; sourceTree = "<group>"; };
+ 26F10BE719187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WKSyntheticTapGestureRecognizer.m; path = ios/WKSyntheticTapGestureRecognizer.m; sourceTree = "<group>"; };
26F9A83A18A3463F00AEB88A /* WKWebViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKWebViewPrivate.h; sourceTree = "<group>"; };
290F4271172A0C7400939FF0 /* AuxiliaryProcessSupplement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuxiliaryProcessSupplement.h; sourceTree = "<group>"; };
29232DF118B29D1100D0596F /* WKAccessibilityWebPageObjectMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKAccessibilityWebPageObjectMac.mm; sourceTree = "<group>"; };
@@ -5904,10 +5904,10 @@
A1046EA02079263100F0C5D8 /* WKPDFView.mm */,
0FCB4E4418BBE044000FCFC9 /* WKScrollView.h */,
0FCB4E4518BBE044000FCFC9 /* WKScrollView.mm */,
- 26F10BE619187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.h */,
- 26F10BE719187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.m */,
CE5B4C8621B73D870022E64F /* WKSyntheticFlagsChangedWebEvent.h */,
CE5B4C8721B73D870022E64F /* WKSyntheticFlagsChangedWebEvent.mm */,
+ 26F10BE619187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.h */,
+ 26F10BE719187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.m */,
316B8B622054B55800BD4A62 /* WKSystemPreviewView.h */,
316B8B612054B55800BD4A62 /* WKSystemPreviewView.mm */,
2D1E8221216FFF5000A15265 /* WKWebEvent.h */,
@@ -9964,8 +9964,8 @@
BC407606124FF0270068F20A /* WKString.h in Headers */,
BC40761A124FF0370068F20A /* WKStringCF.h in Headers */,
BC9099801256A98200083756 /* WKStringPrivate.h in Headers */,
- 26F10BE819187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.h in Headers */,
CE5B4C8821B73D870022E64F /* WKSyntheticFlagsChangedWebEvent.h in Headers */,
+ 26F10BE819187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.h in Headers */,
316B8B642054B55800BD4A62 /* WKSystemPreviewView.h in Headers */,
51F886A61F2C228100C193EF /* WKTestingSupport.h in Headers */,
31D755C11D91B81500843BD1 /* WKTextChecker.h in Headers */,
@@ -11167,7 +11167,7 @@
637281A321ADC744009E0DE6 /* WKDownloadProgress.mm in Sources */,
5CA26D83217AD1B800F97A35 /* WKSafeBrowsingWarning.mm in Sources */,
1DB01944211CF005009FB3E8 /* WKShareSheet.mm in Sources */,
- 26F10BE919187E2E001D0E68 /* WKSyntheticClickTapGestureRecognizer.m in Sources */,
+ 26F10BE919187E2E001D0E68 /* WKSyntheticTapGestureRecognizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Modified: trunk/Source/WebKit/WebProcess/WebPage/ViewGestureGeometryCollector.h (242756 => 242757)
--- trunk/Source/WebKit/WebProcess/WebPage/ViewGestureGeometryCollector.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/WebProcess/WebPage/ViewGestureGeometryCollector.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -46,6 +46,8 @@
void mainFrameDidLayout();
+ void computeZoomInformationForNode(WebCore::Node&, WebCore::FloatPoint& origin, WebCore::FloatRect& renderRect, bool& isReplaced, double& viewportMinimumScale, double& viewportMaximumScale);
+
private:
// IPC::MessageReceiver.
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
@@ -62,7 +64,6 @@
#endif
void dispatchDidCollectGeometryForSmartMagnificationGesture(WebCore::FloatPoint origin, WebCore::FloatRect targetRect, WebCore::FloatRect visibleContentRect, bool fitEntireRect, double viewportMinimumScale, double viewportMaximumScale);
- void computeZoomInformationForNode(WebCore::Node&, WebCore::FloatPoint& origin, WebCore::FloatRect& renderRect, bool& isReplaced, double& viewportMinimumScale, double& viewportMaximumScale);
void computeMinimumAndMaximumViewportScales(double& viewportMinimumScale, double& viewportMaximumScale) const;
#if PLATFORM(IOS_FAMILY)
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (242756 => 242757)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-03-11 23:43:04 UTC (rev 242757)
@@ -614,7 +614,7 @@
bool hasStablePageScaleFactor() const { return m_hasStablePageScaleFactor; }
void handleTap(const WebCore::IntPoint&, OptionSet<WebKit::WebEvent::Modifier>, uint64_t lastLayerTreeTransactionId);
- void potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint&);
+ void potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint&, bool shouldRequestMagnificationInformation);
void commitPotentialTap(OptionSet<WebKit::WebEvent::Modifier>, uint64_t lastLayerTreeTransactionId);
void commitPotentialTapFailed();
void cancelPotentialTap();
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (242756 => 242757)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-03-11 23:43:04 UTC (rev 242757)
@@ -52,7 +52,7 @@
DynamicViewportSizeUpdate(WebCore::FloatSize viewLayoutSize, WebCore::FloatSize maximumUnobscuredSize, WebCore::FloatRect targetExposedContentRect, WebCore::FloatRect targetUnobscuredRect, WebCore::FloatRect targetUnobscuredRectInScrollViewCoordinates, WebCore::RectEdges<float> targetUnobscuredSafeAreaInsets, double scale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID)
HandleTap(WebCore::IntPoint point, OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId)
- PotentialTapAtPosition(uint64_t requestID, WebCore::FloatPoint point)
+ PotentialTapAtPosition(uint64_t requestID, WebCore::FloatPoint point, bool shouldRequestMagnificationInformation)
CommitPotentialTap(OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t lastLayerTreeTransactionId)
CancelPotentialTap()
TapHighlightAtPosition(uint64_t requestID, WebCore::FloatPoint point)
Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (242756 => 242757)
--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm 2019-03-11 23:36:14 UTC (rev 242756)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm 2019-03-11 23:43:04 UTC (rev 242757)
@@ -43,6 +43,7 @@
#import "SandboxUtilities.h"
#import "UIKitSPI.h"
#import "UserData.h"
+#import "ViewGestureGeometryCollector.h"
#import "VisibleContentRectUpdateInfo.h"
#import "WKAccessibilityWebPageObjectIOS.h"
#import "WebAutocorrectionContext.h"
@@ -808,9 +809,22 @@
frame.document()->setFocusedElement(image.get());
}
-void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position)
+void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position, bool shouldRequestMagnificationInformation)
{
m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation, m_potentialTapSecurityOrigin.get());
+
+ if (shouldRequestMagnificationInformation && m_potentialTapNode && m_viewGestureGeometryCollector) {
+ // FIXME: Could this be combined into tap highlight?
+ FloatPoint origin = position;
+ FloatRect renderRect;
+ bool fitEntireRect;
+ double viewportMinimumScale;
+ double viewportMaximumScale;
+
+ m_viewGestureGeometryCollector->computeZoomInformationForNode(*m_potentialTapNode, origin, renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale);
+ send(Messages::WebPageProxy::HandleSmartMagnificationInformationForPotentialTap(requestID, renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale));
+ }
+
sendTapHighlightForNodeIfNecessary(requestID, m_potentialTapNode.get());
#if ENABLE(TOUCH_EVENTS)
if (m_potentialTapNode && !m_potentialTapNode->allowsDoubleTapGesture())