Commit a471ff9b authored by Kevin Babbitt's avatar Kevin Babbitt Committed by Commit Bot

Reland "Ensure UI Automation GetFocus reaches focused node in web content"

This is a reland of 756820dd

The original CL was reverted due to test failures on Win7.

On both Win10 and Win7, UI Automation was generating an initial focus
event when the test listener first connects. On Win10, this initial
focus event comes from a window managed by the operating system
(ClassName=ApplicationManager_ImmersiveShellWindow). Since that element
is outside the scope of the test app, the test listener throws it out.
On Win7, the initial focus event comes from an element in our web
content, so the test listener logs it.

My suspicion is that the difference in behavior is due to mitigations
for focus stealing introduced between Win7 and Win10. Regardless, the
fix is to generate separate expectation files for Win7.

Original change's description:
> Ensure UI Automation GetFocus reaches focused node in web content
>
> AXPlatformNodeDelegate::GetFocus() returns the node within the called
> node's subtree that currently has focus. When an element in web content
> has focus, and a delegate in Views is asked for focus, that delegate can
> only reach as far as the web content root. Calling GetFocus() again on
> the web content root ensures that the platform API returns the currently
> focused node.
>
> Bug: 928811
> Change-Id: Ice47eed0a8ea4281beb48624942ac2428fb1950f
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2099162
> Reviewed-by: Ian Prest <iapres@microsoft.com>
> Commit-Queue: Kevin Babbitt <kbabbitt@microsoft.com>
> Cr-Commit-Position: refs/heads/master@{#749386}

Bug: 928811
Change-Id: I32e59febfb6dbb7b5386c155c252c880a0f2ebc5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2101930
Commit-Queue: Kevin Babbitt <kbabbitt@microsoft.com>
Reviewed-by: default avatarIan Prest <iapres@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#750781}
parent 95570f3a
......@@ -50,6 +50,7 @@
#include "third_party/isimpledom/ISimpleDOMNode.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/platform/ax_fragment_root_win.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
......@@ -4266,6 +4267,44 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
EXPECT_EQ(window_text_str16, name_str16);
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
GetFocusFromRootReachesWebContent) {
LoadInitialAccessibilityTreeFromHtml(
R"HTML(<!DOCTYPE html>
<html>
<button>Focus target</button>
<script>
document.querySelector('button').focus();
</script>
</html>)HTML");
// Obtain the fragment root from the top-level HWND.
HWND hwnd = shell()->window()->GetHost()->GetAcceleratedWidget();
ASSERT_NE(gfx::kNullAcceleratedWidget, hwnd);
ui::AXFragmentRootWin* fragment_root =
ui::AXFragmentRootWin::GetForAcceleratedWidget(hwnd);
ASSERT_NE(nullptr, fragment_root);
Microsoft::WRL::ComPtr<IRawElementProviderFragmentRoot> uia_fragment_root;
ASSERT_HRESULT_SUCCEEDED(
fragment_root->GetNativeViewAccessible()->QueryInterface(
IID_PPV_ARGS(&uia_fragment_root)));
// Verify that calling GetFocus on the fragment root reaches web content.
Microsoft::WRL::ComPtr<IRawElementProviderFragment> focused_fragment;
ASSERT_HRESULT_SUCCEEDED(uia_fragment_root->GetFocus(&focused_fragment));
Microsoft::WRL::ComPtr<IRawElementProviderSimple> focused_element;
ASSERT_HRESULT_SUCCEEDED(focused_fragment.As(&focused_element));
base::win::ScopedVariant name_property;
ASSERT_HRESULT_SUCCEEDED(focused_element->GetPropertyValue(
UIA_NamePropertyId, name_property.Receive()));
ASSERT_EQ(name_property.type(), VT_BSTR);
BSTR name_bstr = name_property.ptr()->bstrVal;
base::string16 actual_name(name_bstr, ::SysStringLen(name_bstr));
EXPECT_EQ(L"Focus target", actual_name);
}
IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
LegacyWindowIsNotControlElement) {
LoadInitialAccessibilityTreeFromHtml(
......
AriaProperties changed on role=combobox
AutomationFocusChanged on role=combobox
AutomationFocusChanged on role=combobox
AutomationFocusChanged on role=option, name=Orange
ExpandCollapseExpandCollapseState changed on role=combobox
<-- End-of-file -->
AriaProperties changed on role=combobox
AriaProperties changed on role=option, name=Apple
AutomationFocusChanged on role=combobox
AutomationFocusChanged on role=option, name=Apple
AutomationFocusChanged on role=option, name=Apple
ExpandCollapseExpandCollapseState changed on role=combobox
SelectionItem_ElementSelected on role=option, name=Apple
<-- End-of-file -->
AriaProperties changed on role=option, name=Apple
AriaProperties changed on role=option, name=Orange
AutomationFocusChanged on role=option, name=Apple
AutomationFocusChanged on role=option, name=Orange
AutomationFocusChanged on role=option, name=Orange
SelectionItem_ElementSelected on role=option, name=Orange
=== Start Continuation ===
AriaProperties changed on role=option, name=Banana
AriaProperties changed on role=option, name=Orange
AutomationFocusChanged on role=option, name=Banana
AutomationFocusChanged on role=option, name=Banana
AutomationFocusChanged on role=option, name=Orange
SelectionItem_ElementSelected on role=option, name=Banana
<-- End-of-file -->
AriaProperties changed on role=option, name=Apple
AriaProperties changed on role=option, name=Orange
AutomationFocusChanged on role=option, name=Apple
AutomationFocusChanged on role=option, name=Orange
AutomationFocusChanged on role=option, name=Orange
SelectionItem_ElementSelected on role=option, name=Orange
<-- End-of-file -->
......@@ -129,10 +129,26 @@ class AXFragmentRootPlatformNodeWin : public AXPlatformNodeWin,
*focus = nullptr;
gfx::NativeViewAccessible focused_element = GetDelegate()->GetFocus();
if (focused_element != nullptr) {
gfx::NativeViewAccessible focused_element = nullptr;
// GetFocus() can return a node at the root of a subtree, for example when
// transitioning from Views into web content. In such cases we want to
// continue drilling to retrieve the actual focused element.
AXPlatformNode* node_to_test = this;
do {
gfx::NativeViewAccessible test_result =
node_to_test->GetDelegate()->GetFocus();
if (test_result != nullptr && test_result != focused_element) {
focused_element = test_result;
node_to_test =
AXPlatformNode::FromNativeViewAccessible(focused_element);
} else {
node_to_test = nullptr;
}
} while (node_to_test);
if (focused_element)
focused_element->QueryInterface(IID_PPV_ARGS(focus));
}
return S_OK;
}
......
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