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

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

Issue 2808383004: Refactor and send voice interaction structure (Closed)
Patch Set: address dominic's review comments Created 3 years, 8 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_android_snapshot.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "ui/accessibility/ax_enums.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 std::string GetClassName(const AXNode* node) {
dmazzoni 2017/04/20 21:04:07 This code is all copied from browser_accessibility
Muyuan 2017/04/21 18:45:12 Done.
24 switch (node->data().role) {
25 case ui::AX_ROLE_SEARCH_BOX:
26 case ui::AX_ROLE_SPIN_BUTTON:
27 case ui::AX_ROLE_TEXT_FIELD:
28 return ui::kAXEditTextClassname;
29 case ui::AX_ROLE_SLIDER:
30 return ui::kAXSeekBarClassname;
31 case ui::AX_ROLE_COLOR_WELL:
32 case ui::AX_ROLE_COMBO_BOX:
33 case ui::AX_ROLE_DATE:
34 case ui::AX_ROLE_POP_UP_BUTTON:
35 case ui::AX_ROLE_INPUT_TIME:
36 return ui::kAXSpinnerClassname;
37 case ui::AX_ROLE_BUTTON:
38 case ui::AX_ROLE_MENU_BUTTON:
39 return ui::kAXButtonClassname;
40 case ui::AX_ROLE_CHECK_BOX:
41 case ui::AX_ROLE_SWITCH:
42 return ui::kAXCheckBoxClassname;
43 case ui::AX_ROLE_RADIO_BUTTON:
44 return ui::kAXRadioButtonClassname;
45 case ui::AX_ROLE_TOGGLE_BUTTON:
46 return ui::kAXToggleButtonClassname;
47 case ui::AX_ROLE_CANVAS:
48 case ui::AX_ROLE_IMAGE:
49 case ui::AX_ROLE_SVG_ROOT:
50 return ui::kAXImageClassname;
51 case ui::AX_ROLE_METER:
52 case ui::AX_ROLE_PROGRESS_INDICATOR:
53 return ui::kAXProgressBarClassname;
54 case ui::AX_ROLE_TAB_LIST:
55 return ui::kAXTabWidgetClassname;
56 case ui::AX_ROLE_GRID:
57 case ui::AX_ROLE_TABLE:
58 return ui::kAXGridViewClassname;
59 case ui::AX_ROLE_LIST:
60 case ui::AX_ROLE_LIST_BOX:
61 case ui::AX_ROLE_DESCRIPTION_LIST:
62 return ui::kAXListViewClassname;
63 case ui::AX_ROLE_DIALOG:
64 return ui::kAXDialogClassname;
65 case ui::AX_ROLE_ROOT_WEB_AREA:
66 return node->parent() == nullptr ? ui::kAXWebViewClassname
67 : ui::kAXViewClassname;
68 case ui::AX_ROLE_MENU_ITEM:
69 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
70 case ui::AX_ROLE_MENU_ITEM_RADIO:
71 return ui::kAXMenuItemClassname;
72 default:
73 return ui::kAXViewClassname;
74 }
75 }
76
77 base::string16 GetText(const AXNode* node) {
78 if (node->IsTextNode()) {
79 return node->data().GetString16Attribute(ui::AX_ATTR_NAME);
80 }
81 base::string16 text;
82 for (auto* child : node->children()) {
83 text += GetText(child);
84 }
85 return text;
86 }
87
88 bool HasFocusableChild(const AXNode* node) {
89 for (auto* child : node->children()) {
90 if ((child->data().state & ui::AX_STATE_FOCUSABLE) != 0 ||
91 HasFocusableChild(child)) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 bool IsLeaf(const AXNode* node) {
99 if (node->child_count() == 0)
100 return true;
101
102 if (node->IsTextNode()) {
103 return true;
104 }
105
106 switch (node->data().role) {
107 case ui::AX_ROLE_IMAGE:
108 case ui::AX_ROLE_METER:
109 case ui::AX_ROLE_SCROLL_BAR:
110 case ui::AX_ROLE_SLIDER:
111 case ui::AX_ROLE_SPLITTER:
112 case ui::AX_ROLE_PROGRESS_INDICATOR:
113 case ui::AX_ROLE_DATE:
114 case ui::AX_ROLE_DATE_TIME:
115 case ui::AX_ROLE_INPUT_TIME:
116 return true;
117 default:
118 return false;
119 }
120 }
121
122 gfx::Rect RelativeToAbsoluteBounds(const AXNode* node,
123 gfx::RectF bounds,
124 const AXTree* tree) {
125 const AXNode* current = node;
126 while (current != nullptr) {
127 if (current->data().transform)
128 current->data().transform->TransformRect(&bounds);
129 auto* container = tree->GetFromId(current->data().offset_container_id);
130 if (!container) {
131 if (current == tree->root())
132 container = current->parent();
133 else
134 container = tree->root();
135 }
136 if (!container || container == current)
137 break;
138
139 gfx::RectF container_bounds = container->data().location;
140 bounds.Offset(container_bounds.x(), container_bounds.y());
141 current = container;
142 }
143 return gfx::ToEnclosingRect(bounds);
144 }
145
146 void FixEmptyBounds(const AXNode* node, gfx::RectF* bounds,
147 const AXTree* tree);
148
149 gfx::Rect GetPageBoundsRect(const AXNode* node, const AXTree* tree) {
150 gfx::RectF bounds = node->data().location;
151 FixEmptyBounds(node, &bounds, tree);
152 return RelativeToAbsoluteBounds(node, bounds, tree);
153 }
154
155 void FixEmptyBounds(const AXNode* node,
156 gfx::RectF* bounds,
157 const AXTree* tree) {
158 if (bounds->width() > 0 && bounds->height() > 0)
159 return;
160 for (auto* child : node->children()) {
161 gfx::Rect child_bounds = GetPageBoundsRect(child, tree);
162 if (child_bounds.width() == 0 || child_bounds.height() == 0)
163 continue;
164 if (bounds->width() == 0 || bounds->height() == 0) {
165 *bounds = gfx::RectF(child_bounds);
166 continue;
167 }
168 bounds->Union(gfx::RectF(child_bounds));
169 }
170 }
171
172 std::unique_ptr<AXSnapshotNodeAndroid> WalkAXTreeDepthFirst(
173 const AXNode* node,
174 gfx::Rect rect,
175 const ui::AXTreeUpdate& update,
176 const AXTree* tree) {
177 auto result = base::MakeUnique<AXSnapshotNodeAndroid>();
178 if (node->IsTextNode())
179 result->text = GetText(node);
180 result->class_name = GetClassName(node);
181
182 result->text_size = -1.0;
183 result->bgcolor = 0;
184 result->color = 0;
185 result->bold = 0;
186 result->italic = 0;
187 result->line_through = 0;
188 result->underline = 0;
189
190 if (node->data().HasFloatAttribute(ui::AX_ATTR_FONT_SIZE)) {
191 gfx::RectF text_size_rect(
192 0, 0, 1, node->data().GetFloatAttribute(ui::AX_ATTR_FONT_SIZE));
193 gfx::Rect scaled_text_size_rect =
194 RelativeToAbsoluteBounds(node, text_size_rect, tree);
195 result->text_size = scaled_text_size_rect.height();
196
197 const int text_style = node->data().GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
198 result->color = node->data().GetIntAttribute(ui::AX_ATTR_COLOR);
199 result->bgcolor =
200 node->data().GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR);
201 result->bold = (text_style & ui::AX_TEXT_STYLE_BOLD) != 0;
202 result->italic = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0;
203 result->line_through = (text_style & ui::AX_TEXT_STYLE_LINE_THROUGH) != 0;
204 result->underline = (text_style & ui::AX_TEXT_STYLE_ITALIC) != 0;
205 }
206
207 const gfx::Rect& absolute_rect = GetPageBoundsRect(node, tree);
208 gfx::Rect parent_relative_rect = absolute_rect;
209 bool is_root = node->parent() == nullptr;
210 if (!is_root) {
211 parent_relative_rect.Offset(-rect.OffsetFromOrigin());
212 }
213 result->rect = gfx::Rect(parent_relative_rect.x(), parent_relative_rect.y(),
214 absolute_rect.width(), absolute_rect.height());
215 result->has_selection = false;
216
217 if (IsLeaf(node)) {
218 int start_selection = 0;
219 int end_selection = 0;
220 if (update.tree_data.sel_anchor_object_id == node->data().id) {
221 start_selection = update.tree_data.sel_anchor_offset;
222 end_selection = GetText(node).length();
223 }
224 if (update.tree_data.sel_focus_object_id == node->data().id) {
225 end_selection = update.tree_data.sel_focus_offset;
226 }
227 if (end_selection > 0) {
228 result->has_selection = true;
229 result->start_selection = start_selection;
230 result->end_selection = end_selection;
231 }
232 }
233
234 for (auto* child : node->children()) {
235 result->children.push_back(
236 WalkAXTreeDepthFirst(child, absolute_rect, update, tree));
237 }
238
239 return result;
240 }
241
242 } // namespace
243
244 AX_EXPORT AXSnapshotNodeAndroid::AXSnapshotNodeAndroid() = default;
245 AX_EXPORT AXSnapshotNodeAndroid::~AXSnapshotNodeAndroid() = default;
246
247 AX_EXPORT std::unique_ptr<AXSnapshotNodeAndroid> AXSnapshotNodeAndroid::Create(
248 const AXTreeUpdate& update) {
249 auto tree = base::MakeUnique<ui::AXSerializableTree>();
250 if (!tree->Unserialize(update)) {
251 LOG(FATAL) << tree->error();
252 }
253 return WalkAXTreeDepthFirst(tree->root(), gfx::Rect(), update, tree.get());
254 }
255
256 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698