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 5 #ifndef UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_ 6 #define UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_ 7 8 #include <bitset> 9 #include <map> 10 #include <ostream> 11 #include <set> 12 #include <vector> 13 14 #include "base/scoped_observer.h" 15 #include "ui/accessibility/ax_event_intent.h" 16 #include "ui/accessibility/ax_export.h" 17 #include "ui/accessibility/ax_tree.h" 18 #include "ui/accessibility/ax_tree_observer.h" 19 20 namespace ui { 21 22 // Subclass of AXTreeObserver that automatically generates AXEvents to fire 23 // based on changes to an accessibility tree. Every platform 24 // tends to want different events, so this class lets each platform 25 // handle the events it wants and ignore the others. 26 class AX_EXPORT AXEventGenerator : public AXTreeObserver { 27 public: 28 enum class Event : int32_t { 29 ACCESS_KEY_CHANGED, 30 ACTIVE_DESCENDANT_CHANGED, 31 ALERT, 32 // ATK treats alignment, indentation, and other format-related attributes as 33 // text attributes even when they are only applicable to the entire object. 34 // And it lacks an event for use when object attributes have changed. 35 ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED, 36 ATOMIC_CHANGED, 37 AUTO_COMPLETE_CHANGED, 38 BUSY_CHANGED, 39 CHECKED_STATE_CHANGED, 40 CHILDREN_CHANGED, 41 CLASS_NAME_CHANGED, 42 COLLAPSED, 43 CONTROLS_CHANGED, 44 DESCRIBED_BY_CHANGED, 45 DESCRIPTION_CHANGED, 46 DOCUMENT_SELECTION_CHANGED, 47 DOCUMENT_TITLE_CHANGED, 48 DROPEFFECT_CHANGED, 49 // TODO(nektar): Deprecate this event and replace it with 50 // "VALUE_IN_TEXT_FIELD_CHANGED". 51 EDITABLE_TEXT_CHANGED, 52 ENABLED_CHANGED, 53 EXPANDED, 54 FOCUS_CHANGED, 55 FLOW_FROM_CHANGED, 56 FLOW_TO_CHANGED, 57 GRABBED_CHANGED, 58 HASPOPUP_CHANGED, 59 HIERARCHICAL_LEVEL_CHANGED, 60 IGNORED_CHANGED, 61 IMAGE_ANNOTATION_CHANGED, 62 INVALID_STATUS_CHANGED, 63 KEY_SHORTCUTS_CHANGED, 64 LABELED_BY_CHANGED, 65 LANGUAGE_CHANGED, 66 LAYOUT_INVALIDATED, // Fired when aria-busy turns from true to false. 67 LIVE_REGION_CHANGED, // Fired on the root of a live region. 68 LIVE_REGION_CREATED, 69 LIVE_REGION_NODE_CHANGED, // Fired on a node within a live region. 70 LIVE_RELEVANT_CHANGED, 71 LIVE_STATUS_CHANGED, 72 LOAD_COMPLETE, 73 LOAD_START, 74 MENU_ITEM_SELECTED, 75 MULTILINE_STATE_CHANGED, 76 MULTISELECTABLE_STATE_CHANGED, 77 NAME_CHANGED, 78 OBJECT_ATTRIBUTE_CHANGED, 79 OTHER_ATTRIBUTE_CHANGED, 80 PARENT_CHANGED, 81 PLACEHOLDER_CHANGED, 82 PORTAL_ACTIVATED, 83 POSITION_IN_SET_CHANGED, 84 RANGE_VALUE_CHANGED, 85 RANGE_VALUE_MAX_CHANGED, 86 RANGE_VALUE_MIN_CHANGED, 87 RANGE_VALUE_STEP_CHANGED, 88 READONLY_CHANGED, 89 RELATED_NODE_CHANGED, 90 REQUIRED_STATE_CHANGED, 91 ROLE_CHANGED, 92 ROW_COUNT_CHANGED, 93 SCROLL_HORIZONTAL_POSITION_CHANGED, 94 SCROLL_VERTICAL_POSITION_CHANGED, 95 SELECTED_CHANGED, 96 SELECTED_CHILDREN_CHANGED, 97 SELECTED_VALUE_CHANGED, 98 SELECTION_IN_TEXT_FIELD_CHANGED, 99 SET_SIZE_CHANGED, 100 SORT_CHANGED, 101 STATE_CHANGED, 102 SUBTREE_CREATED, 103 TEXT_ATTRIBUTE_CHANGED, 104 VALUE_IN_TEXT_FIELD_CHANGED, 105 106 // This event is for the exact set of attributes that affect 107 // the MSAA/IAccessible state on Windows. Not needed on other platforms, 108 // but very natural to compute here. 109 WIN_IACCESSIBLE_STATE_CHANGED, 110 MAX_VALUE = WIN_IACCESSIBLE_STATE_CHANGED, 111 }; 112 113 // For distinguishing between show and hide state when a node has 114 // IGNORED_CHANGED event. 115 enum class IgnoredChangedState : uint8_t { kShow, kHide, kCount = 2 }; 116 117 struct AX_EXPORT EventParams { 118 EventParams(Event event, 119 ax::mojom::EventFrom event_from, 120 const std::vector<AXEventIntent>& event_intents); 121 EventParams(const EventParams& other); 122 ~EventParams(); 123 124 bool operator==(const EventParams& rhs) const; 125 bool operator<(const EventParams& rhs) const; 126 127 Event event; 128 ax::mojom::EventFrom event_from; 129 std::vector<AXEventIntent> event_intents; 130 }; 131 132 struct TargetedEvent final { 133 // |node| must not be null 134 TargetedEvent(ui::AXNode* node, const EventParams& event_params); 135 ~TargetedEvent() = default; 136 137 ui::AXNode* node; 138 const EventParams& event_params; 139 }; 140 141 class AX_EXPORT Iterator 142 : public std::iterator<std::input_iterator_tag, TargetedEvent> { 143 public: 144 Iterator( 145 const std::map<AXNode*, std::set<EventParams>>& map, 146 const std::map<AXNode*, std::set<EventParams>>::const_iterator& head); 147 Iterator(const Iterator& other); 148 ~Iterator(); 149 150 bool operator!=(const Iterator& rhs) const; 151 Iterator& operator++(); 152 TargetedEvent operator*() const; 153 154 private: 155 const std::map<AXNode*, std::set<EventParams>>& map_; 156 std::map<AXNode*, std::set<EventParams>>::const_iterator map_iter_; 157 std::set<EventParams>::const_iterator set_iter_; 158 }; 159 160 // For storing ignored changed states for a particular node. We use bitset as 161 // the underlying data structure to improve memory usage. 162 // We use the index of AXEventGenerator::IgnoredChangedState enum 163 // to access the bitset data. 164 // e.g. AXEventGenerator::IgnoredChangedState::kShow has index 0 in the 165 // IgnoredChangedState enum. If |IgnoredChangedStatesBitset[0]| is set, it 166 // means IgnoredChangedState::kShow is present. Similarly, kHide has index 1 167 // in the enum, and it corresponds to |IgnoredChangedStatesBitset[1]|. 168 using IgnoredChangedStatesBitset = 169 std::bitset<static_cast<size_t>(IgnoredChangedState::kCount)>; 170 using const_iterator = Iterator; 171 using iterator = Iterator; 172 using value_type = TargetedEvent; 173 174 // If you use this constructor, you must call SetTree 175 // before using this class. 176 AXEventGenerator(); 177 178 // Automatically registers itself as the observer of |tree| and 179 // clears it on desctruction. |tree| must be valid for the lifetime 180 // of this object. 181 explicit AXEventGenerator(AXTree* tree); 182 183 ~AXEventGenerator() override; 184 185 // Clears this class as the observer of the previous tree that was 186 // being monitored, if any, and starts monitoring |new_tree|, if not 187 // nullptr. Note that |new_tree| must be valid for the lifetime of 188 // this object or until you call SetTree again. 189 void SetTree(AXTree* new_tree); 190 191 // Null |tree_| without accessing it or destroying it. 192 void ReleaseTree(); 193 194 // 195 // Methods that make this class behave like an STL container, which simplifies 196 // the process of iterating through generated events. 197 // 198 199 bool empty() const; 200 size_t size() const; 201 Iterator begin() const; 202 Iterator end() const; 203 204 // Clear any previously added events. 205 void ClearEvents(); 206 207 // This is called automatically based on changes to the tree observed 208 // by AXTreeObserver, but you can also call it directly to add events 209 // and retrieve them later. 210 // 211 // Note that events are organized by node and then by event id to 212 // efficiently remove duplicates, so events won't be retrieved in the 213 // same order they were added. 214 void AddEvent(ui::AXNode* node, Event event); 215 set_always_fire_load_complete(bool val)216 void set_always_fire_load_complete(bool val) { 217 always_fire_load_complete_ = val; 218 } 219 220 void AddEventsForTesting(AXNode* node, const std::set<EventParams>& events); 221 222 protected: 223 // AXTreeObserver overrides. 224 void OnNodeDataChanged(AXTree* tree, 225 const AXNodeData& old_node_data, 226 const AXNodeData& new_node_data) override; 227 void OnRoleChanged(AXTree* tree, 228 AXNode* node, 229 ax::mojom::Role old_role, 230 ax::mojom::Role new_role) override; 231 void OnStateChanged(AXTree* tree, 232 AXNode* node, 233 ax::mojom::State state, 234 bool new_value) override; 235 void OnStringAttributeChanged(AXTree* tree, 236 AXNode* node, 237 ax::mojom::StringAttribute attr, 238 const std::string& old_value, 239 const std::string& new_value) override; 240 void OnIntAttributeChanged(AXTree* tree, 241 AXNode* node, 242 ax::mojom::IntAttribute attr, 243 int32_t old_value, 244 int32_t new_value) override; 245 void OnFloatAttributeChanged(AXTree* tree, 246 AXNode* node, 247 ax::mojom::FloatAttribute attr, 248 float old_value, 249 float new_value) override; 250 void OnBoolAttributeChanged(AXTree* tree, 251 AXNode* node, 252 ax::mojom::BoolAttribute attr, 253 bool new_value) override; 254 void OnIntListAttributeChanged( 255 AXTree* tree, 256 AXNode* node, 257 ax::mojom::IntListAttribute attr, 258 const std::vector<int32_t>& old_value, 259 const std::vector<int32_t>& new_value) override; 260 void OnTreeDataChanged(AXTree* tree, 261 const ui::AXTreeData& old_data, 262 const ui::AXTreeData& new_data) override; 263 void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override; 264 void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override; 265 void OnNodeWillBeReparented(AXTree* tree, AXNode* node) override; 266 void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) override; 267 void OnNodeReparented(AXTree* tree, AXNode* node) override; 268 void OnAtomicUpdateFinished(AXTree* tree, 269 bool root_changed, 270 const std::vector<Change>& changes) override; 271 272 private: 273 void FireLiveRegionEvents(AXNode* node); 274 void FireActiveDescendantEvents(); 275 void FireValueInTextFieldChangedEvent(AXTree* tree, AXNode* target_node); 276 void FireRelationSourceEvents(AXTree* tree, AXNode* target_node); 277 bool ShouldFireLoadEvents(AXNode* node); 278 // Remove excessive events for a tree update containing node. 279 // We remove certain events on a node when it flips its IGNORED state to 280 // either show/hide and one of the node's ancestor has also flipped its 281 // IGNORED state in the same way (show/hide) in the tree update. 282 // |ancestor_has_ignored_map| contains if a node's ancestor has changed to 283 // IGNORED state. 284 // Map's key is an AXNode. 285 // Map's value is a std::bitset containing IgnoredChangedStates(kShow/kHide). 286 // - Map's value IgnoredChangedStatesBitset contains kShow if an ancestor 287 // of node removed its IGNORED state. 288 // - Map's value IgnoredChangedStatesBitset contains kHide if an ancestor 289 // of node changed to IGNORED state. 290 // - When IgnoredChangedStatesBitset is not set, it means neither the 291 // node nor its ancestor has IGNORED_CHANGED. 292 void TrimEventsDueToAncestorIgnoredChanged( 293 AXNode* node, 294 std::map<AXNode*, IgnoredChangedStatesBitset>& 295 ancestor_ignored_changed_map); 296 void PostprocessEvents(); 297 static void GetRestrictionStates(ax::mojom::Restriction restriction, 298 bool* is_enabled, 299 bool* is_readonly); 300 301 // Returns a vector of values unique to either |lhs| or |rhs| 302 static std::vector<int32_t> ComputeIntListDifference( 303 const std::vector<int32_t>& lhs, 304 const std::vector<int32_t>& rhs); 305 306 AXTree* tree_ = nullptr; // Not owned. 307 std::map<AXNode*, std::set<EventParams>> tree_events_; 308 309 // Valid between the call to OnIntAttributeChanged and the call to 310 // OnAtomicUpdateFinished. List of nodes whose active descendant changed. 311 std::vector<AXNode*> active_descendant_changed_; 312 313 bool always_fire_load_complete_ = false; 314 315 // Please make sure that this ScopedObserver is always declared last in order 316 // to prevent any use-after-free. 317 ScopedObserver<AXTree, AXTreeObserver> tree_event_observer_{this}; 318 }; 319 320 AX_EXPORT std::ostream& operator<<(std::ostream& os, 321 AXEventGenerator::Event event); 322 AX_EXPORT const char* ToString(AXEventGenerator::Event event); 323 324 } // namespace ui 325 326 #endif // UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_ 327