<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[243153] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/243153">243153</a></dd>
<dt>Author</dt> <dd>dbates@webkit.org</dd>
<dt>Date</dt> <dd>2019-03-19 11:25:21 -0700 (Tue, 19 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS] Focus not preserved when switching between tabs
https://bugs.webkit.org/show_bug.cgi?id=195820
<rdar://problem/43614450>

Reviewed by Brent Fulgham.

Source/WebKit:

Fixes a usability annoyance when using a hardware keyboard; focus is not preserved when switching between tabs.
Do not unconditionally tell the WebProcess to blur the currently focused element when the content view (WKContentView)
resigns first responder. Instead only tell it to blur when the content view is resigning because either the
accessory view was dismissed (Done button was pressed) or the keyboard was dismissed (the hide keyboard button
was pressed).

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm: Add new ivar to track whether the content view is resigning
first responder status because the accessory view is being dismissed.
(-[WKContentView resignFirstResponderForWebView]): Only tell WebKit to blur the focused element if we are
resigning because the accessory view is being dismissed or the keyboard was hidden. We continue to do all
other steps when resigning, including hiding the keyboard. Note that by not telling WebKit to blur the
focused element we let it's focus controller manage the focused element with respect to the current
page activation state (i.e. whether the content view is first responder or not). When the content view
becomes the first responder then WebKit's focus controller will be told that the page has become activated
and will tell the UIProcess to focus the currently focused element, which will bring up the keyboard.
(-[WKContentView accessoryDone]): Update state so we know that a subsequent call to resign first responder
was due to the accessory view being dismissed.

Tools:

Add tests to ensure that we restore focus when resigning and becoming first responder.

* TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
(TestWebKitAPI::TEST):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitUIProcessiosWKContentViewInteractionh">trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsiosKeyboardInputTestsIOSmm">trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (243152 => 243153)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2019-03-19 18:03:33 UTC (rev 243152)
+++ trunk/Source/WebKit/ChangeLog       2019-03-19 18:25:21 UTC (rev 243153)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2019-03-19  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Focus not preserved when switching between tabs
+        https://bugs.webkit.org/show_bug.cgi?id=195820
+        <rdar://problem/43614450>
+
+        Reviewed by Brent Fulgham.
+
+        Fixes a usability annoyance when using a hardware keyboard; focus is not preserved when switching between tabs.
+        Do not unconditionally tell the WebProcess to blur the currently focused element when the content view (WKContentView)
+        resigns first responder. Instead only tell it to blur when the content view is resigning because either the
+        accessory view was dismissed (Done button was pressed) or the keyboard was dismissed (the hide keyboard button
+        was pressed).
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm: Add new ivar to track whether the content view is resigning
+        first responder status because the accessory view is being dismissed.
+        (-[WKContentView resignFirstResponderForWebView]): Only tell WebKit to blur the focused element if we are
+        resigning because the accessory view is being dismissed or the keyboard was hidden. We continue to do all
+        other steps when resigning, including hiding the keyboard. Note that by not telling WebKit to blur the
+        focused element we let it's focus controller manage the focused element with respect to the current
+        page activation state (i.e. whether the content view is first responder or not). When the content view
+        becomes the first responder then WebKit's focus controller will be told that the page has become activated
+        and will tell the UIProcess to focus the currently focused element, which will bring up the keyboard.
+        (-[WKContentView accessoryDone]): Update state so we know that a subsequent call to resign first responder
+        was due to the accessory view being dismissed.
+
</ins><span class="cx"> 2019-03-19  Per Arne Vollan  <pvollan@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS] Remove overridden rules in sandbox
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessiosWKContentViewInteractionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (243152 => 243153)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h     2019-03-19 18:03:33 UTC (rev 243152)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h        2019-03-19 18:25:21 UTC (rev 243153)
</span><span class="lines">@@ -311,6 +311,7 @@
</span><span class="cx"> 
</span><span class="cx">     BOOL _becomingFirstResponder;
</span><span class="cx">     BOOL _resigningFirstResponder;
</span><ins>+    BOOL _dismissingAccessory;
</ins><span class="cx">     BOOL _needsDeferredEndScrollingSelectionUpdate;
</span><span class="cx">     BOOL _isChangingFocus;
</span><span class="cx">     BOOL _isBlurringFocusedElement;
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (243152 => 243153)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm    2019-03-19 18:03:33 UTC (rev 243152)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm       2019-03-19 18:25:21 UTC (rev 243153)
</span><span class="lines">@@ -1174,7 +1174,8 @@
</span><span class="cx">     if (!_webView._retainingActiveFocusedState) {
</span><span class="cx">         // We need to complete the editing operation before we blur the element.
</span><span class="cx">         [self _endEditing];
</span><del>-        _page->blurFocusedElement();
</del><ins>+        if (_dismissingAccessory || _keyboardDidRequestDismissal)
+            _page->blurFocusedElement();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     [self _cancelInteraction];
</span><span class="lines">@@ -3691,6 +3692,7 @@
</span><span class="cx"> // UIWebFormAccessoryDelegate
</span><span class="cx"> - (void)accessoryDone
</span><span class="cx"> {
</span><ins>+    SetForScope<BOOL> dismissingAccessoryScope { _dismissingAccessory, YES };
</ins><span class="cx">     [self resignFirstResponder];
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (243152 => 243153)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2019-03-19 18:03:33 UTC (rev 243152)
+++ trunk/Tools/ChangeLog       2019-03-19 18:25:21 UTC (rev 243153)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2019-03-19  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Focus not preserved when switching between tabs
+        https://bugs.webkit.org/show_bug.cgi?id=195820
+        <rdar://problem/43614450>
+
+        Reviewed by Brent Fulgham.
+
+        Add tests to ensure that we restore focus when resigning and becoming first responder.
+
+        * TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm:
+        (TestWebKitAPI::TEST):
+
</ins><span class="cx"> 2019-03-19  Alex Christensen  <achristensen@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         Make WTFLogChannelState and WTFLogLevel enum classes
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsiosKeyboardInputTestsIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm (243152 => 243153)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm     2019-03-19 18:03:33 UTC (rev 243152)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/KeyboardInputTestsIOS.mm        2019-03-19 18:25:21 UTC (rev 243153)
</span><span class="lines">@@ -274,7 +274,7 @@
</span><span class="cx">     EXPECT_WK_STREQ("a", [webView stringByEvaluatingJavaScript:@"document.querySelector('input').value"]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST(KeyboardInputTests, CaretSelectionRectAfterRestoringFirstResponder)
</del><ins>+TEST(KeyboardInputTests, CaretSelectionRectAfterRestoringFirstResponderWithRetainActiveFocusedState)
</ins><span class="cx"> {
</span><span class="cx">     auto expectedCaretRect = CGRectMake(16, 13, 2, 15);
</span><span class="cx">     auto webView = webViewWithAutofocusedInput();
</span><span class="lines">@@ -290,7 +290,7 @@
</span><span class="cx">     [webView waitForCaretViewFrameToBecome:expectedCaretRect];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST(KeyboardInputTests, RangedSelectionRectAfterRestoringFirstResponder)
</del><ins>+TEST(KeyboardInputTests, RangedSelectionRectAfterRestoringFirstResponderWithRetainActiveFocusedState)
</ins><span class="cx"> {
</span><span class="cx">     NSArray *expectedSelectionRects = @[ [NSValue valueWithCGRect:CGRectMake(16, 13, 24, 15)] ];
</span><span class="cx"> 
</span><span class="lines">@@ -309,6 +309,37 @@
</span><span class="cx">     [webView waitForSelectionViewRectsToBecome:expectedSelectionRects];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST(KeyboardInputTests, CaretSelectionRectAfterRestoringFirstResponder)
+{
+    auto expectedCaretRect = CGRectMake(16, 13, 2, 15);
+    auto webView = webViewWithAutofocusedInput();
+    EXPECT_WK_STREQ("INPUT", [webView stringByEvaluatingJavaScript:@"document.activeElement.tagName"]);
+    [webView waitForCaretViewFrameToBecome:expectedCaretRect];
+
+    [webView resignFirstResponder];
+    [webView waitForCaretViewFrameToBecome:CGRectZero];
+
+    [webView becomeFirstResponder];
+    [webView waitForCaretViewFrameToBecome:expectedCaretRect];
+}
+
+TEST(KeyboardInputTests, RangedSelectionRectAfterRestoringFirstResponder)
+{
+    NSArray *expectedSelectionRects = @[ [NSValue valueWithCGRect:CGRectMake(16, 13, 24, 15)] ];
+
+    auto webView = webViewWithAutofocusedInput();
+    [[webView textInputContentView] insertText:@"hello"];
+    [webView selectAll:nil];
+    EXPECT_WK_STREQ("INPUT", [webView stringByEvaluatingJavaScript:@"document.activeElement.tagName"]);
+    [webView waitForSelectionViewRectsToBecome:expectedSelectionRects];
+
+    [webView resignFirstResponder];
+    [webView waitForSelectionViewRectsToBecome:@[ ]];
+
+    [webView becomeFirstResponder];
+    [webView waitForSelectionViewRectsToBecome:expectedSelectionRects];
+}
+
</ins><span class="cx"> TEST(KeyboardInputTests, KeyboardTypeForInput)
</span><span class="cx"> {
</span><span class="cx">     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
</span></span></pre>
</div>
</div>

</body>
</html>