Source/WebCore/ChangeLog

 12019-04-22 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 [iOS] element.focus() sometimes fails to reveal the focused element when it becomes editable dynamically
 4 https://bugs.webkit.org/show_bug.cgi?id=197188
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 The bug was caused by the scroll-to-reveal code trgiggered by Element::updateFocusAppearance updating
 9 the scroll position via scrolling tree update in a layer tree commit which happens after
 10 _zoomToRevealFocusedElement in WKWebContent view had already scrolled the frame view.
 11
 12 To fix this problem, we need to defer the editor state update until the layer commit (see r244494),
 13 and update the scrolling tree before invoking WebPageProxy::editorStateChanged which brings up
 14 the keyboard and scroll-to-reveal the caret in the UI process side.
 15
 16 We also avoid revealing the focus for the second time via Document::scheduleScrollToFocusedElement
 17 in Element::updateFocusAppearance as this timer based scrolling also happens after we had already
 18 revealed the caret in _zoomToRevealFocusedElement. This is a bit hacky but works for most cases since
 19 we wouldn't bring up a keyboard if the focused element was not editable anyway.
 20
 21 Test: editing/selection/ios/scrolling-to-focused-element-inside-iframe.html
 22
 23 * dom/Element.cpp:
 24 (WebCore::Element::updateFocusAppearance): Avoid scheduling a timer based reavel of the focused element
 25 when we're already revealing the element via selection change.
 26
1272019-04-22 Simon Fraser <simon.fraser@apple.com>
228
329 Introduce the concept of "opportunistic" stacking contexts

Source/WebKit/ChangeLog

 12019-04-22 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 [iOS] element.focus() sometimes fails to reveal the focused element when it becomes editable dynamically
 4 https://bugs.webkit.org/show_bug.cgi?id=197188
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Commit the scroll tree update before revealing the keyboard via editor state update.
 9
 10 * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
 11 (WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
 12
1132019-04-22 Ryan Haddad <ryanhaddad@apple.com>
214
315 Unreviewed, rolling out r244437.

Source/WebCore/dom/Element.cpp

@@void Element::updateFocusAppearance(SelectionRestorationMode, SelectionRevealMod
27852785 if (frame->selection().shouldChangeSelection(newSelection)) {
27862786 frame->selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
27872787 frame->selection().revealSelection(revealMode);
 2788 return;
27882789 }
27892790 }
27902791

Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm

@@void RemoteLayerTreeDrawingAreaProxy::commitLayerTree(const RemoteLayerTreeTrans
199199 m_transactionIDForPendingCACommit = layerTreeTransaction.transactionID();
200200 m_activityStateChangeID = layerTreeTransaction.activityStateChangeID();
201201
202  if (layerTreeTransaction.hasEditorState())
203  m_webPageProxy.editorStateChanged(layerTreeTransaction.editorState());
204 
205202 if (m_remoteLayerTreeHost->updateLayerTree(layerTreeTransaction)) {
206203 if (layerTreeTransaction.transactionID() >= m_transactionIDForUnhidingContent)
207204 m_webPageProxy.setRemoteLayerTreeRootNode(m_remoteLayerTreeHost->rootNode());

@@void RemoteLayerTreeDrawingAreaProxy::commitLayerTree(const RemoteLayerTreeTrans
255252 didRefreshDisplay();
256253#endif
257254
 255 if (layerTreeTransaction.hasEditorState())
 256 m_webPageProxy.editorStateChanged(layerTreeTransaction.editorState());
 257
258258 if (auto milestones = layerTreeTransaction.newlyReachedPaintingMilestones())
259259 m_webPageProxy.didReachLayoutMilestone(milestones);
260260

LayoutTests/ChangeLog

 12019-04-22 Ryosuke Niwa <rniwa@webkit.org>
 2
 3 [iOS] element.focus() sometimes fails to reveal the focused element when it becomes editable dynamically
 4 https://bugs.webkit.org/show_bug.cgi?id=197188
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Added a regression test.
 9
 10 * editing/selection/ios/scrolling-to-focused-element-inside-iframe-expected.txt: Added.
 11 * editing/selection/ios/scrolling-to-focused-element-inside-iframe.html: Added.
 12
1132019-04-22 Justin Fan <justin_fan@apple.com>
214
315 [WebGPU] Move swap chain methods from GPUDevice to GPUCanvasContext

LayoutTests/editing/selection/ios/scrolling-to-focused-element-inside-iframe-expected.txt

 1
 2
 3--------
 4Frame: '<!--frame1-->'
 5--------
 6click here This tests focusing an element inside an iframe at the bottom of the page.
 7To manually test, tap on "click here" below with docked software keyboard.
 8PASS

LayoutTests/editing/selection/ios/scrolling-to-focused-element-inside-iframe.html

 1<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
 2<html>
 3<head>
 4<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
 5</head>
 6<body>
 7<style>
 8html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
 9iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 10</style>
 11<script src="../../../resources/ui-helper.js"></script>
 12<script>
 13
 14const frame = document.createElement('iframe');
 15document.body.appendChild(frame);
 16frame.contentDocument.body.innerHTML = `
 17<style>
 18html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
 19body { background: #6cf; }
 20#description { position: absolute; top: 50%; padding: 10px; }
 21#container { position: absolute; top: 90%; left: 20%; width: 60%; padding: 10px; font-size: 20px; text-align: center; height: 200px; border: solid 1px #ccc; }
 22</style>
 23<div id="container" onclick="this.contentEditable = true; this.focus();">click here</div>
 24<p id="description">
 25 This tests focusing an element inside an iframe at the bottom of the page.<br>
 26 To manually test, tap on "click here" below with docked software keyboard.<br>
 27 <span id="result"></span>
 28</p>
 29`;
 30
 31let keyboardHeight = 250;
 32
 33function checkScrollTop() {
 34 frame.contentWindow.result.textContent = visualViewport.pageTop > keyboardHeight ? 'PASS' : `FAIL - ${visualViewport.offsetTop}px`;
 35}
 36
 37async function runTest() {
 38 testRunner.dumpAsText();
 39 testRunner.waitUntilDone();
 40 testRunner.dumpChildFramesAsText();
 41 await UIHelper.setHardwareKeyboardAttached(false);
 42 await UIHelper.activateAndWaitForInputSessionAt(frame.offsetWidth / 2, frame.offsetHeight - 5);
 43 await UIHelper.ensurePresentationUpdate();
 44 const rect = await UIHelper.inputViewBounds();
 45 keyboardHeight = rect.height;
 46 checkScrollTop();
 47 testRunner.notifyDone();
 48}
 49
 50if (window.testRunner)
 51 runTest();
 52else
 53 frame.contentWindow.container.addEventListener('focus', () => setTimeout(checkScrollTop, 500));
 54
 55</script>
 56</body>
 57</html>