blob: 6c07d345a85c05c1a74c06ccced0aa0b4f4b7706 [file] [log] [blame]
// Copyright 2019 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 CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "chromecast/browser/accessibility/proto/cast_server_accessibility.pb.h"
#include "chromecast/browser/cast_web_contents.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/accessibility/ax_action_handler.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/ax_tree_source.h"
namespace aura {
class Window;
} // namespace aura
namespace content {
class BrowserContext;
} // namespace content
namespace extensions {
class AutomationEventRouterInterface;
} // namespace extensions
namespace ui {
struct AXEvent;
} // namespace ui
namespace chromecast {
namespace accessibility {
class FlutterSemanticsNode;
// This class translates accessibility trees found in the gallium accessibility
// OnAccessibilityEventRequest proto into a tree update Chrome's accessibility
// API can work with.
class AXTreeSourceFlutter : public ui::AXTreeSource<FlutterSemanticsNode*>,
public CastWebContentsObserver,
public ui::AXActionHandler {
public:
class Delegate {
public:
virtual ~Delegate() {}
virtual void OnAction(const ui::AXActionData& data) = 0;
virtual void OnVirtualKeyboardBoundsChange(const gfx::Rect& bounds) = 0;
};
AXTreeSourceFlutter(
Delegate* delegate,
content::BrowserContext* browser_context,
extensions::AutomationEventRouterInterface* event_router = nullptr);
AXTreeSourceFlutter(const AXTreeSourceFlutter&) = delete;
~AXTreeSourceFlutter() override;
AXTreeSourceFlutter& operator=(const AXTreeSourceFlutter&) = delete;
// AXTreeSource implementation.
bool GetTreeData(ui::AXTreeData* data) const override;
// AXTreeSource implementation used by FlutterAccessibilityInfoData
// subclasses.
FlutterSemanticsNode* GetRoot() const override;
FlutterSemanticsNode* GetFromId(int32_t id) const override;
void SerializeNode(FlutterSemanticsNode* node,
ui::AXNodeData* out_data) const override;
FlutterSemanticsNode* GetParent(FlutterSemanticsNode* node) const override;
// Notifies automation of an accessibility event.
void NotifyAccessibilityEvent(
const ::gallium::castos::OnAccessibilityEventRequest* event_data);
// Notifies automation of a result to an action.
void NotifyActionResult(const ui::AXActionData& data, bool result);
// Attaches tree to an aura window and gives it system focus.
void Focus(aura::Window* window);
// Gets the window id of this tree.
int32_t window_id() const { return window_id_; }
void UpdateTree();
// CastWebContentsObserver
void PageStopped(PageState page_state, int error_code) override;
void SetAccessibilityEnabled(bool value);
private:
class AXTreeWebContentsObserver : public content::WebContentsObserver {
public:
AXTreeWebContentsObserver(
content::WebContents* web_contents,
chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source);
AXTreeWebContentsObserver(const AXTreeWebContentsObserver&) = delete;
AXTreeWebContentsObserver& operator=(const AXTreeWebContentsObserver&) =
delete;
void RenderFrameHostChanged(content::RenderFrameHost* old_host,
content::RenderFrameHost* new_host) override;
void AXTreeIDForMainFrameHasChanged() override;
private:
chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source_;
};
using AXTreeFlutterSerializer = ui::AXTreeSerializer<FlutterSemanticsNode*>;
friend class AXTreeSourceFlutterTest;
// AXTreeSource overrides.
int32_t GetId(FlutterSemanticsNode* node) const override;
void GetChildren(
FlutterSemanticsNode* node,
std::vector<FlutterSemanticsNode*>* out_children) const override;
bool IsValid(FlutterSemanticsNode* node) const override;
bool IsIgnored(FlutterSemanticsNode* node) const override;
bool IsEqual(FlutterSemanticsNode* node1,
FlutterSemanticsNode* node2) const override;
FlutterSemanticsNode* GetNull() const override;
// Computes the smallest rect that encloses all of the descendants of |node|.
gfx::Rect ComputeEnclosingBounds(FlutterSemanticsNode* node) const;
// Helper to recursively compute bounds for |node|. Returns true if non-empty
// bounds were encountered.
void ComputeEnclosingBoundsInternal(FlutterSemanticsNode* node,
gfx::Rect* computed_bounds) const;
// AXHostDelegate implementation.
void PerformAction(const ui::AXActionData& data) override;
// Resets tree state.
void Reset();
// Detects live region changes and generates events for them.
void HandleLiveRegions(std::vector<ui::AXEvent>* events);
// Detects added or deleted routes that trigger TTS from edge
// transitions (i.e. alert dialogs).
void HandleRoutes(std::vector<ui::AXEvent>* events);
// Detects rapidly changing nodes and use native TTS instead.
void HandleNativeTTS();
// Handle the virtual keyboard nodes and calculate the bounds of it.
void HandleVirtualKeyboardNodes();
// Depth first search for a node under 'parent' with names route flag.
FlutterSemanticsNode* FindRoutesNode(FlutterSemanticsNode* parent);
// Find the first focusable node from the root. If none found, return
// the root node id.
int32_t FindFirstFocusableNodeId();
// Submit text to TTS engine.
void SubmitTTS(const std::string& text);
std::unique_ptr<AXTreeFlutterSerializer> current_tree_serializer_;
int32_t root_id_;
int32_t window_id_;
int32_t focused_id_;
// A delegate that handles accessibility actions on behalf of this tree. The
// delegate is valid during the lifetime of this tree.
Delegate* delegate_;
content::BrowserContext* const browser_context_;
extensions::AutomationEventRouterInterface* const event_router_;
// Maps a node id to its tree data.
base::flat_map<int32_t /* node_id */, std::unique_ptr<FlutterSemanticsNode>>
tree_map_;
// Maps a node id to its parent.
base::flat_map<int32_t /* node_id */, int32_t /* parent_node_id */>
parent_map_;
// Mapping from ArcAccessibilityInfoData ID to its cached computed bounds.
// This simplifies bounds calculations.
base::flat_map<int32_t, gfx::Rect> cached_computed_bounds_;
// Cache from node id to computed name for live region.
std::map<int32_t, std::string> live_region_name_cache_;
// Cache for nodes with scopes route flags.
std::vector<int32_t> scopes_route_cache_;
// Cache form node id to tts string for native tts components.
std::map<int32_t, std::string> native_tts_name_cache_;
std::vector<int32_t> reparented_children_;
std::vector<std::string> child_trees_;
// Maps web contents id to the web contents observer
base::flat_map<int32_t, std::unique_ptr<AXTreeWebContentsObserver>>
child_tree_observers_;
// Observed CastWebContents for this tree node.
CastWebContents* cast_web_contents_;
// Copy of most recent tree data
gallium::castos::OnAccessibilityEventRequest last_event_data_;
bool accessibility_enabled_ = false;
// The bounds of virtual keyboard.
gfx::Rect keyboard_bounds_;
};
} // namespace accessibility
} // namespace chromecast
#endif // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_