Commit 02cb40dc authored by Katie D's avatar Katie D Committed by Commit Bot

Use ARC++ windows in Chrome accessibility tree.

This completes work from go/a11y-arc++-window-mapping,
but does not yet remove the restriction that we only look at the
interesting subtree.

That restriction is still valid because we only want one
root node ID. If we assume that there is only one, we can remove
this restriction.

Bug: 891483
Change-Id: Ib9581be294de88c6ed4c4e9934536859edc9b4e7
Reviewed-on: https://chromium-review.googlesource.com/c/1319858
Commit-Queue: Katie Dektar <katie@chromium.org>
Reviewed-by: default avatarYuki Awano <yawano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609400}
parent 67b185c6
...@@ -139,19 +139,18 @@ void AccessibilityNodeInfoDataWrapper::PopulateAXRole( ...@@ -139,19 +139,18 @@ void AccessibilityNodeInfoDataWrapper::PopulateAXRole(
// need additional information contained only in the CollectionInfo. The // need additional information contained only in the CollectionInfo. The
// CollectionInfo should be an ancestor of this node. // CollectionInfo should be an ancestor of this node.
AXCollectionInfoData* collection_info = nullptr; AXCollectionInfoData* collection_info = nullptr;
for (AXNodeInfoData* container = node_ptr_; container;) { for (const ArcAccessibilityInfoData* container =
if (!container) static_cast<const ArcAccessibilityInfoData*>(this);
container;) {
if (!container || !container->IsNode())
break; break;
if (container->collection_info.get()) { if (container->IsNode() && container->GetNode()->collection_info.get()) {
collection_info = container->collection_info.get(); collection_info = container->GetNode()->collection_info.get();
break; break;
} }
ArcAccessibilityInfoData* container_data = container =
tree_source_->GetParent(tree_source_->GetFromId(container->id)); tree_source_->GetParent(tree_source_->GetFromId(container->GetId()));
if (!container_data->IsNode())
break;
container = container_data->GetNode();
} }
if (collection_info) { if (collection_info) {
...@@ -387,6 +386,10 @@ void AccessibilityNodeInfoDataWrapper::Serialize( ...@@ -387,6 +386,10 @@ void AccessibilityNodeInfoDataWrapper::Serialize(
local_bounds.width(), local_bounds.width(),
local_bounds.height()); local_bounds.height());
} }
// TODO(katie): Try using offset_container_id to make bounds calculations
// more efficient. If this is the child of the root, set the
// offset_container_id to be the root. Otherwise, set it to the first node
// child of the root.
// Integer properties. // Integer properties.
int32_t val; int32_t val;
......
...@@ -239,6 +239,7 @@ TEST_F(ArcAccessibilityHelperBridgeTest, TaskAndAXTreeLifecycle) { ...@@ -239,6 +239,7 @@ TEST_F(ArcAccessibilityHelperBridgeTest, TaskAndAXTreeLifecycle) {
// Same task id, different package name. // Same task id, different package name.
event2->node_data.clear(); event2->node_data.clear();
event2->node_data.push_back(arc::mojom::AccessibilityNodeInfoData::New()); event2->node_data.push_back(arc::mojom::AccessibilityNodeInfoData::New());
event2->source_id = 3;
event2->node_data[0]->id = 3; event2->node_data[0]->id = 3;
event2->node_data[0]->string_properties = event2->node_data[0]->string_properties =
base::flat_map<arc::mojom::AccessibilityStringProperty, std::string>(); base::flat_map<arc::mojom::AccessibilityStringProperty, std::string>();
......
...@@ -31,7 +31,7 @@ AXTreeSourceArc::AXTreeSourceArc(Delegate* delegate) ...@@ -31,7 +31,7 @@ AXTreeSourceArc::AXTreeSourceArc(Delegate* delegate)
: current_tree_serializer_(new AXTreeArcSerializer(this)), : current_tree_serializer_(new AXTreeArcSerializer(this)),
root_id_(-1), root_id_(-1),
window_id_(-1), window_id_(-1),
focused_node_id_(-1), focused_id_(-1),
is_notification_(false), is_notification_(false),
delegate_(delegate) {} delegate_(delegate) {}
...@@ -61,10 +61,30 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -61,10 +61,30 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
continue; continue;
auto it = event_data->node_data[i]->int_list_properties->find( auto it = event_data->node_data[i]->int_list_properties->find(
AXIntListProperty::CHILD_NODE_IDS); AXIntListProperty::CHILD_NODE_IDS);
if (it != event_data->node_data[i]->int_list_properties->end()) { if (it == event_data->node_data[i]->int_list_properties->end())
all_children_map[event_data->node_data[i]->id] = it->second; continue;
all_children_map[event_data->node_data[i]->id] = it->second;
for (size_t j = 0; j < it->second.size(); ++j)
all_parent_map[it->second[j]] = event_data->node_data[i]->id;
}
if (event_data->window_data) {
for (size_t i = 0; i < event_data->window_data->size(); ++i) {
int32_t window_id = event_data->window_data->at(i)->window_id;
int32_t root_node_id = event_data->window_data->at(i)->root_node_id;
if (root_node_id) {
all_parent_map[root_node_id] = window_id;
all_children_map[window_id] = {root_node_id};
}
if (!event_data->window_data->at(i)->int_list_properties)
continue;
auto it = event_data->window_data->at(i)->int_list_properties->find(
mojom::AccessibilityWindowIntListProperty::CHILD_WINDOW_IDS);
if (it == event_data->window_data->at(i)->int_list_properties->end())
continue;
all_children_map[window_id].insert(all_children_map[window_id].begin(),
it->second.begin(), it->second.end());
for (size_t j = 0; j < it->second.size(); ++j) for (size_t j = 0; j < it->second.size(); ++j)
all_parent_map[it->second[j]] = event_data->node_data[i]->id; all_parent_map[it->second[j]] = window_id;
} }
} }
...@@ -103,8 +123,19 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -103,8 +123,19 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
tree_map_[id] = tree_map_[id] =
std::make_unique<AccessibilityNodeInfoDataWrapper>(this, node); std::make_unique<AccessibilityNodeInfoDataWrapper>(this, node);
if (tree_map_[id]->IsFocused()) { if (tree_map_[id]->IsFocused())
focused_node_id_ = id; focused_id_ = id;
}
if (event_data->window_data) {
for (size_t i = 0; i < event_data->window_data->size(); ++i) {
int32_t id = event_data->window_data->at(i)->window_id;
// Only map nodes in the parent_map and the root.
// This avoids adding other subtrees that are not interesting.
if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
continue;
AXWindowInfoData* window = event_data->window_data->at(i).get();
tree_map_[id] =
std::make_unique<AccessibilityWindowInfoDataWrapper>(this, window);
} }
} }
...@@ -117,6 +148,14 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -117,6 +148,14 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
continue; continue;
cached_computed_bounds_[id] = ComputeEnclosingBounds(tree_map_[id].get()); cached_computed_bounds_[id] = ComputeEnclosingBounds(tree_map_[id].get());
} }
if (event_data->window_data) {
for (int i = event_data->window_data->size() - 1; i >= 0; --i) {
int32_t id = event_data->window_data->at(i)->window_id;
if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
continue;
cached_computed_bounds_[id] = ComputeEnclosingBounds(tree_map_[id].get());
}
}
ExtensionMsg_AccessibilityEventBundleParams event_bundle; ExtensionMsg_AccessibilityEventBundleParams event_bundle;
event_bundle.tree_id = tree_id(); event_bundle.tree_id = tree_id();
...@@ -147,10 +186,25 @@ void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data, ...@@ -147,10 +186,25 @@ void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data,
bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const { bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const {
data->tree_id = tree_id(); data->tree_id = tree_id();
if (focused_node_id_ >= 0) if (focused_id_ >= 0) {
data->focus_id = focused_node_id_; data->focus_id = focused_id_;
else if (root_id_ >= 0) } else if (root_id_ >= 0) {
data->focus_id = root_id_; ArcAccessibilityInfoData* root = GetRoot();
if (root->IsNode()) {
data->focus_id = root_id_;
} else {
std::vector<ArcAccessibilityInfoData*> children;
root->GetChildren(&children);
if (!children.empty()) {
for (size_t i = 0; i < children.size(); ++i) {
if (children[i]->IsNode()) {
data->focus_id = children[i]->GetId();
break;
}
}
}
}
}
return true; return true;
} }
...@@ -261,9 +315,11 @@ void AXTreeSourceArc::SerializeNode(ArcAccessibilityInfoData* info_data, ...@@ -261,9 +315,11 @@ void AXTreeSourceArc::SerializeNode(ArcAccessibilityInfoData* info_data,
int32_t id = info_data->GetId(); int32_t id = info_data->GetId();
out_data->id = id; out_data->id = id;
// TODO(katie): this may not hold true with Windows. it's probably the root // If the node is the root, or if the node's parent is the root window,
// window's root node which is a kRootWebArea. // the role should be rootWebArea.
if (id == root_id_) if (info_data->IsNode() && id == root_id_)
out_data->role = ax::mojom::Role::kRootWebArea;
else if (info_data->IsNode() && parent_map_.at(id) == root_id_)
out_data->role = ax::mojom::Role::kRootWebArea; out_data->role = ax::mojom::Role::kRootWebArea;
else else
info_data->PopulateAXRole(out_data); info_data->PopulateAXRole(out_data);
...@@ -275,46 +331,44 @@ const gfx::Rect AXTreeSourceArc::GetBounds(ArcAccessibilityInfoData* info_data, ...@@ -275,46 +331,44 @@ const gfx::Rect AXTreeSourceArc::GetBounds(ArcAccessibilityInfoData* info_data,
aura::Window* active_window) const { aura::Window* active_window) const {
DCHECK_NE(root_id_, -1); DCHECK_NE(root_id_, -1);
gfx::Rect node_bounds = info_data->GetBounds(); gfx::Rect info_data_bounds = info_data->GetBounds();
if (active_window && info_data->GetId() == root_id_) {
// Top level window returns its bounds in dip.
aura::Window* toplevel_window = active_window->GetToplevelWindow();
float scale = toplevel_window->layer()->device_scale_factor();
views::Widget* widget =
views::Widget::GetWidgetForNativeView(active_window);
DCHECK(widget);
DCHECK(widget->widget_delegate());
DCHECK(widget->widget_delegate()->GetContentsView());
const gfx::Rect bounds =
widget->widget_delegate()->GetContentsView()->GetBoundsInScreen();
// Bounds of root node is relative to its container, i.e. contents view
// (ShellSurfaceBase).
node_bounds.Offset(
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.x())),
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.y())));
// On Android side, content is rendered without considering height of
// caption bar, e.g. content is rendered at y:0 instead of y:32 where 32 is
// height of caption bar. Add back height of caption bar here.
if (widget->IsMaximized()) {
node_bounds.Offset(
0, static_cast<int>(scale *
static_cast<float>(widget->non_client_view()
->frame_view()
->GetBoundsForClientView()
.y())));
}
return node_bounds; if (!active_window) {
gfx::Rect root_bounds = GetRoot()->GetBounds();
info_data_bounds.Offset(-1 * root_bounds.x(), -1 * root_bounds.y());
return info_data_bounds;
} }
// Bounds of non-root node is relative to its tree's root. // TODO(katie): offset_container_id should work and we shouldn't have to
gfx::Rect root_bounds = GetFromId(root_id_)->GetBounds(); // go into this code path for each node.
node_bounds.Offset(-1 * root_bounds.x(), -1 * root_bounds.y()); aura::Window* toplevel_window = active_window->GetToplevelWindow();
return node_bounds; float scale = toplevel_window->layer()->device_scale_factor();
views::Widget* widget = views::Widget::GetWidgetForNativeView(active_window);
DCHECK(widget);
DCHECK(widget->widget_delegate());
DCHECK(widget->widget_delegate()->GetContentsView());
const gfx::Rect bounds =
widget->widget_delegate()->GetContentsView()->GetBoundsInScreen();
// Bounds of root node is relative to its container, i.e. contents view
// (ShellSurfaceBase).
info_data_bounds.Offset(
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.x())),
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.y())));
// On Android side, content is rendered without considering height of
// caption bar, e.g. content is rendered at y:0 instead of y:32 where 32 is
// height of caption bar. Add back height of caption bar here.
if (widget->IsMaximized()) {
info_data_bounds.Offset(
0, static_cast<int>(scale *
static_cast<float>(widget->non_client_view()
->frame_view()
->GetBoundsForClientView()
.y())));
}
return info_data_bounds;
} }
gfx::Rect AXTreeSourceArc::ComputeEnclosingBounds( gfx::Rect AXTreeSourceArc::ComputeEnclosingBounds(
...@@ -363,7 +417,7 @@ void AXTreeSourceArc::Reset() { ...@@ -363,7 +417,7 @@ void AXTreeSourceArc::Reset() {
cached_computed_bounds_.clear(); cached_computed_bounds_.clear();
current_tree_serializer_.reset(new AXTreeArcSerializer(this)); current_tree_serializer_.reset(new AXTreeArcSerializer(this));
root_id_ = -1; root_id_ = -1;
focused_node_id_ = -1; focused_id_ = -1;
extensions::AutomationEventRouter* router = extensions::AutomationEventRouter* router =
extensions::AutomationEventRouter::GetInstance(); extensions::AutomationEventRouter::GetInstance();
if (!router) if (!router)
......
...@@ -62,10 +62,10 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*, ...@@ -62,10 +62,10 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*,
// TODO(katie): should these be "friended" or "protected" instead? // TODO(katie): should these be "friended" or "protected" instead?
ArcAccessibilityInfoData* GetRoot() const override; ArcAccessibilityInfoData* GetRoot() const override;
ArcAccessibilityInfoData* GetFromId(int32_t id) const override; ArcAccessibilityInfoData* GetFromId(int32_t id) const override;
void SerializeNode(ArcAccessibilityInfoData* node, void SerializeNode(ArcAccessibilityInfoData* info_data,
ui::AXNodeData* out_data) const override; ui::AXNodeData* out_data) const override;
ArcAccessibilityInfoData* GetParent( ArcAccessibilityInfoData* GetParent(
ArcAccessibilityInfoData* node) const override; ArcAccessibilityInfoData* info_data) const override;
// Returns bounds of a node which can be passed to AXNodeData.location. Bounds // Returns bounds of a node which can be passed to AXNodeData.location. Bounds
// are returned in the following coordinates depending on whether it's root or // are returned in the following coordinates depending on whether it's root or
...@@ -74,7 +74,7 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*, ...@@ -74,7 +74,7 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*,
// - Non-root node is relative to the root node of this tree. // - Non-root node is relative to the root node of this tree.
// //
// focused_window is nullptr for notification. // focused_window is nullptr for notification.
const gfx::Rect GetBounds(ArcAccessibilityInfoData* node, const gfx::Rect GetBounds(ArcAccessibilityInfoData* info_data,
aura::Window* focused_window) const; aura::Window* focused_window) const;
bool is_notification() { return is_notification_; } bool is_notification() { return is_notification_; }
...@@ -84,21 +84,22 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*, ...@@ -84,21 +84,22 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*,
class FocusStealer; class FocusStealer;
// AXTreeSource overrides. // AXTreeSource overrides.
int32_t GetId(ArcAccessibilityInfoData* node) const override; int32_t GetId(ArcAccessibilityInfoData* info_data) const override;
void GetChildren( void GetChildren(
ArcAccessibilityInfoData* node, ArcAccessibilityInfoData* info_data,
std::vector<ArcAccessibilityInfoData*>* out_children) const override; std::vector<ArcAccessibilityInfoData*>* out_children) const override;
bool IsValid(ArcAccessibilityInfoData* node) const override; bool IsValid(ArcAccessibilityInfoData* info_data) const override;
bool IsEqual(ArcAccessibilityInfoData* node1, bool IsEqual(ArcAccessibilityInfoData* info_data1,
ArcAccessibilityInfoData* node2) const override; ArcAccessibilityInfoData* info_data2) const override;
ArcAccessibilityInfoData* GetNull() const override; ArcAccessibilityInfoData* GetNull() const override;
// Computes the smallest rect that encloses all of the descendants of |node|. // Computes the smallest rect that encloses all of the descendants of
gfx::Rect ComputeEnclosingBounds(ArcAccessibilityInfoData* node) const; // |info_data|.
gfx::Rect ComputeEnclosingBounds(ArcAccessibilityInfoData* info_data) const;
// Helper to recursively compute bounds for |node|. Returns true if non-empty // Helper to recursively compute bounds for |info_data|. Returns true if
// bounds were encountered. // non-empty bounds were encountered.
void ComputeEnclosingBoundsInternal(ArcAccessibilityInfoData* node, void ComputeEnclosingBoundsInternal(ArcAccessibilityInfoData* info_data,
gfx::Rect& computed_bounds) const; gfx::Rect& computed_bounds) const;
// AXHostDelegate overrides. // AXHostDelegate overrides.
...@@ -115,7 +116,7 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*, ...@@ -115,7 +116,7 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*,
std::unique_ptr<AXTreeArcSerializer> current_tree_serializer_; std::unique_ptr<AXTreeArcSerializer> current_tree_serializer_;
int32_t root_id_; int32_t root_id_;
int32_t window_id_; int32_t window_id_;
int32_t focused_node_id_; int32_t focused_id_;
bool is_notification_; bool is_notification_;
// A delegate that handles accessibility actions on behalf of this tree. The // A delegate that handles accessibility actions on behalf of this tree. The
......
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