Title: [290646] trunk
Revision
290646
Author
[email protected]
Date
2022-03-01 07:16:09 -0800 (Tue, 01 Mar 2022)

Log Message

focus({preventScroll: true}) does not prevent scrolling on iOS
https://bugs.webkit.org/show_bug.cgi?id=236584
rdar://88911184

Reviewed by Simon Fraser.

Source/WebCore:

Plumb `FocusOptions` through `Element::dispatchFocusEvent()` as well as the chrome client hooks for
`elementDidRefocus` and `elementDidFocus`, instead of just a `FocusDirection` flag.

* dom/Document.cpp:
(WebCore::Document::setFocusedElement):
* dom/Element.cpp:
(WebCore::Element::focus):
(WebCore::Element::dispatchFocusEvent):
* dom/Element.h:
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::dispatchFocusEvent):
* html/HTMLSelectElement.h:
* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::dispatchFocusEvent):
* html/HTMLTextFormControlElement.h:
* loader/EmptyClients.h:
* page/ChromeClient.h:
(WebCore::ChromeClient::elementDidFocus):
(WebCore::ChromeClient::elementDidRefocus):
* page/FocusController.cpp:
(WebCore::dispatchEventsOnWindowAndFocusedElement):
(WebCore::FocusController::setFocusedElement):

Source/WebKit:

Add support for `preventScroll` on iOS by avoiding UI-side zooming/scrolling to reveal the focused element if it
was focused with `preventScroll: true`. See below for more details.

Tests: fast/forms/select-focus-prevent-scroll.html
       fast/forms/text-field-focus-prevent-scroll.html

* Shared/FocusedElementInformation.cpp:
(WebKit::FocusedElementInformation::encode const):
(WebKit::FocusedElementInformation::decode):
* Shared/FocusedElementInformation.h:

Add a boolean flag to `FocusedElementInformation` to indicate whether or not scrolling to reveal the focused
element should be prevented.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _zoomToRevealFocusedElement]):

Only zoom to reveal the focused element if the focused element information's `preventScroll` flag is `NO`.

(-[WKContentView _elementDidBlur]):
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::elementDidFocus):
(WebKit::WebChromeClient::elementDidRefocus):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::elementDidRefocus):
(WebKit::WebPage::elementDidFocus):

Use `FocusOptions` to set the `preventScroll` flag when propagating `FocusedElementInformation`.

* WebProcess/WebPage/WebPage.h:

Source/WebKitLegacy/ios:

Adjust the method signature of elementDidFocus. See WebCore ChangeLog for more information.

* WebCoreSupport/WebChromeClientIOS.h:
* WebCoreSupport/WebChromeClientIOS.mm:
(WebChromeClientIOS::elementDidFocus):

Source/WebKitLegacy/mac:

Adjust the method signature of elementDidFocus. See WebCore ChangeLog for more information.

* WebCoreSupport/WebChromeClient.h:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::elementDidFocus):

LayoutTests:

Add a couple of new layout tests to verify that passing in `{ preventScroll: true }` for focus options causes
us to avoid scrolling to reveal focused select elements and text fields.

* fast/forms/select-focus-prevent-scroll-expected.txt: Added.
* fast/forms/select-focus-prevent-scroll.html: Added.
* fast/forms/text-field-focus-prevent-scroll-expected.txt: Added.
* fast/forms/text-field-focus-prevent-scroll.html: Added.
* resources/ui-helper.js:

Also make it safe to call `waitForInputSessionToDismiss()` in a platform-agnostic test, by bailing early if
we're not on iOS, using WebKit2.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (290645 => 290646)


--- trunk/LayoutTests/ChangeLog	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/LayoutTests/ChangeLog	2022-03-01 15:16:09 UTC (rev 290646)
@@ -1,3 +1,23 @@
+2022-03-01  Wenson Hsieh  <[email protected]>
+
+        focus({preventScroll: true}) does not prevent scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=236584
+        rdar://88911184
+
+        Reviewed by Simon Fraser.
+
+        Add a couple of new layout tests to verify that passing in `{ preventScroll: true }` for focus options causes
+        us to avoid scrolling to reveal focused select elements and text fields.
+
+        * fast/forms/select-focus-prevent-scroll-expected.txt: Added.
+        * fast/forms/select-focus-prevent-scroll.html: Added.
+        * fast/forms/text-field-focus-prevent-scroll-expected.txt: Added.
+        * fast/forms/text-field-focus-prevent-scroll.html: Added.
+        * resources/ui-helper.js:
+
+        Also make it safe to call `waitForInputSessionToDismiss()` in a platform-agnostic test, by bailing early if
+        we're not on iOS, using WebKit2.
+
 2022-03-01  Alan Bujtas  <[email protected]>
 
         REGRESSION (r273129): Text contents in <span> with opacity not repainting/updating when sibling element has "will-change: transform"

Added: trunk/LayoutTests/fast/forms/select-focus-prevent-scroll-expected.txt (0 => 290646)


--- trunk/LayoutTests/fast/forms/select-focus-prevent-scroll-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/select-focus-prevent-scroll-expected.txt	2022-03-01 15:16:09 UTC (rev 290646)
@@ -0,0 +1,12 @@
+Verifies that programmatically focusing a select element with preventScroll: true does not cause the page to scroll. To run the test manually, tap or click the button and check that the page does not scroll to the bottom.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.activeElement is select
+PASS pageYOffset is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Focus select
+

Added: trunk/LayoutTests/fast/forms/select-focus-prevent-scroll.html (0 => 290646)


--- trunk/LayoutTests/fast/forms/select-focus-prevent-scroll.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/select-focus-prevent-scroll.html	2022-03-01 15:16:09 UTC (rev 290646)
@@ -0,0 +1,53 @@
+<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src=""
+<script src=""
+<style>
+button {
+    margin-bottom: 8000px;
+}
+</style>
+</head>
+<body>
+    <div><button id="focus">Focus <code>select</code></button></div>
+    <select name="select">
+        <option value="1">First</option>
+        <option value="2">Second</option>
+    </select>
+</body>
+<script>
+jsTestIsAsync = true;
+description("Verifies that programmatically focusing a select element with <code>preventScroll: true</code> does not cause the page to scroll. To run the test manually, tap or click the button and check that the page does not scroll to the bottom.");
+
+let focusButton = document.getElementById("focus");
+select = document.querySelector("select");
+
+focusButton.addEventListener("click", event => {
+    event.preventDefault();
+    select.focus({ preventScroll: true });
+    if (!window.testRunner) {
+        checkScrollOffsetAndFocusedElement();
+        finishJSTest();
+    }
+});
+
+function checkScrollOffsetAndFocusedElement() {
+    shouldBe("document.activeElement", "select");
+    shouldBe("pageYOffset", "0");
+}
+
+addEventListener("load", async () => {
+    if (!window.testRunner)
+        return;
+
+    await UIHelper.activateElementAndWaitForInputSession(focusButton);
+    shouldBe("document.activeElement", "select");
+    shouldBe("pageYOffset", "0");
+    document.activeElement.blur();
+    await UIHelper.waitForInputSessionToDismiss();
+    finishJSTest();
+});
+</script>
+</html>

Added: trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll-expected.txt (0 => 290646)


--- trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll-expected.txt	2022-03-01 15:16:09 UTC (rev 290646)
@@ -0,0 +1,12 @@
+Verifies that programmatically focusing an input element with preventScroll: true does not cause the page to scroll. To run the test manually, tap or click the button and check that the page does not scroll to the bottom.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.activeElement is input
+PASS pageYOffset is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Focus input
+

Added: trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll.html (0 => 290646)


--- trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/text-field-focus-prevent-scroll.html	2022-03-01 15:16:09 UTC (rev 290646)
@@ -0,0 +1,49 @@
+<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src=""
+<script src=""
+<style>
+button {
+    margin-bottom: 8000px;
+}
+</style>
+</head>
+<body>
+    <div><button id="focus">Focus <code>input</code></button></div>
+    <input placeholder="Text field">
+</body>
+<script>
+jsTestIsAsync = true;
+description("Verifies that programmatically focusing an input element with <code>preventScroll: true</code> does not cause the page to scroll. To run the test manually, tap or click the button and check that the page does not scroll to the bottom.");
+
+let focusButton = document.getElementById("focus");
+input = document.querySelector("input");
+
+focusButton.addEventListener("click", event => {
+    event.preventDefault();
+    input.focus({ preventScroll: true });
+    if (!window.testRunner) {
+        checkScrollOffsetAndFocusedElement();
+        finishJSTest();
+    }
+});
+
+function checkScrollOffsetAndFocusedElement() {
+    shouldBe("document.activeElement", "input");
+    shouldBe("pageYOffset", "0");
+}
+
+addEventListener("load", async () => {
+    if (!window.testRunner)
+        return;
+
+    await UIHelper.activateElementAndWaitForInputSession(focusButton);
+    checkScrollOffsetAndFocusedElement();
+    document.activeElement.blur();
+    await UIHelper.waitForInputSessionToDismiss();
+    finishJSTest();
+});
+</script>
+</html>

Modified: trunk/LayoutTests/resources/ui-helper.js (290645 => 290646)


--- trunk/LayoutTests/resources/ui-helper.js	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/LayoutTests/resources/ui-helper.js	2022-03-01 15:16:09 UTC (rev 290646)
@@ -591,6 +591,9 @@
 
     static waitForInputSessionToDismiss()
     {
+        if (!this.isWebKit2() || !this.isIOSFamily())
+            return Promise.resolve();
+
         return new Promise(resolve => {
             testRunner.runUIScript(`
                 (function() {

Modified: trunk/Source/WebCore/ChangeLog (290645 => 290646)


--- trunk/Source/WebCore/ChangeLog	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/ChangeLog	2022-03-01 15:16:09 UTC (rev 290646)
@@ -1,3 +1,34 @@
+2022-03-01  Wenson Hsieh  <[email protected]>
+
+        focus({preventScroll: true}) does not prevent scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=236584
+        rdar://88911184
+
+        Reviewed by Simon Fraser.
+
+        Plumb `FocusOptions` through `Element::dispatchFocusEvent()` as well as the chrome client hooks for
+        `elementDidRefocus` and `elementDidFocus`, instead of just a `FocusDirection` flag.
+
+        * dom/Document.cpp:
+        (WebCore::Document::setFocusedElement):
+        * dom/Element.cpp:
+        (WebCore::Element::focus):
+        (WebCore::Element::dispatchFocusEvent):
+        * dom/Element.h:
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::dispatchFocusEvent):
+        * html/HTMLSelectElement.h:
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::dispatchFocusEvent):
+        * html/HTMLTextFormControlElement.h:
+        * loader/EmptyClients.h:
+        * page/ChromeClient.h:
+        (WebCore::ChromeClient::elementDidFocus):
+        (WebCore::ChromeClient::elementDidRefocus):
+        * page/FocusController.cpp:
+        (WebCore::dispatchEventsOnWindowAndFocusedElement):
+        (WebCore::FocusController::setFocusedElement):
+
 2022-03-01  Alan Bujtas  <[email protected]>
 
         REGRESSION (r273129): Text contents in <span> with opacity not repainting/updating when sibling element has "will-change: transform"

Modified: trunk/Source/WebCore/dom/Document.cpp (290645 => 290646)


--- trunk/Source/WebCore/dom/Document.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/dom/Document.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -4713,7 +4713,7 @@
         }
 
         // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
-        m_focusedElement->dispatchFocusEvent(oldFocusedElement.copyRef(), options.direction);
+        m_focusedElement->dispatchFocusEvent(oldFocusedElement.copyRef(), options);
 
         if (m_focusedElement != newFocusedElement) {
             // handler shifted focus

Modified: trunk/Source/WebCore/dom/Element.cpp (290645 => 290646)


--- trunk/Source/WebCore/dom/Element.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/dom/Element.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -3073,7 +3073,7 @@
     Ref document { this->document() };
     if (document->focusedElement() == this) {
         if (document->page())
-            document->page()->chrome().client().elementDidRefocus(*this);
+            document->page()->chrome().client().elementDidRefocus(*this, options);
         return;
     }
 
@@ -3091,7 +3091,7 @@
         RefPtr currentlyFocusedElement = document->focusedElement();
         if (root->containsIncludingShadowDOM(currentlyFocusedElement.get())) {
             if (document->page())
-                document->page()->chrome().client().elementDidRefocus(*currentlyFocusedElement);
+                document->page()->chrome().client().elementDidRefocus(*currentlyFocusedElement, options);
             return;
         }
 
@@ -3208,10 +3208,10 @@
     dispatchScopedEvent(FocusEvent::create(eventNames().focusoutEvent, Event::CanBubble::Yes, Event::IsCancelable::No, document().windowProxy(), 0, WTFMove(newFocusedElement)));
 }
 
-void Element::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection)
+void Element::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions& options)
 {
     if (auto* page = document().page())
-        page->chrome().client().elementDidFocus(*this);
+        page->chrome().client().elementDidFocus(*this, options);
     dispatchEvent(FocusEvent::create(eventNames().focusEvent, Event::CanBubble::No, Event::IsCancelable::No, document().windowProxy(), 0, WTFMove(oldFocusedElement)));
 }
 

Modified: trunk/Source/WebCore/dom/Element.h (290645 => 290646)


--- trunk/Source/WebCore/dom/Element.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/dom/Element.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -574,7 +574,7 @@
     // FIXME: Consider changing signature to accept Element* because all callers perform copyRef().
     void dispatchFocusInEventIfNeeded(RefPtr<Element>&& oldFocusedElement);
     void dispatchFocusOutEventIfNeeded(RefPtr<Element>&& newFocusedElement);
-    virtual void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection);
+    virtual void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions&);
     virtual void dispatchBlurEvent(RefPtr<Element>&& newFocusedElement);
     void dispatchWebKitImageReadyEventForTesting();
 

Modified: trunk/Source/WebCore/html/HTMLSelectElement.cpp (290645 => 290646)


--- trunk/Source/WebCore/html/HTMLSelectElement.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/html/HTMLSelectElement.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -949,13 +949,13 @@
     return optionIndex;
 }
 
-void HTMLSelectElement::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection direction)
+void HTMLSelectElement::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions& options)
 {
     // Save the selection so it can be compared to the new selection when
     // dispatching change events during blur event dispatch.
     if (usesMenuList())
         saveLastSelection();
-    HTMLFormControlElementWithState::dispatchFocusEvent(WTFMove(oldFocusedElement), direction);
+    HTMLFormControlElementWithState::dispatchFocusEvent(WTFMove(oldFocusedElement), options);
 }
 
 void HTMLSelectElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)

Modified: trunk/Source/WebCore/html/HTMLSelectElement.h (290645 => 290646)


--- trunk/Source/WebCore/html/HTMLSelectElement.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/html/HTMLSelectElement.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -119,7 +119,7 @@
     bool isKeyboardFocusable(KeyboardEvent*) const final;
     bool isMouseFocusable() const final;
 
-    void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection) final;
+    void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions&) final;
     void dispatchBlurEvent(RefPtr<Element>&& newFocusedElement) final;
     
     bool canStartSelection() const final { return false; }

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp (290645 => 290646)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -125,12 +125,12 @@
     updatePlaceholderVisibility();
 }
 
-void HTMLTextFormControlElement::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection direction)
+void HTMLTextFormControlElement::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions& options)
 {
     if (supportsPlaceholder())
         updatePlaceholderVisibility();
-    handleFocusEvent(oldFocusedElement.get(), direction);
-    HTMLFormControlElementWithState::dispatchFocusEvent(WTFMove(oldFocusedElement), direction);
+    handleFocusEvent(oldFocusedElement.get(), options.direction);
+    HTMLFormControlElementWithState::dispatchFocusEvent(WTFMove(oldFocusedElement), options);
 }
 
 void HTMLTextFormControlElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.h (290645 => 290646)


--- trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -145,7 +145,7 @@
     int computeSelectionEnd() const;
     TextFieldSelectionDirection computeSelectionDirection() const;
 
-    void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection) final;
+    void dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, const FocusOptions&) final;
     void dispatchBlurEvent(RefPtr<Element>&& newFocusedElement) final;
     bool childShouldCreateRenderer(const Node&) const override;
     

Modified: trunk/Source/WebCore/loader/EmptyClients.h (290645 => 290646)


--- trunk/Source/WebCore/loader/EmptyClients.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/loader/EmptyClients.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -157,7 +157,7 @@
     void showShareSheet(ShareDataWithParsedURL&, CompletionHandler<void(bool)>&&) final;
     void loadIconForFiles(const Vector<String>&, FileIconLoader&) final { }
 
-    void elementDidFocus(Element&) final { }
+    void elementDidFocus(Element&, const FocusOptions&) final { }
     void elementDidBlur(Element&) final { }
 
     void setCursor(const Cursor&) final { }

Modified: trunk/Source/WebCore/page/ChromeClient.h (290645 => 290646)


--- trunk/Source/WebCore/page/ChromeClient.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/page/ChromeClient.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -135,6 +135,7 @@
 struct ContentRuleListResults;
 struct DataDetectorElementInfo;
 struct DateTimeChooserParameters;
+struct FocusOptions;
 struct GraphicsDeviceAdapter;
 struct MockWebAuthenticationConfiguration;
 struct SecurityOriginData;
@@ -346,9 +347,9 @@
     // Asynchronous request to load an icon for specified filenames.
     virtual void loadIconForFiles(const Vector<String>&, FileIconLoader&) = 0;
         
-    virtual void elementDidFocus(Element&) { }
+    virtual void elementDidFocus(Element&, const FocusOptions&) { }
     virtual void elementDidBlur(Element&) { }
-    virtual void elementDidRefocus(Element&) { }
+    virtual void elementDidRefocus(Element&, const FocusOptions&) { }
 
     virtual void focusedElementDidChangeInputMode(Element&, InputMode) { }
 

Modified: trunk/Source/WebCore/page/FocusController.cpp (290645 => 290646)


--- trunk/Source/WebCore/page/FocusController.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebCore/page/FocusController.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -310,7 +310,7 @@
         document->focusedElement()->dispatchBlurEvent(nullptr);
     document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, Event::CanBubble::No, Event::IsCancelable::No));
     if (focused && document->focusedElement())
-        document->focusedElement()->dispatchFocusEvent(nullptr, FocusDirection::None);
+        document->focusedElement()->dispatchFocusEvent(nullptr, { });
 }
 
 static inline bool isFocusableElementOrScopeOwner(Element& element, KeyboardEvent* event)
@@ -837,7 +837,7 @@
     Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : nullptr;
     if (oldFocusedElement == element) {
         if (element)
-            m_page.chrome().client().elementDidRefocus(*element);
+            m_page.chrome().client().elementDidRefocus(*element, options);
         return true;
     }
 

Modified: trunk/Source/WebKit/ChangeLog (290645 => 290646)


--- trunk/Source/WebKit/ChangeLog	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/ChangeLog	2022-03-01 15:16:09 UTC (rev 290646)
@@ -1,3 +1,43 @@
+2022-03-01  Wenson Hsieh  <[email protected]>
+
+        focus({preventScroll: true}) does not prevent scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=236584
+        rdar://88911184
+
+        Reviewed by Simon Fraser.
+
+        Add support for `preventScroll` on iOS by avoiding UI-side zooming/scrolling to reveal the focused element if it
+        was focused with `preventScroll: true`. See below for more details.
+
+        Tests: fast/forms/select-focus-prevent-scroll.html
+               fast/forms/text-field-focus-prevent-scroll.html
+
+        * Shared/FocusedElementInformation.cpp:
+        (WebKit::FocusedElementInformation::encode const):
+        (WebKit::FocusedElementInformation::decode):
+        * Shared/FocusedElementInformation.h:
+
+        Add a boolean flag to `FocusedElementInformation` to indicate whether or not scrolling to reveal the focused
+        element should be prevented.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _zoomToRevealFocusedElement]):
+
+        Only zoom to reveal the focused element if the focused element information's `preventScroll` flag is `NO`.
+
+        (-[WKContentView _elementDidBlur]):
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::elementDidFocus):
+        (WebKit::WebChromeClient::elementDidRefocus):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::elementDidRefocus):
+        (WebKit::WebPage::elementDidFocus):
+
+        Use `FocusOptions` to set the `preventScroll` flag when propagating `FocusedElementInformation`.
+
+        * WebProcess/WebPage/WebPage.h:
+
 2022-03-01  Kimmo Kinnunen  <[email protected]>
 
         WebGL GPUP OpenGL context is not used even if WebGL via Metal is deselected

Modified: trunk/Source/WebKit/Shared/FocusedElementInformation.cpp (290645 => 290646)


--- trunk/Source/WebKit/Shared/FocusedElementInformation.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/Shared/FocusedElementInformation.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -114,6 +114,7 @@
     encoder << shouldAvoidScrollingWhenFocusedContentIsVisible;
     encoder << shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation;
     encoder << isFocusingWithValidationMessage;
+    encoder << preventScroll;
 }
 
 bool FocusedElementInformation::decode(IPC::Decoder& decoder, FocusedElementInformation& result)
@@ -262,6 +263,9 @@
     if (!decoder.decode(result.isFocusingWithValidationMessage))
         return false;
 
+    if (!decoder.decode(result.preventScroll))
+        return false;
+
     return true;
 }
 #endif

Modified: trunk/Source/WebKit/Shared/FocusedElementInformation.h (290645 => 290646)


--- trunk/Source/WebKit/Shared/FocusedElementInformation.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/Shared/FocusedElementInformation.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -138,6 +138,7 @@
     bool shouldAvoidScrollingWhenFocusedContentIsVisible { false };
     bool shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation { false };
     bool isFocusingWithValidationMessage { false };
+    bool preventScroll { false };
 
     FocusedElementInformationIdentifier identifier;
     WebCore::ScrollingNodeID containerScrollingNodeID { 0 };

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (290645 => 290646)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-03-01 15:16:09 UTC (rev 290646)
@@ -2389,6 +2389,9 @@
 
 - (void)_zoomToRevealFocusedElement
 {
+    if (_focusedElementInformation.preventScroll)
+        return;
+
     if (_suppressSelectionAssistantReasons || _activeTextInteractionCount)
         return;
 
@@ -6827,6 +6830,7 @@
     _focusedElementInformation.shouldAvoidScrollingWhenFocusedContentIsVisible = false;
     _focusedElementInformation.shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation = false;
     _focusedElementInformation.isFocusingWithValidationMessage = false;
+    _focusedElementInformation.preventScroll = false;
     _inputPeripheral = nil;
     _focusRequiresStrongPasswordAssistance = NO;
     _autocorrectionContextNeedsUpdate = YES;

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (290645 => 290646)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -214,14 +214,14 @@
 
 #if PLATFORM(COCOA)
 
-void WebChromeClient::elementDidFocus(Element& element)
+void WebChromeClient::elementDidFocus(Element& element, const FocusOptions& options)
 {
-    m_page.elementDidFocus(element);
+    m_page.elementDidFocus(element, options);
 }
 
-void WebChromeClient::elementDidRefocus(Element& element)
+void WebChromeClient::elementDidRefocus(Element& element, const FocusOptions& options)
 {
-    m_page.elementDidRefocus(element);
+    m_page.elementDidRefocus(element, options);
 }
 
 void WebChromeClient::elementDidBlur(Element& element)

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (290645 => 290646)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -306,9 +306,9 @@
 #endif
 
 #if PLATFORM(COCOA)
-    void elementDidFocus(WebCore::Element&) final;
+    void elementDidFocus(WebCore::Element&, const WebCore::FocusOptions&) final;
     void elementDidBlur(WebCore::Element&) final;
-    void elementDidRefocus(WebCore::Element&) final;
+    void elementDidRefocus(WebCore::Element&, const WebCore::FocusOptions&) final;
     void focusedElementDidChangeInputMode(WebCore::Element&, WebCore::InputMode) final;
 
     void makeFirstResponder() final;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (290645 => 290646)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2022-03-01 15:16:09 UTC (rev 290646)
@@ -6151,9 +6151,9 @@
     }
 }
 
-void WebPage::elementDidRefocus(WebCore::Element& element)
+void WebPage::elementDidRefocus(Element& element, const FocusOptions& options)
 {
-    elementDidFocus(element);
+    elementDidFocus(element, options);
 
     if (m_userIsInteracting)
         scheduleFullEditorStateUpdate();
@@ -6176,7 +6176,7 @@
     return is<HTMLTextFormControlElement>(element) || element.hasEditableStyle();
 }
 
-void WebPage::elementDidFocus(WebCore::Element& element)
+void WebPage::elementDidFocus(Element& element, const FocusOptions& options)
 {
     if (!shouldDispatchUpdateAfterFocusingElement(element)) {
         updateInputContextAfterBlurringAndRefocusingElementIfNeeded(element);
@@ -6204,6 +6204,7 @@
 
         m_formClient->willBeginInputSession(this, &element, WebFrame::fromCoreFrame(*element.document().frame()), m_userIsInteracting, userData);
 
+        information->preventScroll = options.preventScroll;
         send(Messages::WebPageProxy::ElementDidFocus(information.value(), m_userIsInteracting, m_recentlyBlurredElement, m_lastActivityStateChanges, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
 #elif PLATFORM(MAC)
         // FIXME: This can be unified with the iOS code above by bringing ElementDidFocus to macOS.

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (290645 => 290646)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -734,8 +734,8 @@
     MediaKeySystemPermissionRequestManager& mediaKeySystemPermissionRequestManager() { return m_mediaKeySystemPermissionRequestManager; }
 #endif
 
-    void elementDidFocus(WebCore::Element&);
-    void elementDidRefocus(WebCore::Element&);
+    void elementDidFocus(WebCore::Element&, const WebCore::FocusOptions&);
+    void elementDidRefocus(WebCore::Element&, const WebCore::FocusOptions&);
     void elementDidBlur(WebCore::Element&);
     void focusedElementDidChangeInputMode(WebCore::Element&, WebCore::InputMode);
     void resetFocusedElementForFrame(WebFrame*);

Modified: trunk/Source/WebKitLegacy/ios/ChangeLog (290645 => 290646)


--- trunk/Source/WebKitLegacy/ios/ChangeLog	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/ios/ChangeLog	2022-03-01 15:16:09 UTC (rev 290646)
@@ -1,3 +1,17 @@
+2022-03-01  Wenson Hsieh  <[email protected]>
+
+        focus({preventScroll: true}) does not prevent scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=236584
+        rdar://88911184
+
+        Reviewed by Simon Fraser.
+
+        Adjust the method signature of elementDidFocus. See WebCore ChangeLog for more information.
+
+        * WebCoreSupport/WebChromeClientIOS.h:
+        * WebCoreSupport/WebChromeClientIOS.mm:
+        (WebChromeClientIOS::elementDidFocus):
+
 2021-10-22  Ian Anderson  <[email protected]>
 
         Add a module map file for PrivateFrameworks/WebKitLegacy

Modified: trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.h (290645 => 290646)


--- trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -79,7 +79,7 @@
     void suppressFormNotifications() final;
     void restoreFormNotifications() final;
 
-    void elementDidFocus(WebCore::Element&) final;
+    void elementDidFocus(WebCore::Element&, const WebCore::FocusOptions&) final;
     void elementDidBlur(WebCore::Element&) final;
 
     void attachRootGraphicsLayer(WebCore::Frame&, WebCore::GraphicsLayer*) final;

Modified: trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.mm (290645 => 290646)


--- trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.mm	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/ios/WebCoreSupport/WebChromeClientIOS.mm	2022-03-01 15:16:09 UTC (rev 290646)
@@ -273,7 +273,7 @@
         m_formNotificationSuppressions = 0;
 }
 
-void WebChromeClientIOS::elementDidFocus(WebCore::Element& element)
+void WebChromeClientIOS::elementDidFocus(WebCore::Element& element, const WebCore::FocusOptions&)
 {
     if (m_formNotificationSuppressions <= 0)
         [[webView() _UIKitDelegateForwarder] webView:webView() elementDidFocusNode:kit(&element)];

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (290645 => 290646)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2022-03-01 15:16:09 UTC (rev 290646)
@@ -1,3 +1,17 @@
+2022-03-01  Wenson Hsieh  <[email protected]>
+
+        focus({preventScroll: true}) does not prevent scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=236584
+        rdar://88911184
+
+        Reviewed by Simon Fraser.
+
+        Adjust the method signature of elementDidFocus. See WebCore ChangeLog for more information.
+
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::elementDidFocus):
+
 2022-02-27  Wenson Hsieh  <[email protected]>
 
         Invoking "Markup Image" should preserve the existing selection range

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h (290645 => 290646)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2022-03-01 15:16:09 UTC (rev 290646)
@@ -176,7 +176,7 @@
     void disableSuddenTermination() final;
 
 #if !PLATFORM(IOS_FAMILY)
-    void elementDidFocus(WebCore::Element&) override;
+    void elementDidFocus(WebCore::Element&, const WebCore::FocusOptions&) override;
     void elementDidBlur(WebCore::Element&) override;
 #endif
 

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm (290645 => 290646)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2022-03-01 15:09:55 UTC (rev 290645)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2022-03-01 15:16:09 UTC (rev 290646)
@@ -849,7 +849,7 @@
 }
 
 #if !PLATFORM(IOS_FAMILY)
-void WebChromeClient::elementDidFocus(WebCore::Element& element)
+void WebChromeClient::elementDidFocus(WebCore::Element& element, const WebCore::FocusOptions&)
 {
     CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(&element));
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to