summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/all.gyp1
-rw-r--r--ui/accessibility/DEPS3
-rw-r--r--ui/accessibility/accessibility.gyp54
-rw-r--r--ui/accessibility/ax_enums.h124
-rw-r--r--ui/accessibility/ax_export.h32
-rw-r--r--ui/accessibility/ax_node.cc34
-rw-r--r--ui/accessibility/ax_node.h59
-rw-r--r--ui/accessibility/ax_node_data.cc61
-rw-r--r--ui/accessibility/ax_node_data.h202
-rw-r--r--ui/accessibility/ax_serializable_tree.cc70
-rw-r--r--ui/accessibility/ax_serializable_tree.h26
-rw-r--r--ui/accessibility/ax_tree.cc164
-rw-r--r--ui/accessibility/ax_tree.h75
-rw-r--r--ui/accessibility/ax_tree_serializer.cc15
-rw-r--r--ui/accessibility/ax_tree_serializer.h252
-rw-r--r--ui/accessibility/ax_tree_source.h43
-rw-r--r--ui/accessibility/ax_tree_unittest.cc61
-rw-r--r--ui/accessibility/ax_tree_update.cc15
-rw-r--r--ui/accessibility/ax_tree_update.h45
19 files changed, 1336 insertions, 0 deletions
diff --git a/build/all.gyp b/build/all.gyp
index 295637feb..47091e5 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -25,6 +25,7 @@
'../third_party/libxml/libxml.gyp:*',
'../third_party/sqlite/sqlite.gyp:*',
'../third_party/zlib/zlib.gyp:*',
+ '../ui/accessibility/accessibility.gyp:*',
'../ui/snapshot/snapshot.gyp:*',
'../ui/ui.gyp:*',
'../url/url.gyp:*',
diff --git a/ui/accessibility/DEPS b/ui/accessibility/DEPS
new file mode 100644
index 0000000..b273ae3
--- /dev/null
+++ b/ui/accessibility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/gfx",
+]
diff --git a/ui/accessibility/accessibility.gyp b/ui/accessibility/accessibility.gyp
new file mode 100644
index 0000000..673657b
--- /dev/null
+++ b/ui/accessibility/accessibility.gyp
@@ -0,0 +1,54 @@
+# Copyright 2013 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'accessibility',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../gfx/gfx.gyp:gfx',
+ ],
+ 'defines': [
+ 'ACCESSIBILITY_IMPLEMENTATION',
+ ],
+ 'sources': [
+ # All .cc, .h under accessibility, except unittests
+ 'ax_enums.h',
+ 'ax_node.cc',
+ 'ax_node_data.cc',
+ 'ax_node_data.h',
+ 'ax_node.h',
+ 'ax_serializable_tree.cc',
+ 'ax_serializable_tree.h',
+ 'ax_tree.cc',
+ 'ax_tree.h',
+ 'ax_tree_serializer.cc',
+ 'ax_tree_serializer.h',
+ 'ax_tree_source.h',
+ 'ax_tree_update.cc',
+ 'ax_tree_update.h',
+ ]
+ },
+ {
+ 'target_name': 'accessibility_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../testing/gtest.gyp:gtest',
+ '../../testing/gtest.gyp:gtest_main',
+ 'accessibility',
+ ],
+ 'sources': [
+ 'ax_tree_unittest.cc',
+ ]
+ },
+ ],
+}
diff --git a/ui/accessibility/ax_enums.h b/ui/accessibility/ax_enums.h
new file mode 100644
index 0000000..7f543ed
--- /dev/null
+++ b/ui/accessibility/ax_enums.h
@@ -0,0 +1,124 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_ROLES_H_
+#define UI_ACCESSIBILITY_AX_ROLES_H_
+
+// These should be kept in sync with third_party/WebKit/public/web/WebAXEnums.h
+// until the Chromium and Blink trees are merged.
+enum AXRole {
+ AX_ROLE_ALERT_DIALOG = 1,
+ AX_ROLE_ALERT,
+ AX_ROLE_ANNOTATION,
+ AX_ROLE_APPLICATION,
+ AX_ROLE_ARTICLE,
+ AX_ROLE_BANNER,
+ AX_ROLE_BROWSER,
+ AX_ROLE_BUSY_INDICATOR,
+ AX_ROLE_BUTTON,
+ AX_ROLE_CANVAS,
+ AX_ROLE_CELL,
+ AX_ROLE_CHECK_BOX,
+ AX_ROLE_COLOR_WELL,
+ AX_ROLE_COLUMN_HEADER,
+ AX_ROLE_COLUMN,
+ AX_ROLE_COMBO_BOX,
+ AX_ROLE_COMPLEMENTARY,
+ AX_ROLE_CONTENT_INFO,
+ AX_ROLE_DEFINITION,
+ AX_ROLE_DESCRIPTION_LIST_DETAIL,
+ AX_ROLE_DESCRIPTION_LIST_TERM,
+ AX_ROLE_DIALOG,
+ AX_ROLE_DIRECTORY,
+ AX_ROLE_DISCLOSURE_TRIANGLE,
+ AX_ROLE_DIV,
+ AX_ROLE_DOCUMENT,
+ AX_ROLE_DRAWER,
+ AX_ROLE_EDITABLE_TEXT,
+ AX_ROLE_FOOTER,
+ AX_ROLE_FORM,
+ AX_ROLE_GRID,
+ AX_ROLE_GROUP,
+ AX_ROLE_GROW_AREA,
+ AX_ROLE_HEADING,
+ AX_ROLE_HELP_TAG,
+ AX_ROLE_HORIZONTAL_RULE,
+ AX_ROLE_IGNORED,
+ AX_ROLE_IMAGE_MAP_LINK,
+ AX_ROLE_IMAGE_MAP,
+ AX_ROLE_IMAGE,
+ AX_ROLE_INCREMENTOR,
+ AX_ROLE_INLINE_TEXT_BOX,
+ AX_ROLE_LABEL,
+ AX_ROLE_LEGEND,
+ AX_ROLE_LINK,
+ AX_ROLE_LIST_BOX_OPTION,
+ AX_ROLE_LIST_BOX,
+ AX_ROLE_LIST_ITEM,
+ AX_ROLE_LIST_MARKER,
+ AX_ROLE_LIST,
+ AX_ROLE_LOG,
+ AX_ROLE_MAIN,
+ AX_ROLE_MARQUEE,
+ AX_ROLE_MATH_ELEMENT,
+ AX_ROLE_MATH,
+ AX_ROLE_MATTE,
+ AX_ROLE_MENU_BAR,
+ AX_ROLE_MENU_BUTTON,
+ AX_ROLE_MENU_ITEM,
+ AX_ROLE_MENU_LIST_OPTION,
+ AX_ROLE_MENU_LIST_POPUP,
+ AX_ROLE_MENU,
+ AX_ROLE_NAVIGATION,
+ AX_ROLE_NOTE,
+ AX_ROLE_OUTLINE,
+ AX_ROLE_PARAGRAPH,
+ AX_ROLE_POP_UP_BUTTON,
+ AX_ROLE_PRESENTATIONAL,
+ AX_ROLE_PROGRESS_INDICATOR,
+ AX_ROLE_RADIO_BUTTON,
+ AX_ROLE_RADIO_GROUP,
+ AX_ROLE_REGION,
+ AX_ROLE_ROOT_WEB_AREA,
+ AX_ROLE_ROW_HEADER,
+ AX_ROLE_ROW,
+ AX_ROLE_RULER_MARKER,
+ AX_ROLE_RULER,
+ AX_ROLE_SVG_ROOT,
+ AX_ROLE_SCROLL_AREA,
+ AX_ROLE_SCROLL_BAR,
+ AX_ROLE_SEAMLESS_WEB_AREA,
+ AX_ROLE_SEARCH,
+ AX_ROLE_SHEET,
+ AX_ROLE_SLIDER,
+ AX_ROLE_SLIDER_THUMB,
+ AX_ROLE_SPIN_BUTTON_PART,
+ AX_ROLE_SPIN_BUTTON,
+ AX_ROLE_SPLIT_GROUP,
+ AX_ROLE_SPLITTER,
+ AX_ROLE_STATIC_TEXT,
+ AX_ROLE_STATUS,
+ AX_ROLE_SYSTEM_WIDE,
+ AX_ROLE_TAB_GROUP,
+ AX_ROLE_TAB_LIST,
+ AX_ROLE_TAB_PANEL,
+ AX_ROLE_TAB,
+ AX_ROLE_TABLE_HEADER_CONTAINER,
+ AX_ROLE_TABLE,
+ AX_ROLE_TEXT_AREA,
+ AX_ROLE_TEXT_FIELD,
+ AX_ROLE_TIMER,
+ AX_ROLE_TOGGLE_BUTTON,
+ AX_ROLE_TOOLBAR,
+ AX_ROLE_TREE_GRID,
+ AX_ROLE_TREE_ITEM,
+ AX_ROLE_TREE,
+ AX_ROLE_UNKNOWN,
+ AX_ROLE_USER_INTERFACE_TOOLTIP,
+ AX_ROLE_VALUE_INDICATOR,
+ AX_ROLE_WEB_AREA,
+ AX_ROLE_WINDOW
+};
+
+#endif // UI_ACCESSIBILITY_AX_ROLES_H_
diff --git a/ui/accessibility/ax_export.h b/ui/accessibility/ax_export.h
new file mode 100644
index 0000000..f437365
--- /dev/null
+++ b/ui/accessibility/ax_export.h
@@ -0,0 +1,32 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_EXPORT_H_
+#define UI_ACCESSIBILITY_AX_EXPORT_H_
+
+// Defines AX_EXPORT so that functionality implemented by the
+// ui/accessibility module can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(ACCESSIBILITY_IMPLEMENTATION)
+#define AX_EXPORT __declspec(dllexport)
+#else
+#define AX_EXPORT __declspec(dllimport)
+#endif // defined(ACCESSIBILITY_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(ACCESSIBILITY_IMPLEMENTATION)
+#define AX_EXPORT __attribute__((visibility("default")))
+#else
+#define AX_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define AX_EXPORT
+#endif
+
+#endif // UI_ACCESSIBILITY_AX_EXPORT_H_
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
new file mode 100644
index 0000000..8adb940
--- /dev/null
+++ b/ui/accessibility/ax_node.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_node.h"
+
+namespace ui {
+
+AXNode::AXNode(AXNode* parent, int32 id, int32 index_in_parent)
+ : index_in_parent_(index_in_parent),
+ parent_(parent) {
+ data_.id = id;
+}
+
+AXNode::~AXNode() {
+}
+
+void AXNode::SetData(const AXNodeData& src) {
+ data_ = src;
+}
+
+void AXNode::SetIndexInParent(int index_in_parent) {
+ index_in_parent_ = index_in_parent;
+}
+
+void AXNode::SwapChildren(std::vector<AXNode*>& children) {
+ children.swap(children_);
+}
+
+void AXNode::Destroy() {
+ delete this;
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
new file mode 100644
index 0000000..b7e3125
--- /dev/null
+++ b/ui/accessibility/ax_node.h
@@ -0,0 +1,59 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_NODE_H_
+#define UI_ACCESSIBILITY_AX_NODE_H_
+
+#include "ui/accessibility/ax_node_data.h"
+
+namespace ui {
+
+// One node in an AXTree.
+class AX_EXPORT AXNode {
+ public:
+ // The constructor requires a parent, id, and index in parent, but
+ // the data is not required. After initialization, only index_in_parent
+ // is allowed to change, the others are guaranteed to never change.
+ AXNode(AXNode* parent, int32 id, int32 index_in_parent);
+ virtual ~AXNode();
+
+ // Accessors.
+ int32 id() const { return data_.id; }
+ AXNode* parent() const { return parent_; }
+ int child_count() const { return static_cast<int>(children_.size()); }
+ const AXNodeData& data() const { return data_; }
+ const std::vector<AXNode*>& children() const { return children_; }
+
+ // Get the child at the given index.
+ AXNode* ChildAtIndex(int index) const { return children_[index]; }
+
+ // Set the node's accessibility data. This may be done during initial
+ // initialization or later when the node data changes.
+ virtual void SetData(const AXNodeData& src);
+
+ // Set the index in parent, for example if siblings were inserted or deleted.
+ void SetIndexInParent(int index_in_parent);
+
+ // Swap the internal children vector with |children|. This instance
+ // now owns all of the passed children.
+ virtual void SwapChildren(std::vector<AXNode*>& children);
+
+ // This is called when the AXTree no longer includes this node in the
+ // tree. Reference counting is used on some platforms because the
+ // operating system may hold onto a reference to an AXNode
+ // object even after we're through with it, so this may decrement the
+ // reference count and clear out the object's data.
+ virtual void Destroy();
+
+ private:
+ int index_in_parent_;
+ AXNode* parent_;
+ std::vector<AXNode*> children_;
+ AXNodeData data_;
+};
+
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_NODE_H_
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
new file mode 100644
index 0000000..1655fe8
--- /dev/null
+++ b/ui/accessibility/ax_node_data.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_node_data.h"
+
+#include <set>
+
+#include "base/containers/hash_tables.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+using base::DoubleToString;
+using base::IntToString;
+
+namespace ui {
+
+AXNodeData::AXNodeData()
+ : id(-1),
+ role(AX_ROLE_UNKNOWN),
+ state(-1) {
+}
+
+AXNodeData::~AXNodeData() {
+}
+
+void AXNodeData::AddStringAttribute(
+ StringAttribute attribute, const std::string& value) {
+ string_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AXNodeData::AddIntAttribute(
+ IntAttribute attribute, int value) {
+ int_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AXNodeData::AddFloatAttribute(
+ FloatAttribute attribute, float value) {
+ float_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AXNodeData::AddBoolAttribute(
+ BoolAttribute attribute, bool value) {
+ bool_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AXNodeData::AddIntListAttribute(
+ IntListAttribute attribute, const std::vector<int32>& value) {
+ intlist_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AXNodeData::SetName(std::string name) {
+ string_attributes.push_back(std::make_pair(ATTR_NAME, name));
+}
+
+void AXNodeData::SetValue(std::string value) {
+ string_attributes.push_back(std::make_pair(ATTR_VALUE, value));
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
new file mode 100644
index 0000000..1c5defb
--- /dev/null
+++ b/ui/accessibility/ax_node_data.h
@@ -0,0 +1,202 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_NODE_DATA_H_
+#define UI_ACCESSIBILITY_AX_NODE_DATA_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/gfx/rect.h"
+
+namespace ui {
+
+// A compact representation of the accessibility information for a
+// single web object, in a form that can be serialized and sent from
+// one process to another.
+struct AX_EXPORT AXNodeData {
+ // Additional optional attributes that can be optionally attached to
+ // a node.
+ enum StringAttribute {
+ // Document attributes.
+ ATTR_DOC_URL,
+ ATTR_DOC_TITLE,
+ ATTR_DOC_MIMETYPE,
+ ATTR_DOC_DOCTYPE,
+
+ // Attributes that could apply to any node.
+ ATTR_ACCESS_KEY,
+ ATTR_ACTION,
+ ATTR_CONTAINER_LIVE_RELEVANT,
+ ATTR_CONTAINER_LIVE_STATUS,
+ ATTR_DESCRIPTION,
+ ATTR_DISPLAY,
+ ATTR_HELP,
+ ATTR_HTML_TAG,
+ ATTR_NAME,
+ ATTR_LIVE_RELEVANT,
+ ATTR_LIVE_STATUS,
+ ATTR_ROLE,
+ ATTR_SHORTCUT,
+ ATTR_URL,
+ ATTR_VALUE,
+ };
+
+ enum IntAttribute {
+ // Scrollable container attributes.
+ ATTR_SCROLL_X,
+ ATTR_SCROLL_X_MIN,
+ ATTR_SCROLL_X_MAX,
+ ATTR_SCROLL_Y,
+ ATTR_SCROLL_Y_MIN,
+ ATTR_SCROLL_Y_MAX,
+
+ // Editable text attributes.
+ ATTR_TEXT_SEL_START,
+ ATTR_TEXT_SEL_END,
+
+ // Table attributes.
+ ATTR_TABLE_ROW_COUNT,
+ ATTR_TABLE_COLUMN_COUNT,
+ ATTR_TABLE_HEADER_ID,
+
+ // Table row attributes.
+ ATTR_TABLE_ROW_INDEX,
+ ATTR_TABLE_ROW_HEADER_ID,
+
+ // Table column attributes.
+ ATTR_TABLE_COLUMN_INDEX,
+ ATTR_TABLE_COLUMN_HEADER_ID,
+
+ // Table cell attributes.
+ ATTR_TABLE_CELL_COLUMN_INDEX,
+ ATTR_TABLE_CELL_COLUMN_SPAN,
+ ATTR_TABLE_CELL_ROW_INDEX,
+ ATTR_TABLE_CELL_ROW_SPAN,
+
+ // Tree control attributes.
+ ATTR_HIERARCHICAL_LEVEL,
+
+ // Relationships between this element and other elements.
+ ATTR_TITLE_UI_ELEMENT,
+
+ // Color value for AX_ROLE_COLOR_WELL, each component is 0..255
+ ATTR_COLOR_VALUE_RED,
+ ATTR_COLOR_VALUE_GREEN,
+ ATTR_COLOR_VALUE_BLUE,
+
+ // Inline text attributes.
+ ATTR_TEXT_DIRECTION
+ };
+
+ enum FloatAttribute {
+ // Document attributes.
+ ATTR_DOC_LOADING_PROGRESS,
+
+ // Range attributes.
+ ATTR_VALUE_FOR_RANGE,
+ ATTR_MIN_VALUE_FOR_RANGE,
+ ATTR_MAX_VALUE_FOR_RANGE,
+ };
+
+ enum BoolAttribute {
+ // Document attributes.
+ ATTR_DOC_LOADED,
+
+ // True if a checkbox or radio button is in the "mixed" state.
+ ATTR_BUTTON_MIXED,
+
+ // Live region attributes.
+ ATTR_CONTAINER_LIVE_ATOMIC,
+ ATTR_CONTAINER_LIVE_BUSY,
+ ATTR_LIVE_ATOMIC,
+ ATTR_LIVE_BUSY,
+
+ // ARIA readonly flag.
+ ATTR_ARIA_READONLY,
+
+ // Writeable attributes
+ ATTR_CAN_SET_VALUE,
+
+ // If this is set, all of the other fields in this struct should
+ // be ignored and only the locations should change.
+ ATTR_UPDATE_LOCATION_ONLY,
+
+ // Set on a canvas element if it has fallback content.
+ ATTR_CANVAS_HAS_FALLBACK,
+ };
+
+ enum IntListAttribute {
+ // Ids of nodes that are children of this node logically, but are
+ // not children of this node in the tree structure. As an example,
+ // a table cell is a child of a row, and an 'indirect' child of a
+ // column.
+ ATTR_INDIRECT_CHILD_IDS,
+
+ // Character indices where line breaks occur.
+ ATTR_LINE_BREAKS,
+
+ // For a table, the cell ids in row-major order, with duplicate entries
+ // when there's a rowspan or colspan, and with -1 for missing cells.
+ // There are always exactly rows * columns entries.
+ ATTR_CELL_IDS,
+
+ // For a table, the unique cell ids in row-major order of their first
+ // occurrence.
+ ATTR_UNIQUE_CELL_IDS,
+
+ // For inline text. This is the pixel position of the end of this
+ // character within the bounding rectangle of this object, in the
+ // direction given by ATTR_TEXT_DIRECTION. For example, for left-to-right
+ // text, the first offset is the right coordinate of the first character
+ // within the object's bounds, the second offset is the right coordinate
+ // of the second character, and so on.
+ ATTR_CHARACTER_OFFSETS,
+
+ // For inline text. These int lists must be the same size; they represent
+ // the start and end character index of each word within this text.
+ ATTR_WORD_STARTS,
+ ATTR_WORD_ENDS,
+ };
+
+ AXNodeData();
+ virtual ~AXNodeData();
+
+ void AddStringAttribute(StringAttribute attribute,
+ const std::string& value);
+ void AddIntAttribute(IntAttribute attribute, int value);
+ void AddFloatAttribute(FloatAttribute attribute, float value);
+ void AddBoolAttribute(BoolAttribute attribute, bool value);
+ void AddIntListAttribute(IntListAttribute attribute,
+ const std::vector<int32>& value);
+
+ // Convenience functions, mainly for writing unit tests.
+ // Equivalent to AddStringAttribute(ATTR_NAME, name).
+ void SetName(std::string name);
+ // Equivalent to AddStringAttribute(ATTR_VALUE, value).
+ void SetValue(std::string value);
+
+ // This is a simple serializable struct. All member variables should be
+ // public and copyable.
+ int32 id;
+ AXRole role;
+ uint32 state;
+ gfx::Rect location;
+ std::vector<std::pair<StringAttribute, std::string> > string_attributes;
+ std::vector<std::pair<IntAttribute, int32> > int_attributes;
+ std::vector<std::pair<FloatAttribute, float> > float_attributes;
+ std::vector<std::pair<BoolAttribute, bool> > bool_attributes;
+ std::vector<std::pair<IntListAttribute, std::vector<int32> > >
+ intlist_attributes;
+ std::vector<std::pair<std::string, std::string> > html_attributes;
+ std::vector<int32> child_ids;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_NODE_DATA_H_
diff --git a/ui/accessibility/ax_serializable_tree.cc b/ui/accessibility/ax_serializable_tree.cc
new file mode 100644
index 0000000..12bc595
--- /dev/null
+++ b/ui/accessibility/ax_serializable_tree.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_serializable_tree.h"
+
+#include "ui/accessibility/ax_node.h"
+
+namespace ui {
+
+// This class is an implementation of the AXTreeSource interface with
+// AXNode as the node type, that just delegates to an AXTree. The purpose
+// of this is so that AXTreeSerializer only needs to work with the
+// AXTreeSource abstraction and doesn't need to actually know about
+// AXTree directly. Another AXTreeSource is used to abstract the Blink
+// accessibility tree.
+class AX_EXPORT AXTreeSourceAdapter : public AXTreeSource<AXNode> {
+ public:
+ AXTreeSourceAdapter(AXTree* tree) : tree_(tree) {}
+ virtual ~AXTreeSourceAdapter() {}
+
+ // AXTreeSource implementation.
+ virtual AXNode* GetFromId(int32 id) const OVERRIDE {
+ return tree_->GetFromId(id);
+ }
+
+ virtual int32 GetId(const AXNode* node) const OVERRIDE {
+ return node->id();
+ }
+
+ virtual int GetChildCount(const AXNode* node) const OVERRIDE {
+ return node->child_count();
+ }
+
+ virtual AXNode* GetChildAtIndex(const AXNode* node, int index)
+ const OVERRIDE {
+ return node->ChildAtIndex(index);
+ }
+
+ virtual int32 GetParentId(const AXNode* node) const OVERRIDE {
+ if (node->parent())
+ return node->parent()->id();
+ else
+ return 0;
+ }
+
+ virtual void SerializeNode(
+ const AXNode* node, AXNodeData* out_data) const OVERRIDE {
+ *out_data = node->data();
+ }
+
+ private:
+ AXTree* tree_;
+};
+
+AXSerializableTree::AXSerializableTree()
+ : AXTree() {}
+
+AXSerializableTree::AXSerializableTree(const AXTreeUpdate& initial_state)
+ : AXTree(initial_state) {
+}
+
+AXSerializableTree::~AXSerializableTree() {
+}
+
+AXTreeSource<AXNode>* AXSerializableTree::CreateTreeSource() {
+ return new AXTreeSourceAdapter(this);
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_serializable_tree.h b/ui/accessibility/ax_serializable_tree.h
new file mode 100644
index 0000000..c070565
--- /dev/null
+++ b/ui/accessibility/ax_serializable_tree.h
@@ -0,0 +1,26 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_SERIALIZABLE_TREE_H_
+#define UI_ACCESSIBILITY_AX_SERIALIZABLE_TREE_H_
+
+#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_source.h"
+
+namespace ui {
+
+class AX_EXPORT AXSerializableTree : public AXTree {
+ public:
+ AXSerializableTree();
+ explicit AXSerializableTree(const AXTreeUpdate& initial_state);
+ virtual ~AXSerializableTree();
+
+ // Create a TreeSource adapter for this tree. The client gets ownership
+ // of the return value and should delete it when done.
+ virtual AXTreeSource<AXNode>* CreateTreeSource();
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_H_
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
new file mode 100644
index 0000000..b7d6f8a
--- /dev/null
+++ b/ui/accessibility/ax_tree.cc
@@ -0,0 +1,164 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_tree.h"
+
+#include <set>
+
+#include "ui/accessibility/ax_node.h"
+
+namespace ui {
+
+AXTree::AXTree()
+ : root_(NULL) {
+ AXNodeData root;
+ root.id = 0;
+ root.role = AX_ROLE_ROOT_WEB_AREA;
+
+ AXTreeUpdate initial_state;
+ initial_state.nodes.push_back(root);
+ Unserialize(initial_state);
+}
+
+AXTree::AXTree(const AXTreeUpdate& initial_state)
+ : root_(NULL) {
+ Unserialize(initial_state);
+}
+
+AXTree::~AXTree() {
+ if (root_)
+ DestroyNodeAndSubtree(root_);
+}
+
+AXNode* AXTree::GetRoot() const {
+ return root_;
+}
+
+AXNode* AXTree::GetFromId(int32 id) const {
+ base::hash_map<int32, AXNode*>::const_iterator iter = id_map_.find(id);
+ return iter != id_map_.end() ? (iter->second) : NULL;
+}
+
+bool AXTree::Unserialize(const AXTreeUpdate& update) {
+ for (size_t i = 0; i < update.nodes.size(); ++i) {
+ if (!UpdateNode(update.nodes[i]))
+ return false;
+ }
+
+ return true;
+}
+
+AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) {
+ return new AXNode(parent, id, index_in_parent);
+}
+
+bool AXTree::UpdateNode(const AXNodeData& src) {
+ // This method updates one node in the tree based on serialized data
+ // received in an AXTreeUpdate. See AXTreeUpdate for pre and post
+ // conditions.
+
+ // Look up the node by id. If it's not found, then either the root
+ // of the tree is being swapped, or we're out of sync with the source
+ // and this is a serious error.
+ AXNode* node = static_cast<AXNode*>(GetFromId(src.id));
+ if (!node) {
+ if (src.role != AX_ROLE_ROOT_WEB_AREA)
+ return false;
+ node = CreateAndInitializeNode(NULL, src.id, 0);
+ }
+
+ // Set the node's data.
+ node->SetData(src);
+
+ // First, delete nodes that used to be children of this node but aren't
+ // anymore.
+ if (!DeleteOldChildren(node, src.child_ids))
+ return false;
+
+ // Now build a new children vector, reusing nodes when possible,
+ // and swap it in.
+ std::vector<AXNode*> new_children;
+ bool success = CreateNewChildVector(node, src.child_ids, &new_children);
+ node->SwapChildren(new_children);
+
+ // Update the root of the tree if needed.
+ if (src.role == AX_ROLE_ROOT_WEB_AREA &&
+ (!root_ || root_->id() != src.id)) {
+ if (root_)
+ DestroyNodeAndSubtree(root_);
+ root_ = node;
+ OnRootChanged();
+ }
+
+ return success;
+}
+
+void AXTree::OnRootChanged() {
+}
+
+AXNode* AXTree::CreateAndInitializeNode(
+ AXNode* parent, int32 id, int32 index_in_parent) {
+ AXNode* node = CreateNode(parent, id, index_in_parent);
+ id_map_[node->id()] = node;
+ return node;
+}
+
+void AXTree::DestroyNodeAndSubtree(AXNode* node) {
+ id_map_.erase(node->id());
+ for (int i = 0; i < node->child_count(); ++i) {
+ AXNode* child = static_cast<AXNode*>(node->ChildAtIndex(i));
+ child->Destroy();
+ }
+ node->Destroy();
+}
+
+bool AXTree::DeleteOldChildren(AXNode* node,
+ const std::vector<int32> new_child_ids) {
+ // Create a set of child ids in |src| for fast lookup, and return false
+ // if a duplicate is found;
+ std::set<int32> new_child_id_set;
+ for (size_t i = 0; i < new_child_ids.size(); ++i) {
+ if (new_child_id_set.find(new_child_ids[i]) != new_child_id_set.end())
+ return false;
+ new_child_id_set.insert(new_child_ids[i]);
+ }
+
+ // Delete the old children.
+ const std::vector<AXNode*>& old_children = node->children();
+ for (size_t i = 0; i < old_children.size(); ++i) {
+ int old_id = old_children[i]->id();
+ if (new_child_id_set.find(old_id) == new_child_id_set.end())
+ DestroyNodeAndSubtree(old_children[i]);
+ }
+
+ return true;
+}
+
+bool AXTree::CreateNewChildVector(AXNode* node,
+ const std::vector<int32> new_child_ids,
+ std::vector<AXNode*>* new_children) {
+ bool success = true;
+ for (size_t i = 0; i < new_child_ids.size(); ++i) {
+ int32 child_id = new_child_ids[i];
+ int32 index_in_parent = static_cast<int32>(i);
+ AXNode* child = static_cast<AXNode*>(GetFromId(child_id));
+ if (child) {
+ if (child->parent() != node) {
+ // This is a serious error - nodes should never be reparented.
+ // If this case occurs, continue so this node isn't left in an
+ // inconsistent state, but return failure at the end.
+ success = false;
+ continue;
+ }
+ child->SetIndexInParent(index_in_parent);
+ } else {
+ child = CreateAndInitializeNode(node, child_id, index_in_parent);
+ }
+ new_children->push_back(child);
+ }
+
+ return success;
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h
new file mode 100644
index 0000000..84108e0
--- /dev/null
+++ b/ui/accessibility/ax_tree.h
@@ -0,0 +1,75 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_TREE_H_
+#define UI_ACCESSIBILITY_AX_TREE_H_
+
+#include "base/containers/hash_tables.h"
+
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_update.h"
+
+namespace ui {
+
+class AXNode;
+
+// AXTree is a live, managed tree of AXNode objects that can receive
+// updates from another AXTreeSource via AXTreeUpdates, and it can be
+// used as a source for sending updates to another client tree.
+// It's designed to be subclassed to implement support for native
+// accessibility APIs on a specific platform.
+class AX_EXPORT AXTree {
+ public:
+ AXTree();
+ explicit AXTree(const AXTreeUpdate& initial_state);
+ virtual ~AXTree();
+
+ virtual AXNode* GetRoot() const;
+ virtual AXNode* GetFromId(int32 id) const;
+
+ virtual bool Unserialize(const AXTreeUpdate& update);
+
+ protected:
+ // Subclasses can override this to use a subclass of AXNode.
+ virtual AXNode* CreateNode(AXNode* parent, int32 id, int32 index_in_parent);
+
+ // This is called from within Unserialize(), it returns true on success.
+ // Subclasses can override this to do additional processing.
+ virtual bool UpdateNode(const AXNodeData& src);
+
+ // Subclasses can override this to do special behavior when the root changes.
+ virtual void OnRootChanged();
+
+ private:
+ // Convenience function to create a node and call Initialize on it.
+ AXNode* CreateAndInitializeNode(
+ AXNode* parent, int32 id, int32 index_in_parent);
+
+ // Call Destroy() on |node|, and delete it from the id map, and then
+ // call recursively on all nodes in its subtree.
+ void DestroyNodeAndSubtree(AXNode* node);
+
+ // Iterate over the children of |node| and for each child, destroy the
+ // child and its subtree if its id is not in |new_child_ids|. Returns
+ // true on success, false on fatal error.
+ bool DeleteOldChildren(AXNode* node,
+ const std::vector<int32> new_child_ids);
+
+ // Iterate over |new_child_ids| and populate |new_children| with
+ // pointers to child nodes, reusing existing nodes already in the tree
+ // if they exist, and creating otherwise. Reparenting is disallowed, so
+ // if the id already exists as the child of another node, that's an
+ // error. Returns true on success, false on fatal error.
+ bool CreateNewChildVector(AXNode* node,
+ const std::vector<int32> new_child_ids,
+ std::vector<AXNode*>* new_children);
+
+ AXNode* root_;
+ base::hash_map<int32, AXNode*> id_map_;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_H_
diff --git a/ui/accessibility/ax_tree_serializer.cc b/ui/accessibility/ax_tree_serializer.cc
new file mode 100644
index 0000000..eff444c
--- /dev/null
+++ b/ui/accessibility/ax_tree_serializer.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_tree_serializer.h"
+
+namespace ui {
+
+ClientTreeNode::ClientTreeNode() {
+}
+
+ClientTreeNode::~ClientTreeNode() {
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
new file mode 100644
index 0000000..cbc01c0
--- /dev/null
+++ b/ui/accessibility/ax_tree_serializer.h
@@ -0,0 +1,252 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
+#define UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
+
+#include <set>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "ui/accessibility/ax_tree_source.h"
+#include "ui/accessibility/ax_tree_update.h"
+
+namespace ui {
+
+struct ClientTreeNode;
+
+// AXTreeSerializer is a helper class that serializes incremental
+// updates to an AXTreeSource as a vector of AXNodeData structs.
+// These structs can be unserialized by an AXTree. An AXTreeSerializer
+// keeps track of the tree of node ids that its client is aware of, so
+// it will automatically include, as part of any update, any additional nodes
+// that the client is not aware of yet.
+//
+// When the AXTreeSource changes, call SerializeChanges to serialize the
+// changes to the tree as an AXTreeUpdate. If a single node has changed,
+// pass that node to SerializeChanges. If a node has been added or removed,
+// pass the parent of that node to SerializeChanges and it will automatically
+// handle changes to its set of children.
+//
+// TODO(dmazzoni): add sample usage code.
+template<class AXSourceNode>
+class AXTreeSerializer {
+ public:
+ explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
+
+ // Throw out the internal state that keeps track of the nodes the client
+ // knows about. This has the effect that the next update will send the
+ // entire tree over because it assumes the client knows nothing.
+ void Reset();
+
+ // Serialize all changes to |node| and append them to |out_update|.
+ void SerializeChanges(const AXSourceNode* node,
+ AXTreeUpdate* out_update);
+
+ private:
+ // Delete the given client tree node and recursively delete all of its
+ // descendants.
+ void DeleteClientSubtree(ClientTreeNode* client_node);
+
+ void SerializeChangedNodes(const AXSourceNode* node,
+ std::set<int>* ids_serialized,
+ AXTreeUpdate* out_update);
+
+ // The tree source.
+ AXTreeSource<AXSourceNode>* tree_;
+
+ // Our representation of the client tree.
+ ClientTreeNode* client_root_;
+
+ // A map from IDs to nodes in the client tree.
+ base::hash_map<int32, ClientTreeNode*> client_id_map_;
+};
+
+// In order to keep track of what nodes the client knows about, we keep a
+// representation of the client tree - just IDs and parent/child
+// relationships.
+struct AX_EXPORT ClientTreeNode {
+ ClientTreeNode();
+ virtual ~ClientTreeNode();
+ int32 id;
+ ClientTreeNode* parent;
+ std::vector<ClientTreeNode*> children;
+};
+
+template<class AXSourceNode>
+AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
+ AXTreeSource<AXSourceNode>* tree)
+ : tree_(tree),
+ client_root_(NULL) {
+}
+
+template<class AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::Reset() {
+ if (client_root_) {
+ DeleteClientSubtree(client_root_);
+ client_root_ = NULL;
+ }
+}
+
+template<class AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::SerializeChanges(
+ const AXSourceNode* node,
+ AXTreeUpdate* out_update) {
+ std::set<int> ids_serialized;
+ SerializeChangedNodes(node, &ids_serialized, out_update);
+}
+
+template<class AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
+ ClientTreeNode* client_node) {
+ for (size_t i = 0; i < client_node->children.size(); ++i) {
+ client_id_map_.erase(client_node->children[i]->id);
+ DeleteClientSubtree(client_node->children[i]);
+ }
+ client_node->children.clear();
+}
+
+template<class AXSourceNode>
+void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
+ const AXSourceNode* node,
+ std::set<int>* ids_serialized,
+ AXTreeUpdate* out_update) {
+ int id = tree_->GetId(node);
+ if (ids_serialized->find(id) != ids_serialized->end())
+ return;
+ ids_serialized->insert(id);
+
+ // This method has three responsibilities:
+ // 1. Serialize |node| into an AXNodeData, and append it to
+ // the AXTreeUpdate to be sent to the client.
+ // 2. Determine if |node| has any new children that the client doesn't
+ // know about yet, and call SerializeChangedNodes recursively on those.
+ // 3. Update our internal data structure that keeps track of what nodes
+ // the client knows about.
+
+ // First, find the ClientTreeNode for this id in our data structure where
+ // we keep track of what accessibility objects the client already knows
+ // about. If we don't find it, then this must be the new root of the
+ // accessibility tree.
+ //
+ // TODO(dmazzoni): handle the case where the root changes.
+ ClientTreeNode* client_node = NULL;
+ base::hash_map<int32, ClientTreeNode*>::iterator iter =
+ client_id_map_.find(id);
+ if (iter != client_id_map_.end()) {
+ client_node = iter->second;
+ } else {
+ if (client_root_) {
+ client_id_map_.erase(client_root_->id);
+ DeleteClientSubtree(client_root_);
+ }
+ client_root_ = new ClientTreeNode();
+ client_node = client_root_;
+ client_node->id = id;
+ client_node->parent = NULL;
+ client_id_map_[client_node->id] = client_node;
+ }
+
+ // Iterate over the ids of the children of |node|.
+ // Create a set of the child ids so we can quickly look
+ // up which children are new and which ones were there before.
+ // Also catch the case where a child is already in the client tree
+ // data structure with a different parent, and make sure the old parent
+ // clears this node first.
+ base::hash_set<int32> new_child_ids;
+ int child_count = tree_->GetChildCount(node);
+ for (int i = 0; i < child_count; ++i) {
+ AXSourceNode* child = tree_->GetChildAtIndex(node, i);
+ int new_child_id = tree_->GetId(child);
+ new_child_ids.insert(new_child_id);
+
+ ClientTreeNode* client_child = client_id_map_[new_child_id];
+ if (client_child && client_child->parent != client_node) {
+ // The child is being reparented. Find the source tree node
+ // corresponding to the old parent, or the closest ancestor
+ // still in the tree.
+ ClientTreeNode* client_parent = client_child->parent;
+ AXSourceNode* parent = NULL;
+ while (client_parent) {
+ parent = tree_->GetFromId(client_parent->id);
+ if (parent)
+ break;
+ client_parent = client_parent->parent;
+ }
+ CHECK(parent);
+
+ // Call SerializeChangedNodes recursively on the old parent,
+ // so that the update that clears |child| from its old parent
+ // occurs stricly before the update that adds |child| to its
+ // new parent.
+ SerializeChangedNodes(parent, ids_serialized, out_update);
+ }
+ }
+
+ // Go through the old children and delete subtrees for child
+ // ids that are no longer present, and create a map from
+ // id to ClientTreeNode for the rest. It's important to delete
+ // first in a separate pass so that nodes that are reparented
+ // don't end up children of two different parents in the middle
+ // of an update, which can lead to a double-free.
+ base::hash_map<int32, ClientTreeNode*> client_child_id_map;
+ std::vector<ClientTreeNode*> old_children;
+ old_children.swap(client_node->children);
+ for (size_t i = 0; i < old_children.size(); ++i) {
+ ClientTreeNode* old_child = old_children[i];
+ int old_child_id = old_child->id;
+ if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
+ client_id_map_.erase(old_child_id);
+ DeleteClientSubtree(old_child);
+ } else {
+ client_child_id_map[old_child_id] = old_child;
+ }
+ }
+
+ // Serialize this node. This fills in all of the fields in
+ // AXNodeData except child_ids, which we handle below.
+ out_update->nodes.push_back(AXNodeData());
+ AXNodeData* serialized_node = &out_update->nodes.back();
+ tree_->SerializeNode(node, serialized_node);
+ if (serialized_node->id == client_root_->id)
+ serialized_node->role = AX_ROLE_ROOT_WEB_AREA;
+ serialized_node->child_ids.clear();
+
+ // Iterate over the children, make note of the ones that are new
+ // and need to be serialized, and update the ClientTreeNode
+ // data structure to reflect the new tree.
+ std::vector<AXSourceNode*> children_to_serialize;
+ client_node->children.reserve(child_count);
+ for (int i = 0; i < child_count; ++i) {
+ AXSourceNode* child = tree_->GetChildAtIndex(node, i);
+ int child_id = tree_->GetId(child);
+
+ // No need to do anything more with children that aren't new;
+ // the client will reuse its existing object.
+ if (new_child_ids.find(child_id) == new_child_ids.end())
+ continue;
+
+ new_child_ids.erase(child_id);
+ serialized_node->child_ids.push_back(child_id);
+ if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
+ ClientTreeNode* reused_child = client_child_id_map[child_id];
+ client_node->children.push_back(reused_child);
+ } else {
+ ClientTreeNode* new_child = new ClientTreeNode();
+ new_child->id = child_id;
+ new_child->parent = client_node;
+ client_node->children.push_back(new_child);
+ client_id_map_[child_id] = new_child;
+ children_to_serialize.push_back(child);
+ }
+ }
+
+ // Serialize all of the new children, recursively.
+ for (size_t i = 0; i < children_to_serialize.size(); ++i)
+ SerializeChangedNodes(children_to_serialize[i], ids_serialized, out_update);
+}
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
diff --git a/ui/accessibility/ax_tree_source.h b/ui/accessibility/ax_tree_source.h
new file mode 100644
index 0000000..383e70e
--- /dev/null
+++ b/ui/accessibility/ax_tree_source.h
@@ -0,0 +1,43 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_TREE_SOURCE_H_
+#define UI_ACCESSIBILITY_AX_TREE_SOURCE_H_
+
+#include "ui/accessibility/ax_node_data.h"
+
+namespace ui {
+
+// An AXTreeSource is an abstract interface for a serializable
+// accessibility tree. The tree may be in some other format or
+// may be computed dynamically, but maintains the properties that
+// it's a strict tree, it has a unique id for each node, and all
+// of the accessibility information about a node can be serialized
+// as an AXNodeData. This is the primary interface to use when
+// an accessibility tree will be sent over an IPC before being
+// consumed.
+template<class AXNodeSource>
+class AX_EXPORT AXTreeSource {
+ public:
+ virtual ~AXTreeSource() {}
+ virtual AXNodeSource* GetFromId(int32 id) const = 0;
+ virtual int32 GetId(const AXNodeSource* node) const = 0;
+ virtual int GetChildCount(const AXNodeSource* node) const = 0;
+ virtual AXNodeSource* GetChildAtIndex(const AXNodeSource* node, int index)
+ const = 0;
+
+ // Returns the id of this node's parent, or 0 if it doesn't have a parent.
+ virtual int32 GetParentId(const AXNodeSource* node) const = 0;
+
+ // Serialize one node in the tree.
+ virtual void SerializeNode(
+ const AXNodeSource* node, AXNodeData* out_data) const = 0;
+
+ protected:
+ AXTreeSource() {}
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_SOURCE_H_
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
new file mode 100644
index 0000000..3f11899
--- /dev/null
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 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.
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_serializable_tree.h"
+#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+
+namespace ui {
+
+TEST(AXTreeTest, TestSerialize) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = AX_ROLE_ROOT_WEB_AREA;
+ root.child_ids.push_back(2);
+ root.child_ids.push_back(3);
+
+ AXNodeData button;
+ button.id = 2;
+ button.role = AX_ROLE_BUTTON;
+ button.state = 0;
+
+ AXNodeData checkbox;
+ checkbox.id = 3;
+ checkbox.role = AX_ROLE_CHECK_BOX;
+
+ AXTreeUpdate initial_state;
+ initial_state.nodes.push_back(root);
+ initial_state.nodes.push_back(button);
+ initial_state.nodes.push_back(checkbox);
+ AXSerializableTree src_tree(initial_state);
+
+ scoped_ptr<AXTreeSource<AXNode> > tree_source(
+ src_tree.CreateTreeSource());
+ AXTreeSerializer<AXNode> serializer(tree_source.get());
+ AXTreeUpdate update;
+ serializer.SerializeChanges(src_tree.GetRoot(), &update);
+
+ AXTree dst_tree;
+ ASSERT_TRUE(dst_tree.Unserialize(update));
+
+ AXNode* root_node = dst_tree.GetRoot();
+ ASSERT_TRUE(root_node != NULL);
+ EXPECT_EQ(root.id, root_node->id());
+ EXPECT_EQ(root.role, root_node->data().role);
+
+ ASSERT_EQ(2, root_node->child_count());
+
+ AXNode* button_node = root_node->ChildAtIndex(0);
+ EXPECT_EQ(button.id, button_node->id());
+ EXPECT_EQ(button.role, button_node->data().role);
+
+ AXNode* checkbox_node = root_node->ChildAtIndex(1);
+ EXPECT_EQ(checkbox.id, checkbox_node->id());
+ EXPECT_EQ(checkbox.role, checkbox_node->data().role);
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_tree_update.cc b/ui/accessibility/ax_tree_update.cc
new file mode 100644
index 0000000..083c577
--- /dev/null
+++ b/ui/accessibility/ax_tree_update.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+#include "ui/accessibility/ax_tree_update.h"
+
+namespace ui {
+
+AXTreeUpdate::AXTreeUpdate() {
+}
+
+AXTreeUpdate::~AXTreeUpdate() {
+}
+
+} // namespace ui
diff --git a/ui/accessibility/ax_tree_update.h b/ui/accessibility/ax_tree_update.h
new file mode 100644
index 0000000..0599821
--- /dev/null
+++ b/ui/accessibility/ax_tree_update.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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 UI_ACCESSIBILITY_AX_TREE_UPDATE_H_
+#define UI_ACCESSIBILITY_AX_TREE_UPDATE_H_
+
+#include <vector>
+
+#include "ui/accessibility/ax_node_data.h"
+
+namespace ui {
+
+// An AXTreeUpdate is a serialized representation of an atomic change
+// to an AXTree. The sender and receiver must be in sync; the update
+// is only meant to bring the tree from a specific previous state into
+// its next state. Trying to apply it to the wrong tree should immediately
+// die with a fatal assertion. An AXTreeUpdate is just an ordered vector
+// of AXNodeData structures to be applied to the tree in order.
+//
+// Suppose that the next AXNodeData to be applied is |node|. The following
+// invariants must hold:
+// 1. Either |node.id| is already in the tree, or else |node| is the new
+// root of the tree and |node.role| == WebAXRoleRootWebArea.
+// 2. Every child id in |node.child_ids| must either be already a child
+// of this node, or a new id not previously in the tree. It is not
+// allowed to "reparent" a child to this node without first removing
+// that child from its previous parent.
+// 3. When a new id appears in |node.child_ids|, the tree should create a
+// new uninitialized placeholder node for it immediately. That
+// placeholder must be updated within the same AXTreeUpdate, otherwise
+// it's a fatal error. This guarantees the tree is always complete
+// before or after an AXTreeUpdate.
+struct AX_EXPORT AXTreeUpdate {
+ AXTreeUpdate();
+ ~AXTreeUpdate();
+
+ std::vector<AXNodeData> nodes;
+
+ // TODO(dmazzoni): location changes
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_TREE_UPDATE_H_