Commit e6afefd2 authored by Brian Liu Xu's avatar Brian Liu Xu Committed by Commit Bot

Make TreeView descendants explorable with assistive technologies

This changelist includes the following to make |TreeView| explorable:

- Replaces the |kInvisible| state with the |kIgnored| state for unshown
  root nodes. This allows IAccessible2 clients to enter the tree to
  access individual tree items.

- Bridges accessibility hit testing from Views to virtual views so that
  pointer-based assistive technologies can access individual tree items
  using screen coordinates.

             items inside tree views.

AX-Relnotes: In Views, assistive technologies can now hit test tree
Bug: 811277
Change-Id: I56788354aa51b3598ff1afc96cb7214b12d04a85
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134415
Commit-Queue: Brian Liu Xu <brx@microsoft.com>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770855}
parent 0d249e03
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/containers/adapters.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_action_data.h"
...@@ -419,6 +420,22 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync( ...@@ -419,6 +420,22 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(
if (!view()->HitTestPoint(point)) if (!view()->HitTestPoint(point))
return nullptr; return nullptr;
// Check if the point is within any of the virtual children of this view.
// AXVirtualView's HitTestSync is a recursive function that will return the
// deepest child, since it does not support relative bounds.
if (!virtual_children().empty()) {
// Search the greater indices first, since they're on top in the z-order.
for (const std::unique_ptr<AXVirtualView>& child :
base::Reversed(virtual_children())) {
gfx::NativeViewAccessible result =
child->HitTestSync(screen_physical_pixel_x, screen_physical_pixel_y);
if (result)
return result;
}
// If it's not inside any of our virtual children, it's inside this view.
return GetNativeObject();
}
// Check if the point is within any of the immediate children of this // Check if the point is within any of the immediate children of this
// view. We don't have to search further because AXPlatformNode will // view. We don't have to search further because AXPlatformNode will
// do a recursive hit test if we return anything other than |this| or NULL. // do a recursive hit test if we return anything other than |this| or NULL.
...@@ -426,6 +443,10 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync( ...@@ -426,6 +443,10 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(
const auto is_point_in_child = [point, v](View* child) { const auto is_point_in_child = [point, v](View* child) {
if (!child->GetVisible()) if (!child->GetVisible())
return false; return false;
ui::AXNodeData child_data;
child->GetViewAccessibility().GetAccessibleNodeData(&child_data);
if (child_data.HasState(ax::mojom::State::kInvisible))
return false;
gfx::Point point_in_child_coords = point; gfx::Point point_in_child_coords = point;
v->ConvertPointToTarget(v, child, &point_in_child_coords); v->ConvertPointToTarget(v, child, &point_in_child_coords);
return child->HitTestPoint(point_in_child_coords); return child->HitTestPoint(point_in_child_coords);
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <utility> #include <utility>
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/views/controls/focusable_border.h" #include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/highlight_path_generator.h"
...@@ -155,6 +157,12 @@ void FocusRing::OnPaint(gfx::Canvas* canvas) { ...@@ -155,6 +157,12 @@ void FocusRing::OnPaint(gfx::Canvas* canvas) {
} }
} }
void FocusRing::GetAccessibleNodeData(ui::AXNodeData* node_data) {
// Mark the focus ring in the accessibility tree as invisible so that it will
// not be accessed by assistive technologies.
node_data->AddState(ax::mojom::State::kInvisible);
}
void FocusRing::OnViewFocused(View* view) { void FocusRing::OnViewFocused(View* view) {
RefreshLayer(); RefreshLayer();
} }
......
...@@ -77,6 +77,7 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver { ...@@ -77,6 +77,7 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
void ViewHierarchyChanged( void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) override; const ViewHierarchyChangedDetails& details) override;
void OnPaint(gfx::Canvas* canvas) override; void OnPaint(gfx::Canvas* canvas) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
// ViewObserver: // ViewObserver:
void OnViewFocused(View* view) override; void OnViewFocused(View* view) override;
......
...@@ -968,7 +968,8 @@ void TreeView::PopulateAccessibilityData(InternalNode* node, ...@@ -968,7 +968,8 @@ void TreeView::PopulateAccessibilityData(InternalNode* node,
gfx::Rect node_bounds = GetBackgroundBoundsForNode(node); gfx::Rect node_bounds = GetBackgroundBoundsForNode(node);
data->relative_bounds.bounds = gfx::RectF(node_bounds); data->relative_bounds.bounds = gfx::RectF(node_bounds);
} else { } else {
data->AddState(ax::mojom::State::kInvisible); data->AddState(node != &root_ || root_shown_ ? ax::mojom::State::kInvisible
: ax::mojom::State::kIgnored);
} }
} }
......
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