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()
37 role(WebKit::WebAXRoleUnknown
),
41 AccessibilityNodeData::~AccessibilityNodeData() {
44 void AccessibilityNodeData::AddStringAttribute(
45 StringAttribute attribute
, const std::string
& value
) {
46 string_attributes
.push_back(std::make_pair(attribute
, value
));
49 void AccessibilityNodeData::AddIntAttribute(
50 IntAttribute attribute
, int value
) {
51 int_attributes
.push_back(std::make_pair(attribute
, value
));
54 void AccessibilityNodeData::AddFloatAttribute(
55 FloatAttribute attribute
, float value
) {
56 float_attributes
.push_back(std::make_pair(attribute
, value
));
59 void AccessibilityNodeData::AddBoolAttribute(
60 BoolAttribute attribute
, bool value
) {
61 bool_attributes
.push_back(std::make_pair(attribute
, value
));
64 void AccessibilityNodeData::AddIntListAttribute(
65 IntListAttribute attribute
, const std::vector
<int32
>& value
) {
66 intlist_attributes
.push_back(std::make_pair(attribute
, value
));
69 void AccessibilityNodeData::SetName(std::string name
) {
70 string_attributes
.push_back(std::make_pair(ATTR_NAME
, name
));
73 AccessibilityNodeDataTreeNode::AccessibilityNodeDataTreeNode()
74 : AccessibilityNodeData() {
77 AccessibilityNodeDataTreeNode::~AccessibilityNodeDataTreeNode() {
80 AccessibilityNodeDataTreeNode
& AccessibilityNodeDataTreeNode::operator=(
81 const AccessibilityNodeData
& src
) {
82 AccessibilityNodeData::operator=(src
);
86 void MakeAccessibilityNodeDataTree(
87 const std::vector
<AccessibilityNodeData
>& src_vector
,
88 AccessibilityNodeDataTreeNode
* dst_root
) {
89 // This method assumes |src_vector| contains all of the nodes of
90 // an accessibility tree, and that each parent comes before its
91 // children. Each node has an id, and the ids of its children.
92 // The output is a tree where each node contains its children.
94 // Initialize a hash map with all of the ids in |src_vector|.
95 base::hash_map
<int32
, AccessibilityNodeDataTreeNode
*> id_map
;
96 for (size_t i
= 0; i
< src_vector
.size(); ++i
)
97 id_map
[src_vector
[i
].id
] = NULL
;
99 // Copy the nodes to the output tree one at a time.
100 for (size_t i
= 0; i
< src_vector
.size(); ++i
) {
101 const AccessibilityNodeData
& src_node
= src_vector
[i
];
102 AccessibilityNodeDataTreeNode
* dst_node
;
104 // If it's the first element in the vector, assume it's
105 // the root. For any other element, look for it in our
106 // hash map, and skip it if not there (meaning there was
107 // an extranous node, or the nodes were sent in the wrong
112 dst_node
= id_map
[src_node
.id
];
117 // Copy the node data.
118 *dst_node
= src_node
;
120 // Add placeholders for all of the node's children in the tree,
121 // and add them to the hash map so we can find them when we
122 // encounter them in |src_vector|.
123 dst_node
->children
.reserve(src_node
.child_ids
.size());
124 for (size_t j
= 0; j
< src_node
.child_ids
.size(); ++j
) {
125 int child_id
= src_node
.child_ids
[j
];
126 if (id_map
.find(child_id
) != id_map
.end()) {
127 dst_node
->children
.push_back(AccessibilityNodeDataTreeNode());
128 id_map
[child_id
] = &dst_node
->children
.back();
135 std::string
AccessibilityNodeData::DebugString(bool recursive
) const {
138 result
+= "id=" + IntToString(id
);
141 case WebKit::WebAXRoleAlert
: result
+= " ALERT"; break;
142 case WebKit::WebAXRoleAlertDialog
: result
+= " ALERT_DIALOG"; break;
143 case WebKit::WebAXRoleAnnotation
: result
+= " ANNOTATION"; break;
144 case WebKit::WebAXRoleApplication
: result
+= " APPLICATION"; break;
145 case WebKit::WebAXRoleArticle
: result
+= " ARTICLE"; break;
146 case WebKit::WebAXRoleBanner
: result
+= " L_BANNER"; break;
147 case WebKit::WebAXRoleBrowser
: result
+= " BROWSER"; break;
148 case WebKit::WebAXRoleBusyIndicator
: result
+= " BUSY_INDICATOR"; break;
149 case WebKit::WebAXRoleButton
: result
+= " BUTTON"; break;
150 case WebKit::WebAXRoleCanvas
: result
+= " CANVAS"; break;
151 case WebKit::WebAXRoleCell
: result
+= " CELL"; break;
152 case WebKit::WebAXRoleCheckBox
: result
+= " CHECKBOX"; break;
153 case WebKit::WebAXRoleColorWell
: result
+= " COLOR_WELL"; break;
154 case WebKit::WebAXRoleColumn
: result
+= " COLUMN"; break;
155 case WebKit::WebAXRoleColumnHeader
: result
+= " COLUMN_HEADER"; break;
156 case WebKit::WebAXRoleComboBox
: result
+= " COMBO_BOX"; break;
157 case WebKit::WebAXRoleComplementary
: result
+= " L_COMPLEMENTARY"; break;
158 case WebKit::WebAXRoleContentInfo
: result
+= " L_CONTENTINFO"; break;
159 case WebKit::WebAXRoleDefinition
: result
+= " DEFINITION"; break;
160 case WebKit::WebAXRoleDescriptionListDetail
: result
+= " DD"; break;
161 case WebKit::WebAXRoleDescriptionListTerm
: result
+= " DT"; break;
162 case WebKit::WebAXRoleDialog
: result
+= " DIALOG"; break;
163 case WebKit::WebAXRoleDirectory
: result
+= " DIRECTORY"; break;
164 case WebKit::WebAXRoleDisclosureTriangle
:
165 result
+= " DISCLOSURE_TRIANGLE"; break;
166 case WebKit::WebAXRoleDiv
: result
+= " DIV"; break;
167 case WebKit::WebAXRoleDocument
: result
+= " DOCUMENT"; break;
168 case WebKit::WebAXRoleDrawer
: result
+= " DRAWER"; break;
169 case WebKit::WebAXRoleEditableText
: result
+= " EDITABLE_TEXT"; break;
170 case WebKit::WebAXRoleFooter
: result
+= " FOOTER"; break;
171 case WebKit::WebAXRoleForm
: result
+= " FORM"; break;
172 case WebKit::WebAXRoleGrid
: result
+= " GRID"; break;
173 case WebKit::WebAXRoleGroup
: result
+= " GROUP"; break;
174 case WebKit::WebAXRoleGrowArea
: result
+= " GROW_AREA"; break;
175 case WebKit::WebAXRoleHeading
: result
+= " HEADING"; break;
176 case WebKit::WebAXRoleHelpTag
: result
+= " HELP_TAG"; break;
177 case WebKit::WebAXRoleHorizontalRule
: result
+= " HORIZONTAL_RULE"; break;
178 case WebKit::WebAXRoleIgnored
: result
+= " IGNORED"; break;
179 case WebKit::WebAXRoleImage
: result
+= " IMAGE"; break;
180 case WebKit::WebAXRoleImageMap
: result
+= " IMAGE_MAP"; break;
181 case WebKit::WebAXRoleImageMapLink
: result
+= " IMAGE_MAP_LINK"; break;
182 case WebKit::WebAXRoleIncrementor
: result
+= " INCREMENTOR"; break;
183 case WebKit::WebAXRoleLabel
: result
+= " LABEL"; break;
184 case WebKit::WebAXRoleLink
: result
+= " LINK"; break;
185 case WebKit::WebAXRoleList
: result
+= " LIST"; break;
186 case WebKit::WebAXRoleListBox
: result
+= " LISTBOX"; break;
187 case WebKit::WebAXRoleListBoxOption
: result
+= " LISTBOX_OPTION"; break;
188 case WebKit::WebAXRoleListItem
: result
+= " LIST_ITEM"; break;
189 case WebKit::WebAXRoleListMarker
: result
+= " LIST_MARKER"; break;
190 case WebKit::WebAXRoleLog
: result
+= " LOG"; break;
191 case WebKit::WebAXRoleMain
: result
+= " L_MAIN"; break;
192 case WebKit::WebAXRoleMarquee
: result
+= " MARQUEE"; break;
193 case WebKit::WebAXRoleMath
: result
+= " MATH"; break;
194 case WebKit::WebAXRoleMatte
: result
+= " MATTE"; break;
195 case WebKit::WebAXRoleMenu
: result
+= " MENU"; break;
196 case WebKit::WebAXRoleMenuBar
: result
+= " MENU_BAR"; break;
197 case WebKit::WebAXRoleMenuButton
: result
+= " MENU_BUTTON"; break;
198 case WebKit::WebAXRoleMenuItem
: result
+= " MENU_ITEM"; break;
199 case WebKit::WebAXRoleMenuListOption
: result
+= " MENU_LIST_OPTION"; break;
200 case WebKit::WebAXRoleMenuListPopup
: result
+= " MENU_LIST_POPUP"; break;
201 case WebKit::WebAXRoleNavigation
: result
+= " L_NAVIGATION"; break;
202 case WebKit::WebAXRoleNote
: result
+= " NOTE"; break;
203 case WebKit::WebAXRoleOutline
: result
+= " OUTLINE"; break;
204 case WebKit::WebAXRoleParagraph
: result
+= " PARAGRAPH"; break;
205 case WebKit::WebAXRolePopUpButton
: result
+= " POPUP_BUTTON"; break;
206 case WebKit::WebAXRolePresentational
: result
+= " PRESENTATIONAL"; break;
207 case WebKit::WebAXRoleProgressIndicator
:
208 result
+= " PROGRESS_INDICATOR"; break;
209 case WebKit::WebAXRoleRadioButton
: result
+= " RADIO_BUTTON"; break;
210 case WebKit::WebAXRoleRadioGroup
: result
+= " RADIO_GROUP"; break;
211 case WebKit::WebAXRoleRegion
: result
+= " REGION"; break;
212 case WebKit::WebAXRoleRootWebArea
: result
+= " ROOT_WEB_AREA"; break;
213 case WebKit::WebAXRoleRow
: result
+= " ROW"; break;
214 case WebKit::WebAXRoleRowHeader
: result
+= " ROW_HEADER"; break;
215 case WebKit::WebAXRoleRuler
: result
+= " RULER"; break;
216 case WebKit::WebAXRoleRulerMarker
: result
+= " RULER_MARKER"; break;
217 case WebKit::WebAXRoleSVGRoot
: result
+= " SVG_ROOT"; break;
218 case WebKit::WebAXRoleScrollArea
: result
+= " SCROLLAREA"; break;
219 case WebKit::WebAXRoleScrollBar
: result
+= " SCROLLBAR"; break;
220 case WebKit::WebAXRoleSearch
: result
+= " L_SEARCH"; break;
221 case WebKit::WebAXRoleSheet
: result
+= " SHEET"; break;
222 case WebKit::WebAXRoleSlider
: result
+= " SLIDER"; break;
223 case WebKit::WebAXRoleSliderThumb
: result
+= " SLIDER_THUMB"; break;
224 case WebKit::WebAXRoleSpinButton
: result
+= " SPIN_BUTTON"; break;
225 case WebKit::WebAXRoleSpinButtonPart
: result
+= " SPIN_BUTTON_PART"; break;
226 case WebKit::WebAXRoleSplitGroup
: result
+= " SPLIT_GROUP"; break;
227 case WebKit::WebAXRoleSplitter
: result
+= " SPLITTER"; break;
228 case WebKit::WebAXRoleStaticText
: result
+= " STATIC_TEXT"; break;
229 case WebKit::WebAXRoleStatus
: result
+= " STATUS"; break;
230 case WebKit::WebAXRoleSystemWide
: result
+= " SYSTEM_WIDE"; break;
231 case WebKit::WebAXRoleTab
: result
+= " TAB"; break;
232 case WebKit::WebAXRoleTabList
: result
+= " TAB_LIST"; break;
233 case WebKit::WebAXRoleTabPanel
: result
+= " TAB_PANEL"; break;
234 case WebKit::WebAXRoleTable
: result
+= " TABLE"; break;
235 case WebKit::WebAXRoleTableHeaderContainer
:
236 result
+= " TABLE_HDR_CONTAINER"; break;
237 case WebKit::WebAXRoleTextArea
: result
+= " TEXTAREA"; break;
238 case WebKit::WebAXRoleTextField
: result
+= " TEXT_FIELD"; break;
239 case WebKit::WebAXRoleTimer
: result
+= " TIMER"; break;
240 case WebKit::WebAXRoleToggleButton
: result
+= " TOGGLE_BUTTON"; break;
241 case WebKit::WebAXRoleToolbar
: result
+= " TOOLBAR"; break;
242 case WebKit::WebAXRoleTree
: result
+= " TREE"; break;
243 case WebKit::WebAXRoleTreeGrid
: result
+= " TREE_GRID"; break;
244 case WebKit::WebAXRoleTreeItem
: result
+= " TREE_ITEM"; break;
245 case WebKit::WebAXRoleUnknown
: result
+= " UNKNOWN"; break;
246 case WebKit::WebAXRoleUserInterfaceTooltip
: result
+= " TOOLTIP"; break;
247 case WebKit::WebAXRoleValueIndicator
: result
+= " VALUE_INDICATOR"; break;
248 case WebKit::WebAXRoleWebArea
: result
+= " WEB_AREA"; break;
249 case WebKit::WebAXRoleWindow
: result
+= " WINDOW"; break;
254 if (state
& (1 << WebKit::WebAXStateBusy
))
256 if (state
& (1 << WebKit::WebAXStateChecked
))
257 result
+= " CHECKED";
258 if (state
& (1 << WebKit::WebAXStateCollapsed
))
259 result
+= " COLLAPSED";
260 if (state
& (1 << WebKit::WebAXStateExpanded
))
261 result
+= " EXPANDED";
262 if (state
& (1 << WebKit::WebAXStateFocusable
))
263 result
+= " FOCUSABLE";
264 if (state
& (1 << WebKit::WebAXStateFocused
))
265 result
+= " FOCUSED";
266 if (state
& (1 << WebKit::WebAXStateHaspopup
))
267 result
+= " HASPOPUP";
268 if (state
& (1 << WebKit::WebAXStateHovered
))
269 result
+= " HOTTRACKED";
270 if (state
& (1 << WebKit::WebAXStateIndeterminate
))
271 result
+= " INDETERMINATE";
272 if (state
& (1 << WebKit::WebAXStateInvisible
))
273 result
+= " INVISIBLE";
274 if (state
& (1 << WebKit::WebAXStateLinked
))
276 if (state
& (1 << WebKit::WebAXStateMultiselectable
))
277 result
+= " MULTISELECTABLE";
278 if (state
& (1 << WebKit::WebAXStateOffscreen
))
279 result
+= " OFFSCREEN";
280 if (state
& (1 << WebKit::WebAXStatePressed
))
281 result
+= " PRESSED";
282 if (state
& (1 << WebKit::WebAXStateProtected
))
283 result
+= " PROTECTED";
284 if (state
& (1 << WebKit::WebAXStateReadonly
))
285 result
+= " READONLY";
286 if (state
& (1 << WebKit::WebAXStateRequired
))
287 result
+= " REQUIRED";
288 if (state
& (1 << WebKit::WebAXStateSelectable
))
289 result
+= " SELECTABLE";
290 if (state
& (1 << WebKit::WebAXStateSelected
))
291 result
+= " SELECTED";
292 if (state
& (1 << WebKit::WebAXStateVertical
))
293 result
+= " VERTICAL";
294 if (state
& (1 << WebKit::WebAXStateVisited
))
295 result
+= " VISITED";
297 result
+= " (" + IntToString(location
.x()) + ", " +
298 IntToString(location
.y()) + ")-(" +
299 IntToString(location
.width()) + ", " +
300 IntToString(location
.height()) + ")";
302 for (size_t i
= 0; i
< int_attributes
.size(); ++i
) {
303 std::string value
= IntToString(int_attributes
[i
].second
);
304 switch (int_attributes
[i
].first
) {
306 result
+= " scroll_x=" + value
;
308 case ATTR_SCROLL_X_MIN
:
309 result
+= " scroll_x_min=" + value
;
311 case ATTR_SCROLL_X_MAX
:
312 result
+= " scroll_x_max=" + value
;
315 result
+= " scroll_y=" + value
;
317 case ATTR_SCROLL_Y_MIN
:
318 result
+= " scroll_y_min=" + value
;
320 case ATTR_SCROLL_Y_MAX
:
321 result
+= " scroll_y_max=" + value
;
323 case ATTR_HIERARCHICAL_LEVEL
:
324 result
+= " level=" + value
;
326 case ATTR_TEXT_SEL_START
:
327 result
+= " sel_start=" + value
;
329 case ATTR_TEXT_SEL_END
:
330 result
+= " sel_end=" + value
;
332 case ATTR_TABLE_ROW_COUNT
:
333 result
+= " rows=" + value
;
335 case ATTR_TABLE_COLUMN_COUNT
:
336 result
+= " cols=" + value
;
338 case ATTR_TABLE_CELL_COLUMN_INDEX
:
339 result
+= " col=" + value
;
341 case ATTR_TABLE_CELL_ROW_INDEX
:
342 result
+= " row=" + value
;
344 case ATTR_TABLE_CELL_COLUMN_SPAN
:
345 result
+= " colspan=" + value
;
347 case ATTR_TABLE_CELL_ROW_SPAN
:
348 result
+= " rowspan=" + value
;
350 case ATTR_TABLE_COLUMN_HEADER_ID
:
351 result
+= " column_header_id=" + value
;
353 case ATTR_TABLE_COLUMN_INDEX
:
354 result
+= " column_index=" + value
;
356 case ATTR_TABLE_HEADER_ID
:
357 result
+= " header_id=" + value
;
359 case ATTR_TABLE_ROW_HEADER_ID
:
360 result
+= " row_header_id=" + value
;
362 case ATTR_TABLE_ROW_INDEX
:
363 result
+= " row_index=" + value
;
365 case ATTR_TITLE_UI_ELEMENT
:
366 result
+= " title_elem=" + value
;
368 case ATTR_COLOR_VALUE_RED
:
369 result
+= " color_value_red=" + value
;
371 case ATTR_COLOR_VALUE_GREEN
:
372 result
+= " color_value_green=" + value
;
374 case ATTR_COLOR_VALUE_BLUE
:
375 result
+= " color_value_blue=" + value
;
380 for (size_t i
= 0; i
< string_attributes
.size(); ++i
) {
381 std::string value
= string_attributes
[i
].second
;
382 switch (string_attributes
[i
].first
) {
384 result
+= " doc_url=" + value
;
387 result
+= " doc_title=" + value
;
389 case ATTR_DOC_MIMETYPE
:
390 result
+= " doc_mimetype=" + value
;
392 case ATTR_DOC_DOCTYPE
:
393 result
+= " doc_doctype=" + value
;
395 case ATTR_ACCESS_KEY
:
396 result
+= " access_key=" + value
;
399 result
+= " action=" + value
;
401 case ATTR_DESCRIPTION
:
402 result
+= " description=" + value
;
405 result
+= " display=" + value
;
408 result
+= " help=" + value
;
411 result
+= " html_tag=" + value
;
413 case ATTR_LIVE_RELEVANT
:
414 result
+= " relevant=" + value
;
416 case ATTR_LIVE_STATUS
:
417 result
+= " live=" + value
;
419 case ATTR_CONTAINER_LIVE_RELEVANT
:
420 result
+= " container_relevant=" + value
;
422 case ATTR_CONTAINER_LIVE_STATUS
:
423 result
+= " container_live=" + value
;
426 result
+= " role=" + value
;
429 result
+= " shortcut=" + value
;
432 result
+= " url=" + value
;
435 result
+= " name=" + value
;
438 result
+= " value=" + value
;
443 for (size_t i
= 0; i
< float_attributes
.size(); ++i
) {
444 std::string value
= DoubleToString(float_attributes
[i
].second
);
445 switch (float_attributes
[i
].first
) {
446 case ATTR_DOC_LOADING_PROGRESS
:
447 result
+= " doc_progress=" + value
;
449 case ATTR_VALUE_FOR_RANGE
:
450 result
+= " value_for_range=" + value
;
452 case ATTR_MAX_VALUE_FOR_RANGE
:
453 result
+= " max_value=" + value
;
455 case ATTR_MIN_VALUE_FOR_RANGE
:
456 result
+= " min_value=" + value
;
461 for (size_t i
= 0; i
< bool_attributes
.size(); ++i
) {
462 std::string value
= bool_attributes
[i
].second
? "true" : "false";
463 switch (bool_attributes
[i
].first
) {
464 case ATTR_DOC_LOADED
:
465 result
+= " doc_loaded=" + value
;
467 case ATTR_BUTTON_MIXED
:
468 result
+= " mixed=" + value
;
470 case ATTR_LIVE_ATOMIC
:
471 result
+= " atomic=" + value
;
474 result
+= " busy=" + value
;
476 case ATTR_CONTAINER_LIVE_ATOMIC
:
477 result
+= " container_atomic=" + value
;
479 case ATTR_CONTAINER_LIVE_BUSY
:
480 result
+= " container_busy=" + value
;
482 case ATTR_ARIA_READONLY
:
483 result
+= " aria_readonly=" + value
;
485 case ATTR_CAN_SET_VALUE
:
486 result
+= " can_set_value=" + value
;
488 case ATTR_UPDATE_LOCATION_ONLY
:
489 result
+= " update_location_only=" + value
;
491 case ATTR_CANVAS_HAS_FALLBACK
:
492 result
+= " has_fallback=" + value
;
497 for (size_t i
= 0; i
< intlist_attributes
.size(); ++i
) {
498 const std::vector
<int32
>& values
= intlist_attributes
[i
].second
;
499 switch (intlist_attributes
[i
].first
) {
500 case ATTR_INDIRECT_CHILD_IDS
:
501 result
+= " indirect_child_ids=" + IntVectorToString(values
);
503 case ATTR_LINE_BREAKS
:
504 result
+= " line_breaks=" + IntVectorToString(values
);
507 result
+= " cell_ids=" + IntVectorToString(values
);
509 case ATTR_UNIQUE_CELL_IDS
:
510 result
+= " unique_cell_ids=" + IntVectorToString(values
);
515 if (!child_ids
.empty())
516 result
+= " child_ids=" + IntVectorToString(child_ids
);
521 std::string
AccessibilityNodeDataTreeNode::DebugString(bool recursive
) const {
524 static int indent
= 0;
526 for (int i
= 0; i
< indent
; ++i
)
529 result
+= AccessibilityNodeData::DebugString(recursive
);
534 for (size_t i
= 0; i
< children
.size(); ++i
)
535 result
+= children
[i
].DebugString(true);
542 #endif // ifndef NDEBUG
544 } // namespace content