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.
4
5 #include "ui/accessibility/ax_node_data.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <set>
11
12 #include "base/no_destructor.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "ui/accessibility/ax_enum_util.h"
19 #include "ui/accessibility/ax_enums.mojom.h"
20 #include "ui/accessibility/ax_role_properties.h"
21 #include "ui/accessibility/ax_text_utils.h"
22 #include "ui/gfx/transform.h"
23
24 namespace ui {
25
26 namespace {
27
IsFlagSet(uint32_t bitfield,uint32_t flag)28 bool IsFlagSet(uint32_t bitfield, uint32_t flag) {
29 return (bitfield & (1U << flag)) != 0;
30 }
31
IsFlagSet(uint64_t bitfield,uint32_t flag)32 bool IsFlagSet(uint64_t bitfield, uint32_t flag) {
33 return (bitfield & (1ULL << flag)) != 0;
34 }
35
ModifyFlag(uint32_t bitfield,uint32_t flag,bool set)36 uint32_t ModifyFlag(uint32_t bitfield, uint32_t flag, bool set) {
37 return set ? (bitfield |= (1U << flag)) : (bitfield &= ~(1U << flag));
38 }
39
ModifyFlag(uint64_t bitfield,uint32_t flag,bool set)40 uint64_t ModifyFlag(uint64_t bitfield, uint32_t flag, bool set) {
41 return set ? (bitfield |= (1ULL << flag)) : (bitfield &= ~(1ULL << flag));
42 }
43
StateBitfieldToString(uint32_t state_enum)44 std::string StateBitfieldToString(uint32_t state_enum) {
45 std::string str;
46 for (uint32_t i = static_cast<uint32_t>(ax::mojom::State::kNone) + 1;
47 i <= static_cast<uint32_t>(ax::mojom::State::kMaxValue); ++i) {
48 if (IsFlagSet(state_enum, i))
49 str += " " +
50 base::ToUpperASCII(ui::ToString(static_cast<ax::mojom::State>(i)));
51 }
52 return str;
53 }
54
ActionsBitfieldToString(uint64_t actions)55 std::string ActionsBitfieldToString(uint64_t actions) {
56 std::string str;
57 for (uint32_t i = static_cast<uint32_t>(ax::mojom::Action::kNone) + 1;
58 i <= static_cast<uint32_t>(ax::mojom::Action::kMaxValue); ++i) {
59 if (IsFlagSet(actions, i)) {
60 str += ui::ToString(static_cast<ax::mojom::Action>(i));
61 actions = ModifyFlag(actions, i, false);
62 str += actions ? "," : "";
63 }
64 }
65 return str;
66 }
67
IntVectorToString(const std::vector<int> & items)68 std::string IntVectorToString(const std::vector<int>& items) {
69 std::string str;
70 for (size_t i = 0; i < items.size(); ++i) {
71 if (i > 0)
72 str += ",";
73 str += base::NumberToString(items[i]);
74 }
75 return str;
76 }
77
78 // Predicate that returns true if the first value of a pair is |first|.
79 template <typename FirstType, typename SecondType>
80 struct FirstIs {
FirstIsui::__anon4a6c57cf0111::FirstIs81 explicit FirstIs(FirstType first) : first_(first) {}
operator ()ui::__anon4a6c57cf0111::FirstIs82 bool operator()(std::pair<FirstType, SecondType> const& p) {
83 return p.first == first_;
84 }
85 FirstType first_;
86 };
87
88 // Helper function that finds a key in a vector of pairs by matching on the
89 // first value, and returns an iterator.
90 template <typename FirstType, typename SecondType>
91 typename std::vector<std::pair<FirstType, SecondType>>::const_iterator
FindInVectorOfPairs(FirstType first,const std::vector<std::pair<FirstType,SecondType>> & vector)92 FindInVectorOfPairs(
93 FirstType first,
94 const std::vector<std::pair<FirstType, SecondType>>& vector) {
95 return std::find_if(vector.begin(), vector.end(),
96 FirstIs<FirstType, SecondType>(first));
97 }
98
99 } // namespace
100
101 // Return true if |attr| is a node ID that would need to be mapped when
102 // renumbering the ids in a combined tree.
IsNodeIdIntAttribute(ax::mojom::IntAttribute attr)103 bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr) {
104 switch (attr) {
105 case ax::mojom::IntAttribute::kActivedescendantId:
106 case ax::mojom::IntAttribute::kErrormessageId:
107 case ax::mojom::IntAttribute::kInPageLinkTargetId:
108 case ax::mojom::IntAttribute::kMemberOfId:
109 case ax::mojom::IntAttribute::kNextOnLineId:
110 case ax::mojom::IntAttribute::kPopupForId:
111 case ax::mojom::IntAttribute::kPreviousOnLineId:
112 case ax::mojom::IntAttribute::kTableHeaderId:
113 case ax::mojom::IntAttribute::kTableColumnHeaderId:
114 case ax::mojom::IntAttribute::kTableRowHeaderId:
115 case ax::mojom::IntAttribute::kNextFocusId:
116 case ax::mojom::IntAttribute::kPreviousFocusId:
117 return true;
118
119 // Note: all of the attributes are included here explicitly,
120 // rather than using "default:", so that it's a compiler error to
121 // add a new attribute without explicitly considering whether it's
122 // a node id attribute or not.
123 case ax::mojom::IntAttribute::kNone:
124 case ax::mojom::IntAttribute::kDefaultActionVerb:
125 case ax::mojom::IntAttribute::kScrollX:
126 case ax::mojom::IntAttribute::kScrollXMin:
127 case ax::mojom::IntAttribute::kScrollXMax:
128 case ax::mojom::IntAttribute::kScrollY:
129 case ax::mojom::IntAttribute::kScrollYMin:
130 case ax::mojom::IntAttribute::kScrollYMax:
131 case ax::mojom::IntAttribute::kTextSelStart:
132 case ax::mojom::IntAttribute::kTextSelEnd:
133 case ax::mojom::IntAttribute::kTableRowCount:
134 case ax::mojom::IntAttribute::kTableColumnCount:
135 case ax::mojom::IntAttribute::kTableRowIndex:
136 case ax::mojom::IntAttribute::kTableColumnIndex:
137 case ax::mojom::IntAttribute::kTableCellColumnIndex:
138 case ax::mojom::IntAttribute::kTableCellColumnSpan:
139 case ax::mojom::IntAttribute::kTableCellRowIndex:
140 case ax::mojom::IntAttribute::kTableCellRowSpan:
141 case ax::mojom::IntAttribute::kSortDirection:
142 case ax::mojom::IntAttribute::kHierarchicalLevel:
143 case ax::mojom::IntAttribute::kNameFrom:
144 case ax::mojom::IntAttribute::kDescriptionFrom:
145 case ax::mojom::IntAttribute::kSetSize:
146 case ax::mojom::IntAttribute::kPosInSet:
147 case ax::mojom::IntAttribute::kColorValue:
148 case ax::mojom::IntAttribute::kAriaCurrentState:
149 case ax::mojom::IntAttribute::kHasPopup:
150 case ax::mojom::IntAttribute::kBackgroundColor:
151 case ax::mojom::IntAttribute::kColor:
152 case ax::mojom::IntAttribute::kInvalidState:
153 case ax::mojom::IntAttribute::kCheckedState:
154 case ax::mojom::IntAttribute::kRestriction:
155 case ax::mojom::IntAttribute::kListStyle:
156 case ax::mojom::IntAttribute::kTextDirection:
157 case ax::mojom::IntAttribute::kTextPosition:
158 case ax::mojom::IntAttribute::kTextStyle:
159 case ax::mojom::IntAttribute::kTextOverlineStyle:
160 case ax::mojom::IntAttribute::kTextStrikethroughStyle:
161 case ax::mojom::IntAttribute::kTextUnderlineStyle:
162 case ax::mojom::IntAttribute::kAriaColumnCount:
163 case ax::mojom::IntAttribute::kAriaCellColumnIndex:
164 case ax::mojom::IntAttribute::kAriaCellColumnSpan:
165 case ax::mojom::IntAttribute::kAriaRowCount:
166 case ax::mojom::IntAttribute::kAriaCellRowIndex:
167 case ax::mojom::IntAttribute::kAriaCellRowSpan:
168 case ax::mojom::IntAttribute::kImageAnnotationStatus:
169 case ax::mojom::IntAttribute::kDropeffect:
170 case ax::mojom::IntAttribute::kDOMNodeId:
171 return false;
172 }
173
174 NOTREACHED();
175 return false;
176 }
177
178 // Return true if |attr| contains a vector of node ids that would need
179 // to be mapped when renumbering the ids in a combined tree.
IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr)180 bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr) {
181 switch (attr) {
182 case ax::mojom::IntListAttribute::kControlsIds:
183 case ax::mojom::IntListAttribute::kDetailsIds:
184 case ax::mojom::IntListAttribute::kDescribedbyIds:
185 case ax::mojom::IntListAttribute::kFlowtoIds:
186 case ax::mojom::IntListAttribute::kIndirectChildIds:
187 case ax::mojom::IntListAttribute::kLabelledbyIds:
188 case ax::mojom::IntListAttribute::kRadioGroupIds:
189 return true;
190
191 // Note: all of the attributes are included here explicitly,
192 // rather than using "default:", so that it's a compiler error to
193 // add a new attribute without explicitly considering whether it's
194 // a node id attribute or not.
195 case ax::mojom::IntListAttribute::kNone:
196 case ax::mojom::IntListAttribute::kMarkerTypes:
197 case ax::mojom::IntListAttribute::kMarkerStarts:
198 case ax::mojom::IntListAttribute::kMarkerEnds:
199 case ax::mojom::IntListAttribute::kCharacterOffsets:
200 case ax::mojom::IntListAttribute::kCachedLineStarts:
201 case ax::mojom::IntListAttribute::kWordStarts:
202 case ax::mojom::IntListAttribute::kWordEnds:
203 case ax::mojom::IntListAttribute::kCustomActionIds:
204 return false;
205 }
206
207 NOTREACHED();
208 return false;
209 }
210
AXNodeData()211 AXNodeData::AXNodeData()
212 : role(ax::mojom::Role::kUnknown), state(0U), actions(0ULL) {}
213
214 AXNodeData::~AXNodeData() = default;
215
AXNodeData(const AXNodeData & other)216 AXNodeData::AXNodeData(const AXNodeData& other) {
217 id = other.id;
218 role = other.role;
219 state = other.state;
220 actions = other.actions;
221 string_attributes = other.string_attributes;
222 int_attributes = other.int_attributes;
223 float_attributes = other.float_attributes;
224 bool_attributes = other.bool_attributes;
225 intlist_attributes = other.intlist_attributes;
226 stringlist_attributes = other.stringlist_attributes;
227 html_attributes = other.html_attributes;
228 child_ids = other.child_ids;
229 relative_bounds = other.relative_bounds;
230 }
231
AXNodeData(AXNodeData && other)232 AXNodeData::AXNodeData(AXNodeData&& other) {
233 id = other.id;
234 role = other.role;
235 state = other.state;
236 actions = other.actions;
237 string_attributes.swap(other.string_attributes);
238 int_attributes.swap(other.int_attributes);
239 float_attributes.swap(other.float_attributes);
240 bool_attributes.swap(other.bool_attributes);
241 intlist_attributes.swap(other.intlist_attributes);
242 stringlist_attributes.swap(other.stringlist_attributes);
243 html_attributes.swap(other.html_attributes);
244 child_ids.swap(other.child_ids);
245 relative_bounds = other.relative_bounds;
246 }
247
operator =(AXNodeData other)248 AXNodeData& AXNodeData::operator=(AXNodeData other) {
249 id = other.id;
250 role = other.role;
251 state = other.state;
252 actions = other.actions;
253 string_attributes = other.string_attributes;
254 int_attributes = other.int_attributes;
255 float_attributes = other.float_attributes;
256 bool_attributes = other.bool_attributes;
257 intlist_attributes = other.intlist_attributes;
258 stringlist_attributes = other.stringlist_attributes;
259 html_attributes = other.html_attributes;
260 child_ids = other.child_ids;
261 relative_bounds = other.relative_bounds;
262 return *this;
263 }
264
HasBoolAttribute(ax::mojom::BoolAttribute attribute) const265 bool AXNodeData::HasBoolAttribute(ax::mojom::BoolAttribute attribute) const {
266 auto iter = FindInVectorOfPairs(attribute, bool_attributes);
267 return iter != bool_attributes.end();
268 }
269
GetBoolAttribute(ax::mojom::BoolAttribute attribute) const270 bool AXNodeData::GetBoolAttribute(ax::mojom::BoolAttribute attribute) const {
271 bool result;
272 if (GetBoolAttribute(attribute, &result))
273 return result;
274 return false;
275 }
276
GetBoolAttribute(ax::mojom::BoolAttribute attribute,bool * value) const277 bool AXNodeData::GetBoolAttribute(ax::mojom::BoolAttribute attribute,
278 bool* value) const {
279 auto iter = FindInVectorOfPairs(attribute, bool_attributes);
280 if (iter != bool_attributes.end()) {
281 *value = iter->second;
282 return true;
283 }
284
285 return false;
286 }
287
HasFloatAttribute(ax::mojom::FloatAttribute attribute) const288 bool AXNodeData::HasFloatAttribute(ax::mojom::FloatAttribute attribute) const {
289 auto iter = FindInVectorOfPairs(attribute, float_attributes);
290 return iter != float_attributes.end();
291 }
292
GetFloatAttribute(ax::mojom::FloatAttribute attribute) const293 float AXNodeData::GetFloatAttribute(ax::mojom::FloatAttribute attribute) const {
294 float result;
295 if (GetFloatAttribute(attribute, &result))
296 return result;
297 return 0.0;
298 }
299
GetFloatAttribute(ax::mojom::FloatAttribute attribute,float * value) const300 bool AXNodeData::GetFloatAttribute(ax::mojom::FloatAttribute attribute,
301 float* value) const {
302 auto iter = FindInVectorOfPairs(attribute, float_attributes);
303 if (iter != float_attributes.end()) {
304 *value = iter->second;
305 return true;
306 }
307
308 return false;
309 }
310
HasIntAttribute(ax::mojom::IntAttribute attribute) const311 bool AXNodeData::HasIntAttribute(ax::mojom::IntAttribute attribute) const {
312 auto iter = FindInVectorOfPairs(attribute, int_attributes);
313 return iter != int_attributes.end();
314 }
315
GetIntAttribute(ax::mojom::IntAttribute attribute) const316 int AXNodeData::GetIntAttribute(ax::mojom::IntAttribute attribute) const {
317 int result;
318 if (GetIntAttribute(attribute, &result))
319 return result;
320 return 0;
321 }
322
GetIntAttribute(ax::mojom::IntAttribute attribute,int * value) const323 bool AXNodeData::GetIntAttribute(ax::mojom::IntAttribute attribute,
324 int* value) const {
325 auto iter = FindInVectorOfPairs(attribute, int_attributes);
326 if (iter != int_attributes.end()) {
327 *value = int{iter->second};
328 return true;
329 }
330
331 return false;
332 }
333
HasStringAttribute(ax::mojom::StringAttribute attribute) const334 bool AXNodeData::HasStringAttribute(
335 ax::mojom::StringAttribute attribute) const {
336 auto iter = FindInVectorOfPairs(attribute, string_attributes);
337 return iter != string_attributes.end();
338 }
339
GetStringAttribute(ax::mojom::StringAttribute attribute) const340 const std::string& AXNodeData::GetStringAttribute(
341 ax::mojom::StringAttribute attribute) const {
342 auto iter = FindInVectorOfPairs(attribute, string_attributes);
343 return iter != string_attributes.end() ? iter->second : base::EmptyString();
344 }
345
GetStringAttribute(ax::mojom::StringAttribute attribute,std::string * value) const346 bool AXNodeData::GetStringAttribute(ax::mojom::StringAttribute attribute,
347 std::string* value) const {
348 auto iter = FindInVectorOfPairs(attribute, string_attributes);
349 if (iter != string_attributes.end()) {
350 *value = iter->second;
351 return true;
352 }
353
354 return false;
355 }
356
GetString16Attribute(ax::mojom::StringAttribute attribute) const357 base::string16 AXNodeData::GetString16Attribute(
358 ax::mojom::StringAttribute attribute) const {
359 std::string value_utf8;
360 if (!GetStringAttribute(attribute, &value_utf8))
361 return base::string16();
362 return base::UTF8ToUTF16(value_utf8);
363 }
364
GetString16Attribute(ax::mojom::StringAttribute attribute,base::string16 * value) const365 bool AXNodeData::GetString16Attribute(ax::mojom::StringAttribute attribute,
366 base::string16* value) const {
367 std::string value_utf8;
368 if (!GetStringAttribute(attribute, &value_utf8))
369 return false;
370 *value = base::UTF8ToUTF16(value_utf8);
371 return true;
372 }
373
HasIntListAttribute(ax::mojom::IntListAttribute attribute) const374 bool AXNodeData::HasIntListAttribute(
375 ax::mojom::IntListAttribute attribute) const {
376 auto iter = FindInVectorOfPairs(attribute, intlist_attributes);
377 return iter != intlist_attributes.end();
378 }
379
GetIntListAttribute(ax::mojom::IntListAttribute attribute) const380 const std::vector<int32_t>& AXNodeData::GetIntListAttribute(
381 ax::mojom::IntListAttribute attribute) const {
382 static const base::NoDestructor<std::vector<int32_t>> empty_vector;
383 auto iter = FindInVectorOfPairs(attribute, intlist_attributes);
384 if (iter != intlist_attributes.end())
385 return iter->second;
386 return *empty_vector;
387 }
388
GetIntListAttribute(ax::mojom::IntListAttribute attribute,std::vector<int32_t> * value) const389 bool AXNodeData::GetIntListAttribute(ax::mojom::IntListAttribute attribute,
390 std::vector<int32_t>* value) const {
391 auto iter = FindInVectorOfPairs(attribute, intlist_attributes);
392 if (iter != intlist_attributes.end()) {
393 *value = iter->second;
394 return true;
395 }
396
397 return false;
398 }
399
HasStringListAttribute(ax::mojom::StringListAttribute attribute) const400 bool AXNodeData::HasStringListAttribute(
401 ax::mojom::StringListAttribute attribute) const {
402 auto iter = FindInVectorOfPairs(attribute, stringlist_attributes);
403 return iter != stringlist_attributes.end();
404 }
405
GetStringListAttribute(ax::mojom::StringListAttribute attribute) const406 const std::vector<std::string>& AXNodeData::GetStringListAttribute(
407 ax::mojom::StringListAttribute attribute) const {
408 static const base::NoDestructor<std::vector<std::string>> empty_vector;
409 auto iter = FindInVectorOfPairs(attribute, stringlist_attributes);
410 if (iter != stringlist_attributes.end())
411 return iter->second;
412 return *empty_vector;
413 }
414
GetStringListAttribute(ax::mojom::StringListAttribute attribute,std::vector<std::string> * value) const415 bool AXNodeData::GetStringListAttribute(
416 ax::mojom::StringListAttribute attribute,
417 std::vector<std::string>* value) const {
418 auto iter = FindInVectorOfPairs(attribute, stringlist_attributes);
419 if (iter != stringlist_attributes.end()) {
420 *value = iter->second;
421 return true;
422 }
423
424 return false;
425 }
426
GetHtmlAttribute(const char * html_attr,std::string * value) const427 bool AXNodeData::GetHtmlAttribute(const char* html_attr,
428 std::string* value) const {
429 for (const std::pair<std::string, std::string>& html_attribute :
430 html_attributes) {
431 const std::string& attr = html_attribute.first;
432 if (base::LowerCaseEqualsASCII(attr, html_attr)) {
433 *value = html_attribute.second;
434 return true;
435 }
436 }
437
438 return false;
439 }
440
GetHtmlAttribute(const char * html_attr,base::string16 * value) const441 bool AXNodeData::GetHtmlAttribute(const char* html_attr,
442 base::string16* value) const {
443 std::string value_utf8;
444 if (!GetHtmlAttribute(html_attr, &value_utf8))
445 return false;
446 *value = base::UTF8ToUTF16(value_utf8);
447 return true;
448 }
449
AddStringAttribute(ax::mojom::StringAttribute attribute,const std::string & value)450 void AXNodeData::AddStringAttribute(ax::mojom::StringAttribute attribute,
451 const std::string& value) {
452 DCHECK_NE(attribute, ax::mojom::StringAttribute::kNone);
453 if (HasStringAttribute(attribute))
454 RemoveStringAttribute(attribute);
455 string_attributes.push_back(std::make_pair(attribute, value));
456 }
457
AddIntAttribute(ax::mojom::IntAttribute attribute,int value)458 void AXNodeData::AddIntAttribute(ax::mojom::IntAttribute attribute, int value) {
459 DCHECK_NE(attribute, ax::mojom::IntAttribute::kNone);
460 if (HasIntAttribute(attribute))
461 RemoveIntAttribute(attribute);
462 int_attributes.push_back(std::make_pair(attribute, value));
463 }
464
AddFloatAttribute(ax::mojom::FloatAttribute attribute,float value)465 void AXNodeData::AddFloatAttribute(ax::mojom::FloatAttribute attribute,
466 float value) {
467 DCHECK_NE(attribute, ax::mojom::FloatAttribute::kNone);
468 if (HasFloatAttribute(attribute))
469 RemoveFloatAttribute(attribute);
470 float_attributes.push_back(std::make_pair(attribute, value));
471 }
472
AddBoolAttribute(ax::mojom::BoolAttribute attribute,bool value)473 void AXNodeData::AddBoolAttribute(ax::mojom::BoolAttribute attribute,
474 bool value) {
475 DCHECK_NE(attribute, ax::mojom::BoolAttribute::kNone);
476 if (HasBoolAttribute(attribute))
477 RemoveBoolAttribute(attribute);
478 bool_attributes.push_back(std::make_pair(attribute, value));
479 }
480
AddIntListAttribute(ax::mojom::IntListAttribute attribute,const std::vector<int32_t> & value)481 void AXNodeData::AddIntListAttribute(ax::mojom::IntListAttribute attribute,
482 const std::vector<int32_t>& value) {
483 DCHECK_NE(attribute, ax::mojom::IntListAttribute::kNone);
484 if (HasIntListAttribute(attribute))
485 RemoveIntListAttribute(attribute);
486 intlist_attributes.push_back(std::make_pair(attribute, value));
487 }
488
AddStringListAttribute(ax::mojom::StringListAttribute attribute,const std::vector<std::string> & value)489 void AXNodeData::AddStringListAttribute(
490 ax::mojom::StringListAttribute attribute,
491 const std::vector<std::string>& value) {
492 DCHECK_NE(attribute, ax::mojom::StringListAttribute::kNone);
493 if (HasStringListAttribute(attribute))
494 RemoveStringListAttribute(attribute);
495 stringlist_attributes.push_back(std::make_pair(attribute, value));
496 }
497
RemoveStringAttribute(ax::mojom::StringAttribute attribute)498 void AXNodeData::RemoveStringAttribute(ax::mojom::StringAttribute attribute) {
499 DCHECK_NE(attribute, ax::mojom::StringAttribute::kNone);
500 base::EraseIf(string_attributes, [attribute](const auto& string_attribute) {
501 return string_attribute.first == attribute;
502 });
503 }
504
RemoveIntAttribute(ax::mojom::IntAttribute attribute)505 void AXNodeData::RemoveIntAttribute(ax::mojom::IntAttribute attribute) {
506 DCHECK_NE(attribute, ax::mojom::IntAttribute::kNone);
507 base::EraseIf(int_attributes, [attribute](const auto& int_attribute) {
508 return int_attribute.first == attribute;
509 });
510 }
511
RemoveFloatAttribute(ax::mojom::FloatAttribute attribute)512 void AXNodeData::RemoveFloatAttribute(ax::mojom::FloatAttribute attribute) {
513 DCHECK_NE(attribute, ax::mojom::FloatAttribute::kNone);
514 base::EraseIf(float_attributes, [attribute](const auto& float_attribute) {
515 return float_attribute.first == attribute;
516 });
517 }
518
RemoveBoolAttribute(ax::mojom::BoolAttribute attribute)519 void AXNodeData::RemoveBoolAttribute(ax::mojom::BoolAttribute attribute) {
520 DCHECK_NE(attribute, ax::mojom::BoolAttribute::kNone);
521 base::EraseIf(bool_attributes, [attribute](const auto& bool_attribute) {
522 return bool_attribute.first == attribute;
523 });
524 }
525
RemoveIntListAttribute(ax::mojom::IntListAttribute attribute)526 void AXNodeData::RemoveIntListAttribute(ax::mojom::IntListAttribute attribute) {
527 DCHECK_NE(attribute, ax::mojom::IntListAttribute::kNone);
528 base::EraseIf(intlist_attributes, [attribute](const auto& intlist_attribute) {
529 return intlist_attribute.first == attribute;
530 });
531 }
532
RemoveStringListAttribute(ax::mojom::StringListAttribute attribute)533 void AXNodeData::RemoveStringListAttribute(
534 ax::mojom::StringListAttribute attribute) {
535 DCHECK_NE(attribute, ax::mojom::StringListAttribute::kNone);
536 base::EraseIf(stringlist_attributes,
537 [attribute](const auto& stringlist_attribute) {
538 return stringlist_attribute.first == attribute;
539 });
540 }
541
GetTextStyles() const542 AXNodeTextStyles AXNodeData::GetTextStyles() const {
543 AXNodeTextStyles style_attributes;
544
545 GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor,
546 &style_attributes.background_color);
547 GetIntAttribute(ax::mojom::IntAttribute::kColor, &style_attributes.color);
548 GetIntAttribute(ax::mojom::IntAttribute::kInvalidState,
549 &style_attributes.invalid_state);
550 GetIntAttribute(ax::mojom::IntAttribute::kTextOverlineStyle,
551 &style_attributes.overline_style);
552 GetIntAttribute(ax::mojom::IntAttribute::kTextDirection,
553 &style_attributes.text_direction);
554 GetIntAttribute(ax::mojom::IntAttribute::kTextPosition,
555 &style_attributes.text_position);
556 GetIntAttribute(ax::mojom::IntAttribute::kTextStrikethroughStyle,
557 &style_attributes.strikethrough_style);
558 GetIntAttribute(ax::mojom::IntAttribute::kTextStyle,
559 &style_attributes.text_style);
560 GetIntAttribute(ax::mojom::IntAttribute::kTextUnderlineStyle,
561 &style_attributes.underline_style);
562 GetFloatAttribute(ax::mojom::FloatAttribute::kFontSize,
563 &style_attributes.font_size);
564 GetFloatAttribute(ax::mojom::FloatAttribute::kFontWeight,
565 &style_attributes.font_weight);
566 GetStringAttribute(ax::mojom::StringAttribute::kFontFamily,
567 &style_attributes.font_family);
568
569 return style_attributes;
570 }
571
SetName(const std::string & name)572 void AXNodeData::SetName(const std::string& name) {
573 auto iter = std::find_if(string_attributes.begin(), string_attributes.end(),
574 [](const auto& string_attribute) {
575 return string_attribute.first ==
576 ax::mojom::StringAttribute::kName;
577 });
578 if (iter == string_attributes.end()) {
579 string_attributes.push_back(
580 std::make_pair(ax::mojom::StringAttribute::kName, name));
581 } else {
582 iter->second = name;
583 }
584 }
585
SetName(const base::string16 & name)586 void AXNodeData::SetName(const base::string16& name) {
587 SetName(base::UTF16ToUTF8(name));
588 }
589
SetNameExplicitlyEmpty()590 void AXNodeData::SetNameExplicitlyEmpty() {
591 SetNameFrom(ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
592 }
593
SetDescription(const std::string & description)594 void AXNodeData::SetDescription(const std::string& description) {
595 AddStringAttribute(ax::mojom::StringAttribute::kDescription, description);
596 }
597
SetDescription(const base::string16 & description)598 void AXNodeData::SetDescription(const base::string16& description) {
599 SetDescription(base::UTF16ToUTF8(description));
600 }
601
SetValue(const std::string & value)602 void AXNodeData::SetValue(const std::string& value) {
603 AddStringAttribute(ax::mojom::StringAttribute::kValue, value);
604 }
605
SetValue(const base::string16 & value)606 void AXNodeData::SetValue(const base::string16& value) {
607 SetValue(base::UTF16ToUTF8(value));
608 }
609
HasState(ax::mojom::State state_enum) const610 bool AXNodeData::HasState(ax::mojom::State state_enum) const {
611 return IsFlagSet(state, static_cast<uint32_t>(state_enum));
612 }
613
HasAction(ax::mojom::Action action) const614 bool AXNodeData::HasAction(ax::mojom::Action action) const {
615 return IsFlagSet(actions, static_cast<uint32_t>(action));
616 }
617
HasTextStyle(ax::mojom::TextStyle text_style_enum) const618 bool AXNodeData::HasTextStyle(ax::mojom::TextStyle text_style_enum) const {
619 int32_t style = GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
620 return IsFlagSet(static_cast<uint32_t>(style),
621 static_cast<uint32_t>(text_style_enum));
622 }
623
HasDropeffect(ax::mojom::Dropeffect dropeffect_enum) const624 bool AXNodeData::HasDropeffect(ax::mojom::Dropeffect dropeffect_enum) const {
625 int32_t dropeffect = GetIntAttribute(ax::mojom::IntAttribute::kDropeffect);
626 return IsFlagSet(static_cast<uint32_t>(dropeffect),
627 static_cast<uint32_t>(dropeffect_enum));
628 }
629
AddState(ax::mojom::State state_enum)630 void AXNodeData::AddState(ax::mojom::State state_enum) {
631 DCHECK_GT(static_cast<int>(state_enum),
632 static_cast<int>(ax::mojom::State::kNone));
633 DCHECK_LE(static_cast<int>(state_enum),
634 static_cast<int>(ax::mojom::State::kMaxValue));
635 state = ModifyFlag(state, static_cast<uint32_t>(state_enum), true);
636 }
637
RemoveState(ax::mojom::State state_enum)638 void AXNodeData::RemoveState(ax::mojom::State state_enum) {
639 DCHECK_GT(static_cast<int>(state_enum),
640 static_cast<int>(ax::mojom::State::kNone));
641 DCHECK_LE(static_cast<int>(state_enum),
642 static_cast<int>(ax::mojom::State::kMaxValue));
643 state = ModifyFlag(state, static_cast<uint32_t>(state_enum), false);
644 }
645
AddAction(ax::mojom::Action action_enum)646 void AXNodeData::AddAction(ax::mojom::Action action_enum) {
647 switch (action_enum) {
648 case ax::mojom::Action::kNone:
649 NOTREACHED();
650 break;
651
652 // Note: all of the attributes are included here explicitly, rather than
653 // using "default:", so that it's a compiler error to add a new action
654 // without explicitly considering whether there are mutually exclusive
655 // actions that can be performed on a UI control at the same time.
656 case ax::mojom::Action::kBlur:
657 case ax::mojom::Action::kFocus: {
658 ax::mojom::Action excluded_action =
659 (action_enum == ax::mojom::Action::kBlur) ? ax::mojom::Action::kFocus
660 : ax::mojom::Action::kBlur;
661 DCHECK(!HasAction(excluded_action)) << excluded_action;
662 break;
663 }
664
665 case ax::mojom::Action::kClearAccessibilityFocus:
666 case ax::mojom::Action::kCollapse:
667 case ax::mojom::Action::kCustomAction:
668 case ax::mojom::Action::kDecrement:
669 case ax::mojom::Action::kDoDefault:
670 case ax::mojom::Action::kExpand:
671 case ax::mojom::Action::kGetImageData:
672 case ax::mojom::Action::kHitTest:
673 case ax::mojom::Action::kIncrement:
674 case ax::mojom::Action::kInternalInvalidateTree:
675 case ax::mojom::Action::kLoadInlineTextBoxes:
676 case ax::mojom::Action::kReplaceSelectedText:
677 case ax::mojom::Action::kScrollToMakeVisible:
678 case ax::mojom::Action::kScrollToPoint:
679 case ax::mojom::Action::kSetAccessibilityFocus:
680 case ax::mojom::Action::kSetScrollOffset:
681 case ax::mojom::Action::kSetSelection:
682 case ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint:
683 case ax::mojom::Action::kSetValue:
684 case ax::mojom::Action::kShowContextMenu:
685 case ax::mojom::Action::kScrollBackward:
686 case ax::mojom::Action::kScrollForward:
687 case ax::mojom::Action::kScrollUp:
688 case ax::mojom::Action::kScrollDown:
689 case ax::mojom::Action::kScrollLeft:
690 case ax::mojom::Action::kScrollRight:
691 case ax::mojom::Action::kGetTextLocation:
692 case ax::mojom::Action::kAnnotatePageImages:
693 case ax::mojom::Action::kSignalEndOfTest:
694 case ax::mojom::Action::kHideTooltip:
695 case ax::mojom::Action::kShowTooltip:
696 break;
697 }
698
699 actions = ModifyFlag(actions, static_cast<uint32_t>(action_enum), true);
700 }
701
AddTextStyle(ax::mojom::TextStyle text_style_enum)702 void AXNodeData::AddTextStyle(ax::mojom::TextStyle text_style_enum) {
703 DCHECK_GE(static_cast<int>(text_style_enum),
704 static_cast<int>(ax::mojom::TextStyle::kMinValue));
705 DCHECK_LE(static_cast<int>(text_style_enum),
706 static_cast<int>(ax::mojom::TextStyle::kMaxValue));
707 int32_t style = GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
708 style = ModifyFlag(static_cast<uint32_t>(style),
709 static_cast<uint32_t>(text_style_enum), true);
710 RemoveIntAttribute(ax::mojom::IntAttribute::kTextStyle);
711 AddIntAttribute(ax::mojom::IntAttribute::kTextStyle, style);
712 }
713
AddDropeffect(ax::mojom::Dropeffect dropeffect_enum)714 void AXNodeData::AddDropeffect(ax::mojom::Dropeffect dropeffect_enum) {
715 DCHECK_GE(static_cast<int>(dropeffect_enum),
716 static_cast<int>(ax::mojom::Dropeffect::kMinValue));
717 DCHECK_LE(static_cast<int>(dropeffect_enum),
718 static_cast<int>(ax::mojom::Dropeffect::kMaxValue));
719 int32_t dropeffect = GetIntAttribute(ax::mojom::IntAttribute::kDropeffect);
720 dropeffect = ModifyFlag(static_cast<uint32_t>(dropeffect),
721 static_cast<uint32_t>(dropeffect_enum), true);
722 RemoveIntAttribute(ax::mojom::IntAttribute::kDropeffect);
723 AddIntAttribute(ax::mojom::IntAttribute::kDropeffect, dropeffect);
724 }
725
GetCheckedState() const726 ax::mojom::CheckedState AXNodeData::GetCheckedState() const {
727 return static_cast<ax::mojom::CheckedState>(
728 GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
729 }
730
SetCheckedState(ax::mojom::CheckedState checked_state)731 void AXNodeData::SetCheckedState(ax::mojom::CheckedState checked_state) {
732 if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
733 RemoveIntAttribute(ax::mojom::IntAttribute::kCheckedState);
734 if (checked_state != ax::mojom::CheckedState::kNone) {
735 AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
736 static_cast<int32_t>(checked_state));
737 }
738 }
739
GetDefaultActionVerb() const740 ax::mojom::DefaultActionVerb AXNodeData::GetDefaultActionVerb() const {
741 return static_cast<ax::mojom::DefaultActionVerb>(
742 GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb));
743 }
744
SetDefaultActionVerb(ax::mojom::DefaultActionVerb default_action_verb)745 void AXNodeData::SetDefaultActionVerb(
746 ax::mojom::DefaultActionVerb default_action_verb) {
747 if (HasIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb))
748 RemoveIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb);
749 if (default_action_verb != ax::mojom::DefaultActionVerb::kNone) {
750 AddIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb,
751 static_cast<int32_t>(default_action_verb));
752 }
753 }
754
GetHasPopup() const755 ax::mojom::HasPopup AXNodeData::GetHasPopup() const {
756 return static_cast<ax::mojom::HasPopup>(
757 GetIntAttribute(ax::mojom::IntAttribute::kHasPopup));
758 }
759
SetHasPopup(ax::mojom::HasPopup has_popup)760 void AXNodeData::SetHasPopup(ax::mojom::HasPopup has_popup) {
761 if (HasIntAttribute(ax::mojom::IntAttribute::kHasPopup))
762 RemoveIntAttribute(ax::mojom::IntAttribute::kHasPopup);
763 if (has_popup != ax::mojom::HasPopup::kFalse) {
764 AddIntAttribute(ax::mojom::IntAttribute::kHasPopup,
765 static_cast<int32_t>(has_popup));
766 }
767 }
768
GetInvalidState() const769 ax::mojom::InvalidState AXNodeData::GetInvalidState() const {
770 return static_cast<ax::mojom::InvalidState>(
771 GetIntAttribute(ax::mojom::IntAttribute::kInvalidState));
772 }
773
SetInvalidState(ax::mojom::InvalidState invalid_state)774 void AXNodeData::SetInvalidState(ax::mojom::InvalidState invalid_state) {
775 if (HasIntAttribute(ax::mojom::IntAttribute::kInvalidState))
776 RemoveIntAttribute(ax::mojom::IntAttribute::kInvalidState);
777 if (invalid_state != ax::mojom::InvalidState::kNone) {
778 AddIntAttribute(ax::mojom::IntAttribute::kInvalidState,
779 static_cast<int32_t>(invalid_state));
780 }
781 }
782
GetNameFrom() const783 ax::mojom::NameFrom AXNodeData::GetNameFrom() const {
784 return static_cast<ax::mojom::NameFrom>(
785 GetIntAttribute(ax::mojom::IntAttribute::kNameFrom));
786 }
787
SetNameFrom(ax::mojom::NameFrom name_from)788 void AXNodeData::SetNameFrom(ax::mojom::NameFrom name_from) {
789 if (HasIntAttribute(ax::mojom::IntAttribute::kNameFrom))
790 RemoveIntAttribute(ax::mojom::IntAttribute::kNameFrom);
791 if (name_from != ax::mojom::NameFrom::kNone) {
792 AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
793 static_cast<int32_t>(name_from));
794 }
795 }
796
GetDescriptionFrom() const797 ax::mojom::DescriptionFrom AXNodeData::GetDescriptionFrom() const {
798 return static_cast<ax::mojom::DescriptionFrom>(
799 GetIntAttribute(ax::mojom::IntAttribute::kDescriptionFrom));
800 }
801
SetDescriptionFrom(ax::mojom::DescriptionFrom description_from)802 void AXNodeData::SetDescriptionFrom(
803 ax::mojom::DescriptionFrom description_from) {
804 if (HasIntAttribute(ax::mojom::IntAttribute::kDescriptionFrom))
805 RemoveIntAttribute(ax::mojom::IntAttribute::kDescriptionFrom);
806 if (description_from != ax::mojom::DescriptionFrom::kNone) {
807 AddIntAttribute(ax::mojom::IntAttribute::kDescriptionFrom,
808 static_cast<int32_t>(description_from));
809 }
810 }
811
GetTextPosition() const812 ax::mojom::TextPosition AXNodeData::GetTextPosition() const {
813 return static_cast<ax::mojom::TextPosition>(
814 GetIntAttribute(ax::mojom::IntAttribute::kTextPosition));
815 }
816
SetTextPosition(ax::mojom::TextPosition text_position)817 void AXNodeData::SetTextPosition(ax::mojom::TextPosition text_position) {
818 if (HasIntAttribute(ax::mojom::IntAttribute::kTextPosition))
819 RemoveIntAttribute(ax::mojom::IntAttribute::kTextPosition);
820 if (text_position != ax::mojom::TextPosition::kNone) {
821 AddIntAttribute(ax::mojom::IntAttribute::kTextPosition,
822 static_cast<int32_t>(text_position));
823 }
824 }
825
GetImageAnnotationStatus() const826 ax::mojom::ImageAnnotationStatus AXNodeData::GetImageAnnotationStatus() const {
827 return static_cast<ax::mojom::ImageAnnotationStatus>(
828 GetIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus));
829 }
830
SetImageAnnotationStatus(ax::mojom::ImageAnnotationStatus status)831 void AXNodeData::SetImageAnnotationStatus(
832 ax::mojom::ImageAnnotationStatus status) {
833 if (HasIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus))
834 RemoveIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus);
835 if (status != ax::mojom::ImageAnnotationStatus::kNone) {
836 AddIntAttribute(ax::mojom::IntAttribute::kImageAnnotationStatus,
837 static_cast<int32_t>(status));
838 }
839 }
840
GetRestriction() const841 ax::mojom::Restriction AXNodeData::GetRestriction() const {
842 return static_cast<ax::mojom::Restriction>(
843 GetIntAttribute(ax::mojom::IntAttribute::kRestriction));
844 }
845
SetRestriction(ax::mojom::Restriction restriction)846 void AXNodeData::SetRestriction(ax::mojom::Restriction restriction) {
847 if (HasIntAttribute(ax::mojom::IntAttribute::kRestriction))
848 RemoveIntAttribute(ax::mojom::IntAttribute::kRestriction);
849 if (restriction != ax::mojom::Restriction::kNone) {
850 AddIntAttribute(ax::mojom::IntAttribute::kRestriction,
851 static_cast<int32_t>(restriction));
852 }
853 }
854
GetListStyle() const855 ax::mojom::ListStyle AXNodeData::GetListStyle() const {
856 return static_cast<ax::mojom::ListStyle>(
857 GetIntAttribute(ax::mojom::IntAttribute::kListStyle));
858 }
859
SetListStyle(ax::mojom::ListStyle list_style)860 void AXNodeData::SetListStyle(ax::mojom::ListStyle list_style) {
861 if (HasIntAttribute(ax::mojom::IntAttribute::kListStyle))
862 RemoveIntAttribute(ax::mojom::IntAttribute::kListStyle);
863 if (list_style != ax::mojom::ListStyle::kNone) {
864 AddIntAttribute(ax::mojom::IntAttribute::kListStyle,
865 static_cast<int32_t>(list_style));
866 }
867 }
868
GetTextDirection() const869 ax::mojom::TextDirection AXNodeData::GetTextDirection() const {
870 return static_cast<ax::mojom::TextDirection>(
871 GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
872 }
873
SetTextDirection(ax::mojom::TextDirection text_direction)874 void AXNodeData::SetTextDirection(ax::mojom::TextDirection text_direction) {
875 if (HasIntAttribute(ax::mojom::IntAttribute::kTextDirection))
876 RemoveIntAttribute(ax::mojom::IntAttribute::kTextDirection);
877 if (text_direction != ax::mojom::TextDirection::kNone) {
878 AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
879 static_cast<int32_t>(text_direction));
880 }
881 }
882
IsClickable() const883 bool AXNodeData::IsClickable() const {
884 // If it has a custom default action verb except for
885 // ax::mojom::DefaultActionVerb::kClickAncestor, it's definitely clickable.
886 // ax::mojom::DefaultActionVerb::kClickAncestor is used when an element with a
887 // click listener is present in its ancestry chain.
888 if (HasIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb) &&
889 (GetDefaultActionVerb() != ax::mojom::DefaultActionVerb::kClickAncestor))
890 return true;
891
892 return ui::IsClickable(role);
893 }
894
IsIgnored() const895 bool AXNodeData::IsIgnored() const {
896 if (HasState(ax::mojom::State::kIgnored) || role == ax::mojom::Role::kIgnored)
897 return true;
898 return false;
899 }
900
IsInvocable() const901 bool AXNodeData::IsInvocable() const {
902 // A control is "invocable" if it initiates an action when activated but
903 // does not maintain any state. A control that maintains state when activated
904 // would be considered a toggle or expand-collapse element - these elements
905 // are "clickable" but not "invocable".
906 return IsClickable() && !SupportsExpandCollapse() &&
907 !ui::SupportsToggle(role);
908 }
909
IsPlainTextField() const910 bool AXNodeData::IsPlainTextField() const {
911 // We need to check both the role and editable state, because some ARIA text
912 // fields may in fact not be editable, whilst some editable fields might not
913 // have the role.
914 return !HasState(ax::mojom::State::kRichlyEditable) &&
915 (role == ax::mojom::Role::kTextField ||
916 role == ax::mojom::Role::kTextFieldWithComboBox ||
917 role == ax::mojom::Role::kSearchBox ||
918 GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot));
919 }
920
IsReadOnlyOrDisabled() const921 bool AXNodeData::IsReadOnlyOrDisabled() const {
922 switch (GetRestriction()) {
923 case ax::mojom::Restriction::kReadOnly:
924 case ax::mojom::Restriction::kDisabled:
925 return true;
926 case ax::mojom::Restriction::kNone: {
927 if (HasState(ax::mojom::State::kEditable) ||
928 HasState(ax::mojom::State::kRichlyEditable)) {
929 return false;
930 }
931
932 // By default, when readonly is not supported, we assume the node is never
933 // editable - then always readonly.
934 return ShouldHaveReadonlyStateByDefault(role) ||
935 !IsReadOnlySupported(role);
936 }
937 }
938 }
939
IsRangeValueSupported() const940 bool AXNodeData::IsRangeValueSupported() const {
941 // https://www.w3.org/TR/wai-aria-1.1/#aria-valuenow
942 // https://www.w3.org/TR/wai-aria-1.1/#aria-valuetext
943 // Roles that support aria-valuetext / aria-valuenow
944 switch (role) {
945 case ax::mojom::Role::kMeter:
946 case ax::mojom::Role::kProgressIndicator:
947 case ax::mojom::Role::kScrollBar:
948 case ax::mojom::Role::kSlider:
949 case ax::mojom::Role::kSpinButton:
950 return true;
951 case ax::mojom::Role::kSplitter:
952 // According to the ARIA spec, role="separator" acts as a splitter only
953 // when focusable, and supports a range only in that case.
954 return HasState(ax::mojom::State::kFocusable);
955 default:
956 return false;
957 }
958 }
959
SupportsExpandCollapse() const960 bool AXNodeData::SupportsExpandCollapse() const {
961 if (GetHasPopup() != ax::mojom::HasPopup::kFalse ||
962 HasState(ax::mojom::State::kExpanded) ||
963 HasState(ax::mojom::State::kCollapsed))
964 return true;
965
966 return ui::SupportsExpandCollapse(role);
967 }
968
IsContainedInActiveLiveRegion() const969 bool AXNodeData::IsContainedInActiveLiveRegion() const {
970 if (!HasStringAttribute(ax::mojom::StringAttribute::kContainerLiveStatus))
971 return false;
972
973 if (base::CompareCaseInsensitiveASCII(
974 GetStringAttribute(ax::mojom::StringAttribute::kContainerLiveStatus),
975 "off") == 0)
976 return false;
977
978 if (GetBoolAttribute(ax::mojom::BoolAttribute::kContainerLiveBusy))
979 return false;
980
981 return true;
982 }
983
ToString() const984 std::string AXNodeData::ToString() const {
985 std::string result;
986
987 result += "id=" + base::NumberToString(id);
988 result += " ";
989 result += ui::ToString(role);
990
991 result += StateBitfieldToString(state);
992
993 result += " " + relative_bounds.ToString();
994
995 for (const std::pair<ax::mojom::IntAttribute, int32_t>& int_attribute :
996 int_attributes) {
997 std::string value = base::NumberToString(int_attribute.second);
998 switch (int_attribute.first) {
999 case ax::mojom::IntAttribute::kDefaultActionVerb:
1000 result += " action=" + base::UTF16ToUTF8(ActionVerbToUnlocalizedString(
1001 static_cast<ax::mojom::DefaultActionVerb>(
1002 int_attribute.second)));
1003 break;
1004 case ax::mojom::IntAttribute::kScrollX:
1005 result += " scroll_x=" + value;
1006 break;
1007 case ax::mojom::IntAttribute::kScrollXMin:
1008 result += " scroll_x_min=" + value;
1009 break;
1010 case ax::mojom::IntAttribute::kScrollXMax:
1011 result += " scroll_x_max=" + value;
1012 break;
1013 case ax::mojom::IntAttribute::kScrollY:
1014 result += " scroll_y=" + value;
1015 break;
1016 case ax::mojom::IntAttribute::kScrollYMin:
1017 result += " scroll_y_min=" + value;
1018 break;
1019 case ax::mojom::IntAttribute::kScrollYMax:
1020 result += " scroll_y_max=" + value;
1021 break;
1022 case ax::mojom::IntAttribute::kHierarchicalLevel:
1023 result += " level=" + value;
1024 break;
1025 case ax::mojom::IntAttribute::kTextSelStart:
1026 result += " sel_start=" + value;
1027 break;
1028 case ax::mojom::IntAttribute::kTextSelEnd:
1029 result += " sel_end=" + value;
1030 break;
1031 case ax::mojom::IntAttribute::kAriaColumnCount:
1032 result += " aria_column_count=" + value;
1033 break;
1034 case ax::mojom::IntAttribute::kAriaCellColumnIndex:
1035 result += " aria_cell_column_index=" + value;
1036 break;
1037 case ax::mojom::IntAttribute::kAriaCellColumnSpan:
1038 result += " aria_cell_column_span=" + value;
1039 break;
1040 case ax::mojom::IntAttribute::kAriaRowCount:
1041 result += " aria_row_count=" + value;
1042 break;
1043 case ax::mojom::IntAttribute::kAriaCellRowIndex:
1044 result += " aria_cell_row_index=" + value;
1045 break;
1046 case ax::mojom::IntAttribute::kAriaCellRowSpan:
1047 result += " aria_cell_row_span=" + value;
1048 break;
1049 case ax::mojom::IntAttribute::kTableRowCount:
1050 result += " rows=" + value;
1051 break;
1052 case ax::mojom::IntAttribute::kTableColumnCount:
1053 result += " cols=" + value;
1054 break;
1055 case ax::mojom::IntAttribute::kTableCellColumnIndex:
1056 result += " col=" + value;
1057 break;
1058 case ax::mojom::IntAttribute::kTableCellRowIndex:
1059 result += " row=" + value;
1060 break;
1061 case ax::mojom::IntAttribute::kTableCellColumnSpan:
1062 result += " colspan=" + value;
1063 break;
1064 case ax::mojom::IntAttribute::kTableCellRowSpan:
1065 result += " rowspan=" + value;
1066 break;
1067 case ax::mojom::IntAttribute::kTableColumnHeaderId:
1068 result += " column_header_id=" + value;
1069 break;
1070 case ax::mojom::IntAttribute::kTableColumnIndex:
1071 result += " column_index=" + value;
1072 break;
1073 case ax::mojom::IntAttribute::kTableHeaderId:
1074 result += " header_id=" + value;
1075 break;
1076 case ax::mojom::IntAttribute::kTableRowHeaderId:
1077 result += " row_header_id=" + value;
1078 break;
1079 case ax::mojom::IntAttribute::kTableRowIndex:
1080 result += " row_index=" + value;
1081 break;
1082 case ax::mojom::IntAttribute::kSortDirection:
1083 switch (static_cast<ax::mojom::SortDirection>(int_attribute.second)) {
1084 case ax::mojom::SortDirection::kUnsorted:
1085 result += " sort_direction=none";
1086 break;
1087 case ax::mojom::SortDirection::kAscending:
1088 result += " sort_direction=ascending";
1089 break;
1090 case ax::mojom::SortDirection::kDescending:
1091 result += " sort_direction=descending";
1092 break;
1093 case ax::mojom::SortDirection::kOther:
1094 result += " sort_direction=other";
1095 break;
1096 default:
1097 break;
1098 }
1099 break;
1100 case ax::mojom::IntAttribute::kNameFrom:
1101 result += " name_from=";
1102 result += ui::ToString(
1103 static_cast<ax::mojom::NameFrom>(int_attribute.second));
1104 break;
1105 case ax::mojom::IntAttribute::kDescriptionFrom:
1106 result += " description_from=";
1107 result += ui::ToString(
1108 static_cast<ax::mojom::DescriptionFrom>(int_attribute.second));
1109 break;
1110 case ax::mojom::IntAttribute::kActivedescendantId:
1111 result += " activedescendant=" + value;
1112 break;
1113 case ax::mojom::IntAttribute::kErrormessageId:
1114 result += " errormessage=" + value;
1115 break;
1116 case ax::mojom::IntAttribute::kInPageLinkTargetId:
1117 result += " in_page_link_target_id=" + value;
1118 break;
1119 case ax::mojom::IntAttribute::kMemberOfId:
1120 result += " member_of_id=" + value;
1121 break;
1122 case ax::mojom::IntAttribute::kNextOnLineId:
1123 result += " next_on_line_id=" + value;
1124 break;
1125 case ax::mojom::IntAttribute::kPopupForId:
1126 result += " popup_for_id=" + value;
1127 break;
1128 case ax::mojom::IntAttribute::kPreviousOnLineId:
1129 result += " previous_on_line_id=" + value;
1130 break;
1131 case ax::mojom::IntAttribute::kColorValue:
1132 result += base::StringPrintf(" color_value=&%X", int_attribute.second);
1133 break;
1134 case ax::mojom::IntAttribute::kAriaCurrentState:
1135 switch (
1136 static_cast<ax::mojom::AriaCurrentState>(int_attribute.second)) {
1137 case ax::mojom::AriaCurrentState::kFalse:
1138 result += " aria_current_state=false";
1139 break;
1140 case ax::mojom::AriaCurrentState::kTrue:
1141 result += " aria_current_state=true";
1142 break;
1143 case ax::mojom::AriaCurrentState::kPage:
1144 result += " aria_current_state=page";
1145 break;
1146 case ax::mojom::AriaCurrentState::kStep:
1147 result += " aria_current_state=step";
1148 break;
1149 case ax::mojom::AriaCurrentState::kLocation:
1150 result += " aria_current_state=location";
1151 break;
1152 case ax::mojom::AriaCurrentState::kDate:
1153 result += " aria_current_state=date";
1154 break;
1155 case ax::mojom::AriaCurrentState::kTime:
1156 result += " aria_current_state=time";
1157 break;
1158 default:
1159 break;
1160 }
1161 break;
1162 case ax::mojom::IntAttribute::kBackgroundColor:
1163 result +=
1164 base::StringPrintf(" background_color=&%X", int_attribute.second);
1165 break;
1166 case ax::mojom::IntAttribute::kColor:
1167 result += base::StringPrintf(" color=&%X", int_attribute.second);
1168 break;
1169 case ax::mojom::IntAttribute::kListStyle:
1170 switch (static_cast<ax::mojom::ListStyle>(int_attribute.second)) {
1171 case ax::mojom::ListStyle::kCircle:
1172 result += " list_style=circle";
1173 break;
1174 case ax::mojom::ListStyle::kDisc:
1175 result += " list_style=disc";
1176 break;
1177 case ax::mojom::ListStyle::kImage:
1178 result += " list_style=image";
1179 break;
1180 case ax::mojom::ListStyle::kNumeric:
1181 result += " list_style=numeric";
1182 break;
1183 case ax::mojom::ListStyle::kOther:
1184 result += " list_style=other";
1185 break;
1186 case ax::mojom::ListStyle::kSquare:
1187 result += " list_style=square";
1188 break;
1189 default:
1190 break;
1191 }
1192 break;
1193 case ax::mojom::IntAttribute::kTextDirection:
1194 switch (static_cast<ax::mojom::TextDirection>(int_attribute.second)) {
1195 case ax::mojom::TextDirection::kLtr:
1196 result += " text_direction=ltr";
1197 break;
1198 case ax::mojom::TextDirection::kRtl:
1199 result += " text_direction=rtl";
1200 break;
1201 case ax::mojom::TextDirection::kTtb:
1202 result += " text_direction=ttb";
1203 break;
1204 case ax::mojom::TextDirection::kBtt:
1205 result += " text_direction=btt";
1206 break;
1207 default:
1208 break;
1209 }
1210 break;
1211 case ax::mojom::IntAttribute::kTextPosition:
1212 switch (static_cast<ax::mojom::TextPosition>(int_attribute.second)) {
1213 case ax::mojom::TextPosition::kNone:
1214 result += " text_position=none";
1215 break;
1216 case ax::mojom::TextPosition::kSubscript:
1217 result += " text_position=subscript";
1218 break;
1219 case ax::mojom::TextPosition::kSuperscript:
1220 result += " text_position=superscript";
1221 break;
1222 default:
1223 break;
1224 }
1225 break;
1226 case ax::mojom::IntAttribute::kTextStyle: {
1227 std::string text_style_value;
1228 if (HasTextStyle(ax::mojom::TextStyle::kBold))
1229 text_style_value += "bold,";
1230 if (HasTextStyle(ax::mojom::TextStyle::kItalic))
1231 text_style_value += "italic,";
1232 if (HasTextStyle(ax::mojom::TextStyle::kUnderline))
1233 text_style_value += "underline,";
1234 if (HasTextStyle(ax::mojom::TextStyle::kLineThrough))
1235 text_style_value += "line-through,";
1236 if (HasTextStyle(ax::mojom::TextStyle::kOverline))
1237 text_style_value += "overline,";
1238 result += text_style_value.substr(0, text_style_value.size() - 1);
1239 break;
1240 }
1241 case ax::mojom::IntAttribute::kTextOverlineStyle:
1242 result += std::string(" text_overline_style=") +
1243 ui::ToString(static_cast<ax::mojom::TextDecorationStyle>(
1244 int_attribute.second));
1245 break;
1246 case ax::mojom::IntAttribute::kTextStrikethroughStyle:
1247 result += std::string(" text_strikethrough_style=") +
1248 ui::ToString(static_cast<ax::mojom::TextDecorationStyle>(
1249 int_attribute.second));
1250 break;
1251 case ax::mojom::IntAttribute::kTextUnderlineStyle:
1252 result += std::string(" text_underline_style=") +
1253 ui::ToString(static_cast<ax::mojom::TextDecorationStyle>(
1254 int_attribute.second));
1255 break;
1256 case ax::mojom::IntAttribute::kSetSize:
1257 result += " setsize=" + value;
1258 break;
1259 case ax::mojom::IntAttribute::kPosInSet:
1260 result += " posinset=" + value;
1261 break;
1262 case ax::mojom::IntAttribute::kHasPopup:
1263 switch (static_cast<ax::mojom::HasPopup>(int_attribute.second)) {
1264 case ax::mojom::HasPopup::kTrue:
1265 result += " haspopup=true";
1266 break;
1267 case ax::mojom::HasPopup::kMenu:
1268 result += " haspopup=menu";
1269 break;
1270 case ax::mojom::HasPopup::kListbox:
1271 result += " haspopup=listbox";
1272 break;
1273 case ax::mojom::HasPopup::kTree:
1274 result += " haspopup=tree";
1275 break;
1276 case ax::mojom::HasPopup::kGrid:
1277 result += " haspopup=grid";
1278 break;
1279 case ax::mojom::HasPopup::kDialog:
1280 result += " haspopup=dialog";
1281 break;
1282 case ax::mojom::HasPopup::kFalse:
1283 default:
1284 break;
1285 }
1286 break;
1287 case ax::mojom::IntAttribute::kInvalidState:
1288 switch (static_cast<ax::mojom::InvalidState>(int_attribute.second)) {
1289 case ax::mojom::InvalidState::kFalse:
1290 result += " invalid_state=false";
1291 break;
1292 case ax::mojom::InvalidState::kTrue:
1293 result += " invalid_state=true";
1294 break;
1295 case ax::mojom::InvalidState::kOther:
1296 result += " invalid_state=other";
1297 break;
1298 default:
1299 break;
1300 }
1301 break;
1302 case ax::mojom::IntAttribute::kCheckedState:
1303 switch (static_cast<ax::mojom::CheckedState>(int_attribute.second)) {
1304 case ax::mojom::CheckedState::kFalse:
1305 result += " checked_state=false";
1306 break;
1307 case ax::mojom::CheckedState::kTrue:
1308 result += " checked_state=true";
1309 break;
1310 case ax::mojom::CheckedState::kMixed:
1311 result += " checked_state=mixed";
1312 break;
1313 default:
1314 break;
1315 }
1316 break;
1317 case ax::mojom::IntAttribute::kRestriction:
1318 switch (static_cast<ax::mojom::Restriction>(int_attribute.second)) {
1319 case ax::mojom::Restriction::kReadOnly:
1320 result += " restriction=readonly";
1321 break;
1322 case ax::mojom::Restriction::kDisabled:
1323 result += " restriction=disabled";
1324 break;
1325 default:
1326 break;
1327 }
1328 break;
1329 case ax::mojom::IntAttribute::kNextFocusId:
1330 result += " next_focus_id=" + value;
1331 break;
1332 case ax::mojom::IntAttribute::kPreviousFocusId:
1333 result += " previous_focus_id=" + value;
1334 break;
1335 case ax::mojom::IntAttribute::kImageAnnotationStatus:
1336 result += std::string(" image_annotation_status=") +
1337 ui::ToString(static_cast<ax::mojom::ImageAnnotationStatus>(
1338 int_attribute.second));
1339 break;
1340 case ax::mojom::IntAttribute::kDropeffect:
1341 result += " dropeffect=" + value;
1342 break;
1343 case ax::mojom::IntAttribute::kDOMNodeId:
1344 result += " dom_node_id=" + value;
1345 break;
1346 case ax::mojom::IntAttribute::kNone:
1347 break;
1348 }
1349 }
1350
1351 for (const std::pair<ax::mojom::StringAttribute, std::string>&
1352 string_attribute : string_attributes) {
1353 std::string value = string_attribute.second;
1354 switch (string_attribute.first) {
1355 case ax::mojom::StringAttribute::kAccessKey:
1356 result += " access_key=" + value;
1357 break;
1358 case ax::mojom::StringAttribute::kAriaInvalidValue:
1359 result += " aria_invalid_value=" + value;
1360 break;
1361 case ax::mojom::StringAttribute::kAutoComplete:
1362 result += " autocomplete=" + value;
1363 break;
1364 case ax::mojom::StringAttribute::kChildTreeId:
1365 result += " child_tree_id=" + value.substr(0, 8);
1366 break;
1367 case ax::mojom::StringAttribute::kClassName:
1368 result += " class_name=" + value;
1369 break;
1370 case ax::mojom::StringAttribute::kDescription:
1371 result += " description=" + value;
1372 break;
1373 case ax::mojom::StringAttribute::kDisplay:
1374 result += " display=" + value;
1375 break;
1376 case ax::mojom::StringAttribute::kFontFamily:
1377 result += " font-family=" + value;
1378 break;
1379 case ax::mojom::StringAttribute::kHtmlTag:
1380 result += " html_tag=" + value;
1381 break;
1382 case ax::mojom::StringAttribute::kImageAnnotation:
1383 result += " image_annotation=" + value;
1384 break;
1385 case ax::mojom::StringAttribute::kImageDataUrl:
1386 result += " image_data_url=(" +
1387 base::NumberToString(static_cast<int>(value.size())) +
1388 " bytes)";
1389 break;
1390 case ax::mojom::StringAttribute::kInnerHtml:
1391 result += " inner_html=" + value;
1392 break;
1393 case ax::mojom::StringAttribute::kInputType:
1394 result += " input_type=" + value;
1395 break;
1396 case ax::mojom::StringAttribute::kKeyShortcuts:
1397 result += " key_shortcuts=" + value;
1398 break;
1399 case ax::mojom::StringAttribute::kLanguage:
1400 result += " language=" + value;
1401 break;
1402 case ax::mojom::StringAttribute::kLiveRelevant:
1403 result += " relevant=" + value;
1404 break;
1405 case ax::mojom::StringAttribute::kLiveStatus:
1406 result += " live=" + value;
1407 break;
1408 case ax::mojom::StringAttribute::kContainerLiveRelevant:
1409 result += " container_relevant=" + value;
1410 break;
1411 case ax::mojom::StringAttribute::kContainerLiveStatus:
1412 result += " container_live=" + value;
1413 break;
1414 case ax::mojom::StringAttribute::kPlaceholder:
1415 result += " placeholder=" + value;
1416 break;
1417 case ax::mojom::StringAttribute::kRole:
1418 result += " role=" + value;
1419 break;
1420 case ax::mojom::StringAttribute::kRoleDescription:
1421 result += " role_description=" + value;
1422 break;
1423 case ax::mojom::StringAttribute::kTooltip:
1424 result += " tooltip=" + value;
1425 break;
1426 case ax::mojom::StringAttribute::kUrl:
1427 result += " url=" + value;
1428 break;
1429 case ax::mojom::StringAttribute::kName:
1430 result += " name=" + value;
1431 break;
1432 case ax::mojom::StringAttribute::kValue:
1433 result += " value=" + value;
1434 break;
1435 case ax::mojom::StringAttribute::kNone:
1436 break;
1437 }
1438 }
1439
1440 for (const std::pair<ax::mojom::FloatAttribute, float>& float_attribute :
1441 float_attributes) {
1442 std::string value = base::NumberToString(float_attribute.second);
1443 switch (float_attribute.first) {
1444 case ax::mojom::FloatAttribute::kValueForRange:
1445 result += " value_for_range=" + value;
1446 break;
1447 case ax::mojom::FloatAttribute::kMaxValueForRange:
1448 result += " max_value=" + value;
1449 break;
1450 case ax::mojom::FloatAttribute::kMinValueForRange:
1451 result += " min_value=" + value;
1452 break;
1453 case ax::mojom::FloatAttribute::kStepValueForRange:
1454 result += " step_value=" + value;
1455 break;
1456 case ax::mojom::FloatAttribute::kFontSize:
1457 result += " font_size=" + value;
1458 break;
1459 case ax::mojom::FloatAttribute::kFontWeight:
1460 result += " font_weight=" + value;
1461 break;
1462 case ax::mojom::FloatAttribute::kNone:
1463 break;
1464 }
1465 }
1466
1467 for (const std::pair<ax::mojom::BoolAttribute, bool>& bool_attribute :
1468 bool_attributes) {
1469 std::string value = bool_attribute.second ? "true" : "false";
1470 switch (bool_attribute.first) {
1471 case ax::mojom::BoolAttribute::kEditableRoot:
1472 result += " editable_root=" + value;
1473 break;
1474 case ax::mojom::BoolAttribute::kLiveAtomic:
1475 result += " atomic=" + value;
1476 break;
1477 case ax::mojom::BoolAttribute::kBusy:
1478 result += " busy=" + value;
1479 break;
1480 case ax::mojom::BoolAttribute::kContainerLiveAtomic:
1481 result += " container_atomic=" + value;
1482 break;
1483 case ax::mojom::BoolAttribute::kContainerLiveBusy:
1484 result += " container_busy=" + value;
1485 break;
1486 case ax::mojom::BoolAttribute::kUpdateLocationOnly:
1487 result += " update_location_only=" + value;
1488 break;
1489 case ax::mojom::BoolAttribute::kCanvasHasFallback:
1490 result += " has_fallback=" + value;
1491 break;
1492 case ax::mojom::BoolAttribute::kModal:
1493 result += " modal=" + value;
1494 break;
1495 case ax::mojom::BoolAttribute::kScrollable:
1496 result += " scrollable=" + value;
1497 break;
1498 case ax::mojom::BoolAttribute::kClickable:
1499 result += " clickable=" + value;
1500 break;
1501 case ax::mojom::BoolAttribute::kClipsChildren:
1502 result += " clips_children=" + value;
1503 break;
1504 case ax::mojom::BoolAttribute::kSelected:
1505 result += " selected=" + value;
1506 break;
1507 case ax::mojom::BoolAttribute::kSupportsTextLocation:
1508 result += " supports_text_location=" + value;
1509 break;
1510 case ax::mojom::BoolAttribute::kGrabbed:
1511 result += " grabbed=" + value;
1512 break;
1513 case ax::mojom::BoolAttribute::kIsLineBreakingObject:
1514 result += " is_line_breaking_object=" + value;
1515 break;
1516 case ax::mojom::BoolAttribute::kIsPageBreakingObject:
1517 result += " is_page_breaking_object=" + value;
1518 break;
1519 case ax::mojom::BoolAttribute::kHasAriaAttribute:
1520 result += " has_aria_attribute=" + value;
1521 break;
1522 case ax::mojom::BoolAttribute::kNone:
1523 break;
1524 }
1525 }
1526
1527 for (const std::pair<ax::mojom::IntListAttribute, std::vector<int32_t>>&
1528 intlist_attribute : intlist_attributes) {
1529 const std::vector<int32_t>& values = intlist_attribute.second;
1530 switch (intlist_attribute.first) {
1531 case ax::mojom::IntListAttribute::kIndirectChildIds:
1532 result += " indirect_child_ids=" + IntVectorToString(values);
1533 break;
1534 case ax::mojom::IntListAttribute::kControlsIds:
1535 result += " controls_ids=" + IntVectorToString(values);
1536 break;
1537 case ax::mojom::IntListAttribute::kDescribedbyIds:
1538 result += " describedby_ids=" + IntVectorToString(values);
1539 break;
1540 case ax::mojom::IntListAttribute::kDetailsIds:
1541 result += " details_ids=" + IntVectorToString(values);
1542 break;
1543 case ax::mojom::IntListAttribute::kFlowtoIds:
1544 result += " flowto_ids=" + IntVectorToString(values);
1545 break;
1546 case ax::mojom::IntListAttribute::kLabelledbyIds:
1547 result += " labelledby_ids=" + IntVectorToString(values);
1548 break;
1549 case ax::mojom::IntListAttribute::kRadioGroupIds:
1550 result += " radio_group_ids=" + IntVectorToString(values);
1551 break;
1552 case ax::mojom::IntListAttribute::kMarkerTypes: {
1553 std::string types_str;
1554 for (size_t i = 0; i < values.size(); ++i) {
1555 int32_t type = values[i];
1556 if (type == static_cast<int32_t>(ax::mojom::MarkerType::kNone))
1557 continue;
1558
1559 if (i > 0)
1560 types_str += ',';
1561
1562 if (type & static_cast<int32_t>(ax::mojom::MarkerType::kSpelling))
1563 types_str += "spelling&";
1564 if (type & static_cast<int32_t>(ax::mojom::MarkerType::kGrammar))
1565 types_str += "grammar&";
1566 if (type & static_cast<int32_t>(ax::mojom::MarkerType::kTextMatch))
1567 types_str += "text_match&";
1568 if (type &
1569 static_cast<int32_t>(ax::mojom::MarkerType::kActiveSuggestion))
1570 types_str += "active_suggestion&";
1571 if (type & static_cast<int32_t>(ax::mojom::MarkerType::kSuggestion))
1572 types_str += "suggestion&";
1573
1574 if (!types_str.empty())
1575 types_str = types_str.substr(0, types_str.size() - 1);
1576 }
1577
1578 if (!types_str.empty())
1579 result += " marker_types=" + types_str;
1580 break;
1581 }
1582 case ax::mojom::IntListAttribute::kMarkerStarts:
1583 result += " marker_starts=" + IntVectorToString(values);
1584 break;
1585 case ax::mojom::IntListAttribute::kMarkerEnds:
1586 result += " marker_ends=" + IntVectorToString(values);
1587 break;
1588 case ax::mojom::IntListAttribute::kCharacterOffsets:
1589 result += " character_offsets=" + IntVectorToString(values);
1590 break;
1591 case ax::mojom::IntListAttribute::kCachedLineStarts:
1592 result += " cached_line_start_offsets=" + IntVectorToString(values);
1593 break;
1594 case ax::mojom::IntListAttribute::kWordStarts:
1595 result += " word_starts=" + IntVectorToString(values);
1596 break;
1597 case ax::mojom::IntListAttribute::kWordEnds:
1598 result += " word_ends=" + IntVectorToString(values);
1599 break;
1600 case ax::mojom::IntListAttribute::kCustomActionIds:
1601 result += " custom_action_ids=" + IntVectorToString(values);
1602 break;
1603 case ax::mojom::IntListAttribute::kNone:
1604 break;
1605 }
1606 }
1607
1608 for (const std::pair<ax::mojom::StringListAttribute,
1609 std::vector<std::string>>& stringlist_attribute :
1610 stringlist_attributes) {
1611 const std::vector<std::string>& values = stringlist_attribute.second;
1612 switch (stringlist_attribute.first) {
1613 case ax::mojom::StringListAttribute::kCustomActionDescriptions:
1614 result +=
1615 " custom_action_descriptions: " + base::JoinString(values, ",");
1616 break;
1617 case ax::mojom::StringListAttribute::kNone:
1618 break;
1619 }
1620 }
1621
1622 if (actions)
1623 result += " actions=" + ActionsBitfieldToString(actions);
1624
1625 if (!child_ids.empty())
1626 result += " child_ids=" + IntVectorToString(child_ids);
1627
1628 return result;
1629 }
1630
DropeffectBitfieldToString() const1631 std::string AXNodeData::DropeffectBitfieldToString() const {
1632 if (!HasIntAttribute(ax::mojom::IntAttribute::kDropeffect))
1633 return "";
1634
1635 std::string str;
1636 for (int dropeffect_idx = static_cast<int>(ax::mojom::Dropeffect::kMinValue);
1637 dropeffect_idx <= static_cast<int>(ax::mojom::Dropeffect::kMaxValue);
1638 ++dropeffect_idx) {
1639 ax::mojom::Dropeffect dropeffect_enum =
1640 static_cast<ax::mojom::Dropeffect>(dropeffect_idx);
1641 if (HasDropeffect(dropeffect_enum))
1642 str += " " + std::string(ui::ToString(dropeffect_enum));
1643 }
1644
1645 // Removing leading space in final string.
1646 return str.substr(1);
1647 }
1648
1649 } // namespace ui
1650