Commit 8b86c254 authored by Muyuan Li's avatar Muyuan Li Committed by Commit Bot

Reland: Refactor AXSnapshotNodeAndroid into mojo.

This is a reland of CL:
https://chromium-review.googlesource.com/c/chromium/src/+/1014464
which was reverted by:
https://chromium-review.googlesource.com/c/chromium/src/+/1043187
due to compilation error.

Original commit message:
> Refactor AXSnapshotNodeAndroid into mojo.
>
> Test: browser_tests --gtest_filter=ArcVoiceInteractionArcHomeServiceTest.*
TBR=dmazzoni@chromium.org,sky@chromium.org,dcheng@chromium.org

Change-Id: Ieca4bf35f3aa913683e8d1ce34160731317a797f
Reviewed-on: https://chromium-review.googlesource.com/1045487Reviewed-by: default avatarMuyuan Li <muyuanli@chromium.org>
Commit-Queue: Muyuan Li <muyuanli@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556983}
parent 865fffd1
...@@ -33,6 +33,7 @@ source_set("chromeos") { ...@@ -33,6 +33,7 @@ source_set("chromeos") {
"//chromeos:vm_applications_apps_proto", "//chromeos:vm_applications_apps_proto",
"//components/policy/proto", "//components/policy/proto",
"//content/app/resources", "//content/app/resources",
"//ui/accessibility/mojom",
"//ui/chromeos/resources", "//ui/chromeos/resources",
"//ui/chromeos/strings", "//ui/chromeos/strings",
"//ui/resources", "//ui/resources",
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#include "components/arc/connection_holder.h" #include "components/arc/connection_holder.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "ui/accessibility/platform/ax_snapshot_node_android_platform.h" #include "ui/accessibility/ax_assistant_structure.h"
#include "ui/accessibility/mojom/ax_assistant_structure.mojom.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/dip_util.h"
...@@ -49,30 +50,33 @@ constexpr base::TimeDelta kWizardCompletedTimeout = ...@@ -49,30 +50,33 @@ constexpr base::TimeDelta kWizardCompletedTimeout =
base::TimeDelta::FromMinutes(1); base::TimeDelta::FromMinutes(1);
mojom::VoiceInteractionStructurePtr CreateVoiceInteractionStructure( mojom::VoiceInteractionStructurePtr CreateVoiceInteractionStructure(
const ui::AXSnapshotNodeAndroid& view_structure) { const ui::AssistantTree& tree,
const ui::AssistantNode& node) {
auto structure = mojom::VoiceInteractionStructure::New(); auto structure = mojom::VoiceInteractionStructure::New();
structure->text = view_structure.text; structure->text = node.text;
structure->text_size = view_structure.text_size; structure->text_size = node.text_size;
structure->bold = view_structure.bold; structure->bold = node.bold;
structure->italic = view_structure.italic; structure->italic = node.italic;
structure->underline = view_structure.underline; structure->underline = node.underline;
structure->line_through = view_structure.line_through; structure->line_through = node.line_through;
structure->color = view_structure.color; structure->color = node.color;
structure->bgcolor = view_structure.bgcolor; structure->bgcolor = node.bgcolor;
structure->role = view_structure.role; structure->role = node.role;
structure->class_name = view_structure.class_name; structure->class_name = node.class_name;
structure->rect = view_structure.rect; structure->rect = node.rect;
if (view_structure.has_selection) { if (node.selection.has_value()) {
structure->selection = gfx::Range(view_structure.start_selection, structure->selection =
view_structure.end_selection); gfx::Range(node.selection->start(), node.selection->end());
} }
for (auto& child : view_structure.children) for (int child : node.children_indices) {
structure->children.push_back(CreateVoiceInteractionStructure(*child)); structure->children.push_back(
CreateVoiceInteractionStructure(tree, *tree.nodes[child]));
}
return structure; return structure;
} }
...@@ -97,8 +101,10 @@ void RequestVoiceInteractionStructureCallback( ...@@ -97,8 +101,10 @@ void RequestVoiceInteractionStructureCallback(
title_node->rect = gfx::Rect(bounds.size()); title_node->rect = gfx::Rect(bounds.size());
title_node->class_name = "android.view.dummy.WebTitle"; title_node->class_name = "android.view.dummy.WebTitle";
title_node->text = title; title_node->text = title;
auto assistant_tree = ui::CreateAssistantTree(update, false);
title_node->children.push_back(CreateVoiceInteractionStructure( title_node->children.push_back(CreateVoiceInteractionStructure(
*ui::AXSnapshotNodeAndroid::Create(update, false))); *assistant_tree, *assistant_tree->nodes.front()));
root->children.push_back(std::move(title_node)); root->children.push_back(std::move(title_node));
std::move(callback).Run(std::move(root)); std::move(callback).Run(std::move(root));
} }
...@@ -334,8 +340,9 @@ void ArcVoiceInteractionArcHomeService::OnVoiceInteractionOobeSetupComplete() { ...@@ -334,8 +340,9 @@ void ArcVoiceInteractionArcHomeService::OnVoiceInteractionOobeSetupComplete() {
// static // static
mojom::VoiceInteractionStructurePtr mojom::VoiceInteractionStructurePtr
ArcVoiceInteractionArcHomeService::CreateVoiceInteractionStructureForTesting( ArcVoiceInteractionArcHomeService::CreateVoiceInteractionStructureForTesting(
const ui::AXSnapshotNodeAndroid& view_structure) { const ui::AssistantTree& tree,
return CreateVoiceInteractionStructure(view_structure); const ui::AssistantNode& node) {
return CreateVoiceInteractionStructure(tree, node);
} }
} // namespace arc } // namespace arc
...@@ -20,8 +20,9 @@ class BrowserContext; ...@@ -20,8 +20,9 @@ class BrowserContext;
} // namespace content } // namespace content
namespace ui { namespace ui {
struct AXSnapshotNodeAndroid; struct AssistantTree;
} // ui struct AssistantNode;
} // namespace ui
namespace arc { namespace arc {
...@@ -66,8 +67,8 @@ class ArcVoiceInteractionArcHomeService ...@@ -66,8 +67,8 @@ class ArcVoiceInteractionArcHomeService
void OnVoiceInteractionOobeSetupComplete() override; void OnVoiceInteractionOobeSetupComplete() override;
static mojom::VoiceInteractionStructurePtr static mojom::VoiceInteractionStructurePtr
CreateVoiceInteractionStructureForTesting( CreateVoiceInteractionStructureForTesting(const ui::AssistantTree& tree,
const ui::AXSnapshotNodeAndroid& view_structure); const ui::AssistantNode& node);
void set_assistant_started_timeout_for_testing( void set_assistant_started_timeout_for_testing(
const base::TimeDelta& timeout) { const base::TimeDelta& timeout) {
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
#include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/interactive_test_utils.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "ui/accessibility/ax_assistant_structure.h"
#include "ui/accessibility/ax_tree_update.h" #include "ui/accessibility/ax_tree_update.h"
#include "ui/accessibility/platform/ax_snapshot_node_android_platform.h"
namespace arc { namespace arc {
...@@ -63,9 +63,11 @@ class ArcVoiceInteractionArcHomeServiceTest : public InProcessBrowserTest { ...@@ -63,9 +63,11 @@ class ArcVoiceInteractionArcHomeServiceTest : public InProcessBrowserTest {
base::Unretained(&waiter)), base::Unretained(&waiter)),
ui::kAXModeComplete); ui::kAXModeComplete);
waiter.Wait(); waiter.Wait();
auto node = ui::AXSnapshotNodeAndroid::Create(waiter.snapshot(), false); std::unique_ptr<ui::AssistantTree> tree =
ui::CreateAssistantTree(waiter.snapshot(), false);
return ArcVoiceInteractionArcHomeService:: return ArcVoiceInteractionArcHomeService::
CreateVoiceInteractionStructureForTesting(*node); CreateVoiceInteractionStructureForTesting(*tree, *tree->nodes.front());
} }
private: private:
......
...@@ -2152,6 +2152,8 @@ jumbo_source_set("browser") { ...@@ -2152,6 +2152,8 @@ jumbo_source_set("browser") {
"//media", "//media",
"//media/capture/content/android", "//media/capture/content/android",
"//media/capture/video/android", "//media/capture/video/android",
"//ui/accessibility:ax_assistant",
"//ui/accessibility/mojom",
"//ui/android", "//ui/android",
"//ui/compositor", "//ui/compositor",
] ]
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
#include "content/common/accessibility_messages.h" #include "content/common/accessibility_messages.h"
#include "content/public/common/content_client.h" #include "content/public/common/content_client.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/accessibility/ax_assistant_structure.h"
#include "ui/accessibility/ax_role_properties.h" #include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/platform/ax_android_constants.h" #include "ui/accessibility/platform/ax_android_constants.h"
#include "ui/accessibility/platform/ax_snapshot_node_android_platform.h"
#include "ui/accessibility/platform/ax_unique_id.h" #include "ui/accessibility/platform/ax_unique_id.h"
namespace { namespace {
...@@ -265,7 +265,7 @@ bool BrowserAccessibilityAndroid::IsHierarchical() const { ...@@ -265,7 +265,7 @@ bool BrowserAccessibilityAndroid::IsHierarchical() const {
} }
bool BrowserAccessibilityAndroid::IsLink() const { bool BrowserAccessibilityAndroid::IsLink() const {
return ui::AXSnapshotNodeAndroid::AXRoleIsLink(GetRole()); return ui::AXRoleIsLink(GetRole());
} }
bool BrowserAccessibilityAndroid::IsMultiLine() const { bool BrowserAccessibilityAndroid::IsMultiLine() const {
...@@ -370,8 +370,8 @@ bool BrowserAccessibilityAndroid::CanOpenPopup() const { ...@@ -370,8 +370,8 @@ bool BrowserAccessibilityAndroid::CanOpenPopup() const {
} }
const char* BrowserAccessibilityAndroid::GetClassName() const { const char* BrowserAccessibilityAndroid::GetClassName() const {
return ui::AXSnapshotNodeAndroid::AXRoleToAndroidClassName( return ui::AXRoleToAndroidClassName(GetRole(),
GetRole(), PlatformGetParent() != nullptr); PlatformGetParent() != nullptr);
} }
base::string16 BrowserAccessibilityAndroid::GetText() const { base::string16 BrowserAccessibilityAndroid::GetText() const {
...@@ -421,7 +421,7 @@ base::string16 BrowserAccessibilityAndroid::GetText() const { ...@@ -421,7 +421,7 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
if (text.empty() && (IsLink() || GetRole() == ax::mojom::Role::kImage) && if (text.empty() && (IsLink() || GetRole() == ax::mojom::Role::kImage) &&
!HasExplicitlyEmptyName()) { !HasExplicitlyEmptyName()) {
base::string16 url = GetString16Attribute(ax::mojom::StringAttribute::kUrl); base::string16 url = GetString16Attribute(ax::mojom::StringAttribute::kUrl);
text = ui::AXSnapshotNodeAndroid::AXUrlBaseText(url); text = ui::AXUrlBaseText(url);
} }
return text; return text;
......
...@@ -41,8 +41,9 @@ ...@@ -41,8 +41,9 @@
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "jni/WebContentsImpl_jni.h" #include "jni/WebContentsImpl_jni.h"
#include "net/android/network_library.h" #include "net/android/network_library.h"
#include "ui/accessibility/ax_assistant_structure.h"
#include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_snapshot_node_android_platform.h" #include "ui/accessibility/mojom/ax_assistant_structure.mojom.h"
#include "ui/android/overscroll_refresh_handler.h" #include "ui/android/overscroll_refresh_handler.h"
#include "ui/android/window_android.h" #include "ui/android/window_android.h"
#include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/android/java_bitmap.h"
...@@ -90,7 +91,8 @@ void SmartClipCallback(const ScopedJavaGlobalRef<jobject>& callback, ...@@ -90,7 +91,8 @@ void SmartClipCallback(const ScopedJavaGlobalRef<jobject>& callback,
ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_CreateJavaAXSnapshot( ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_CreateJavaAXSnapshot(
JNIEnv* env, JNIEnv* env,
const ui::AXSnapshotNodeAndroid* node, const ui::AssistantTree* tree,
const ui::AssistantNode* node,
bool is_root) { bool is_root) {
ScopedJavaLocalRef<jstring> j_text = ScopedJavaLocalRef<jstring> j_text =
ConvertUTF16ToJavaString(env, node->text); ConvertUTF16ToJavaString(env, node->text);
...@@ -103,15 +105,16 @@ ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_CreateJavaAXSnapshot( ...@@ -103,15 +105,16 @@ ScopedJavaLocalRef<jobject> JNI_WebContentsImpl_CreateJavaAXSnapshot(
node->text_size, node->bold, node->italic, node->underline, node->text_size, node->bold, node->italic, node->underline,
node->line_through, j_class); node->line_through, j_class);
if (node->has_selection) { if (node->selection.has_value()) {
Java_WebContentsImpl_setAccessibilitySnapshotSelection( Java_WebContentsImpl_setAccessibilitySnapshotSelection(
env, j_node, node->start_selection, node->end_selection); env, j_node, node->selection->start(), node->selection->end());
} }
for (auto& child : node->children) { for (int child : node->children_indices) {
Java_WebContentsImpl_addAccessibilityNodeAsChild( Java_WebContentsImpl_addAccessibilityNodeAsChild(
env, j_node, env, j_node,
JNI_WebContentsImpl_CreateJavaAXSnapshot(env, child.get(), false)); JNI_WebContentsImpl_CreateJavaAXSnapshot(
env, tree, tree->nodes[child].get(), false));
} }
return j_node; return j_node;
} }
...@@ -127,10 +130,10 @@ void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback, ...@@ -127,10 +130,10 @@ void AXTreeSnapshotCallback(const ScopedJavaGlobalRef<jobject>& callback,
std::unique_ptr<BrowserAccessibilityManagerAndroid> manager( std::unique_ptr<BrowserAccessibilityManagerAndroid> manager(
static_cast<BrowserAccessibilityManagerAndroid*>( static_cast<BrowserAccessibilityManagerAndroid*>(
BrowserAccessibilityManager::Create(result, nullptr))); BrowserAccessibilityManager::Create(result, nullptr)));
auto snapshot = ui::AXSnapshotNodeAndroid::Create( std::unique_ptr<ui::AssistantTree> assistant_tree =
result, manager->ShouldExposePasswordText()); ui::CreateAssistantTree(result, manager->ShouldExposePasswordText());
ScopedJavaLocalRef<jobject> j_root = ScopedJavaLocalRef<jobject> j_root = JNI_WebContentsImpl_CreateJavaAXSnapshot(
JNI_WebContentsImpl_CreateJavaAXSnapshot(env, snapshot.get(), true); env, assistant_tree.get(), assistant_tree->nodes.front().get(), true);
Java_WebContentsImpl_onAccessibilitySnapshot(env, j_root, callback); Java_WebContentsImpl_onAccessibilitySnapshot(env, j_root, callback);
} }
......
...@@ -73,8 +73,6 @@ component("accessibility") { ...@@ -73,8 +73,6 @@ component("accessibility") {
"platform/ax_android_constants.h", "platform/ax_android_constants.h",
"platform/ax_platform_node.cc", "platform/ax_platform_node.cc",
"platform/ax_platform_node.h", "platform/ax_platform_node.h",
"platform/ax_snapshot_node_android_platform.cc",
"platform/ax_snapshot_node_android_platform.h",
"platform/ax_unique_id.cc", "platform/ax_unique_id.cc",
"platform/ax_unique_id.h", "platform/ax_unique_id.h",
] ]
...@@ -151,6 +149,16 @@ component("accessibility") { ...@@ -151,6 +149,16 @@ component("accessibility") {
} }
} }
source_set("ax_assistant") {
sources = [
"ax_assistant_structure.cc",
"ax_assistant_structure.h",
]
deps = [
":accessibility",
]
}
static_library("test_support") { static_library("test_support") {
testonly = true testonly = true
sources = [ sources = [
......
...@@ -13,5 +13,8 @@ include_rules = [ ...@@ -13,5 +13,8 @@ include_rules = [
specific_include_rules = { specific_include_rules = {
"run_all_unittests.cc": [ "run_all_unittests.cc": [
"+mojo/edk/embedder", "+mojo/edk/embedder",
] ],
"ax_assistant_util.h": [
"+ui/accessibility/mojom",
],
} }
// Copyright 2017 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ui/accessibility/platform/ax_snapshot_node_android_platform.h" #include "ui/accessibility/ax_assistant_structure.h"
#include <string> #include <string>
#include "base/logging.h" #include "base/logging.h"
#include "base/optional.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 "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include "ui/accessibility/ax_serializable_tree.h" #include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/platform/ax_android_constants.h" #include "ui/accessibility/platform/ax_android_constants.h"
#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/transform.h" #include "ui/gfx/transform.h"
namespace ui { namespace ui {
...@@ -211,11 +213,11 @@ base::string16 GetText(const AXNode* node, bool show_password) { ...@@ -211,11 +213,11 @@ base::string16 GetText(const AXNode* node, bool show_password) {
} }
} }
if (text.empty() && (AXSnapshotNodeAndroid::AXRoleIsLink(node->data().role) || if (text.empty() && (AXRoleIsLink(node->data().role) ||
node->data().role == ax::mojom::Role::kImage)) { node->data().role == ax::mojom::Role::kImage)) {
base::string16 url = base::string16 url =
node->data().GetString16Attribute(ax::mojom::StringAttribute::kUrl); node->data().GetString16Attribute(ax::mojom::StringAttribute::kUrl);
text = AXSnapshotNodeAndroid::AXUrlBaseText(url); text = AXUrlBaseText(url);
} }
return text; return text;
} }
...@@ -264,36 +266,135 @@ base::Optional<std::string> AXRoleToString(ax::mojom::Role role) { ...@@ -264,36 +266,135 @@ base::Optional<std::string> AXRoleToString(ax::mojom::Role role) {
} }
} }
AssistantNode* AddChild(AssistantTree* tree) {
auto node = std::make_unique<AssistantNode>();
tree->nodes.push_back(std::move(node));
return tree->nodes.back().get();
}
struct WalkAXTreeConfig {
bool should_select_leaf;
const bool show_password;
};
void WalkAXTreeDepthFirst(const AXNode* node,
const gfx::Rect& rect,
const AXTreeUpdate& update,
const AXTree* tree,
WalkAXTreeConfig* config,
AssistantTree* assistant_tree,
AssistantNode* result) {
result->text = GetText(node, config->show_password);
result->class_name =
AXRoleToAndroidClassName(node->data().role, node->parent() != nullptr);
result->role = AXRoleToString(node->data().role);
result->text_size = -1.0;
result->bgcolor = 0;
result->color = 0;
result->bold = 0;
result->italic = 0;
result->line_through = 0;
result->underline = 0;
if (node->data().HasFloatAttribute(ax::mojom::FloatAttribute::kFontSize)) {
gfx::RectF text_size_rect(
0, 0, 1,
node->data().GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize));
gfx::Rect scaled_text_size_rect =
gfx::ToEnclosingRect(tree->RelativeToTreeBounds(node, text_size_rect));
result->text_size = scaled_text_size_rect.height();
const int32_t text_style =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
result->color =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kColor);
result->bgcolor =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor);
result->bold =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold)) != 0;
result->italic =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic)) != 0;
result->line_through =
(text_style & static_cast<int32_t>(
ax::mojom::TextStyle::kTextStyleLineThrough)) != 0;
result->underline =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline)) != 0;
}
const gfx::Rect& absolute_rect =
gfx::ToEnclosingRect(tree->GetTreeBounds(node));
gfx::Rect parent_relative_rect = absolute_rect;
bool is_root = node->parent() == nullptr;
if (!is_root) {
parent_relative_rect.Offset(-rect.OffsetFromOrigin());
}
result->rect = gfx::Rect(parent_relative_rect.x(), parent_relative_rect.y(),
absolute_rect.width(), absolute_rect.height());
if (IsLeaf(node) && update.has_tree_data) {
int start_selection = 0;
int end_selection = 0;
if (update.tree_data.sel_anchor_object_id == node->id()) {
start_selection = update.tree_data.sel_anchor_offset;
config->should_select_leaf = true;
}
if (config->should_select_leaf) {
end_selection =
static_cast<int32_t>(GetText(node, config->show_password).length());
}
if (update.tree_data.sel_focus_object_id == node->id()) {
end_selection = update.tree_data.sel_focus_offset;
config->should_select_leaf = false;
}
if (end_selection > 0)
result->selection =
base::make_optional<gfx::Range>(start_selection, end_selection);
}
for (auto* child : node->children()) {
auto* n = AddChild(assistant_tree);
result->children_indices.push_back(assistant_tree->nodes.size() - 1);
WalkAXTreeDepthFirst(child, absolute_rect, update, tree, config,
assistant_tree, n);
}
}
} // namespace } // namespace
AXSnapshotNodeAndroid::AXSnapshotNodeAndroid() = default; AssistantNode::AssistantNode() = default;
AX_EXPORT AXSnapshotNodeAndroid::~AXSnapshotNodeAndroid() = default; AssistantNode::AssistantNode(const AssistantNode& other) = default;
AssistantNode::~AssistantNode() = default;
// static AssistantTree::AssistantTree() = default;
AX_EXPORT std::unique_ptr<AXSnapshotNodeAndroid> AXSnapshotNodeAndroid::Create( AssistantTree::~AssistantTree() = default;
const AXTreeUpdate& update,
bool show_password) { std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update,
bool show_password) {
auto tree = std::make_unique<AXSerializableTree>(); auto tree = std::make_unique<AXSerializableTree>();
if (!tree->Unserialize(update)) { auto assistant_tree = std::make_unique<AssistantTree>();
auto* root = AddChild(assistant_tree.get());
if (!tree->Unserialize(update))
LOG(FATAL) << tree->error(); LOG(FATAL) << tree->error();
}
WalkAXTreeConfig config{ WalkAXTreeConfig config{
false, // should_select_leaf false, // should_select_leaf
show_password // show_password show_password // show_password
}; };
return WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get(), WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get(), &config,
config); assistant_tree.get(), root);
return assistant_tree;
} }
// static bool AXRoleIsLink(ax::mojom::Role role) {
AX_EXPORT bool AXSnapshotNodeAndroid::AXRoleIsLink(ax::mojom::Role role) {
return role == ax::mojom::Role::kLink; return role == ax::mojom::Role::kLink;
} }
// static base::string16 AXUrlBaseText(base::string16 url) {
AX_EXPORT base::string16 AXSnapshotNodeAndroid::AXUrlBaseText(
base::string16 url) {
// Given a url like http://foo.com/bar/baz.png, just return the // Given a url like http://foo.com/bar/baz.png, just return the
// base text, e.g., "baz". // base text, e.g., "baz".
int trailing_slashes = 0; int trailing_slashes = 0;
...@@ -312,10 +413,7 @@ AX_EXPORT base::string16 AXSnapshotNodeAndroid::AXUrlBaseText( ...@@ -312,10 +413,7 @@ AX_EXPORT base::string16 AXSnapshotNodeAndroid::AXUrlBaseText(
return url; return url;
} }
// static const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent) {
AX_EXPORT const char* AXSnapshotNodeAndroid::AXRoleToAndroidClassName(
ax::mojom::Role role,
bool has_parent) {
switch (role) { switch (role) {
case ax::mojom::Role::kSearchBox: case ax::mojom::Role::kSearchBox:
case ax::mojom::Role::kSpinButton: case ax::mojom::Role::kSpinButton:
...@@ -370,98 +468,4 @@ AX_EXPORT const char* AXSnapshotNodeAndroid::AXRoleToAndroidClassName( ...@@ -370,98 +468,4 @@ AX_EXPORT const char* AXSnapshotNodeAndroid::AXRoleToAndroidClassName(
} }
} }
// static
std::unique_ptr<AXSnapshotNodeAndroid>
AXSnapshotNodeAndroid::WalkAXTreeDepthFirst(
const AXNode* node,
gfx::Rect rect,
const AXTreeUpdate& update,
const AXTree* tree,
AXSnapshotNodeAndroid::WalkAXTreeConfig& config) {
auto result =
std::unique_ptr<AXSnapshotNodeAndroid>(new AXSnapshotNodeAndroid());
result->text = GetText(node, config.show_password);
result->class_name = AXSnapshotNodeAndroid::AXRoleToAndroidClassName(
node->data().role, node->parent() != nullptr);
result->role = AXRoleToString(node->data().role);
result->text_size = -1.0;
result->bgcolor = 0;
result->color = 0;
result->bold = 0;
result->italic = 0;
result->line_through = 0;
result->underline = 0;
if (node->data().HasFloatAttribute(ax::mojom::FloatAttribute::kFontSize)) {
gfx::RectF text_size_rect(
0, 0, 1,
node->data().GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize));
gfx::Rect scaled_text_size_rect =
gfx::ToEnclosingRect(tree->RelativeToTreeBounds(node, text_size_rect));
result->text_size = scaled_text_size_rect.height();
const int32_t text_style =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
result->color =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kColor);
result->bgcolor =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor);
result->bold =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold)) != 0;
result->italic =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic)) != 0;
result->line_through =
(text_style & static_cast<int32_t>(
ax::mojom::TextStyle::kTextStyleLineThrough)) != 0;
result->underline =
(text_style &
static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline)) != 0;
}
const gfx::Rect& absolute_rect =
gfx::ToEnclosingRect(tree->GetTreeBounds(node));
gfx::Rect parent_relative_rect = absolute_rect;
bool is_root = node->parent() == nullptr;
if (!is_root) {
parent_relative_rect.Offset(-rect.OffsetFromOrigin());
}
result->rect = gfx::Rect(parent_relative_rect.x(), parent_relative_rect.y(),
absolute_rect.width(), absolute_rect.height());
result->has_selection = false;
if (IsLeaf(node) && update.has_tree_data) {
int start_selection = 0;
int end_selection = 0;
if (update.tree_data.sel_anchor_object_id == node->id()) {
start_selection = update.tree_data.sel_anchor_offset;
config.should_select_leaf = true;
}
if (config.should_select_leaf) {
end_selection =
static_cast<int32_t>(GetText(node, config.show_password).length());
}
if (update.tree_data.sel_focus_object_id == node->id()) {
end_selection = update.tree_data.sel_focus_offset;
config.should_select_leaf = false;
}
if (end_selection > 0) {
result->has_selection = true;
result->start_selection = start_selection;
result->end_selection = end_selection;
}
}
for (auto* child : node->children()) {
result->children.push_back(
WalkAXTreeDepthFirst(child, absolute_rect, update, tree, config));
}
return result;
}
} // namespace ui } // namespace ui
// 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_ACCESSIBILITY_AX_ASSISTANT_STRUCTURE_H_
#define UI_ACCESSIBILITY_AX_ASSISTANT_STRUCTURE_H_
#include <cstdint>
#include <vector>
#include "base/macros.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/range/range.h"
namespace ui {
struct AssistantNode {
AssistantNode();
AssistantNode(const AssistantNode& other);
~AssistantNode();
std::vector<int32_t> children_indices;
// Geometry of the view in pixels
gfx::Rect rect;
// Text of the view.
base::string16 text;
// Text properties
float text_size;
uint32_t color;
uint32_t bgcolor;
bool bold;
bool italic;
bool underline;
bool line_through;
// Selected portion of the text.
base::Optional<gfx::Range> selection;
// Fake Android view class name of the element. Each node is assigned
// a closest approximation of Android's views to keep the server happy.
std::string class_name;
// Accessibility functionality of the node inferred from DOM or based on HTML
// role attribute.
base::Optional<std::string> role;
};
struct AssistantTree {
AssistantTree();
~AssistantTree();
std::vector<std::unique_ptr<AssistantNode>> nodes;
private:
DISALLOW_COPY_AND_ASSIGN(AssistantTree);
};
std::unique_ptr<AssistantTree> CreateAssistantTree(const AXTreeUpdate& update,
bool show_password);
bool AXRoleIsLink(ax::mojom::Role role);
base::string16 AXUrlBaseText(base::string16 url);
const char* AXRoleToAndroidClassName(ax::mojom::Role role, bool has_parent);
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_ASSISTANT_STRUCTURE_H_
...@@ -6,6 +6,7 @@ import("//mojo/public/tools/bindings/mojom.gni") ...@@ -6,6 +6,7 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") { mojom("mojom") {
sources = [ sources = [
"ax_assistant_structure.mojom",
"ax_node_data.mojom", "ax_node_data.mojom",
"ax_tree_data.mojom", "ax_tree_data.mojom",
"ax_tree_update.mojom", "ax_tree_update.mojom",
...@@ -16,5 +17,6 @@ mojom("mojom") { ...@@ -16,5 +17,6 @@ mojom("mojom") {
"//ui/accessibility:ax_enums_mojo", "//ui/accessibility:ax_enums_mojo",
"//ui/gfx/geometry/mojo", "//ui/gfx/geometry/mojo",
"//ui/gfx/mojo", "//ui/gfx/mojo",
"//ui/gfx/range/mojo",
] ]
} }
// 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.
module ax.mojom;
import "mojo/public/mojom/base/string16.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/range/mojo/range.mojom";
// Tree structure for assistant. The tree is represented as a flat array of
// nodes, each containing a children_indices vector that points to its child
// nodes. The purpose is to work around max depth restriction of recursive
// data structure in mojo.
struct AssistantTree {
array<AssistantNode> nodes;
};
// Represents view structure to be passed to assistant. The view structure is
// synthesized from the AXNode.
struct AssistantNode {
array<int32> children_indices;
// Geometry of the view in pixels
gfx.mojom.Rect rect;
// Text of the view.
mojo_base.mojom.String16 text;
// Text properties
float text_size;
uint32 color;
uint32 bgcolor;
bool bold;
bool italic;
bool underline;
bool line_through;
// Selected portion of the text.
gfx.mojom.Range? selection;
// Fake Android view class name of the element. Each node is assigned
// a closest approximation of Android's views to keep the server happy.
string class_name;
// Accessibility functionality of the node inferred from DOM or based on HTML
// role attribute.
string? role;
};
# 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.
mojom = "//ui/accessibility/mojom/ax_assistant_structure.mojom"
public_headers = [ "//ui/accessibility/ax_assistant_structure.h" ]
traits_headers =
[ "//ui/accessibility/mojom/ax_assistant_structure_mojom_traits.h" ]
sources = [
"ax_assistant_structure_mojom_traits.cc",
"ax_assistant_structure_mojom_traits.h",
]
public_deps = [
"//ui/accessibility:ax_assistant",
"//ui/gfx",
"//ui/gfx/geometry/mojo",
"//ui/gfx/geometry/mojo:struct_traits",
"//ui/gfx/range/mojo",
"//ui/gfx/range/mojo:struct_traits",
]
type_mappings = [
"ax.mojom.AssistantTree=ui::AssistantTree[move_only]",
"ax.mojom.AssistantNode=std::unique_ptr<ui::AssistantNode>[move_only]",
]
// 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/accessibility/mojom/ax_assistant_structure_mojom_traits.h"
#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
#include "ui/gfx/range/mojo/range_struct_traits.h"
namespace mojo {
// static
bool StructTraits<ax::mojom::AssistantTreeDataView, ui::AssistantTree>::Read(
ax::mojom::AssistantTreeDataView data,
ui::AssistantTree* out) {
if (!data.ReadNodes(&out->nodes))
return false;
for (size_t i = 0; i < out->nodes.size(); i++) {
// Each child's index should be greater than its parent and within the array
// bounds. This implies that there is no circle in the tree.
for (size_t child_index : out->nodes[i]->children_indices) {
if (child_index <= i || child_index >= out->nodes.size())
return false;
}
}
return true;
}
// static
bool StructTraits<ax::mojom::AssistantNodeDataView,
std::unique_ptr<ui::AssistantNode>>::
Read(ax::mojom::AssistantNodeDataView data,
std::unique_ptr<ui::AssistantNode>* out) {
DCHECK(!out->get());
*out = std::make_unique<ui::AssistantNode>();
(*out)->bgcolor = data.bgcolor();
(*out)->bold = data.bold();
(*out)->color = data.color();
(*out)->italic = data.italic();
(*out)->line_through = data.line_through();
(*out)->underline = data.underline();
if (!data.ReadRect(&(*out)->rect) || !data.ReadText(&(*out)->text) ||
!data.ReadRole(&(*out)->role) ||
!data.ReadSelection(&(*out)->selection) ||
!data.ReadChildrenIndices(&(*out)->children_indices) ||
!data.ReadClassName(&(*out)->class_name)) {
return false;
}
return true;
}
} // namespace mojo
// 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_ACCESSIBILITY_MOJOM_AX_ASSISTANT_STRUCTURE_MOJOM_TRAITS_H_
#define UI_ACCESSIBILITY_MOJOM_AX_ASSISTANT_STRUCTURE_MOJOM_TRAITS_H_
#include <memory>
#include "ui/accessibility/ax_assistant_structure.h"
#include "ui/accessibility/mojom/ax_assistant_structure.mojom-shared.h"
#include "ui/accessibility/mojom/ax_assistant_structure.mojom.h"
namespace mojo {
template <>
struct StructTraits<ax::mojom::AssistantTreeDataView, ui::AssistantTree> {
static bool Read(ax::mojom::AssistantTreeDataView data,
ui::AssistantTree* out);
};
template <>
struct StructTraits<ax::mojom::AssistantNodeDataView,
std::unique_ptr<ui::AssistantNode>> {
static std::vector<int32_t> children_indices(
const std::unique_ptr<ui::AssistantNode>& node) {
return node->children_indices;
}
static gfx::Rect rect(const std::unique_ptr<ui::AssistantNode>& node) {
return node->rect;
}
static base::string16 text(const std::unique_ptr<ui::AssistantNode>& node) {
return node->text;
}
static float text_size(const std::unique_ptr<ui::AssistantNode>& node) {
return node->text_size;
}
static uint32_t color(const std::unique_ptr<ui::AssistantNode>& node) {
return node->color;
}
static uint32_t bgcolor(const std::unique_ptr<ui::AssistantNode>& node) {
return node->bgcolor;
}
static bool bold(const std::unique_ptr<ui::AssistantNode>& node) {
return node->bold;
}
static bool italic(const std::unique_ptr<ui::AssistantNode>& node) {
return node->italic;
}
static bool underline(const std::unique_ptr<ui::AssistantNode>& node) {
return node->underline;
}
static bool line_through(const std::unique_ptr<ui::AssistantNode>& node) {
return node->line_through;
}
static base::Optional<gfx::Range> selection(
const std::unique_ptr<ui::AssistantNode>& node) {
return node->selection;
}
static std::string class_name(
const std::unique_ptr<ui::AssistantNode>& node) {
return node->class_name;
}
static base::Optional<std::string> role(
const std::unique_ptr<ui::AssistantNode>& node) {
return node->role;
}
static bool Read(ax::mojom::AssistantNodeDataView data,
std::unique_ptr<ui::AssistantNode>* out);
};
} // namespace mojo
#endif // UI_ACCESSIBILITY_MOJOM_AX_ASSISTANT_STRUCTURE_MOJOM_TRAITS_H_
...@@ -6,4 +6,5 @@ typemaps = [ ...@@ -6,4 +6,5 @@ typemaps = [
"//ui/accessibility/mojom/ax_node_data.typemap", "//ui/accessibility/mojom/ax_node_data.typemap",
"//ui/accessibility/mojom/ax_tree_data.typemap", "//ui/accessibility/mojom/ax_tree_data.typemap",
"//ui/accessibility/mojom/ax_tree_update.typemap", "//ui/accessibility/mojom/ax_tree_update.typemap",
"//ui/accessibility/mojom/ax_assistant_structure.typemap",
] ]
// Copyright 2017 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_ACCESSIBILITY_PLATFORM_AX_SNAPSHOT_ANDROID_H_
#define UI_ACCESSIBILITY_PLATFORM_AX_SNAPSHOT_ANDROID_H_
#include <cstdint>
#include <memory>
#include <vector>
#include "base/optional.h"
#include "base/strings/string16.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
class AXNode;
class AXTree;
// An intermediate representation of the accessibility snapshot
// in order to share code between ARC and Android. The field names
// are kept consistent with AccessibilitySnapshotNode.java.
struct AXSnapshotNodeAndroid {
// Builds a whole tree of AXSnapshotNodeAndroid objects from
// an AXTreeUpdate.
AX_EXPORT static std::unique_ptr<AXSnapshotNodeAndroid> Create(
const AXTreeUpdate& update,
bool show_password);
// Returns a fake Android view class that is a closest
// approximation of the ax::mojom::Role.
AX_EXPORT static const char* AXRoleToAndroidClassName(ax::mojom::Role role,
bool has_parent);
AX_EXPORT static bool AXRoleIsLink(ax::mojom::Role role);
AX_EXPORT static base::string16 AXUrlBaseText(base::string16 url);
AX_EXPORT ~AXSnapshotNodeAndroid();
gfx::Rect rect;
base::string16 text;
float text_size;
int32_t color;
int32_t bgcolor;
bool bold;
bool italic;
bool underline;
bool line_through;
bool has_selection;
int32_t start_selection;
int32_t end_selection;
base::Optional<std::string> role;
std::string class_name;
std::vector<std::unique_ptr<AXSnapshotNodeAndroid>> children;
private:
AXSnapshotNodeAndroid();
struct WalkAXTreeConfig {
bool should_select_leaf;
const bool show_password;
};
static std::unique_ptr<AXSnapshotNodeAndroid> WalkAXTreeDepthFirst(
const AXNode* node,
gfx::Rect rect,
const AXTreeUpdate& update,
const AXTree* tree,
WalkAXTreeConfig& config);
DISALLOW_COPY_AND_ASSIGN(AXSnapshotNodeAndroid);
};
} // namespace ui
#endif // UI_ACCESSIBILITY_PLATFORM_AX_SNAPSHOT_ANDROID_H_
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