Chromium Code Reviews| Index: ui/accessibility/ax_position.h |
| diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h |
| index bbce7f3a8d7b2483378ed65e63f6741f46e424a3..bd45c3e3c1330cb497b73ef8d760832bd43506f1 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,9 @@ class AXPosition { |
| AX_TEXT_AFFINITY_DOWNSTREAM); |
| text_position = |
| text_position->AsLeafTextPosition()->CreateNextTextAnchorPosition(); |
| + while (text_position->IsInLineBreak()) { |
| + text_position = text_position->CreateNextTextAnchorPosition(); |
| + } |
|
dmazzoni
2017/04/10 22:39:49
nit: no brackets needed here?
|
| if (text_position->IsNullPosition()) |
| return text_position; |
| @@ -793,7 +841,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 +851,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 +873,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(); |
| @@ -866,7 +914,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(); |
| @@ -903,7 +951,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(); |