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(); |