1 // Copyright 2013 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 "ui/accessibility/ax_node_data.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
14 using base::DoubleToString
;
15 using base::IntToString
;
21 std::string
IntVectorToString(const std::vector
<int>& items
) {
23 for (size_t i
= 0; i
< items
.size(); ++i
) {
26 str
+= IntToString(items
[i
]);
31 // Predicate that returns true if the first value of a pair is |first|.
32 template<typename FirstType
, typename SecondType
>
34 FirstIs(FirstType first
)
36 bool operator()(std::pair
<FirstType
, SecondType
> const& p
) {
37 return p
.first
== first_
;
42 // Helper function that finds a key in a vector of pairs by matching on the
43 // first value, and returns an iterator.
44 template<typename FirstType
, typename SecondType
>
45 typename
std::vector
<std::pair
<FirstType
, SecondType
>>::const_iterator
48 const std::vector
<std::pair
<FirstType
, SecondType
>>& vector
) {
49 return std::find_if(vector
.begin(),
51 FirstIs
<FirstType
, SecondType
>(first
));
56 AXNodeData::AXNodeData()
58 role(AX_ROLE_UNKNOWN
),
62 AXNodeData::~AXNodeData() {
65 bool AXNodeData::HasBoolAttribute(AXBoolAttribute attribute
) const {
66 auto iter
= FindInVectorOfPairs(attribute
, bool_attributes
);
67 return iter
!= bool_attributes
.end();
70 bool AXNodeData::GetBoolAttribute(AXBoolAttribute attribute
) const {
72 if (GetBoolAttribute(attribute
, &result
))
77 bool AXNodeData::GetBoolAttribute(
78 AXBoolAttribute attribute
, bool* value
) const {
79 auto iter
= FindInVectorOfPairs(attribute
, bool_attributes
);
80 if (iter
!= bool_attributes
.end()) {
81 *value
= iter
->second
;
88 bool AXNodeData::HasFloatAttribute(AXFloatAttribute attribute
) const {
89 auto iter
= FindInVectorOfPairs(attribute
, float_attributes
);
90 return iter
!= float_attributes
.end();
93 float AXNodeData::GetFloatAttribute(AXFloatAttribute attribute
) const {
95 if (GetFloatAttribute(attribute
, &result
))
100 bool AXNodeData::GetFloatAttribute(
101 AXFloatAttribute attribute
, float* value
) const {
102 auto iter
= FindInVectorOfPairs(attribute
, float_attributes
);
103 if (iter
!= float_attributes
.end()) {
104 *value
= iter
->second
;
111 bool AXNodeData::HasIntAttribute(AXIntAttribute attribute
) const {
112 auto iter
= FindInVectorOfPairs(attribute
, int_attributes
);
113 return iter
!= int_attributes
.end();
116 int AXNodeData::GetIntAttribute(AXIntAttribute attribute
) const {
118 if (GetIntAttribute(attribute
, &result
))
123 bool AXNodeData::GetIntAttribute(
124 AXIntAttribute attribute
, int* value
) const {
125 auto iter
= FindInVectorOfPairs(attribute
, int_attributes
);
126 if (iter
!= int_attributes
.end()) {
127 *value
= iter
->second
;
134 bool AXNodeData::HasStringAttribute(AXStringAttribute attribute
) const {
135 auto iter
= FindInVectorOfPairs(attribute
, string_attributes
);
136 return iter
!= string_attributes
.end();
139 const std::string
& AXNodeData::GetStringAttribute(
140 AXStringAttribute attribute
) const {
141 CR_DEFINE_STATIC_LOCAL(std::string
, empty_string
, ());
142 auto iter
= FindInVectorOfPairs(attribute
, string_attributes
);
143 return iter
!= string_attributes
.end() ? iter
->second
: empty_string
;
146 bool AXNodeData::GetStringAttribute(
147 AXStringAttribute attribute
, std::string
* value
) const {
148 auto iter
= FindInVectorOfPairs(attribute
, string_attributes
);
149 if (iter
!= string_attributes
.end()) {
150 *value
= iter
->second
;
157 base::string16
AXNodeData::GetString16Attribute(
158 AXStringAttribute attribute
) const {
159 std::string value_utf8
;
160 if (!GetStringAttribute(attribute
, &value_utf8
))
161 return base::string16();
162 return base::UTF8ToUTF16(value_utf8
);
165 bool AXNodeData::GetString16Attribute(
166 AXStringAttribute attribute
,
167 base::string16
* value
) const {
168 std::string value_utf8
;
169 if (!GetStringAttribute(attribute
, &value_utf8
))
171 *value
= base::UTF8ToUTF16(value_utf8
);
175 bool AXNodeData::HasIntListAttribute(AXIntListAttribute attribute
) const {
176 auto iter
= FindInVectorOfPairs(attribute
, intlist_attributes
);
177 return iter
!= intlist_attributes
.end();
180 const std::vector
<int32
>& AXNodeData::GetIntListAttribute(
181 AXIntListAttribute attribute
) const {
182 CR_DEFINE_STATIC_LOCAL(std::vector
<int32
>, empty_vector
, ());
183 auto iter
= FindInVectorOfPairs(attribute
, intlist_attributes
);
184 if (iter
!= intlist_attributes
.end())
189 bool AXNodeData::GetIntListAttribute(
190 AXIntListAttribute attribute
, std::vector
<int32
>* value
) const {
191 auto iter
= FindInVectorOfPairs(attribute
, intlist_attributes
);
192 if (iter
!= intlist_attributes
.end()) {
193 *value
= iter
->second
;
200 bool AXNodeData::GetHtmlAttribute(
201 const char* html_attr
, std::string
* value
) const {
202 for (size_t i
= 0; i
< html_attributes
.size(); ++i
) {
203 const std::string
& attr
= html_attributes
[i
].first
;
204 if (base::LowerCaseEqualsASCII(attr
, html_attr
)) {
205 *value
= html_attributes
[i
].second
;
213 bool AXNodeData::GetHtmlAttribute(
214 const char* html_attr
, base::string16
* value
) const {
215 std::string value_utf8
;
216 if (!GetHtmlAttribute(html_attr
, &value_utf8
))
218 *value
= base::UTF8ToUTF16(value_utf8
);
222 void AXNodeData::AddStringAttribute(
223 AXStringAttribute attribute
, const std::string
& value
) {
224 string_attributes
.push_back(std::make_pair(attribute
, value
));
227 void AXNodeData::AddIntAttribute(
228 AXIntAttribute attribute
, int value
) {
229 int_attributes
.push_back(std::make_pair(attribute
, value
));
232 void AXNodeData::AddFloatAttribute(
233 AXFloatAttribute attribute
, float value
) {
234 float_attributes
.push_back(std::make_pair(attribute
, value
));
237 void AXNodeData::AddBoolAttribute(
238 AXBoolAttribute attribute
, bool value
) {
239 bool_attributes
.push_back(std::make_pair(attribute
, value
));
242 void AXNodeData::AddIntListAttribute(
243 AXIntListAttribute attribute
, const std::vector
<int32
>& value
) {
244 intlist_attributes
.push_back(std::make_pair(attribute
, value
));
247 void AXNodeData::SetName(std::string name
) {
248 string_attributes
.push_back(std::make_pair(AX_ATTR_NAME
, name
));
251 void AXNodeData::SetValue(std::string value
) {
252 string_attributes
.push_back(std::make_pair(AX_ATTR_VALUE
, value
));
255 std::string
AXNodeData::ToString() const {
258 result
+= "id=" + IntToString(id
);
259 result
+= " " + ui::ToString(role
);
261 if (state
& (1 << AX_STATE_BUSY
))
263 if (state
& (1 << AX_STATE_CHECKED
))
264 result
+= " CHECKED";
265 if (state
& (1 << AX_STATE_COLLAPSED
))
266 result
+= " COLLAPSED";
267 if (state
& (1 << AX_STATE_EDITABLE
))
268 result
+= " EDITABLE";
269 if (state
& (1 << AX_STATE_EXPANDED
))
270 result
+= " EXPANDED";
271 if (state
& (1 << AX_STATE_FOCUSABLE
))
272 result
+= " FOCUSABLE";
273 if (state
& (1 << AX_STATE_FOCUSED
))
274 result
+= " FOCUSED";
275 if (state
& (1 << AX_STATE_HASPOPUP
))
276 result
+= " HASPOPUP";
277 if (state
& (1 << AX_STATE_HOVERED
))
278 result
+= " HOVERED";
279 if (state
& (1 << AX_STATE_INDETERMINATE
))
280 result
+= " INDETERMINATE";
281 if (state
& (1 << AX_STATE_INVISIBLE
))
282 result
+= " INVISIBLE";
283 if (state
& (1 << AX_STATE_LINKED
))
285 if (state
& (1 << AX_STATE_MULTISELECTABLE
))
286 result
+= " MULTISELECTABLE";
287 if (state
& (1 << AX_STATE_OFFSCREEN
))
288 result
+= " OFFSCREEN";
289 if (state
& (1 << AX_STATE_PRESSED
))
290 result
+= " PRESSED";
291 if (state
& (1 << AX_STATE_PROTECTED
))
292 result
+= " PROTECTED";
293 if (state
& (1 << AX_STATE_READ_ONLY
))
294 result
+= " READONLY";
295 if (state
& (1 << AX_STATE_REQUIRED
))
296 result
+= " REQUIRED";
297 if (state
& (1 << AX_STATE_RICHLY_EDITABLE
))
298 result
+= " RICHLY_EDITABLE";
299 if (state
& (1 << AX_STATE_SELECTABLE
))
300 result
+= " SELECTABLE";
301 if (state
& (1 << AX_STATE_SELECTED
))
302 result
+= " SELECTED";
303 if (state
& (1 << AX_STATE_VERTICAL
))
304 result
+= " VERTICAL";
305 if (state
& (1 << AX_STATE_VISITED
))
306 result
+= " VISITED";
308 result
+= " (" + IntToString(location
.x()) + ", " +
309 IntToString(location
.y()) + ")-(" +
310 IntToString(location
.width()) + ", " +
311 IntToString(location
.height()) + ")";
313 for (size_t i
= 0; i
< int_attributes
.size(); ++i
) {
314 std::string value
= IntToString(int_attributes
[i
].second
);
315 switch (int_attributes
[i
].first
) {
316 case AX_ATTR_SCROLL_X
:
317 result
+= " scroll_x=" + value
;
319 case AX_ATTR_SCROLL_X_MIN
:
320 result
+= " scroll_x_min=" + value
;
322 case AX_ATTR_SCROLL_X_MAX
:
323 result
+= " scroll_x_max=" + value
;
325 case AX_ATTR_SCROLL_Y
:
326 result
+= " scroll_y=" + value
;
328 case AX_ATTR_SCROLL_Y_MIN
:
329 result
+= " scroll_y_min=" + value
;
331 case AX_ATTR_SCROLL_Y_MAX
:
332 result
+= " scroll_y_max=" + value
;
334 case AX_ATTR_HIERARCHICAL_LEVEL
:
335 result
+= " level=" + value
;
337 case AX_ATTR_ANCHOR_OBJECT_ID
:
338 result
+= " anchor_object_id=" + value
;
340 case AX_ATTR_ANCHOR_OFFSET
:
341 result
+= " anchor_offset=" + value
;
343 case AX_ATTR_FOCUS_OBJECT_ID
:
344 result
+= " focus_object_id=" + value
;
346 case AX_ATTR_FOCUS_OFFSET
:
347 result
+= " focus_offset=" + value
;
349 case AX_ATTR_TEXT_SEL_START
:
350 result
+= " sel_start=" + value
;
352 case AX_ATTR_TEXT_SEL_END
:
353 result
+= " sel_end=" + value
;
355 case AX_ATTR_TABLE_ROW_COUNT
:
356 result
+= " rows=" + value
;
358 case AX_ATTR_TABLE_COLUMN_COUNT
:
359 result
+= " cols=" + value
;
361 case AX_ATTR_TABLE_CELL_COLUMN_INDEX
:
362 result
+= " col=" + value
;
364 case AX_ATTR_TABLE_CELL_ROW_INDEX
:
365 result
+= " row=" + value
;
367 case AX_ATTR_TABLE_CELL_COLUMN_SPAN
:
368 result
+= " colspan=" + value
;
370 case AX_ATTR_TABLE_CELL_ROW_SPAN
:
371 result
+= " rowspan=" + value
;
373 case AX_ATTR_TABLE_COLUMN_HEADER_ID
:
374 result
+= " column_header_id=" + value
;
376 case AX_ATTR_TABLE_COLUMN_INDEX
:
377 result
+= " column_index=" + value
;
379 case AX_ATTR_TABLE_HEADER_ID
:
380 result
+= " header_id=" + value
;
382 case AX_ATTR_TABLE_ROW_HEADER_ID
:
383 result
+= " row_header_id=" + value
;
385 case AX_ATTR_TABLE_ROW_INDEX
:
386 result
+= " row_index=" + value
;
388 case AX_ATTR_SORT_DIRECTION
:
389 switch (int_attributes
[i
].second
) {
390 case AX_SORT_DIRECTION_UNSORTED
:
391 result
+= " sort_direction=none";
393 case AX_SORT_DIRECTION_ASCENDING
:
394 result
+= " sort_direction=ascending";
396 case AX_SORT_DIRECTION_DESCENDING
:
397 result
+= " sort_direction=descending";
399 case AX_SORT_DIRECTION_OTHER
:
400 result
+= " sort_direction=other";
404 case AX_ATTR_TITLE_UI_ELEMENT
:
405 result
+= " title_elem=" + value
;
407 case AX_ATTR_ACTIVEDESCENDANT_ID
:
408 result
+= " activedescendant=" + value
;
410 case AX_ATTR_TREE_ID
:
411 result
+= " tree_id=" + value
;
413 case AX_ATTR_CHILD_TREE_ID
:
414 result
+= " child_tree_id=" + value
;
416 case AX_ATTR_PARENT_TREE_ID
:
417 result
+= " parent_tree_id=" + value
;
419 case AX_ATTR_COLOR_VALUE
:
420 result
+= base::StringPrintf(" color_value=&%X",
421 int_attributes
[i
].second
);
423 case AX_ATTR_BACKGROUND_COLOR
:
424 result
+= base::StringPrintf(" background_color=&%X",
425 int_attributes
[i
].second
);
428 result
+= base::StringPrintf(" color=&%X", int_attributes
[i
].second
);
430 case AX_ATTR_TEXT_DIRECTION
:
431 switch (int_attributes
[i
].second
) {
432 case AX_TEXT_DIRECTION_LTR
:
433 result
+= " text_direction=ltr";
435 case AX_TEXT_DIRECTION_RTL
:
436 result
+= " text_direction=rtl";
438 case AX_TEXT_DIRECTION_TTB
:
439 result
+= " text_direction=ttb";
441 case AX_TEXT_DIRECTION_BTT
:
442 result
+= " text_direction=btt";
445 case AX_ATTR_TEXT_STYLE
: {
446 unsigned int text_style
= int_attributes
[i
].second
;
447 if (text_style
== AX_TEXT_STYLE_NONE
)
449 std::string
text_style_value(" text_style=");
450 if (text_style
& AX_TEXT_STYLE_BOLD
)
451 text_style_value
+= "bold,";
452 if (text_style
& AX_TEXT_STYLE_ITALIC
)
453 text_style_value
+= "italic,";
454 if (text_style
& AX_TEXT_STYLE_UNDERLINE
)
455 text_style_value
+= "underline,";
456 if (text_style
& AX_TEXT_STYLE_LINE_THROUGH
)
457 text_style_value
+= "line-through,";
458 result
+= text_style_value
.substr(0, text_style_value
.size() - 1);;
461 case AX_ATTR_SET_SIZE
:
462 result
+= " setsize=" + value
;
464 case AX_ATTR_POS_IN_SET
:
465 result
+= " posinset=" + value
;
467 case AX_ATTR_INVALID_STATE
:
468 switch (int_attributes
[i
].second
) {
469 case AX_INVALID_STATE_FALSE
:
470 result
+= " invalid_state=false";
472 case AX_INVALID_STATE_TRUE
:
473 result
+= " invalid_state=true";
475 case AX_INVALID_STATE_SPELLING
:
476 result
+= " invalid_state=spelling";
478 case AX_INVALID_STATE_GRAMMAR
:
479 result
+= " invalid_state=grammar";
481 case AX_INVALID_STATE_OTHER
:
482 result
+= " invalid_state=other";
486 case AX_INT_ATTRIBUTE_NONE
:
491 for (size_t i
= 0; i
< string_attributes
.size(); ++i
) {
492 std::string value
= string_attributes
[i
].second
;
493 switch (string_attributes
[i
].first
) {
494 case AX_ATTR_DOC_URL
:
495 result
+= " doc_url=" + value
;
497 case AX_ATTR_DOC_TITLE
:
498 result
+= " doc_title=" + value
;
500 case AX_ATTR_DOC_MIMETYPE
:
501 result
+= " doc_mimetype=" + value
;
503 case AX_ATTR_DOC_DOCTYPE
:
504 result
+= " doc_doctype=" + value
;
506 case AX_ATTR_ACCESS_KEY
:
507 result
+= " access_key=" + value
;
510 result
+= " action=" + value
;
512 case AX_ATTR_AUTO_COMPLETE
:
513 result
+= " autocomplete=" + value
;
515 case AX_ATTR_DESCRIPTION
:
516 result
+= " description=" + value
;
518 case AX_ATTR_DISPLAY
:
519 result
+= " display=" + value
;
522 result
+= " help=" + value
;
524 case AX_ATTR_HTML_TAG
:
525 result
+= " html_tag=" + value
;
527 case AX_ATTR_ARIA_INVALID_VALUE
:
528 result
+= " aria_invalid_value=" + value
;
530 case AX_ATTR_LIVE_RELEVANT
:
531 result
+= " relevant=" + value
;
533 case AX_ATTR_LIVE_STATUS
:
534 result
+= " live=" + value
;
536 case AX_ATTR_CONTAINER_LIVE_RELEVANT
:
537 result
+= " container_relevant=" + value
;
539 case AX_ATTR_CONTAINER_LIVE_STATUS
:
540 result
+= " container_live=" + value
;
542 case AX_ATTR_PLACEHOLDER
:
543 result
+= "placeholder" + value
;
546 result
+= " role=" + value
;
548 case AX_ATTR_SHORTCUT
:
549 result
+= " shortcut=" + value
;
552 result
+= " url=" + value
;
555 result
+= " name=" + value
;
558 result
+= " value=" + value
;
560 case AX_STRING_ATTRIBUTE_NONE
:
565 for (size_t i
= 0; i
< float_attributes
.size(); ++i
) {
566 std::string value
= DoubleToString(float_attributes
[i
].second
);
567 switch (float_attributes
[i
].first
) {
568 case AX_ATTR_DOC_LOADING_PROGRESS
:
569 result
+= " doc_progress=" + value
;
571 case AX_ATTR_VALUE_FOR_RANGE
:
572 result
+= " value_for_range=" + value
;
574 case AX_ATTR_MAX_VALUE_FOR_RANGE
:
575 result
+= " max_value=" + value
;
577 case AX_ATTR_MIN_VALUE_FOR_RANGE
:
578 result
+= " min_value=" + value
;
580 case AX_ATTR_FONT_SIZE
:
581 result
+= " font_size=" + value
;
583 case AX_FLOAT_ATTRIBUTE_NONE
:
588 for (size_t i
= 0; i
< bool_attributes
.size(); ++i
) {
589 std::string value
= bool_attributes
[i
].second
? "true" : "false";
590 switch (bool_attributes
[i
].first
) {
591 case AX_ATTR_DOC_LOADED
:
592 result
+= " doc_loaded=" + value
;
594 case AX_ATTR_BUTTON_MIXED
:
595 result
+= " mixed=" + value
;
597 case AX_ATTR_LIVE_ATOMIC
:
598 result
+= " atomic=" + value
;
600 case AX_ATTR_LIVE_BUSY
:
601 result
+= " busy=" + value
;
603 case AX_ATTR_CONTAINER_LIVE_ATOMIC
:
604 result
+= " container_atomic=" + value
;
606 case AX_ATTR_CONTAINER_LIVE_BUSY
:
607 result
+= " container_busy=" + value
;
609 case AX_ATTR_ARIA_READONLY
:
610 result
+= " aria_readonly=" + value
;
612 case AX_ATTR_CAN_SET_VALUE
:
613 result
+= " can_set_value=" + value
;
615 case AX_ATTR_UPDATE_LOCATION_ONLY
:
616 result
+= " update_location_only=" + value
;
618 case AX_ATTR_CANVAS_HAS_FALLBACK
:
619 result
+= " has_fallback=" + value
;
621 case AX_BOOL_ATTRIBUTE_NONE
:
626 for (size_t i
= 0; i
< intlist_attributes
.size(); ++i
) {
627 const std::vector
<int32
>& values
= intlist_attributes
[i
].second
;
628 switch (intlist_attributes
[i
].first
) {
629 case AX_ATTR_INDIRECT_CHILD_IDS
:
630 result
+= " indirect_child_ids=" + IntVectorToString(values
);
632 case AX_ATTR_CONTROLS_IDS
:
633 result
+= " controls_ids=" + IntVectorToString(values
);
635 case AX_ATTR_DESCRIBEDBY_IDS
:
636 result
+= " describedby_ids=" + IntVectorToString(values
);
638 case AX_ATTR_FLOWTO_IDS
:
639 result
+= " flowto_ids=" + IntVectorToString(values
);
641 case AX_ATTR_LABELLEDBY_IDS
:
642 result
+= " labelledby_ids=" + IntVectorToString(values
);
644 case AX_ATTR_OWNS_IDS
:
645 result
+= " owns_ids=" + IntVectorToString(values
);
647 case AX_ATTR_LINE_BREAKS
:
648 result
+= " line_breaks=" + IntVectorToString(values
);
650 case AX_ATTR_CELL_IDS
:
651 result
+= " cell_ids=" + IntVectorToString(values
);
653 case AX_ATTR_UNIQUE_CELL_IDS
:
654 result
+= " unique_cell_ids=" + IntVectorToString(values
);
656 case AX_ATTR_CHARACTER_OFFSETS
:
657 result
+= " character_offsets=" + IntVectorToString(values
);
659 case AX_ATTR_WORD_STARTS
:
660 result
+= " word_starts=" + IntVectorToString(values
);
662 case AX_ATTR_WORD_ENDS
:
663 result
+= " word_ends=" + IntVectorToString(values
);
665 case AX_INT_LIST_ATTRIBUTE_NONE
:
670 if (!child_ids
.empty())
671 result
+= " child_ids=" + IntVectorToString(child_ids
);
676 bool AXNodeData::IsRoot() const {
677 return (role
== AX_ROLE_ROOT_WEB_AREA
||
678 role
== AX_ROLE_DESKTOP
);
681 void AXNodeData::SetRoot() {
682 role
= AX_ROLE_ROOT_WEB_AREA
;