Skip to content

Commit

Permalink
Cross-process iframe accessibility.
Browse files Browse the repository at this point in the history
This change completes the plumbing to join cross-process iframes into a single composed accessibility tree on platforms that implement native accessibility APIs (Windows, Mac, Android).

Further work will be needed to update some accessibility API implementations to be multi-frame-aware.

BUG=368298

Committed: https://crrev.com/387942c041da17ea6337bc0a81e96619e67e4ac4
Cr-Commit-Position: refs/heads/master@{#294118}

Review URL: https://codereview.chromium.org/268543008

Cr-Commit-Position: refs/heads/master@{#294210}
  • Loading branch information
minorninth authored and Commit bot committed Sep 10, 2014
1 parent b84165f commit 0b5d248
Show file tree
Hide file tree
Showing 28 changed files with 557 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void AccessibilityTreeFormatter::RecursiveBuildAccessibilityTree(
dict->Set(kChildrenDictAttr, children);

for (size_t i = 0; i < node.PlatformChildCount(); ++i) {
BrowserAccessibility* child_node = node.InternalGetChild(i);
BrowserAccessibility* child_node = node.PlatformGetChild(i);
base::DictionaryValue* child_dict = new base::DictionaryValue;
children->Append(child_dict);
RecursiveBuildAccessibilityTree(*child_node, child_dict);
Expand Down
32 changes: 30 additions & 2 deletions content/browser/accessibility/browser_accessibility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ BrowserAccessibility* BrowserAccessibility::Create() {

BrowserAccessibility::BrowserAccessibility()
: manager_(NULL),
node_(NULL) {
node_(NULL),
child_frame_tree_node_id_(0) {
}

BrowserAccessibility::~BrowserAccessibility() {
Expand Down Expand Up @@ -63,6 +64,15 @@ bool BrowserAccessibility::PlatformIsLeaf() const {
}

uint32 BrowserAccessibility::PlatformChildCount() const {
if (child_frame_tree_node_id_ &&
manager_ && manager_->delegate()) {
BrowserAccessibilityManager* child_manager =
manager_->delegate()->AccessibilityGetChildFrame(
child_frame_tree_node_id_);
if (child_manager)
return 1;
}

return PlatformIsLeaf() ? 0 : InternalChildCount();
}

Expand All @@ -83,6 +93,16 @@ bool BrowserAccessibility::IsDescendantOf(

BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
uint32 child_index) const {
if (child_index == 0 && child_frame_tree_node_id_ &&
manager_ &&
manager_->delegate()) {
BrowserAccessibilityManager* child_manager =
manager_->delegate()->AccessibilityGetChildFrame(
child_frame_tree_node_id_);
if (child_manager)
return child_manager->GetRoot();
}

DCHECK(child_index < InternalChildCount());
return InternalGetChild(child_index);
}
Expand Down Expand Up @@ -122,7 +142,9 @@ BrowserAccessibility* BrowserAccessibility::GetParent() const {
if (!node_ || !manager_)
return NULL;
ui::AXNode* parent = node_->parent();
return parent ? manager_->GetFromAXNode(parent) : NULL;
if (parent)
return manager_->GetFromAXNode(parent);
return manager_->GetCrossFrameParent();
}

int32 BrowserAccessibility::GetIndexInParent() const {
Expand Down Expand Up @@ -680,4 +702,10 @@ int BrowserAccessibility::GetStaticTextLenRecursive() const {
return len;
}

void BrowserAccessibility::SetChildFrameTreeNodeId(
int64 child_frame_tree_node_id) {
child_frame_tree_node_id_ = child_frame_tree_node_id;
manager_->NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, this);
}

} // namespace content
24 changes: 18 additions & 6 deletions content/browser/accessibility/browser_accessibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ class BrowserAccessibilityWin;
//
// BrowserAccessibility
//
// Class implementing the cross platform interface for the Browser-Renderer
// communication of accessibility information, providing accessibility
// to be used by screen readers and other assistive technology (AT).
// A BrowserAccessibility object represents one node in the accessibility
// tree on the browser side. It exactly corresponds to one WebAXObject from
// Blink. It's owned by a BrowserAccessibilityManager.
//
// An implementation for each platform handles platform specific accessibility
// APIs.
// There are subclasses of BrowserAccessibility for each platform where
// we implement native accessibility APIs. This base class is used occasionally
// for tests.
//
////////////////////////////////////////////////////////////////////////////////
class CONTENT_EXPORT BrowserAccessibility {
Expand Down Expand Up @@ -245,6 +246,15 @@ class CONTENT_EXPORT BrowserAccessibility {
// Append the text from this node and its children.
std::string GetTextRecursive() const;

// Identifies the given frame tree node id as the only child of this node,
// so any call to PlatformChildCount/PlatformGetChild will use
// BrowserAccessibilityDelegate::AccessibilityGetChildFrame to retrieve
// the BrowserAccessibilityManager of the child frame and return its root
// node as this node's child.
void SetChildFrameTreeNodeId(int64 child_frame_tree_node_id);

int64 child_frame_tree_node_id() const { return child_frame_tree_node_id_; }

protected:
BrowserAccessibility();

Expand All @@ -262,7 +272,9 @@ class CONTENT_EXPORT BrowserAccessibility {
std::string name_;
std::string value_;

private:
// If nonzero, the frame tree node id of the child frame of this node.
int64 child_frame_tree_node_id_;

DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
};

Expand Down
69 changes: 67 additions & 2 deletions content/browser/accessibility/browser_accessibility_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,38 @@
#include "base/logging.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/common/accessibility_messages.h"
#include "ui/accessibility/ax_tree_serializer.h"

namespace content {

namespace {

// Recursively searches |ancestor_node| and its descendants for a
// BrowserAccessibility with |child| as its immediate and only child.
// Searches only the frame that |ancestor_node| belongs to, does not descend
// into child frames (but |child| can be the root of another frame).
BrowserAccessibility* FindParentOfNode(
BrowserAccessibility* ancestor_node, BrowserAccessibility* child) {
if (ancestor_node->PlatformChildCount() == 1 &&
ancestor_node->PlatformGetChild(0) == child) {
return ancestor_node;
}

if (ancestor_node->InternalChildCount() == 0)
return NULL;

for (uint32 i = 0; i < ancestor_node->PlatformChildCount(); ++i) {
BrowserAccessibility* result = FindParentOfNode(
ancestor_node->PlatformGetChild(i), child);
if (result)
return result;
}

return NULL;
}

} // namespace.

ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node1,
const ui::AXNodeData& node2 /* = ui::AXNodeData() */,
Expand Down Expand Up @@ -67,7 +96,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
tree_(new ui::AXTree()),
tree_(new ui::AXSerializableTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
Expand All @@ -79,7 +108,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
tree_(new ui::AXTree()),
tree_(new ui::AXSerializableTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
Expand Down Expand Up @@ -363,4 +392,40 @@ void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
GetFromAXNode(node)->OnUpdateFinished();
}

ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
tree_->CreateTreeSource());
ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
ui::AXTreeUpdate update;
serializer.SerializeChanges(tree_->GetRoot(), &update);
return update;
}

void BrowserAccessibilityManager::SetChildFrameTreeNodeId(
int32 node_id, int64 child_frame_tree_node_id) {
BrowserAccessibility* node = GetFromID(node_id);
if (node) {
// The node id passed to us is the web area for the proxy frame.
// In order to replace this node with the child frame, set the
// child frame id on its parent.
BrowserAccessibility* node_parent = node->GetParent();
if (node_parent)
node_parent->SetChildFrameTreeNodeId(child_frame_tree_node_id);
}
}

BrowserAccessibility* BrowserAccessibilityManager::GetCrossFrameParent() {
if (!delegate_)
return NULL;

BrowserAccessibilityManager* parent_frame =
delegate_->AccessibilityGetParentFrame();
if (!parent_frame)
return NULL;

// Recursively search the parent frame to find the node that has this
// frame as its child.
return FindParentOfNode(parent_frame->GetRoot(), GetRoot());
}

} // namespace content
36 changes: 19 additions & 17 deletions content/browser/accessibility/browser_accessibility_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/native_widget_types.h"

Expand All @@ -22,6 +22,7 @@ struct AccessibilityHostMsg_LocationChangeParams;

namespace content {
class BrowserAccessibility;
class BrowserAccessibilityManager;
#if defined(OS_ANDROID)
class BrowserAccessibilityManagerAndroid;
#endif
Expand All @@ -42,6 +43,12 @@ CONTENT_EXPORT ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node9 = 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() {}
Expand All @@ -63,6 +70,9 @@ class CONTENT_EXPORT BrowserAccessibilityDelegate {
virtual void AccessibilityFatalError() = 0;
virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() = 0;
virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0;
virtual BrowserAccessibilityManager* AccessibilityGetChildFrame(
int64 frame_tree_node_id) = 0;
virtual BrowserAccessibilityManager* AccessibilityGetParentFrame() = 0;
};

class CONTENT_EXPORT BrowserAccessibilityFactory {
Expand Down Expand Up @@ -189,6 +199,13 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
delegate_ = delegate;
}

// Get a snapshot of the current tree as an AXTreeUpdate.
ui::AXTreeUpdate SnapshotAXTreeForTesting();

// Frame tree support.
void SetChildFrameTreeNodeId(int32 node_id, int64 child_frame_tree_node_id);
BrowserAccessibility* GetCrossFrameParent();

protected:
BrowserAccessibilityManager(
BrowserAccessibilityDelegate* delegate,
Expand Down Expand Up @@ -225,21 +242,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
OSK_ALLOWED
};

// Update a set of nodes using data received from the renderer
// process.
bool UpdateNodes(const std::vector<ui::AXNodeData>& nodes);

// Update one node from the tree using data received from the renderer
// process. Returns true on success, false on fatal error.
bool UpdateNode(const ui::AXNodeData& src);

void SetRoot(BrowserAccessibility* root);

BrowserAccessibility* CreateNode(
BrowserAccessibility* parent,
int32 id,
int32 index_in_parent);

protected:
// The object that can perform actions on our behalf.
BrowserAccessibilityDelegate* delegate_;
Expand All @@ -248,7 +250,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
scoped_ptr<BrowserAccessibilityFactory> factory_;

// The underlying tree of accessibility objects.
scoped_ptr<ui::AXTree> tree_;
scoped_ptr<ui::AXSerializableTree> tree_;

// The node that currently has focus.
ui::AXNode* focus_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ class TestBrowserAccessibilityDelegate
OVERRIDE {
return NULL;
}
virtual BrowserAccessibilityManager* AccessibilityGetChildFrame(
int64 frame_tree_node_id) OVERRIDE {
return NULL;
}
virtual BrowserAccessibilityManager* AccessibilityGetParentFrame() OVERRIDE {
return NULL;
}

bool got_fatal_error() const { return got_fatal_error_; }
void reset_got_fatal_error() { got_fatal_error_ = false; }
Expand Down
Loading

0 comments on commit 0b5d248

Please sign in to comment.