123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_
- #define UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_
- #include <bitset>
- #include <map>
- #include <memory>
- #include <ostream>
- #include <set>
- #include <string>
- #include <vector>
- #include "base/memory/raw_ptr.h"
- #include "base/scoped_observation.h"
- #include "ui/accessibility/ax_event_intent.h"
- #include "ui/accessibility/ax_export.h"
- #include "ui/accessibility/ax_tree.h"
- #include "ui/accessibility/ax_tree_observer.h"
- namespace ui {
- class AXLiveRegionTracker;
- // Subclass of AXTreeObserver that automatically generates AXEvents to fire
- // based on changes to an accessibility tree. Every platform
- // tends to want different events, so this class lets each platform
- // handle the events it wants and ignore the others.
- class AX_EXPORT AXEventGenerator : public AXTreeObserver {
- public:
- enum class Event : int32_t {
- ACCESS_KEY_CHANGED,
- ACTIVE_DESCENDANT_CHANGED,
- ALERT,
- ARIA_CURRENT_CHANGED,
- // ATK treats alignment, indentation, and other format-related attributes as
- // text attributes even when they are only applicable to the entire object.
- // And it lacks an event for use when object attributes have changed.
- ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED,
- ATOMIC_CHANGED,
- AUTO_COMPLETE_CHANGED,
- BUSY_CHANGED,
- CARET_BOUNDS_CHANGED,
- CHECKED_STATE_CHANGED,
- CHECKED_STATE_DESCRIPTION_CHANGED,
- CHILDREN_CHANGED,
- CLASS_NAME_CHANGED,
- COLLAPSED,
- CONTROLS_CHANGED,
- DETAILS_CHANGED,
- DESCRIBED_BY_CHANGED,
- DESCRIPTION_CHANGED,
- DOCUMENT_SELECTION_CHANGED,
- DOCUMENT_TITLE_CHANGED,
- DROPEFFECT_CHANGED,
- // TODO(nektar): Deprecate this event and replace it with
- // "VALUE_IN_TEXT_FIELD_CHANGED".
- EDITABLE_TEXT_CHANGED,
- ENABLED_CHANGED,
- EXPANDED,
- FOCUS_CHANGED,
- FLOW_FROM_CHANGED,
- FLOW_TO_CHANGED,
- GRABBED_CHANGED,
- HASPOPUP_CHANGED,
- HIERARCHICAL_LEVEL_CHANGED,
- IGNORED_CHANGED,
- IMAGE_ANNOTATION_CHANGED,
- INVALID_STATUS_CHANGED,
- KEY_SHORTCUTS_CHANGED,
- LABELED_BY_CHANGED,
- LANGUAGE_CHANGED,
- LAYOUT_INVALIDATED, // Fired when aria-busy turns from true to false.
- // Fired only on the root of the ARIA live region.
- LIVE_REGION_CHANGED,
- // Fired only on the root of the ARIA live region.
- LIVE_REGION_CREATED,
- // Fired on all the nodes within the ARIA live region excluding its root.
- LIVE_REGION_NODE_CHANGED,
- // Fired only on the root of the ARIA live region.
- LIVE_RELEVANT_CHANGED,
- // Fired only on the root of the ARIA live region.
- LIVE_STATUS_CHANGED,
- MENU_ITEM_SELECTED,
- MENU_POPUP_END,
- MENU_POPUP_START,
- MULTILINE_STATE_CHANGED,
- MULTISELECTABLE_STATE_CHANGED,
- NAME_CHANGED,
- OBJECT_ATTRIBUTE_CHANGED,
- OTHER_ATTRIBUTE_CHANGED,
- PARENT_CHANGED,
- PLACEHOLDER_CHANGED,
- PORTAL_ACTIVATED,
- POSITION_IN_SET_CHANGED,
- RANGE_VALUE_CHANGED,
- RANGE_VALUE_MAX_CHANGED,
- RANGE_VALUE_MIN_CHANGED,
- RANGE_VALUE_STEP_CHANGED,
- READONLY_CHANGED,
- RELATED_NODE_CHANGED,
- REQUIRED_STATE_CHANGED,
- ROLE_CHANGED,
- ROW_COUNT_CHANGED,
- SCROLL_HORIZONTAL_POSITION_CHANGED,
- SCROLL_VERTICAL_POSITION_CHANGED,
- SELECTED_CHANGED,
- SELECTED_CHILDREN_CHANGED,
- SELECTED_VALUE_CHANGED,
- SET_SIZE_CHANGED,
- SORT_CHANGED,
- STATE_CHANGED,
- SUBTREE_CREATED,
- TEXT_ATTRIBUTE_CHANGED,
- TEXT_SELECTION_CHANGED,
- VALUE_IN_TEXT_FIELD_CHANGED,
- // This event is fired for the exact set of attributes that affect the
- // MSAA/IAccessible state on Windows. It is not needed on other platforms,
- // but it is very natural to compute in this class.
- WIN_IACCESSIBLE_STATE_CHANGED,
- MAX_VALUE = WIN_IACCESSIBLE_STATE_CHANGED,
- };
- // For distinguishing between show and hide state when a node has
- // an IGNORED_CHANGED event.
- enum class IgnoredChangedState : uint8_t { kShow, kHide, kCount = 2 };
- struct AX_EXPORT EventParams final {
- explicit EventParams(Event event);
- EventParams(Event event,
- ax::mojom::EventFrom event_from,
- ax::mojom::Action event_from_action,
- const std::vector<AXEventIntent>& event_intents);
- EventParams(const EventParams& other);
- ~EventParams();
- EventParams& operator=(const EventParams& other);
- bool operator==(const EventParams& rhs) const;
- bool operator<(const EventParams& rhs) const;
- Event event;
- ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone;
- ax::mojom::Action event_from_action;
- std::vector<AXEventIntent> event_intents;
- };
- struct AX_EXPORT TargetedEvent final {
- TargetedEvent(AXNodeID node_id, const EventParams& event_params);
- ~TargetedEvent();
- const AXNodeID node_id;
- const EventParams& event_params;
- };
- class AX_EXPORT Iterator {
- public:
- using iterator_category = std::input_iterator_tag;
- using value_type = TargetedEvent;
- using difference_type = std::ptrdiff_t;
- using pointer = TargetedEvent*;
- using reference = TargetedEvent&;
- Iterator(
- std::map<AXNodeID, std::set<EventParams>>::const_iterator
- map_start_iter,
- std::map<AXNodeID, std::set<EventParams>>::const_iterator map_end_iter);
- Iterator(const Iterator& other);
- ~Iterator();
- Iterator& operator=(const Iterator& other);
- Iterator& operator++();
- Iterator operator++(int); // Postfix increment.
- value_type operator*() const;
- private:
- AX_EXPORT friend bool operator==(const Iterator& lhs, const Iterator& rhs);
- AX_EXPORT friend bool operator!=(const Iterator& lhs, const Iterator& rhs);
- AX_EXPORT friend void swap(Iterator& lhs, Iterator& rhs);
- std::map<AXNodeID, std::set<EventParams>>::const_iterator map_iter_;
- std::map<AXNodeID, std::set<EventParams>>::const_iterator map_end_iter_;
- std::set<EventParams>::const_iterator set_iter_;
- };
- // For storing ignored changed states for a particular node. We use bitset as
- // the underlying data structure to improve memory usage.
- // We use the index of AXEventGenerator::IgnoredChangedState enum
- // to access the bitset data.
- // e.g. AXEventGenerator::IgnoredChangedState::kShow has index 0 in the
- // IgnoredChangedState enum. If |IgnoredChangedStatesBitset[0]| is set, it
- // means IgnoredChangedState::kShow is present. Similarly, kHide has index 1
- // in the enum, and it corresponds to |IgnoredChangedStatesBitset[1]|.
- using IgnoredChangedStatesBitset =
- std::bitset<static_cast<size_t>(IgnoredChangedState::kCount)>;
- using const_iterator = Iterator;
- using iterator = Iterator;
- using value_type = TargetedEvent;
- // If you use this constructor, you must call SetTree
- // before using this class.
- AXEventGenerator();
- // Automatically registers itself as the observer of |tree| and
- // clears it on desctruction. |tree| must be valid for the lifetime
- // of this object.
- explicit AXEventGenerator(AXTree* tree);
- ~AXEventGenerator() override;
- // Clears this class as the observer of the previous tree that was
- // being monitored, if any, and starts monitoring |new_tree|, if not
- // nullptr. Note that |new_tree| must be valid for the lifetime of
- // this object or until you call SetTree again.
- void SetTree(AXTree* new_tree);
- // Nulls-out |tree_| without accessing it or destroying it.
- void ReleaseTree();
- //
- // Methods that make this class behave like an STL container, which simplifies
- // the process of iterating through generated events.
- //
- bool empty() const;
- size_t size() const;
- Iterator begin() const;
- Iterator end() const;
- // Clear any previously added events.
- void ClearEvents();
- // This is called automatically based on changes to the tree observed
- // by AXTreeObserver, but you can also call it directly to add events
- // and retrieve them later.
- //
- // Note that events are organized by node and then by event id to
- // efficiently remove duplicates, so events won't be retrieved in the
- // same order they were added.
- void AddEvent(ui::AXNode* node, Event event);
- void AddEventsForTesting(const AXNode& node,
- const std::set<EventParams>& events);
- protected:
- // AXTreeObserver overrides.
- void OnIgnoredWillChange(AXTree* tree,
- AXNode* node,
- bool is_ignored_new_value) override;
- void OnNodeDataChanged(AXTree* tree,
- const AXNodeData& old_node_data,
- const AXNodeData& new_node_data) override;
- void OnRoleChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::Role old_role,
- ax::mojom::Role new_role) override;
- void OnIgnoredChanged(AXTree* tree,
- AXNode* node,
- bool is_ignored_new_value) override;
- void OnStateChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::State state,
- bool new_value) override;
- void OnStringAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::StringAttribute attr,
- const std::string& old_value,
- const std::string& new_value) override;
- void OnIntAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::IntAttribute attr,
- int32_t old_value,
- int32_t new_value) override;
- void OnFloatAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::FloatAttribute attr,
- float old_value,
- float new_value) override;
- void OnBoolAttributeChanged(AXTree* tree,
- AXNode* node,
- ax::mojom::BoolAttribute attr,
- bool new_value) override;
- void OnIntListAttributeChanged(
- AXTree* tree,
- AXNode* node,
- ax::mojom::IntListAttribute attr,
- const std::vector<int32_t>& old_value,
- const std::vector<int32_t>& new_value) override;
- void OnTreeDataChanged(AXTree* tree,
- const ui::AXTreeData& old_data,
- const ui::AXTreeData& new_data) override;
- void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override;
- void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override;
- void OnNodeWillBeReparented(AXTree* tree, AXNode* node) override;
- void OnSubtreeWillBeReparented(AXTree* tree, AXNode* node) override;
- void OnNodeDeleted(AXTree* tree, AXNodeID node_id) override;
- void OnNodeReparented(AXTree* tree, AXNode* node) override;
- void OnNodeCreated(AXTree* tree, AXNode* node) override;
- void OnAtomicUpdateFinished(AXTree* tree,
- bool root_changed,
- const std::vector<Change>& changes) override;
- private:
- static void GetRestrictionStates(ax::mojom::Restriction restriction,
- bool* is_enabled,
- bool* is_readonly);
- // Returns a vector of values unique to either |lhs| or |rhs|
- static std::vector<int32_t> ComputeIntListDifference(
- const std::vector<int32_t>& lhs,
- const std::vector<int32_t>& rhs);
- void FireLiveRegionEvents(AXNode* node);
- void FireActiveDescendantEvents();
- // If the given target node is inside a text field and the node's modification
- // could affect the field's value, generates an `VALUE_IN_TEXT_FIELD_CHANGED`
- // on the text field that contains the node.
- void FireValueInTextFieldChangedEventIfNecessary(AXTree* tree,
- AXNode* target_node);
- void FireRelationSourceEvents(AXTree* tree, AXNode* target_node);
- // Remove excessive events for a tree update containing node.
- // We remove certain events on a node when it flips its IGNORED state to
- // either show/hide and one of the node's ancestor has also flipped its
- // IGNORED state in the same way (show/hide) in the tree update.
- // |ancestor_has_ignored_map| contains if a node's ancestor has changed to
- // IGNORED state.
- // Map's key is an AXNode.
- // Map's value is a std::bitset containing IgnoredChangedStates(kShow/kHide).
- // - Map's value IgnoredChangedStatesBitset contains kShow if an ancestor
- // of node removed its IGNORED state.
- // - Map's value IgnoredChangedStatesBitset contains kHide if an ancestor
- // of node changed to IGNORED state.
- // - When IgnoredChangedStatesBitset is not set, it means neither the
- // node nor its ancestor has IGNORED_CHANGED.
- void TrimEventsDueToAncestorIgnoredChanged(
- AXNode* node,
- std::map<AXNode*, IgnoredChangedStatesBitset>&
- ancestor_ignored_changed_map);
- void PostprocessEvents();
- raw_ptr<AXTree> tree_ = nullptr; // Not owned.
- std::map<AXNodeID, std::set<EventParams>> tree_events_;
- // Valid between the call to OnIntAttributeChanged and the call to
- // OnAtomicUpdateFinished. List of nodes whose active descendant changed.
- std::vector<AXNode*> active_descendant_changed_;
- // Keeps track of nodes that have changed their state from ignored to
- // unignored, but which used to be in an invisible subtree. We should not fire
- // `Event::PARENT_CHANGED` on any of their children because they were
- // previously unknown to ATs.
- std::set<AXNodeID> nodes_to_suppress_parent_changed_on_;
- // Helper that tracks live regions.
- std::unique_ptr<AXLiveRegionTracker> live_region_tracker_;
- // Please make sure that this ScopedObserver is always declared last in order
- // to prevent any use-after-free.
- base::ScopedObservation<AXTree, AXTreeObserver> tree_event_observation_{this};
- };
- AX_EXPORT std::ostream& operator<<(std::ostream& os,
- AXEventGenerator::Event event);
- AX_EXPORT const char* ToString(AXEventGenerator::Event event);
- } // namespace ui
- #endif // UI_ACCESSIBILITY_AX_EVENT_GENERATOR_H_
|