Commit 61d99852 authored by Ian Prest's avatar Ian Prest Committed by Commit Bot

Fire UIA focus event, and add UIA test pass

1. Added `BrowserAccessibilityManagerWin::FireUiaAccessibilityEvent`.
-- New function, modelled on `FireWinAccessibilityEvent`.
-- Both functions now examine the experimental UIA flag.

2. Fire the `UIA_AutomationFocusChangedEventId` event when appropriate.

3. Refactored the test "pass" logic in `DumpAccessibilityTestBase` to
run a test pass for each tree-formatter factory method that is returned
by `AccessibilityEventRecorder::GetTestPasses`.
-- This allows each platform to run a different set of test passes.

4. Added a third pass for tests on Windows to test UIA.
-- They look for files with the "-expected-win-uia.txt" suffix.
-- This allows us to provide expected results for UIA events separately
from MSAA events.

5. All existing Windows/MSAA tests that had `EVENT_OBJECT_FOCUS` events
were enabled for the new UIA pass.
-- We'll enable the remaining tests as more UIA events are added.

6. Since you can't simultaneously listen to both MSAA and UIA events,
a new event-recorder `AccessibilityEventRecorderUia` was needed to
record UIA events.
-- Heavily based on existing class `AccessibilityEventRecorderWin`.

Bug: 928949

Change-Id: Ic4fde227c8f5674a915c0d30eb05151f3250a704
Reviewed-on: https://chromium-review.googlesource.com/c/1474976
Commit-Queue: Ian Prest <iapres@microsoft.com>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#634359}
parent 1bc0f674
......@@ -24,6 +24,19 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
const base::StringPiece& application_name_match_pattern) {
return std::make_unique<AccessibilityEventRecorder>(manager);
}
// static
std::vector<AccessibilityEventRecorder::EventRecorderFactory>
AccessibilityEventRecorder::GetTestPasses() {
return {
#if !defined(OS_ANDROID)
// Note: Android doesn't do a "blink" pass; the blink tree is different on
// Android because we exclude inline text boxes, for performance.
&AccessibilityEventRecorder::Create,
#endif
&AccessibilityEventRecorder::Create,
};
}
#endif
void AccessibilityEventRecorder::OnEvent(const std::string& event) {
......
......@@ -44,6 +44,14 @@ class AccessibilityEventRecorder {
const base::StringPiece& application_name_match_pattern =
base::StringPiece());
// Get a set of factory methods to create event-recorders, one for each test
// pass; see |DumpAccessibilityTestBase|.
using EventRecorderFactory = std::unique_ptr<AccessibilityEventRecorder> (*)(
BrowserAccessibilityManager* manager,
base::ProcessId pid,
const base::StringPiece& application_name_match_pattern);
static std::vector<EventRecorderFactory> GetTestPasses();
AccessibilityEventRecorder(BrowserAccessibilityManager* manager);
virtual ~AccessibilityEventRecorder();
......
......@@ -97,6 +97,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
manager, pid, application_name_match_pattern);
}
std::vector<AccessibilityEventRecorder::EventRecorderFactory>
AccessibilityEventRecorder::GetTestPasses() {
// Both the Blink pass and native pass use the same recorder
return {
&AccessibilityEventRecorder::Create,
&AccessibilityEventRecorder::Create,
};
}
bool AccessibilityEventRecorderAuraLinux::ShouldUseATSPI() {
return pid_ != base::GetCurrentProcId() ||
!application_name_match_pattern_.empty();
......
......@@ -73,6 +73,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
return std::make_unique<AccessibilityEventRecorderMac>(manager, pid);
}
std::vector<AccessibilityEventRecorder::EventRecorderFactory>
AccessibilityEventRecorder::GetTestPasses() {
// Both the Blink pass and native pass use the same recorder
return {
&AccessibilityEventRecorder::Create,
&AccessibilityEventRecorder::Create,
};
}
AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
BrowserAccessibilityManager* manager,
base::ProcessId pid)
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/accessibility/accessibility_event_recorder_uia_win.h"
#include <string>
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/browser_accessibility_com_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "ui/base/win/atl_module.h"
namespace content {
namespace {
std::string BstrToUTF8(BSTR bstr) {
base::string16 str16(bstr, SysStringLen(bstr));
return base::UTF16ToUTF8(str16);
}
} // namespace
// static
AccessibilityEventRecorderUia* AccessibilityEventRecorderUia::instance_ =
nullptr;
// static
std::unique_ptr<AccessibilityEventRecorder>
AccessibilityEventRecorderUia::CreateUia(
BrowserAccessibilityManager* manager,
base::ProcessId pid,
const base::StringPiece& application_name_match_pattern) {
return std::make_unique<AccessibilityEventRecorderUia>(
manager, pid, application_name_match_pattern);
}
AccessibilityEventRecorderUia::AccessibilityEventRecorderUia(
BrowserAccessibilityManager* manager,
base::ProcessId pid,
const base::StringPiece& application_name_match_pattern)
: AccessibilityEventRecorder(manager) {
CHECK(!instance_) << "There can be only one instance of"
<< " AccessibilityEventRecorder at a time.";
// Create an instance of the CUIAutomation class.
CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER,
IID_IUIAutomation, &uia_);
CHECK(uia_.Get());
uia_->CreateCacheRequest(&cache_request_);
CHECK(cache_request_.Get());
// Find the root IUIAutomationElement for the content window
HWND hwnd = manager->GetRoot()->GetTargetForNativeAccessibilityEvent();
CHECK(hwnd);
Microsoft::WRL::ComPtr<IUIAutomationElement> root;
uia_->ElementFromHandle(hwnd, &root);
CHECK(root.Get());
// Create the event handler
ui::win::CreateATLModuleIfNeeded();
CHECK(
SUCCEEDED(CComObject<EventHandler>::CreateInstance(&uia_event_handler_)));
uia_event_handler_->Init(this, root);
// Subscribe to focus events
uia_->AddFocusChangedEventHandler(nullptr, uia_event_handler_.Get());
instance_ = this;
}
AccessibilityEventRecorderUia::~AccessibilityEventRecorderUia() {
uia_event_handler_->owner_ = nullptr;
uia_event_handler_.Reset();
instance_ = nullptr;
}
AccessibilityEventRecorderUia::EventHandler::EventHandler() {}
AccessibilityEventRecorderUia::EventHandler::~EventHandler() {}
void AccessibilityEventRecorderUia::EventHandler::Init(
AccessibilityEventRecorderUia* owner,
Microsoft::WRL::ComPtr<IUIAutomationElement> root) {
owner_ = owner;
root_ = root;
}
STDMETHODIMP
AccessibilityEventRecorderUia::EventHandler::HandleFocusChangedEvent(
IUIAutomationElement* sender) {
if (!owner_)
return S_OK;
base::win::ScopedBstr id;
sender->get_CurrentAutomationId(id.Receive());
base::win::ScopedVariant id_variant(id, id.Length());
Microsoft::WRL::ComPtr<IUIAutomationElement> element_found;
Microsoft::WRL::ComPtr<IUIAutomationCondition> condition;
owner_->uia_->CreatePropertyCondition(UIA_AutomationIdPropertyId, id_variant,
&condition);
CHECK(condition);
root_->FindFirst(TreeScope::TreeScope_Subtree, condition.Get(),
&element_found);
if (!element_found) {
VLOG(1) << "Ignoring UIA focus event outside our frame";
return S_OK;
}
std::string log = base::StringPrintf("UIA_AutomationFocusChangedEventId %s",
GetSenderInfo(sender).c_str());
owner_->OnEvent(log);
return S_OK;
}
std::string AccessibilityEventRecorderUia::EventHandler::GetSenderInfo(
IUIAutomationElement* sender) {
std::string sender_info = "";
auto append_property = [&](const char* name, auto getter) {
base::win::ScopedBstr bstr;
(sender->*getter)(bstr.Receive());
if (bstr.Length() > 0) {
sender_info +=
base::StringPrintf("%s%s=%s", sender_info.empty() ? "" : ", ", name,
BstrToUTF8(bstr).c_str());
}
};
append_property("role", &IUIAutomationElement::get_CurrentAriaRole);
append_property("name", &IUIAutomationElement::get_CurrentName);
if (!sender_info.empty())
sender_info = "on " + sender_info;
return sender_info;
}
} // namespace content
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EVENT_RECORDER_UIA_WIN_H_
#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EVENT_RECORDER_UIA_WIN_H_
#include <ole2.h>
#include <stdint.h>
#include <uiautomation.h>
#include <wrl/client.h>
#include "base/win/atl.h"
#include "content/browser/accessibility/accessibility_event_recorder.h"
namespace content {
class AccessibilityEventRecorderUia : public AccessibilityEventRecorder {
public:
AccessibilityEventRecorderUia(
BrowserAccessibilityManager* manager = nullptr,
base::ProcessId pid = 0,
const base::StringPiece& application_name_match_pattern =
base::StringPiece());
~AccessibilityEventRecorderUia() override;
static std::unique_ptr<AccessibilityEventRecorder> CreateUia(
BrowserAccessibilityManager* manager = nullptr,
base::ProcessId pid = 0,
const base::StringPiece& application_name_match_pattern =
base::StringPiece());
private:
Microsoft::WRL::ComPtr<IUIAutomation> uia_;
Microsoft::WRL::ComPtr<IUIAutomationCacheRequest> cache_request_;
static AccessibilityEventRecorderUia* instance_;
// An implementation of various UIA interface that forward event
// notifications to the owning event recorder.
class EventHandler : public CComObjectRootEx<CComMultiThreadModel>,
public IUIAutomationFocusChangedEventHandler {
public:
explicit EventHandler();
virtual ~EventHandler();
void Init(AccessibilityEventRecorderUia* owner,
Microsoft::WRL::ComPtr<IUIAutomationElement> root);
BEGIN_COM_MAP(EventHandler)
COM_INTERFACE_ENTRY(IUIAutomationFocusChangedEventHandler)
END_COM_MAP()
// IUIAutomationFocusChangedEventHandler interface.
STDMETHOD(HandleFocusChangedEvent)(IUIAutomationElement* sender) override;
// Points to the event recorder to receive notifications.
AccessibilityEventRecorderUia* owner_;
private:
std::string GetSenderInfo(IUIAutomationElement* sender);
Microsoft::WRL::ComPtr<IUIAutomationElement> root_;
DISALLOW_COPY_AND_ASSIGN(EventHandler);
};
Microsoft::WRL::ComPtr<CComObject<EventHandler>> uia_event_handler_;
DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRecorderUia);
};
} // namespace content
#endif
......@@ -17,6 +17,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/accessibility_event_recorder_uia_win.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
......@@ -131,6 +132,18 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
manager, pid, application_name_match_pattern);
}
std::vector<AccessibilityEventRecorder::EventRecorderFactory>
AccessibilityEventRecorder::GetTestPasses() {
// In addition to the 'Blink' pass, Windows includes two accessibility APIs
// that need to be tested independently (MSAA & UIA); the Blink pass uses the
// same recorder as the MSAA pass.
return {
&AccessibilityEventRecorder::Create,
&AccessibilityEventRecorder::Create,
&AccessibilityEventRecorderUia::CreateUia,
};
}
// static
CALLBACK void AccessibilityEventRecorderWin::WinEventHookThunk(
HWINEVENTHOOK handle,
......
......@@ -211,4 +211,7 @@ bool AccessibilityTreeFormatter::WriteAttribute(bool include_by_default,
return true;
}
void AccessibilityTreeFormatter::SetUpCommandLineForTestPass(
base::CommandLine* command_line) {}
} // namespace content
......@@ -24,6 +24,10 @@ namespace {
const char kChildrenDictAttr[] = "children";
}
namespace base {
class CommandLine;
}
namespace content {
// A utility class for formatting platform-specific accessibility information,
......@@ -68,6 +72,14 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
// Create the appropriate native subclass of AccessibilityTreeFormatter.
static std::unique_ptr<AccessibilityTreeFormatter> Create();
// Get a set of factory methods to create tree-formatters, one for each test
// pass; see |DumpAccessibilityTestBase|.
using FormatterFactory = std::unique_ptr<AccessibilityTreeFormatter> (*)();
static std::vector<FormatterFactory> GetTestPasses();
// Called to allow each test pass to alter the command-line
virtual void SetUpCommandLineForTestPass(base::CommandLine* command_line);
static bool MatchesPropertyFilters(
const std::vector<PropertyFilter>& property_filters,
const base::string16& text,
......
......@@ -86,6 +86,16 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterAndroid>();
}
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
// Note: Android doesn't do a "blink" pass; the blink tree is different on
// Android because we exclude inline text boxes, for performance.
return {
&AccessibilityTreeFormatter::Create,
};
}
AccessibilityTreeFormatterAndroid::AccessibilityTreeFormatterAndroid() {
}
......
......@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_auralinux.h"
#include "content/browser/accessibility/browser_accessibility_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
......@@ -65,6 +66,15 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterAuraLinux>();
}
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
AccessibilityTreeFormatterAuraLinux::AccessibilityTreeFormatterAuraLinux() {
}
......
......@@ -138,6 +138,12 @@ AccessibilityTreeFormatterBlink::AccessibilityTreeFormatterBlink()
AccessibilityTreeFormatterBlink::~AccessibilityTreeFormatterBlink() {}
// static
std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatterBlink::CreateBlink() {
return std::make_unique<AccessibilityTreeFormatterBlink>();
}
const char* const TREE_DATA_ATTRIBUTES[] = {"TreeData.textSelStartOffset",
"TreeData.textSelEndOffset"};
......
......@@ -18,6 +18,8 @@ class CONTENT_EXPORT AccessibilityTreeFormatterBlink
explicit AccessibilityTreeFormatterBlink();
~AccessibilityTreeFormatterBlink() override;
static std::unique_ptr<AccessibilityTreeFormatter> CreateBlink();
private:
const base::FilePath::StringType GetExpectedFileSuffix() override;
const std::string GetAllowEmptyString() override;
......
......@@ -13,6 +13,7 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
......@@ -238,6 +239,15 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterMac>();
}
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
AccessibilityTreeFormatterMac::AccessibilityTreeFormatterMac() {
}
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/strings/string_number_conversions.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/accessibility_tree_formatter_browser.h"
namespace content {
......@@ -32,6 +33,15 @@ std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterStub>();
}
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
#endif
AccessibilityTreeFormatterStub::AccessibilityTreeFormatterStub()
......
......@@ -14,6 +14,7 @@
#include <string>
#include <utility>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
......@@ -24,10 +25,12 @@
#include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "third_party/iaccessible2/ia2_api_all.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/base/win/atl_module.h"
#include "ui/gfx/win/hwnd_util.h"
......@@ -78,6 +81,8 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter {
LONG window_x = 0,
LONG window_y = 0);
void SetUpCommandLineForTestPass(base::CommandLine* command_line) override;
private:
void RecursiveBuildAccessibilityTree(
const Microsoft::WRL::ComPtr<IAccessible> node,
......@@ -119,6 +124,23 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter {
base::DictionaryValue* filtered_dict_result = nullptr) override;
};
// This is currently a clone of the base Windows MSAA formatter in order to
// override the GetExpectedFileSuffix function for UIA tests; it will
// eventually be replaced with a full UIA implementation.
class AccessibilityTreeFormatterUia : public AccessibilityTreeFormatterWin {
public:
AccessibilityTreeFormatterUia() {}
~AccessibilityTreeFormatterUia() override {}
static std::unique_ptr<AccessibilityTreeFormatter> CreateUia();
void SetUpCommandLineForTestPass(base::CommandLine* command_line) override;
const base::FilePath::StringType GetExpectedFileSuffix() override {
return FILE_PATH_LITERAL("-expected-win-uia.txt");
}
};
// static
std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatter::Create() {
......@@ -126,6 +148,36 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterWin>();
}
// static
std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatterUia::CreateUia() {
base::win::AssertComInitialized();
return std::make_unique<AccessibilityTreeFormatterUia>();
}
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
// In addition to the 'Blink' pass, Windows includes two accessibility APIs
// that need to be tested independently (MSAA & UIA).
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
&AccessibilityTreeFormatterUia::CreateUia,
};
}
void AccessibilityTreeFormatterWin::SetUpCommandLineForTestPass(
base::CommandLine* command_line) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(
::switches::kEnableExperimentalUIAutomation);
}
void AccessibilityTreeFormatterUia::SetUpCommandLineForTestPass(
base::CommandLine* command_line) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kEnableExperimentalUIAutomation);
}
AccessibilityTreeFormatterWin::AccessibilityTreeFormatterWin() {
ui::win::CreateATLModuleIfNeeded();
}
......
......@@ -88,6 +88,7 @@ void BrowserAccessibilityManagerWin::FireFocusEvent(
BrowserAccessibilityManager::FireFocusEvent(node);
DCHECK(node);
FireWinAccessibilityEvent(EVENT_OBJECT_FOCUS, node);
FireUiaAccessibilityEvent(UIA_AutomationFocusChangedEventId, node);
}
void BrowserAccessibilityManagerWin::FireBlinkEvent(
......@@ -196,30 +197,15 @@ void BrowserAccessibilityManagerWin::FireGeneratedEvent(
void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent(
LONG win_event_type,
BrowserAccessibility* node) {
if (!node->CanFireEvents())
if (::switches::IsExperimentalAccessibilityPlatformUIAEnabled())
return;
// If there's no root delegate, this may be a new frame that hasn't
// yet been swapped in or added to the frame tree. Suppress firing events
// until then.
BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
if (!root_delegate)
if (!ShouldFireEventForNode(node))
return;
HWND hwnd = root_delegate->AccessibilityGetAcceleratedWidget();
HWND hwnd = GetParentHWND();
if (!hwnd)
return;
// Don't fire events when this document might be stale as the user has
// started navigating to a new document.
if (user_is_navigating_away_)
return;
// Inline text boxes are an internal implementation detail, we don't
// expose them to Windows.
if (node->GetRole() == ax::mojom::Role::kInlineTextBox)
return;
// Pass the negation of this node's unique id in the |child_id|
// argument to NotifyWinEvent; the AT client will then call get_accChild
// on the HWND's accessibility object and pass it that same id, which
......@@ -228,6 +214,18 @@ void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent(
::NotifyWinEvent(win_event_type, hwnd, OBJID_CLIENT, child_id);
}
void BrowserAccessibilityManagerWin::FireUiaAccessibilityEvent(
LONG uia_event,
BrowserAccessibility* node) {
if (!::switches::IsExperimentalAccessibilityPlatformUIAEnabled())
return;
if (!ShouldFireEventForNode(node))
return;
::UiaRaiseAutomationEvent(ToBrowserAccessibilityWin(node)->GetCOM(),
uia_event);
}
bool BrowserAccessibilityManagerWin::CanFireEvents() {
BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
if (!root_delegate)
......@@ -345,4 +343,29 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished(
}
}
bool BrowserAccessibilityManagerWin::ShouldFireEventForNode(
BrowserAccessibility* node) {
if (!node || !node->CanFireEvents())
return false;
// If there's no root delegate, this may be a new frame that hasn't
// yet been swapped in or added to the frame tree. Suppress firing events
// until then.
BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
if (!root_delegate)
return false;
// Don't fire events when this document might be stale as the user has
// started navigating to a new document.
if (user_is_navigating_away_)
return false;
// Inline text boxes are an internal implementation detail, we don't
// expose them to Windows.
if (node->GetRole() == ax::mojom::Role::kInlineTextBox)
return false;
return true;
}
} // namespace content
......@@ -45,6 +45,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
BrowserAccessibility* node) override;
void FireWinAccessibilityEvent(LONG win_event, BrowserAccessibility* node);
void FireUiaAccessibilityEvent(LONG uia_event, BrowserAccessibility* node);
// Track this object and post a VISIBLE_DATA_CHANGED notification when
// its container scrolls.
......@@ -61,6 +62,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
bool root_changed,
const std::vector<ui::AXTreeObserver::Change>& changes) override;
bool ShouldFireEventForNode(BrowserAccessibility* node);
private:
// Give BrowserAccessibilityManager::Create access to our constructor.
friend class BrowserAccessibilityManager;
......
......@@ -15,11 +15,12 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_command_line.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/accessibility/accessibility_event_recorder.h"
#include "content/browser/accessibility/accessibility_tree_formatter.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
......@@ -80,9 +81,9 @@ typedef AccessibilityTreeFormatter::PropertyFilter PropertyFilter;
typedef AccessibilityTreeFormatter::NodeFilter NodeFilter;
DumpAccessibilityTestBase::DumpAccessibilityTestBase()
: is_blink_pass_(false),
enable_accessibility_after_navigating_(false) {
}
: formatter_factory_(nullptr),
event_recorder_factory_(nullptr),
enable_accessibility_after_navigating_(false) {}
DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {
}
......@@ -100,8 +101,7 @@ void DumpAccessibilityTestBase::SetUpOnMainThread() {
base::string16
DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() {
std::unique_ptr<AccessibilityTreeFormatter> formatter(
CreateAccessibilityTreeFormatter());
std::unique_ptr<AccessibilityTreeFormatter> formatter(formatter_factory_());
std::vector<PropertyFilter> property_filters;
property_filters.push_back(
PropertyFilter(base::ASCIIToUTF16("*"), PropertyFilter::ALLOW));
......@@ -188,29 +188,30 @@ void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives(
}
}
std::unique_ptr<AccessibilityTreeFormatter>
DumpAccessibilityTestBase::CreateAccessibilityTreeFormatter() {
if (is_blink_pass_)
return std::make_unique<AccessibilityTreeFormatterBlink>();
else
return AccessibilityTreeFormatter::Create();
}
void DumpAccessibilityTestBase::RunTest(
const base::FilePath file_path, const char* file_dir) {
#if !defined(OS_ANDROID)
// The blink tree is different on Android because we exclude inline
// text boxes, for performance.
is_blink_pass_ = true;
RunTestForPlatform(file_path, file_dir);
#endif
is_blink_pass_ = false;
RunTestForPlatform(file_path, file_dir);
// Get all the tree formatters; the test is run independently on each one.
auto formatters = AccessibilityTreeFormatter::GetTestPasses();
auto event_recorders = AccessibilityEventRecorder::GetTestPasses();
DCHECK(event_recorders.size() == formatters.size());
int pass_count = formatters.size();
for (int pass = 0; pass < pass_count; ++pass) {
formatter_factory_ = formatters[pass];
event_recorder_factory_ = event_recorders[pass];
RunTestForPlatform(file_path, file_dir);
}
formatter_factory_ = nullptr;
event_recorder_factory_ = nullptr;
}
void DumpAccessibilityTestBase::RunTestForPlatform(
const base::FilePath file_path, const char* file_dir) {
formatter_ = CreateAccessibilityTreeFormatter();
formatter_ = formatter_factory_();
base::test::ScopedCommandLine scoped_command_line;
formatter_->SetUpCommandLineForTestPass(
scoped_command_line.GetProcessCommandLine());
// Disable the "hot tracked" state (set when the mouse is hovering over
// an object) because it makes test output change based on the mouse position.
......
......@@ -11,6 +11,7 @@
#include "base/debug/leak_annotations.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "content/browser/accessibility/accessibility_event_recorder.h"
#include "content/browser/accessibility/accessibility_tree_formatter.h"
#include "content/public/test/content_browser_test.h"
......@@ -96,10 +97,6 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
std::vector<std::string>* wait_for,
std::vector<std::string>* run_until);
// Create the right AccessibilityTreeFormatter subclass.
std::unique_ptr<AccessibilityTreeFormatter>
CreateAccessibilityTreeFormatter();
void RunTestForPlatform(const base::FilePath file_path, const char* file_dir);
// The default property filters plus the property filters loaded from the test
......@@ -114,12 +111,13 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
ScopedLeakSanitizerDisabler lsan_disabler;
#endif
// The current tree-formatter and event-recorder factories.
AccessibilityTreeFormatter::FormatterFactory formatter_factory_;
AccessibilityEventRecorder::EventRecorderFactory event_recorder_factory_;
// The current AccessibilityTreeFormatter.
std::unique_ptr<AccessibilityTreeFormatter> formatter_;
// Whether we're doing a native pass or internal/blink tree pass.
bool is_blink_pass_;
// Whether we should enable accessibility after navigating to the page,
// otherwise we enable it first.
bool enable_accessibility_after_navigating_;
......
......@@ -104,9 +104,10 @@ std::vector<std::string> DumpAccessibilityEventsTest::Dump(
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
shell()->web_contents());
base::ProcessId pid = base::GetCurrentProcId();
std::unique_ptr<AccessibilityEventRecorder> event_recorder(
AccessibilityEventRecorder::Create(
web_contents->GetRootBrowserAccessibilityManager(), pid));
std::unique_ptr<AccessibilityEventRecorder> event_recorder =
event_recorder_factory_(
web_contents->GetRootBrowserAccessibilityManager(), pid,
base::StringPiece{});
event_recorder->set_only_web_events(true);
// Save a copy of the accessibility tree (as a text dump); we'll
......
......@@ -130,8 +130,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
}
std::vector<std::string> Dump(std::vector<std::string>& unused) override {
std::unique_ptr<AccessibilityTreeFormatter> formatter(
CreateAccessibilityTreeFormatter());
std::unique_ptr<AccessibilityTreeFormatter> formatter(formatter_factory_());
formatter->SetPropertyFilters(property_filters_);
formatter->SetNodeFilters(node_filters_);
base::string16 actual_contents_utf16;
......
......@@ -34,6 +34,8 @@ jumbo_static_library("test_support") {
"../browser/accessibility/accessibility_event_recorder.cc",
"../browser/accessibility/accessibility_event_recorder.h",
"../browser/accessibility/accessibility_event_recorder_mac.mm",
"../browser/accessibility/accessibility_event_recorder_uia_win.cc",
"../browser/accessibility/accessibility_event_recorder_uia_win.h",
"../browser/accessibility/accessibility_event_recorder_win.cc",
"../browser/background_fetch/background_fetch_embedded_worker_test_helper.cc",
"../browser/background_fetch/background_fetch_embedded_worker_test_helper.h",
......
UIA_AutomationFocusChangedEventId on role=option, name=Apple
UIA_AutomationFocusChangedEventId on role=option, name=Apple
UIA_AutomationFocusChangedEventId on role=option, name=Apple
UIA_AutomationFocusChangedEventId on role=option, name=Banana
UIA_AutomationFocusChangedEventId on role=option, name=Orange
UIA_AutomationFocusChangedEventId on role=combobox
UIA_AutomationFocusChangedEventId on role=textbox, name=Pet name:
......@@ -3,6 +3,7 @@
@WIN-ALLOW:EVENT_OBJECT_FOCUS*
@WIN-ALLOW:EVENT_SYSTEM_ALERT*
@WIN-ALLOW:EVENT_OBJECT_LIVE*
@WIN-ALLOW:UIA_AutomationFocusChangedEventId*
@MAC-DENY:*
@MAC-ALLOW:AXFocusedUIElementChanged*
@MAC-ALLOW:AXFocusedUIElementChanged*
......
UIA_AutomationFocusChangedEventId on role=group, name=tbody
UIA_AutomationFocusChangedEventId on role=group, name=tfoot
UIA_AutomationFocusChangedEventId on role=group, name=thead
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