diff options
-rw-r--r-- | build/all.gyp | 1 | ||||
-rw-r--r-- | ui/accessibility/DEPS | 3 | ||||
-rw-r--r-- | ui/accessibility/accessibility.gyp | 54 | ||||
-rw-r--r-- | ui/accessibility/ax_enums.h | 124 | ||||
-rw-r--r-- | ui/accessibility/ax_export.h | 32 | ||||
-rw-r--r-- | ui/accessibility/ax_node.cc | 34 | ||||
-rw-r--r-- | ui/accessibility/ax_node.h | 59 | ||||
-rw-r--r-- | ui/accessibility/ax_node_data.cc | 61 | ||||
-rw-r--r-- | ui/accessibility/ax_node_data.h | 202 | ||||
-rw-r--r-- | ui/accessibility/ax_serializable_tree.cc | 70 | ||||
-rw-r--r-- | ui/accessibility/ax_serializable_tree.h | 26 | ||||
-rw-r--r-- | ui/accessibility/ax_tree.cc | 164 | ||||
-rw-r--r-- | ui/accessibility/ax_tree.h | 75 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_serializer.cc | 15 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_serializer.h | 252 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_source.h | 43 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_unittest.cc | 61 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_update.cc | 15 | ||||
-rw-r--r-- | ui/accessibility/ax_tree_update.h | 45 |
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_ |