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( ...@@ -24,6 +24,19 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
const base::StringPiece& application_name_match_pattern) { const base::StringPiece& application_name_match_pattern) {
return std::make_unique<AccessibilityEventRecorder>(manager); 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 #endif
void AccessibilityEventRecorder::OnEvent(const std::string& event) { void AccessibilityEventRecorder::OnEvent(const std::string& event) {
......
...@@ -44,6 +44,14 @@ class AccessibilityEventRecorder { ...@@ -44,6 +44,14 @@ class AccessibilityEventRecorder {
const base::StringPiece& application_name_match_pattern = const base::StringPiece& application_name_match_pattern =
base::StringPiece()); 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); AccessibilityEventRecorder(BrowserAccessibilityManager* manager);
virtual ~AccessibilityEventRecorder(); virtual ~AccessibilityEventRecorder();
......
...@@ -97,6 +97,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create( ...@@ -97,6 +97,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
manager, pid, application_name_match_pattern); 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() { bool AccessibilityEventRecorderAuraLinux::ShouldUseATSPI() {
return pid_ != base::GetCurrentProcId() || return pid_ != base::GetCurrentProcId() ||
!application_name_match_pattern_.empty(); !application_name_match_pattern_.empty();
......
...@@ -73,6 +73,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create( ...@@ -73,6 +73,15 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
return std::make_unique<AccessibilityEventRecorderMac>(manager, pid); 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( AccessibilityEventRecorderMac::AccessibilityEventRecorderMac(
BrowserAccessibilityManager* manager, BrowserAccessibilityManager* manager,
base::ProcessId pid) 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 @@ ...@@ -17,6 +17,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_bstr.h" #include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.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/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_win.h" #include "content/browser/accessibility/browser_accessibility_win.h"
...@@ -131,6 +132,18 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create( ...@@ -131,6 +132,18 @@ std::unique_ptr<AccessibilityEventRecorder> AccessibilityEventRecorder::Create(
manager, pid, application_name_match_pattern); 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 // static
CALLBACK void AccessibilityEventRecorderWin::WinEventHookThunk( CALLBACK void AccessibilityEventRecorderWin::WinEventHookThunk(
HWINEVENTHOOK handle, HWINEVENTHOOK handle,
......
...@@ -211,4 +211,7 @@ bool AccessibilityTreeFormatter::WriteAttribute(bool include_by_default, ...@@ -211,4 +211,7 @@ bool AccessibilityTreeFormatter::WriteAttribute(bool include_by_default,
return true; return true;
} }
void AccessibilityTreeFormatter::SetUpCommandLineForTestPass(
base::CommandLine* command_line) {}
} // namespace content } // namespace content
...@@ -24,6 +24,10 @@ namespace { ...@@ -24,6 +24,10 @@ namespace {
const char kChildrenDictAttr[] = "children"; const char kChildrenDictAttr[] = "children";
} }
namespace base {
class CommandLine;
}
namespace content { namespace content {
// A utility class for formatting platform-specific accessibility information, // A utility class for formatting platform-specific accessibility information,
...@@ -68,6 +72,14 @@ class CONTENT_EXPORT AccessibilityTreeFormatter { ...@@ -68,6 +72,14 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
// Create the appropriate native subclass of AccessibilityTreeFormatter. // Create the appropriate native subclass of AccessibilityTreeFormatter.
static std::unique_ptr<AccessibilityTreeFormatter> Create(); 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( static bool MatchesPropertyFilters(
const std::vector<PropertyFilter>& property_filters, const std::vector<PropertyFilter>& property_filters,
const base::string16& text, const base::string16& text,
......
...@@ -86,6 +86,16 @@ AccessibilityTreeFormatter::Create() { ...@@ -86,6 +86,16 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterAndroid>(); 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() { AccessibilityTreeFormatterAndroid::AccessibilityTreeFormatterAndroid() {
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.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/accessibility_tree_formatter_utils_auralinux.h"
#include "content/browser/accessibility/browser_accessibility_auralinux.h" #include "content/browser/accessibility/browser_accessibility_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h" #include "ui/accessibility/platform/ax_platform_node_auralinux.h"
...@@ -65,6 +66,15 @@ AccessibilityTreeFormatter::Create() { ...@@ -65,6 +66,15 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterAuraLinux>(); return std::make_unique<AccessibilityTreeFormatterAuraLinux>();
} }
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
AccessibilityTreeFormatterAuraLinux::AccessibilityTreeFormatterAuraLinux() { AccessibilityTreeFormatterAuraLinux::AccessibilityTreeFormatterAuraLinux() {
} }
......
...@@ -138,6 +138,12 @@ AccessibilityTreeFormatterBlink::AccessibilityTreeFormatterBlink() ...@@ -138,6 +138,12 @@ AccessibilityTreeFormatterBlink::AccessibilityTreeFormatterBlink()
AccessibilityTreeFormatterBlink::~AccessibilityTreeFormatterBlink() {} AccessibilityTreeFormatterBlink::~AccessibilityTreeFormatterBlink() {}
// static
std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatterBlink::CreateBlink() {
return std::make_unique<AccessibilityTreeFormatterBlink>();
}
const char* const TREE_DATA_ATTRIBUTES[] = {"TreeData.textSelStartOffset", const char* const TREE_DATA_ATTRIBUTES[] = {"TreeData.textSelStartOffset",
"TreeData.textSelEndOffset"}; "TreeData.textSelEndOffset"};
......
...@@ -18,6 +18,8 @@ class CONTENT_EXPORT AccessibilityTreeFormatterBlink ...@@ -18,6 +18,8 @@ class CONTENT_EXPORT AccessibilityTreeFormatterBlink
explicit AccessibilityTreeFormatterBlink(); explicit AccessibilityTreeFormatterBlink();
~AccessibilityTreeFormatterBlink() override; ~AccessibilityTreeFormatterBlink() override;
static std::unique_ptr<AccessibilityTreeFormatter> CreateBlink();
private: private:
const base::FilePath::StringType GetExpectedFileSuffix() override; const base::FilePath::StringType GetExpectedFileSuffix() override;
const std::string GetAllowEmptyString() override; const std::string GetAllowEmptyString() override;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.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_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_mac.h" #include "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_manager.h"
...@@ -238,6 +239,15 @@ AccessibilityTreeFormatter::Create() { ...@@ -238,6 +239,15 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterMac>(); return std::make_unique<AccessibilityTreeFormatterMac>();
} }
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
AccessibilityTreeFormatterMac::AccessibilityTreeFormatterMac() { AccessibilityTreeFormatterMac::AccessibilityTreeFormatterMac() {
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/strings/string_number_conversions.h" #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" #include "content/browser/accessibility/accessibility_tree_formatter_browser.h"
namespace content { namespace content {
...@@ -32,6 +33,15 @@ std::unique_ptr<AccessibilityTreeFormatter> ...@@ -32,6 +33,15 @@ std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatter::Create() { AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterStub>(); return std::make_unique<AccessibilityTreeFormatterStub>();
} }
// static
std::vector<AccessibilityTreeFormatter::FormatterFactory>
AccessibilityTreeFormatter::GetTestPasses() {
return {
&AccessibilityTreeFormatterBlink::CreateBlink,
&AccessibilityTreeFormatter::Create,
};
}
#endif #endif
AccessibilityTreeFormatterStub::AccessibilityTreeFormatterStub() AccessibilityTreeFormatterStub::AccessibilityTreeFormatterStub()
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
...@@ -24,10 +25,12 @@ ...@@ -24,10 +25,12 @@
#include "base/win/com_init_util.h" #include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h" #include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.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/accessibility_tree_formatter_utils_win.h"
#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_win.h" #include "content/browser/accessibility/browser_accessibility_win.h"
#include "third_party/iaccessible2/ia2_api_all.h" #include "third_party/iaccessible2/ia2_api_all.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/base/win/atl_module.h" #include "ui/base/win/atl_module.h"
#include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/win/hwnd_util.h"
...@@ -78,6 +81,8 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter { ...@@ -78,6 +81,8 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter {
LONG window_x = 0, LONG window_x = 0,
LONG window_y = 0); LONG window_y = 0);
void SetUpCommandLineForTestPass(base::CommandLine* command_line) override;
private: private:
void RecursiveBuildAccessibilityTree( void RecursiveBuildAccessibilityTree(
const Microsoft::WRL::ComPtr<IAccessible> node, const Microsoft::WRL::ComPtr<IAccessible> node,
...@@ -119,6 +124,23 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter { ...@@ -119,6 +124,23 @@ class AccessibilityTreeFormatterWin : public AccessibilityTreeFormatter {
base::DictionaryValue* filtered_dict_result = nullptr) override; 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 // static
std::unique_ptr<AccessibilityTreeFormatter> std::unique_ptr<AccessibilityTreeFormatter>
AccessibilityTreeFormatter::Create() { AccessibilityTreeFormatter::Create() {
...@@ -126,6 +148,36 @@ AccessibilityTreeFormatter::Create() { ...@@ -126,6 +148,36 @@ AccessibilityTreeFormatter::Create() {
return std::make_unique<AccessibilityTreeFormatterWin>(); 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() { AccessibilityTreeFormatterWin::AccessibilityTreeFormatterWin() {
ui::win::CreateATLModuleIfNeeded(); ui::win::CreateATLModuleIfNeeded();
} }
......
...@@ -88,6 +88,7 @@ void BrowserAccessibilityManagerWin::FireFocusEvent( ...@@ -88,6 +88,7 @@ void BrowserAccessibilityManagerWin::FireFocusEvent(
BrowserAccessibilityManager::FireFocusEvent(node); BrowserAccessibilityManager::FireFocusEvent(node);
DCHECK(node); DCHECK(node);
FireWinAccessibilityEvent(EVENT_OBJECT_FOCUS, node); FireWinAccessibilityEvent(EVENT_OBJECT_FOCUS, node);
FireUiaAccessibilityEvent(UIA_AutomationFocusChangedEventId, node);
} }
void BrowserAccessibilityManagerWin::FireBlinkEvent( void BrowserAccessibilityManagerWin::FireBlinkEvent(
...@@ -196,30 +197,15 @@ void BrowserAccessibilityManagerWin::FireGeneratedEvent( ...@@ -196,30 +197,15 @@ void BrowserAccessibilityManagerWin::FireGeneratedEvent(
void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent( void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent(
LONG win_event_type, LONG win_event_type,
BrowserAccessibility* node) { BrowserAccessibility* node) {
if (!node->CanFireEvents()) if (::switches::IsExperimentalAccessibilityPlatformUIAEnabled())
return; return;
if (!ShouldFireEventForNode(node))
// 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; return;
HWND hwnd = root_delegate->AccessibilityGetAcceleratedWidget(); HWND hwnd = GetParentHWND();
if (!hwnd) if (!hwnd)
return; 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| // Pass the negation of this node's unique id in the |child_id|
// argument to NotifyWinEvent; the AT client will then call get_accChild // argument to NotifyWinEvent; the AT client will then call get_accChild
// on the HWND's accessibility object and pass it that same id, which // on the HWND's accessibility object and pass it that same id, which
...@@ -228,6 +214,18 @@ void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent( ...@@ -228,6 +214,18 @@ void BrowserAccessibilityManagerWin::FireWinAccessibilityEvent(
::NotifyWinEvent(win_event_type, hwnd, OBJID_CLIENT, child_id); ::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() { bool BrowserAccessibilityManagerWin::CanFireEvents() {
BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager(); BrowserAccessibilityDelegate* root_delegate = GetDelegateFromRootManager();
if (!root_delegate) if (!root_delegate)
...@@ -345,4 +343,29 @@ void BrowserAccessibilityManagerWin::OnAtomicUpdateFinished( ...@@ -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 } // namespace content
...@@ -45,6 +45,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin ...@@ -45,6 +45,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
BrowserAccessibility* node) override; BrowserAccessibility* node) override;
void FireWinAccessibilityEvent(LONG win_event, BrowserAccessibility* node); 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 // Track this object and post a VISIBLE_DATA_CHANGED notification when
// its container scrolls. // its container scrolls.
...@@ -61,6 +62,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin ...@@ -61,6 +62,8 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
bool root_changed, bool root_changed,
const std::vector<ui::AXTreeObserver::Change>& changes) override; const std::vector<ui::AXTreeObserver::Change>& changes) override;
bool ShouldFireEventForNode(BrowserAccessibility* node);
private: private:
// Give BrowserAccessibilityManager::Create access to our constructor. // Give BrowserAccessibilityManager::Create access to our constructor.
friend class BrowserAccessibilityManager; friend class BrowserAccessibilityManager;
......
...@@ -15,11 +15,12 @@ ...@@ -15,11 +15,12 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.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_restrictions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.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.h"
#include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
#include "content/browser/accessibility/browser_accessibility.h" #include "content/browser/accessibility/browser_accessibility.h"
#include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "content/browser/accessibility/browser_accessibility_state_impl.h"
...@@ -80,9 +81,9 @@ typedef AccessibilityTreeFormatter::PropertyFilter PropertyFilter; ...@@ -80,9 +81,9 @@ typedef AccessibilityTreeFormatter::PropertyFilter PropertyFilter;
typedef AccessibilityTreeFormatter::NodeFilter NodeFilter; typedef AccessibilityTreeFormatter::NodeFilter NodeFilter;
DumpAccessibilityTestBase::DumpAccessibilityTestBase() DumpAccessibilityTestBase::DumpAccessibilityTestBase()
: is_blink_pass_(false), : formatter_factory_(nullptr),
enable_accessibility_after_navigating_(false) { event_recorder_factory_(nullptr),
} enable_accessibility_after_navigating_(false) {}
DumpAccessibilityTestBase::~DumpAccessibilityTestBase() { DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {
} }
...@@ -100,8 +101,7 @@ void DumpAccessibilityTestBase::SetUpOnMainThread() { ...@@ -100,8 +101,7 @@ void DumpAccessibilityTestBase::SetUpOnMainThread() {
base::string16 base::string16
DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() { DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() {
std::unique_ptr<AccessibilityTreeFormatter> formatter( std::unique_ptr<AccessibilityTreeFormatter> formatter(formatter_factory_());
CreateAccessibilityTreeFormatter());
std::vector<PropertyFilter> property_filters; std::vector<PropertyFilter> property_filters;
property_filters.push_back( property_filters.push_back(
PropertyFilter(base::ASCIIToUTF16("*"), PropertyFilter::ALLOW)); PropertyFilter(base::ASCIIToUTF16("*"), PropertyFilter::ALLOW));
...@@ -188,29 +188,30 @@ void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( ...@@ -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( void DumpAccessibilityTestBase::RunTest(
const base::FilePath file_path, const char* file_dir) { const base::FilePath file_path, const char* file_dir) {
#if !defined(OS_ANDROID) // Get all the tree formatters; the test is run independently on each one.
// The blink tree is different on Android because we exclude inline auto formatters = AccessibilityTreeFormatter::GetTestPasses();
// text boxes, for performance. auto event_recorders = AccessibilityEventRecorder::GetTestPasses();
is_blink_pass_ = true; DCHECK(event_recorders.size() == formatters.size());
RunTestForPlatform(file_path, file_dir);
#endif int pass_count = formatters.size();
is_blink_pass_ = false; for (int pass = 0; pass < pass_count; ++pass) {
RunTestForPlatform(file_path, file_dir); 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( void DumpAccessibilityTestBase::RunTestForPlatform(
const base::FilePath file_path, const char* file_dir) { 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 // 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. // an object) because it makes test output change based on the mouse position.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/debug/leak_annotations.h" #include "base/debug/leak_annotations.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "build/build_config.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.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
...@@ -96,10 +97,6 @@ class DumpAccessibilityTestBase : public ContentBrowserTest { ...@@ -96,10 +97,6 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
std::vector<std::string>* wait_for, std::vector<std::string>* wait_for,
std::vector<std::string>* run_until); 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); void RunTestForPlatform(const base::FilePath file_path, const char* file_dir);
// The default property filters plus the property filters loaded from the test // The default property filters plus the property filters loaded from the test
...@@ -114,12 +111,13 @@ class DumpAccessibilityTestBase : public ContentBrowserTest { ...@@ -114,12 +111,13 @@ class DumpAccessibilityTestBase : public ContentBrowserTest {
ScopedLeakSanitizerDisabler lsan_disabler; ScopedLeakSanitizerDisabler lsan_disabler;
#endif #endif
// The current tree-formatter and event-recorder factories.
AccessibilityTreeFormatter::FormatterFactory formatter_factory_;
AccessibilityEventRecorder::EventRecorderFactory event_recorder_factory_;
// The current AccessibilityTreeFormatter. // The current AccessibilityTreeFormatter.
std::unique_ptr<AccessibilityTreeFormatter> formatter_; 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, // Whether we should enable accessibility after navigating to the page,
// otherwise we enable it first. // otherwise we enable it first.
bool enable_accessibility_after_navigating_; bool enable_accessibility_after_navigating_;
......
...@@ -104,9 +104,10 @@ std::vector<std::string> DumpAccessibilityEventsTest::Dump( ...@@ -104,9 +104,10 @@ std::vector<std::string> DumpAccessibilityEventsTest::Dump(
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
shell()->web_contents()); shell()->web_contents());
base::ProcessId pid = base::GetCurrentProcId(); base::ProcessId pid = base::GetCurrentProcId();
std::unique_ptr<AccessibilityEventRecorder> event_recorder( std::unique_ptr<AccessibilityEventRecorder> event_recorder =
AccessibilityEventRecorder::Create( event_recorder_factory_(
web_contents->GetRootBrowserAccessibilityManager(), pid)); web_contents->GetRootBrowserAccessibilityManager(), pid,
base::StringPiece{});
event_recorder->set_only_web_events(true); event_recorder->set_only_web_events(true);
// Save a copy of the accessibility tree (as a text dump); we'll // Save a copy of the accessibility tree (as a text dump); we'll
......
...@@ -130,8 +130,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase { ...@@ -130,8 +130,7 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase {
} }
std::vector<std::string> Dump(std::vector<std::string>& unused) override { std::vector<std::string> Dump(std::vector<std::string>& unused) override {
std::unique_ptr<AccessibilityTreeFormatter> formatter( std::unique_ptr<AccessibilityTreeFormatter> formatter(formatter_factory_());
CreateAccessibilityTreeFormatter());
formatter->SetPropertyFilters(property_filters_); formatter->SetPropertyFilters(property_filters_);
formatter->SetNodeFilters(node_filters_); formatter->SetNodeFilters(node_filters_);
base::string16 actual_contents_utf16; base::string16 actual_contents_utf16;
......
...@@ -34,6 +34,8 @@ jumbo_static_library("test_support") { ...@@ -34,6 +34,8 @@ jumbo_static_library("test_support") {
"../browser/accessibility/accessibility_event_recorder.cc", "../browser/accessibility/accessibility_event_recorder.cc",
"../browser/accessibility/accessibility_event_recorder.h", "../browser/accessibility/accessibility_event_recorder.h",
"../browser/accessibility/accessibility_event_recorder_mac.mm", "../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/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.cc",
"../browser/background_fetch/background_fetch_embedded_worker_test_helper.h", "../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 @@ ...@@ -3,6 +3,7 @@
@WIN-ALLOW:EVENT_OBJECT_FOCUS* @WIN-ALLOW:EVENT_OBJECT_FOCUS*
@WIN-ALLOW:EVENT_SYSTEM_ALERT* @WIN-ALLOW:EVENT_SYSTEM_ALERT*
@WIN-ALLOW:EVENT_OBJECT_LIVE* @WIN-ALLOW:EVENT_OBJECT_LIVE*
@WIN-ALLOW:UIA_AutomationFocusChangedEventId*
@MAC-DENY:* @MAC-DENY:*
@MAC-ALLOW:AXFocusedUIElementChanged* @MAC-ALLOW:AXFocusedUIElementChanged*
@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