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 base::Optional<int> GetPosInSet(const AXNode& node) = 0; 60 virtual base::Optional<int> GetSetSize(const AXNode& node) = 0; 61 62 virtual Selection GetUnignoredSelection() const = 0; 63 virtual bool GetTreeUpdateInProgressState() const = 0; 64 virtual bool HasPaginationSupport() const = 0; 65 }; 66 67 template <typename NodeType, 68 NodeType* (NodeType::*NextSibling)() const, 69 NodeType* (NodeType::*PreviousSibling)() const, 70 NodeType* (NodeType::*FirstChild)() 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 AXID 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::GetFirstUnignoredChild, 132 &AXNode::GetLastUnignoredChild>; 133 UnignoredChildIterator UnignoredChildrenBegin() const; 134 UnignoredChildIterator UnignoredChildrenEnd() const; 135 136 // Walking the tree including both ignored and unignored nodes. 137 // These methods consider only the direct children or siblings of a node. 138 AXNode* GetFirstChild() const; 139 AXNode* GetLastChild() const; 140 AXNode* GetPreviousSibling() const; 141 AXNode* GetNextSibling() const; 142 143 // Returns true if the node has any of the text related roles, including 144 // kStaticText, kInlineTextBox and kListMarker (for Legacy Layout). Does not 145 // include any text field roles. 146 bool IsText() const; 147 148 // Returns true if the node has any line break related roles or is the child 149 // of a node with line break related roles. 150 bool IsLineBreak() const; 151 152 // Set the node's accessibility data. This may be done during initialization 153 // or later when the node data changes. 154 void SetData(const AXNodeData& src); 155 156 // Update this node's location. This is separate from |SetData| just because 157 // changing only the location is common and should be more efficient than 158 // re-copying all of the data. 159 // 160 // The node's location is stored as a relative bounding box, the ID of 161 // the element it's relative to, and an optional transformation matrix. 162 // See ax_node_data.h for details. 163 void SetLocation(int32_t offset_container_id, 164 const gfx::RectF& location, 165 gfx::Transform* transform); 166 167 // Set the index in parent, for example if siblings were inserted or deleted. 168 void SetIndexInParent(size_t index_in_parent); 169 170 // Update the unignored index in parent for unignored children. 171 void UpdateUnignoredCachedValues(); 172 173 // Swap the internal children vector with |children|. This instance 174 // now owns all of the passed children. 175 void SwapChildren(std::vector<AXNode*>* children); 176 177 // This is called when the AXTree no longer includes this node in the 178 // tree. Reference counting is used on some platforms because the 179 // operating system may hold onto a reference to an AXNode 180 // object even after we're through with it, so this may decrement the 181 // reference count and clear out the object's data. 182 void Destroy(); 183 184 // Return true if this object is equal to or a descendant of |ancestor|. 185 bool IsDescendantOf(const AXNode* ancestor) const; 186 187 // Gets the text offsets where new lines start either from the node's data or 188 // by computing them and caching the result. 189 std::vector<int> GetOrComputeLineStartOffsets(); 190 191 // Accessing accessibility attributes. 192 // See |AXNodeData| for more information. 193 HasBoolAttribute(ax::mojom::BoolAttribute attribute)194 bool HasBoolAttribute(ax::mojom::BoolAttribute attribute) const { 195 return data().HasBoolAttribute(attribute); 196 } GetBoolAttribute(ax::mojom::BoolAttribute attribute)197 bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const { 198 return data().GetBoolAttribute(attribute); 199 } GetBoolAttribute(ax::mojom::BoolAttribute attribute,bool * value)200 bool GetBoolAttribute(ax::mojom::BoolAttribute attribute, bool* value) const { 201 return data().GetBoolAttribute(attribute, value); 202 } 203 HasFloatAttribute(ax::mojom::FloatAttribute attribute)204 bool HasFloatAttribute(ax::mojom::FloatAttribute attribute) const { 205 return data().HasFloatAttribute(attribute); 206 } GetFloatAttribute(ax::mojom::FloatAttribute attribute)207 float GetFloatAttribute(ax::mojom::FloatAttribute attribute) const { 208 return data().GetFloatAttribute(attribute); 209 } GetFloatAttribute(ax::mojom::FloatAttribute attribute,float * value)210 bool GetFloatAttribute(ax::mojom::FloatAttribute attribute, 211 float* value) const { 212 return data().GetFloatAttribute(attribute, value); 213 } 214 HasIntAttribute(ax::mojom::IntAttribute attribute)215 bool HasIntAttribute(ax::mojom::IntAttribute attribute) const { 216 return data().HasIntAttribute(attribute); 217 } GetIntAttribute(ax::mojom::IntAttribute attribute)218 int GetIntAttribute(ax::mojom::IntAttribute attribute) const { 219 return data().GetIntAttribute(attribute); 220 } GetIntAttribute(ax::mojom::IntAttribute attribute,int * value)221 bool GetIntAttribute(ax::mojom::IntAttribute attribute, int* value) const { 222 return data().GetIntAttribute(attribute, value); 223 } 224 HasStringAttribute(ax::mojom::StringAttribute attribute)225 bool HasStringAttribute(ax::mojom::StringAttribute attribute) const { 226 return data().HasStringAttribute(attribute); 227 } GetStringAttribute(ax::mojom::StringAttribute attribute)228 const std::string& GetStringAttribute( 229 ax::mojom::StringAttribute attribute) const { 230 return data().GetStringAttribute(attribute); 231 } GetStringAttribute(ax::mojom::StringAttribute attribute,std::string * value)232 bool GetStringAttribute(ax::mojom::StringAttribute attribute, 233 std::string* value) const { 234 return data().GetStringAttribute(attribute, value); 235 } 236 GetString16Attribute(ax::mojom::StringAttribute attribute,base::string16 * value)237 bool GetString16Attribute(ax::mojom::StringAttribute attribute, 238 base::string16* value) const { 239 return data().GetString16Attribute(attribute, value); 240 } GetString16Attribute(ax::mojom::StringAttribute attribute)241 base::string16 GetString16Attribute( 242 ax::mojom::StringAttribute attribute) const { 243 return data().GetString16Attribute(attribute); 244 } 245 HasIntListAttribute(ax::mojom::IntListAttribute attribute)246 bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const { 247 return data().HasIntListAttribute(attribute); 248 } GetIntListAttribute(ax::mojom::IntListAttribute attribute)249 const std::vector<int32_t>& GetIntListAttribute( 250 ax::mojom::IntListAttribute attribute) const { 251 return data().GetIntListAttribute(attribute); 252 } GetIntListAttribute(ax::mojom::IntListAttribute attribute,std::vector<int32_t> * value)253 bool GetIntListAttribute(ax::mojom::IntListAttribute attribute, 254 std::vector<int32_t>* value) const { 255 return data().GetIntListAttribute(attribute, value); 256 } 257 HasStringListAttribute(ax::mojom::StringListAttribute attribute)258 bool HasStringListAttribute(ax::mojom::StringListAttribute attribute) const { 259 return data().HasStringListAttribute(attribute); 260 } GetStringListAttribute(ax::mojom::StringListAttribute attribute)261 const std::vector<std::string>& GetStringListAttribute( 262 ax::mojom::StringListAttribute attribute) const { 263 return data().GetStringListAttribute(attribute); 264 } GetStringListAttribute(ax::mojom::StringListAttribute attribute,std::vector<std::string> * value)265 bool GetStringListAttribute(ax::mojom::StringListAttribute attribute, 266 std::vector<std::string>* value) const { 267 return data().GetStringListAttribute(attribute, value); 268 } 269 GetHtmlAttribute(const char * attribute,base::string16 * value)270 bool GetHtmlAttribute(const char* attribute, base::string16* value) const { 271 return data().GetHtmlAttribute(attribute, value); 272 } GetHtmlAttribute(const char * attribute,std::string * value)273 bool GetHtmlAttribute(const char* attribute, std::string* value) const { 274 return data().GetHtmlAttribute(attribute, value); 275 } 276 277 // Return the hierarchical level if supported. 278 base::Optional<int> GetHierarchicalLevel() const; 279 280 // PosInSet and SetSize public methods. 281 bool IsOrderedSetItem() const; 282 bool IsOrderedSet() const; 283 base::Optional<int> GetPosInSet(); 284 base::Optional<int> GetSetSize(); 285 286 // Helpers for GetPosInSet and GetSetSize. 287 // Returns true if the role of ordered set matches the role of item. 288 // Returns false otherwise. 289 bool SetRoleMatchesItemRole(const AXNode* ordered_set) const; 290 291 // Container objects that should be ignored for computing PosInSet and SetSize 292 // for ordered sets. 293 bool IsIgnoredContainerForOrderedSet() const; 294 295 const std::string& GetInheritedStringAttribute( 296 ax::mojom::StringAttribute attribute) const; 297 base::string16 GetInheritedString16Attribute( 298 ax::mojom::StringAttribute attribute) const; 299 300 // If this node is a leaf, returns the inner text of this node. This is 301 // equivalent to its visible accessible name. Otherwise, if this node is not a 302 // leaf, represents every non-textual child node with a special "embedded 303 // object character", and every textual child node with its inner text. 304 // Textual nodes include e.g. static text and white space. 305 // 306 // This is how displayed text and embedded objects are represented in 307 // ATK and IAccessible2 APIs. 308 std::string GetHypertext() const; 309 310 // Returns the text of this node and all descendant nodes; including text 311 // found in embedded objects. 312 // 313 // Only text displayed on screen is included. Text from ARIA and HTML 314 // attributes that is either not displayed on screen, or outside this node, is 315 // not returned. 316 std::string GetInnerText() const; 317 318 // Returns a string representing the language code. 319 // 320 // This will consider the language declared in the DOM, and may eventually 321 // attempt to automatically detect the language from the text. 322 // 323 // This language code will be BCP 47. 324 // 325 // Returns empty string if no appropriate language was found. 326 std::string GetLanguage() const; 327 328 // Returns the value of a control such as a text field, a slider, a <select> 329 // element, a date picker or an ARIA combo box. In order to minimize 330 // cross-process communication between the renderer and the browser, this 331 // method may compute the value from the control's inner text in the case of a 332 // text field. 333 std::string GetValueForControl() const; 334 335 // 336 // Helper functions for tables, table rows, and table cells. 337 // Most of these functions construct and cache an AXTableInfo behind 338 // the scenes to infer many properties of tables. 339 // 340 // These interfaces use attributes provided by the source of the 341 // AX tree where possible, but fills in missing details and ignores 342 // specified attributes when they're bad or inconsistent. That way 343 // you're guaranteed to get a valid, consistent table when using these 344 // interfaces. 345 // 346 347 // Table-like nodes (including grids). All indices are 0-based except 348 // ARIA indices are all 1-based. In other words, the top-left corner 349 // of the table is row 0, column 0, cell index 0 - but that same cell 350 // has a minimum ARIA row index of 1 and column index of 1. 351 // 352 // The below methods return base::nullopt if the AXNode they are called on is 353 // not inside a table. 354 bool IsTable() const; 355 base::Optional<int> GetTableColCount() const; 356 base::Optional<int> GetTableRowCount() const; 357 base::Optional<int> GetTableAriaColCount() const; 358 base::Optional<int> GetTableAriaRowCount() const; 359 base::Optional<int> GetTableCellCount() const; 360 base::Optional<bool> GetTableHasColumnOrRowHeaderNode() const; 361 AXNode* GetTableCaption() const; 362 AXNode* GetTableCellFromIndex(int index) const; 363 AXNode* GetTableCellFromCoords(int row_index, int col_index) const; 364 // Get all the column header node ids of the table. 365 std::vector<AXNode::AXID> GetTableColHeaderNodeIds() const; 366 // Get the column header node ids associated with |col_index|. 367 std::vector<AXNode::AXID> GetTableColHeaderNodeIds(int col_index) const; 368 // Get the row header node ids associated with |row_index|. 369 std::vector<AXNode::AXID> GetTableRowHeaderNodeIds(int row_index) const; 370 std::vector<AXNode::AXID> GetTableUniqueCellIds() const; 371 // Extra computed nodes for the accessibility tree for macOS: 372 // one column node for each table column, followed by one 373 // table header container node, or nullptr if not applicable. 374 const std::vector<AXNode*>* GetExtraMacNodes() const; 375 376 // Table row-like nodes. 377 bool IsTableRow() const; 378 base::Optional<int> GetTableRowRowIndex() const; 379 // Get the node ids that represent rows in a table. 380 std::vector<AXNode::AXID> GetTableRowNodeIds() const; 381 382 #if defined(OS_APPLE) 383 // Table column-like nodes. These nodes are only present on macOS. 384 bool IsTableColumn() const; 385 base::Optional<int> GetTableColColIndex() const; 386 #endif // defined(OS_APPLE) 387 388 // Table cell-like nodes. 389 bool IsTableCellOrHeader() const; 390 base::Optional<int> GetTableCellIndex() const; 391 base::Optional<int> GetTableCellColIndex() const; 392 base::Optional<int> GetTableCellRowIndex() const; 393 base::Optional<int> GetTableCellColSpan() const; 394 base::Optional<int> GetTableCellRowSpan() const; 395 base::Optional<int> GetTableCellAriaColIndex() const; 396 base::Optional<int> GetTableCellAriaRowIndex() const; 397 std::vector<AXNode::AXID> GetTableCellColHeaderNodeIds() const; 398 std::vector<AXNode::AXID> GetTableCellRowHeaderNodeIds() const; 399 void GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const; 400 void GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const; 401 402 // Helper methods to check if a cell is an ARIA-1.1+ 'cell' or 'gridcell' 403 bool IsCellOrHeaderOfARIATable() const; 404 bool IsCellOrHeaderOfARIAGrid() const; 405 406 // Return an object containing information about the languages detected on 407 // this node. 408 // Callers should not retain this pointer, instead they should request it 409 // every time it is needed. 410 // 411 // Returns nullptr if the node has no language info. 412 AXLanguageInfo* GetLanguageInfo() const; 413 414 // This should only be called by LabelLanguageForSubtree and is used as part 415 // of the language detection feature. 416 void SetLanguageInfo(std::unique_ptr<AXLanguageInfo> lang_info); 417 418 // Destroy the language info for this node. 419 void ClearLanguageInfo(); 420 421 // Returns true if node is a group and is a direct descendant of a set-like 422 // element. 423 bool IsEmbeddedGroup() const; 424 425 // Returns true if node has ignored state or ignored role. 426 bool IsIgnored() const; 427 428 // Returns true if an ancestor of this node (not including itself) is a 429 // leaf node, meaning that this node is not actually exposed to any 430 // platform's accessibility layer. 431 bool IsChildOfLeaf() const; 432 433 // Returns true if this is a leaf node, meaning all its 434 // children should not be exposed to any platform's native accessibility 435 // layer. 436 // 437 // The definition of a leaf includes nodes with children that are exclusively 438 // an internal renderer implementation, such as the children of an HTML native 439 // text field, as well as nodes with presentational children according to the 440 // ARIA and HTML5 Specs. Also returns true if all of the node's descendants 441 // are ignored. 442 // 443 // A leaf node should never have children that are focusable or 444 // that might send notifications. 445 bool IsLeaf() const; 446 447 // Returns true if this node is a list marker or if it's a descendant 448 // of a list marker node. Returns false otherwise. 449 bool IsInListMarker() const; 450 451 // Returns true if this node is a collapsed popup button that is parent to a 452 // menu list popup. 453 bool IsCollapsedMenuListPopUpButton() const; 454 455 // Returns the popup button ancestor of this current node if any. The popup 456 // button needs to be the parent of a menu list popup and needs to be 457 // collapsed. 458 AXNode* GetCollapsedMenuListPopUpButtonAncestor() const; 459 460 // If this node is within an editable region, returns the node that is at the 461 // root of that editable region, otherwise returns nullptr. In accessibility, 462 // an editable region is synonymous to a text field. 463 AXNode* GetTextFieldAncestor() const; 464 465 // Returns true if the ancestor of the current node is a plain text field. 466 bool IsDescendantOfPlainTextField() const; 467 468 // Finds and returns a pointer to ordered set containing node. 469 AXNode* GetOrderedSet() const; 470 471 private: 472 // Computes the text offset where each line starts by traversing all child 473 // leaf nodes. 474 void ComputeLineStartOffsets(std::vector<int>* line_offsets, 475 int* start_offset) const; 476 AXTableInfo* GetAncestorTableInfo() const; 477 void IdVectorToNodeVector(const std::vector<int32_t>& ids, 478 std::vector<AXNode*>* nodes) const; 479 480 int UpdateUnignoredCachedValuesRecursive(int startIndex); 481 AXNode* ComputeLastUnignoredChildRecursive() const; 482 AXNode* ComputeFirstUnignoredChildRecursive() const; 483 484 // Returns the value of a range control such as a slider or a scroll bar in 485 // text format. 486 std::string GetTextForRangeValue() const; 487 488 // Returns the value of a color well (a color chooser control) in a human 489 // readable format. For example: "50% red 40% green 90% blue". 490 std::string GetValueForColorWell() const; 491 492 // Returns the value of a text field. If necessary, computes the value from 493 // the field's internal representation in the accessibility tree, in order to 494 // minimize cross-process communication between the renderer and the browser 495 // processes. 496 std::string GetValueForTextField() const; 497 498 OwnerTree* const tree_; // Owns this. 499 size_t index_in_parent_; 500 size_t unignored_index_in_parent_; 501 size_t unignored_child_count_ = 0; 502 AXNode* const parent_; 503 std::vector<AXNode*> children_; 504 AXNodeData data_; 505 506 // Stores the detected language computed from the node's text. 507 std::unique_ptr<AXLanguageInfo> language_info_; 508 }; 509 510 AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXNode& node); 511 512 template <typename NodeType, 513 NodeType* (NodeType::*NextSibling)() const, 514 NodeType* (NodeType::*PreviousSibling)() const, 515 NodeType* (NodeType::*FirstChild)() const, 516 NodeType* (NodeType::*LastChild)() const> 517 AXNode::ChildIteratorBase<NodeType, 518 NextSibling, 519 PreviousSibling, 520 FirstChild, ChildIteratorBase(const NodeType * parent,NodeType * child)521 LastChild>::ChildIteratorBase(const NodeType* parent, 522 NodeType* child) 523 : parent_(parent), child_(child) {} 524 525 template <typename NodeType, 526 NodeType* (NodeType::*NextSibling)() const, 527 NodeType* (NodeType::*PreviousSibling)() const, 528 NodeType* (NodeType::*FirstChild)() const, 529 NodeType* (NodeType::*LastChild)() const> 530 AXNode::ChildIteratorBase<NodeType, 531 NextSibling, 532 PreviousSibling, 533 FirstChild, ChildIteratorBase(const ChildIteratorBase & it)534 LastChild>::ChildIteratorBase(const ChildIteratorBase& 535 it) 536 : parent_(it.parent_), child_(it.child_) {} 537 538 template <typename NodeType, 539 NodeType* (NodeType::*NextSibling)() const, 540 NodeType* (NodeType::*PreviousSibling)() const, 541 NodeType* (NodeType::*FirstChild)() const, 542 NodeType* (NodeType::*LastChild)() const> 543 bool AXNode::ChildIteratorBase<NodeType, 544 NextSibling, 545 PreviousSibling, 546 FirstChild, 547 LastChild>::operator==(const ChildIteratorBase& 548 rhs) const { 549 return parent_ == rhs.parent_ && child_ == rhs.child_; 550 } 551 552 template <typename NodeType, 553 NodeType* (NodeType::*NextSibling)() const, 554 NodeType* (NodeType::*PreviousSibling)() const, 555 NodeType* (NodeType::*FirstChild)() const, 556 NodeType* (NodeType::*LastChild)() const> 557 bool AXNode::ChildIteratorBase<NodeType, 558 NextSibling, 559 PreviousSibling, 560 FirstChild, 561 LastChild>::operator!=(const ChildIteratorBase& 562 rhs) const { 563 return parent_ != rhs.parent_ || child_ != rhs.child_; 564 } 565 566 template <typename NodeType, 567 NodeType* (NodeType::*NextSibling)() const, 568 NodeType* (NodeType::*PreviousSibling)() const, 569 NodeType* (NodeType::*FirstChild)() const, 570 NodeType* (NodeType::*LastChild)() const> 571 AXNode::ChildIteratorBase<NodeType, 572 NextSibling, 573 PreviousSibling, 574 FirstChild, 575 LastChild>& 576 AXNode::ChildIteratorBase<NodeType, 577 NextSibling, 578 PreviousSibling, 579 FirstChild, 580 LastChild>::operator++() { 581 // |child_ = nullptr| denotes the iterator's past-the-end condition. When we 582 // increment the iterator past the end, we remain at the past-the-end iterator 583 // condition. 584 if (child_ && parent_) { 585 if (child_ == (parent_->*LastChild)()) 586 child_ = nullptr; 587 else 588 child_ = (child_->*NextSibling)(); 589 } 590 591 return *this; 592 } 593 594 template <typename NodeType, 595 NodeType* (NodeType::*NextSibling)() const, 596 NodeType* (NodeType::*PreviousSibling)() const, 597 NodeType* (NodeType::*FirstChild)() const, 598 NodeType* (NodeType::*LastChild)() const> 599 AXNode::ChildIteratorBase<NodeType, 600 NextSibling, 601 PreviousSibling, 602 FirstChild, 603 LastChild>& 604 AXNode::ChildIteratorBase<NodeType, 605 NextSibling, 606 PreviousSibling, 607 FirstChild, 608 LastChild>::operator--() { 609 if (parent_) { 610 // If the iterator is past the end, |child_=nullptr|, decrement the iterator 611 // gives us the last iterator element. 612 if (!child_) 613 child_ = (parent_->*LastChild)(); 614 // Decrement the iterator gives us the previous element, except when the 615 // iterator is at the beginning; in which case, decrementing the iterator 616 // remains at the beginning. 617 else if (child_ != (parent_->*FirstChild)()) 618 child_ = (child_->*PreviousSibling)(); 619 } 620 621 return *this; 622 } 623 624 template <typename NodeType, 625 NodeType* (NodeType::*NextSibling)() const, 626 NodeType* (NodeType::*PreviousSibling)() const, 627 NodeType* (NodeType::*FirstChild)() const, 628 NodeType* (NodeType::*LastChild)() const> 629 NodeType* AXNode::ChildIteratorBase<NodeType, 630 NextSibling, 631 PreviousSibling, 632 FirstChild, get()633 LastChild>::get() const { 634 DCHECK(child_); 635 return child_; 636 } 637 638 template <typename NodeType, 639 NodeType* (NodeType::*NextSibling)() const, 640 NodeType* (NodeType::*PreviousSibling)() const, 641 NodeType* (NodeType::*FirstChild)() const, 642 NodeType* (NodeType::*LastChild)() const> 643 NodeType& AXNode::ChildIteratorBase<NodeType, 644 NextSibling, 645 PreviousSibling, 646 FirstChild, 647 LastChild>::operator*() const { 648 DCHECK(child_); 649 return *child_; 650 } 651 652 template <typename NodeType, 653 NodeType* (NodeType::*NextSibling)() const, 654 NodeType* (NodeType::*PreviousSibling)() const, 655 NodeType* (NodeType::*FirstChild)() const, 656 NodeType* (NodeType::*LastChild)() const> 657 NodeType* AXNode::ChildIteratorBase<NodeType, 658 NextSibling, 659 PreviousSibling, 660 FirstChild, 661 LastChild>::operator->() const { 662 DCHECK(child_); 663 return child_; 664 } 665 666 } // namespace ui 667 668 #endif // UI_ACCESSIBILITY_AX_NODE_H_ 669