| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef UI_ACCESSIBILITY_AX_TREE_MANAGER_H_ |
| #define UI_ACCESSIBILITY_AX_TREE_MANAGER_H_ |
| |
| #include "base/scoped_observation.h" |
| #include "ui/accessibility/ax_event_generator.h" |
| #include "ui/accessibility/ax_export.h" |
| #include "ui/accessibility/ax_tree.h" |
| #include "ui/accessibility/ax_tree_observer.h" |
| |
| namespace ui { |
| |
| class AXNode; |
| class AXTreeManagerMap; |
| |
| // Abstract interface for a class that owns an AXTree and manages its |
| // connections to other AXTrees in the same page or desktop (parent and child |
| // trees). |
| // |
| // Note, the tree manager may be created for a tree which has unknown (not |
| // valid) tree id. A such tree is not registered with the tree map and thus |
| // cannot be retrieved from the map. When the tree gets data and tree id, then |
| // it is registered in the map automatically (see OnTreeDataChanged callback |
| // notification). The mechanism implements the tree id data integrirty between |
| // the tree map and trees, also it doesn't allow to register two different trees |
| // with unknown IDs. |
| class AX_EXPORT AXTreeManager : public AXTreeObserver { |
| public: |
| static AXTreeManager* FromID(const AXTreeID& ax_tree_id); |
| // If the child of `parent_node` exists in a separate child tree, return the |
| // tree manager for that child tree. Otherwise, return nullptr. |
| static AXTreeManager* ForChildTree(const AXNode& parent_node); |
| |
| // For testing only, register a function to be called when focus changes |
| // in any AXTreeManager. |
| static void SetFocusChangeCallbackForTesting(base::RepeatingClosure callback); |
| |
| AXTreeManager(const AXTreeManager&) = delete; |
| AXTreeManager& operator=(const AXTreeManager&) = delete; |
| |
| ~AXTreeManager() override; |
| |
| enum class RetargetEventType { |
| RetargetEventTypeGenerated = 0, |
| RetargetEventTypeBlinkGeneral, |
| RetargetEventTypeBlinkHover, |
| }; |
| |
| // Subclasses override these methods to send native event notifications. |
| virtual void FireFocusEvent(AXNode* node); |
| // Return |node| by default, but some platforms want to update the target node |
| // based on the event type. |
| virtual AXNode* RetargetForEvents(AXNode* node, RetargetEventType type) const; |
| virtual void FireGeneratedEvent(ui::AXEventGenerator::Event event_type, |
| const ui::AXNode* node) {} |
| virtual bool CanFireEvents() const; |
| |
| // Returns the AXNode with the given |node_id| from the tree that has the |
| // given |tree_id|. This allows for callers to access nodes outside of their |
| // own tree. Returns nullptr if |tree_id| or |node_id| is not found. |
| // TODO(kschmi): Remove |tree_id| parameter, as it's unnecessary. |
| virtual AXNode* GetNodeFromTree(const AXTreeID& tree_id, |
| const AXNodeID node_id) const; |
| |
| // Returns the AXNode in the current tree that has the given |node_id|. |
| // Returns nullptr if |node_id| is not found. |
| virtual AXNode* GetNode(const AXNodeID node_id) const; |
| |
| // Returns true if the manager has a tree with a valid (not unknown) ID. |
| bool HasValidTreeID() const { |
| return ax_tree_ && ax_tree_->GetAXTreeID() != ui::AXTreeIDUnknown(); |
| } |
| |
| // Returns the tree id of the tree managed by this AXTreeManager. |
| AXTreeID GetTreeID() const { |
| return ax_tree_ ? ax_tree_->GetAXTreeID() : ui::AXTreeIDUnknown(); |
| } |
| |
| // Returns the AXTreeData for the tree managed by this AXTreeManager. |
| const AXTreeData& GetTreeData() const; |
| |
| // Returns the tree id of the parent tree. |
| // Returns AXTreeIDUnknown if this tree doesn't have a parent tree. |
| virtual AXTreeID GetParentTreeID() const; |
| |
| // Returns the AXNode that is at the root of the current tree. |
| AXNode* GetRoot() const; |
| |
| bool IsRoot() const; |
| |
| // Returns the root AXTreeManager by walking up the tree to any parent trees. |
| // If there is a parent tree that is not yet connected, returns nullptr. |
| AXTreeManager* GetRootManager() const; |
| |
| // If this tree has a parent tree, returns the node in the parent tree that |
| // hosts the current tree. Returns nullptr if this tree doesn't have a parent |
| // tree. |
| virtual AXNode* GetParentNodeFromParentTree() const; |
| |
| void Initialize(const AXTreeUpdate& initial_tree); |
| |
| // Called when the tree manager is about to be removed from the tree map, |
| // `AXTreeManagerMap`. |
| void WillBeRemovedFromMap(); |
| |
| AXTree* ax_tree() const { return ax_tree_.get(); } |
| |
| const AXEventGenerator& event_generator() const { return event_generator_; } |
| AXEventGenerator& event_generator() { return event_generator_; } |
| |
| // AXTreeObserver implementation. |
| void OnTreeDataChanged(AXTree* tree, |
| const AXTreeData& old_data, |
| const AXTreeData& new_data) override; |
| void OnNodeWillBeDeleted(AXTree* tree, AXNode* node) override; |
| void OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) override {} |
| void OnNodeCreated(AXTree* tree, AXNode* node) override {} |
| void OnNodeDeleted(AXTree* tree, int32_t node_id) override {} |
| void OnNodeReparented(AXTree* tree, AXNode* node) override {} |
| void OnRoleChanged(AXTree* tree, |
| AXNode* node, |
| ax::mojom::Role old_role, |
| ax::mojom::Role new_role) override {} |
| void OnAtomicUpdateFinished( |
| AXTree* tree, |
| bool root_changed, |
| const std::vector<AXTreeObserver::Change>& changes) override; |
| |
| protected: |
| AXTreeManager(); |
| explicit AXTreeManager(std::unique_ptr<AXTree> tree); |
| |
| virtual AXTreeManager* GetParentManager() const; |
| |
| // Return the last node that had focus, no searching. |
| static AXNode* GetLastFocusedNode(); |
| |
| static void SetLastFocusedNode(AXNode* node); |
| |
| // Add parent connection if missing (!connected_to_parent_tree_node_). If the |
| // root's parent is in another accessibility tree but it wasn't previously |
| // connected, post the proper notifications on the parent. |
| void EnsureParentConnectionIfNotRootManager(); |
| |
| // Refreshes a parent node in a parent tree when it needs to be informed that |
| // this tree is ready or being destroyed. |
| void ParentConnectionChanged(AXNode* parent); |
| |
| // Inheriting classes should override this method to update the `parent` |
| // attributes accordingly when the parent connection changes. |
| virtual void UpdateAttributesOnParent(AXNode* parent) {} |
| |
| // Perform some additional clean up on the derived classes to be called in the |
| // destructor. |
| virtual void CleanUp() {} |
| |
| // True if the root's parent is in another accessibility tree and that |
| // parent's child is the root. Ensures that the parent node is notified |
| // once when this subtree is first connected. |
| bool connected_to_parent_tree_node_; |
| |
| std::unique_ptr<AXTree> ax_tree_; |
| |
| AXEventGenerator event_generator_; |
| |
| // Stores the id of the last focused node, as well as the id |
| // of the tree that contains it, so that when focus might have changed we can |
| // figure out whether we need to fire a focus event. |
| // |
| // NOTE: Don't use or modify these properties directly, use the |
| // SetLastFocusedNode and GetLastFocusedNode methods instead. |
| static absl::optional<AXNodeID> last_focused_node_id_; |
| static absl::optional<AXTreeID> last_focused_node_tree_id_; |
| |
| private: |
| friend class AXDummyTreeManager; |
| friend class TestAXTreeManager; |
| |
| static AXTreeManagerMap& GetMap(); |
| |
| // Automatically stops observing notifications from the AXTree when this class |
| // is destructed. |
| // |
| // This member needs to be destructed before any observed AXTrees. Since |
| // destructors for non-static member fields are called in the reverse order of |
| // declaration, do not move this member above other members. |
| base::ScopedObservation<AXTree, AXTreeObserver> tree_observation_{this}; |
| }; |
| |
| } // namespace ui |
| |
| #endif // UI_ACCESSIBILITY_AX_TREE_MANAGER_H_ |