#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 AX_EXPORT AXEventGenerator : public AXTreeObserver {
public:
enum class Event : int32_t {
NONE,
ACCESS_KEY_CHANGED,
ACTIVE_DESCENDANT_CHANGED,
ALERT,
ARIA_CURRENT_CHANGED,
ATK_TEXT_OBJECT_ATTRIBUTE_CHANGED,
ATOMIC_CHANGED,
AUTO_COMPLETE_CHANGED,
AUTOFILL_AVAILABILITY_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,
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,
LIVE_REGION_CHANGED,
LIVE_REGION_CREATED,
LIVE_REGION_NODE_CHANGED,
LIVE_RELEVANT_CHANGED,
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,
WIN_IACCESSIBLE_STATE_CHANGED,
MAX_VALUE = WIN_IACCESSIBLE_STATE_CHANGED,
};
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);
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_;
};
using IgnoredChangedStatesBitset =
std::bitset<static_cast<size_t>(IgnoredChangedState::kCount)>;
using const_iterator = Iterator;
using iterator = Iterator;
using value_type = TargetedEvent;
AXEventGenerator();
explicit AXEventGenerator(AXTree* tree);
~AXEventGenerator() override;
void SetTree(AXTree* new_tree);
void ReleaseTree();
bool empty() const;
size_t size() const;
Iterator begin() const;
Iterator end() const;
void ClearEvents();
void AddEvent(ui::AXNode* node, Event event);
void AddEventsForTesting(const AXNode& node,
const std::set<EventParams>& events);
protected:
void OnIgnoredWillChange(
AXTree* tree,
AXNode* node,
bool is_ignored_new_value,
bool is_changing_unignored_parents_children) 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 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);
static std::vector<int32_t> ComputeIntListDifference(
const std::vector<int32_t>& lhs,
const std::vector<int32_t>& rhs);
bool IsRemovalRelevantInLiveRegion(AXNode* node);
void FireLiveRegionEvents(AXNode* node, bool is_removal);
void FireActiveDescendantEvents();
void FireValueInTextFieldChangedEventIfNecessary(AXTree* tree,
AXNode* target_node);
void FireRelationSourceEvents(AXTree* tree, AXNode* target_node);
void TrimEventsDueToAncestorIgnoredChanged(
AXNode* node,
std::map<AXNode*, IgnoredChangedStatesBitset>&
ancestor_ignored_changed_map);
void PostprocessEvents();
raw_ptr<AXTree> tree_ = nullptr;
std::map<AXNodeID, std::set<EventParams>> tree_events_;
std::vector<AXNode*> active_descendant_changed_;
std::set<AXNodeID> nodes_to_suppress_parent_changed_on_;
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);
AX_EXPORT bool MaybeParseGeneratedEvent(const char* attribute,
AXEventGenerator::Event* result);
AX_EXPORT AXEventGenerator::Event ParseGeneratedEvent(const char* attribute);
}
#endif