Make preserve and restore focus more likely to be symmetrical
authormegan_gardner@apple.com <megan_gardner@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Jan 2018 22:16:08 +0000 (22:16 +0000)
committermegan_gardner@apple.com <megan_gardner@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 30 Jan 2018 22:16:08 +0000 (22:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182264
Source/WebKit:

<rdar://problem/36948473>

Reviewed by Tim Horton.

Keep a stack of if we actually increment the focusState, so that
changes to the web content do not result in asymmetric decrements to the focus state.
To work around problems associated with <rdar://problem/37000122>.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _restoreFocusWithToken:]):
(-[WKContentView _preserveFocusWithToken:destructively:]):

LayoutTests:

Reviewed by Tim Horton.

Added new test to verify that opening a selection form twice works.

* fast/forms/ios/ipad/select-form-run-twice-expected.txt: Added.
* fast/forms/ios/ipad/select-form-run-twice.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/forms/ios/ipad/select-form-run-twice-expected.txt [new file with mode: 0644]
LayoutTests/fast/forms/ios/ipad/select-form-run-twice.html [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

index 99f730b443e0e27d89b4253237c16119a43e4433..ed3424aba40518404eadafc66e518301f804117c 100644 (file)
@@ -1,3 +1,15 @@
+2018-01-30  Megan Gardner  <megan_gardner@apple.com>
+
+        Make preserve and restore focus more likely to be symmetrical
+        https://bugs.webkit.org/show_bug.cgi?id=182264
+
+        Reviewed by Tim Horton.
+
+        Added new test to verify that opening a selection form twice works.
+
+        * fast/forms/ios/ipad/select-form-run-twice-expected.txt: Added.
+        * fast/forms/ios/ipad/select-form-run-twice.html: Added.
+
 2018-01-30  Dean Jackson  <dino@apple.com>
 
         CrashTracer: com.apple.WebKit.WebContent at WebCore: WebCore::Document::updateStyleIfNeeded
diff --git a/LayoutTests/fast/forms/ios/ipad/select-form-run-twice-expected.txt b/LayoutTests/fast/forms/ios/ipad/select-form-run-twice-expected.txt
new file mode 100644 (file)
index 0000000..f08ec5d
--- /dev/null
@@ -0,0 +1,7 @@
+This is the top
+
+First Click
+Final Click
+March June
+PASS: hit testing found #nextButton after first select interaction
+PASS: hit testing found #finalTarget after select interaction
diff --git a/LayoutTests/fast/forms/ios/ipad/select-form-run-twice.html b/LayoutTests/fast/forms/ios/ipad/select-form-run-twice.html
new file mode 100644 (file)
index 0000000..ea1c152
--- /dev/null
@@ -0,0 +1,140 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
+    <style>
+        body {
+            height: 1500px;
+        }
+        #container {
+            position: fixed;
+            top: 10px;
+            left: 10px;
+            bottom: 30px;
+            right: 10px;
+            background-color: rgba(0, 0, 0, 0.5);
+            padding: 10px;
+            box-sizing: border-box;
+            border: 5px solid black;
+        }
+        
+        select {
+            display: block;
+            margin: 500px 200px 20px 20px;
+        }
+        
+        button {
+            display: block;
+        }
+        
+    </style>
+    <script src="../resources/zooming-test-utils.js"></script>
+    <script src="../../../../resources/basic-gestures.js"></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        function getScrollDownUIScript(x, y)
+        {
+            return `
+                (function() {
+                    uiController.didEndScrollingCallback = function() {
+                        uiController.uiScriptComplete();
+                    };
+
+                    uiController.scrollToOffset(${x}, ${y});
+                })();`
+        }
+
+        function getTapOnSelectUIScript(x, y, row)
+        {
+            return `
+                (function() {
+                    uiController.didStartFormControlInteractionCallback = function() {
+                        uiController.selectFormAccessoryPickerRow(${row});
+                    };
+
+                    uiController.didEndFormControlInteractionCallback = function() {
+                        uiController.uiScriptComplete();
+                    };
+
+                    uiController.singleTapAtPoint(${x}, ${y}, function() {
+                    });
+                })();`
+        }
+
+        function firstButtonClicked()
+        {
+            document.getElementById('nextStep').textContent = 'PASS: hit testing found #nextButton after first select interaction';
+            var selectElement = document.getElementsByTagName('select')[0];
+            var point = getPointInsideElement(selectElement, 10, 10);
+            testRunner.runUIScript(getTapOnSelectUIScript(point.x, point.y, 5), function() {
+                document.getElementById('select-value2').textContent = selectElement.value;
+                    tryTapOnButton('finalTarget');
+            });
+        }
+    
+        function finalButtonClicked()
+        {
+            document.getElementById('result').textContent = 'PASS: hit testing found #finalTarget after select interaction';
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+
+        async function tryTapOnButton(target)
+        {
+            var point = getPointInsideElement(document.getElementById(target), 10, 10);
+            await tapAtPoint(point.x, point.y);
+            
+            // We have to keep retrying, because the dimming view behind the popover animates out,
+            // and we currently have no callback when that animation completes.
+            window.setTimeout(tryTapOnButton.bind(this, target), 100);
+        }
+
+        function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            testRunner.waitUntilDone();
+            testRunner.dumpAsText();
+
+            testRunner.runUIScript(getScrollDownUIScript(0, 500), function() {
+                var selectElement = document.getElementsByTagName('select')[0];
+                var point = getPointInsideElement(selectElement, 10, 10);
+                testRunner.runUIScript(getTapOnSelectUIScript(point.x, point.y, 2), function() {
+                    document.getElementById('select-value').textContent = selectElement.value;
+                    tryTapOnButton('firstTarget');
+                });
+            });
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <p>This is the top</p>
+    <div id="container">
+        <button id="firstTarget" onclick="firstButtonClicked()">First Click</button>
+        <button id="finalTarget" onclick="finalButtonClicked()">Final Click</button>
+        <select>
+            <option>January</option>
+            <option>February</option>
+            <option>March</option>
+            <option>April</option>
+            <option>May</option>
+            <option>June</option>
+            <option>July</option>
+            <option>August</option>
+            <option>September</option>
+        </select>
+        <span id="select-value">Value goes here</span>
+        <span id="select-value2">2nd Value goes here</span>
+        <div id="nextStep">FAIL: should have hit-tested and found #target element</div>
+        <div id="result">FAIL: should have hit-tested and found #target element</div>
+    </div>
+    
+</div>
+</body>
+</html>
index 2c7b90ca4d8e89a4ed7b730eccd161ecc1cb2924..e47d58b83aa076fbf78f842e95d7d6c6a5417d8a 100644 (file)
@@ -1,3 +1,20 @@
+2018-01-30  Megan Gardner  <megan_gardner@apple.com>
+
+        Make preserve and restore focus more likely to be symmetrical
+        https://bugs.webkit.org/show_bug.cgi?id=182264
+        <rdar://problem/36948473>
+        
+        Reviewed by Tim Horton.
+
+        Keep a stack of if we actually increment the focusState, so that
+        changes to the web content do not result in asymmetric decrements to the focus state. 
+        To work around problems associated with <rdar://problem/37000122>.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _restoreFocusWithToken:]):
+        (-[WKContentView _preserveFocusWithToken:destructively:]):
+
 2018-01-30  Brent Fulgham  <bfulgham@apple.com>
 
         Add telemetry to track storage access API adoption
index c26f2474c86b00ae7eef39d1cafc19bb65f56c24..39de2ef692644e9a84ff06a64fae2603c4bcf82a 100644 (file)
@@ -171,6 +171,7 @@ struct WKAutoCorrectionData {
     RetainPtr<WKFileUploadPanel> _fileUploadPanel;
     RetainPtr<UIGestureRecognizer> _previewGestureRecognizer;
     RetainPtr<UIGestureRecognizer> _previewSecondaryGestureRecognizer;
+    Vector<bool> _focusStateStack;
 #if HAVE(LINK_PREVIEW)
     RetainPtr<UIPreviewItemController> _previewItemController;
 #endif
index a339190f790cde1722e149c1032aadcaac451a0b..8297b4f519d839ad629ce5b2e902374908f4e40b 100644 (file)
@@ -4169,14 +4169,21 @@ static bool isAssistableInputType(InputType type)
 
 - (void)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token
 {
-    if (!_inputPeripheral)
+    ASSERT(!_focusStateStack.isEmpty());
+    
+    if (_focusStateStack.takeLast()) {
+        ASSERT(_webView->_activeFocusedStateRetainCount);
         --_webView->_activeFocusedStateRetainCount;
+    }
 }
 
 - (void)_preserveFocusWithToken:(id <NSCopying, NSSecureCoding>)token destructively:(BOOL)destructively
 {
-    if (!_inputPeripheral)
+    if (!_inputPeripheral) {
         ++_webView->_activeFocusedStateRetainCount;
+        _focusStateStack.append(true);
+    } else
+        _focusStateStack.append(false);
 }
 
 #pragma mark - Implementation of UIWebTouchEventsGestureRecognizerDelegate.