ax_event_generator.cc 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. // Copyright 2017 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_event_generator.h"
  5. #include <algorithm>
  6. #include "base/containers/contains.h"
  7. #include "ui/accessibility/ax_enums.mojom.h"
  8. #include "ui/accessibility/ax_event.h"
  9. #include "ui/accessibility/ax_live_region_tracker.h"
  10. #include "ui/accessibility/ax_node.h"
  11. #include "ui/accessibility/ax_role_properties.h"
  12. namespace ui {
  13. namespace {
  14. bool HasEvent(const std::set<AXEventGenerator::EventParams>& node_events,
  15. AXEventGenerator::Event event) {
  16. return node_events.count(AXEventGenerator::EventParams(event));
  17. }
  18. void RemoveEvent(std::set<AXEventGenerator::EventParams>* node_events,
  19. AXEventGenerator::Event event) {
  20. node_events->erase(AXEventGenerator::EventParams(event));
  21. }
  22. // If a node toggled its ignored state, don't also fire children-changed because
  23. // platforms likely will do that in response to ignored-changed. Also do not
  24. // fire parent-changed on ignored nodes because functionally the parent did not
  25. // change as far as platform assistive technologies are concerned.
  26. // Suppress name- and description-changed because those can be emitted as a side
  27. // effect of calculating alternative text values for a newly-displayed object.
  28. // Ditto for text attributes such as foreground and background colors, or
  29. // display changing from "none" to "block."
  30. void RemoveEventsDueToIgnoredChanged(
  31. std::set<AXEventGenerator::EventParams>* node_events) {
  32. RemoveEvent(node_events,
  33. AXEventGenerator::Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED);
  34. RemoveEvent(node_events, AXEventGenerator::Event::CHILDREN_CHANGED);
  35. RemoveEvent(node_events, AXEventGenerator::Event::DESCRIPTION_CHANGED);
  36. RemoveEvent(node_events, AXEventGenerator::Event::NAME_CHANGED);
  37. RemoveEvent(node_events, AXEventGenerator::Event::OBJECT_ATTRIBUTE_CHANGED);
  38. RemoveEvent(node_events, AXEventGenerator::Event::PARENT_CHANGED);
  39. RemoveEvent(node_events, AXEventGenerator::Event::SORT_CHANGED);
  40. RemoveEvent(node_events, AXEventGenerator::Event::TEXT_ATTRIBUTE_CHANGED);
  41. RemoveEvent(node_events,
  42. AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED);
  43. }
  44. // Add a particular AXEventGenerator::IgnoredChangedState to
  45. // |ignored_changed_states|.
  46. void AddIgnoredChangedState(
  47. const AXEventGenerator::IgnoredChangedState& state,
  48. AXEventGenerator::IgnoredChangedStatesBitset* ignored_changed_states) {
  49. ignored_changed_states->set(static_cast<size_t>(state));
  50. }
  51. // Returns true if |ignored_changed_states| contains a particular
  52. // AXEventGenerator::IgnoredChangedState.
  53. bool HasIgnoredChangedState(
  54. const AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
  55. const AXEventGenerator::IgnoredChangedState& state) {
  56. return ignored_changed_states[static_cast<size_t>(state)];
  57. }
  58. } // namespace
  59. //
  60. // AXEventGenerator::EventParams
  61. //
  62. AXEventGenerator::EventParams::EventParams(const Event event) : event(event) {}
  63. AXEventGenerator::EventParams::EventParams(
  64. const Event event,
  65. const ax::mojom::EventFrom event_from,
  66. const ax::mojom::Action event_from_action,
  67. const std::vector<AXEventIntent>& event_intents)
  68. : event(event),
  69. event_from(event_from),
  70. event_from_action(event_from_action),
  71. event_intents(event_intents) {}
  72. AXEventGenerator::EventParams::EventParams(const EventParams& other) = default;
  73. AXEventGenerator::EventParams::~EventParams() = default;
  74. AXEventGenerator::EventParams& AXEventGenerator::EventParams::operator=(
  75. const EventParams& other) = default;
  76. bool AXEventGenerator::EventParams::operator==(const EventParams& rhs) const {
  77. return rhs.event == event;
  78. }
  79. bool AXEventGenerator::EventParams::operator<(const EventParams& rhs) const {
  80. return event < rhs.event;
  81. }
  82. //
  83. // AXEventGenerator::TargetedEvent
  84. //
  85. AXEventGenerator::TargetedEvent::TargetedEvent(AXNodeID node_id,
  86. const EventParams& event_params)
  87. : node_id(node_id), event_params(event_params) {
  88. DCHECK_NE(node_id, kInvalidAXNodeID);
  89. }
  90. AXEventGenerator::TargetedEvent::~TargetedEvent() = default;
  91. //
  92. // AXEventGenerator::Iterator
  93. //
  94. AXEventGenerator::Iterator::Iterator(
  95. std::map<AXNodeID, std::set<EventParams>>::const_iterator map_start_iter,
  96. std::map<AXNodeID, std::set<EventParams>>::const_iterator map_end_iter)
  97. : map_iter_(map_start_iter), map_end_iter_(map_end_iter) {
  98. if (map_iter_ != map_end_iter_)
  99. set_iter_ = map_iter_->second.begin();
  100. }
  101. AXEventGenerator::Iterator::Iterator(const AXEventGenerator::Iterator& other) =
  102. default;
  103. AXEventGenerator::Iterator::~Iterator() = default;
  104. AXEventGenerator::Iterator& AXEventGenerator::Iterator::operator=(
  105. const Iterator& other) = default;
  106. AXEventGenerator::Iterator& AXEventGenerator::Iterator::operator++() {
  107. if (map_iter_ == map_end_iter_)
  108. return *this;
  109. DCHECK(set_iter_ != map_iter_->second.end());
  110. set_iter_++;
  111. // The map pointed to by |map_end_iter_| may contain empty sets of events in
  112. // its entries (i.e. |set_iter_| is at the iterator's end). In this case, we
  113. // want to increment |map_iter_| to point to the next entry of the map that
  114. // contains a non-empty set of events.
  115. while (map_iter_ != map_end_iter_ && set_iter_ == map_iter_->second.end()) {
  116. map_iter_++;
  117. if (map_iter_ != map_end_iter_)
  118. set_iter_ = map_iter_->second.begin();
  119. }
  120. return *this;
  121. }
  122. AXEventGenerator::Iterator AXEventGenerator::Iterator::operator++(int) {
  123. if (map_iter_ == map_end_iter_)
  124. return *this;
  125. Iterator iter = *this;
  126. ++(*this);
  127. return iter;
  128. }
  129. AXEventGenerator::TargetedEvent AXEventGenerator::Iterator::operator*() const {
  130. DCHECK(map_iter_ != map_end_iter_);
  131. DCHECK(set_iter_ != map_iter_->second.end());
  132. return AXEventGenerator::TargetedEvent(map_iter_->first, *set_iter_);
  133. }
  134. bool operator==(const AXEventGenerator::Iterator& lhs,
  135. const AXEventGenerator::Iterator& rhs) {
  136. if (lhs.map_iter_ == lhs.map_end_iter_ && rhs.map_iter_ == rhs.map_end_iter_)
  137. return true;
  138. return lhs.map_iter_ == rhs.map_iter_ && lhs.set_iter_ == rhs.set_iter_;
  139. }
  140. bool operator!=(const AXEventGenerator::Iterator& lhs,
  141. const AXEventGenerator::Iterator& rhs) {
  142. return !(lhs == rhs);
  143. }
  144. void swap(AXEventGenerator::Iterator& lhs, AXEventGenerator::Iterator& rhs) {
  145. if (lhs == rhs)
  146. return;
  147. std::map<AXNodeID, std::set<AXEventGenerator::EventParams>>::const_iterator
  148. map_iter = lhs.map_iter_;
  149. lhs.map_iter_ = rhs.map_iter_;
  150. rhs.map_iter_ = map_iter;
  151. std::map<AXNodeID, std::set<AXEventGenerator::EventParams>>::const_iterator
  152. map_end_iter = lhs.map_end_iter_;
  153. lhs.map_end_iter_ = rhs.map_end_iter_;
  154. rhs.map_end_iter_ = map_end_iter;
  155. std::set<AXEventGenerator::EventParams>::const_iterator set_iter =
  156. lhs.set_iter_;
  157. lhs.set_iter_ = rhs.set_iter_;
  158. rhs.set_iter_ = set_iter;
  159. }
  160. //
  161. // AXEventGenerator
  162. //
  163. AXEventGenerator::AXEventGenerator() = default;
  164. AXEventGenerator::AXEventGenerator(AXTree* tree) : tree_(tree) {
  165. if (tree_) {
  166. tree_event_observation_.Observe(tree_.get());
  167. live_region_tracker_ = std::make_unique<AXLiveRegionTracker>(*tree_);
  168. }
  169. }
  170. AXEventGenerator::~AXEventGenerator() = default;
  171. void AXEventGenerator::SetTree(AXTree* new_tree) {
  172. if (tree_) {
  173. DCHECK(tree_event_observation_.IsObservingSource(tree_.get()));
  174. tree_event_observation_.Reset();
  175. live_region_tracker_.reset();
  176. }
  177. tree_ = new_tree;
  178. if (tree_) {
  179. tree_event_observation_.Observe(tree_.get());
  180. live_region_tracker_ = std::make_unique<AXLiveRegionTracker>(*tree_);
  181. }
  182. }
  183. void AXEventGenerator::ReleaseTree() {
  184. tree_event_observation_.Reset();
  185. tree_ = nullptr;
  186. }
  187. bool AXEventGenerator::empty() const {
  188. return tree_events_.empty();
  189. }
  190. size_t AXEventGenerator::size() const {
  191. return tree_events_.size();
  192. }
  193. AXEventGenerator::Iterator AXEventGenerator::begin() const {
  194. auto map_iter = tree_events_.begin();
  195. if (map_iter != tree_events_.end()) {
  196. auto set_iter = map_iter->second.begin();
  197. // |tree_events_| may contain empty sets of events in its first entry
  198. // (i.e. |set_iter| is at the iterator's end). In this case, we want to
  199. // increment |map_iter| to point to the next entry of |tree_events_| that
  200. // contains a non-empty set of events.
  201. while (map_iter != tree_events_.end() &&
  202. set_iter == map_iter->second.end()) {
  203. map_iter++;
  204. if (map_iter != tree_events_.end())
  205. set_iter = map_iter->second.begin();
  206. }
  207. }
  208. return AXEventGenerator::Iterator(map_iter, tree_events_.end());
  209. }
  210. AXEventGenerator::Iterator AXEventGenerator::end() const {
  211. return AXEventGenerator::Iterator(tree_events_.end(), tree_events_.end());
  212. }
  213. void AXEventGenerator::ClearEvents() {
  214. tree_events_.clear();
  215. }
  216. void AXEventGenerator::AddEvent(AXNode* node, AXEventGenerator::Event event) {
  217. DCHECK(node);
  218. if (node->GetRole() == ax::mojom::Role::kInlineTextBox)
  219. return;
  220. // Extra Mac node creation and deletion in `AXTableInfo` directly call AXTree
  221. // observer methods, which skips all unserialization logic found in
  222. // `AXTree::Unserialize`.
  223. //
  224. // It only makes sense to generate events when we are called here within
  225. // `AXTree::Unserialize`. The below condition also guards against any future
  226. // callers of this type, whether Mac or not.
  227. if (!tree_->event_data())
  228. return;
  229. std::set<EventParams>& node_events = tree_events_[node->id()];
  230. node_events.emplace(event, tree_->event_data()->event_from,
  231. tree_->event_data()->event_from_action,
  232. tree_->event_data()->event_intents);
  233. }
  234. void AXEventGenerator::OnIgnoredWillChange(AXTree* tree,
  235. AXNode* node,
  236. bool is_ignored_new_value) {
  237. // If the node had been ignored and invisible before it changes to unignored,
  238. // then we should not fire `EVENT::PARENT_CHANGED` on its children because
  239. // they were previously unknown to ATs as they were in a hidden subtree.
  240. // TODO(nektar): Handle this by instead removing the `PARENT_CHANGED` event in
  241. // post-processing, because invisibility is not an accurate indicator of
  242. // whether nodes are known to the AT. In fact, a node can be invisible and
  243. // have visible descendants.
  244. if (!is_ignored_new_value && node->data().IsInvisible())
  245. nodes_to_suppress_parent_changed_on_.insert(node->id());
  246. }
  247. void AXEventGenerator::OnNodeDataChanged(AXTree* tree,
  248. const AXNodeData& old_node_data,
  249. const AXNodeData& new_node_data) {
  250. DCHECK_EQ(tree_, tree);
  251. AXNode* node = tree_->GetFromId(new_node_data.id);
  252. if (!node)
  253. return;
  254. // Fire CHILDREN_CHANGED events when the list of children updates.
  255. // Internally we store inline text box nodes as children of a static text
  256. // node or a line break node, which enables us to determine character bounds
  257. // and line layout. We don't expose those to platform APIs, though, so
  258. // suppress CHILDREN_CHANGED events on static text nodes.
  259. if (new_node_data.child_ids != old_node_data.child_ids && !node->IsText()) {
  260. if (node->IsIgnored()) {
  261. AXNode* unignored_parent = node->GetUnignoredParent();
  262. if (unignored_parent)
  263. AddEvent(unignored_parent, Event::CHILDREN_CHANGED);
  264. return;
  265. }
  266. AddEvent(node, Event::CHILDREN_CHANGED);
  267. }
  268. }
  269. void AXEventGenerator::OnRoleChanged(AXTree* tree,
  270. AXNode* node,
  271. ax::mojom::Role old_role,
  272. ax::mojom::Role new_role) {
  273. DCHECK_EQ(tree_, tree);
  274. AddEvent(node, Event::ROLE_CHANGED);
  275. }
  276. void AXEventGenerator::OnIgnoredChanged(AXTree* tree,
  277. AXNode* node,
  278. bool is_ignored_new_value) {
  279. DCHECK_EQ(tree_, tree);
  280. AXNode* unignored_parent = node->GetUnignoredParent();
  281. if (unignored_parent)
  282. AddEvent(unignored_parent, Event::CHILDREN_CHANGED);
  283. AddEvent(node, Event::IGNORED_CHANGED);
  284. if (!is_ignored_new_value)
  285. AddEvent(node, Event::SUBTREE_CREATED);
  286. if (node->GetRole() == ax::mojom::Role::kMenu) {
  287. if (is_ignored_new_value) {
  288. AddEvent(node, Event::MENU_POPUP_END);
  289. } else {
  290. AddEvent(node, Event::MENU_POPUP_START);
  291. }
  292. }
  293. // If the ignored state of a node has changed, the inclusion/exclusion of that
  294. // node in platform accessibility trees will change. Fire PARENT_CHANGED on
  295. // the unignored children of a node whose ignored state changed in order to
  296. // notify ATs that existing children may have been reparented.
  297. //
  298. // Note that we should not fire parent-changed if the invisible state of the
  299. // node has changed because when invisibility changes, the entire subtree is
  300. // being inserted / removed. For example if the 'hidden' property is changed
  301. // on list item, we should not fire parent-changed on the list marker or
  302. // static text children because: A) If the 'hidden' property has been removed,
  303. // both the list marker and the static text were not previously known to ATs
  304. // since they were not in the accessibility tree, and B) If the 'hidden'
  305. // property has been added then the children will be ignored and thus no
  306. // longer be in the accessibility tree that is exposed to the platform layer.
  307. // The second condition is automatically taken care of by the fact that we are
  308. // only iterating through unignored children.
  309. // TODO(nektar): Handle this by instead removing the `PARENT_CHANGED` event in
  310. // post-processing, because invisibility is not an accurate indicator of
  311. // whether nodes are known to the AT. In fact, a node can be invisible and
  312. // have visible descendants.
  313. const bool was_in_invisible_subtree =
  314. !base::Contains(nodes_to_suppress_parent_changed_on_, node->id());
  315. if (was_in_invisible_subtree) {
  316. for (auto iter = node->UnignoredChildrenBegin();
  317. iter != node->UnignoredChildrenEnd(); ++iter) {
  318. AddEvent(iter.get(), Event::PARENT_CHANGED);
  319. }
  320. }
  321. }
  322. void AXEventGenerator::OnStateChanged(AXTree* tree,
  323. AXNode* node,
  324. ax::mojom::State state,
  325. bool new_value) {
  326. DCHECK_EQ(tree_, tree);
  327. DCHECK_NE(state, ax::mojom::State::kIgnored)
  328. << "The ignored state should be handled in "
  329. "`AXEventGenerator::OnIgnoredChanged` and not in this method.";
  330. AddEvent(node, Event::STATE_CHANGED);
  331. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  332. switch (state) {
  333. case ax::mojom::State::kExpanded:
  334. AddEvent(node, new_value ? Event::EXPANDED : Event::COLLAPSED);
  335. if (IsTableRow(node->GetRole()) ||
  336. node->GetRole() == ax::mojom::Role::kTreeItem) {
  337. AXNode* container = node;
  338. while (container && !IsRowContainer(container->GetRole()))
  339. container = container->parent();
  340. if (container)
  341. AddEvent(container, Event::ROW_COUNT_CHANGED);
  342. }
  343. break;
  344. case ax::mojom::State::kMultiline:
  345. AddEvent(node, Event::MULTILINE_STATE_CHANGED);
  346. break;
  347. case ax::mojom::State::kMultiselectable:
  348. AddEvent(node, Event::MULTISELECTABLE_STATE_CHANGED);
  349. break;
  350. case ax::mojom::State::kRequired:
  351. AddEvent(node, Event::REQUIRED_STATE_CHANGED);
  352. break;
  353. default:
  354. break;
  355. }
  356. }
  357. void AXEventGenerator::OnStringAttributeChanged(AXTree* tree,
  358. AXNode* node,
  359. ax::mojom::StringAttribute attr,
  360. const std::string& old_value,
  361. const std::string& new_value) {
  362. DCHECK_EQ(tree_, tree);
  363. switch (attr) {
  364. case ax::mojom::StringAttribute::kAccessKey:
  365. AddEvent(node, Event::ACCESS_KEY_CHANGED);
  366. break;
  367. case ax::mojom::StringAttribute::kAutoComplete:
  368. AddEvent(node, Event::AUTO_COMPLETE_CHANGED);
  369. break;
  370. case ax::mojom::StringAttribute::kCheckedStateDescription:
  371. AddEvent(node, Event::CHECKED_STATE_DESCRIPTION_CHANGED);
  372. break;
  373. case ax::mojom::StringAttribute::kClassName:
  374. AddEvent(node, Event::CLASS_NAME_CHANGED);
  375. break;
  376. case ax::mojom::StringAttribute::kDescription:
  377. AddEvent(node, Event::DESCRIPTION_CHANGED);
  378. break;
  379. case ax::mojom::StringAttribute::kFontFamily:
  380. AddEvent(node, Event::TEXT_ATTRIBUTE_CHANGED);
  381. break;
  382. case ax::mojom::StringAttribute::kImageAnnotation:
  383. // The image annotation is reported as part of the accessible name.
  384. AddEvent(node, Event::IMAGE_ANNOTATION_CHANGED);
  385. break;
  386. case ax::mojom::StringAttribute::kKeyShortcuts:
  387. AddEvent(node, Event::KEY_SHORTCUTS_CHANGED);
  388. break;
  389. case ax::mojom::StringAttribute::kLanguage:
  390. AddEvent(node, Event::LANGUAGE_CHANGED);
  391. break;
  392. case ax::mojom::StringAttribute::kLiveRelevant:
  393. AddEvent(node, Event::LIVE_RELEVANT_CHANGED);
  394. break;
  395. case ax::mojom::StringAttribute::kLiveStatus:
  396. AddEvent(node, Event::LIVE_STATUS_CHANGED);
  397. // Fire a LIVE_REGION_CREATED if the previous value was off, and the new
  398. // value is not-off. According to the ARIA spec, "When the property is not
  399. // set on an object that needs to send updates, the politeness level is
  400. // the value of the nearest ancestor that sets the aria-live attribute."
  401. // Example: A new chat message is added to the room with aria-live="off",
  402. // then the author removes aria-live.
  403. if (!IsAlert(node->GetRole())) {
  404. bool was_off = !old_value.empty()
  405. ? old_value == "off"
  406. : !node->data().IsContainedInActiveLiveRegion();
  407. bool is_off = !new_value.empty()
  408. ? new_value == "off"
  409. : !node->data().IsContainedInActiveLiveRegion();
  410. if (was_off && !is_off)
  411. AddEvent(node, Event::LIVE_REGION_CREATED);
  412. }
  413. break;
  414. case ax::mojom::StringAttribute::kName:
  415. // If the name of the root node changes, we expect OnTreeDataChanged to
  416. // add a DOCUMENT_TITLE_CHANGED event instead.
  417. if (node != tree->root())
  418. AddEvent(node, Event::NAME_CHANGED);
  419. // If it's in a live region, fire live region events.
  420. if (node->HasStringAttribute(
  421. ax::mojom::StringAttribute::kContainerLiveStatus)) {
  422. FireLiveRegionEvents(node);
  423. }
  424. FireValueInTextFieldChangedEventIfNecessary(tree, node);
  425. break;
  426. case ax::mojom::StringAttribute::kPlaceholder:
  427. AddEvent(node, Event::PLACEHOLDER_CHANGED);
  428. break;
  429. case ax::mojom::StringAttribute::kValue:
  430. if (node->data().IsRangeValueSupported()) {
  431. AddEvent(node, Event::RANGE_VALUE_CHANGED);
  432. } else if (IsSelectElement(node->GetRole())) {
  433. AddEvent(node, Event::SELECTED_VALUE_CHANGED);
  434. } else if (node->data().IsTextField()) {
  435. AddEvent(node, Event::VALUE_IN_TEXT_FIELD_CHANGED);
  436. }
  437. break;
  438. default:
  439. AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
  440. break;
  441. }
  442. }
  443. void AXEventGenerator::OnIntAttributeChanged(AXTree* tree,
  444. AXNode* node,
  445. ax::mojom::IntAttribute attr,
  446. int32_t old_value,
  447. int32_t new_value) {
  448. DCHECK_EQ(tree_, tree);
  449. switch (attr) {
  450. case ax::mojom::IntAttribute::kActivedescendantId:
  451. // Don't fire on invisible containers, as it confuses some screen readers,
  452. // such as NVDA.
  453. if (!node->data().IsInvisible()) {
  454. AddEvent(node, Event::ACTIVE_DESCENDANT_CHANGED);
  455. active_descendant_changed_.push_back(node);
  456. }
  457. break;
  458. case ax::mojom::IntAttribute::kCheckedState:
  459. AddEvent(node, Event::CHECKED_STATE_CHANGED);
  460. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  461. break;
  462. case ax::mojom::IntAttribute::kAriaCurrentState:
  463. AddEvent(node, Event::ARIA_CURRENT_CHANGED);
  464. break;
  465. case ax::mojom::IntAttribute::kDropeffect:
  466. AddEvent(node, Event::DROPEFFECT_CHANGED);
  467. break;
  468. case ax::mojom::IntAttribute::kHasPopup:
  469. AddEvent(node, Event::HASPOPUP_CHANGED);
  470. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  471. break;
  472. case ax::mojom::IntAttribute::kHierarchicalLevel:
  473. AddEvent(node, Event::HIERARCHICAL_LEVEL_CHANGED);
  474. break;
  475. case ax::mojom::IntAttribute::kInvalidState:
  476. AddEvent(node, Event::INVALID_STATUS_CHANGED);
  477. break;
  478. case ax::mojom::IntAttribute::kPosInSet:
  479. AddEvent(node, Event::POSITION_IN_SET_CHANGED);
  480. break;
  481. case ax::mojom::IntAttribute::kRestriction: {
  482. bool was_enabled;
  483. bool was_readonly;
  484. GetRestrictionStates(static_cast<ax::mojom::Restriction>(old_value),
  485. &was_enabled, &was_readonly);
  486. bool is_enabled;
  487. bool is_readonly;
  488. GetRestrictionStates(static_cast<ax::mojom::Restriction>(new_value),
  489. &is_enabled, &is_readonly);
  490. if (was_enabled != is_enabled) {
  491. AddEvent(node, Event::ENABLED_CHANGED);
  492. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  493. }
  494. if (was_readonly != is_readonly) {
  495. AddEvent(node, Event::READONLY_CHANGED);
  496. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  497. }
  498. break;
  499. }
  500. case ax::mojom::IntAttribute::kScrollX:
  501. AddEvent(node, Event::SCROLL_HORIZONTAL_POSITION_CHANGED);
  502. break;
  503. case ax::mojom::IntAttribute::kScrollY:
  504. AddEvent(node, Event::SCROLL_VERTICAL_POSITION_CHANGED);
  505. break;
  506. case ax::mojom::IntAttribute::kSortDirection:
  507. // Ignore sort direction changes on roles other than table headers and
  508. // grid headers.
  509. if (IsTableHeader(node->GetRole()))
  510. AddEvent(node, Event::SORT_CHANGED);
  511. break;
  512. case ax::mojom::IntAttribute::kImageAnnotationStatus:
  513. // The image annotation is reported as part of the accessible name.
  514. AddEvent(node, Event::IMAGE_ANNOTATION_CHANGED);
  515. break;
  516. case ax::mojom::IntAttribute::kSetSize:
  517. AddEvent(node, Event::SET_SIZE_CHANGED);
  518. break;
  519. case ax::mojom::IntAttribute::kBackgroundColor:
  520. case ax::mojom::IntAttribute::kColor:
  521. case ax::mojom::IntAttribute::kTextDirection:
  522. case ax::mojom::IntAttribute::kTextPosition:
  523. case ax::mojom::IntAttribute::kTextStyle:
  524. case ax::mojom::IntAttribute::kTextOverlineStyle:
  525. case ax::mojom::IntAttribute::kTextStrikethroughStyle:
  526. case ax::mojom::IntAttribute::kTextUnderlineStyle:
  527. AddEvent(node, Event::TEXT_ATTRIBUTE_CHANGED);
  528. break;
  529. case ax::mojom::IntAttribute::kTextAlign:
  530. // Alignment is exposed as an object attribute because it cannot apply to
  531. // a substring. However, for some platforms (e.g. ATK), alignment is a
  532. // text attribute. Therefore fire both events to ensure platforms get the
  533. // expected notifications.
  534. AddEvent(node, Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED);
  535. AddEvent(node, Event::OBJECT_ATTRIBUTE_CHANGED);
  536. break;
  537. default:
  538. AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
  539. break;
  540. }
  541. }
  542. void AXEventGenerator::OnFloatAttributeChanged(AXTree* tree,
  543. AXNode* node,
  544. ax::mojom::FloatAttribute attr,
  545. float old_value,
  546. float new_value) {
  547. DCHECK_EQ(tree_, tree);
  548. switch (attr) {
  549. case ax::mojom::FloatAttribute::kMaxValueForRange:
  550. AddEvent(node, Event::RANGE_VALUE_MAX_CHANGED);
  551. break;
  552. case ax::mojom::FloatAttribute::kMinValueForRange:
  553. AddEvent(node, Event::RANGE_VALUE_MIN_CHANGED);
  554. break;
  555. case ax::mojom::FloatAttribute::kStepValueForRange:
  556. AddEvent(node, Event::RANGE_VALUE_STEP_CHANGED);
  557. break;
  558. case ax::mojom::FloatAttribute::kValueForRange:
  559. AddEvent(node, Event::RANGE_VALUE_CHANGED);
  560. break;
  561. case ax::mojom::FloatAttribute::kFontSize:
  562. case ax::mojom::FloatAttribute::kFontWeight:
  563. AddEvent(node, Event::TEXT_ATTRIBUTE_CHANGED);
  564. break;
  565. case ax::mojom::FloatAttribute::kTextIndent:
  566. // Indentation is exposed as an object attribute because it cannot apply
  567. // to a substring. However, for some platforms (e.g. ATK), alignment is a
  568. // text attribute. Therefore fire both events to ensure platforms get the
  569. // expected notifications.
  570. AddEvent(node, Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED);
  571. AddEvent(node, Event::OBJECT_ATTRIBUTE_CHANGED);
  572. break;
  573. default:
  574. AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
  575. break;
  576. }
  577. }
  578. void AXEventGenerator::OnBoolAttributeChanged(AXTree* tree,
  579. AXNode* node,
  580. ax::mojom::BoolAttribute attr,
  581. bool new_value) {
  582. DCHECK_EQ(tree_, tree);
  583. switch (attr) {
  584. case ax::mojom::BoolAttribute::kBusy:
  585. AddEvent(node, Event::BUSY_CHANGED);
  586. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  587. // Fire an 'invalidated' event when aria-busy becomes false.
  588. if (!new_value)
  589. AddEvent(node, Event::LAYOUT_INVALIDATED);
  590. break;
  591. case ax::mojom::BoolAttribute::kGrabbed:
  592. AddEvent(node, Event::GRABBED_CHANGED);
  593. break;
  594. case ax::mojom::BoolAttribute::kLiveAtomic:
  595. AddEvent(node, Event::ATOMIC_CHANGED);
  596. break;
  597. case ax::mojom::BoolAttribute::kSelected: {
  598. AddEvent(node, Event::SELECTED_CHANGED);
  599. AddEvent(node, Event::WIN_IACCESSIBLE_STATE_CHANGED);
  600. AXNode* container = node;
  601. while (container &&
  602. !IsContainerWithSelectableChildren(container->GetRole()))
  603. container = container->parent();
  604. if (container)
  605. AddEvent(container, Event::SELECTED_CHILDREN_CHANGED);
  606. break;
  607. }
  608. default:
  609. AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
  610. break;
  611. }
  612. }
  613. void AXEventGenerator::OnIntListAttributeChanged(
  614. AXTree* tree,
  615. AXNode* node,
  616. ax::mojom::IntListAttribute attr,
  617. const std::vector<int32_t>& old_value,
  618. const std::vector<int32_t>& new_value) {
  619. DCHECK_EQ(tree_, tree);
  620. switch (attr) {
  621. case ax::mojom::IntListAttribute::kControlsIds:
  622. AddEvent(node, Event::CONTROLS_CHANGED);
  623. break;
  624. case ax::mojom::IntListAttribute::kDetailsIds:
  625. AddEvent(node, Event::DETAILS_CHANGED);
  626. break;
  627. case ax::mojom::IntListAttribute::kDescribedbyIds:
  628. AddEvent(node, Event::DESCRIBED_BY_CHANGED);
  629. break;
  630. case ax::mojom::IntListAttribute::kFlowtoIds: {
  631. AddEvent(node, Event::FLOW_TO_CHANGED);
  632. // Fire FLOW_FROM_CHANGED for all nodes added or removed.
  633. // TODO(nektar): Consider removing this because flowto is unused by AT.
  634. for (AXNodeID id : ComputeIntListDifference(old_value, new_value)) {
  635. if (AXNode* target_node = tree->GetFromId(id))
  636. AddEvent(target_node, Event::FLOW_FROM_CHANGED);
  637. }
  638. break;
  639. }
  640. case ax::mojom::IntListAttribute::kLabelledbyIds:
  641. AddEvent(node, Event::LABELED_BY_CHANGED);
  642. break;
  643. case ax::mojom::IntListAttribute::kMarkerEnds:
  644. case ax::mojom::IntListAttribute::kMarkerStarts:
  645. case ax::mojom::IntListAttribute::kMarkerTypes:
  646. // On a native text field, the spelling- and grammar-error markers are
  647. // associated with children not exposed on any platform. Therefore, we
  648. // adjust the node we fire that event on here.
  649. if (AXNode* text_field = node->GetTextFieldAncestor()) {
  650. AddEvent(text_field, Event::TEXT_ATTRIBUTE_CHANGED);
  651. } else {
  652. AddEvent(node, Event::TEXT_ATTRIBUTE_CHANGED);
  653. }
  654. break;
  655. case ax::mojom::IntListAttribute::kCaretBounds:
  656. AddEvent(node, Event::CARET_BOUNDS_CHANGED);
  657. break;
  658. default:
  659. AddEvent(node, Event::OTHER_ATTRIBUTE_CHANGED);
  660. break;
  661. }
  662. }
  663. void AXEventGenerator::OnTreeDataChanged(AXTree* tree,
  664. const AXTreeData& old_tree_data,
  665. const AXTreeData& new_tree_data) {
  666. DCHECK_EQ(tree_, tree);
  667. DCHECK(tree->root());
  668. if (new_tree_data.title != old_tree_data.title)
  669. AddEvent(tree->root(), Event::DOCUMENT_TITLE_CHANGED);
  670. if (new_tree_data.sel_is_backward != old_tree_data.sel_is_backward ||
  671. new_tree_data.sel_anchor_object_id !=
  672. old_tree_data.sel_anchor_object_id ||
  673. new_tree_data.sel_anchor_offset != old_tree_data.sel_anchor_offset ||
  674. new_tree_data.sel_anchor_affinity != old_tree_data.sel_anchor_affinity ||
  675. new_tree_data.sel_focus_object_id != old_tree_data.sel_focus_object_id ||
  676. new_tree_data.sel_focus_offset != old_tree_data.sel_focus_offset ||
  677. new_tree_data.sel_focus_affinity != old_tree_data.sel_focus_affinity) {
  678. AddEvent(tree->root(), Event::DOCUMENT_SELECTION_CHANGED);
  679. // A special event is also fired internally for selection changes in text
  680. // fields. The reasons are both historical and in order to have a unified
  681. // way of handling selection changes between Web and Views. Views don't have
  682. // the concept of a document selection but some individual Views controls
  683. // have the ability for the user to select text inside them.
  684. const AXNode* selection_focus =
  685. tree_->GetFromId(new_tree_data.sel_focus_object_id);
  686. if (selection_focus) {
  687. // Even if it is possible for the document selection to span multiple text
  688. // fields, an event should still fire on the field where the selection
  689. // ends.
  690. if (AXNode* text_field = selection_focus->GetTextFieldAncestor())
  691. AddEvent(text_field, Event::TEXT_SELECTION_CHANGED);
  692. }
  693. }
  694. }
  695. void AXEventGenerator::OnNodeWillBeDeleted(AXTree* tree, AXNode* node) {
  696. DCHECK_EQ(tree_, tree);
  697. live_region_tracker_->OnNodeWillBeDeleted(*node);
  698. FireValueInTextFieldChangedEventIfNecessary(tree, node);
  699. }
  700. void AXEventGenerator::OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) {
  701. DCHECK_EQ(tree_, tree);
  702. }
  703. void AXEventGenerator::OnNodeWillBeReparented(AXTree* tree, AXNode* node) {
  704. DCHECK_EQ(tree_, tree);
  705. tree_events_.erase(node->id());
  706. }
  707. void AXEventGenerator::OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) {
  708. DCHECK_EQ(tree_, tree);
  709. }
  710. void AXEventGenerator::OnNodeDeleted(AXTree* tree, AXNodeID node_id) {
  711. DCHECK_EQ(tree_, tree);
  712. tree_events_.erase(node_id);
  713. }
  714. void AXEventGenerator::OnNodeReparented(AXTree* tree, AXNode* node) {
  715. DCHECK_EQ(tree_, tree);
  716. AddEvent(node, Event::PARENT_CHANGED);
  717. }
  718. void AXEventGenerator::OnNodeCreated(AXTree* tree, AXNode* node) {
  719. DCHECK_EQ(tree_, tree);
  720. FireValueInTextFieldChangedEventIfNecessary(tree, node);
  721. }
  722. void AXEventGenerator::OnAtomicUpdateFinished(
  723. AXTree* tree,
  724. bool root_changed,
  725. const std::vector<Change>& changes) {
  726. DCHECK_EQ(tree_, tree);
  727. DCHECK(tree->root());
  728. for (const auto& change : changes) {
  729. DCHECK(change.node);
  730. if ((change.type == NODE_CREATED || change.type == SUBTREE_CREATED ||
  731. change.type == NODE_REPARENTED || change.type == SUBTREE_REPARENTED)) {
  732. if (change.node->HasStringAttribute(
  733. ax::mojom::StringAttribute::kContainerLiveStatus)) {
  734. live_region_tracker_->UpdateCachedLiveRootForNode(*change.node);
  735. }
  736. }
  737. if (change.type == SUBTREE_CREATED) {
  738. AddEvent(change.node, Event::SUBTREE_CREATED);
  739. } else if (change.type != NODE_CREATED) {
  740. FireRelationSourceEvents(tree, change.node);
  741. continue;
  742. }
  743. if (IsAlert(change.node->GetRole()))
  744. AddEvent(change.node, Event::ALERT);
  745. else if (change.node->data().IsActiveLiveRegionRoot())
  746. AddEvent(change.node, Event::LIVE_REGION_CREATED);
  747. else if (change.node->data().IsContainedInActiveLiveRegion())
  748. FireLiveRegionEvents(change.node);
  749. }
  750. FireActiveDescendantEvents();
  751. nodes_to_suppress_parent_changed_on_.clear();
  752. // If we queued any live region change events during node deletion, add them
  753. // here. It's necessary to wait to add these events, because an update might
  754. // destroy and recreate live region roots after OnNodeWillBeDeleted is called.
  755. // TODO(mrobinson): Consider designing AXEventGenerator to have a more
  756. // resilient way to queue up events for nodes that might be destroyed and
  757. // recreated in a single update.
  758. for (auto& id : live_region_tracker_->live_region_roots_with_changes()) {
  759. // If node is null, the live region root with a change was deleted during
  760. // the course of this update and we should not trigger an event.
  761. if (AXNode* node = tree_->GetFromId(id)) {
  762. AddEvent(node, Event::LIVE_REGION_CHANGED);
  763. }
  764. }
  765. live_region_tracker_->OnAtomicUpdateFinished();
  766. PostprocessEvents();
  767. }
  768. void AXEventGenerator::AddEventsForTesting(
  769. const AXNode& node,
  770. const std::set<EventParams>& events) {
  771. tree_events_[node.id()] = events;
  772. }
  773. void AXEventGenerator::FireLiveRegionEvents(AXNode* node) {
  774. AXNode* live_root = live_region_tracker_->GetLiveRootIfNotBusy(*node);
  775. // Note that |live_root| might be nullptr if a live region was just added,
  776. // or if it has aria-busy="true".
  777. if (!live_root)
  778. return;
  779. // Fire LIVE_REGION_NODE_CHANGED on each node that changed.
  780. if (!node->GetStringAttribute(ax::mojom::StringAttribute::kName).empty()) {
  781. AddEvent(node, Event::LIVE_REGION_NODE_CHANGED);
  782. }
  783. // Fire LIVE_REGION_CHANGED on the root of the live region.
  784. AddEvent(live_root, Event::LIVE_REGION_CHANGED);
  785. }
  786. void AXEventGenerator::FireActiveDescendantEvents() {
  787. for (AXNode* node : active_descendant_changed_) {
  788. AXNode* descendant = tree_->GetFromId(
  789. node->GetIntAttribute(ax::mojom::IntAttribute::kActivedescendantId));
  790. if (!descendant)
  791. continue;
  792. switch (descendant->GetRole()) {
  793. case ax::mojom::Role::kMenuItem:
  794. case ax::mojom::Role::kMenuItemCheckBox:
  795. case ax::mojom::Role::kMenuItemRadio:
  796. case ax::mojom::Role::kMenuListOption:
  797. AddEvent(descendant, Event::MENU_ITEM_SELECTED);
  798. break;
  799. default:
  800. break;
  801. }
  802. }
  803. active_descendant_changed_.clear();
  804. }
  805. void AXEventGenerator::FireValueInTextFieldChangedEventIfNecessary(
  806. AXTree* tree,
  807. AXNode* target_node) {
  808. // Text is only found on leaf nodes, so the text in a text field would change
  809. // if any of the leaf nodes in it have changed their names.
  810. if (!target_node->IsLeaf())
  811. return;
  812. AXNode* text_field_ancestor = target_node->GetTextFieldAncestor();
  813. if (!text_field_ancestor || text_field_ancestor == target_node)
  814. return;
  815. AddEvent(text_field_ancestor, Event::EDITABLE_TEXT_CHANGED);
  816. AddEvent(text_field_ancestor, Event::VALUE_IN_TEXT_FIELD_CHANGED);
  817. }
  818. void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
  819. AXNode* target_node) {
  820. AXNodeID target_id = target_node->id();
  821. std::set<AXNode*> source_nodes;
  822. auto callback = [&](const auto& entry) {
  823. const auto& target_to_sources = entry.second;
  824. auto sources_it = target_to_sources.find(target_id);
  825. if (sources_it == target_to_sources.end())
  826. return;
  827. auto sources = sources_it->second;
  828. std::for_each(sources.begin(), sources.end(), [&](AXNodeID source_id) {
  829. AXNode* source_node = tree->GetFromId(source_id);
  830. if (!source_node || source_nodes.count(source_node) > 0)
  831. return;
  832. source_nodes.insert(source_node);
  833. // GCC < 6.4 requires this pointer when calling a member
  834. // function in anonymous function
  835. this->AddEvent(source_node, Event::RELATED_NODE_CHANGED);
  836. });
  837. };
  838. std::for_each(tree->int_reverse_relations().begin(),
  839. tree->int_reverse_relations().end(), callback);
  840. std::for_each(
  841. tree->intlist_reverse_relations().begin(),
  842. tree->intlist_reverse_relations().end(), [&](auto& entry) {
  843. // Explicitly exclude relationships for which an additional event on the
  844. // source node would cause extra noise. For example, kRadioGroupIds
  845. // forms relations among all radio buttons and serves little value for
  846. // AT to get events on the previous radio button in the group.
  847. if (entry.first != ax::mojom::IntListAttribute::kRadioGroupIds)
  848. callback(entry);
  849. });
  850. }
  851. void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
  852. AXNode* node,
  853. std::map<AXNode*, IgnoredChangedStatesBitset>&
  854. ancestor_ignored_changed_map) {
  855. DCHECK(node);
  856. // Recursively compute and cache ancestor ignored changed results in
  857. // |ancestor_ignored_changed_map|, if |node|'s ancestors have become ignored
  858. // and the ancestor's ignored changed results have not been cached.
  859. if (node->parent() &&
  860. !base::Contains(ancestor_ignored_changed_map, node->parent())) {
  861. TrimEventsDueToAncestorIgnoredChanged(node->parent(),
  862. ancestor_ignored_changed_map);
  863. }
  864. // If an ancestor of |node| changed to ignored state (hide), append hide state
  865. // to the corresponding entry in the map for |node|. Similarly, if an ancestor
  866. // of |node| removed its ignored state (show), we append show state to the
  867. // corresponding entry in map for |node| as well. If |node| flipped its
  868. // ignored state as well, we want to remove various events related to
  869. // IGNORED_CHANGED event.
  870. const auto& parent_map_iter =
  871. ancestor_ignored_changed_map.find(node->parent());
  872. const auto& curr_events_iter = tree_events_.find(node->id());
  873. // Initialize |ancestor_ignored_changed_map[node]| with an empty bitset,
  874. // representing neither |node| nor its ancestor has IGNORED_CHANGED.
  875. IgnoredChangedStatesBitset& ancestor_ignored_changed_states =
  876. ancestor_ignored_changed_map[node];
  877. // If |ancestor_ignored_changed_map| contains an entry for |node|'s
  878. // ancestor's and the ancestor has either show/hide state, we want to populate
  879. // |node|'s show/hide state in the map based on its cached ancestor result.
  880. // An empty entry in |ancestor_ignored_changed_map| for |node| means that
  881. // neither |node| nor its ancestor has IGNORED_CHANGED.
  882. if (parent_map_iter != ancestor_ignored_changed_map.end()) {
  883. // Propagate ancestor's show/hide states to |node|'s entry in the map.
  884. if (HasIgnoredChangedState(parent_map_iter->second,
  885. IgnoredChangedState::kHide)) {
  886. AddIgnoredChangedState(IgnoredChangedState::kHide,
  887. &ancestor_ignored_changed_states);
  888. }
  889. if (HasIgnoredChangedState(parent_map_iter->second,
  890. IgnoredChangedState::kShow)) {
  891. AddIgnoredChangedState(IgnoredChangedState::kShow,
  892. &ancestor_ignored_changed_states);
  893. }
  894. // If |node| has IGNORED changed with show/hide state that matches one of
  895. // its ancestors' IGNORED changed show/hide states, we want to remove
  896. // |node|'s IGNORED_CHANGED related events.
  897. if (curr_events_iter != tree_events_.end() &&
  898. HasEvent(curr_events_iter->second, Event::IGNORED_CHANGED)) {
  899. if ((HasIgnoredChangedState(parent_map_iter->second,
  900. IgnoredChangedState::kHide) &&
  901. node->IsIgnored()) ||
  902. (HasIgnoredChangedState(parent_map_iter->second,
  903. IgnoredChangedState::kShow) &&
  904. !node->IsIgnored())) {
  905. RemoveEvent(&(curr_events_iter->second), Event::IGNORED_CHANGED);
  906. RemoveEventsDueToIgnoredChanged(&(curr_events_iter->second));
  907. }
  908. if (node->IsIgnored()) {
  909. AddIgnoredChangedState(IgnoredChangedState::kHide,
  910. &ancestor_ignored_changed_states);
  911. } else {
  912. AddIgnoredChangedState(IgnoredChangedState::kShow,
  913. &ancestor_ignored_changed_states);
  914. }
  915. }
  916. return;
  917. }
  918. // If ignored changed results for ancestors are not cached, calculate the
  919. // corresponding entry for |node| in the map using the ignored states and
  920. // events of |node|.
  921. if (curr_events_iter != tree_events_.end() &&
  922. HasEvent(curr_events_iter->second, Event::IGNORED_CHANGED)) {
  923. if (node->IsIgnored()) {
  924. AddIgnoredChangedState(IgnoredChangedState::kHide,
  925. &ancestor_ignored_changed_states);
  926. } else {
  927. AddIgnoredChangedState(IgnoredChangedState::kShow,
  928. &ancestor_ignored_changed_states);
  929. }
  930. return;
  931. }
  932. }
  933. void AXEventGenerator::PostprocessEvents() {
  934. std::map<AXNode*, IgnoredChangedStatesBitset> ancestor_ignored_changed_map;
  935. std::set<AXNode*> removed_subtree_created_nodes;
  936. std::set<AXNode*> removed_parent_changed_nodes;
  937. // First pass through |tree_events_|, remove events that we do not need.
  938. for (auto& iter : tree_events_) {
  939. AXNodeID node_id = iter.first;
  940. AXNode* node = tree_->GetFromId(node_id);
  941. // TODO(http://crbug.com/2279799): remove all of the cases that could
  942. // add a null node to |tree_events|.
  943. DCHECK(node);
  944. if (!node)
  945. continue;
  946. std::set<EventParams>& node_events = iter.second;
  947. // A newly created live region or alert should not *also* fire a
  948. // live region changed event.
  949. if (HasEvent(node_events, Event::ALERT) ||
  950. HasEvent(node_events, Event::LIVE_REGION_CREATED)) {
  951. RemoveEvent(&node_events, Event::LIVE_REGION_CHANGED);
  952. }
  953. if (HasEvent(node_events, Event::IGNORED_CHANGED)) {
  954. // If a node toggled its ignored state, we only want to fire
  955. // IGNORED_CHANGED event on the top most ancestor where this ignored state
  956. // change takes place and suppress all the descendants's IGNORED_CHANGED
  957. // events.
  958. TrimEventsDueToAncestorIgnoredChanged(node, ancestor_ignored_changed_map);
  959. RemoveEventsDueToIgnoredChanged(&node_events);
  960. }
  961. // When the selected option in an expanded select element changes, the
  962. // foreground and background colors change. But we don't want to treat
  963. // those as text attribute changes. This can also happen when a widget
  964. // such as a button becomes enabled/disabled.
  965. if (HasEvent(node_events, Event::SELECTED_CHANGED) ||
  966. HasEvent(node_events, Event::ENABLED_CHANGED)) {
  967. RemoveEvent(&node_events, Event::TEXT_ATTRIBUTE_CHANGED);
  968. }
  969. AXNode* parent = node->GetUnignoredParent();
  970. // Don't fire text attribute changed on this node if its immediate parent
  971. // also has text attribute changed.
  972. if (parent && HasEvent(node_events, Event::TEXT_ATTRIBUTE_CHANGED) &&
  973. tree_events_.find(parent->id()) != tree_events_.end() &&
  974. HasEvent(tree_events_[parent->id()], Event::TEXT_ATTRIBUTE_CHANGED)) {
  975. RemoveEvent(&node_events, Event::TEXT_ATTRIBUTE_CHANGED);
  976. }
  977. // Don't fire parent changed on this node if any of its ancestors also has
  978. // parent changed. However, if the ancestor also has subtree created, it is
  979. // possible that the created subtree is actually a newly unignored parent
  980. // of an existing node. In that instance, we need to inform ATs that the
  981. // existing node's parent has changed on the platform.
  982. if (HasEvent(node_events, Event::PARENT_CHANGED)) {
  983. while (parent && (tree_events_.find(parent->id()) != tree_events_.end() ||
  984. base::Contains(removed_parent_changed_nodes, parent))) {
  985. if ((base::Contains(removed_parent_changed_nodes, parent) ||
  986. HasEvent(tree_events_[parent->id()], Event::PARENT_CHANGED)) &&
  987. !HasEvent(tree_events_[parent->id()], Event::SUBTREE_CREATED)) {
  988. RemoveEvent(&node_events, Event::PARENT_CHANGED);
  989. removed_parent_changed_nodes.insert(node);
  990. break;
  991. }
  992. parent = parent->GetUnignoredParent();
  993. }
  994. }
  995. // Don't fire parent changed on ignored events, because these nodes do not
  996. // exist for platform accessibility. If the node toggles the ignored state,
  997. // that's an IGNORED_CHANGED event and it's treated differently. In some
  998. // occasions it may result in a PARENT_CHANGED event on a different node
  999. // (see AXEventGenerator::OnIgnoredChanged).
  1000. if (node->IsIgnored())
  1001. RemoveEvent(&node_events, Event::PARENT_CHANGED);
  1002. // Don't fire subtree created on this node if any of its ancestors also has
  1003. // subtree created.
  1004. parent = node->GetUnignoredParent();
  1005. if (HasEvent(node_events, Event::SUBTREE_CREATED)) {
  1006. while (parent &&
  1007. (tree_events_.find(parent->id()) != tree_events_.end() ||
  1008. base::Contains(removed_subtree_created_nodes, parent))) {
  1009. if (base::Contains(removed_subtree_created_nodes, parent) ||
  1010. HasEvent(tree_events_[parent->id()], Event::SUBTREE_CREATED)) {
  1011. RemoveEvent(&node_events, Event::SUBTREE_CREATED);
  1012. removed_subtree_created_nodes.insert(node);
  1013. break;
  1014. }
  1015. parent = parent->GetUnignoredParent();
  1016. }
  1017. }
  1018. }
  1019. // Second pass through |tree_events_|, remove nodes that do not have any
  1020. // events left.
  1021. auto iter = tree_events_.begin();
  1022. while (iter != tree_events_.end()) {
  1023. std::set<EventParams>& node_events = iter->second;
  1024. if (node_events.empty())
  1025. iter = tree_events_.erase(iter);
  1026. else
  1027. ++iter;
  1028. }
  1029. }
  1030. // static
  1031. void AXEventGenerator::GetRestrictionStates(ax::mojom::Restriction restriction,
  1032. bool* is_enabled,
  1033. bool* is_readonly) {
  1034. switch (restriction) {
  1035. case ax::mojom::Restriction::kDisabled:
  1036. *is_enabled = false;
  1037. *is_readonly = true;
  1038. break;
  1039. case ax::mojom::Restriction::kReadOnly:
  1040. *is_enabled = true;
  1041. *is_readonly = true;
  1042. break;
  1043. case ax::mojom::Restriction::kNone:
  1044. *is_enabled = true;
  1045. *is_readonly = false;
  1046. break;
  1047. }
  1048. }
  1049. // static
  1050. std::vector<int32_t> AXEventGenerator::ComputeIntListDifference(
  1051. const std::vector<int32_t>& lhs,
  1052. const std::vector<int32_t>& rhs) {
  1053. std::set<int32_t> sorted_lhs(lhs.cbegin(), lhs.cend());
  1054. std::set<int32_t> sorted_rhs(rhs.cbegin(), rhs.cend());
  1055. std::vector<int32_t> result;
  1056. std::set_symmetric_difference(sorted_lhs.cbegin(), sorted_lhs.cend(),
  1057. sorted_rhs.cbegin(), sorted_rhs.cend(),
  1058. std::back_inserter(result));
  1059. return result;
  1060. }
  1061. std::ostream& operator<<(std::ostream& os, AXEventGenerator::Event event) {
  1062. return os << ToString(event);
  1063. }
  1064. const char* ToString(AXEventGenerator::Event event) {
  1065. switch (event) {
  1066. case AXEventGenerator::Event::ACCESS_KEY_CHANGED:
  1067. return "accessKeyChanged";
  1068. case AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED:
  1069. return "activeDescendantChanged";
  1070. case AXEventGenerator::Event::ALERT:
  1071. return "alert";
  1072. case AXEventGenerator::Event::ARIA_CURRENT_CHANGED:
  1073. return "ariaCurrentChanged";
  1074. case AXEventGenerator::Event::ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED:
  1075. return "atkTextObjectAttributeChanged";
  1076. case AXEventGenerator::Event::ATOMIC_CHANGED:
  1077. return "atomicChanged";
  1078. case AXEventGenerator::Event::AUTO_COMPLETE_CHANGED:
  1079. return "autoCompleteChanged";
  1080. case AXEventGenerator::Event::BUSY_CHANGED:
  1081. return "busyChanged";
  1082. case AXEventGenerator::Event::CARET_BOUNDS_CHANGED:
  1083. return "caretBoundsChanged";
  1084. case AXEventGenerator::Event::CHECKED_STATE_CHANGED:
  1085. return "checkedStateChanged";
  1086. case AXEventGenerator::Event::CHECKED_STATE_DESCRIPTION_CHANGED:
  1087. return "checkedStateDescriptionChanged";
  1088. case AXEventGenerator::Event::CHILDREN_CHANGED:
  1089. return "childrenChanged";
  1090. case AXEventGenerator::Event::CLASS_NAME_CHANGED:
  1091. return "classNameChanged";
  1092. case AXEventGenerator::Event::COLLAPSED:
  1093. return "collapsed";
  1094. case AXEventGenerator::Event::CONTROLS_CHANGED:
  1095. return "controlsChanged";
  1096. case AXEventGenerator::Event::DETAILS_CHANGED:
  1097. return "detailsChanged";
  1098. case AXEventGenerator::Event::DESCRIBED_BY_CHANGED:
  1099. return "describedByChanged";
  1100. case AXEventGenerator::Event::DESCRIPTION_CHANGED:
  1101. return "descriptionChanged";
  1102. case AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED:
  1103. return "documentSelectionChanged";
  1104. case AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED:
  1105. return "documentTitleChanged";
  1106. case AXEventGenerator::Event::DROPEFFECT_CHANGED:
  1107. return "dropeffectChanged";
  1108. case ui::AXEventGenerator::Event::EDITABLE_TEXT_CHANGED:
  1109. return "editableTextChanged";
  1110. case AXEventGenerator::Event::ENABLED_CHANGED:
  1111. return "enabledChanged";
  1112. case AXEventGenerator::Event::EXPANDED:
  1113. return "expanded";
  1114. case AXEventGenerator::Event::FOCUS_CHANGED:
  1115. return "focusChanged";
  1116. case AXEventGenerator::Event::FLOW_FROM_CHANGED:
  1117. return "flowFromChanged";
  1118. case AXEventGenerator::Event::FLOW_TO_CHANGED:
  1119. return "flowToChanged";
  1120. case AXEventGenerator::Event::GRABBED_CHANGED:
  1121. return "grabbedChanged";
  1122. case AXEventGenerator::Event::HASPOPUP_CHANGED:
  1123. return "haspopupChanged";
  1124. case AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED:
  1125. return "hierarchicalLevelChanged";
  1126. case ui::AXEventGenerator::Event::IGNORED_CHANGED:
  1127. return "ignoredChanged";
  1128. case AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED:
  1129. return "imageAnnotationChanged";
  1130. case AXEventGenerator::Event::INVALID_STATUS_CHANGED:
  1131. return "invalidStatusChanged";
  1132. case AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED:
  1133. return "keyShortcutsChanged";
  1134. case AXEventGenerator::Event::LABELED_BY_CHANGED:
  1135. return "labeledByChanged";
  1136. case AXEventGenerator::Event::LANGUAGE_CHANGED:
  1137. return "languageChanged";
  1138. case AXEventGenerator::Event::LAYOUT_INVALIDATED:
  1139. return "layoutInvalidated";
  1140. case AXEventGenerator::Event::LIVE_REGION_CHANGED:
  1141. return "liveRegionChanged";
  1142. case AXEventGenerator::Event::LIVE_REGION_CREATED:
  1143. return "liveRegionCreated";
  1144. case AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED:
  1145. return "liveRegionNodeChanged";
  1146. case AXEventGenerator::Event::LIVE_RELEVANT_CHANGED:
  1147. return "liveRelevantChanged";
  1148. case AXEventGenerator::Event::LIVE_STATUS_CHANGED:
  1149. return "liveStatusChanged";
  1150. case AXEventGenerator::Event::MENU_ITEM_SELECTED:
  1151. return "menuItemSelected";
  1152. case ui::AXEventGenerator::Event::MENU_POPUP_END:
  1153. return "menuPopupEnd";
  1154. case ui::AXEventGenerator::Event::MENU_POPUP_START:
  1155. return "menuPopupStart";
  1156. case AXEventGenerator::Event::MULTILINE_STATE_CHANGED:
  1157. return "multilineStateChanged";
  1158. case AXEventGenerator::Event::MULTISELECTABLE_STATE_CHANGED:
  1159. return "multiselectableStateChanged";
  1160. case AXEventGenerator::Event::NAME_CHANGED:
  1161. return "nameChanged";
  1162. case AXEventGenerator::Event::OBJECT_ATTRIBUTE_CHANGED:
  1163. return "objectAttributeChanged";
  1164. case AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED:
  1165. return "otherAttributeChanged";
  1166. case AXEventGenerator::Event::PARENT_CHANGED:
  1167. return "parentChanged";
  1168. case AXEventGenerator::Event::PLACEHOLDER_CHANGED:
  1169. return "placeholderChanged";
  1170. case AXEventGenerator::Event::PORTAL_ACTIVATED:
  1171. return "portalActivated";
  1172. case AXEventGenerator::Event::POSITION_IN_SET_CHANGED:
  1173. return "positionInSetChanged";
  1174. case AXEventGenerator::Event::RANGE_VALUE_CHANGED:
  1175. return "rangeValueChanged";
  1176. case AXEventGenerator::Event::RANGE_VALUE_MAX_CHANGED:
  1177. return "rangeValueMaxChanged";
  1178. case AXEventGenerator::Event::RANGE_VALUE_MIN_CHANGED:
  1179. return "rangeValueMinChanged";
  1180. case AXEventGenerator::Event::RANGE_VALUE_STEP_CHANGED:
  1181. return "rangeValueStepChanged";
  1182. case AXEventGenerator::Event::READONLY_CHANGED:
  1183. return "readonlyChanged";
  1184. case AXEventGenerator::Event::RELATED_NODE_CHANGED:
  1185. return "relatedNodeChanged";
  1186. case AXEventGenerator::Event::REQUIRED_STATE_CHANGED:
  1187. return "requiredStateChanged";
  1188. case AXEventGenerator::Event::ROLE_CHANGED:
  1189. return "roleChanged";
  1190. case AXEventGenerator::Event::ROW_COUNT_CHANGED:
  1191. return "rowCountChanged";
  1192. case AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED:
  1193. return "scrollHorizontalPositionChanged";
  1194. case AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED:
  1195. return "scrollVerticalPositionChanged";
  1196. case AXEventGenerator::Event::SELECTED_CHANGED:
  1197. return "selectedChanged";
  1198. case AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
  1199. return "selectedChildrenChanged";
  1200. case AXEventGenerator::Event::SELECTED_VALUE_CHANGED:
  1201. return "selectedValueChanged";
  1202. case AXEventGenerator::Event::TEXT_SELECTION_CHANGED:
  1203. return "textSelectionChanged";
  1204. case AXEventGenerator::Event::SET_SIZE_CHANGED:
  1205. return "setSizeChanged";
  1206. case AXEventGenerator::Event::SORT_CHANGED:
  1207. return "sortChanged";
  1208. case AXEventGenerator::Event::STATE_CHANGED:
  1209. return "stateChanged";
  1210. case AXEventGenerator::Event::SUBTREE_CREATED:
  1211. return "subtreeCreated";
  1212. case AXEventGenerator::Event::TEXT_ATTRIBUTE_CHANGED:
  1213. return "textAttributeChanged";
  1214. case AXEventGenerator::Event::VALUE_IN_TEXT_FIELD_CHANGED:
  1215. return "valueInTextFieldChanged";
  1216. case AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED:
  1217. return "winIaccessibleStateChanged";
  1218. }
  1219. }
  1220. } // namespace ui