diff options
Diffstat (limited to 'chromium/ui/views/accessibility')
12 files changed, 221 insertions, 28 deletions
diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.cc b/chromium/ui/views/accessibility/accessibility_alert_window.cc index 4c5b0e47f60..9afdb5263f9 100644 --- a/chromium/ui/views/accessibility/accessibility_alert_window.cc +++ b/chromium/ui/views/accessibility/accessibility_alert_window.cc @@ -29,7 +29,7 @@ AccessibilityAlertWindow::AccessibilityAlertWindow(aura::Window* parent, AccessibilityAlertWindow::~AccessibilityAlertWindow() = default; void AccessibilityAlertWindow::HandleAlert(const std::string& alert_string) { - if (!alert_window_->parent()) + if (!alert_window_ || !alert_window_->parent()) return; alert_window_->SetTitle(base::UTF8ToUTF16(alert_string)); diff --git a/chromium/ui/views/accessibility/accessibility_alert_window.h b/chromium/ui/views/accessibility/accessibility_alert_window.h index 999c55e9f78..5895a714ea8 100644 --- a/chromium/ui/views/accessibility/accessibility_alert_window.h +++ b/chromium/ui/views/accessibility/accessibility_alert_window.h @@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/gtest_prod_util.h" #include "base/scoped_observer.h" #include "ui/aura/env.h" #include "ui/aura/env_observer.h" @@ -35,6 +36,9 @@ class VIEWS_EXPORT AccessibilityAlertWindow : public aura::EnvObserver { void HandleAlert(const std::string& alert_string); private: + FRIEND_TEST_ALL_PREFIXES(AccessibilityAlertWindowTest, HandleAlert); + FRIEND_TEST_ALL_PREFIXES(AccessibilityAlertWindowTest, OnWillDestroyEnv); + // aura::EnvObserver: void OnWillDestroyEnv() override; diff --git a/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc b/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc new file mode 100644 index 00000000000..60af94effee --- /dev/null +++ b/chromium/ui/views/accessibility/accessibility_alert_window_unittest.cc @@ -0,0 +1,83 @@ +// Copyright 2020 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 "ui/views/accessibility/accessibility_alert_window.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_enums.mojom.h" +#include "ui/aura/window.h" +#include "ui/compositor/layer_type.h" +#include "ui/views/accessibility/ax_aura_obj_cache.h" +#include "ui/views/accessibility/ax_aura_obj_wrapper.h" +#include "ui/views/test/views_test_base.h" + +namespace views { + +class FakeAXAuraObjCacheDelegate : public AXAuraObjCache::Delegate { + public: + FakeAXAuraObjCacheDelegate() = default; + FakeAXAuraObjCacheDelegate(const FakeAXAuraObjCacheDelegate&) = delete; + FakeAXAuraObjCacheDelegate& operator=(const FakeAXAuraObjCacheDelegate&) = + delete; + ~FakeAXAuraObjCacheDelegate() override = default; + + void OnChildWindowRemoved(AXAuraObjWrapper* parent) override {} + void OnEvent(AXAuraObjWrapper* aura_obj, + ax::mojom::Event event_type) override { + if (event_type == ax::mojom::Event::kAlert) + count_++; + } + + int count() { return count_; } + void set_count(int count) { count_ = count; } + + private: + int count_ = 0; +}; + +class AccessibilityAlertWindowTest : public ViewsTestBase { + public: + AccessibilityAlertWindowTest() = default; + AccessibilityAlertWindowTest(const AccessibilityAlertWindowTest&) = delete; + AccessibilityAlertWindowTest& operator=(const AccessibilityAlertWindowTest&) = + delete; + ~AccessibilityAlertWindowTest() override = default; + + protected: + void SetUp() override { + ViewsTestBase::SetUp(); + + parent_ = std::make_unique<aura::Window>(nullptr); + parent_->Init(ui::LAYER_SOLID_COLOR); + } + + std::unique_ptr<aura::Window> parent_; + AXAuraObjCache cache; +}; + +TEST_F(AccessibilityAlertWindowTest, HandleAlert) { + FakeAXAuraObjCacheDelegate delegate; + cache.SetDelegate(&delegate); + + AccessibilityAlertWindow window(parent_.get(), &cache); + + window.HandleAlert("test"); + EXPECT_EQ(1, delegate.count()); + + delegate.set_count(0); + window.OnWillDestroyEnv(); + + window.HandleAlert("test"); + EXPECT_EQ(0, delegate.count()); +} + +TEST_F(AccessibilityAlertWindowTest, OnWillDestroyEnv) { + AccessibilityAlertWindow window(parent_.get(), &cache); + window.OnWillDestroyEnv(); + + EXPECT_FALSE(window.observer_.IsObservingSources()); + EXPECT_FALSE(window.alert_window_); +} + +} // namespace views diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.h b/chromium/ui/views/accessibility/ax_tree_source_views.h index 37317b530b5..a867cd971bc 100644 --- a/chromium/ui/views/accessibility/ax_tree_source_views.h +++ b/chromium/ui/views/accessibility/ax_tree_source_views.h @@ -61,6 +61,8 @@ class VIEWS_EXPORT AXTreeSourceViews // Useful for debugging. std::string ToString(views::AXAuraObjWrapper* root, std::string prefix); + const ui::AXTreeID tree_id_for_test() const { return tree_id_; } + private: // The top-level object to use for the AX tree. See class comment. AXAuraObjWrapper* const root_ = nullptr; diff --git a/chromium/ui/views/accessibility/ax_virtual_view.cc b/chromium/ui/views/accessibility/ax_virtual_view.cc index 060d4a77c65..cc9f8aae5fe 100644 --- a/chromium/ui/views/accessibility/ax_virtual_view.cc +++ b/chromium/ui/views/accessibility/ax_virtual_view.cc @@ -21,6 +21,7 @@ #include "ui/base/ui_base_types.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/accessibility/view_ax_platform_node_delegate.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -284,7 +285,7 @@ gfx::NativeViewAccessible AXVirtualView::ChildAtIndex(int index) { return nullptr; } -#if !defined(OS_MACOSX) +#if !defined(OS_APPLE) gfx::NativeViewAccessible AXVirtualView::GetNSWindow() { NOTREACHED(); return nullptr; @@ -386,7 +387,10 @@ gfx::NativeViewAccessible AXVirtualView::GetFocus() { } ui::AXPlatformNode* AXVirtualView::GetFromNodeID(int32_t id) { - // TODO(nektar): Implement. + AXVirtualView* virtual_view = GetFromId(id); + if (virtual_view) { + return virtual_view->ax_platform_node(); + } return nullptr; } @@ -423,6 +427,18 @@ gfx::AcceleratedWidget AXVirtualView::GetTargetForNativeAccessibilityEvent() { return gfx::kNullAcceleratedWidget; } +base::Optional<bool> AXVirtualView::GetTableHasColumnOrRowHeaderNode() const { + return GetDelegate()->GetTableHasColumnOrRowHeaderNode(); +} + +std::vector<int32_t> AXVirtualView::GetColHeaderNodeIds() const { + return GetDelegate()->GetColHeaderNodeIds(); +} + +std::vector<int32_t> AXVirtualView::GetColHeaderNodeIds(int col_index) const { + return GetDelegate()->GetColHeaderNodeIds(col_index); +} + bool AXVirtualView::IsIgnored() const { return GetData().IsIgnored(); } @@ -473,6 +489,12 @@ View* AXVirtualView::GetOwnerView() const { return nullptr; } +ViewAXPlatformNodeDelegate* AXVirtualView::GetDelegate() const { + DCHECK(GetOwnerView()); + return static_cast<ViewAXPlatformNodeDelegate*>( + &GetOwnerView()->GetViewAccessibility()); +} + AXVirtualViewWrapper* AXVirtualView::GetOrCreateWrapper( views::AXAuraObjCache* cache) { #if defined(USE_AURA) diff --git a/chromium/ui/views/accessibility/ax_virtual_view.h b/chromium/ui/views/accessibility/ax_virtual_view.h index 6b1f9eeda4a..299d106a01b 100644 --- a/chromium/ui/views/accessibility/ax_virtual_view.h +++ b/chromium/ui/views/accessibility/ax_virtual_view.h @@ -40,6 +40,7 @@ namespace views { class AXAuraObjCache; class View; class ViewAccessibility; +class ViewAXPlatformNodeDelegate; // Implements a virtual view that is used only for accessibility. // @@ -99,6 +100,8 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase { } AXVirtualView* virtual_parent_view() { return virtual_parent_view_; } + ui::AXPlatformNode* ax_platform_node() { return ax_platform_node_; } + // Returns true if |view| is contained within the hierarchy of this // AXVirtualView, even as an indirect descendant. Will return true if |view| // is also this AXVirtualView. @@ -153,10 +156,16 @@ class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase { bool IsOffscreen() const override; const ui::AXUniqueId& GetUniqueId() const override; gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override; + base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const override; + std::vector<int32_t> GetColHeaderNodeIds() const override; + std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override; // Gets the real View that owns our shallowest virtual ancestor,, if any. View* GetOwnerView() const; + // Gets the view platform delegate if exists, otherwise nullptr. + ViewAXPlatformNodeDelegate* GetDelegate() const; + // Gets or creates a wrapper suitable for use with tree sources. AXVirtualViewWrapper* GetOrCreateWrapper(views::AXAuraObjCache* cache); diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc index 35dce74a77b..00b72e939ed 100644 --- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc +++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc @@ -213,7 +213,7 @@ void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent( ax_platform_node_->NotifyAccessibilityEvent(event_type); } -#if defined(OS_MACOSX) +#if defined(OS_APPLE) void ViewAXPlatformNodeDelegate::AnnounceText(const base::string16& text) { ax_platform_node_->AnnounceText(text); } @@ -345,6 +345,10 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) { return nullptr; } +bool ViewAXPlatformNodeDelegate::HasModalDialog() const { + return GetChildWidgets().is_tab_modal_showing; +} + gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNSWindow() { NOTREACHED(); return nullptr; @@ -377,6 +381,17 @@ bool ViewAXPlatformNodeDelegate::IsLeaf() const { return ViewAccessibility::IsLeaf() || AXPlatformNodeDelegateBase::IsLeaf(); } +bool ViewAXPlatformNodeDelegate::IsToplevelBrowserWindow() { + // Note: only used on Desktop Linux. Other platforms don't have an application + // node so this would never return true. + ui::AXNodeData data = GetData(); + if (data.role != ax::mojom::Role::kWindow) + return false; + + AXPlatformNodeDelegate* parent = GetParentDelegate(); + return parent && parent->GetData().role == ax::mojom::Role::kApplication; +} + gfx::Rect ViewAXPlatformNodeDelegate::GetBoundsRect( const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, @@ -525,6 +540,46 @@ const ui::AXUniqueId& ViewAXPlatformNodeDelegate::GetUniqueId() const { return ViewAccessibility::GetUniqueId(); } +base::Optional<bool> +ViewAXPlatformNodeDelegate::GetTableHasColumnOrRowHeaderNode() const { + if (!GetAncestorTableView()) + return false; + return !GetAncestorTableView()->visible_columns().empty(); +} + +std::vector<int32_t> ViewAXPlatformNodeDelegate::GetColHeaderNodeIds() const { + std::vector<int32_t> col_header_ids; + if (!virtual_children().empty()) { + for (const std::unique_ptr<AXVirtualView>& header_cell : + virtual_children().front()->children()) { + const ui::AXNodeData& header_data = header_cell->GetData(); + if (header_data.role == ax::mojom::Role::kColumnHeader) { + col_header_ids.push_back(header_data.id); + } + } + } + return col_header_ids; +} + +std::vector<int32_t> ViewAXPlatformNodeDelegate::GetColHeaderNodeIds( + int col_index) const { + std::vector<int32_t> columns = GetColHeaderNodeIds(); + if (columns.size() <= size_t{col_index}) { + return {}; + } + return {columns[col_index]}; +} + +TableView* ViewAXPlatformNodeDelegate::GetAncestorTableView() const { + ui::AXNodeData data; + view()->GetViewAccessibility().GetAccessibleNodeData(&data); + + if (!ui::IsTableLike(data.role)) + return nullptr; + + return static_cast<TableView*>(view()); +} + bool ViewAXPlatformNodeDelegate::IsOrderedSetItem() const { const ui::AXNodeData& data = GetData(); return (view()->GetGroup() >= 0) || diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h index 8d3ddca5571..923e54ac9bb 100644 --- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h +++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h @@ -17,6 +17,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" #include "ui/views/accessibility/view_accessibility.h" +#include "ui/views/controls/table/table_view.h" #include "ui/views/widget/widget_observer.h" namespace ui { @@ -45,7 +46,7 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility, // ViewAccessibility: gfx::NativeViewAccessible GetNativeObject() const override; void NotifyAccessibilityEvent(ax::mojom::Event event_type) override; -#if defined(OS_MACOSX) +#if defined(OS_APPLE) void AnnounceText(const base::string16& text) override; #endif void FireFocusAfterMenuClose() override; @@ -58,11 +59,13 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility, const ui::AXNodeData& GetData() const override; int GetChildCount() const override; gfx::NativeViewAccessible ChildAtIndex(int index) override; + bool HasModalDialog() const override; gfx::NativeViewAccessible GetNSWindow() override; gfx::NativeViewAccessible GetNativeViewAccessible() override; gfx::NativeViewAccessible GetParent() override; bool IsChildOfLeaf() const override; bool IsLeaf() const override; + bool IsToplevelBrowserWindow() override; gfx::Rect GetBoundsRect( const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, @@ -81,6 +84,9 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility, bool IsMinimized() const override; // Also in |ViewAccessibility|. const ui::AXUniqueId& GetUniqueId() const override; + base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const override; + std::vector<int32_t> GetColHeaderNodeIds() const override; + std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override; // Ordered-set-like and item-like nodes. bool IsOrderedSetItem() const override; @@ -106,6 +112,9 @@ class ViewAXPlatformNodeDelegate : public ViewAccessibility, ChildWidgetsResult GetChildWidgets() const; + // Gets the real TableView, otherwise nullptr. + TableView* GetAncestorTableView() const; + // We own this, but it is reference-counted on some platforms so we can't use // a unique_ptr. It is destroyed in the destructor. ui::AXPlatformNode* ax_platform_node_; diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc index 3f8100365a7..b7bf51dc1a8 100644 --- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc +++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_auralinux_unittest.cc @@ -36,6 +36,10 @@ TEST_F(ViewAXPlatformNodeDelegateAuraLinuxTest, TextfieldAccessibility) { textfield->SetAccessibleName(base::UTF8ToUTF16("Name")); content->AddChildView(textfield); + ASSERT_EQ(0, atk_object_get_n_accessible_children( + textfield->GetNativeViewAccessible())) + << "Text fields should be leaf nodes on this platform, otherwise no " + "descendants will be recognized by assistive software."; AtkText* atk_text = ATK_TEXT(textfield->GetNativeViewAccessible()); ASSERT_NE(nullptr, atk_text); diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc index cf4bc178a1d..51fd747d4bc 100644 --- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc +++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc @@ -40,6 +40,28 @@ class TestButton : public Button { ~TestButton() override = default; }; +class TestAXEventObserver : public AXEventObserver { + public: + explicit TestAXEventObserver(AXAuraObjCache* cache) : cache_(cache) { + AXEventManager::Get()->AddObserver(this); + } + TestAXEventObserver(const TestAXEventObserver&) = delete; + TestAXEventObserver& operator=(const TestAXEventObserver&) = delete; + ~TestAXEventObserver() override { + AXEventManager::Get()->RemoveObserver(this); + } + + // AXEventObserver: + void OnViewEvent(View* view, ax::mojom::Event event_type) override { + std::vector<AXAuraObjWrapper*> out_children; + AXAuraObjWrapper* ax_obj = cache_->GetOrCreate(view->GetWidget()); + ax_obj->GetChildren(&out_children); + } + + private: + AXAuraObjCache* cache_; +}; + } // namespace class ViewAXPlatformNodeDelegateTest : public ViewsTestBase { @@ -412,28 +434,6 @@ class DerivedTestView : public View { void OnBlur() override { SetVisible(false); } }; -class TestAXEventObserver : public AXEventObserver { - public: - explicit TestAXEventObserver(AXAuraObjCache* cache) : cache_(cache) { - AXEventManager::Get()->AddObserver(this); - } - TestAXEventObserver(const TestAXEventObserver&) = delete; - TestAXEventObserver& operator=(const TestAXEventObserver&) = delete; - ~TestAXEventObserver() override { - AXEventManager::Get()->RemoveObserver(this); - } - - // AXEventObserver: - void OnViewEvent(View* view, ax::mojom::Event event_type) override { - std::vector<AXAuraObjWrapper*> out_children; - AXAuraObjWrapper* ax_obj = cache_->GetOrCreate(view->GetWidget()); - ax_obj->GetChildren(&out_children); - } - - private: - AXAuraObjCache* cache_; -}; - using ViewAccessibilityTest = ViewsTestBase; // Check if the destruction of the widget ends successfully if |view|'s diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc index 00ffe077cd7..460b47fe4b2 100644 --- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc +++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc @@ -89,6 +89,11 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, TextfieldAccessibility) { content_accessible->get_accChild(child_index, &textfield_dispatch)); ASSERT_EQ(S_OK, textfield_dispatch.As(&textfield_accessible)); + ASSERT_EQ(S_OK, textfield_accessible->get_accChildCount(&child_count)); + EXPECT_EQ(0, child_count) + << "Text fields should be leaf nodes on this platform, otherwise no " + "descendants will be recognized by assistive software."; + ScopedBstr name; ScopedVariant childid_self(CHILDID_SELF); ASSERT_EQ(S_OK, diff --git a/chromium/ui/views/accessibility/views_ax_tree_manager.h b/chromium/ui/views/accessibility/views_ax_tree_manager.h index 5212d3d2a44..324af2d35b5 100644 --- a/chromium/ui/views/accessibility/views_ax_tree_manager.h +++ b/chromium/ui/views/accessibility/views_ax_tree_manager.h @@ -87,7 +87,7 @@ class VIEWS_EXPORT ViewsAXTreeManager : public ui::AXTreeManager, ui::AXNode* GetRootAsAXNode() const override; ui::AXNode* GetParentNodeFromParentTreeAsAXNode() const override; - // AXActionHandler implementation. + // AXActionHandlerBase implementation. void PerformAction(const ui::AXActionData& data) override; // AXEventObserver implementation. |