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

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

Issue 2806773002: Switched to using |AXPosition| for calculating word and line boundaries on Windows. (Closed)
Patch Set: Fixed line boundaries. Created 3 years, 8 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
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 <algorithm> 10 #include <algorithm>
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 if (child_index_ == BEFORE_TEXT) { 124 if (child_index_ == BEFORE_TEXT) {
125 str_child_index = "before_text"; 125 str_child_index = "before_text";
126 } else if (child_index_ == INVALID_INDEX) { 126 } else if (child_index_ == INVALID_INDEX) {
127 str_child_index = "invalid"; 127 str_child_index = "invalid";
128 } else { 128 } else {
129 str_child_index = base::IntToString(child_index_); 129 str_child_index = base::IntToString(child_index_);
130 } 130 }
131 str = "TreePosition tree_id=" + base::IntToString(tree_id_) + 131 str = "TreePosition tree_id=" + base::IntToString(tree_id_) +
132 " anchor_id=" + base::IntToString(anchor_id_) + " child_index=" + 132 " anchor_id=" + base::IntToString(anchor_id_) + " child_index=" +
133 str_child_index; 133 str_child_index;
134 break;
134 } 135 }
135 case AXPositionKind::TEXT_POSITION: { 136 case AXPositionKind::TEXT_POSITION: {
136 std::string str_text_offset; 137 std::string str_text_offset;
137 if (text_offset_ == INVALID_OFFSET) { 138 if (text_offset_ == INVALID_OFFSET) {
138 str_text_offset = "invalid"; 139 str_text_offset = "invalid";
139 } else { 140 } else {
140 str_text_offset = base::IntToString(text_offset_); 141 str_text_offset = base::IntToString(text_offset_);
141 } 142 }
142 str = "TextPosition tree_id=" + base::IntToString(tree_id_) + 143 str = "TextPosition tree_id=" + base::IntToString(tree_id_) +
143 " anchor_id=" + base::IntToString(anchor_id_) + " text_offset=" + 144 " anchor_id=" + base::IntToString(anchor_id_) + " text_offset=" +
144 str_text_offset + " affinity=" + 145 str_text_offset + " affinity=" +
145 ui::ToString(static_cast<AXTextAffinity>(affinity_)); 146 ui::ToString(static_cast<AXTextAffinity>(affinity_));
147 break;
146 } 148 }
147 } 149 }
148 150
149 if (!IsTextPosition() || text_offset_ > MaxTextOffset()) 151 if (!IsTextPosition() || text_offset_ > MaxTextOffset())
150 return str; 152 return str;
151 153
152 std::string text = base::UTF16ToUTF8(GetInnerText()); 154 std::string text = base::UTF16ToUTF8(GetInnerText());
153 DCHECK_GE(text_offset_, 0); 155 DCHECK_GE(text_offset_, 0);
154 DCHECK_LE(text_offset_, static_cast<int>(text.length())); 156 DCHECK_LE(text_offset_, static_cast<int>(text.length()));
155 std::string annotated_text; 157 std::string annotated_text;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 return false; 220 return false;
219 case AXPositionKind::TREE_POSITION: 221 case AXPositionKind::TREE_POSITION:
220 return child_index_ == AnchorChildCount(); 222 return child_index_ == AnchorChildCount();
221 case AXPositionKind::TEXT_POSITION: 223 case AXPositionKind::TEXT_POSITION:
222 return text_offset_ == MaxTextOffset(); 224 return text_offset_ == MaxTextOffset();
223 } 225 }
224 226
225 return false; 227 return false;
226 } 228 }
227 229
230 bool AtStartOfWord() const {
231 AXPositionInstance text_position = AsLeafTextPosition();
232 switch (text_position->kind_) {
233 case AXPositionKind::NULL_POSITION:
234 return false;
235 case AXPositionKind::TREE_POSITION:
236 NOTREACHED();
237 return false;
238 case AXPositionKind::TEXT_POSITION: {
239 const std::vector<int32_t> word_starts =
240 text_position->GetWordStartOffsets();
241 auto iterator =
242 std::find(word_starts.begin(), word_starts.end(),
243 static_cast<int32_t>(text_position->text_offset_));
244 return iterator != word_starts.end();
245 }
246 }
247 return false;
248 }
249
250 bool AtEndOfWord() const {
251 AXPositionInstance text_position = AsLeafTextPosition();
252 switch (text_position->kind_) {
253 case AXPositionKind::NULL_POSITION:
254 return false;
255 case AXPositionKind::TREE_POSITION:
256 NOTREACHED();
257 return false;
258 case AXPositionKind::TEXT_POSITION: {
259 const std::vector<int32_t> word_ends =
260 text_position->GetWordEndOffsets();
261 auto iterator =
262 std::find(word_ends.begin(), word_ends.end(),
263 static_cast<int32_t>(text_position->text_offset_));
264 return iterator != word_ends.end();
265 }
266 }
267 return false;
268 }
269
270 bool AtStartOfLine() const {
271 AXPositionInstance text_position = AsLeafTextPosition();
272 switch (text_position->kind_) {
273 case AXPositionKind::NULL_POSITION:
274 return false;
275 case AXPositionKind::TREE_POSITION:
276 NOTREACHED();
277 return false;
278 case AXPositionKind::TEXT_POSITION:
279 return !text_position->IsInLineBreak() &&
280 GetPreviousOnLineID(text_position->anchor_id_) ==
281 INVALID_ANCHOR_ID &&
282 text_position->AtStartOfAnchor();
283 }
284 return false;
285 }
286
287 bool AtEndOfLine() const {
288 AXPositionInstance text_position = AsLeafTextPosition();
289 switch (text_position->kind_) {
290 case AXPositionKind::NULL_POSITION:
291 return false;
292 case AXPositionKind::TREE_POSITION:
293 NOTREACHED();
294 return false;
295 case AXPositionKind::TEXT_POSITION:
296 return !text_position->IsInLineBreak() &&
297 GetNextOnLineID(text_position->anchor_id_) ==
298 INVALID_ANCHOR_ID &&
299 text_position->AtEndOfAnchor();
300 }
301 return false;
302 }
303
228 // This method returns a position instead of a node because this allows us to 304 // This method returns a position instead of a node because this allows us to
229 // return the corresponding text offset or child index in the ancestor that 305 // return the corresponding text offset or child index in the ancestor that
230 // relates to the current position. 306 // relates to the current position.
231 // Also, this method uses position instead of tree logic to traverse the tree, 307 // Also, this method uses position instead of tree logic to traverse the tree,
232 // because positions can handle moving across multiple trees, while trees 308 // because positions can handle moving across multiple trees, while trees
233 // cannot. 309 // cannot.
234 AXPositionInstance LowestCommonAncestor( 310 AXPositionInstance LowestCommonAncestor(
235 const AXPosition<AXPositionType, AXNodeType>& second) const { 311 const AXPosition<AXPositionType, AXNodeType>& second) const {
236 if (IsNullPosition() || second.IsNullPosition()) 312 if (IsNullPosition() || second.IsNullPosition())
237 return CreateNullPosition(); 313 return CreateNullPosition();
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 AXPositionInstance CreateParentPosition() const { 518 AXPositionInstance CreateParentPosition() const {
443 if (IsNullPosition()) 519 if (IsNullPosition())
444 return CreateNullPosition(); 520 return CreateNullPosition();
445 521
446 int tree_id = INVALID_TREE_ID; 522 int tree_id = INVALID_TREE_ID;
447 int32_t parent_id = INVALID_ANCHOR_ID; 523 int32_t parent_id = INVALID_ANCHOR_ID;
448 AnchorParent(&tree_id, &parent_id); 524 AnchorParent(&tree_id, &parent_id);
449 if (tree_id == INVALID_TREE_ID || parent_id == INVALID_ANCHOR_ID) 525 if (tree_id == INVALID_TREE_ID || parent_id == INVALID_ANCHOR_ID)
450 return CreateNullPosition(); 526 return CreateNullPosition();
451 527
452 DCHECK_NE(tree_id, INVALID_TREE_ID);
453 DCHECK_NE(parent_id, INVALID_ANCHOR_ID);
454 switch (kind_) { 528 switch (kind_) {
455 case AXPositionKind::NULL_POSITION: 529 case AXPositionKind::NULL_POSITION:
456 NOTREACHED(); 530 NOTREACHED();
457 return CreateNullPosition(); 531 return CreateNullPosition();
458 case AXPositionKind::TREE_POSITION: 532 case AXPositionKind::TREE_POSITION:
459 return CreateTreePosition(tree_id, parent_id, AnchorIndexInParent()); 533 return CreateTreePosition(tree_id, parent_id, AnchorIndexInParent());
460 case AXPositionKind::TEXT_POSITION: 534 case AXPositionKind::TEXT_POSITION: {
461 // Make sure that our affinity is propagated to our parent because by 535 // If our parent contains all our text, we need to maintain the affinity
462 // design our parent includes all our text. 536 // and the text offset. Otherwise, we return a position that is either
463 return CreateTextPosition(tree_id, parent_id, 537 // before or after the child and we don't maintain the affinity when the
464 AnchorTextOffsetInParent() + text_offset_, 538 // position is after the child.
465 affinity_); 539 int parent_offset = AnchorTextOffsetInParent();
540 AXTextAffinity parent_affinity = affinity_;
541 if (MaxTextOffset() == MaxTextOffsetInParent()) {
542 parent_offset += text_offset_;
543 } else if (text_offset_ > 0) {
544 parent_offset += MaxTextOffsetInParent();
545 parent_affinity = AX_TEXT_AFFINITY_DOWNSTREAM;
546 }
547 return CreateTextPosition(tree_id, parent_id, parent_offset,
548 parent_affinity);
549 }
466 } 550 }
467 551
468 return CreateNullPosition(); 552 return CreateNullPosition();
469 } 553 }
470 554
471 // Creates a position using the next text-only node as its anchor. 555 // Creates a position using the next text-only node as its anchor.
472 // Assumes that text-only nodes are leaf nodes. 556 // Assumes that text-only nodes are leaf nodes.
473 AXPositionInstance CreateNextTextAnchorPosition() const { 557 AXPositionInstance CreateNextTextAnchorPosition() const {
474 AXPositionInstance next_leaf(CreateNextAnchorPosition()); 558 AXPositionInstance next_leaf(CreateNextAnchorPosition());
475 while (!next_leaf->IsNullPosition() && next_leaf->AnchorChildCount()) { 559 while (!next_leaf->IsNullPosition() && next_leaf->AnchorChildCount()) {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 text_position = text_position->AsTreePosition(); 625 text_position = text_position->AsTreePosition();
542 return text_position; 626 return text_position;
543 } 627 }
544 628
545 AXPositionInstance CreateNextWordStartPosition() const { 629 AXPositionInstance CreateNextWordStartPosition() const {
546 bool was_tree_position = IsTreePosition(); 630 bool was_tree_position = IsTreePosition();
547 AXPositionInstance text_position = AsLeafTextPosition(); 631 AXPositionInstance text_position = AsLeafTextPosition();
548 if (text_position->IsNullPosition()) 632 if (text_position->IsNullPosition())
549 return text_position; 633 return text_position;
550 634
551 // Ignore any nodes with no text or no word boundaries.
552 while (!text_position->IsNullPosition() &&
553 (!text_position->MaxTextOffset() ||
554 text_position->GetWordStartOffsets().empty())) {
555 text_position = text_position->CreateNextTextAnchorPosition();
556 }
557
558 if (text_position->IsNullPosition())
559 return text_position;
560
561 const std::vector<int32_t> word_starts = 635 const std::vector<int32_t> word_starts =
562 text_position->GetWordStartOffsets(); 636 text_position->GetWordStartOffsets();
563 auto iterator = 637 auto iterator =
564 std::upper_bound(word_starts.begin(), word_starts.end(), 638 std::upper_bound(word_starts.begin(), word_starts.end(),
565 static_cast<int32_t>(text_position->text_offset_)); 639 static_cast<int32_t>(text_position->text_offset_));
566 if (iterator == word_starts.end()) { 640 if (iterator == word_starts.end()) {
641 // Ignore any nodes with no text or no word boundaries.
567 do { 642 do {
568 text_position = text_position->CreateNextTextAnchorPosition(); 643 text_position = text_position->CreateNextTextAnchorPosition();
569 } while (!text_position->IsNullPosition() && 644 } while (!text_position->IsNullPosition() &&
570 (!text_position->MaxTextOffset() || 645 (!text_position->MaxTextOffset() ||
571 text_position->GetWordStartOffsets().empty())); 646 text_position->GetWordStartOffsets().empty()));
572 if (text_position->IsNullPosition()) 647 if (text_position->IsNullPosition())
573 return text_position; 648 return text_position;
574 649
575 // In case there are some non-word characters in front of the first word
576 // in this text node.
577 const std::vector<int32_t> word_starts = 650 const std::vector<int32_t> word_starts =
578 text_position->GetWordStartOffsets(); 651 text_position->GetWordStartOffsets();
652 DCHECK(!word_starts.empty());
579 text_position->text_offset_ = static_cast<int>(word_starts[0]); 653 text_position->text_offset_ = static_cast<int>(word_starts[0]);
580 } else { 654 } else {
581 text_position->text_offset_ = static_cast<int>(*iterator); 655 text_position->text_offset_ = static_cast<int>(*iterator);
582 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 656 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
583 } 657 }
584 658
585 // If the word boundary is in the same subtree, return a position rooted at 659 // If the word boundary is in the same subtree, return a position rooted at
586 // the current position. 660 // the current position.
587 // This is necessary because we don't want to return any position that might 661 // This is necessary because we don't want to return any position that might
588 // be in the shadow DOM if the original position was not. 662 // be in the shadow DOM if the original position was not.
589 AXPositionInstance common_ancestor = 663 AXPositionInstance common_ancestor =
590 text_position->LowestCommonAncestor(*this); 664 text_position->LowestCommonAncestor(*this);
591 if (GetAnchor() == common_ancestor->GetAnchor()) 665 if (GetAnchor() == common_ancestor->GetAnchor())
592 return common_ancestor; 666 text_position = std::move(common_ancestor);
593 667
594 if (was_tree_position) 668 if (was_tree_position)
595 text_position = text_position->AsTreePosition(); 669 text_position = text_position->AsTreePosition();
596 return text_position; 670 return text_position;
597 } 671 }
598 672
599 AXPositionInstance CreatePreviousWordStartPosition() const { 673 AXPositionInstance CreatePreviousWordStartPosition() const {
600 bool was_tree_position = IsTreePosition(); 674 bool was_tree_position = IsTreePosition();
601 AXPositionInstance text_position = AsLeafTextPosition(); 675 AXPositionInstance text_position = AsLeafTextPosition();
602 if (text_position->IsNullPosition())
603 return text_position;
604 676
605 if (text_position->AtStartOfAnchor()) { 677 if (text_position->AtStartOfAnchor()) {
606 text_position = text_position->CreatePreviousTextAnchorPosition(); 678 text_position = text_position->CreatePreviousTextAnchorPosition();
607 text_position = text_position->CreatePositionAtEndOfAnchor(); 679 text_position = text_position->CreatePositionAtEndOfAnchor();
608 } 680 }
609
610 // Ignore any nodes with no text or no word boundaries.
611 while (!text_position->IsNullPosition() &&
612 (!text_position->MaxTextOffset() ||
613 text_position->GetWordStartOffsets().empty())) {
614 text_position = text_position->CreatePreviousTextAnchorPosition();
615 text_position = text_position->CreatePositionAtEndOfAnchor();
616 }
617
618 if (text_position->IsNullPosition()) 681 if (text_position->IsNullPosition())
619 return text_position; 682 return text_position;
620 683
621 const std::vector<int32_t> word_starts = 684 const std::vector<int32_t> word_starts =
622 text_position->GetWordStartOffsets(); 685 text_position->GetWordStartOffsets();
623 auto iterator = 686 auto iterator =
624 std::lower_bound(word_starts.begin(), word_starts.end(), 687 std::lower_bound(word_starts.begin(), word_starts.end(),
625 static_cast<int32_t>(text_position->text_offset_)); 688 static_cast<int32_t>(text_position->text_offset_));
626 if (iterator == word_starts.begin()) { 689 if (word_starts.empty() || iterator == word_starts.begin()) {
627 // There must be some non-word characters in front of the first word in 690 // Ignore any nodes with no text or no word boundaries.
628 // this text node.
629 do { 691 do {
630 text_position = text_position->CreatePreviousTextAnchorPosition(); 692 text_position = text_position->CreatePreviousTextAnchorPosition();
631 } while (!text_position->IsNullPosition() && 693 } while (!text_position->IsNullPosition() &&
632 (!text_position->MaxTextOffset() || 694 (!text_position->MaxTextOffset() ||
633 text_position->GetWordStartOffsets().empty())); 695 text_position->GetWordStartOffsets().empty()));
634 if (text_position->IsNullPosition()) 696 if (text_position->IsNullPosition())
635 return text_position; 697 return text_position;
636 698
637 const std::vector<int32_t> word_starts = 699 const std::vector<int32_t> word_starts =
638 text_position->GetWordStartOffsets(); 700 text_position->GetWordStartOffsets();
701 DCHECK(!word_starts.empty());
639 text_position->text_offset_ = static_cast<int>(*(word_starts.end() - 1)); 702 text_position->text_offset_ = static_cast<int>(*(word_starts.end() - 1));
640 } else { 703 } else {
641 text_position->text_offset_ = static_cast<int>(*(--iterator)); 704 text_position->text_offset_ = static_cast<int>(*(--iterator));
642 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 705 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
643 } 706 }
644 707
645 // If the word boundary is in the same subtree, return a position rooted at 708 // If the word boundary is in the same subtree, return a position rooted at
646 // the current position. 709 // the current position.
647 // This is necessary because we don't want to return any position that might 710 // This is necessary because we don't want to return any position that might
648 // be in the shadow DOM if the original position was not. 711 // be in the shadow DOM if the original position was not.
649 AXPositionInstance common_ancestor = 712 AXPositionInstance common_ancestor =
650 text_position->LowestCommonAncestor(*this); 713 text_position->LowestCommonAncestor(*this);
651 if (GetAnchor() == common_ancestor->GetAnchor()) 714 if (GetAnchor() == common_ancestor->GetAnchor())
652 return common_ancestor; 715 text_position = std::move(common_ancestor);
653 716
654 if (was_tree_position) 717 if (was_tree_position)
655 text_position = text_position->AsTreePosition(); 718 text_position = text_position->AsTreePosition();
656 return text_position; 719 return text_position;
657 } 720 }
658 721
659 // Word end positions are one past the last character of the word. 722 // Word end positions are one past the last character of the word.
660 AXPositionInstance CreateNextWordEndPosition() const { 723 AXPositionInstance CreateNextWordEndPosition() const {
661 bool was_tree_position = IsTreePosition(); 724 bool was_tree_position = IsTreePosition();
662 AXPositionInstance text_position = AsLeafTextPosition(); 725 AXPositionInstance text_position = AsLeafTextPosition();
726
727 if (text_position->AtEndOfAnchor())
728 text_position = text_position->CreateNextTextAnchorPosition();
663 if (text_position->IsNullPosition()) 729 if (text_position->IsNullPosition())
664 return text_position; 730 return text_position;
665 731
666 if (text_position->AtEndOfAnchor()) 732 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
667 text_position = text_position->CreateNextTextAnchorPosition(); 733 auto iterator =
668 734 std::upper_bound(word_ends.begin(), word_ends.end(),
669 // Ignore any nodes with no text or no word boundaries. 735 static_cast<int32_t>(text_position->text_offset_));
670 while (!text_position->IsNullPosition() &&
671 (!text_position->MaxTextOffset() ||
672 text_position->GetWordEndOffsets().empty())) {
673 text_position = text_position->CreateNextTextAnchorPosition();
674 }
675
676 if (text_position->IsNullPosition())
677 return text_position;
678
679 const std::vector<int> word_ends = text_position->GetWordEndOffsets();
680 auto iterator = std::upper_bound(word_ends.begin(), word_ends.end(),
681 text_position->text_offset_);
682 if (iterator == word_ends.end()) { 736 if (iterator == word_ends.end()) {
683 // We should be in the last word of this text node. 737 // Ignore any nodes with no text or no word boundaries.
684 do { 738 do {
685 text_position = text_position->CreateNextTextAnchorPosition(); 739 text_position = text_position->CreateNextTextAnchorPosition();
686 } while (!text_position->IsNullPosition() && 740 } while (!text_position->IsNullPosition() &&
687 (!text_position->MaxTextOffset() || 741 (!text_position->MaxTextOffset() ||
688 text_position->GetWordEndOffsets().empty())); 742 text_position->GetWordEndOffsets().empty()));
689 if (text_position->IsNullPosition()) 743 if (text_position->IsNullPosition())
690 return text_position; 744 return text_position;
691 745
692 const std::vector<int> word_ends = text_position->GetWordEndOffsets(); 746 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
693 text_position->text_offset_ = word_ends[0]; 747 DCHECK(!word_ends.empty());
748 text_position->text_offset_ = static_cast<int>(word_ends[0]);
694 } else { 749 } else {
695 text_position->text_offset_ = *iterator; 750 text_position->text_offset_ = static_cast<int>(*iterator);
696 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 751 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
697 } 752 }
698 753
699 // If the word boundary is in the same subtree, return a position rooted at 754 // If the word boundary is in the same subtree, return a position rooted at
700 // the current position. 755 // the current position.
701 // This is necessary because we don't want to return any position that might 756 // This is necessary because we don't want to return any position that might
702 // be in the shadow DOM if the original position was not. 757 // be in the shadow DOM if the original position was not.
703 AXPositionInstance common_ancestor = 758 AXPositionInstance common_ancestor =
704 text_position->LowestCommonAncestor(*this); 759 text_position->LowestCommonAncestor(*this);
705 if (GetAnchor() == common_ancestor->GetAnchor()) 760 if (GetAnchor() == common_ancestor->GetAnchor())
706 return common_ancestor; 761 text_position = std::move(common_ancestor);
707 762
708 if (was_tree_position) 763 if (was_tree_position)
709 text_position = text_position->AsTreePosition(); 764 text_position = text_position->AsTreePosition();
710 return text_position; 765 return text_position;
711 } 766 }
712 767
713 // Word end positions are one past the last character of the word. 768 // Word end positions are one past the last character of the word.
714 AXPositionInstance CreatePreviousWordEndPosition() const { 769 AXPositionInstance CreatePreviousWordEndPosition() const {
715 bool was_tree_position = IsTreePosition(); 770 bool was_tree_position = IsTreePosition();
716 AXPositionInstance text_position = AsLeafTextPosition(); 771 AXPositionInstance text_position = AsLeafTextPosition();
717 if (text_position->IsNullPosition())
718 return text_position;
719 772
720 if (text_position->AtStartOfAnchor()) { 773 if (text_position->AtStartOfAnchor()) {
721 text_position = text_position->CreatePreviousTextAnchorPosition(); 774 text_position = text_position->CreatePreviousTextAnchorPosition();
722 text_position = text_position->CreatePositionAtEndOfAnchor(); 775 text_position = text_position->CreatePositionAtEndOfAnchor();
723 } 776 }
724
725 // Ignore any nodes with no text or no word boundaries.
726 while (!text_position->IsNullPosition() &&
727 (!text_position->MaxTextOffset() ||
728 text_position->GetWordStartOffsets().empty())) {
729 text_position = text_position->CreatePreviousTextAnchorPosition();
730 }
731
732 if (text_position->IsNullPosition()) 777 if (text_position->IsNullPosition())
733 return text_position; 778 return text_position;
734 779
735 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets(); 780 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
736 auto iterator = 781 auto iterator =
737 std::lower_bound(word_ends.begin(), word_ends.end(), 782 std::lower_bound(word_ends.begin(), word_ends.end(),
738 static_cast<int32_t>(text_position->text_offset_)); 783 static_cast<int32_t>(text_position->text_offset_));
739 if (iterator == word_ends.begin()) { 784 if (word_ends.empty() || iterator == word_ends.begin()) {
740 // We must be anywhere up to and including the end of the first word in 785 // Ignore any nodes with no text or no word boundaries.
741 // this node.
742 do { 786 do {
743 text_position = text_position->CreatePreviousTextAnchorPosition(); 787 text_position = text_position->CreatePreviousTextAnchorPosition();
744 } while (!text_position->IsNullPosition() && 788 } while (!text_position->IsNullPosition() &&
745 (!text_position->MaxTextOffset() || 789 (!text_position->MaxTextOffset() ||
746 text_position->GetWordStartOffsets().empty())); 790 text_position->GetWordStartOffsets().empty()));
747 if (text_position->IsNullPosition()) 791 if (text_position->IsNullPosition())
748 return text_position; 792 return text_position;
749 793
750 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets(); 794 const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
795 DCHECK(!word_ends.empty());
751 text_position->text_offset_ = static_cast<int>(*(word_ends.end() - 1)); 796 text_position->text_offset_ = static_cast<int>(*(word_ends.end() - 1));
752 } else { 797 } else {
753 text_position->text_offset_ = static_cast<int>(*(--iterator)); 798 text_position->text_offset_ = static_cast<int>(*(--iterator));
754 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM; 799 text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
755 } 800 }
756 801
757 // If the word boundary is in the same subtree, return a position rooted at 802 // If the word boundary is in the same subtree, return a position rooted at
758 // the current position. 803 // the current position.
759 // This is necessary because we don't want to return any position that might 804 // 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. 805 // be in the shadow DOM if the original position was not.
761 AXPositionInstance common_ancestor = 806 AXPositionInstance common_ancestor =
762 text_position->LowestCommonAncestor(*this); 807 text_position->LowestCommonAncestor(*this);
763 if (GetAnchor() == common_ancestor->GetAnchor()) 808 if (GetAnchor() == common_ancestor->GetAnchor())
764 return common_ancestor; 809 text_position = std::move(common_ancestor);
765 810
766 if (was_tree_position) 811 if (was_tree_position)
767 text_position = text_position->AsTreePosition(); 812 text_position = text_position->AsTreePosition();
768 return text_position; 813 return text_position;
769 } 814 }
770 815
771 AXPositionInstance CreateNextLineStartPosition() const { 816 AXPositionInstance CreateNextLineStartPosition() const {
772 bool was_tree_position = IsTreePosition(); 817 bool was_tree_position = IsTreePosition();
773 AXPositionInstance text_position = AsLeafTextPosition(); 818 AXPositionInstance text_position = AsLeafTextPosition();
774 if (text_position->IsNullPosition()) 819 if (text_position->IsNullPosition())
775 return text_position; 820 return text_position;
776 821
777 // Find the next line break. 822 // Find the next line break.
778 int32_t next_on_line_id = text_position->anchor_id_; 823 int32_t next_on_line_id = text_position->anchor_id_;
779 while (GetNextOnLineID(next_on_line_id) != INVALID_ANCHOR_ID) 824 while (GetNextOnLineID(next_on_line_id) != INVALID_ANCHOR_ID)
780 next_on_line_id = GetNextOnLineID(next_on_line_id); 825 next_on_line_id = GetNextOnLineID(next_on_line_id);
781 text_position = 826 text_position =
782 CreateTextPosition(tree_id_, next_on_line_id, 0 /* text_offset */, 827 CreateTextPosition(tree_id_, next_on_line_id, 0 /* text_offset */,
783 AX_TEXT_AFFINITY_DOWNSTREAM); 828 AX_TEXT_AFFINITY_DOWNSTREAM);
784 text_position = 829 text_position =
785 text_position->AsLeafTextPosition()->CreateNextTextAnchorPosition(); 830 text_position->AsLeafTextPosition()->CreateNextTextAnchorPosition();
831 while (text_position->IsInLineBreak()) {
832 text_position = text_position->CreateNextTextAnchorPosition();
833 }
dmazzoni 2017/04/10 22:39:49 nit: no brackets needed here?
786 if (text_position->IsNullPosition()) 834 if (text_position->IsNullPosition())
787 return text_position; 835 return text_position;
788 836
789 // If the line boundary is in the same subtree, return a position rooted at 837 // If the line boundary is in the same subtree, return a position rooted at
790 // the current position. 838 // the current position.
791 // This is necessary because we don't want to return any position that might 839 // This is necessary because we don't want to return any position that might
792 // be in the shadow DOM if the original position was not. 840 // be in the shadow DOM if the original position was not.
793 AXPositionInstance common_ancestor = 841 AXPositionInstance common_ancestor =
794 text_position->LowestCommonAncestor(*this); 842 text_position->LowestCommonAncestor(*this);
795 if (GetAnchor() == common_ancestor->GetAnchor()) 843 if (GetAnchor() == common_ancestor->GetAnchor())
796 return common_ancestor; 844 text_position = std::move(common_ancestor);
797 845
798 if (was_tree_position) 846 if (was_tree_position)
799 text_position = text_position->AsTreePosition(); 847 text_position = text_position->AsTreePosition();
800 return text_position; 848 return text_position;
801 } 849 }
802 850
803 AXPositionInstance CreatePreviousLineStartPosition() const { 851 AXPositionInstance CreatePreviousLineStartPosition() const {
804 bool was_tree_position = IsTreePosition(); 852 bool was_tree_position = IsTreePosition();
805 AXPositionInstance text_position = AsLeafTextPosition(); 853 AXPositionInstance text_position = AsLeafTextPosition();
806 if (text_position->AtStartOfAnchor()) 854 if (text_position->IsInLineBreak() || text_position->AtStartOfAnchor())
807 text_position = text_position->CreatePreviousTextAnchorPosition(); 855 text_position = text_position->CreatePreviousTextAnchorPosition();
808 if (text_position->IsNullPosition()) 856 if (text_position->IsNullPosition())
809 return text_position; 857 return text_position;
810 858
811 int32_t previous_on_line_id = text_position->anchor_id_; 859 int32_t previous_on_line_id = text_position->anchor_id_;
812 while (GetPreviousOnLineID(previous_on_line_id) != INVALID_ANCHOR_ID) 860 while (GetPreviousOnLineID(previous_on_line_id) != INVALID_ANCHOR_ID)
813 previous_on_line_id = GetPreviousOnLineID(previous_on_line_id); 861 previous_on_line_id = GetPreviousOnLineID(previous_on_line_id);
814 text_position = 862 text_position =
815 CreateTextPosition(tree_id_, previous_on_line_id, 0 /* text_offset */, 863 CreateTextPosition(tree_id_, previous_on_line_id, 0 /* text_offset */,
816 AX_TEXT_AFFINITY_DOWNSTREAM); 864 AX_TEXT_AFFINITY_DOWNSTREAM);
817 text_position = text_position->AsLeafTextPosition(); 865 text_position = text_position->AsLeafTextPosition();
818 if (text_position->IsNullPosition()) 866 if (text_position->IsNullPosition())
819 return text_position; 867 return text_position;
820 868
821 // If the line boundary is in the same subtree, return a position rooted at 869 // If the line boundary is in the same subtree, return a position rooted at
822 // the current position. 870 // the current position.
823 // This is necessary because we don't want to return any position that might 871 // This is necessary because we don't want to return any position that might
824 // be in the shadow DOM if the original position was not. 872 // be in the shadow DOM if the original position was not.
825 AXPositionInstance common_ancestor = 873 AXPositionInstance common_ancestor =
826 text_position->LowestCommonAncestor(*this); 874 text_position->LowestCommonAncestor(*this);
827 if (GetAnchor() == common_ancestor->GetAnchor()) 875 if (GetAnchor() == common_ancestor->GetAnchor())
828 return common_ancestor; 876 text_position = std::move(common_ancestor);
829 877
830 if (was_tree_position) 878 if (was_tree_position)
831 text_position = text_position->AsTreePosition(); 879 text_position = text_position->AsTreePosition();
832 return text_position; 880 return text_position;
833 } 881 }
834 882
835 // Line end positions are one past the last character of the line, excluding 883 // Line end positions are one past the last character of the line, excluding
836 // any newline characters. 884 // any newline characters.
837 AXPositionInstance CreateNextLineEndPosition() const { 885 AXPositionInstance CreateNextLineEndPosition() const {
838 bool was_tree_position = IsTreePosition(); 886 bool was_tree_position = IsTreePosition();
(...skipping 20 matching lines...) Expand all
859 return text_position; 907 return text_position;
860 text_position = text_position->CreatePositionAtEndOfAnchor(); 908 text_position = text_position->CreatePositionAtEndOfAnchor();
861 909
862 // If the line boundary is in the same subtree, return a position rooted at 910 // If the line boundary is in the same subtree, return a position rooted at
863 // the current position. 911 // the current position.
864 // This is necessary because we don't want to return any position that might 912 // This is necessary because we don't want to return any position that might
865 // be in the shadow DOM if the original position was not. 913 // be in the shadow DOM if the original position was not.
866 AXPositionInstance common_ancestor = 914 AXPositionInstance common_ancestor =
867 text_position->LowestCommonAncestor(*this); 915 text_position->LowestCommonAncestor(*this);
868 if (GetAnchor() == common_ancestor->GetAnchor()) 916 if (GetAnchor() == common_ancestor->GetAnchor())
869 return common_ancestor; 917 text_position = std::move(common_ancestor);
870 918
871 if (was_tree_position) 919 if (was_tree_position)
872 text_position = text_position->AsTreePosition(); 920 text_position = text_position->AsTreePosition();
873 return text_position; 921 return text_position;
874 } 922 }
875 923
876 // Line end positions are one past the last character of the line, excluding 924 // Line end positions are one past the last character of the line, excluding
877 // any newline characters. 925 // any newline characters.
878 AXPositionInstance CreatePreviousLineEndPosition() const { 926 AXPositionInstance CreatePreviousLineEndPosition() const {
879 bool was_tree_position = IsTreePosition(); 927 bool was_tree_position = IsTreePosition();
(...skipping 16 matching lines...) Expand all
896 return text_position; 944 return text_position;
897 text_position = text_position->CreatePositionAtEndOfAnchor(); 945 text_position = text_position->CreatePositionAtEndOfAnchor();
898 946
899 // If the line boundary is in the same subtree, return a position rooted at 947 // If the line boundary is in the same subtree, return a position rooted at
900 // the current position. 948 // the current position.
901 // This is necessary because we don't want to return any position that might 949 // This is necessary because we don't want to return any position that might
902 // be in the shadow DOM if the original position was not. 950 // be in the shadow DOM if the original position was not.
903 AXPositionInstance common_ancestor = 951 AXPositionInstance common_ancestor =
904 text_position->LowestCommonAncestor(*this); 952 text_position->LowestCommonAncestor(*this);
905 if (GetAnchor() == common_ancestor->GetAnchor()) 953 if (GetAnchor() == common_ancestor->GetAnchor())
906 return common_ancestor; 954 text_position = std::move(common_ancestor);
907 955
908 if (was_tree_position) 956 if (was_tree_position)
909 text_position = text_position->AsTreePosition(); 957 text_position = text_position->AsTreePosition();
910 return text_position; 958 return text_position;
911 } 959 }
912 960
913 // TODO(nektar): Add sentence and paragraph navigation methods. 961 // TODO(nektar): Add sentence and paragraph navigation methods.
914 962
915 // Abstract methods. 963 // Abstract methods.
916 964
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
1141 1189
1142 template <class AXPositionType, class AXNodeType> 1190 template <class AXPositionType, class AXNodeType>
1143 bool operator>=(const AXPosition<AXPositionType, AXNodeType>& first, 1191 bool operator>=(const AXPosition<AXPositionType, AXNodeType>& first,
1144 const AXPosition<AXPositionType, AXNodeType>& second) { 1192 const AXPosition<AXPositionType, AXNodeType>& second) {
1145 return first == second || first > second; 1193 return first == second || first > second;
1146 } 1194 }
1147 1195
1148 } // namespace ui 1196 } // namespace ui
1149 1197
1150 #endif // UI_ACCESSIBILITY_AX_POSITION_H_ 1198 #endif // UI_ACCESSIBILITY_AX_POSITION_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698