ax_node_data.cc 69 KB

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