Diff
Modified: trunk/LayoutTests/ChangeLog (287809 => 287810)
--- trunk/LayoutTests/ChangeLog 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/LayoutTests/ChangeLog 2022-01-08 16:40:34 UTC (rev 287810)
@@ -1,3 +1,23 @@
+2022-01-08 Tyler Wilcock <[email protected]>
+
+ AX: AccessibilityObject::setFocused(true) should make the webpage focused, and make web content the first responder
+ https://bugs.webkit.org/show_bug.cgi?id=234885
+
+ Reviewed by Darin Adler.
+
+ Add tests verifying that focusing an element via an AX client:
+
+ 1. Makes the page focused immediately
+ 2. Makes web content the first responder
+
+ This allows a focus ring to be drawn, even when apps that embed
+ WKWebViews don't make web content the first responder themselves.
+
+ * accessibility/ios-simulator/accessibility-make-first-responder-expected.txt: Added.
+ * accessibility/ios-simulator/accessibility-make-first-responder.html: Added.
+ * accessibility/ios-simulator/taking-focus-should-refocus-page-expected.txt: Added.
+ * accessibility/ios-simulator/taking-focus-should-refocus-page.html: Added.
+
2022-01-07 Myles C. Maxfield <[email protected]>
[GPU Process] Can't getImageData on canvas larger than 4096x4096
Added: trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder-expected.txt (0 => 287810)
--- trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder-expected.txt 2022-01-08 16:40:34 UTC (rev 287810)
@@ -0,0 +1,14 @@
+Test that assistiveTechnologyMakeFirstResponder works correctly on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS isWebContentFirstResponder is true
+Resigning web content first respondership
+PASS isWebContentFirstResponder is false
+Performing accessibility object focus
+PASS isWebContentFirstResponder is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder.html (0 => 287810)
--- trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder.html (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/accessibility-make-first-responder.html 2022-01-08 16:40:34 UTC (rev 287810)
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+ description("Test that assistiveTechnologyMakeFirstResponder works correctly on iOS.");
+ window.jsTestIsAsync = true;
+
+ function performTest() {
+ if (window.testRunner) {
+ setTimeout(async function() {
+ await verifyWebContentIsFirstResponder(true);
+ debug("Resigning web content first respondership");
+ await resignWebContentFirstResponder();
+ await verifyWebContentIsFirstResponder(false);
+
+ var inputObj = accessibilityController.accessibleElementById("input");
+ inputObj.takeFocus();
+ debug("Performing accessibility object focus");
+
+ await verifyWebContentIsFirstResponder(true);
+ finishJSTest();
+ }, 0);
+ }
+ }
+
+ var isWebContentFirstResponder;
+ async function verifyWebContentIsFirstResponder(expectFirstRespondership)
+ {
+ // Set the global var to the opposite of what we expect and allow the UI script to give us the expected value.
+ isWebContentFirstResponder = !expectFirstRespondership;
+
+ // Because taking and resigning first respondership requires async IPC between the web and UI processes, we
+ // must also asynchronously wait to get our expected value.
+ await waitFor(() => {
+ setTimeout(async () => {
+ isWebContentFirstResponder = await (new Promise(resolve => {
+ testRunner.runUIScript(`uiController.isWebContentFirstResponder`, result => resolve(result === "true"));
+ }));
+ }, 0)
+ return isWebContentFirstResponder == expectFirstRespondership;
+ });
+ shouldBe("isWebContentFirstResponder", `${expectFirstRespondership}`);
+ }
+
+ async function resignWebContentFirstResponder()
+ {
+ await (new Promise(resolve => {
+ testRunner.runUIScript(`uiController.resignFirstResponder()`, resolve);
+ }));
+ }
+
+ window.addEventListener('load', performTest, false);
+ </script>
+</head>
+<body>
+ <input id="input" type="text">
+</body>
+</html>
Added: trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page-expected.txt (0 => 287810)
--- trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page-expected.txt 2022-01-08 16:40:34 UTC (rev 287810)
@@ -0,0 +1,25 @@
+This test ensures that making an element focused via accessibility (e.g. full keyboard access) re-focuses the page so that a focus ring can be drawn.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(button).getPropertyValue('outline-width') is '0px'
+PASS getComputedStyle(textInput).getPropertyValue('outline-width') is '0px'
+
+Taking focus via accessibilityController for id #button
+PASS getComputedStyle(button).getPropertyValue('outline-width') is '3px'
+PASS getComputedStyle(textInput).getPropertyValue('outline-width') is '0px'
+
+Taking focus via accessibilityController for id #text-input
+PASS getComputedStyle(button).getPropertyValue('outline-width') is '0px'
+PASS getComputedStyle(textInput).getPropertyValue('outline-width') is '3px'
+
+Making the entire page un-focused
+
+Taking focus via accessibilityController for id #button
+PASS getComputedStyle(button).getPropertyValue('outline-width') is '3px'
+PASS getComputedStyle(textInput).getPropertyValue('outline-width') is '0px'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Click me
Added: trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page.html (0 => 287810)
--- trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page.html (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/taking-focus-should-refocus-page.html 2022-01-08 16:40:34 UTC (rev 287810)
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<button id="button">Click me</button>
+<input type="text" id="text-input">
+
+<script>
+ description("This test ensures that making an element focused via accessibility (e.g. full keyboard access) re-focuses the page so that a focus ring can be drawn.");
+
+ function takeFocus(id) {
+ debug(`\nTaking focus via accessibilityController for id #${id}`);
+ accessibilityController.accessibleElementById(id).takeFocus();
+ }
+
+ if (window.accessibilityController) {
+ var button = document.getElementById("button");
+ var textInput = document.getElementById("text-input");
+ shouldBe("getComputedStyle(button).getPropertyValue('outline-width')", "'0px'");
+ shouldBe("getComputedStyle(textInput).getPropertyValue('outline-width')", "'0px'");
+
+ takeFocus("button");
+ // Expect focus ring to have been drawn for the button.
+ shouldBe("getComputedStyle(button).getPropertyValue('outline-width')", "'3px'");
+ shouldBe("getComputedStyle(textInput).getPropertyValue('outline-width')", "'0px'");
+
+ takeFocus("text-input");
+ shouldBe("getComputedStyle(button).getPropertyValue('outline-width')", "'0px'");
+ shouldBe("getComputedStyle(textInput).getPropertyValue('outline-width')", "'3px'");
+
+ debug("\nMaking the entire page un-focused");
+ // This simulates situations in which WebKit is embedded in another app and focus is not properly handed
+ // over to WebKit when necessary, i.e. a full-keyboard access user tabbing into the embedded web view.
+ if (window.internals)
+ internals.setPageIsFocused(false);
+ else
+ debug("FAIL: window.internals not available")
+
+ takeFocus("button");
+ // Focusing the button via accessibility should re-focus the page and allow a focus ring to be drawn.
+ // This simulates conditions where embedded WKWebView's are not ever marked as focused via their hosting
+ // app, e.g. via [WKContentViewInteraction becomeFirstResponderForWebView].
+ shouldBe("getComputedStyle(button).getPropertyValue('outline-width')", "'3px'");
+ shouldBe("getComputedStyle(textInput).getPropertyValue('outline-width')", "'0px'");
+ }
+</script>
+</body>
+</html>
+
Modified: trunk/Source/WebCore/ChangeLog (287809 => 287810)
--- trunk/Source/WebCore/ChangeLog 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebCore/ChangeLog 2022-01-08 16:40:34 UTC (rev 287810)
@@ -1,3 +1,32 @@
+2022-01-08 Tyler Wilcock <[email protected]>
+
+ AX: AccessibilityObject::setFocused(true) should make the webpage focused, and make web content the first responder
+ https://bugs.webkit.org/show_bug.cgi?id=234885
+
+ Reviewed by Darin Adler.
+
+ With this patch, focusing an element via an AX client on iOS makes
+ the page focused immediately. This allows a focus ring to be drawn,
+ even when apps that embed WKWebViews don't make web content the
+ first responder themselves (`[WKContentViewInteraction becomeFirstResponderForWebView]`
+ makes the page focused after a delay due to async IPC between the UI and web processes).
+
+ Tests: accessibility/ios-simulator/accessibility-make-first-responder.html
+ accessibility/ios-simulator/taking-focus-should-refocus-page.html
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::setFocused):
+ Make the webpage focused if it isn't already focused.
+
+ * testing/Internals.cpp:
+ (WebCore::Internals::setPageIsFocused):
+ Added to simulate the scenario where the webpage doesn't gain focus
+ through becoming first responder.
+ * testing/Internals.h:
+ Add setPageIsFocused.
+ * testing/Internals.idl:
+ Add setPageIsFocused.
+
2022-01-08 Alan Bujtas <[email protected]>
[LFC][IFC] Implement TextUtil::breakWord for the complex font codepath using ubrk_next
Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (287809 => 287810)
--- trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.cpp 2022-01-08 16:40:34 UTC (rev 287810)
@@ -2771,21 +2771,35 @@
{
if (focus) {
// Ensure that the view is focused and active, otherwise, any attempt to set focus to an object inside it will fail.
- auto* document = this->document();
- if (!document)
- return;
-
- auto* frame = document->frame();
+ auto* frame = document() ? document()->frame() : nullptr;
if (frame && frame->selection().isFocusedAndActive())
return; // Nothing to do, already focused and active.
- auto* page = document->page();
+ auto* page = document() ? document()->page() : nullptr;
if (!page)
return;
- ChromeClient& chromeClient = page->chrome().client();
- chromeClient.focus();
+ page->chrome().client().focus();
+ // Reset the page pointer in case ChromeClient::focus() caused a side effect that invalidated our old one.
+ page = document() ? document()->page() : nullptr;
+ if (!page)
+ return;
+#if PLATFORM(IOS_FAMILY)
+ // Mark the page as focused so the focus ring can be drawn immediately. The page is also marked
+ // as focused as part assistiveTechnologyMakeFirstResponder, but that requires some back-and-forth
+ // IPC between the web and UI processes, during which we can miss the drawing of the focus ring for the
+ // first focused element. Making the page focused is a requirement for making the page selection focused.
+ // This is iOS only until there's a demonstrated need for this preemptive focus on other platforms.
+ if (!page->focusController().isFocused())
+ page->focusController().setFocused(true);
+
+ // Reset the page pointer in case FocusController::setFocused(true) caused a side effect that invalidated our old one.
+ page = document() ? document()->page() : nullptr;
+ if (!page)
+ return;
+#endif
+
#if PLATFORM(COCOA)
auto* frameView = documentFrameView();
if (!frameView)
@@ -2793,9 +2807,9 @@
// Legacy WebKit1 case.
if (frameView->platformWidget())
- chromeClient.makeFirstResponder((NSResponder *)frameView->platformWidget());
+ page->chrome().client().makeFirstResponder((NSResponder *)frameView->platformWidget());
else
- chromeClient.assistiveTechnologyMakeFirstResponder();
+ page->chrome().client().assistiveTechnologyMakeFirstResponder();
#endif
}
}
Modified: trunk/Source/WebCore/testing/Internals.cpp (287809 => 287810)
--- trunk/Source/WebCore/testing/Internals.cpp 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebCore/testing/Internals.cpp 2022-01-08 16:40:34 UTC (rev 287810)
@@ -5360,6 +5360,11 @@
updatePageActivityState(ActivityState::IsVisible, isVisible);
}
+void Internals::setPageIsFocused(bool isFocused)
+{
+ updatePageActivityState(ActivityState::IsFocused, isFocused);
+}
+
void Internals::setPageIsFocusedAndActive(bool isFocusedAndActive)
{
updatePageActivityState({ ActivityState::IsFocused, ActivityState::WindowIsActive }, isFocusedAndActive);
Modified: trunk/Source/WebCore/testing/Internals.h (287809 => 287810)
--- trunk/Source/WebCore/testing/Internals.h 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebCore/testing/Internals.h 2022-01-08 16:40:34 UTC (rev 287810)
@@ -845,6 +845,7 @@
#endif
void setPageVisibility(bool isVisible);
+ void setPageIsFocused(bool);
void setPageIsFocusedAndActive(bool);
void setPageIsInWindow(bool);
bool isPageActive() const;
Modified: trunk/Source/WebCore/testing/Internals.idl (287809 => 287810)
--- trunk/Source/WebCore/testing/Internals.idl 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebCore/testing/Internals.idl 2022-01-08 16:40:34 UTC (rev 287810)
@@ -885,6 +885,7 @@
[Conditional=WEBGL] boolean platformSupportsMetal(boolean isWebGL2);
undefined setPageVisibility(boolean isVisible);
+ undefined setPageIsFocused(boolean isFocused);
undefined setPageIsFocusedAndActive(boolean isFocused);
undefined setPageIsInWindow(boolean isInWindow);
boolean isPageActive();
Modified: trunk/Source/WebKit/ChangeLog (287809 => 287810)
--- trunk/Source/WebKit/ChangeLog 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebKit/ChangeLog 2022-01-08 16:40:34 UTC (rev 287810)
@@ -1,3 +1,21 @@
+2022-01-08 Tyler Wilcock <[email protected]>
+
+ AX: AccessibilityObject::setFocused(true) should make the webpage focused, and make web content the first responder
+ https://bugs.webkit.org/show_bug.cgi?id=234885
+
+ Reviewed by Darin Adler.
+
+ With this patch, focusing an element via an AX client on iOS makes web content
+ the first responder. This allows a focus ring to be drawn and for web content
+ to perform other important actions upon taking first respondership
+ (see `[WKContentViewInteraction becomeFirstResponderForWebView]`), even when apps
+ that embed WKWebViews don't make web content the first responder themselves.
+
+ * UIProcess/ios/PageClientImplIOS.mm:
+ (WebKit::PageClientImpl::assistiveTechnologyMakeFirstResponder):
+ * UIProcess/ios/WebPageProxyIOS.mm:
+ (WebKit::WebPageProxy::assistiveTechnologyMakeFirstResponder):
+
2022-01-07 Jean-Yves Avenard <[email protected]>
Remove IPC::SharedBufferDataReference and use IPC::SharedBufferCopy instead
Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm (287809 => 287810)
--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm 2022-01-08 16:40:34 UTC (rev 287810)
@@ -391,7 +391,7 @@
void PageClientImpl::assistiveTechnologyMakeFirstResponder()
{
- notImplemented();
+ [m_contentView becomeFirstResponder];
}
void PageClientImpl::makeFirstResponder()
Modified: trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm (287809 => 287810)
--- trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm 2022-01-08 16:40:34 UTC (rev 287810)
@@ -741,7 +741,7 @@
void WebPageProxy::assistiveTechnologyMakeFirstResponder()
{
- notImplemented();
+ pageClient().assistiveTechnologyMakeFirstResponder();
}
void WebPageProxy::makeFirstResponder()
Modified: trunk/Tools/ChangeLog (287809 => 287810)
--- trunk/Tools/ChangeLog 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/ChangeLog 2022-01-08 16:40:34 UTC (rev 287810)
@@ -1,3 +1,27 @@
+2022-01-08 Tyler Wilcock <[email protected]>
+
+ AX: AccessibilityObject::setFocused(true) should make the webpage focused, and make web content the first responder
+ https://bugs.webkit.org/show_bug.cgi?id=234885
+
+ Reviewed by Darin Adler.
+
+ Add testing functionality necessary to check that web content is the
+ first responder in the UI process.
+
+ * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+ * TestRunnerShared/UIScriptContext/UIScriptController.h:
+ (WTR::UIScriptController::isWebContentFirstResponder const):
+ Added.
+
+ * WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm:
+ (WTR::AccessibilityUIElement::takeFocus):
+ Implement this method.
+
+ * WebKitTestRunner/ios/UIScriptControllerIOS.h:
+ * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+ (WTR::UIScriptControllerIOS::isWebContentFirstResponder const):
+ Added.
+
2022-01-07 Tim Horton <[email protected]>
A/B comparison tests fail trying to look up fuzzy match tolerance
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl (287809 => 287810)
--- trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl 2022-01-08 16:40:34 UTC (rev 287810)
@@ -359,6 +359,7 @@
undefined firstResponderSuppressionForWebView(boolean shouldSuppress);
undefined makeWindowContentViewFirstResponder();
readonly attribute boolean isWindowContentViewFirstResponder;
+ readonly attribute boolean isWebContentFirstResponder;
undefined setHardwareKeyboardAttached(boolean attached);
Modified: trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h (287809 => 287810)
--- trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/TestRunnerShared/UIScriptContext/UIScriptController.h 2022-01-08 16:40:34 UTC (rev 287810)
@@ -118,6 +118,7 @@
virtual void firstResponderSuppressionForWebView(bool) { notImplemented(); }
virtual void makeWindowContentViewFirstResponder() { notImplemented(); }
virtual bool isWindowContentViewFirstResponder() const { notImplemented(); return false; }
+ virtual bool isWebContentFirstResponder() const { notImplemented(); return false; }
virtual void removeViewFromWindow(JSValueRef) { notImplemented(); }
virtual void addViewToWindow(JSValueRef) { notImplemented(); }
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm (287809 => 287810)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/ios/AccessibilityUIElementIOS.mm 2022-01-08 16:40:34 UTC (rev 287810)
@@ -70,6 +70,7 @@
- (CGFloat)_accessibilityMinValue;
- (CGFloat)_accessibilityMaxValue;
- (void)_accessibilitySetValue:(NSString *)value;
+- (void)_accessibilitySetFocus:(BOOL)focus;
- (void)_accessibilityActivate;
- (UIAccessibilityTraits)_axSelectedTrait;
- (UIAccessibilityTraits)_axTextAreaTrait;
@@ -1181,6 +1182,7 @@
void AccessibilityUIElement::takeFocus()
{
+ [m_element _accessibilitySetFocus:YES];
}
void AccessibilityUIElement::takeSelection()
Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h (287809 => 287810)
--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h 2022-01-08 16:40:34 UTC (rev 287810)
@@ -168,6 +168,8 @@
void waitForSingleTapToReset() const;
WebCore::FloatRect rectForMenuAction(CFStringRef) const;
void singleTapAtPointWithModifiers(WebCore::FloatPoint location, Vector<String>&& modifierFlags, BlockPtr<void()>&&);
+
+ bool isWebContentFirstResponder() const override;
};
}
Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (287809 => 287810)
--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2022-01-08 14:27:39 UTC (rev 287809)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm 2022-01-08 16:40:34 UTC (rev 287810)
@@ -1326,6 +1326,11 @@
webView()._suppressSoftwareKeyboard = suppressSoftwareKeyboard;
}
+bool UIScriptControllerIOS::isWebContentFirstResponder() const
+{
+ return [webView() _contentViewIsFirstResponder];
}
+}
+
#endif // PLATFORM(IOS_FAMILY)