This document describes how accessibility is implemented throughout Chromium at a high level.
The three central concepts of accessibility are:
Here's an example of an accessibility tree looks like. The following HTML:
<select title="Select A"> <option value="1">Option 1</option> <option value="2" selected>Option 2</option> <option value="3">Option 3</option> </select>
has a generated accessibility tree like this:
0: AXMenuList title="Select A" 1: AXMenuListOption title="Option 1" 2: AXMenuListOption title="Option 2" selected 3: AXMenuListOption title="Option 3"
Given that accessibility tree, an example of the events generated when selecting “Option 1” might be:
AXMenuListItemUnselected 2 AXMenuListItemSelected 1 AXMenuListValueChanged 0
An example of a command used to change the selection from “Option 1” to “Option 3” might be:
All three concepts are handled at several layers in Chromium.
Blink constructs an accessibility tree (a hierarchy of WebAXObjects) from the page it is rendering. WebAXObject is the public API wrapper around AXObject, which is the core class of Blink's accessibility tree. AXObject is an abstract class; the most commonly used concrete subclass of it is AXNodeObject, which wraps a Node. In turn, most AXNodeObjects are actually AXLayoutObjects, which wrap both a Node and a LayoutObject. Access to the LayoutObject is important because some elements are only in the AXObject tree depending on their visibility, geometry, linewrapping, and so on. There are some subclasses of AXLayoutObject that implement special-case logic for specific types of Node. There are also other subclasses of AXObject, which are mostly used for testing.
Note that not all AXLayoutObjects correspond to actual Nodes; some are synthetic layout objects which group related inline elements or similar.
The central class responsible for dealing with accessibility events in Blink is AXObjectCacheImpl, which is responsible for caching the corresponding AXObjects for Nodes or LayoutObjects. This class has many methods named
handleFoo, which are called throughout Blink to notify the AXObjectCacheImpl that it may need to update its tree. Since this class is already aware of all accessibility events in Blink, it is also responsible for relaying accessibility events from Blink to the embedding content layer.
The content layer lives on both sides of the renderer/browser split. The content layer translates WebAXObjects into AXContentNodeData, which is a subclass of ui::AXNodeData. The ui::AXNodeData class and related classes are Chromium's cross-platform accessibility tree. The translation is implemented in BlinkAXTreeSource. This translation happens on the renderer side, so the ui::AXNodeData tree now needs to be sent to the browser, which is done by sending AccessibilityHostMsg_EventParams with the payload being serialized delta-updates to the tree, so that changes that happen on the renderer side can be reflected on the browser side.
AccessibilityMsg_FooIPCs to the renderer, where they will be received by RenderAccessibilityImpl.
On Chrome OS, RenderFrameHostImpl does not route events to BrowserAccessibilityManager at all, since there is no platform screenreader outside Chrome to integrate with.
Views generates a NativeViewAccessibility for each View, which is used as the delegate for an AXPlatformNode representing that View. This part is relatively straightforward, but then the generated tree must be combined with the web accessibility tree, which is handled by BrowserAccessibilityManager.