1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef UI_ACCESSIBILITY_AX_NODE_H_ 6 #define UI_ACCESSIBILITY_AX_NODE_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 #include <ostream> 12 #include <string> 13 #include <vector> 14 15 #include "base/optional.h" 16 #include "build/build_config.h" 17 #include "ui/accessibility/ax_export.h" 18 #include "ui/accessibility/ax_node_data.h" 19 #include "ui/accessibility/ax_tree_id.h" 20 21 namespace ui { 22 23 class AXTableInfo; 24 struct AXLanguageInfo; 25 26 // One node in an AXTree. 27 class AX_EXPORT AXNode final { 28 public: 29 // Defines the type used for AXNode IDs. 30 using AXID = int32_t; 31 32 // If a node is not yet or no longer valid, its ID should have a value of 33 // kInvalidAXID. 34 static constexpr AXID kInvalidAXID = 0; 35 36 // Interface to the tree class that owns an AXNode. We use this instead 37 // of letting AXNode have a pointer to its AXTree directly so that we're 38 // forced to think twice before calling an AXTree interface that might not 39 // be necessary. 40 class OwnerTree { 41 public: 42 struct Selection { 43 bool is_backward; 44 AXID anchor_object_id; 45 int anchor_offset; 46 ax::mojom::TextAffinity anchor_affinity; 47 AXID focus_object_id; 48 int focus_offset; 49 ax::mojom::TextAffinity focus_affinity; 50 }; 51 52 // See AXTree::GetAXTreeID. 53 virtual AXTreeID GetAXTreeID() const = 0; 54 // See AXTree::GetTableInfo. 55 virtual AXTableInfo* GetTableInfo(const AXNode* table_node) const = 0; 56 // See AXTree::GetFromId. 57 virtual AXNode* GetFromId(int32_t id) const = 0; 58 59 virtual int32_t GetPosInSet(const AXNode& node, 60 const AXNode* ordered_set) = 0; 61 virtual int32_t GetSetSize(const AXNode& node, 62 const AXNode* ordered_set) = 0; 63 virtual Selection GetUnignoredSelection() const = 0; 64 virtual bool GetTreeUpdateInProgressState() const = 0; 65 virtual bool HasPaginationSupport() const = 0; 66 }; 67 68 template <typename NodeType, 69 NodeType* (NodeType::*NextSibling)() const, 70 NodeType* (NodeType::*PreviousSibling)() const, 71 NodeType* (NodeType::*LastChild)() const> 72 class ChildIteratorBase { 73 public: 74 ChildIteratorBase(const NodeType* parent, NodeType* child); 75 ChildIteratorBase(const ChildIteratorBase& it); ~ChildIteratorBase()76 ~ChildIteratorBase() {} 77 bool operator==(const ChildIteratorBase& rhs) const; 78 bool operator!=(const ChildIteratorBase& rhs) const; 79 ChildIteratorBase& operator++(); 80 ChildIteratorBase& operator--(); 81 NodeType* get() const; 82 NodeType& operator*() const; 83 NodeType* operator->() const; 84 85 protected: 86 const NodeType* parent_; 87 NodeType* child_; 88 }; 89 90 // The constructor requires a parent, id, and index in parent, but 91 // the data is not required. After initialization, only index_in_parent 92 // and unignored_index_in_parent is allowed to change, the others are 93 // guaranteed to never change. 94 AXNode(OwnerTree* tree, 95 AXNode* parent, 96 int32_t id, 97 size_t index_in_parent, 98 size_t unignored_index_in_parent = 0); 99 virtual ~AXNode(); 100 101 // Accessors. tree()102 OwnerTree* tree() const { return tree_; } id()103 int32_t id() const { return data_.id; } parent()104 AXNode* parent() const { return parent_; } data()105 const AXNodeData& data() const { return data_; } children()106 const std::vector<AXNode*>& children() const { return children_; } index_in_parent()107 size_t index_in_parent() const { return index_in_parent_; } 108 109 // Returns ownership of |data_| to the caller; effectively clearing |data_|. 110 AXNodeData&& TakeData(); 111 112 // Walking the tree skipping ignored nodes. 113 size_t GetUnignoredChildCount() const; 114 AXNode* GetUnignoredChildAtIndex(size_t index) const; 115 AXNode* GetUnignoredParent() const; 116 size_t GetUnignoredIndexInParent() const; 117 size_t GetIndexInParent() const; 118 AXNode* GetFirstUnignoredChild() const; 119 AXNode* GetLastUnignoredChild() const; 120 AXNode* GetDeepestFirstUnignoredChild() const; 121 AXNode* GetDeepestLastUnignoredChild() const; 122 AXNode* GetNextUnignoredSibling() const; 123 AXNode* GetPreviousUnignoredSibling() const; 124 AXNode* GetNextUnignoredInTreeOrder() const; 125 AXNode* GetPreviousUnignoredInTreeOrder() const; 126 127 using UnignoredChildIterator = 128 ChildIteratorBase<AXNode, 129 &AXNode::GetNextUnignoredSibling, 130 &AXNode::GetPreviousUnignoredSibling, 131 &AXNode::GetLastUnignoredChild>; 132 UnignoredChildIterator UnignoredChildrenBegin() const; 133 UnignoredChildIterator UnignoredChildrenEnd() const; 134 135 // Returns true if the node has any of the text related roles. 136 bool IsText() const; 137 138 // Returns true if the node has any line break related roles or is the child a 139 // node with line break related roles. 140 bool IsLineBreak() const; 141 142 // Set the node's accessibility data. This may be done during initialization 143 // or later when the node data changes. 144 void SetData(const AXNodeData& src); 145 146 // Update this node's location. This is separate from |SetData| just because 147 // changing only the location is common and should be more efficient than 148 // re-copying all of the data. 149 // 150 // The node's location is stored as a relative bounding box, the ID of 151 // the element it's relative to, and an optional transformation matrix. 152 // See ax_node_data.h for details. 153 void SetLocation(int32_t offset_container_id, 154 const gfx::RectF& location, 155 gfx::Transform* transform); 156 157 // Set the index in parent, for example if siblings were inserted or deleted. 158 void SetIndexInParent(size_t index_in_parent); 159 160 // Update the unignored index in parent for unignored children. 161 void UpdateUnignoredCachedValues(); 162 163 // Swap the internal children vector with |children|. This instance 164 // now owns all of the passed children. 165 void SwapChildren(std::vector<AXNode*>* children); 166 167 // This is called when the AXTree no longer includes this node in the 168 // tree. Reference counting is used on some platforms because the 169 // operating system may hold onto a reference to an AXNode 170 // object even after we're through with it, so this may decrement the 171 // reference count and clear out the object's data. 172 void Destroy(); 173 174 // Return true if this object is equal to or a descendant of |ancestor|. 175 bool IsDescendantOf(const AXNode* ancestor) const; 176 177 // Gets the text offsets where new lines start either from the node's data or 178 // by computing them and caching the result. 179 std::vector<int> GetOrComputeLineStartOffsets(); 180 181 // Accessing accessibility attributes. 182 // See |AXNodeData| for more information. 183 HasBoolAttribute(ax::mojom::BoolAttribute attribute)184 bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const { 185 return data().HasBoolAttribute(attribute); 186 } GetBoolAttribute(ax::mojom::BoolAttribute attribute)187 bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const { 188 return data().GetBoolAttribute(attribute); 189 } GetBoolAttribute(ax::mojom::BoolAttribute attribute,bool * value)190 bool GetBoolAttribute(ax::mojom::BoolAttribute attribute, bool* value) const { 191 return data().GetBoolAttribute(attribute, value); 192 } 193 HasFloatAttribute(ax::mojom::FloatAttribute attribute)194 bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const { 195 return data().HasFloatAttribute(attribute); 196 } GetFloatAttribute(ax::mojom::FloatAttribute attribute)197 float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const { 198 return data().GetFloatAttribute(attribute); 199 } GetFloatAttribute(ax::mojom::FloatAttribute attribute,float * value)200 bool GetFloatAttribute(ax::mojom::FloatAttribute attribute, 201 float* value) const { 202 return data().GetFloatAttribute(attribute, value); 203 } 204 HasIntAttribute(ax::mojom::IntAttribute attribute)205 bool HasIntAttribute(ax::mojom::IntAttribute attribute) const { 206 return data().HasIntAttribute(attribute); 207 } GetIntAttribute(ax::mojom::IntAttribute attribute)208 int GetIntAttribute(ax::mojom::IntAttribute attribute) const { 209 return data().GetIntAttribute(attribute); 210 } GetIntAttribute(ax::mojom::IntAttribute attribute,int * value)211 bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const { 212 return data().GetIntAttribute(attribute, value); 213 } 214 HasStringAttribute(ax::mojom::StringAttribute attribute)215 bool HasStringAttribute(ax::mojom::StringAttribute attribute) const { 216 return data().HasStringAttribute(attribute); 217 } GetStringAttribute(ax::mojom::StringAttribute attribute)218 const std::string& GetStringAttribute( 219 ax::mojom::StringAttribute attribute) const { 220 return data().GetStringAttribute(attribute); 221 } GetStringAttribute(ax::mojom::StringAttribute attribute,std::string * value)222 bool GetStringAttribute(ax::mojom::StringAttribute attribute, 223 std::string* value) const { 224 return data().GetStringAttribute(attribute, value); 225 } 226 GetString16Attribute(ax::mojom::StringAttribute attribute,base::string16 * value)227 bool GetString16Attribute(ax::mojom::StringAttribute attribute, 228 base::string16* value) const { 229 return data().GetString16Attribute(attribute, value); 230 } GetString16Attribute(ax::mojom::StringAttribute attribute)231 base::string16 GetString16Attribute( 232 ax::mojom::StringAttribute attribute) const { 233 return data().GetString16Attribute(attribute); 234 } 235 HasIntListAttribute(ax::mojom::IntListAttribute attribute)236 bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const { 237 return data().HasIntListAttribute(attribute); 238 } GetIntListAttribute(ax::mojom::IntListAttribute attribute)239 const std::vector<int32_t>& GetIntListAttribute( 240 ax::mojom::IntListAttribute attribute) const { 241 return data().GetIntListAttribute(attribute); 242 } GetIntListAttribute(ax::mojom::IntListAttribute attribute,std::vector<int32_t> * value)243 bool GetIntListAttribute(ax::mojom::IntListAttribute attribute, 244 std::vector<int32_t>* value) const { 245 return data().GetIntListAttribute(attribute, value); 246 } 247 HasStringListAttribute(ax::mojom::StringListAttribute attribute)248 bool HasStringListAttribute(ax::mojom::StringListAttribute attribute) const { 249 return data().HasStringListAttribute(attribute); 250 } GetStringListAttribute(ax::mojom::StringListAttribute attribute)251 const std::vector<std::string>& GetStringListAttribute( 252 ax::mojom::StringListAttribute attribute) const { 253 return data().GetStringListAttribute(attribute); 254 } GetStringListAttribute(ax::mojom::StringListAttribute attribute,std::vector<std::string> * value)255 bool GetStringListAttribute(ax::mojom::StringListAttribute attribute, 256 std::vector<std::string>* value) const { 257 return data().GetStringListAttribute(attribute, value); 258 } 259 GetHtmlAttribute(const char * attribute,base::string16 * value)260 bool GetHtmlAttribute(const char* attribute, base::string16* value) const { 261 return data().GetHtmlAttribute(attribute, value); 262 } GetHtmlAttribute(const char * attribute,std::string * value)263 bool GetHtmlAttribute(const char* attribute, std::string* value) const { 264 return data().GetHtmlAttribute(attribute, value); 265 } 266 267 // Return the hierarchical level if supported. 268 base::Optional<int> GetHierarchicalLevel() const; 269 270 // PosInSet and SetSize public methods. 271 bool IsOrderedSetItem() const; 272 bool IsOrderedSet() const; 273 base::Optional<int> GetPosInSet(); 274 base::Optional<int> GetSetSize(); 275 276 // Helpers for GetPosInSet and GetSetSize. 277 // Returns true if the role of ordered set matches the role of item. 278 // Returns false otherwise. 279 bool SetRoleMatchesItemRole(const AXNode* ordered_set) const; 280 281 // Container objects that should be ignored for computing PosInSet and SetSize 282 // for ordered sets. 283 bool IsIgnoredContainerForOrderedSet() const; 284 285 const std::string& GetInheritedStringAttribute( 286 ax::mojom::StringAttribute attribute) const; 287 base::string16 GetInheritedString16Attribute( 288 ax::mojom::StringAttribute attribute) const; 289 290 // Return a string representing the language code. 291 // 292 // This will consider the language declared in the DOM, and may eventually 293 // attempt to automatically detect the language from the text. 294 // 295 // This language code will be BCP 47. 296 // 297 // Returns empty string if no appropriate language was found. 298 std::string GetLanguage() const; 299 300 // 301 // Helper functions for tables, table rows, and table cells. 302 // Most of these functions construct and cache an AXTableInfo behind 303 // the scenes to infer many properties of tables. 304 // 305 // These interfaces use attributes provided by the source of the 306 // AX tree where possible, but fills in missing details and ignores 307 // specified attributes when they're bad or inconsistent. That way 308 // you're guaranteed to get a valid, consistent table when using these 309 // interfaces. 310 // 311 312 // Table-like nodes (including grids). All indices are 0-based except 313 // ARIA indices are all 1-based. In other words, the top-left corner 314 // of the table is row 0, column 0, cell index 0 - but that same cell 315 // has a minimum ARIA row index of 1 and column index of 1. 316 // 317 // The below methods return base::nullopt if the AXNode they are called on is 318 // not inside a table. 319 bool IsTable() const; 320 base::Optional<int> GetTableColCount() const; 321 base::Optional<int> GetTableRowCount() const; 322 base::Optional<int> GetTableAriaColCount() const; 323 base::Optional<int> GetTableAriaRowCount() const; 324 base::Optional<int> GetTableCellCount() const; 325 base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const; 326 AXNode* GetTableCaption() const; 327 AXNode* GetTableCellFromIndex(int index) const; 328 AXNode* GetTableCellFromCoords(int row_index, int col_index) const; 329 void GetTableColHeaderNodeIds(int col_index, 330 std::vector<int32_t>* col_header_ids) const; 331 void GetTableRowHeaderNodeIds(int row_index, 332 std::vector<int32_t>* row_header_ids) const; 333 void GetTableUniqueCellIds(std::vector<int32_t>* row_header_ids) const; 334 // Extra computed nodes for the accessibility tree for macOS: 335 // one column node for each table column, followed by one 336 // table header container node, or nullptr if not applicable. 337 const std::vector<AXNode*>* GetExtraMacNodes() const; 338 339 // Table row-like nodes. 340 bool IsTableRow() const; 341 base::Optional<int> GetTableRowRowIndex() const; 342 // Get the node ids that represent rows in a table. 343 std::vector<AXNode::AXID> GetTableRowNodeIds() const; 344 345 #if defined(OS_MACOSX) 346 // Table column-like nodes. These nodes are only present on macOS. 347 bool IsTableColumn() const; 348 base::Optional<int> GetTableColColIndex() const; 349 #endif // defined(OS_MACOSX) 350 351 // Table cell-like nodes. 352 bool IsTableCellOrHeader() const; 353 base::Optional<int> GetTableCellIndex() const; 354 base::Optional<int> GetTableCellColIndex() const; 355 base::Optional<int> GetTableCellRowIndex() const; 356 base::Optional<int> GetTableCellColSpan() const; 357 base::Optional<int> GetTableCellRowSpan() const; 358 base::Optional<int> GetTableCellAriaColIndex() const; 359 base::Optional<int> GetTableCellAriaRowIndex() const; 360 void GetTableCellColHeaderNodeIds(std::vector<int32_t>* col_header_ids) const; 361 void GetTableCellRowHeaderNodeIds(std::vector<int32_t>* row_header_ids) const; 362 void GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const; 363 void GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const; 364 365 // Helper methods to check if a cell is an ARIA-1.1+ 'cell' or 'gridcell' 366 bool IsCellOrHeaderOfARIATable() const; 367 bool IsCellOrHeaderOfARIAGrid() const; 368 369 // Return an object containing information about the languages detected on 370 // this node. 371 // Callers should not retain this pointer, instead they should request it 372 // every time it is needed. 373 // 374 // Returns nullptr if the node has no language info. 375 AXLanguageInfo* GetLanguageInfo() const; 376 377 // This should only be called by LabelLanguageForSubtree and is used as part 378 // of the language detection feature. 379 void SetLanguageInfo(std::unique_ptr<AXLanguageInfo> lang_info); 380 381 // Destroy the language info for this node. 382 void ClearLanguageInfo(); 383 384 // Returns true if node has ignored state or ignored role. 385 bool IsIgnored() const; 386 387 // Returns true if this current node is a list marker or if it's a descendant 388 // of a list marker node. Returns false otherwise. 389 bool IsInListMarker() const; 390 391 private: 392 // Computes the text offset where each line starts by traversing all child 393 // leaf nodes. 394 void ComputeLineStartOffsets(std::vector<int>* line_offsets, 395 int* start_offset) const; 396 AXTableInfo* GetAncestorTableInfo() const; 397 void IdVectorToNodeVector(const std::vector<int32_t>& ids, 398 std::vector<AXNode*>* nodes) const; 399 400 int UpdateUnignoredCachedValuesRecursive(int startIndex); 401 AXNode* ComputeLastUnignoredChildRecursive() const; 402 AXNode* ComputeFirstUnignoredChildRecursive() const; 403 404 // Finds and returns a pointer to ordered set containing node. 405 AXNode* GetOrderedSet() const; 406 407 OwnerTree* const tree_; // Owns this. 408 size_t index_in_parent_; 409 size_t unignored_index_in_parent_; 410 size_t unignored_child_count_ = 0; 411 AXNode* const parent_; 412 std::vector<AXNode*> children_; 413 AXNodeData data_; 414 415 std::unique_ptr<AXLanguageInfo> language_info_; 416 }; 417 418 AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXNode& node); 419 420 template <typename NodeType, 421 NodeType* (NodeType::*NextSibling)() const, 422 NodeType* (NodeType::*PreviousSibling)() const, 423 NodeType* (NodeType::*LastChild)() const> 424 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: ChildIteratorBase(const NodeType * parent,NodeType * child)425 ChildIteratorBase(const NodeType* parent, NodeType* child) 426 : parent_(parent), child_(child) {} 427 428 template <typename NodeType, 429 NodeType* (NodeType::*NextSibling)() const, 430 NodeType* (NodeType::*PreviousSibling)() const, 431 NodeType* (NodeType::*LastChild)() const> 432 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: ChildIteratorBase(const ChildIteratorBase & it)433 ChildIteratorBase(const ChildIteratorBase& it) 434 : parent_(it.parent_), child_(it.child_) {} 435 436 template <typename NodeType, 437 NodeType* (NodeType::*NextSibling)() const, 438 NodeType* (NodeType::*PreviousSibling)() const, 439 NodeType* (NodeType::*LastChild)() const> 440 bool AXNode:: 441 ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 442 operator==(const ChildIteratorBase& rhs) const { 443 return parent_ == rhs.parent_ && child_ == rhs.child_; 444 } 445 446 template <typename NodeType, 447 NodeType* (NodeType::*NextSibling)() const, 448 NodeType* (NodeType::*PreviousSibling)() const, 449 NodeType* (NodeType::*LastChild)() const> 450 bool AXNode:: 451 ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 452 operator!=(const ChildIteratorBase& rhs) const { 453 return parent_ != rhs.parent_ || child_ != rhs.child_; 454 } 455 456 template <typename NodeType, 457 NodeType* (NodeType::*NextSibling)() const, 458 NodeType* (NodeType::*PreviousSibling)() const, 459 NodeType* (NodeType::*LastChild)() const> 460 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>& 461 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 462 operator++() { 463 if (child_) 464 child_ = (child_->*NextSibling)(); 465 return *this; 466 } 467 468 template <typename NodeType, 469 NodeType* (NodeType::*NextSibling)() const, 470 NodeType* (NodeType::*PreviousSibling)() const, 471 NodeType* (NodeType::*LastChild)() const> 472 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>& 473 AXNode::ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 474 operator--() { 475 if (child_) 476 child_ = (child_->*PreviousSibling)(); 477 else 478 child_ = (parent_->*LastChild)(); 479 return *this; 480 } 481 482 template <typename NodeType, 483 NodeType* (NodeType::*NextSibling)() const, 484 NodeType* (NodeType::*PreviousSibling)() const, 485 NodeType* (NodeType::*LastChild)() const> 486 NodeType* AXNode:: get()487 ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>::get() 488 const { 489 DCHECK(child_); 490 return child_; 491 } 492 493 template <typename NodeType, 494 NodeType* (NodeType::*NextSibling)() const, 495 NodeType* (NodeType::*PreviousSibling)() const, 496 NodeType* (NodeType::*LastChild)() const> 497 NodeType& AXNode:: 498 ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 499 operator*() const { 500 DCHECK(child_); 501 return *child_; 502 } 503 504 template <typename NodeType, 505 NodeType* (NodeType::*NextSibling)() const, 506 NodeType* (NodeType::*PreviousSibling)() const, 507 NodeType* (NodeType::*LastChild)() const> 508 NodeType* AXNode:: 509 ChildIteratorBase<NodeType, NextSibling, PreviousSibling, LastChild>:: 510 operator->() const { 511 DCHECK(child_); 512 return child_; 513 } 514 515 } // namespace ui 516 517 #endif // UI_ACCESSIBILITY_AX_NODE_H_ 518