Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: ui/accessibility/platform/ax_snapshot_node_android_platform.cc

Issue 2808383004: Refactor and send voice interaction structure (Closed)
Patch Set: add test case Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/accessibility/platform/ax_snapshot_node_android_platform.h"
6
7 #include <memory>
Luis Héctor Chávez 2017/04/25 18:22:36 nit: you don't need this since you're already incl
Muyuan 2017/04/25 19:38:13 Done.
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "ui/accessibility/ax_export.h"
13 #include "ui/accessibility/ax_node.h"
14 #include "ui/accessibility/ax_serializable_tree.h"
15 #include "ui/accessibility/platform/ax_android_constants.h"
16 #include "ui/gfx/geometry/rect_conversions.h"
17 #include "ui/gfx/transform.h"
18
19 namespace ui {
20
21 namespace {
22
23 base::string16 GetText(const AXNode* node) {
24 if (node->IsTextNode()) {
25 return node->data().GetString16Attribute(ui::AX_ATTR_NAME);
26 }
27 base::string16 text;
28 for (auto* child : node->children()) {
29 text += GetText(child);
30 }
31 return text;
32 }
33
34 bool HasFocusableChild(const AXNode* node) {
35 for (auto* child : node->children()) {
36 if ((child->data().state & ui::AX_STATE_FOCUSABLE) != 0 ||
37 HasFocusableChild(child)) {
38 return true;
39 }
40 }
41 return false;
42 }
43
44 bool IsLeaf(const AXNode* node) {
45 if (node->child_count() == 0)
46 return true;
47
48 if (node->IsTextNode()) {
49 return true;
50 }
51
52 switch (node->data().role) {
53 case ui::AX_ROLE_IMAGE:
54 case ui::AX_ROLE_METER:
55 case ui::AX_ROLE_SCROLL_BAR:
56 case ui::AX_ROLE_SLIDER:
57 case ui::AX_ROLE_SPLITTER:
58 case ui::AX_ROLE_PROGRESS_INDICATOR:
59 case ui::AX_ROLE_DATE:
60 case ui::AX_ROLE_DATE_TIME:
61 case ui::AX_ROLE_INPUT_TIME:
62 return true;
63 default:
64 return false;
65 }
66 }
67
68 gfx::Rect RelativeToAbsoluteBounds(const AXNode* node,
69 gfx::RectF bounds,
70 const AXTree* tree) {
71 const AXNode* current = node;
72 while (current != nullptr) {
73 if (current->data().transform)
74 current->data().transform->TransformRect(&bounds);
75 auto* container = tree->GetFromId(current->data().offset_container_id);
76 if (!container) {
77 if (current == tree->root())
78 container = current->parent();
79 else
80 container = tree->root();
81 }
82 if (!container || container == current)
83 break;
84
85 gfx::RectF container_bounds = container->data().location;
86 bounds.Offset(container_bounds.x(), container_bounds.y());
87 current = container;
88 }
89 return gfx::ToEnclosingRect(bounds);
90 }
91
92 void FixEmptyBounds(const AXNode* node, gfx::RectF* bounds, const AXTree* tree);
93
94 gfx::Rect GetPageBoundsRect(const AXNode* node, const AXTree* tree) {
95 gfx::RectF bounds = node->data().location;
96 FixEmptyBounds(node, &bounds, tree);
97 return RelativeToAbsoluteBounds(node, bounds, tree);
98 }
99
100 void FixEmptyBounds(const AXNode* node,
101 gfx::RectF* bounds,
102 const AXTree* tree) {
103 if (bounds->width() > 0 && bounds->height() > 0)
104 return;
105 for (auto* child : node->children()) {
106 gfx::Rect child_bounds = GetPageBoundsRect(child, tree);
107 if (child_bounds.width() == 0 || child_bounds.height() == 0)
108 continue;
109 if (bounds->width() == 0 || bounds->height() == 0) {
110 *bounds = gfx::RectF(child_bounds);
111 continue;
112 }
113 bounds->Union(gfx::RectF(child_bounds));
114 }
115 }
116
117 } // namespace
118
119 AXSnapshotNodeAndroid::AXSnapshotNodeAndroid() = default;
120 AX_EXPORT AXSnapshotNodeAndroid::~AXSnapshotNodeAndroid() = default;
121
122 // static
123 AX_EXPORT std::unique_ptr<AXSnapshotNodeAndroid> AXSnapshotNodeAndroid::Create(
124 const AXTreeUpdate& update) {
125 auto tree = base::MakeUnique<ui::AXSerializableTree>();
126 if (!tree->Unserialize(update)) {
127 LOG(FATAL) << tree->error();
128 }
129 return WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get());
130 }
131
132 // static
133 AX_EXPORT const char* AXSnapshotNodeAndroid::AXRoleToAndroidClassName(
134 AXRole role,
135 bool has_parent) {
136 switch (role) {
137 case ui::AX_ROLE_SEARCH_BOX:
138 case ui::AX_ROLE_SPIN_BUTTON:
139 case ui::AX_ROLE_TEXT_FIELD:
140 return ui::kAXEditTextClassname;
141 case ui::AX_ROLE_SLIDER:
142 return ui::kAXSeekBarClassname;
143 case ui::AX_ROLE_COLOR_WELL:
144 case ui::AX_ROLE_COMBO_BOX:
145 case ui::AX_ROLE_DATE:
146 case ui::AX_ROLE_POP_UP_BUTTON:
147 case ui::AX_ROLE_INPUT_TIME:
148 return ui::kAXSpinnerClassname;
149 case ui::AX_ROLE_BUTTON:
150 case ui::AX_ROLE_MENU_BUTTON:
151 return ui::kAXButtonClassname;
152 case ui::AX_ROLE_CHECK_BOX:
153 case ui::AX_ROLE_SWITCH:
154 return ui::kAXCheckBoxClassname;
155 case ui::AX_ROLE_RADIO_BUTTON:
156 return ui::kAXRadioButtonClassname;
157 case ui::AX_ROLE_TOGGLE_BUTTON:
158 return ui::kAXToggleButtonClassname;
159 case ui::AX_ROLE_CANVAS:
160 case ui::AX_ROLE_IMAGE:
161 case ui::AX_ROLE_SVG_ROOT:
162 return ui::kAXImageClassname;
163 case ui::AX_ROLE_METER:
164 case ui::AX_ROLE_PROGRESS_INDICATOR:
165 return ui::kAXProgressBarClassname;
166 case ui::AX_ROLE_TAB_LIST:
167 return ui::kAXTabWidgetClassname;
168 case ui::AX_ROLE_GRID:
169 case ui::AX_ROLE_TREE_GRID:
170 case ui::AX_ROLE_TABLE:
171 return ui::kAXGridViewClassname;
172 case ui::AX_ROLE_LIST:
173 case ui::AX_ROLE_LIST_BOX:
174 case ui::AX_ROLE_DESCRIPTION_LIST:
175 return ui::kAXListViewClassname;
176 case ui::AX_ROLE_DIALOG:
177 return ui::kAXDialogClassname;
178 case ui::AX_ROLE_ROOT_WEB_AREA:
179 return has_parent ? ui::kAXWebViewClassname : ui::kAXViewClassname;
180 case ui::AX_ROLE_MENU_ITEM:
181 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
182 case ui::AX_ROLE_MENU_ITEM_RADIO:
183 return ui::kAXMenuItemClassname;
184 default:
185 return ui::kAXViewClassname;
186 }
187 }
188
189 // static
190 std::unique_ptr<AXSnapshotNodeAndroid>
191 AXSnapshotNodeAndroid::WalkAXTreeDepthFirst(const AXNode* node,
192 gfx::Rect rect,
193 const ui::AXTreeUpdate& update,
194 const AXTree* tree) {
195 auto result =
196 std::unique_ptr<AXSnapshotNodeAndroid>(new AXSnapshotNodeAndroid);
Luis Héctor Chávez 2017/04/25 18:22:36 nit: prefer base::make_unique<AXSnapshotNodeAndroi
Muyuan 2017/04/25 19:38:13 OK.. actually it was there to address the comment:
Luis Héctor Chávez 2017/04/25 20:05:32 As discussed offline, either parens or a comment a
Muyuan 2017/04/25 20:49:42 Done.
197 result->text = GetText(node);
198 result->class_name = AXSnapshotNodeAndroid::AXRoleToAndroidClassName(
199 node->data().role, node->parent() != nullptr);
200
201 result->text_size = -1.0;
202 result->bgcolor = 0;
203 result->color = 0;
204 result->bold = 0;
205 result->italic = 0;
206 result->line_through = 0;
207 result->underline = 0;
208
209 if (node->data().HasFloatAttribute(ui::AX_ATTR_FONT_SIZE)) {
210 gfx::RectF text_size_rect(
211 0, 0, 1, node->data().GetFloatAttribute(ui::AX_ATTR_FONT_SIZE));
212 gfx::Rect scaled_text_size_rect =
213 RelativeToAbsoluteBounds(node, text_size_rect, tree);
214 result->text_size = scaled_text_size_rect.height();
215
216 const int text_style = node->data().GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
217 result->color = node->data().GetIntAttribute(ui::AX_ATTR_COLOR);
218 result->bgcolor =
219 node->data().GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR);
220 result->bold = (text_style & ui::AX_TEXT_STYLE_BOLD) != 0;
221 result->italic = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0;
222 result->line_through = (text_style & ui::AX_TEXT_STYLE_LINE_THROUGH) != 0;
223 result->underline = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0;
224 }
225
226 const gfx::Rect& absolute_rect = GetPageBoundsRect(node, tree);
227 gfx::Rect parent_relative_rect = absolute_rect;
228 bool is_root = node->parent() == nullptr;
229 if (!is_root) {
230 parent_relative_rect.Offset(-rect.OffsetFromOrigin());
231 }
232 result->rect = gfx::Rect(parent_relative_rect.x(), parent_relative_rect.y(),
233 absolute_rect.width(), absolute_rect.height());
234 result->has_selection = false;
235
236 if (IsLeaf(node)) {
237 int start_selection = 0;
238 int end_selection = 0;
239 if (update.tree_data.sel_anchor_object_id == node->data().id) {
240 start_selection = update.tree_data.sel_anchor_offset;
241 end_selection = GetText(node).length();
242 }
243 if (update.tree_data.sel_focus_object_id == node->data().id) {
244 end_selection = update.tree_data.sel_focus_offset;
245 }
246 if (end_selection > 0) {
247 result->has_selection = true;
248 result->start_selection = start_selection;
249 result->end_selection = end_selection;
250 }
251 }
252
253 for (auto* child : node->children()) {
254 result->children.push_back(
255 WalkAXTreeDepthFirst(child, absolute_rect, update, tree));
256 }
257
258 return result;
259 }
260
261 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698