| Index: ui/accessibility/ax_position.h
|
| diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
|
| index bbce7f3a8d7b2483378ed65e63f6741f46e424a3..0938f0509e23253cd7f2fc4a883948d82ece8236 100644
|
| --- a/ui/accessibility/ax_position.h
|
| +++ b/ui/accessibility/ax_position.h
|
| @@ -131,6 +131,7 @@ class AXPosition {
|
| str = "TreePosition tree_id=" + base::IntToString(tree_id_) +
|
| " anchor_id=" + base::IntToString(anchor_id_) + " child_index=" +
|
| str_child_index;
|
| + break;
|
| }
|
| case AXPositionKind::TEXT_POSITION: {
|
| std::string str_text_offset;
|
| @@ -143,6 +144,7 @@ class AXPosition {
|
| " anchor_id=" + base::IntToString(anchor_id_) + " text_offset=" +
|
| str_text_offset + " affinity=" +
|
| ui::ToString(static_cast<AXTextAffinity>(affinity_));
|
| + break;
|
| }
|
| }
|
|
|
| @@ -225,6 +227,80 @@ class AXPosition {
|
| return false;
|
| }
|
|
|
| + bool AtStartOfWord() const {
|
| + AXPositionInstance text_position = AsLeafTextPosition();
|
| + switch (text_position->kind_) {
|
| + case AXPositionKind::NULL_POSITION:
|
| + return false;
|
| + case AXPositionKind::TREE_POSITION:
|
| + NOTREACHED();
|
| + return false;
|
| + case AXPositionKind::TEXT_POSITION: {
|
| + const std::vector<int32_t> word_starts =
|
| + text_position->GetWordStartOffsets();
|
| + auto iterator =
|
| + std::find(word_starts.begin(), word_starts.end(),
|
| + static_cast<int32_t>(text_position->text_offset_));
|
| + return iterator != word_starts.end();
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool AtEndOfWord() const {
|
| + AXPositionInstance text_position = AsLeafTextPosition();
|
| + switch (text_position->kind_) {
|
| + case AXPositionKind::NULL_POSITION:
|
| + return false;
|
| + case AXPositionKind::TREE_POSITION:
|
| + NOTREACHED();
|
| + return false;
|
| + case AXPositionKind::TEXT_POSITION: {
|
| + const std::vector<int32_t> word_ends =
|
| + text_position->GetWordEndOffsets();
|
| + auto iterator =
|
| + std::find(word_ends.begin(), word_ends.end(),
|
| + static_cast<int32_t>(text_position->text_offset_));
|
| + return iterator != word_ends.end();
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool AtStartOfLine() const {
|
| + AXPositionInstance text_position = AsLeafTextPosition();
|
| + switch (text_position->kind_) {
|
| + case AXPositionKind::NULL_POSITION:
|
| + return false;
|
| + case AXPositionKind::TREE_POSITION:
|
| + NOTREACHED();
|
| + return false;
|
| + case AXPositionKind::TEXT_POSITION:
|
| + return !text_position->IsInLineBreak() &&
|
| + GetPreviousOnLineID(text_position->anchor_id_) ==
|
| + INVALID_ANCHOR_ID &&
|
| + text_position->AtStartOfAnchor();
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool AtEndOfLine() const {
|
| + AXPositionInstance text_position = AsLeafTextPosition();
|
| + switch (text_position->kind_) {
|
| + case AXPositionKind::NULL_POSITION:
|
| + return false;
|
| + case AXPositionKind::TREE_POSITION:
|
| + NOTREACHED();
|
| + return false;
|
| + case AXPositionKind::TEXT_POSITION:
|
| + return !text_position->IsInLineBreak() &&
|
| + GetNextOnLineID(text_position->anchor_id_) ==
|
| + INVALID_ANCHOR_ID &&
|
| + text_position->AtEndOfAnchor();
|
| + }
|
| + return false;
|
| + }
|
| +
|
| // This method returns a position instead of a node because this allows us to
|
| // return the corresponding text offset or child index in the ancestor that
|
| // relates to the current position.
|
| @@ -449,20 +525,28 @@ class AXPosition {
|
| if (tree_id == INVALID_TREE_ID || parent_id == INVALID_ANCHOR_ID)
|
| return CreateNullPosition();
|
|
|
| - DCHECK_NE(tree_id, INVALID_TREE_ID);
|
| - DCHECK_NE(parent_id, INVALID_ANCHOR_ID);
|
| switch (kind_) {
|
| case AXPositionKind::NULL_POSITION:
|
| NOTREACHED();
|
| return CreateNullPosition();
|
| case AXPositionKind::TREE_POSITION:
|
| return CreateTreePosition(tree_id, parent_id, AnchorIndexInParent());
|
| - case AXPositionKind::TEXT_POSITION:
|
| - // Make sure that our affinity is propagated to our parent because by
|
| - // design our parent includes all our text.
|
| - return CreateTextPosition(tree_id, parent_id,
|
| - AnchorTextOffsetInParent() + text_offset_,
|
| - affinity_);
|
| + case AXPositionKind::TEXT_POSITION: {
|
| + // If our parent contains all our text, we need to maintain the affinity
|
| + // and the text offset. Otherwise, we return a position that is either
|
| + // before or after the child and we don't maintain the affinity when the
|
| + // position is after the child.
|
| + int parent_offset = AnchorTextOffsetInParent();
|
| + AXTextAffinity parent_affinity = affinity_;
|
| + if (MaxTextOffset() == MaxTextOffsetInParent()) {
|
| + parent_offset += text_offset_;
|
| + } else if (text_offset_ > 0) {
|
| + parent_offset += MaxTextOffsetInParent();
|
| + parent_affinity = AX_TEXT_AFFINITY_DOWNSTREAM;
|
| + }
|
| + return CreateTextPosition(tree_id, parent_id, parent_offset,
|
| + parent_affinity);
|
| + }
|
| }
|
|
|
| return CreateNullPosition();
|
| @@ -548,22 +632,13 @@ class AXPosition {
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| - // Ignore any nodes with no text or no word boundaries.
|
| - while (!text_position->IsNullPosition() &&
|
| - (!text_position->MaxTextOffset() ||
|
| - text_position->GetWordStartOffsets().empty())) {
|
| - text_position = text_position->CreateNextTextAnchorPosition();
|
| - }
|
| -
|
| - if (text_position->IsNullPosition())
|
| - return text_position;
|
| -
|
| const std::vector<int32_t> word_starts =
|
| text_position->GetWordStartOffsets();
|
| auto iterator =
|
| std::upper_bound(word_starts.begin(), word_starts.end(),
|
| static_cast<int32_t>(text_position->text_offset_));
|
| if (iterator == word_starts.end()) {
|
| + // Ignore any nodes with no text or no word boundaries.
|
| do {
|
| text_position = text_position->CreateNextTextAnchorPosition();
|
| } while (!text_position->IsNullPosition() &&
|
| @@ -572,10 +647,9 @@ class AXPosition {
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| - // In case there are some non-word characters in front of the first word
|
| - // in this text node.
|
| const std::vector<int32_t> word_starts =
|
| text_position->GetWordStartOffsets();
|
| + DCHECK(!word_starts.empty());
|
| text_position->text_offset_ = static_cast<int>(word_starts[0]);
|
| } else {
|
| text_position->text_offset_ = static_cast<int>(*iterator);
|
| @@ -589,7 +663,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -599,22 +673,11 @@ class AXPosition {
|
| AXPositionInstance CreatePreviousWordStartPosition() const {
|
| bool was_tree_position = IsTreePosition();
|
| AXPositionInstance text_position = AsLeafTextPosition();
|
| - if (text_position->IsNullPosition())
|
| - return text_position;
|
|
|
| if (text_position->AtStartOfAnchor()) {
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| text_position = text_position->CreatePositionAtEndOfAnchor();
|
| }
|
| -
|
| - // Ignore any nodes with no text or no word boundaries.
|
| - while (!text_position->IsNullPosition() &&
|
| - (!text_position->MaxTextOffset() ||
|
| - text_position->GetWordStartOffsets().empty())) {
|
| - text_position = text_position->CreatePreviousTextAnchorPosition();
|
| - text_position = text_position->CreatePositionAtEndOfAnchor();
|
| - }
|
| -
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| @@ -623,9 +686,8 @@ class AXPosition {
|
| auto iterator =
|
| std::lower_bound(word_starts.begin(), word_starts.end(),
|
| static_cast<int32_t>(text_position->text_offset_));
|
| - if (iterator == word_starts.begin()) {
|
| - // There must be some non-word characters in front of the first word in
|
| - // this text node.
|
| + if (word_starts.empty() || iterator == word_starts.begin()) {
|
| + // Ignore any nodes with no text or no word boundaries.
|
| do {
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| } while (!text_position->IsNullPosition() &&
|
| @@ -636,6 +698,7 @@ class AXPosition {
|
|
|
| const std::vector<int32_t> word_starts =
|
| text_position->GetWordStartOffsets();
|
| + DCHECK(!word_starts.empty());
|
| text_position->text_offset_ = static_cast<int>(*(word_starts.end() - 1));
|
| } else {
|
| text_position->text_offset_ = static_cast<int>(*(--iterator));
|
| @@ -649,7 +712,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -660,27 +723,18 @@ class AXPosition {
|
| AXPositionInstance CreateNextWordEndPosition() const {
|
| bool was_tree_position = IsTreePosition();
|
| AXPositionInstance text_position = AsLeafTextPosition();
|
| - if (text_position->IsNullPosition())
|
| - return text_position;
|
|
|
| if (text_position->AtEndOfAnchor())
|
| text_position = text_position->CreateNextTextAnchorPosition();
|
| -
|
| - // Ignore any nodes with no text or no word boundaries.
|
| - while (!text_position->IsNullPosition() &&
|
| - (!text_position->MaxTextOffset() ||
|
| - text_position->GetWordEndOffsets().empty())) {
|
| - text_position = text_position->CreateNextTextAnchorPosition();
|
| - }
|
| -
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| - const std::vector<int> word_ends = text_position->GetWordEndOffsets();
|
| - auto iterator = std::upper_bound(word_ends.begin(), word_ends.end(),
|
| - text_position->text_offset_);
|
| + const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
|
| + auto iterator =
|
| + std::upper_bound(word_ends.begin(), word_ends.end(),
|
| + static_cast<int32_t>(text_position->text_offset_));
|
| if (iterator == word_ends.end()) {
|
| - // We should be in the last word of this text node.
|
| + // Ignore any nodes with no text or no word boundaries.
|
| do {
|
| text_position = text_position->CreateNextTextAnchorPosition();
|
| } while (!text_position->IsNullPosition() &&
|
| @@ -689,10 +743,11 @@ class AXPosition {
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| - const std::vector<int> word_ends = text_position->GetWordEndOffsets();
|
| - text_position->text_offset_ = word_ends[0];
|
| + const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
|
| + DCHECK(!word_ends.empty());
|
| + text_position->text_offset_ = static_cast<int>(word_ends[0]);
|
| } else {
|
| - text_position->text_offset_ = *iterator;
|
| + text_position->text_offset_ = static_cast<int>(*iterator);
|
| text_position->affinity_ = AX_TEXT_AFFINITY_DOWNSTREAM;
|
| }
|
|
|
| @@ -703,7 +758,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -714,21 +769,11 @@ class AXPosition {
|
| AXPositionInstance CreatePreviousWordEndPosition() const {
|
| bool was_tree_position = IsTreePosition();
|
| AXPositionInstance text_position = AsLeafTextPosition();
|
| - if (text_position->IsNullPosition())
|
| - return text_position;
|
|
|
| if (text_position->AtStartOfAnchor()) {
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| text_position = text_position->CreatePositionAtEndOfAnchor();
|
| }
|
| -
|
| - // Ignore any nodes with no text or no word boundaries.
|
| - while (!text_position->IsNullPosition() &&
|
| - (!text_position->MaxTextOffset() ||
|
| - text_position->GetWordStartOffsets().empty())) {
|
| - text_position = text_position->CreatePreviousTextAnchorPosition();
|
| - }
|
| -
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| @@ -736,9 +781,8 @@ class AXPosition {
|
| auto iterator =
|
| std::lower_bound(word_ends.begin(), word_ends.end(),
|
| static_cast<int32_t>(text_position->text_offset_));
|
| - if (iterator == word_ends.begin()) {
|
| - // We must be anywhere up to and including the end of the first word in
|
| - // this node.
|
| + if (word_ends.empty() || iterator == word_ends.begin()) {
|
| + // Ignore any nodes with no text or no word boundaries.
|
| do {
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| } while (!text_position->IsNullPosition() &&
|
| @@ -748,6 +792,7 @@ class AXPosition {
|
| return text_position;
|
|
|
| const std::vector<int32_t> word_ends = text_position->GetWordEndOffsets();
|
| + DCHECK(!word_ends.empty());
|
| text_position->text_offset_ = static_cast<int>(*(word_ends.end() - 1));
|
| } else {
|
| text_position->text_offset_ = static_cast<int>(*(--iterator));
|
| @@ -761,7 +806,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -783,6 +828,8 @@ class AXPosition {
|
| AX_TEXT_AFFINITY_DOWNSTREAM);
|
| text_position =
|
| text_position->AsLeafTextPosition()->CreateNextTextAnchorPosition();
|
| + while (text_position->IsInLineBreak())
|
| + text_position = text_position->CreateNextTextAnchorPosition();
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
|
|
| @@ -793,7 +840,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -803,7 +850,7 @@ class AXPosition {
|
| AXPositionInstance CreatePreviousLineStartPosition() const {
|
| bool was_tree_position = IsTreePosition();
|
| AXPositionInstance text_position = AsLeafTextPosition();
|
| - if (text_position->AtStartOfAnchor())
|
| + if (text_position->IsInLineBreak() || text_position->AtStartOfAnchor())
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
| @@ -825,7 +872,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -852,9 +899,8 @@ class AXPosition {
|
| CreateTextPosition(tree_id_, next_on_line_id, 0 /* text_offset */,
|
| AX_TEXT_AFFINITY_DOWNSTREAM);
|
| text_position = text_position->AsLeafTextPosition();
|
| - while (text_position->IsInLineBreak()) {
|
| + while (text_position->IsInLineBreak())
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| - }
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
| text_position = text_position->CreatePositionAtEndOfAnchor();
|
| @@ -866,7 +912,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
| @@ -889,9 +935,8 @@ class AXPosition {
|
| AX_TEXT_AFFINITY_DOWNSTREAM);
|
| text_position =
|
| text_position->AsLeafTextPosition()->CreatePreviousTextAnchorPosition();
|
| - while (text_position->IsInLineBreak()) {
|
| + while (text_position->IsInLineBreak())
|
| text_position = text_position->CreatePreviousTextAnchorPosition();
|
| - }
|
| if (text_position->IsNullPosition())
|
| return text_position;
|
| text_position = text_position->CreatePositionAtEndOfAnchor();
|
| @@ -903,7 +948,7 @@ class AXPosition {
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| if (GetAnchor() == common_ancestor->GetAnchor())
|
| - return common_ancestor;
|
| + text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| text_position = text_position->AsTreePosition();
|
|
|