Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(623)

Side by Side Diff: ui/accessibility/ax_position.h

Issue 2934953004: De-templatize ui::AXPosition
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/accessibility/ax_node_position_unittest.cc ('k') | ui/accessibility/ax_position.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef UI_ACCESSIBILITY_AX_POSITION_H_ 5 #ifndef UI_ACCESSIBILITY_AX_POSITION_H_
6 #define UI_ACCESSIBILITY_AX_POSITION_H_ 6 #define UI_ACCESSIBILITY_AX_POSITION_H_
7 7
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <memory> 10 #include <memory>
11 #include <stack> 11 #include <stack>
12 #include <string> 12 #include <string>
13 #include <utility> 13 #include <utility>
14 #include <vector> 14 #include <vector>
15 15
16 #include "base/memory/ptr_util.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/strings/string16.h" 18 #include "base/strings/string16.h"
18 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
20 #include "ui/accessibility/ax_enums.h" 21 #include "ui/accessibility/ax_enums.h"
22 #include "ui/accessibility/ax_export.h"
21 23
22 namespace ui { 24 namespace ui {
23 25
24 // Defines the type of position in the accessibility tree. 26 // Defines the type of position in the accessibility tree.
25 // A tree position is used when referring to a specific child of a node in the 27 // A tree position is used when referring to a specific child of a node in the
26 // accessibility tree. 28 // accessibility tree.
27 // A text position is used when referring to a specific character of text inside 29 // A text position is used when referring to a specific character of text inside
28 // a particular node. 30 // a particular node.
29 // A null position is used to signify that the provided data is invalid or that 31 // A null position is used to signify that the provided data is invalid or that
30 // a boundary has been reached. 32 // a boundary has been reached.
31 enum class AXPositionKind { NULL_POSITION, TREE_POSITION, TEXT_POSITION }; 33 enum class AXPositionKind { NULL_POSITION, TREE_POSITION, TEXT_POSITION };
32 34
33 // Forward declarations. 35 // Forward declarations.
34 template <class AXPositionType, class AXNodeType> 36 class AXPositionBase;
35 class AXPosition; 37 AX_EXPORT bool operator==(const AXPositionBase& first,
36 template <class AXPositionType, class AXNodeType> 38 const AXPositionBase& second);
37 bool operator==(const AXPosition<AXPositionType, AXNodeType>& first, 39 AX_EXPORT bool operator!=(const AXPositionBase& first,
38 const AXPosition<AXPositionType, AXNodeType>& second); 40 const AXPositionBase& second);
39 template <class AXPositionType, class AXNodeType> 41 AX_EXPORT bool operator<(const AXPositionBase& first,
40 bool operator!=(const AXPosition<AXPositionType, AXNodeType>& first, 42 const AXPositionBase& second);
41 const AXPosition<AXPositionType, AXNodeType>& second); 43 AX_EXPORT bool operator<=(const AXPositionBase& first,
44 const AXPositionBase& second);
45 AX_EXPORT bool operator>(const AXPositionBase& first,
46 const AXPositionBase& second);
47 AX_EXPORT bool operator>=(const AXPositionBase& first,
48 const AXPositionBase& second);
42 49
43 // A position in the accessibility tree. 50 // A position in the accessibility tree.
44 // 51 //
45 // This class could either represent a tree position or a text position. 52 // This class could either represent a tree position or a text position.
46 // Tree positions point to either a child of a specific node or at the end of a 53 // Tree positions point to either a child of a specific node or at the end of a
47 // node (i.e. an "after children" position). 54 // node (i.e. an "after children" position).
48 // Text positions point to either a character offset in the text inside a 55 // Text positions point to either a character offset in the text inside a
49 // particular node including text from all its children, or to the end of the 56 // particular node including text from all its children, or to the end of the
50 // node's text, (i.e. an "after text" position). 57 // node's text, (i.e. an "after text" position).
51 // On tree positions that have a leaf node as their anchor, we also need to 58 // On tree positions that have a leaf node as their anchor, we also need to
(...skipping 10 matching lines...) Expand all
62 // 69 //
63 // This class template uses static polymorphism in order to allow sub-classes to 70 // This class template uses static polymorphism in order to allow sub-classes to
64 // be created from the base class without the base class knowing the type of the 71 // be created from the base class without the base class knowing the type of the
65 // sub-class in advance. 72 // sub-class in advance.
66 // The template argument |AXPositionType| should always be set to the type of 73 // The template argument |AXPositionType| should always be set to the type of
67 // any class that inherits from this template, making this a 74 // any class that inherits from this template, making this a
68 // "curiously recursive template". 75 // "curiously recursive template".
69 // 76 //
70 // This class can be copied using the |Clone| method. It is designed to be 77 // This class can be copied using the |Clone| method. It is designed to be
71 // immutable. 78 // immutable.
72 template <class AXPositionType, class AXNodeType> 79 class AX_EXPORT AXPositionBase {
73 class AXPosition {
74 public: 80 public:
75 using AXPositionInstance = 81 using AXPositionInstance = std::unique_ptr<AXPositionBase>;
76 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>>; 82 using OpaqueAnchor = void*;
77 83
78 static const int INVALID_TREE_ID = -1; 84 static constexpr int INVALID_TREE_ID = -1;
79 static const int32_t INVALID_ANCHOR_ID = -1; 85 static constexpr int32_t INVALID_ANCHOR_ID = -1;
80 static const int BEFORE_TEXT = -1; 86 static constexpr int BEFORE_TEXT = -1;
81 static const int INVALID_INDEX = -2; 87 static constexpr int INVALID_INDEX = -2;
82 static const int INVALID_OFFSET = -1; 88 static constexpr int INVALID_OFFSET = -1;
83 89
84 static AXPositionInstance CreateNullPosition() { 90 AXPositionBase() {}
85 AXPositionInstance new_position(new AXPositionType()); 91 virtual ~AXPositionBase() {}
86 new_position->Initialize(AXPositionKind::NULL_POSITION, INVALID_TREE_ID,
87 INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET,
88 AX_TEXT_AFFINITY_DOWNSTREAM);
89 return new_position;
90 }
91
92 static AXPositionInstance CreateTreePosition(int tree_id,
93 int32_t anchor_id,
94 int child_index) {
95 AXPositionInstance new_position(new AXPositionType());
96 new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
97 child_index, INVALID_OFFSET,
98 AX_TEXT_AFFINITY_DOWNSTREAM);
99 return new_position;
100 }
101
102 static AXPositionInstance CreateTextPosition(int tree_id,
103 int32_t anchor_id,
104 int text_offset,
105 AXTextAffinity affinity) {
106 AXPositionInstance new_position(new AXPositionType());
107 new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id,
108 INVALID_INDEX, text_offset, affinity);
109 return new_position;
110 }
111
112 AXPosition() {}
113 virtual ~AXPosition() {}
114 92
115 virtual AXPositionInstance Clone() const = 0; 93 virtual AXPositionInstance Clone() const = 0;
116 94 virtual AXPositionInstance CreateNullPosition() const = 0;
95 virtual AXPositionInstance CreateTreePosition(int tree_id,
96 int32_t anchor_id,
97 int child_index) const = 0;
98 virtual AXPositionInstance CreateTextPosition(
99 int tree_id,
100 int32_t anchor_id,
101 int text_offset,
102 AXTextAffinity affinity) const = 0;
117 std::string ToString() const { 103 std::string ToString() const {
118 std::string str; 104 std::string str;
119 switch (kind_) { 105 switch (kind_) {
120 case AXPositionKind::NULL_POSITION: 106 case AXPositionKind::NULL_POSITION:
121 return "NullPosition"; 107 return "NullPosition";
122 case AXPositionKind::TREE_POSITION: { 108 case AXPositionKind::TREE_POSITION: {
123 std::string str_child_index; 109 std::string str_child_index;
124 if (child_index_ == BEFORE_TEXT) { 110 if (child_index_ == BEFORE_TEXT) {
125 str_child_index = "before_text"; 111 str_child_index = "before_text";
126 } else if (child_index_ == INVALID_INDEX) { 112 } else if (child_index_ == INVALID_INDEX) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 annotated_text = text.substr(0, text_offset_) + "<" + text[text_offset_] + 147 annotated_text = text.substr(0, text_offset_) + "<" + text[text_offset_] +
162 ">" + text.substr(text_offset_ + 1); 148 ">" + text.substr(text_offset_ + 1);
163 } 149 }
164 150
165 return str + " annotated_text=" + annotated_text; 151 return str + " annotated_text=" + annotated_text;
166 } 152 }
167 153
168 int tree_id() const { return tree_id_; } 154 int tree_id() const { return tree_id_; }
169 int32_t anchor_id() const { return anchor_id_; } 155 int32_t anchor_id() const { return anchor_id_; }
170 156
171 AXNodeType* GetAnchor() const { 157 OpaqueAnchor GetOpaqueAnchor() const {
172 if (tree_id_ == INVALID_TREE_ID || anchor_id_ == INVALID_ANCHOR_ID) 158 if (tree_id_ == INVALID_TREE_ID || anchor_id_ == INVALID_ANCHOR_ID)
173 return nullptr; 159 return nullptr;
174 DCHECK_GE(tree_id_, 0); 160 DCHECK_GE(tree_id_, 0);
175 DCHECK_GE(anchor_id_, 0); 161 DCHECK_GE(anchor_id_, 0);
176 return GetNodeInTree(tree_id_, anchor_id_); 162 return GetOpaqueNodeInTree(tree_id_, anchor_id_);
177 } 163 }
178 164
179 AXPositionKind kind() const { return kind_; } 165 AXPositionKind kind() const { return kind_; }
180 int child_index() const { return child_index_; } 166 int child_index() const { return child_index_; }
181 int text_offset() const { return text_offset_; } 167 int text_offset() const { return text_offset_; }
182 AXTextAffinity affinity() const { return affinity_; } 168 AXTextAffinity affinity() const { return affinity_; }
183 169
184 bool IsNullPosition() const { 170 bool IsNullPosition() const {
185 return kind_ == AXPositionKind::NULL_POSITION || !GetAnchor(); 171 return kind_ == AXPositionKind::NULL_POSITION || !GetOpaqueAnchor();
186 } 172 }
187 173
188 bool IsTreePosition() const { 174 bool IsTreePosition() const {
189 return GetAnchor() && kind_ == AXPositionKind::TREE_POSITION; 175 return GetOpaqueAnchor() && kind_ == AXPositionKind::TREE_POSITION;
190 } 176 }
191 177
192 bool IsTextPosition() const { 178 bool IsTextPosition() const {
193 return GetAnchor() && kind_ == AXPositionKind::TEXT_POSITION; 179 return GetOpaqueAnchor() && kind_ == AXPositionKind::TEXT_POSITION;
194 } 180 }
195 181
196 bool AtStartOfAnchor() const { 182 bool AtStartOfAnchor() const {
197 if (!GetAnchor()) 183 if (!GetOpaqueAnchor())
198 return false; 184 return false;
199 185
200 switch (kind_) { 186 switch (kind_) {
201 case AXPositionKind::NULL_POSITION: 187 case AXPositionKind::NULL_POSITION:
202 return false; 188 return false;
203 case AXPositionKind::TREE_POSITION: 189 case AXPositionKind::TREE_POSITION:
204 if (AnchorChildCount()) 190 if (AnchorChildCount())
205 return child_index_ == 0; 191 return child_index_ == 0;
206 return child_index_ == BEFORE_TEXT; 192 return child_index_ == BEFORE_TEXT;
207 case AXPositionKind::TEXT_POSITION: 193 case AXPositionKind::TEXT_POSITION:
208 return text_offset_ == 0; 194 return text_offset_ == 0;
209 } 195 }
210 196
211 return false; 197 return false;
212 } 198 }
213 199
214 bool AtEndOfAnchor() const { 200 bool AtEndOfAnchor() const {
215 if (!GetAnchor()) 201 if (!GetOpaqueAnchor())
216 return false; 202 return false;
217 203
218 switch (kind_) { 204 switch (kind_) {
219 case AXPositionKind::NULL_POSITION: 205 case AXPositionKind::NULL_POSITION:
220 return false; 206 return false;
221 case AXPositionKind::TREE_POSITION: 207 case AXPositionKind::TREE_POSITION:
222 return child_index_ == AnchorChildCount(); 208 return child_index_ == AnchorChildCount();
223 case AXPositionKind::TEXT_POSITION: 209 case AXPositionKind::TEXT_POSITION:
224 return text_offset_ == MaxTextOffset(); 210 return text_offset_ == MaxTextOffset();
225 } 211 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } 289 }
304 return false; 290 return false;
305 } 291 }
306 292
307 // This method returns a position instead of a node because this allows us to 293 // This method returns a position instead of a node because this allows us to
308 // return the corresponding text offset or child index in the ancestor that 294 // return the corresponding text offset or child index in the ancestor that
309 // relates to the current position. 295 // relates to the current position.
310 // Also, this method uses position instead of tree logic to traverse the tree, 296 // Also, this method uses position instead of tree logic to traverse the tree,
311 // because positions can handle moving across multiple trees, while trees 297 // because positions can handle moving across multiple trees, while trees
312 // cannot. 298 // cannot.
313 AXPositionInstance LowestCommonAncestor( 299 AXPositionInstance LowestCommonAncestor(const AXPositionBase& second) const {
314 const AXPosition<AXPositionType, AXNodeType>& second) const {
315 if (IsNullPosition() || second.IsNullPosition()) 300 if (IsNullPosition() || second.IsNullPosition())
316 return CreateNullPosition(); 301 return CreateNullPosition();
317 if (GetAnchor() == second.GetAnchor()) 302 if (GetOpaqueAnchor() == second.GetOpaqueAnchor())
318 return Clone(); 303 return Clone();
319 304
320 std::stack<AXPositionInstance> ancestors1; 305 std::stack<AXPositionInstance> ancestors1;
321 ancestors1.push(std::move(Clone())); 306 ancestors1.push(Clone());
322 while (!ancestors1.top()->IsNullPosition()) 307 while (!ancestors1.top()->IsNullPosition())
323 ancestors1.push(std::move(ancestors1.top()->CreateParentPosition())); 308 ancestors1.push(ancestors1.top()->CreateParentPosition());
324 309
325 std::stack<AXPositionInstance> ancestors2; 310 std::stack<AXPositionInstance> ancestors2;
326 ancestors2.push(std::move(second.Clone())); 311 ancestors2.push(second.Clone());
327 while (!ancestors2.top()->IsNullPosition()) 312 while (!ancestors2.top()->IsNullPosition())
328 ancestors2.push(std::move(ancestors2.top()->CreateParentPosition())); 313 ancestors2.push(ancestors2.top()->CreateParentPosition());
329 314
330 AXPositionInstance common_ancestor; 315 AXPositionInstance common_ancestor;
331 while (!ancestors1.empty() && !ancestors2.empty() && 316 while (!ancestors1.empty() && !ancestors2.empty() &&
332 ancestors1.top()->GetAnchor() == ancestors2.top()->GetAnchor()) { 317 ancestors1.top()->GetOpaqueAnchor() ==
318 ancestors2.top()->GetOpaqueAnchor()) {
333 common_ancestor = std::move(ancestors1.top()); 319 common_ancestor = std::move(ancestors1.top());
334 ancestors1.pop(); 320 ancestors1.pop();
335 ancestors2.pop(); 321 ancestors2.pop();
336 } 322 }
337 return common_ancestor; 323 return common_ancestor;
338 } 324 }
339 325
340 AXPositionInstance AsTreePosition() const { 326 AXPositionInstance AsTreePosition() const {
341 if (IsNullPosition() || IsTreePosition()) 327 if (IsNullPosition() || IsTreePosition())
342 return Clone(); 328 return Clone();
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 text_position->text_offset_ = static_cast<int>(*iterator); 644 text_position->text_offset_ = static_cast<int>(*iterator);
659 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 645 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
660 } 646 }
661 647
662 // If the word boundary is in the same subtree, return a position rooted at 648 // If the word boundary is in the same subtree, return a position rooted at
663 // the current position. 649 // the current position.
664 // This is necessary because we don't want to return any position that might 650 // This is necessary because we don't want to return any position that might
665 // be in the shadow DOM if the original position was not. 651 // be in the shadow DOM if the original position was not.
666 AXPositionInstance common_ancestor = 652 AXPositionInstance common_ancestor =
667 text_position->LowestCommonAncestor(*this); 653 text_position->LowestCommonAncestor(*this);
668 if (GetAnchor() == common_ancestor->GetAnchor()) 654 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
669 text_position = std::move(common_ancestor); 655 text_position = std::move(common_ancestor);
670 656
671 if (was_tree_position) 657 if (was_tree_position)
672 text_position = text_position->AsTreePosition(); 658 text_position = text_position->AsTreePosition();
673 return text_position; 659 return text_position;
674 } 660 }
675 661
676 AXPositionInstance CreatePreviousWordStartPosition() const { 662 AXPositionInstance CreatePreviousWordStartPosition() const {
677 bool was_tree_position = IsTreePosition(); 663 bool was_tree_position = IsTreePosition();
678 AXPositionInstance text_position = AsLeafTextPosition(); 664 AXPositionInstance text_position = AsLeafTextPosition();
(...skipping 28 matching lines...) Expand all
707 text_position->text_offset_ = static_cast<int>(*(--iterator)); 693 text_position->text_offset_ = static_cast<int>(*(--iterator));
708 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 694 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
709 } 695 }
710 696
711 // If the word boundary is in the same subtree, return a position rooted at 697 // If the word boundary is in the same subtree, return a position rooted at
712 // the current position. 698 // the current position.
713 // This is necessary because we don't want to return any position that might 699 // This is necessary because we don't want to return any position that might
714 // be in the shadow DOM if the original position was not. 700 // be in the shadow DOM if the original position was not.
715 AXPositionInstance common_ancestor = 701 AXPositionInstance common_ancestor =
716 text_position->LowestCommonAncestor(*this); 702 text_position->LowestCommonAncestor(*this);
717 if (GetAnchor() == common_ancestor->GetAnchor()) 703 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
718 text_position = std::move(common_ancestor); 704 text_position = std::move(common_ancestor);
719 705
720 if (was_tree_position) 706 if (was_tree_position)
721 text_position = text_position->AsTreePosition(); 707 text_position = text_position->AsTreePosition();
722 return text_position; 708 return text_position;
723 } 709 }
724 710
725 // Word end positions are one past the last character of the word. 711 // Word end positions are one past the last character of the word.
726 AXPositionInstance CreateNextWordEndPosition() const { 712 AXPositionInstance CreateNextWordEndPosition() const {
727 bool was_tree_position = IsTreePosition(); 713 bool was_tree_position = IsTreePosition();
(...skipping 25 matching lines...) Expand all
753 text_position->text_offset_ = static_cast<int>(*iterator); 739 text_position->text_offset_ = static_cast<int>(*iterator);
754 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 740 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
755 } 741 }
756 742
757 // If the word boundary is in the same subtree, return a position rooted at 743 // If the word boundary is in the same subtree, return a position rooted at
758 // the current position. 744 // the current position.
759 // This is necessary because we don't want to return any position that might 745 // This is necessary because we don't want to return any position that might
760 // be in the shadow DOM if the original position was not. 746 // be in the shadow DOM if the original position was not.
761 AXPositionInstance common_ancestor = 747 AXPositionInstance common_ancestor =
762 text_position->LowestCommonAncestor(*this); 748 text_position->LowestCommonAncestor(*this);
763 if (GetAnchor() == common_ancestor->GetAnchor()) 749 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
764 text_position = std::move(common_ancestor); 750 text_position = std::move(common_ancestor);
765 751
766 if (was_tree_position) 752 if (was_tree_position)
767 text_position = text_position->AsTreePosition(); 753 text_position = text_position->AsTreePosition();
768 return text_position; 754 return text_position;
769 } 755 }
770 756
771 // Word end positions are one past the last character of the word. 757 // Word end positions are one past the last character of the word.
772 AXPositionInstance CreatePreviousWordEndPosition() const { 758 AXPositionInstance CreatePreviousWordEndPosition() const {
773 bool was_tree_position = IsTreePosition(); 759 bool was_tree_position = IsTreePosition();
(...skipping 27 matching lines...) Expand all
801 text_position->text_offset_ = static_cast<int>(*(--iterator)); 787 text_position->text_offset_ = static_cast<int>(*(--iterator));
802 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 788 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
803 } 789 }
804 790
805 // If the word boundary is in the same subtree, return a position rooted at 791 // If the word boundary is in the same subtree, return a position rooted at
806 // the current position. 792 // the current position.
807 // This is necessary because we don't want to return any position that might 793 // This is necessary because we don't want to return any position that might
808 // be in the shadow DOM if the original position was not. 794 // be in the shadow DOM if the original position was not.
809 AXPositionInstance common_ancestor = 795 AXPositionInstance common_ancestor =
810 text_position->LowestCommonAncestor(*this); 796 text_position->LowestCommonAncestor(*this);
811 if (GetAnchor() == common_ancestor->GetAnchor()) 797 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
812 text_position = std::move(common_ancestor); 798 text_position = std::move(common_ancestor);
813 799
814 if (was_tree_position) 800 if (was_tree_position)
815 text_position = text_position->AsTreePosition(); 801 text_position = text_position->AsTreePosition();
816 return text_position; 802 return text_position;
817 } 803 }
818 804
819 AXPositionInstance CreateNextLineStartPosition() const { 805 AXPositionInstance CreateNextLineStartPosition() const {
820 bool was_tree_position = IsTreePosition(); 806 bool was_tree_position = IsTreePosition();
821 AXPositionInstance text_position = AsLeafTextPosition(); 807 AXPositionInstance text_position = AsLeafTextPosition();
(...skipping 13 matching lines...) Expand all
835 text_position = text_position->CreateNextTextAnchorPosition(); 821 text_position = text_position->CreateNextTextAnchorPosition();
836 if (text_position->IsNullPosition()) 822 if (text_position->IsNullPosition())
837 return text_position; 823 return text_position;
838 824
839 // If the line boundary is in the same subtree, return a position rooted at 825 // If the line boundary is in the same subtree, return a position rooted at
840 // the current position. 826 // the current position.
841 // This is necessary because we don't want to return any position that might 827 // This is necessary because we don't want to return any position that might
842 // be in the shadow DOM if the original position was not. 828 // be in the shadow DOM if the original position was not.
843 AXPositionInstance common_ancestor = 829 AXPositionInstance common_ancestor =
844 text_position->LowestCommonAncestor(*this); 830 text_position->LowestCommonAncestor(*this);
845 if (GetAnchor() == common_ancestor->GetAnchor()) 831 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
846 text_position = std::move(common_ancestor); 832 text_position = std::move(common_ancestor);
847 833
848 if (was_tree_position) 834 if (was_tree_position)
849 text_position = text_position->AsTreePosition(); 835 text_position = text_position->AsTreePosition();
850 return text_position; 836 return text_position;
851 } 837 }
852 838
853 AXPositionInstance CreatePreviousLineStartPosition() const { 839 AXPositionInstance CreatePreviousLineStartPosition() const {
854 bool was_tree_position = IsTreePosition(); 840 bool was_tree_position = IsTreePosition();
855 AXPositionInstance text_position = AsLeafTextPosition(); 841 AXPositionInstance text_position = AsLeafTextPosition();
(...skipping 11 matching lines...) Expand all
867 text_position = text_position->AsLeafTextPosition(); 853 text_position = text_position->AsLeafTextPosition();
868 if (text_position->IsNullPosition()) 854 if (text_position->IsNullPosition())
869 return text_position; 855 return text_position;
870 856
871 // If the line boundary is in the same subtree, return a position rooted at 857 // If the line boundary is in the same subtree, return a position rooted at
872 // the current position. 858 // the current position.
873 // This is necessary because we don't want to return any position that might 859 // This is necessary because we don't want to return any position that might
874 // be in the shadow DOM if the original position was not. 860 // be in the shadow DOM if the original position was not.
875 AXPositionInstance common_ancestor = 861 AXPositionInstance common_ancestor =
876 text_position->LowestCommonAncestor(*this); 862 text_position->LowestCommonAncestor(*this);
877 if (GetAnchor() == common_ancestor->GetAnchor()) 863 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
878 text_position = std::move(common_ancestor); 864 text_position = std::move(common_ancestor);
879 865
880 if (was_tree_position) 866 if (was_tree_position)
881 text_position = text_position->AsTreePosition(); 867 text_position = text_position->AsTreePosition();
882 return text_position; 868 return text_position;
883 } 869 }
884 870
885 // Line end positions are one past the last character of the line, excluding 871 // Line end positions are one past the last character of the line, excluding
886 // any newline characters. 872 // any newline characters.
887 AXPositionInstance CreateNextLineEndPosition() const { 873 AXPositionInstance CreateNextLineEndPosition() const {
(...skipping 19 matching lines...) Expand all
907 if (text_position->IsNullPosition()) 893 if (text_position->IsNullPosition())
908 return text_position; 894 return text_position;
909 text_position = text_position->CreatePositionAtEndOfAnchor(); 895 text_position = text_position->CreatePositionAtEndOfAnchor();
910 896
911 // If the line boundary is in the same subtree, return a position rooted at 897 // If the line boundary is in the same subtree, return a position rooted at
912 // the current position. 898 // the current position.
913 // This is necessary because we don't want to return any position that might 899 // This is necessary because we don't want to return any position that might
914 // be in the shadow DOM if the original position was not. 900 // be in the shadow DOM if the original position was not.
915 AXPositionInstance common_ancestor = 901 AXPositionInstance common_ancestor =
916 text_position->LowestCommonAncestor(*this); 902 text_position->LowestCommonAncestor(*this);
917 if (GetAnchor() == common_ancestor->GetAnchor()) 903 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
918 text_position = std::move(common_ancestor); 904 text_position = std::move(common_ancestor);
919 905
920 if (was_tree_position) 906 if (was_tree_position)
921 text_position = text_position->AsTreePosition(); 907 text_position = text_position->AsTreePosition();
922 return text_position; 908 return text_position;
923 } 909 }
924 910
925 // Line end positions are one past the last character of the line, excluding 911 // Line end positions are one past the last character of the line, excluding
926 // any newline characters. 912 // any newline characters.
927 AXPositionInstance CreatePreviousLineEndPosition() const { 913 AXPositionInstance CreatePreviousLineEndPosition() const {
(...skipping 15 matching lines...) Expand all
943 if (text_position->IsNullPosition()) 929 if (text_position->IsNullPosition())
944 return text_position; 930 return text_position;
945 text_position = text_position->CreatePositionAtEndOfAnchor(); 931 text_position = text_position->CreatePositionAtEndOfAnchor();
946 932
947 // If the line boundary is in the same subtree, return a position rooted at 933 // If the line boundary is in the same subtree, return a position rooted at
948 // the current position. 934 // the current position.
949 // This is necessary because we don't want to return any position that might 935 // This is necessary because we don't want to return any position that might
950 // be in the shadow DOM if the original position was not. 936 // be in the shadow DOM if the original position was not.
951 AXPositionInstance common_ancestor = 937 AXPositionInstance common_ancestor =
952 text_position->LowestCommonAncestor(*this); 938 text_position->LowestCommonAncestor(*this);
953 if (GetAnchor() == common_ancestor->GetAnchor()) 939 if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
954 text_position = std::move(common_ancestor); 940 text_position = std::move(common_ancestor);
955 941
956 if (was_tree_position) 942 if (was_tree_position)
957 text_position = text_position->AsTreePosition(); 943 text_position = text_position->AsTreePosition();
958 return text_position; 944 return text_position;
959 } 945 }
960 946
961 // TODO(nektar): Add sentence and paragraph navigation methods. 947 // TODO(nektar): Add sentence and paragraph navigation methods.
962 948
963 // Abstract methods. 949 // Abstract methods.
964 950
965 // Returns the text that is present inside the anchor node, including any text 951 // Returns the text that is present inside the anchor node, including any text
966 // found in descendant nodes. 952 // found in descendant nodes.
967 virtual base::string16 GetInnerText() const = 0; 953 virtual base::string16 GetInnerText() const = 0;
968 954
969 protected: 955 protected:
970 AXPosition(const AXPosition<AXPositionType, AXNodeType>& other) = default; 956 AXPositionBase(const AXPositionBase& other) = default;
971 virtual AXPosition<AXPositionType, AXNodeType>& operator=( 957 virtual AXPositionBase& operator=(const AXPositionBase& other) = default;
972 const AXPosition<AXPositionType, AXNodeType>& other) = default;
973 958
974 virtual void Initialize(AXPositionKind kind, 959 void Initialize(AXPositionKind kind,
975 int tree_id, 960 int tree_id,
976 int32_t anchor_id, 961 int32_t anchor_id,
977 int child_index, 962 int child_index,
978 int text_offset, 963 int text_offset,
979 AXTextAffinity affinity) { 964 AXTextAffinity affinity) {
980 kind_ = kind; 965 kind_ = kind;
981 tree_id_ = tree_id; 966 tree_id_ = tree_id;
982 anchor_id_ = anchor_id; 967 anchor_id_ = anchor_id;
983 child_index_ = child_index; 968 child_index_ = child_index;
984 text_offset_ = text_offset; 969 text_offset_ = text_offset;
985 affinity_ = affinity; 970 affinity_ = affinity;
986 971
987 if (!GetAnchor() || kind_ == AXPositionKind::NULL_POSITION || 972 if (!GetOpaqueAnchor() || kind_ == AXPositionKind::NULL_POSITION ||
988 (kind_ == AXPositionKind::TREE_POSITION && 973 (kind_ == AXPositionKind::TREE_POSITION &&
989 (child_index_ != BEFORE_TEXT && 974 (child_index_ != BEFORE_TEXT &&
990 (child_index_ < 0 || child_index_ > AnchorChildCount()))) || 975 (child_index_ < 0 || child_index_ > AnchorChildCount()))) ||
991 (kind_ == AXPositionKind::TEXT_POSITION && 976 (kind_ == AXPositionKind::TEXT_POSITION &&
992 (text_offset_ < 0 || text_offset_ > MaxTextOffset()))) { 977 (text_offset_ < 0 || text_offset_ > MaxTextOffset()))) {
993 // Reset to the null position. 978 // Reset to the null position.
994 kind_ = AXPositionKind::NULL_POSITION; 979 kind_ = AXPositionKind::NULL_POSITION;
995 tree_id_ = INVALID_TREE_ID; 980 tree_id_ = INVALID_TREE_ID;
996 anchor_id_ = INVALID_ANCHOR_ID; 981 anchor_id_ = INVALID_ANCHOR_ID;
997 child_index_ = INVALID_INDEX; 982 child_index_ = INVALID_INDEX;
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 return offset_in_parent; 1069 return offset_in_parent;
1085 } 1070 }
1086 1071
1087 // Abstract methods. 1072 // Abstract methods.
1088 virtual void AnchorChild(int child_index, 1073 virtual void AnchorChild(int child_index,
1089 int* tree_id, 1074 int* tree_id,
1090 int32_t* child_id) const = 0; 1075 int32_t* child_id) const = 0;
1091 virtual int AnchorChildCount() const = 0; 1076 virtual int AnchorChildCount() const = 0;
1092 virtual int AnchorIndexInParent() const = 0; 1077 virtual int AnchorIndexInParent() const = 0;
1093 virtual void AnchorParent(int* tree_id, int32_t* parent_id) const = 0; 1078 virtual void AnchorParent(int* tree_id, int32_t* parent_id) const = 0;
1094 virtual AXNodeType* GetNodeInTree(int tree_id, int32_t node_id) const = 0; 1079 virtual OpaqueAnchor GetOpaqueNodeInTree(int tree_id,
1080 int32_t node_id) const = 0;
1095 // Returns the length of the text that is present inside the anchor node, 1081 // Returns the length of the text that is present inside the anchor node,
1096 // including any text found in descendant text nodes. 1082 // including any text found in descendant text nodes.
1097 virtual int MaxTextOffset() const = 0; 1083 virtual int MaxTextOffset() const = 0;
1098 // Returns the length of text that this anchor node takes up in its parent. 1084 // Returns the length of text that this anchor node takes up in its parent.
1099 // On some platforms, embedded objects are represented in their parent with a 1085 // On some platforms, embedded objects are represented in their parent with a
1100 // single embedded object character. 1086 // single embedded object character.
1101 virtual int MaxTextOffsetInParent() const { return MaxTextOffset(); } 1087 virtual int MaxTextOffsetInParent() const;
1102 virtual bool IsInLineBreak() const = 0; 1088 virtual bool IsInLineBreak() const = 0;
1103 virtual std::vector<int32_t> GetWordStartOffsets() const = 0; 1089 virtual std::vector<int32_t> GetWordStartOffsets() const = 0;
1104 virtual std::vector<int32_t> GetWordEndOffsets() const = 0; 1090 virtual std::vector<int32_t> GetWordEndOffsets() const = 0;
1105 virtual int32_t GetNextOnLineID(int32_t node_id) const = 0; 1091 virtual int32_t GetNextOnLineID(int32_t node_id) const = 0;
1106 virtual int32_t GetPreviousOnLineID(int32_t node_id) const = 0; 1092 virtual int32_t GetPreviousOnLineID(int32_t node_id) const = 0;
1107 1093
1108 private: 1094 private:
1109 AXPositionKind kind_; 1095 AXPositionKind kind_;
1110 int tree_id_; 1096 int tree_id_;
1111 int32_t anchor_id_; 1097 int32_t anchor_id_;
1112 1098
1113 // For text positions, |child_index_| is initially set to |-1| and only 1099 // For text positions, |child_index_| is initially set to |-1| and only
1114 // computed on demand. The same with tree positions and |text_offset_|. 1100 // computed on demand. The same with tree positions and |text_offset_|.
1115 int child_index_; 1101 int child_index_;
1116 int text_offset_; 1102 int text_offset_;
1117 1103
1118 // TODO(nektar): Get rid of affinity and make Blink handle affinity 1104 // TODO(nektar): Get rid of affinity and make Blink handle affinity
1119 // internally since inline text objects don't span lines. 1105 // internally since inline text objects don't span lines.
1120 AXTextAffinity affinity_; 1106 AXTextAffinity affinity_;
1121 }; 1107 };
1122 1108
1123 template <class AXPositionType, class AXNodeType> 1109 template <class AXPositionType, class AXNodeType>
1124 const int AXPosition<AXPositionType, AXNodeType>::INVALID_TREE_ID; 1110 class AXPosition : public AXPositionBase {
1125 template <class AXPositionType, class AXNodeType> 1111 public:
1126 const int32_t AXPosition<AXPositionType, AXNodeType>::INVALID_ANCHOR_ID; 1112 using AXPositionInstance = AXPositionBase::AXPositionInstance;
1127 template <class AXPositionType, class AXNodeType> 1113 using ConcreteNodeType = AXNodeType;
1128 const int AXPosition<AXPositionType, AXNodeType>::BEFORE_TEXT; 1114 using ConcreteInstance =
1129 template <class AXPositionType, class AXNodeType> 1115 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>>;
1130 const int AXPosition<AXPositionType, AXNodeType>::INVALID_INDEX;
1131 template <class AXPositionType, class AXNodeType>
1132 const int AXPosition<AXPositionType, AXNodeType>::INVALID_OFFSET;
1133 1116
1134 template <class AXPositionType, class AXNodeType> 1117 static ConcreteInstance CreateConcreteNullPosition() {
1135 bool operator==(const AXPosition<AXPositionType, AXNodeType>& first, 1118 ConcreteInstance new_position(new AXPositionType());
1136 const AXPosition<AXPositionType, AXNodeType>& second) { 1119 new_position->Initialize(AXPositionKind::NULL_POSITION, INVALID_TREE_ID,
1137 if (first.IsNullPosition() && second.IsNullPosition()) 1120 INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET,
1138 return true; 1121 AX_TEXT_AFFINITY_DOWNSTREAM);
1139 return first.tree_id() == second.tree_id() && 1122 return new_position;
1140 first.anchor_id() == second.anchor_id() && 1123 }
1141 first.child_index() == second.child_index() &&
1142 first.text_offset() == second.text_offset() &&
1143 first.affinity() == second.affinity();
1144 }
1145 1124
1146 template <class AXPositionType, class AXNodeType> 1125 static ConcreteInstance CreateConcreteTreePosition(int tree_id,
1147 bool operator!=(const AXPosition<AXPositionType, AXNodeType>& first, 1126 int32_t anchor_id,
1148 const AXPosition<AXPositionType, AXNodeType>& second) { 1127 int child_index) {
1149 return !(first == second); 1128 ConcreteInstance new_position(new AXPositionType());
1150 } 1129 new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
1130 child_index, INVALID_OFFSET,
1131 AX_TEXT_AFFINITY_DOWNSTREAM);
1132 return new_position;
1133 }
1151 1134
1152 template <class AXPositionType, class AXNodeType> 1135 static ConcreteInstance CreateConcreteTextPosition(int tree_id,
1153 bool operator<(const AXPosition<AXPositionType, AXNodeType>& first, 1136 int32_t anchor_id,
1154 const AXPosition<AXPositionType, AXNodeType>& second) { 1137 int text_offset,
1155 if (first.IsNullPosition() || second.IsNullPosition()) 1138 AXTextAffinity affinity) {
1156 return false; 1139 ConcreteInstance new_position(new AXPositionType());
1140 new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id,
1141 INVALID_INDEX, text_offset, affinity);
1142 return new_position;
1143 }
1157 1144
1158 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> first_ancestor = 1145 static ConcreteInstance FromBase(AXPositionInstance instance) {
1159 first.LowestCommonAncestor(second)->AsTreePosition(); 1146 return ConcreteInstance(static_cast<AXPosition*>(instance.release()));
1160 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> second_ancestor = 1147 }
1161 second.LowestCommonAncestor(first)->AsTreePosition();
1162 DCHECK_EQ(first_ancestor->GetAnchor(), second_ancestor->GetAnchor());
1163 return !first_ancestor->IsNullPosition() &&
1164 first_ancestor->AsTextPosition()->text_offset() <
1165 second_ancestor->AsTextPosition()->text_offset();
1166 }
1167 1148
1168 template <class AXPositionType, class AXNodeType> 1149 AXNodeType* GetAnchor() const {
1169 bool operator<=(const AXPosition<AXPositionType, AXNodeType>& first, 1150 return static_cast<AXNodeType*>(GetOpaqueAnchor());
1170 const AXPosition<AXPositionType, AXNodeType>& second) { 1151 }
1171 return first == second || first < second; 1152 virtual ConcreteInstance CloneConcrete() const = 0;
1172 } 1153 virtual AXNodeType* GetNodeInTree(int tree_id, int32_t node_id) const = 0;
1173 1154
1174 template <class AXPositionType, class AXNodeType> 1155 AXPositionInstance Clone() const override {
1175 bool operator>(const AXPosition<AXPositionType, AXNodeType>& first, 1156 return base::WrapUnique<AXPositionBase>(CloneConcrete().release());
1176 const AXPosition<AXPositionType, AXNodeType>& second) { 1157 }
1177 if (first.IsNullPosition() || second.IsNullPosition()) 1158 virtual OpaqueAnchor GetOpaqueNodeInTree(int tree_id, int32_t node_id) const {
1178 return false; 1159 return GetNodeInTree(tree_id, node_id);
1160 }
1179 1161
1180 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> first_ancestor = 1162 AXPositionInstance CreateNullPosition() const override {
1181 first.LowestCommonAncestor(second)->AsTreePosition(); 1163 return base::WrapUnique<AXPositionBase>(
1182 std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> second_ancestor = 1164 CreateConcreteNullPosition().release());
1183 second.LowestCommonAncestor(first)->AsTreePosition(); 1165 }
1184 DCHECK_EQ(first_ancestor->GetAnchor(), second_ancestor->GetAnchor());
1185 return !first_ancestor->IsNullPosition() &&
1186 first_ancestor->AsTextPosition()->text_offset() >
1187 second_ancestor->AsTextPosition()->text_offset();
1188 }
1189 1166
1190 template <class AXPositionType, class AXNodeType> 1167 AXPositionInstance CreateTreePosition(int tree_id,
1191 bool operator>=(const AXPosition<AXPositionType, AXNodeType>& first, 1168 int32_t anchor_id,
1192 const AXPosition<AXPositionType, AXNodeType>& second) { 1169 int child_index) const override {
1193 return first == second || first > second; 1170 return base::WrapUnique<AXPositionBase>(
1194 } 1171 CreateConcreteTreePosition(tree_id, anchor_id, child_index).release());
1172 }
1173
1174 AXPositionInstance CreateTextPosition(
1175 int tree_id,
1176 int32_t anchor_id,
1177 int text_offset,
1178 AXTextAffinity affinity) const override {
1179 return base::WrapUnique<AXPositionBase>(
1180 CreateConcreteTextPosition(tree_id, anchor_id, text_offset, affinity)
1181 .release());
1182 }
1183 };
1195 1184
1196 } // namespace ui 1185 } // namespace ui
1197 1186
1198 #endif // UI_ACCESSIBILITY_AX_POSITION_H_ 1187 #endif // UI_ACCESSIBILITY_AX_POSITION_H_
OLDNEW
« no previous file with comments | « ui/accessibility/ax_node_position_unittest.cc ('k') | ui/accessibility/ax_position.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698