blob: 697c8f2ede94e3e1f2898933a432b60b51a4054e [file] [log] [blame]
// Copyright (c) 2012 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 CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_
#define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/callback_forward.h"
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "content/browser/accessibility/accessibility_flags.h"
#include "content/browser/accessibility/browser_accessibility_position.h"
#include "content/common/content_export.h"
#include "content/public/browser/ax_event_notification_details.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_range.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/native_widget_types.h"
struct AccessibilityHostMsg_LocationChangeParams;
namespace content {
class BrowserAccessibility;
class BrowserAccessibilityManager;
#if defined(OS_ANDROID)
class BrowserAccessibilityManagerAndroid;
#elif defined(OS_WIN)
class BrowserAccessibilityManagerWin;
#elif BUILDFLAG(USE_ATK)
class BrowserAccessibilityManagerAuraLinux;
#elif defined(OS_MACOSX)
class BrowserAccessibilityManagerMac;
#endif
// For testing.
CONTENT_EXPORT ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node,
const ui::AXNodeData& node2 = ui::AXNodeData(),
const ui::AXNodeData& node3 = ui::AXNodeData(),
const ui::AXNodeData& node4 = ui::AXNodeData(),
const ui::AXNodeData& node5 = ui::AXNodeData(),
const ui::AXNodeData& node6 = ui::AXNodeData(),
const ui::AXNodeData& node7 = ui::AXNodeData(),
const ui::AXNodeData& node8 = ui::AXNodeData(),
const ui::AXNodeData& node9 = ui::AXNodeData(),
const ui::AXNodeData& node10 = ui::AXNodeData(),
const ui::AXNodeData& node11 = ui::AXNodeData(),
const ui::AXNodeData& node12 = ui::AXNodeData());
// Class that can perform actions on behalf of the BrowserAccessibilityManager.
// Note: BrowserAccessibilityManager should never cache any of the return
// values from any of these interfaces, especially those that return pointers.
// They may only be valid within this call stack. That policy eliminates any
// concerns about ownership and lifecycle issues; none of these interfaces
// transfer ownership and no return values are guaranteed to be valid outside
// of the current call stack.
class CONTENT_EXPORT BrowserAccessibilityDelegate {
public:
virtual ~BrowserAccessibilityDelegate() {}
virtual void AccessibilityPerformAction(const ui::AXActionData& data) = 0;
virtual bool AccessibilityViewHasFocus() const = 0;
virtual gfx::Rect AccessibilityGetViewBounds() const = 0;
virtual gfx::Point AccessibilityOriginInScreen(
const gfx::Rect& bounds) const = 0;
virtual float AccessibilityGetDeviceScaleFactor() const = 0;
virtual void AccessibilityFatalError() = 0;
virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() = 0;
virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0;
};
class CONTENT_EXPORT BrowserAccessibilityFactory {
public:
virtual ~BrowserAccessibilityFactory() {}
// Create an instance of BrowserAccessibility and return a new
// reference to it.
virtual BrowserAccessibility* Create();
};
// This is all of the information about the current find in page result,
// so we can activate it if requested.
struct BrowserAccessibilityFindInPageInfo {
BrowserAccessibilityFindInPageInfo();
// This data about find in text results is updated as the user types.
int request_id;
int match_index;
int start_id;
int start_offset;
int end_id;
int end_offset;
// The active request id indicates that the user committed to a find query,
// e.g. by pressing enter or pressing the next or previous buttons. If
// |active_request_id| == |request_id|, we fire an accessibility event
// to move screen reader focus to that event.
int active_request_id;
};
// Manages a tree of BrowserAccessibility objects.
class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXEventGenerator {
public:
// Creates the platform-specific BrowserAccessibilityManager, but
// with no parent window pointer. Only useful for unit tests.
static BrowserAccessibilityManager* Create(
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
static BrowserAccessibilityManager* FromID(
ui::AXTreeIDRegistry::AXTreeID ax_tree_id);
~BrowserAccessibilityManager() override;
void Initialize(const ui::AXTreeUpdate& initial_tree);
static ui::AXTreeUpdate GetEmptyDocument();
// Subclasses override these methods to send native event notifications.
virtual void FireFocusEvent(BrowserAccessibility* node);
virtual void FireBlinkEvent(ui::AXEvent event_type,
BrowserAccessibility* node) {}
virtual void FireGeneratedEvent(AXEventGenerator::Event event_type,
BrowserAccessibility* node) {}
// Checks whether focus has changed since the last time it was checked,
// taking into account whether the window has focus and which frame within
// the frame tree has focus. If focus has changed, calls FireFocusEvent.
void FireFocusEventsIfNeeded();
// Return whether or not we are currently able to fire events.
virtual bool CanFireEvents();
// Return a pointer to the root of the tree, does not make a new reference.
BrowserAccessibility* GetRoot();
// Returns a pointer to the BrowserAccessibility object for a given AXNode.
BrowserAccessibility* GetFromAXNode(const ui::AXNode* node) const;
// Return a pointer to the object corresponding to the given id,
// does not make a new reference.
BrowserAccessibility* GetFromID(int32_t id) const;
// If this tree has a parent tree, return the parent node in that tree.
BrowserAccessibility* GetParentNodeFromParentTree();
// Get the AXTreeData for this frame.
const ui::AXTreeData& GetTreeData();
// Called to notify the accessibility manager that its associated native
// view got focused.
virtual void OnWindowFocused();
// Called to notify the accessibility manager that its associated native
// view lost focus.
virtual void OnWindowBlurred();
// Notify the accessibility manager about page navigation.
void UserIsNavigatingAway();
virtual void UserIsReloading();
void NavigationSucceeded();
void NavigationFailed();
// Pretend that the given node has focus, for testing only. Doesn't
// communicate with the renderer and doesn't fire any events.
void SetFocusLocallyForTesting(BrowserAccessibility* node);
// For testing only, register a function to be called when focus changes
// in any BrowserAccessibilityManager.
static void SetFocusChangeCallbackForTesting(const base::Closure& callback);
// Normally we avoid firing accessibility focus events when the containing
// native window isn't focused, and we also delay some other events like
// live region events to improve screen reader compatibility.
// However, this can lead to test flakiness, so for testing, simplify
// this behavior and just fire all events with no delay as if the window
// had focus.
static void NeverSuppressOrDelayEventsForTesting();
// Accessibility actions. All of these are implemented asynchronously
// by sending a message to the renderer to perform the respective action
// on the given node. See the definition of |ui::AXActionData| for more
// information about each of these actions.
void Decrement(const BrowserAccessibility& node);
void DoDefaultAction(const BrowserAccessibility& node);
void GetImageData(const BrowserAccessibility& node,
const gfx::Size& max_size);
void HitTest(const gfx::Point& point);
void Increment(const BrowserAccessibility& node);
void LoadInlineTextBoxes(const BrowserAccessibility& node);
void ScrollToMakeVisible(
const BrowserAccessibility& node, gfx::Rect subfocus);
void ScrollToPoint(
const BrowserAccessibility& node, gfx::Point point);
void SetFocus(const BrowserAccessibility& node);
void SetScrollOffset(const BrowserAccessibility& node, gfx::Point offset);
void SetValue(
const BrowserAccessibility& node, const base::string16& value);
void SetSelection(
ui::AXRange<
BrowserAccessibilityPosition::AXPositionInstance::element_type>
range);
void ShowContextMenu(const BrowserAccessibility& node);
// Retrieve the bounds of the parent View in screen coordinates.
virtual gfx::Rect GetViewBounds();
// Fire an event telling native assistive technology to move focus to the
// given find in page result.
void ActivateFindInPageResult(int request_id, int match_index);
// Called when the renderer process has notified us of about tree changes.
virtual void OnAccessibilityEvents(
const std::vector<AXEventNotificationDetails>& details);
// Called when the renderer process updates the location of accessibility
// objects. Calls SendLocationChangeEvents(), which can be overridden.
void OnLocationChanges(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
// Called when a new find in page result is received. We hold on to this
// information and don't activate it until the user requests it.
void OnFindInPageResult(
int request_id, int match_index, int start_id, int start_offset,
int end_id, int end_offset);
// Called in response to a hit test, when the object hit has a child frame
// (like an iframe element or browser plugin), and we need to do another
// hit test recursively.
void OnChildFrameHitTestResult(const gfx::Point& point,
int hit_obj_id,
ui::AXEvent event_to_fire);
// This is called when the user has committed to a find in page query,
// e.g. by pressing enter or tapping on the next / previous result buttons.
// If a match has already been received for this request id,
// activate the result now by firing an accessibility event. If a match
// has not been received, we hold onto this request id and update it
// when OnFindInPageResult is called.
void ActivateFindInPageResult(int request_id);
#if defined(OS_WIN)
BrowserAccessibilityManagerWin* ToBrowserAccessibilityManagerWin();
#endif
#if defined(OS_ANDROID)
BrowserAccessibilityManagerAndroid* ToBrowserAccessibilityManagerAndroid();
#endif
#if BUILDFLAG(USE_ATK)
BrowserAccessibilityManagerAuraLinux*
ToBrowserAccessibilityManagerAuraLinux();
#endif
#if defined(OS_MACOSX)
BrowserAccessibilityManagerMac* ToBrowserAccessibilityManagerMac();
#endif
// Return the object that has focus, starting at the top of the frame tree.
virtual BrowserAccessibility* GetFocus();
// Return the object that has focus, only considering this frame and
// descendants.
BrowserAccessibility* GetFocusFromThisOrDescendantFrame();
// Given a focused node |focus|, returns a descendant of that node if it
// has an active descendant, otherwise returns |focus|.
BrowserAccessibility* GetActiveDescendant(BrowserAccessibility* focus);
// Returns true if native focus is anywhere in this WebContents or not.
bool NativeViewHasFocus();
// True by default, but some platforms want to treat the root
// scroll offsets separately.
virtual bool UseRootScrollOffsetsWhenComputingBounds();
// Walk the tree using depth-first pre-order traversal.
static BrowserAccessibility* NextInTreeOrder(
const BrowserAccessibility* object);
static BrowserAccessibility* PreviousInTreeOrder(
const BrowserAccessibility* object);
static BrowserAccessibility* NextTextOnlyObject(
const BrowserAccessibility* object);
static BrowserAccessibility* PreviousTextOnlyObject(
const BrowserAccessibility* object);
// If the two objects provided have a common ancestor returns both the
// common ancestor and the child indices of the two subtrees in which the
// objects are located.
// Returns false if a common ancestor cannot be found.
static bool FindIndicesInCommonParent(const BrowserAccessibility& object1,
const BrowserAccessibility& object2,
BrowserAccessibility** common_parent,
int* child_index1,
int* child_index2);
// Sets |out_is_before| to true if |object1| comes before |object2|
// in tree order (pre-order traversal), and false if the objects are the
// same or not in the same tree.
static ui::AXTreeOrder CompareNodes(
const BrowserAccessibility& object1,
const BrowserAccessibility& object2);
static std::vector<const BrowserAccessibility*> FindTextOnlyObjectsInRange(
const BrowserAccessibility& start_object,
const BrowserAccessibility& end_object);
static base::string16 GetTextForRange(
const BrowserAccessibility& start_object,
const BrowserAccessibility& end_object);
// If start and end offsets are greater than the text's length, returns all
// the text.
static base::string16 GetTextForRange(
const BrowserAccessibility& start_object,
int start_offset,
const BrowserAccessibility& end_object,
int end_offset);
static gfx::Rect GetPageBoundsForRange(
const BrowserAccessibility& start_object,
int start_offset,
const BrowserAccessibility& end_object,
int end_offset);
// Accessors.
ui::AXTreeIDRegistry::AXTreeID ax_tree_id() const { return ax_tree_id_; }
float device_scale_factor() const { return device_scale_factor_; }
const ui::AXTree* ax_tree() const { return tree_.get(); }
// AXTreeDelegate implementation.
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
const std::vector<ui::AXTreeDelegate::Change>& changes) override;
BrowserAccessibilityDelegate* delegate() const { return delegate_; }
// If this BrowserAccessibilityManager is a child frame or guest frame,
// return the BrowserAccessibilityManager from the highest ancestor frame
// in the frame tree.
BrowserAccessibilityManager* GetRootManager();
// Returns the BrowserAccessibilityDelegate from |GetRootManager|, above.
BrowserAccessibilityDelegate* GetDelegateFromRootManager();
// Returns whether this is the top document.
bool IsRootTree();
// Get a snapshot of the current tree as an AXTreeUpdate.
ui::AXTreeUpdate SnapshotAXTreeForTesting();
// Use a custom device scale factor for testing.
void UseCustomDeviceScaleFactorForTesting(float device_scale_factor);
// Given a point in screen coordinates, trigger an asynchronous hit test
// but return the best possible match instantly.
//
//
BrowserAccessibility* CachingAsyncHitTest(const gfx::Point& screen_point);
// Called in response to a hover event, caches the result for the next
// call to CachingAsyncHitTest().
void CacheHitTestResult(BrowserAccessibility* hit_test_result);
protected:
using BrowserAccessibilityPositionInstance =
BrowserAccessibilityPosition::AXPositionInstance;
using AXPlatformRange =
ui::AXRange<BrowserAccessibilityPositionInstance::element_type>;
BrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory);
BrowserAccessibilityManager(
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory);
// Send platform-specific notifications to each of these objects that
// their location has changed. This is called by OnLocationChanges
// after it's updated the internal data structure.
virtual void SendLocationChangeEvents(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
protected:
// The object that can perform actions on our behalf.
BrowserAccessibilityDelegate* delegate_;
// Factory to create BrowserAccessibility objects (for dependency injection).
std::unique_ptr<BrowserAccessibilityFactory> factory_;
// The underlying tree of accessibility objects.
std::unique_ptr<ui::AXSerializableTree> tree_;
// A mapping from a node id to its wrapper of type BrowserAccessibility.
base::hash_map<int32_t, BrowserAccessibility*> id_wrapper_map_;
// True if the user has initiated a navigation to another page.
bool user_is_navigating_away_;
BrowserAccessibilityFindInPageInfo find_in_page_info_;
// These are only used by the root BrowserAccessibilityManager of a
// frame tree. Stores the last focused node and last focused manager so
// that when focus might have changed we can figure out whether we need
// to fire a focus event.
//
// NOTE: these pointers are not cleared, so they should never be
// dereferenced, only used for comparison.
BrowserAccessibility* last_focused_node_;
BrowserAccessibilityManager* last_focused_manager_;
// These cache the AX tree ID, node ID, and global screen bounds of the
// last object found by an asynchronous hit test. Subsequent hit test
// requests that remain within this object's bounds will return the same
// object, but will also trigger a new asynchronous hit test request.
int last_hover_ax_tree_id_;
int last_hover_node_id_;
gfx::Rect last_hover_bounds_;
// 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_;
// The global ID of this accessibility tree.
ui::AXTreeIDRegistry::AXTreeID ax_tree_id_;
// If this tree has a parent tree, this is the cached ID of the parent
// node within that parent tree. It's computed as needed and cached for
// speed so that it can be accessed quickly if it hasn't changed.
int parent_node_id_from_parent_tree_;
// The device scale factor for the view associated with this frame,
// cached each time there's any update to the accessibility tree.
float device_scale_factor_;
// For testing only: If true, the manually-set device scale factor will be
// used and it won't be updated from the delegate.
bool use_custom_device_scale_factor_for_testing_;
// Fire all events regardless of focus and with no delay, to avoid test
// flakiness. See NeverSuppressOrDelayEventsForTesting() for details.
static bool never_suppress_or_delay_events_for_testing_;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager);
};
} // namespace content
#endif // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_H_