(iPad) Link tapping is sluggish on many sites
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jan 2019 19:15:57 +0000 (19:15 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jan 2019 19:15:57 +0000 (19:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=193522
<rdar://problem/47102987>

Reviewed by Wenson Hsieh.

Source/WebKit:

Some WKWebView clients might set the initial zoom scale of the page to
something other than 1, which disables the "fast tap" behaviour.
The fix is very simple -- just check against the initial scale rather
than 1.

The most likely regression from this would be pages designed for desktop,
but provide a viewport tag saying width=device-width and initial-scale.
They might stop allowing double-tap-to-zoom.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _allowsDoubleTapGestures]): Check against initial page scale.

LayoutTests:

Add a test that checks a double tap will trigger a click
event on a page that is at initial scale.

Extra bonus: for some reason adding this test, or making this code
change, uncovered a couple of bugs in existing tests. The
viewport-zooms-from-element-to-initial-scale test was completely wrong
because it was expecting the incorrect result, which was triggered by
the zoom callback firing early at a forced scale value. The
viewport-no-width-value-allows-double-tap test was triggering a JS
error in its UI script. I modernised both of these to use UIHelper instead.

* fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale-expected.txt: Added.
* fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale.html: Added.
* fast/events/ios/viewport-no-width-value-allows-double-tap.html:
* fast/events/ios/viewport-zooms-from-element-to-initial-scale-expected.txt:
* fast/events/ios/viewport-zooms-from-element-to-initial-scale.html:
* resources/ui-helper.js: Add doubleTapAt and zoomByDoubleTapAt helpers. Remove the
unnecessary "Done" return value from many of the callbacks. Give zoomToScale a return
value.
(window.UIHelper.tapAt.return.new.Promise):
(window.UIHelper.tapAt):
(window.UIHelper.doubleTapAt.return.new.Promise):
(window.UIHelper.doubleTapAt):
(window.UIHelper.zoomByDoubleTappingAt):
(window.UIHelper.activateAt.return.new.Promise):
(window.UIHelper.activateAt):
(window.UIHelper.toggleCapsLock):
(window.UIHelper.ensurePresentationUpdate.return.new.Promise):
(window.UIHelper.ensurePresentationUpdate):
(window.UIHelper.activateAndWaitForInputSessionAt.return.new.Promise.):
(window.UIHelper.activateFormControl.return.new.Promise.):
(window.UIHelper.replaceTextAtRange):
(window.UIHelper.zoomToScale):
(window.UIHelper.stylusTapAt.return.new.Promise):
(window.UIHelper.stylusTapAt):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240119 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale.html [new file with mode: 0644]
LayoutTests/fast/events/ios/viewport-no-width-value-allows-double-tap.html
LayoutTests/fast/events/ios/viewport-zooms-from-element-to-initial-scale-expected.txt
LayoutTests/fast/events/ios/viewport-zooms-from-element-to-initial-scale.html
LayoutTests/resources/ui-helper.js
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

index 8d1f88e..f379523 100644 (file)
@@ -1,3 +1,47 @@
+2019-01-16  Dean Jackson  <dino@apple.com>
+
+        (iPad) Link tapping is sluggish on many sites
+        https://bugs.webkit.org/show_bug.cgi?id=193522
+        <rdar://problem/47102987>
+
+        Reviewed by Wenson Hsieh.
+
+        Add a test that checks a double tap will trigger a click
+        event on a page that is at initial scale.
+
+        Extra bonus: for some reason adding this test, or making this code
+        change, uncovered a couple of bugs in existing tests. The
+        viewport-zooms-from-element-to-initial-scale test was completely wrong
+        because it was expecting the incorrect result, which was triggered by
+        the zoom callback firing early at a forced scale value. The
+        viewport-no-width-value-allows-double-tap test was triggering a JS
+        error in its UI script. I modernised both of these to use UIHelper instead.
+
+        * fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale-expected.txt: Added.
+        * fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale.html: Added.
+        * fast/events/ios/viewport-no-width-value-allows-double-tap.html:
+        * fast/events/ios/viewport-zooms-from-element-to-initial-scale-expected.txt:
+        * fast/events/ios/viewport-zooms-from-element-to-initial-scale.html:
+        * resources/ui-helper.js: Add doubleTapAt and zoomByDoubleTapAt helpers. Remove the
+        unnecessary "Done" return value from many of the callbacks. Give zoomToScale a return
+        value.
+        (window.UIHelper.tapAt.return.new.Promise):
+        (window.UIHelper.tapAt):
+        (window.UIHelper.doubleTapAt.return.new.Promise):
+        (window.UIHelper.doubleTapAt):
+        (window.UIHelper.zoomByDoubleTappingAt):
+        (window.UIHelper.activateAt.return.new.Promise):
+        (window.UIHelper.activateAt):
+        (window.UIHelper.toggleCapsLock):
+        (window.UIHelper.ensurePresentationUpdate.return.new.Promise):
+        (window.UIHelper.ensurePresentationUpdate):
+        (window.UIHelper.activateAndWaitForInputSessionAt.return.new.Promise.):
+        (window.UIHelper.activateFormControl.return.new.Promise.):
+        (window.UIHelper.replaceTextAtRange):
+        (window.UIHelper.zoomToScale):
+        (window.UIHelper.stylusTapAt.return.new.Promise):
+        (window.UIHelper.stylusTapAt):
+
 2019-01-17  Per Arne Vollan  <pvollan@apple.com>
 
         Layout Test js/dfg-int-overflow-in-loop.html is failing
diff --git a/LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale-expected.txt b/LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale-expected.txt
new file mode 100644 (file)
index 0000000..651c5b9
--- /dev/null
@@ -0,0 +1,2 @@
+PASS: Click fired on element with handler.
+This document is set up to enable fast clicks, because it has not moved from its initial scale. Double tapping on the rectangle above should send a click event, not trigger a zoom.
diff --git a/LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale.html b/LayoutTests/fast/events/ios/fast-click-double-tap-sends-click-when-initial-scale.html
new file mode 100644 (file)
index 0000000..9e11f0b
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+
+<html>
+<meta name="viewport" content="initial-scale=0.98,width=device-width">
+<head>
+    <script src="../../../resources/ui-helper.js"></script>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        async function runTest()
+        {
+            document.getElementById("target").addEventListener("click", handleClick, false);
+
+            if (!window.testRunner)
+                return;
+            await UIHelper.doubleTapAt(50, 50);
+        }
+
+        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 is set up to enable fast clicks, because
+    it has not moved from its initial scale. Double tapping on the rectangle
+    above should send a click event, not trigger a zoom.</div>
+</body>
+</html>
index 4802253..8caeef5 100644 (file)
@@ -5,28 +5,16 @@
 
 <head>
     <script src="../../../resources/js-test-pre.js"></script>
-    <script id="ui-script" type="text/plain">
-        (function() {
-            uiController.doubleTapAtPoint(15, 400, function() {
-                uiController.uiScriptComplete();
-            });
-        })();
-    </script>
+    <script src="../../../resources/ui-helper.js"></script>
 
     <script>
-    var scriptCompleted = false;
-    var clickCount = 0;
     if (window.testRunner)
         testRunner.waitUntilDone();
 
-    function getUIScript() {
-        return document.getElementById("ui-script").text;
-    }
-
-    function runTest() {
+    async function runTest() {
         window.addEventListener("scroll", scrolled, false);
-        if (testRunner.runUIScript)
-            testRunner.runUIScript(getUIScript());
+        if (window.testRunner)
+            await UIHelper.doubleTapAt(15, 400);
     }
     function scrolled() {
         if (window.testRunner)
index f9fe216..6ec50bb 100644 (file)
@@ -3,35 +3,22 @@
 <html>
 <meta name="viewport" content="initial-scale=5, width=device-width">
 <head>
-    <script id="ui-script" type="text/plain">
-        (function() {
-            uiController.didEndZoomingCallback = function() {
-                uiController.uiScriptComplete(uiController.zoomScale);
-            };
-            uiController.doubleTapAtPoint(15, 15, function() {});
-        })();
-    </script>
+    <script src="../../../resources/ui-helper.js"></script>
     <script>
         if (window.testRunner) {
             testRunner.dumpAsText();
             testRunner.waitUntilDone();
         }
 
-        function getUIScript()
-        {
-            return document.getElementById("ui-script").text;
-        }
-
-        function runTest()
+        async function runTest()
         {
-            if (!window.eventSender || !testRunner.runUIScript)
+            if (!window.testRunner)
                 return;
 
-            eventSender.scalePageBy(1.6, 1.6);
-            testRunner.runUIScript(getUIScript(), function(result) {
-                document.getElementById("target").innerText = "The viewport zoomed to scale: " + Number(result);
-                testRunner.notifyDone();
-            });
+            await UIHelper.zoomToScale(1.6);
+            let result = await UIHelper.zoomByDoubleTappingAt(15, 15);
+            document.getElementById("target").innerText = "The viewport zoomed to scale: " + Number(result);
+            testRunner.notifyDone();
         }
     </script>
     <style>
index 2f569aa..1269759 100644 (file)
@@ -25,11 +25,61 @@ window.UIHelper = class UIHelper {
         return new Promise((resolve) => {
             testRunner.runUIScript(`
                 uiController.singleTapAtPoint(${x}, ${y}, function() {
-                    uiController.uiScriptComplete('Done');
+                    uiController.uiScriptComplete();
                 });`, resolve);
         });
     }
 
+    static doubleTapAt(x, y)
+    {
+        console.assert(this.isIOS());
+
+        if (!this.isWebKit2()) {
+            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((resolve) => {
+            testRunner.runUIScript(`
+                uiController.doubleTapAtPoint(${x}, ${y}, function() {
+                    uiController.uiScriptComplete();
+                });`, resolve);
+        });
+    }
+
+    static zoomByDoubleTappingAt(x, y)
+    {
+        console.assert(this.isIOS());
+
+        if (!this.isWebKit2()) {
+            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((resolve) => {
+            testRunner.runUIScript(`
+                uiController.didEndZoomingCallback = () => {
+                    uiController.didEndZoomingCallback = null;
+                    uiController.uiScriptComplete(uiController.zoomScale);
+                };
+                uiController.doubleTapAtPoint(${x}, ${y}, () => {});`, resolve);
+        });
+    }
+
     static activateAt(x, y)
     {
         if (!this.isWebKit2() || !this.isIOS()) {
@@ -42,7 +92,7 @@ window.UIHelper = class UIHelper {
         return new Promise((resolve) => {
             testRunner.runUIScript(`
                 uiController.singleTapAtPoint(${x}, ${y}, function() {
-                    uiController.uiScriptComplete('Done');
+                    uiController.uiScriptComplete();
                 });`, resolve);
         });
     }
@@ -69,7 +119,7 @@ window.UIHelper = class UIHelper {
     static toggleCapsLock()
     {
         return new Promise((resolve) => {
-            testRunner.runUIScript(`uiController.toggleCapsLock(() => uiController.uiScriptComplete('Done'));`, resolve);
+            testRunner.runUIScript(`uiController.toggleCapsLock(() => uiController.uiScriptComplete());`, resolve);
         });
     }
 
@@ -83,7 +133,7 @@ window.UIHelper = class UIHelper {
         return new Promise(resolve => {
             testRunner.runUIScript(`
                 uiController.doAfterPresentationUpdate(function() {
-                    uiController.uiScriptComplete('Done');
+                    uiController.uiScriptComplete();
                 });`, resolve);
         });
     }
@@ -108,7 +158,7 @@ window.UIHelper = class UIHelper {
             testRunner.runUIScript(`
                 (function() {
                     uiController.didShowKeyboardCallback = function() {
-                        uiController.uiScriptComplete("Done");
+                        uiController.uiScriptComplete();
                     };
                     uiController.singleTapAtPoint(${x}, ${y}, function() { });
                 })()`, resolve);
@@ -127,7 +177,7 @@ window.UIHelper = class UIHelper {
             testRunner.runUIScript(`
                 (function() {
                     uiController.didStartFormControlInteractionCallback = function() {
-                        uiController.uiScriptComplete("Done");
+                        uiController.uiScriptComplete();
                     };
                     uiController.singleTapAtPoint(${x}, ${y}, function() { });
                 })()`, resolve);
@@ -250,7 +300,7 @@ window.UIHelper = class UIHelper {
         return new Promise(resolve => {
             testRunner.runUIScript(`(() => {
                 uiController.replaceTextAtRange("${text}", ${location}, ${length});
-                uiController.uiScriptComplete('Done');
+                uiController.uiScriptComplete();
             })()`, resolve);
         });
     }
@@ -348,7 +398,7 @@ window.UIHelper = class UIHelper {
 
     static zoomToScale(scale)
     {
-        const uiScript = `uiController.zoomToScale(${scale}, () => uiController.uiScriptComplete())`;
+        const uiScript = `uiController.zoomToScale(${scale}, () => uiController.uiScriptComplete(uiController.zoomScale))`;
         return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
     }
 
@@ -457,7 +507,7 @@ window.UIHelper = class UIHelper {
         return new Promise((resolve) => {
             testRunner.runUIScript(`
                 uiController.stylusTapAtPoint(${x}, ${y}, 2, 1, 0.5, function() {
-                    uiController.uiScriptComplete('Done');
+                    uiController.uiScriptComplete();
                 });`, resolve);
         });
     }
index 3436967..b470139 100644 (file)
@@ -1,3 +1,23 @@
+2019-01-16  Dean Jackson  <dino@apple.com>
+
+        (iPad) Link tapping is sluggish on many sites
+        https://bugs.webkit.org/show_bug.cgi?id=193522
+        <rdar://problem/47102987>
+
+        Reviewed by Wenson Hsieh.
+
+        Some WKWebView clients might set the initial zoom scale of the page to
+        something other than 1, which disables the "fast tap" behaviour.
+        The fix is very simple -- just check against the initial scale rather
+        than 1.
+
+        The most likely regression from this would be pages designed for desktop,
+        but provide a viewport tag saying width=device-width and initial-scale.
+        They might stop allowing double-tap-to-zoom.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _allowsDoubleTapGestures]): Check against initial page scale.
+
 2019-01-17  Alex Christensen  <achristensen@webkit.org>
 
         Stop using NetworkStorageSession::storageSession in WebCore
index 4a441b0..7c45a7d 100644 (file)
@@ -2505,9 +2505,8 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
 
     // At this point, we have a page that asked for width = device-width. However,
     // if the content's width and height were large, we might have had to shrink it.
-    // Since we'll enable double tap zoom whenever we're not at the actual
-    // initial scale, this simply becomes a test of the current scale against 1.
-    return !areEssentiallyEqualAsFloat(contentZoomScale(self), 1);
+    // We'll enable double tap zoom whenever we're not at the actual initial scale.
+    return !areEssentiallyEqualAsFloat(contentZoomScale(self), _initialScaleFactor);
 }
 
 - (BOOL)_stylusTapGestureShouldCreateEditableImage