Commit 03e2bfa9 authored by Kurt Catti-Schmidt (SCHMIDT)'s avatar Kurt Catti-Schmidt (SCHMIDT) Committed by Commit Bot

Fire focus events on nodes when the frame isn't already focused.

This change fixes a particular issue where the Javascript "onfocus()"
event doesn't fire when accessibility API's call focus() on a
specific node when the frame containing that node doesn't currently
have focus.

Blink's implementation of "onfocus()" in Document::SetFocusedElement has
a condition under GetPage()->GetFocusController().IsFocused() to prevent
focus from being fired if the page doesn't have focus. This is correct
behavior from Javascript's perspective.

From the accessibility side, behavior was already added to focus on the
document before focusing on a specific node in
https://chromium-review.googlesource.com/c/chromium/src/+/1809943

However, when that change calls into
RenderFrameHostImpl::AccessibilityViewSetFocus, if the view is a
RenderWidgetHostViewChildFrame, nothing will happen, as that method is
empty. So this change completes that method with a simple focus
implementation.

A browser test was added to confirm that the Javascript onfocus event
is properly fired.

Bug: 1124067
Change-Id: I5a77fcdfba96da45fe548e93c2da8c9a69181066
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2389005
Commit-Queue: Kurt Catti-Schmidt <kschmi@microsoft.com>
Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805465}
parent 3d30fbc4
......@@ -1240,6 +1240,59 @@ IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
EXPECT_EQ(text->GetId(), anchor_waiter.event_target_id());
}
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
FocusFiresJavascriptOnfocus) {
LoadInitialAccessibilityTreeFromHtmlFilePath(
"/accessibility/html/iframe-focus.html");
// There are two iframes in the test page, so wait for both of them to
// complete loading before proceeding.
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Ordinary Button");
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Button with focus handler");
BrowserAccessibilityManager* root_accessibility_manager = GetManager();
ASSERT_NE(nullptr, root_accessibility_manager);
BrowserAccessibility* root_browser_accessibility =
root_accessibility_manager->GetRoot();
ASSERT_NE(nullptr, root_browser_accessibility);
// Focus the button within the second iframe to set focus on that document,
// then set focus on the first iframe (with the Javascript onfocus handler)
// and ensure onfocus fires there.
BrowserAccessibility* second_iframe_browser_accessibility =
root_browser_accessibility->InternalDeepestLastChild();
ASSERT_NE(nullptr, second_iframe_browser_accessibility);
BrowserAccessibility* second_iframe_root_browser_accessibility =
second_iframe_browser_accessibility->PlatformGetChild(0);
ASSERT_NE(nullptr, second_iframe_root_browser_accessibility);
BrowserAccessibility* second_button = FindNodeByRole(
second_iframe_root_browser_accessibility, ax::mojom::Role::kButton);
ASSERT_NE(nullptr, second_button);
AccessibilityNotificationWaiter waiter(
shell()->web_contents(), ui::kAXModeComplete, ax::mojom::Event::kFocus);
second_iframe_root_browser_accessibility->manager()->SetFocus(*second_button);
waiter.WaitForNotification();
EXPECT_EQ(second_button, root_accessibility_manager->GetFocus());
BrowserAccessibility* first_iframe_browser_accessibility =
root_browser_accessibility->InternalDeepestFirstChild();
ASSERT_NE(nullptr, first_iframe_browser_accessibility);
BrowserAccessibility* first_iframe_root_browser_accessibility =
first_iframe_browser_accessibility->PlatformGetChild(0);
ASSERT_NE(nullptr, first_iframe_root_browser_accessibility);
BrowserAccessibility* first_button = FindNodeByRole(
first_iframe_root_browser_accessibility, ax::mojom::Role::kButton);
ASSERT_NE(nullptr, first_button);
// The page in the first iframe will append the word "Focused" when onfocus is
// fired, so wait for that node to be added.
first_iframe_root_browser_accessibility->manager()->SetFocus(*first_button);
WaitForAccessibilityTreeToContainNodeWithName(shell()->web_contents(),
"Focused");
EXPECT_EQ(first_button, root_accessibility_manager->GetFocus());
}
IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
IFrameContentHadFocus_ThenRootDocumentGainedFocus) {
// Start by loading a document with iframes.
......
......@@ -187,7 +187,10 @@ void RenderWidgetHostViewChildFrame::SetBounds(const gfx::Rect& rect) {
}
}
void RenderWidgetHostViewChildFrame::Focus() {}
void RenderWidgetHostViewChildFrame::Focus() {
if (frame_connector_ && !frame_connector_->HasFocus())
return frame_connector_->FocusRootView();
}
bool RenderWidgetHostViewChildFrame::HasFocus() {
if (frame_connector_)
......@@ -644,10 +647,8 @@ bool RenderWidgetHostViewChildFrame::ScreenRectIsUnstableFor(
void RenderWidgetHostViewChildFrame::PreProcessTouchEvent(
const blink::WebTouchEvent& event) {
if (event.GetType() == blink::WebInputEvent::Type::kTouchStart &&
frame_connector_ && !frame_connector_->HasFocus()) {
frame_connector_->FocusRootView();
}
if (event.GetType() == blink::WebInputEvent::Type::kTouchStart)
Focus();
}
viz::FrameSinkId RenderWidgetHostViewChildFrame::GetRootFrameSinkId() {
......
<!DOCTYPE html>
<html>
<body style="margin: 0; padding: 0;">
<div style="width: 300px; height: 100px;">
<script>
function log_focused() {
let log = document.getElementById("focused_log");
log.innerText = "Focused";
}
</script>
<button style="margin: 25px; border: 0; width: 250px; height: 50px" onfocus="log_focused()">
Button with focus handler
</button>
<div id="focused_log"></div>
</div>
</body>
</html>
<!--
@MAC-ALLOW:AXRoleDescription
@WIN-ALLOW:ia2_hypertext=*
@WIN-ALLOW:parent=*
@WIN-ALLOW:window_class=*
@BLINK-ALLOW:scrollable=*
-->
<!DOCTYPE html>
<html>
<body>
<iframe style="width:200px; height: 200px;" src="frame/button_onfocus.html">
</iframe>
<iframe style="width:200px; height: 200px;" src="frame/button.html">
</iframe>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment