Commit 2f29d8e8 authored by James Cook's avatar James Cook Committed by Commit Bot

a11y: Extract base class AXTreeSourceViews

AXTreeSourceAura and AXTreeSourceMus share code, so extract a common
base class.

Bug: 851578
Test: views_unittests, views_mus_unittests, unit_tests
Change-Id: I64a245dc6cdb97aaba8e2e05c0a6c7d008a38ef5
Reviewed-on: https://chromium-review.googlesource.com/1117918Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571662}
parent 0762c388
......@@ -190,3 +190,17 @@ TEST_F(AXTreeSourceAuraTest, Serialize) {
ASSERT_EQ(ax::mojom::Role::kTextField,
out_update2.nodes[text_field_update_index].role);
}
TEST_F(AXTreeSourceAuraTest, SerializeWindowSetsClipsChildren) {
AXTreeSourceAura ax_tree;
AuraAXTreeSerializer ax_serializer(&ax_tree);
AXAuraObjWrapper* widget_wrapper =
AXAuraObjCache::GetInstance()->GetOrCreate(widget_);
ui::AXNodeData node_data;
ax_tree.SerializeNode(widget_wrapper, &node_data);
EXPECT_EQ(ax::mojom::Role::kWindow, node_data.role);
bool clips_children = false;
EXPECT_TRUE(node_data.GetBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, &clips_children));
EXPECT_TRUE(clips_children);
}
......@@ -4,122 +4,24 @@
#include "chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h"
#include <stddef.h>
#include <vector>
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_view_obj_wrapper.h"
#include "ui/views/controls/webview/webview.h"
#if defined(TOOLKIT_VIEWS)
#include "ui/views/controls/webview/webview.h" // nogncheck
#endif
using views::AXAuraObjCache;
using views::AXAuraObjWrapper;
AXTreeSourceAura::AXTreeSourceAura() {
root_.reset(new AXRootObjWrapper());
}
AXTreeSourceAura::~AXTreeSourceAura() {
root_.reset();
}
bool AXTreeSourceAura::HandleAccessibleAction(const ui::AXActionData& action) {
int id = action.target_node_id;
AXTreeSourceAura::AXTreeSourceAura()
: desktop_root_(std::make_unique<AXRootObjWrapper>()) {}
// In Views, we only support setting the selection within a single node,
// not across multiple nodes like on the web.
if (action.action == ax::mojom::Action::kSetSelection) {
if (action.anchor_node_id != action.focus_node_id) {
NOTREACHED();
return false;
}
id = action.anchor_node_id;
}
AXAuraObjWrapper* obj = AXAuraObjCache::GetInstance()->Get(id);
if (obj)
return obj->HandleAccessibleAction(action);
return false;
}
bool AXTreeSourceAura::GetTreeData(ui::AXTreeData* tree_data) const {
tree_data->tree_id = 0;
tree_data->loaded = true;
tree_data->loading_progress = 1.0;
AXAuraObjWrapper* focus = AXAuraObjCache::GetInstance()->GetFocus();
if (focus)
tree_data->focus_id = focus->GetUniqueId().Get();
return true;
}
AXAuraObjWrapper* AXTreeSourceAura::GetRoot() const {
return root_.get();
}
AXAuraObjWrapper* AXTreeSourceAura::GetFromId(int32_t id) const {
if (id == root_->GetUniqueId().Get())
return root_.get();
return AXAuraObjCache::GetInstance()->Get(id);
}
AXTreeSourceAura::~AXTreeSourceAura() = default;
int32_t AXTreeSourceAura::GetId(AXAuraObjWrapper* node) const {
return node->GetUniqueId().Get();
views::AXAuraObjWrapper* AXTreeSourceAura::GetRoot() const {
return desktop_root_.get();
}
void AXTreeSourceAura::GetChildren(
AXAuraObjWrapper* node,
std::vector<AXAuraObjWrapper*>* out_children) const {
node->GetChildren(out_children);
}
AXAuraObjWrapper* AXTreeSourceAura::GetParent(AXAuraObjWrapper* node) const {
AXAuraObjWrapper* parent = node->GetParent();
if (!parent && node->GetUniqueId() != root_->GetUniqueId())
parent = root_.get();
return parent;
}
bool AXTreeSourceAura::IsValid(AXAuraObjWrapper* node) const {
return node != nullptr;
}
bool AXTreeSourceAura::IsEqual(AXAuraObjWrapper* node1,
AXAuraObjWrapper* node2) const {
if (!node1 || !node2)
return false;
return node1->GetUniqueId() == node2->GetUniqueId();
}
AXAuraObjWrapper* AXTreeSourceAura::GetNull() const {
return NULL;
}
void AXTreeSourceAura::SerializeNode(AXAuraObjWrapper* node,
void AXTreeSourceAura::SerializeNode(views::AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
node->Serialize(out_data);
// Convert the global coordinates reported by each AXAuraObjWrapper
// into parent-relative coordinates to be used in the accessibility
// tree. That way when any Window, Widget, or View moves (and fires
// a location changed event), its descendants all move relative to
// it by default.
AXAuraObjWrapper* parent = node->GetParent();
if (parent) {
ui::AXNodeData parent_data;
parent->Serialize(&parent_data);
out_data->location.Offset(-parent_data.location.OffsetFromOrigin());
out_data->offset_container_id = parent->GetUniqueId().Get();
}
AXTreeSourceViews::SerializeNode(node, out_data);
if (out_data->role == ax::mojom::Role::kWebView) {
views::View* view = static_cast<views::AXViewObjWrapper*>(node)->view();
......@@ -137,19 +39,3 @@ void AXTreeSourceAura::SerializeNode(AXAuraObjWrapper* node,
out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kClipsChildren, true);
}
}
std::string AXTreeSourceAura::ToString(AXAuraObjWrapper* root,
std::string prefix) {
ui::AXNodeData data;
root->Serialize(&data);
std::string output = prefix + data.ToString() + '\n';
std::vector<AXAuraObjWrapper*> children;
root->GetChildren(&children);
prefix += prefix[0];
for (size_t i = 0; i < children.size(); ++i)
output += ToString(children[i], prefix);
return output;
}
......@@ -5,59 +5,27 @@
#ifndef CHROME_BROWSER_UI_AURA_ACCESSIBILITY_AX_TREE_SOURCE_AURA_H_
#define CHROME_BROWSER_UI_AURA_ACCESSIBILITY_AX_TREE_SOURCE_AURA_H_
#include <stdint.h>
#include <map>
#include <memory>
#include "base/macros.h"
#include "chrome/browser/ui/aura/accessibility/ax_root_obj_wrapper.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_source.h"
namespace ui {
struct AXActionData;
} // namespace ui
namespace views {
class AXAuraObjWrapper;
} // namespace views
#include "ui/views/accessibility/ax_tree_source_views.h"
// This class exposes the views hierarchy as an accessibility tree permitting
// use with other accessibility classes.
class AXTreeSourceAura
: public ui::AXTreeSource<views::AXAuraObjWrapper*,
ui::AXNodeData,
ui::AXTreeData> {
class AXTreeSourceAura : public views::AXTreeSourceViews {
public:
AXTreeSourceAura();
~AXTreeSourceAura() override;
// Invoke actions on an Aura view.
bool HandleAccessibleAction(const ui::AXActionData& action);
// AXTreeSource implementation.
bool GetTreeData(ui::AXTreeData* data) const override;
// AXTreeSource:
views::AXAuraObjWrapper* GetRoot() const override;
views::AXAuraObjWrapper* GetFromId(int32_t id) const override;
int32_t GetId(views::AXAuraObjWrapper* node) const override;
void GetChildren(
views::AXAuraObjWrapper* node,
std::vector<views::AXAuraObjWrapper*>* out_children) const override;
views::AXAuraObjWrapper* GetParent(
views::AXAuraObjWrapper* node) const override;
bool IsValid(views::AXAuraObjWrapper* node) const override;
bool IsEqual(views::AXAuraObjWrapper* node1,
views::AXAuraObjWrapper* node2) const override;
views::AXAuraObjWrapper* GetNull() const override;
void SerializeNode(views::AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const override;
// Useful for debugging.
std::string ToString(views::AXAuraObjWrapper* root, std::string prefix);
private:
std::unique_ptr<AXRootObjWrapper> root_;
// A root object representing the entire desktop.
std::unique_ptr<AXRootObjWrapper> desktop_root_;
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceAura);
};
......
......@@ -574,6 +574,7 @@ jumbo_component("views") {
public += [
"accessibility/ax_aura_obj_cache.h",
"accessibility/ax_aura_obj_wrapper.h",
"accessibility/ax_tree_source_views.h",
"accessibility/ax_view_obj_wrapper.h",
"accessibility/ax_widget_obj_wrapper.h",
"accessibility/ax_window_obj_wrapper.h",
......@@ -606,6 +607,7 @@ jumbo_component("views") {
sources += [
"accessibility/ax_aura_obj_cache.cc",
"accessibility/ax_aura_obj_wrapper.cc",
"accessibility/ax_tree_source_views.cc",
"accessibility/ax_view_obj_wrapper.cc",
"accessibility/ax_widget_obj_wrapper.cc",
"accessibility/ax_window_obj_wrapper.cc",
......@@ -1074,6 +1076,7 @@ source_set("views_unittests_sources") {
if (use_aura) {
sources += [
"accessibility/ax_aura_obj_cache_unittest.cc",
"accessibility/ax_tree_source_views_unittest.cc",
"controls/native/native_view_host_aura_unittest.cc",
"touchui/touch_selection_menu_runner_views_unittest.cc",
"view_unittest_aura.cc",
......
// Copyright 2018 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/ax_tree_source_views.h"
#include <vector>
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
namespace views {
void AXTreeSourceViews::HandleAccessibleAction(const ui::AXActionData& action) {
int id = action.target_node_id;
// In Views, we only support setting the selection within a single node,
// not across multiple nodes like on the web.
if (action.action == ax::mojom::Action::kSetSelection) {
if (action.anchor_node_id != action.focus_node_id) {
NOTREACHED();
return;
}
id = action.anchor_node_id;
}
AXAuraObjWrapper* obj = AXAuraObjCache::GetInstance()->Get(id);
if (obj)
obj->HandleAccessibleAction(action);
}
bool AXTreeSourceViews::GetTreeData(ui::AXTreeData* tree_data) const {
tree_data->tree_id = 0;
tree_data->loaded = true;
tree_data->loading_progress = 1.0;
AXAuraObjWrapper* focus = AXAuraObjCache::GetInstance()->GetFocus();
if (focus)
tree_data->focus_id = focus->GetUniqueId().Get();
return true;
}
AXAuraObjWrapper* AXTreeSourceViews::GetFromId(int32_t id) const {
AXAuraObjWrapper* root = GetRoot();
// Root might not be in the cache.
if (id == root->GetUniqueId().Get())
return root;
return AXAuraObjCache::GetInstance()->Get(id);
}
int32_t AXTreeSourceViews::GetId(AXAuraObjWrapper* node) const {
return node->GetUniqueId().Get();
}
void AXTreeSourceViews::GetChildren(
AXAuraObjWrapper* node,
std::vector<AXAuraObjWrapper*>* out_children) const {
node->GetChildren(out_children);
}
AXAuraObjWrapper* AXTreeSourceViews::GetParent(AXAuraObjWrapper* node) const {
AXAuraObjWrapper* root = GetRoot();
// The root has no parent by definition.
if (node->GetUniqueId() == root->GetUniqueId())
return nullptr;
AXAuraObjWrapper* parent = node->GetParent();
// A top-level widget doesn't have a parent, so return the root.
if (!parent)
return root;
return parent;
}
bool AXTreeSourceViews::IsValid(AXAuraObjWrapper* node) const {
return node != nullptr;
}
bool AXTreeSourceViews::IsEqual(AXAuraObjWrapper* node1,
AXAuraObjWrapper* node2) const {
return node1 && node2 && node1->GetUniqueId() == node2->GetUniqueId();
}
AXAuraObjWrapper* AXTreeSourceViews::GetNull() const {
return nullptr;
}
void AXTreeSourceViews::SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
node->Serialize(out_data);
// Converts the global coordinates reported by each AXAuraObjWrapper
// into parent-relative coordinates to be used in the accessibility
// tree. That way when any Window, Widget, or View moves (and fires
// a location changed event), its descendants all move relative to
// it by default.
AXAuraObjWrapper* parent = node->GetParent();
if (!parent)
return;
ui::AXNodeData parent_data;
parent->Serialize(&parent_data);
out_data->location.Offset(-parent_data.location.OffsetFromOrigin());
out_data->offset_container_id = parent->GetUniqueId().Get();
}
std::string AXTreeSourceViews::ToString(AXAuraObjWrapper* root,
std::string prefix) {
ui::AXNodeData data;
root->Serialize(&data);
std::string output = prefix + data.ToString() + '\n';
std::vector<AXAuraObjWrapper*> children;
root->GetChildren(&children);
prefix += prefix[0];
for (AXAuraObjWrapper* child : children)
output += ToString(child, prefix);
return output;
}
AXTreeSourceViews::AXTreeSourceViews() = default;
AXTreeSourceViews::~AXTreeSourceViews() = default;
} // namespace views
// Copyright 2018 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 UI_VIEWS_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_
#define UI_VIEWS_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_
#include "base/macros.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_source.h"
#include "ui/views/views_export.h"
namespace ui {
struct AXActionData;
}
namespace views {
class AXAuraObjWrapper;
// This class exposes the views hierarchy as an accessibility tree permitting
// use with other accessibility classes. Subclasses must implement GetRoot().
// The root can be an existing object in the Widget/View hierarchy or a new node
// (for example to create the "desktop" node for the extension API call
// chrome.automation.getDesktop()).
class VIEWS_EXPORT AXTreeSourceViews
: public ui::
AXTreeSource<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData> {
public:
// Invokes an action on an Aura object.
void HandleAccessibleAction(const ui::AXActionData& action);
// AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override;
// GetRoot() must be implemented by subclasses.
AXAuraObjWrapper* GetFromId(int32_t id) const override;
int32_t GetId(AXAuraObjWrapper* node) const override;
void GetChildren(AXAuraObjWrapper* node,
std::vector<AXAuraObjWrapper*>* out_children) const override;
AXAuraObjWrapper* GetParent(AXAuraObjWrapper* node) const override;
bool IsValid(AXAuraObjWrapper* node) const override;
bool IsEqual(AXAuraObjWrapper* node1, AXAuraObjWrapper* node2) const override;
AXAuraObjWrapper* GetNull() const override;
void SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const override;
// Useful for debugging.
std::string ToString(views::AXAuraObjWrapper* root, std::string prefix);
protected:
AXTreeSourceViews();
~AXTreeSourceViews() override;
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViews);
};
} // namespace views
#endif // UI_VIEWS_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_
// Copyright 2018 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/ax_tree_source_views.h"
#include <vector>
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/controls/label.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
namespace views {
namespace {
// TestAXTreeSourceViews provides a root object for testing.
class TestAXTreeSourceViews : public AXTreeSourceViews {
public:
TestAXTreeSourceViews(AXAuraObjWrapper* root) : root_(root) {}
~TestAXTreeSourceViews() override = default;
// AXTreeSource:
AXAuraObjWrapper* GetRoot() const override { return root_; }
private:
AXAuraObjWrapper* root_;
DISALLOW_COPY_AND_ASSIGN(TestAXTreeSourceViews);
};
class AXTreeSourceViewsTest : public ViewsTestBase {
public:
AXTreeSourceViewsTest() = default;
~AXTreeSourceViewsTest() override = default;
// testing::Test:
void SetUp() override {
ViewsTestBase::SetUp();
widget_ = std::make_unique<Widget>();
Widget::InitParams params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(11, 22, 333, 444);
params.context = GetContext();
widget_->Init(params);
widget_->SetContentsView(new View());
label1_ = new Label(base::ASCIIToUTF16("Label 1"));
label1_->SetBounds(1, 1, 111, 111);
widget_->GetContentsView()->AddChildView(label1_);
label2_ = new Label(base::ASCIIToUTF16("Label 2"));
label2_->SetBounds(2, 2, 222, 222);
widget_->GetContentsView()->AddChildView(label2_);
}
void TearDown() override {
widget_.reset();
ViewsTestBase::TearDown();
}
std::unique_ptr<Widget> widget_;
Label* label1_ = nullptr; // Owned by views hierarchy.
Label* label2_ = nullptr; // Owned by views hierarchy.
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViewsTest);
};
TEST_F(AXTreeSourceViewsTest, Basics) {
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
// Start the tree at the Widget's contents view.
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
TestAXTreeSourceViews tree(root);
EXPECT_EQ(root, tree.GetRoot());
// The root has no parent.
EXPECT_FALSE(tree.GetParent(root));
// The root has the right children.
std::vector<AXAuraObjWrapper*> children;
tree.GetChildren(root, &children);
ASSERT_EQ(2u, children.size());
// The labels are the children.
AXAuraObjWrapper* label1 = children[0];
AXAuraObjWrapper* label2 = children[1];
EXPECT_EQ(label1, cache->GetOrCreate(label1_));
EXPECT_EQ(label2, cache->GetOrCreate(label2_));
// The parents is correct.
EXPECT_EQ(root, tree.GetParent(label1));
EXPECT_EQ(root, tree.GetParent(label2));
// IDs match the ones in the cache.
EXPECT_EQ(root->GetUniqueId().Get(), tree.GetId(root));
EXPECT_EQ(label1->GetUniqueId().Get(), tree.GetId(label1));
EXPECT_EQ(label2->GetUniqueId().Get(), tree.GetId(label2));
// Reverse ID lookups work.
EXPECT_EQ(root, tree.GetFromId(root->GetUniqueId().Get()));
EXPECT_EQ(label1, tree.GetFromId(label1->GetUniqueId().Get()));
EXPECT_EQ(label2, tree.GetFromId(label2->GetUniqueId().Get()));
// Validity.
EXPECT_TRUE(tree.IsValid(root));
EXPECT_FALSE(tree.IsValid(nullptr));
// Comparisons.
EXPECT_TRUE(tree.IsEqual(label1, label1));
EXPECT_FALSE(tree.IsEqual(label1, label2));
EXPECT_FALSE(tree.IsEqual(label1, nullptr));
EXPECT_FALSE(tree.IsEqual(nullptr, label1));
// Null pointers is the null value.
EXPECT_EQ(nullptr, tree.GetNull());
}
} // namespace
} // namespace views
......@@ -4,12 +4,8 @@
#include "ui/views/mus/ax_tree_source_mus.h"
#include <vector>
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
namespace views {
......@@ -20,60 +16,14 @@ AXTreeSourceMus::AXTreeSourceMus(AXAuraObjWrapper* root) : root_(root) {
AXTreeSourceMus::~AXTreeSourceMus() = default;
bool AXTreeSourceMus::GetTreeData(ui::AXTreeData* tree_data) const {
tree_data->tree_id = 0;
tree_data->loaded = true;
tree_data->loading_progress = 1.0;
// TODO(jamescook): Support focus in more than one app.
AXAuraObjWrapper* focus = AXAuraObjCache::GetInstance()->GetFocus();
if (focus)
tree_data->focus_id = focus->GetUniqueId().Get();
return true;
}
AXAuraObjWrapper* AXTreeSourceMus::GetRoot() const {
return root_;
}
AXAuraObjWrapper* AXTreeSourceMus::GetFromId(int32_t id) const {
return AXAuraObjCache::GetInstance()->Get(id);
}
int32_t AXTreeSourceMus::GetId(AXAuraObjWrapper* node) const {
return node->GetUniqueId().Get();
}
void AXTreeSourceMus::GetChildren(
AXAuraObjWrapper* node,
std::vector<AXAuraObjWrapper*>* out_children) const {
node->GetChildren(out_children);
}
AXAuraObjWrapper* AXTreeSourceMus::GetParent(AXAuraObjWrapper* node) const {
// Stop at |root_| even if it has a views parent.
if (node->GetUniqueId() == root_->GetUniqueId())
return nullptr;
return node->GetParent();
}
bool AXTreeSourceMus::IsValid(AXAuraObjWrapper* node) const {
return node != nullptr;
}
bool AXTreeSourceMus::IsEqual(AXAuraObjWrapper* node1,
AXAuraObjWrapper* node2) const {
return node1 && node2 && node1->GetUniqueId() == node2->GetUniqueId();
}
AXAuraObjWrapper* AXTreeSourceMus::GetNull() const {
return nullptr;
}
void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
node->Serialize(out_data);
if (IsEqual(node, root_)) {
node->Serialize(out_data);
// Root is a ClientView with an offset from the containing Widget. However,
// the ClientView in the host (browser) already has an offset from its
// Widget, so the root should start at (0,0).
......@@ -82,17 +32,7 @@ void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
return;
}
// Convert the global coordinates reported by each AXAuraObjWrapper
// into parent-relative coordinates to be used in the accessibility
// tree. That way when any Window, Widget, or View moves (and fires
// a location changed event), its descendants all move relative to
// it by default.
AXAuraObjWrapper* parent = node->GetParent();
DCHECK(parent);
ui::AXNodeData parent_data;
parent->Serialize(&parent_data);
out_data->location.Offset(-parent_data.location.OffsetFromOrigin());
out_data->offset_container_id = parent->GetUniqueId().Get();
AXTreeSourceViews::SerializeNode(node, out_data);
}
} // namespace views
......@@ -6,9 +6,7 @@
#define UI_VIEWS_MUS_AX_TREE_SOURCE_MUS_H_
#include "base/macros.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_source.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
#include "ui/views/mus/mus_export.h"
namespace views {
......@@ -19,26 +17,14 @@ class AXAuraObjWrapper;
// use with other accessibility classes. Only used for out-of-process views
// apps (e.g. Chrome OS shortcut_viewer app). The browser process uses
// AXTreeSourceAura.
// TODO(jamescook): Extract a base class and share with AXTreeSourceAura.
class VIEWS_MUS_EXPORT AXTreeSourceMus
: public ui::
AXTreeSource<AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData> {
class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
public:
// |root| must outlive this object.
explicit AXTreeSourceMus(AXAuraObjWrapper* root);
~AXTreeSourceMus() override;
// AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override;
AXAuraObjWrapper* GetRoot() const override;
AXAuraObjWrapper* GetFromId(int32_t id) const override;
int32_t GetId(AXAuraObjWrapper* node) const override;
void GetChildren(AXAuraObjWrapper* node,
std::vector<AXAuraObjWrapper*>* out_children) const override;
AXAuraObjWrapper* GetParent(AXAuraObjWrapper* node) const override;
bool IsValid(AXAuraObjWrapper* node) const override;
bool IsEqual(AXAuraObjWrapper* node1, AXAuraObjWrapper* node2) const override;
AXAuraObjWrapper* GetNull() const override;
void SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const override;
......
......@@ -35,12 +35,9 @@ class AXTreeSourceMusTest : public ViewsTestBase {
params.context = GetContext();
widget_->Init(params);
widget_->SetContentsView(new View());
label1_ = new Label(base::ASCIIToUTF16("Label 1"));
label1_->SetBounds(1, 1, 111, 111);
widget_->GetContentsView()->AddChildView(label1_);
label2_ = new Label(base::ASCIIToUTF16("Label 2"));
label2_->SetBounds(2, 2, 222, 222);
widget_->GetContentsView()->AddChildView(label2_);
label_ = new Label(base::ASCIIToUTF16("Label"));
label_->SetBounds(1, 1, 111, 111);
widget_->GetContentsView()->AddChildView(label_);
}
void TearDown() override {
......@@ -49,63 +46,12 @@ class AXTreeSourceMusTest : public ViewsTestBase {
}
std::unique_ptr<Widget> widget_;
Label* label1_ = nullptr; // Owned by views hierarchy.
Label* label2_ = nullptr; // Owned by views hierarchy.
Label* label_ = nullptr; // Owned by views hierarchy.
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMusTest);
};
TEST_F(AXTreeSourceMusTest, Basics) {
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
// Start the tree at the Widget's contents view.
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
AXTreeSourceMus tree(root);
EXPECT_EQ(root, tree.GetRoot());
// The root has no parent.
EXPECT_FALSE(tree.GetParent(root));
// The root has the right children.
std::vector<AXAuraObjWrapper*> children;
tree.GetChildren(root, &children);
ASSERT_EQ(2u, children.size());
// The labels are the children.
AXAuraObjWrapper* label1 = children[0];
AXAuraObjWrapper* label2 = children[1];
EXPECT_EQ(label1, cache->GetOrCreate(label1_));
EXPECT_EQ(label2, cache->GetOrCreate(label2_));
// The parents is correct.
EXPECT_EQ(root, tree.GetParent(label1));
EXPECT_EQ(root, tree.GetParent(label2));
// IDs match the ones in the cache.
EXPECT_EQ(root->GetUniqueId().Get(), tree.GetId(root));
EXPECT_EQ(label1->GetUniqueId().Get(), tree.GetId(label1));
EXPECT_EQ(label2->GetUniqueId().Get(), tree.GetId(label2));
// Reverse ID lookups work.
EXPECT_EQ(root, tree.GetFromId(root->GetUniqueId().Get()));
EXPECT_EQ(label1, tree.GetFromId(label1->GetUniqueId().Get()));
EXPECT_EQ(label2, tree.GetFromId(label2->GetUniqueId().Get()));
// Validity.
EXPECT_TRUE(tree.IsValid(root));
EXPECT_FALSE(tree.IsValid(nullptr));
// Comparisons.
EXPECT_TRUE(tree.IsEqual(label1, label1));
EXPECT_FALSE(tree.IsEqual(label1, label2));
EXPECT_FALSE(tree.IsEqual(label1, nullptr));
EXPECT_FALSE(tree.IsEqual(nullptr, label1));
// Null pointers is the null value.
EXPECT_EQ(nullptr, tree.GetNull());
}
TEST_F(AXTreeSourceMusTest, Serialize) {
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
......@@ -122,7 +68,7 @@ TEST_F(AXTreeSourceMusTest, Serialize) {
EXPECT_EQ(-1, node_data.offset_container_id);
// Serialize a child.
tree.SerializeNode(cache->GetOrCreate(label1_), &node_data);
tree.SerializeNode(cache->GetOrCreate(label_), &node_data);
// Child has relative position with the root as the container.
EXPECT_EQ(gfx::RectF(1, 1, 111, 111), node_data.location);
......
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