1 // Copyright (c) 2012 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.
5 #include "content/common/accessibility_node_data.h"
9 #include "base/containers/hash_tables.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
14 using base::DoubleToString
;
15 using base::IntToString
;
20 std::string
IntVectorToString(const std::vector
<int>& items
) {
22 for (size_t i
= 0; i
< items
.size(); ++i
) {
25 str
+= IntToString(items
[i
]);
31 } // Anonymous namespace
35 AccessibilityNodeData::AccessibilityNodeData()
41 AccessibilityNodeData::~AccessibilityNodeData() {
44 AccessibilityNodeDataTreeNode::AccessibilityNodeDataTreeNode()
45 : AccessibilityNodeData() {
48 AccessibilityNodeDataTreeNode::~AccessibilityNodeDataTreeNode() {
51 AccessibilityNodeDataTreeNode
& AccessibilityNodeDataTreeNode::operator=(
52 const AccessibilityNodeData
& src
) {
53 AccessibilityNodeData::operator=(src
);
57 void MakeAccessibilityNodeDataTree(
58 const std::vector
<AccessibilityNodeData
>& src_vector
,
59 AccessibilityNodeDataTreeNode
* dst_root
) {
60 // This method assumes |src_vector| contains all of the nodes of
61 // an accessibility tree, and that each parent comes before its
62 // children. Each node has an id, and the ids of its children.
63 // The output is a tree where each node contains its children.
65 // Initialize a hash map with all of the ids in |src_vector|.
66 base::hash_map
<int32
, AccessibilityNodeDataTreeNode
*> id_map
;
67 for (size_t i
= 0; i
< src_vector
.size(); ++i
)
68 id_map
[src_vector
[i
].id
] = NULL
;
70 // Copy the nodes to the output tree one at a time.
71 for (size_t i
= 0; i
< src_vector
.size(); ++i
) {
72 const AccessibilityNodeData
& src_node
= src_vector
[i
];
73 AccessibilityNodeDataTreeNode
* dst_node
;
75 // If it's the first element in the vector, assume it's
76 // the root. For any other element, look for it in our
77 // hash map, and skip it if not there (meaning there was
78 // an extranous node, or the nodes were sent in the wrong
83 dst_node
= id_map
[src_node
.id
];
88 // Copy the node data.
91 // Add placeholders for all of the node's children in the tree,
92 // and add them to the hash map so we can find them when we
93 // encounter them in |src_vector|.
94 dst_node
->children
.reserve(src_node
.child_ids
.size());
95 for (size_t j
= 0; j
< src_node
.child_ids
.size(); ++j
) {
96 int child_id
= src_node
.child_ids
[j
];
97 if (id_map
.find(child_id
) != id_map
.end()) {
98 dst_node
->children
.push_back(AccessibilityNodeDataTreeNode());
99 id_map
[child_id
] = &dst_node
->children
.back();
106 std::string
AccessibilityNodeData::DebugString(bool recursive
) const {
109 result
+= "id=" + IntToString(id
);
112 case ROLE_ALERT
: result
+= " ALERT"; break;
113 case ROLE_ALERT_DIALOG
: result
+= " ALERT_DIALOG"; break;
114 case ROLE_ANNOTATION
: result
+= " ANNOTATION"; break;
115 case ROLE_APPLICATION
: result
+= " APPLICATION"; break;
116 case ROLE_ARTICLE
: result
+= " ARTICLE"; break;
117 case ROLE_BROWSER
: result
+= " BROWSER"; break;
118 case ROLE_BUSY_INDICATOR
: result
+= " BUSY_INDICATOR"; break;
119 case ROLE_BUTTON
: result
+= " BUTTON"; break;
120 case ROLE_CANVAS
: result
+= " CANVAS"; break;
121 case ROLE_CANVAS_WITH_FALLBACK_CONTENT
: result
+= " CANVAS_FALLBACK"; break;
122 case ROLE_CELL
: result
+= " CELL"; break;
123 case ROLE_CHECKBOX
: result
+= " CHECKBOX"; break;
124 case ROLE_COLOR_WELL
: result
+= " COLOR_WELL"; break;
125 case ROLE_COLUMN
: result
+= " COLUMN"; break;
126 case ROLE_COLUMN_HEADER
: result
+= " COLUMN_HEADER"; break;
127 case ROLE_COMBO_BOX
: result
+= " COMBO_BOX"; break;
128 case ROLE_DEFINITION
: result
+= " DEFINITION"; break;
129 case ROLE_DESCRIPTION_LIST_DETAIL
: result
+= " DD"; break;
130 case ROLE_DESCRIPTION_LIST_TERM
: result
+= " DT"; break;
131 case ROLE_DIALOG
: result
+= " DIALOG"; break;
132 case ROLE_DIRECTORY
: result
+= " DIRECTORY"; break;
133 case ROLE_DISCLOSURE_TRIANGLE
: result
+= " DISCLOSURE_TRIANGLE"; break;
134 case ROLE_DIV
: result
+= " DIV"; break;
135 case ROLE_DOCUMENT
: result
+= " DOCUMENT"; break;
136 case ROLE_DRAWER
: result
+= " DRAWER"; break;
137 case ROLE_EDITABLE_TEXT
: result
+= " EDITABLE_TEXT"; break;
138 case ROLE_FOOTER
: result
+= " FOOTER"; break;
139 case ROLE_FORM
: result
+= " FORM"; break;
140 case ROLE_GRID
: result
+= " GRID"; break;
141 case ROLE_GROUP
: result
+= " GROUP"; break;
142 case ROLE_GROW_AREA
: result
+= " GROW_AREA"; break;
143 case ROLE_HEADING
: result
+= " HEADING"; break;
144 case ROLE_HELP_TAG
: result
+= " HELP_TAG"; break;
145 case ROLE_HORIZONTAL_RULE
: result
+= " HORIZONTAL_RULE"; break;
146 case ROLE_IGNORED
: result
+= " IGNORED"; break;
147 case ROLE_IMAGE
: result
+= " IMAGE"; break;
148 case ROLE_IMAGE_MAP
: result
+= " IMAGE_MAP"; break;
149 case ROLE_IMAGE_MAP_LINK
: result
+= " IMAGE_MAP_LINK"; break;
150 case ROLE_INCREMENTOR
: result
+= " INCREMENTOR"; break;
151 case ROLE_LABEL
: result
+= " LABEL"; break;
152 case ROLE_LANDMARK_APPLICATION
: result
+= " L_APPLICATION"; break;
153 case ROLE_LANDMARK_BANNER
: result
+= " L_BANNER"; break;
154 case ROLE_LANDMARK_COMPLEMENTARY
: result
+= " L_COMPLEMENTARY"; break;
155 case ROLE_LANDMARK_CONTENTINFO
: result
+= " L_CONTENTINFO"; break;
156 case ROLE_LANDMARK_MAIN
: result
+= " L_MAIN"; break;
157 case ROLE_LANDMARK_NAVIGATION
: result
+= " L_NAVIGATION"; break;
158 case ROLE_LANDMARK_SEARCH
: result
+= " L_SEARCH"; break;
159 case ROLE_LINK
: result
+= " LINK"; break;
160 case ROLE_LIST
: result
+= " LIST"; break;
161 case ROLE_LISTBOX
: result
+= " LISTBOX"; break;
162 case ROLE_LISTBOX_OPTION
: result
+= " LISTBOX_OPTION"; break;
163 case ROLE_LIST_ITEM
: result
+= " LIST_ITEM"; break;
164 case ROLE_LIST_MARKER
: result
+= " LIST_MARKER"; break;
165 case ROLE_LOG
: result
+= " LOG"; break;
166 case ROLE_MARQUEE
: result
+= " MARQUEE"; break;
167 case ROLE_MATH
: result
+= " MATH"; break;
168 case ROLE_MATTE
: result
+= " MATTE"; break;
169 case ROLE_MENU
: result
+= " MENU"; break;
170 case ROLE_MENU_BAR
: result
+= " MENU_BAR"; break;
171 case ROLE_MENU_BUTTON
: result
+= " MENU_BUTTON"; break;
172 case ROLE_MENU_ITEM
: result
+= " MENU_ITEM"; break;
173 case ROLE_MENU_LIST_OPTION
: result
+= " MENU_LIST_OPTION"; break;
174 case ROLE_MENU_LIST_POPUP
: result
+= " MENU_LIST_POPUP"; break;
175 case ROLE_NOTE
: result
+= " NOTE"; break;
176 case ROLE_OUTLINE
: result
+= " OUTLINE"; break;
177 case ROLE_PARAGRAPH
: result
+= " PARAGRAPH"; break;
178 case ROLE_POPUP_BUTTON
: result
+= " POPUP_BUTTON"; break;
179 case ROLE_PRESENTATIONAL
: result
+= " PRESENTATIONAL"; break;
180 case ROLE_PROGRESS_INDICATOR
: result
+= " PROGRESS_INDICATOR"; break;
181 case ROLE_RADIO_BUTTON
: result
+= " RADIO_BUTTON"; break;
182 case ROLE_RADIO_GROUP
: result
+= " RADIO_GROUP"; break;
183 case ROLE_REGION
: result
+= " REGION"; break;
184 case ROLE_ROOT_WEB_AREA
: result
+= " ROOT_WEB_AREA"; break;
185 case ROLE_ROW
: result
+= " ROW"; break;
186 case ROLE_ROW_HEADER
: result
+= " ROW_HEADER"; break;
187 case ROLE_RULER
: result
+= " RULER"; break;
188 case ROLE_RULER_MARKER
: result
+= " RULER_MARKER"; break;
189 case ROLE_SCROLLAREA
: result
+= " SCROLLAREA"; break;
190 case ROLE_SCROLLBAR
: result
+= " SCROLLBAR"; break;
191 case ROLE_SHEET
: result
+= " SHEET"; break;
192 case ROLE_SLIDER
: result
+= " SLIDER"; break;
193 case ROLE_SLIDER_THUMB
: result
+= " SLIDER_THUMB"; break;
194 case ROLE_SPIN_BUTTON
: result
+= " SPIN_BUTTON"; break;
195 case ROLE_SPIN_BUTTON_PART
: result
+= " SPIN_BUTTON_PART"; break;
196 case ROLE_SPLITTER
: result
+= " SPLITTER"; break;
197 case ROLE_SPLIT_GROUP
: result
+= " SPLIT_GROUP"; break;
198 case ROLE_STATIC_TEXT
: result
+= " STATIC_TEXT"; break;
199 case ROLE_STATUS
: result
+= " STATUS"; break;
200 case ROLE_SVG_ROOT
: result
+= " SVG_ROOT"; break;
201 case ROLE_SYSTEM_WIDE
: result
+= " SYSTEM_WIDE"; break;
202 case ROLE_TAB
: result
+= " TAB"; break;
203 case ROLE_TABLE
: result
+= " TABLE"; break;
204 case ROLE_TABLE_HEADER_CONTAINER
: result
+= " TABLE_HDR_CONTAINER"; break;
205 case ROLE_TAB_GROUP_UNUSED
: result
+= " TAB_GROUP_UNUSED"; break;
206 case ROLE_TAB_LIST
: result
+= " TAB_LIST"; break;
207 case ROLE_TAB_PANEL
: result
+= " TAB_PANEL"; break;
208 case ROLE_TEXTAREA
: result
+= " TEXTAREA"; break;
209 case ROLE_TEXT_FIELD
: result
+= " TEXT_FIELD"; break;
210 case ROLE_TIMER
: result
+= " TIMER"; break;
211 case ROLE_TOGGLE_BUTTON
: result
+= " TOGGLE_BUTTON"; break;
212 case ROLE_TOOLBAR
: result
+= " TOOLBAR"; break;
213 case ROLE_TOOLTIP
: result
+= " TOOLTIP"; break;
214 case ROLE_TREE
: result
+= " TREE"; break;
215 case ROLE_TREE_GRID
: result
+= " TREE_GRID"; break;
216 case ROLE_TREE_ITEM
: result
+= " TREE_ITEM"; break;
217 case ROLE_UNKNOWN
: result
+= " UNKNOWN"; break;
218 case ROLE_VALUE_INDICATOR
: result
+= " VALUE_INDICATOR"; break;
219 case ROLE_WEBCORE_LINK
: result
+= " WEBCORE_LINK"; break;
220 case ROLE_WEB_AREA
: result
+= " WEB_AREA"; break;
221 case ROLE_WINDOW
: result
+= " WINDOW"; break;
226 if (state
& (1 << STATE_BUSY
))
228 if (state
& (1 << STATE_CHECKED
))
229 result
+= " CHECKED";
230 if (state
& (1 << STATE_COLLAPSED
))
231 result
+= " COLLAPSED";
232 if (state
& (1 << STATE_EXPANDED
))
233 result
+= " EXPANDED";
234 if (state
& (1 << STATE_FOCUSABLE
))
235 result
+= " FOCUSABLE";
236 if (state
& (1 << STATE_FOCUSED
))
237 result
+= " FOCUSED";
238 if (state
& (1 << STATE_HASPOPUP
))
239 result
+= " HASPOPUP";
240 if (state
& (1 << STATE_HOTTRACKED
))
241 result
+= " HOTTRACKED";
242 if (state
& (1 << STATE_INDETERMINATE
))
243 result
+= " INDETERMINATE";
244 if (state
& (1 << STATE_INVISIBLE
))
245 result
+= " INVISIBLE";
246 if (state
& (1 << STATE_LINKED
))
248 if (state
& (1 << STATE_MULTISELECTABLE
))
249 result
+= " MULTISELECTABLE";
250 if (state
& (1 << STATE_OFFSCREEN
))
251 result
+= " OFFSCREEN";
252 if (state
& (1 << STATE_PRESSED
))
253 result
+= " PRESSED";
254 if (state
& (1 << STATE_PROTECTED
))
255 result
+= " PROTECTED";
256 if (state
& (1 << STATE_READONLY
))
257 result
+= " READONLY";
258 if (state
& (1 << STATE_REQUIRED
))
259 result
+= " REQUIRED";
260 if (state
& (1 << STATE_SELECTABLE
))
261 result
+= " SELECTABLE";
262 if (state
& (1 << STATE_SELECTED
))
263 result
+= " SELECTED";
264 if (state
& (1 << STATE_TRAVERSED
))
265 result
+= " TRAVERSED";
266 if (state
& (1 << STATE_UNAVAILABLE
))
267 result
+= " UNAVAILABLE";
268 if (state
& (1 << STATE_VERTICAL
))
269 result
+= " VERTICAL";
270 if (state
& (1 << STATE_VISITED
))
271 result
+= " VISITED";
273 std::string tmp
= UTF16ToUTF8(name
);
274 RemoveChars(tmp
, "\n", &tmp
);
276 result
+= " name=" + tmp
;
278 tmp
= UTF16ToUTF8(value
);
279 RemoveChars(tmp
, "\n", &tmp
);
281 result
+= " value=" + tmp
;
283 result
+= " (" + IntToString(location
.x()) + ", " +
284 IntToString(location
.y()) + ")-(" +
285 IntToString(location
.width()) + ", " +
286 IntToString(location
.height()) + ")";
288 for (std::map
<IntAttribute
, int32
>::const_iterator iter
=
289 int_attributes
.begin();
290 iter
!= int_attributes
.end();
292 std::string value
= IntToString(iter
->second
);
293 switch (iter
->first
) {
295 result
+= " scroll_x=" + value
;
297 case ATTR_SCROLL_X_MIN
:
298 result
+= " scroll_x_min=" + value
;
300 case ATTR_SCROLL_X_MAX
:
301 result
+= " scroll_x_max=" + value
;
304 result
+= " scroll_y=" + value
;
306 case ATTR_SCROLL_Y_MIN
:
307 result
+= " scroll_y_min=" + value
;
309 case ATTR_SCROLL_Y_MAX
:
310 result
+= " scroll_y_max=" + value
;
312 case ATTR_HIERARCHICAL_LEVEL
:
313 result
+= " level=" + value
;
315 case ATTR_TEXT_SEL_START
:
316 result
+= " sel_start=" + value
;
318 case ATTR_TEXT_SEL_END
:
319 result
+= " sel_end=" + value
;
321 case ATTR_TABLE_ROW_COUNT
:
322 result
+= " rows=" + value
;
324 case ATTR_TABLE_COLUMN_COUNT
:
325 result
+= " cols=" + value
;
327 case ATTR_TABLE_CELL_COLUMN_INDEX
:
328 result
+= " col=" + value
;
330 case ATTR_TABLE_CELL_ROW_INDEX
:
331 result
+= " row=" + value
;
333 case ATTR_TABLE_CELL_COLUMN_SPAN
:
334 result
+= " colspan=" + value
;
336 case ATTR_TABLE_CELL_ROW_SPAN
:
337 result
+= " rowspan=" + value
;
339 case ATTR_TABLE_COLUMN_HEADER_ID
:
340 result
+= " column_header_id=" + value
;
342 case ATTR_TABLE_COLUMN_INDEX
:
343 result
+= " column_index=" + value
;
345 case ATTR_TABLE_HEADER_ID
:
346 result
+= " header_id=" + value
;
348 case ATTR_TABLE_ROW_HEADER_ID
:
349 result
+= " row_header_id=" + value
;
351 case ATTR_TABLE_ROW_INDEX
:
352 result
+= " row_index=" + value
;
354 case ATTR_TITLE_UI_ELEMENT
:
355 result
+= " title_elem=" + value
;
357 case ATTR_COLOR_VALUE_RED
:
358 result
+= " color_value_red=" + value
;
360 case ATTR_COLOR_VALUE_GREEN
:
361 result
+= " color_value_green=" + value
;
363 case ATTR_COLOR_VALUE_BLUE
:
364 result
+= " color_value_blue=" + value
;
369 for (std::map
<StringAttribute
, string16
>::const_iterator iter
=
370 string_attributes
.begin();
371 iter
!= string_attributes
.end();
373 std::string value
= UTF16ToUTF8(iter
->second
);
374 switch (iter
->first
) {
376 result
+= " doc_url=" + value
;
379 result
+= " doc_title=" + value
;
381 case ATTR_DOC_MIMETYPE
:
382 result
+= " doc_mimetype=" + value
;
384 case ATTR_DOC_DOCTYPE
:
385 result
+= " doc_doctype=" + value
;
387 case ATTR_ACCESS_KEY
:
388 result
+= " access_key=" + value
;
391 result
+= " action=" + value
;
393 case ATTR_DESCRIPTION
:
394 result
+= " description=" + value
;
397 result
+= " display=" + value
;
400 result
+= " help=" + value
;
403 result
+= " html_tag=" + value
;
405 case ATTR_LIVE_RELEVANT
:
406 result
+= " relevant=" + value
;
408 case ATTR_LIVE_STATUS
:
409 result
+= " live=" + value
;
411 case ATTR_CONTAINER_LIVE_RELEVANT
:
412 result
+= " container_relevant=" + value
;
414 case ATTR_CONTAINER_LIVE_STATUS
:
415 result
+= " container_live=" + value
;
418 result
+= " role=" + value
;
421 result
+= " shortcut=" + value
;
424 result
+= " url=" + value
;
429 for (std::map
<FloatAttribute
, float>::const_iterator iter
=
430 float_attributes
.begin();
431 iter
!= float_attributes
.end();
433 std::string value
= DoubleToString(iter
->second
);
434 switch (iter
->first
) {
435 case ATTR_DOC_LOADING_PROGRESS
:
436 result
+= " doc_progress=" + value
;
438 case ATTR_VALUE_FOR_RANGE
:
439 result
+= " value_for_range=" + value
;
441 case ATTR_MAX_VALUE_FOR_RANGE
:
442 result
+= " max_value=" + value
;
444 case ATTR_MIN_VALUE_FOR_RANGE
:
445 result
+= " min_value=" + value
;
450 for (std::map
<BoolAttribute
, bool>::const_iterator iter
=
451 bool_attributes
.begin();
452 iter
!= bool_attributes
.end();
454 std::string value
= iter
->second
? "true" : "false";
455 switch (iter
->first
) {
456 case ATTR_DOC_LOADED
:
457 result
+= " doc_loaded=" + value
;
459 case ATTR_BUTTON_MIXED
:
460 result
+= " mixed=" + value
;
462 case ATTR_LIVE_ATOMIC
:
463 result
+= " atomic=" + value
;
466 result
+= " busy=" + value
;
468 case ATTR_CONTAINER_LIVE_ATOMIC
:
469 result
+= " container_atomic=" + value
;
471 case ATTR_CONTAINER_LIVE_BUSY
:
472 result
+= " container_busy=" + value
;
474 case ATTR_ARIA_READONLY
:
475 result
+= " aria_readonly=" + value
;
477 case ATTR_CAN_SET_VALUE
:
478 result
+= " can_set_value=" + value
;
480 case ATTR_UPDATE_LOCATION_ONLY
:
481 result
+= " update_location_only=" + value
;
486 if (!child_ids
.empty())
487 result
+= " child_ids=" + IntVectorToString(child_ids
);
489 if (!indirect_child_ids
.empty())
490 result
+= " indirect_child_ids=" + IntVectorToString(indirect_child_ids
);
492 if (!line_breaks
.empty())
493 result
+= " line_breaks=" + IntVectorToString(line_breaks
);
495 if (!cell_ids
.empty())
496 result
+= " cell_ids=" + IntVectorToString(cell_ids
);
501 std::string
AccessibilityNodeDataTreeNode::DebugString(bool recursive
) const {
504 static int indent
= 0;
506 for (int i
= 0; i
< indent
; ++i
)
509 result
+= AccessibilityNodeData::DebugString(recursive
);
514 for (size_t i
= 0; i
< children
.size(); ++i
)
515 result
+= children
[i
].DebugString(true);
522 #endif // ifndef NDEBUG
524 } // namespace content