Commit b62e2e5d authored by Benjamin Beaudry's avatar Benjamin Beaudry Committed by Commit Bot

Encapsulate text range provider endpoints in helper class

This CL encapsulates both |start_| and |end_| ebdpoints of
AXPlatformNodeTextRangeProviderWin into an helper class with designated
getters and setters. In the follow-up CL:2432805, we are using the
setters to execute extra logic on the new endpoints.

The encapsulation will prevent anyone from setting new endpoints without
going through the setter.

Bug: N/A
Change-Id: Ia6d56391cdd0df42c0fecc87d6e575710dfda758
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2456513
Commit-Queue: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Reviewed-by: default avatarKurt Catti-Schmidt <kschmi@microsoft.com>
Reviewed-by: default avatarDaniel Libby <dlibby@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#815256}
parent 16d00437
......@@ -44,11 +44,11 @@ class AXPlatformNodeTextProviderTest : public AXPlatformNodeWinTest {
}
const AXNodePosition::AXPositionInstance& GetStart(
const AXPlatformNodeTextRangeProviderWin* text_range) {
return text_range->start_;
return text_range->start();
}
const AXNodePosition::AXPositionInstance& GetEnd(
const AXPlatformNodeTextRangeProviderWin* text_range) {
return text_range->end_;
return text_range->end();
}
};
......
......@@ -14,38 +14,38 @@
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \
if (!owner() || !owner()->GetDelegate() || !start_ || \
!start_->GetAnchor() || !end_ || !end_->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
start_ = start_->AsValidPosition(); \
end_ = end_->AsValidPosition();
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_IN(in) \
if (!owner() || !owner()->GetDelegate() || !start_ || \
!start_->GetAnchor() || !end_ || !end_->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
if (!in) \
return E_POINTER; \
start_ = start_->AsValidPosition(); \
end_ = end_->AsValidPosition();
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_OUT(out) \
if (!owner() || !owner()->GetDelegate() || !start_ || \
!start_->GetAnchor() || !end_ || !end_->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
if (!out) \
return E_POINTER; \
*out = {}; \
start_ = start_->AsValidPosition(); \
end_ = end_->AsValidPosition();
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \
if (!owner() || !owner()->GetDelegate() || !start() || \
!start()->GetAnchor() || !end() || !end()->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
SetStart(start()->AsValidPosition()); \
SetEnd(end()->AsValidPosition());
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_IN(in) \
if (!owner() || !owner()->GetDelegate() || !start() || \
!start()->GetAnchor() || !end() || !end()->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
if (!in) \
return E_POINTER; \
SetStart(start()->AsValidPosition()); \
SetEnd(end()->AsValidPosition());
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_OUT(out) \
if (!owner() || !owner()->GetDelegate() || !start() || \
!start()->GetAnchor() || !end() || !end()->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
if (!out) \
return E_POINTER; \
*out = {}; \
SetStart(start()->AsValidPosition()); \
SetEnd(end()->AsValidPosition());
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_IN_1_OUT(in, out) \
if (!owner() || !owner()->GetDelegate() || !start_ || \
!start_->GetAnchor() || !end_ || !end_->GetAnchor()) \
if (!owner() || !owner()->GetDelegate() || !start() || \
!start()->GetAnchor() || !end() || !end()->GetAnchor()) \
return UIA_E_ELEMENTNOTAVAILABLE; \
if (!in || !out) \
return E_POINTER; \
*out = {}; \
start_ = start_->AsValidPosition(); \
end_ = end_->AsValidPosition();
SetStart(start()->AsValidPosition()); \
SetEnd(end()->AsValidPosition());
// Validate bounds calculated by AXPlatformNodeDelegate. Degenerate bounds
// indicate the interface is not yet supported on the platform.
#define UIA_VALIDATE_BOUNDS(bounds) \
......@@ -101,8 +101,8 @@ ITextRangeProvider* AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
&text_range_provider))) {
DCHECK(text_range_provider);
text_range_provider->owner_ = owner;
text_range_provider->start_ = std::move(start);
text_range_provider->end_ = std::move(end);
text_range_provider->SetStart(std::move(start));
text_range_provider->SetEnd(std::move(end));
text_range_provider->AddRef();
return text_range_provider;
}
......@@ -118,7 +118,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Clone(ITextRangeProvider** clone) {
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_OUT(clone);
*clone =
CreateTextRangeProvider(owner_.Get(), start_->Clone(), end_->Clone());
CreateTextRangeProvider(owner_.Get(), start()->Clone(), end()->Clone());
return S_OK;
}
......@@ -132,8 +132,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Compare(ITextRangeProvider* other,
if (other->QueryInterface(IID_PPV_ARGS(&other_provider)) != S_OK)
return UIA_E_INVALIDOPERATION;
if (*start_ == *(other_provider->start_) &&
*end_ == *(other_provider->end_)) {
if (*start() == *(other_provider->start()) &&
*end() == *(other_provider->end())) {
*result = TRUE;
}
return S_OK;
......@@ -153,11 +153,11 @@ HRESULT AXPlatformNodeTextRangeProviderWin::CompareEndpoints(
return UIA_E_INVALIDOPERATION;
const AXPositionInstance& this_provider_endpoint =
(this_endpoint == TextPatternRangeEndpoint_Start) ? start_ : end_;
(this_endpoint == TextPatternRangeEndpoint_Start) ? start() : end();
const AXPositionInstance& other_provider_endpoint =
(other_endpoint == TextPatternRangeEndpoint_Start)
? other_provider->start_
: other_provider->end_;
? other_provider->start()
: other_provider->end();
base::Optional<int> comparison =
this_provider_endpoint->CompareTo(*other_provider_endpoint);
......@@ -192,98 +192,99 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnitImpl(
case TextUnit_Character: {
// For characters, the start endpoint will always be on a TextUnit
// boundary, thus we only need to move the end position.
AXPositionInstance end_backup = end_->Clone();
end_ = start_->CreateNextCharacterPosition(
AXBoundaryBehavior::CrossBoundary);
AXPositionInstance end_backup = end()->Clone();
SetEnd(start()->CreateNextCharacterPosition(
AXBoundaryBehavior::CrossBoundary));
if (end_->IsNullPosition()) {
if (end()->IsNullPosition()) {
// The previous could fail if the start is at the end of the last anchor
// of the tree, try expanding to the previous character instead.
AXPositionInstance start_backup = start_->Clone();
start_ = start_->CreatePreviousCharacterPosition(
AXBoundaryBehavior::CrossBoundary);
AXPositionInstance start_backup = start()->Clone();
SetStart(start()->CreatePreviousCharacterPosition(
AXBoundaryBehavior::CrossBoundary));
if (start_->IsNullPosition()) {
if (start()->IsNullPosition()) {
// Text representation is empty, undo everything and exit.
start_ = std::move(start_backup);
end_ = std::move(end_backup);
SetStart(std::move(start_backup));
SetEnd(std::move(end_backup));
return S_OK;
}
end_ = start_->CreateNextCharacterPosition(
AXBoundaryBehavior::CrossBoundary);
DCHECK(!end_->IsNullPosition());
SetEnd(start()->CreateNextCharacterPosition(
AXBoundaryBehavior::CrossBoundary));
DCHECK(!end()->IsNullPosition());
}
NormalizeTextRange();
break;
}
case TextUnit_Format:
start_ = start_->CreatePreviousFormatStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
end_ = start_->CreateNextFormatEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
SetStart(start()->CreatePreviousFormatStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary));
SetEnd(start()->CreateNextFormatEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary));
break;
case TextUnit_Word: {
AXPositionInstance start_backup = start_->Clone();
start_ = start_->CreatePreviousWordStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
AXPositionInstance start_backup = start()->Clone();
SetStart(start()->CreatePreviousWordStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary));
// Since we use AXBoundaryBehavior::StopIfAlreadyAtBoundary, the only case
// possible where CreatePreviousWordStartPosition can return a
// NullPosition is when it's called on a node before the first word
// boundary. This can happen when the document starts with nodes that have
// no word boundaries, like whitespaces and punctuation. When it happens,
// move the position back to the start of the document.
if (start_->IsNullPosition())
start_ = start_backup->CreatePositionAtStartOfDocument();
if (start()->IsNullPosition())
SetStart(start_backup->CreatePositionAtStartOfDocument());
// Since start_ is already located at a word boundary, we need to cross it
// in order to move to the next one. Because Windows ATs behave
// undesirably when the start and end endpoints are not in the same anchor
// (for character and word navigation), stop at anchor boundary.
end_ = start_->CreateNextWordStartPosition(
AXBoundaryBehavior::StopAtAnchorBoundary);
SetEnd(start()->CreateNextWordStartPosition(
AXBoundaryBehavior::StopAtAnchorBoundary));
break;
}
case TextUnit_Line:
start_ = start_->CreateBoundaryStartPosition(
SetStart(start()->CreateBoundaryStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary,
ax::mojom::MoveDirection::kBackward,
base::BindRepeating(&AtStartOfLinePredicate),
base::BindRepeating(&AtEndOfLinePredicate));
end_ = start_->CreateBoundaryEndPosition(
base::BindRepeating(&AtEndOfLinePredicate)));
SetEnd(start()->CreateBoundaryEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary,
ax::mojom::MoveDirection::kForward,
base::BindRepeating(&AtStartOfLinePredicate),
base::BindRepeating(&AtEndOfLinePredicate));
base::BindRepeating(&AtEndOfLinePredicate)));
break;
case TextUnit_Paragraph:
start_ = start_->CreatePreviousParagraphStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
end_ = start_->CreateNextParagraphEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary);
SetStart(start()->CreatePreviousParagraphStartPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary));
SetEnd(start()->CreateNextParagraphEndPosition(
AXBoundaryBehavior::StopIfAlreadyAtBoundary));
break;
case TextUnit_Page: {
// Per UIA spec, if the document containing the current range doesn't
// support pagination, default to document navigation.
const AXNode* common_anchor = start_->LowestCommonAnchor(*end_);
const AXNode* common_anchor = start()->LowestCommonAnchor(*end());
if (common_anchor->tree()->HasPaginationSupport()) {
start_ = start_->CreatePreviousPageStartPosition(
ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
end_ = start_->CreateNextPageEndPosition(
ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
SetStart(start()->CreatePreviousPageStartPosition(
ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
SetEnd(start()->CreateNextPageEndPosition(
ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
break;
}
}
FALLTHROUGH;
case TextUnit_Document:
start_ = start_->CreatePositionAtStartOfDocument()->AsLeafTextPosition();
end_ = start_->CreatePositionAtEndOfDocument();
SetStart(
start()->CreatePositionAtStartOfDocument()->AsLeafTextPosition());
SetEnd(start()->CreatePositionAtEndOfDocument());
break;
default:
return UIA_E_NOTSUPPORTED;
}
DCHECK(!start_->IsNullPosition());
DCHECK(!end_->IsNullPosition());
DCHECK(!start()->IsNullPosition());
DCHECK(!end()->IsNullPosition());
return S_OK;
}
......@@ -330,7 +331,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindAttribute(
AXPositionInstance matched_range_end = nullptr;
std::vector<AXNodeRange> anchors;
AXNodeRange range(start_->Clone(), end_->Clone());
AXNodeRange range(start()->Clone(), end()->Clone());
for (AXNodeRange leaf_text_range : range)
anchors.emplace_back(std::move(leaf_text_range));
......@@ -440,12 +441,12 @@ HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
// breaking object. FindText() is rarely called, and when it is, it's not to
// look for a string starting or ending with a newline. This may change
// someday, and if so, we'll have to address this issue.
const AXNode* common_anchor = start_->LowestCommonAnchor(*end_);
const AXNode* common_anchor = start()->LowestCommonAnchor(*end());
AXPositionInstance start_ancestor_position =
start_->CreateAncestorPosition(common_anchor);
start()->CreateAncestorPosition(common_anchor);
DCHECK(!start_ancestor_position->IsNullPosition());
AXPositionInstance end_ancestor_position =
end_->CreateAncestorPosition(common_anchor);
end()->CreateAncestorPosition(common_anchor);
DCHECK(!end_ancestor_position->IsNullPosition());
AXTreeID tree_id = start_ancestor_position->tree_id();
AXNode::AXID anchor_id = start_ancestor_position->anchor_id();
......@@ -481,11 +482,11 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetAttributeValue(
base::win::VariantVector attribute_value;
// The range is inclusive, so advance our endpoint to the next position
const auto end_leaf_text_position = end_->AsLeafTextPosition();
const auto end_leaf_text_position = end()->AsLeafTextPosition();
auto end = end_leaf_text_position->CreateNextAnchorPosition();
// Iterate over anchor positions
for (auto it = start_->AsLeafTextPosition();
for (auto it = start()->AsLeafTextPosition();
it->anchor_id() != end->anchor_id() || it->tree_id() != end->tree_id();
it = it->CreateNextAnchorPosition()) {
// If the iterator creates a null position, then it has likely overrun the
......@@ -548,7 +549,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetBoundingRectangles(
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL_1_OUT(screen_physical_pixel_rectangles);
*screen_physical_pixel_rectangles = nullptr;
AXNodeRange range(start_->Clone(), end_->Clone());
AXNodeRange range(start()->Clone(), end()->Clone());
AXRangePhysicalPixelRectDelegate rect_delegate(this);
std::vector<gfx::Rect> rects = range.GetRects(&rect_delegate);
......@@ -648,9 +649,9 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
return S_OK;
// Save a clone of start and end, in case one of the moves fails.
auto start_backup = start_->Clone();
auto end_backup = end_->Clone();
bool is_degenerate_range = (*start_ == *end_);
auto start_backup = start()->Clone();
auto end_backup = end()->Clone();
bool is_degenerate_range = (*start() == *end());
// Move the start of the text range forward or backward in the document by the
// requested number of text unit boundaries.
......@@ -660,10 +661,10 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
bool succeeded_move = SUCCEEDED(hr) && start_units_moved != 0;
if (succeeded_move) {
end_ = start_->Clone();
SetEnd(start()->Clone());
if (!is_degenerate_range) {
bool forwards = count > 0;
if (forwards && start_->AtEndOfDocument()) {
if (forwards && start()->AtEndOfDocument()) {
// The start is at the end of the document, so move the start backward
// by one text unit to expand the text range from the degenerate range
// state.
......@@ -686,7 +687,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
// Because Windows ATs behave undesirably when the start and end endpoints
// are not in the same anchor (for character and word navigation), make
// sure to bring back the end endpoint to the end of the start's anchor.
if (start_->anchor_id() != end_->anchor_id() &&
if (start()->anchor_id() != end()->anchor_id() &&
(unit == TextUnit_Character || unit == TextUnit_Word)) {
ExpandToEnclosingUnitImpl(unit);
}
......@@ -694,8 +695,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
}
if (!succeeded_move) {
start_ = std::move(start_backup);
end_ = std::move(end_backup);
SetStart(std::move(start_backup));
SetEnd(std::move(end_backup));
start_units_moved = 0;
if (!SUCCEEDED(hr))
return hr;
......@@ -729,7 +730,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitImpl(
}
bool is_start_endpoint = endpoint == TextPatternRangeEndpoint_Start;
AXPositionInstance& position_to_move = is_start_endpoint ? start_ : end_;
AXPositionInstance position_to_move =
is_start_endpoint ? start()->Clone() : end()->Clone();
AXPositionInstance new_position;
switch (unit) {
......@@ -762,19 +764,22 @@ HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitImpl(
default:
return UIA_E_NOTSUPPORTED;
}
position_to_move = std::move(new_position);
if (is_start_endpoint)
SetStart(std::move(new_position));
else
SetEnd(std::move(new_position));
// If the start was moved past the end, create a degenerate range with the end
// equal to the start; do the equivalent if the end moved past the start.
base::Optional<int> endpoint_comparison =
AXNodeRange::CompareEndpoints(start_.get(), end_.get());
AXNodeRange::CompareEndpoints(start().get(), end().get());
DCHECK(endpoint_comparison.has_value());
if (endpoint_comparison.value_or(0) > 0) {
if (is_start_endpoint)
end_ = start_->Clone();
SetEnd(start()->Clone());
else
start_ = end_->Clone();
SetStart(end()->Clone());
}
return S_OK;
}
......@@ -794,17 +799,17 @@ HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByRange(
const AXPositionInstance& other_provider_endpoint =
(other_endpoint == TextPatternRangeEndpoint_Start)
? other_provider->start_
: other_provider->end_;
? other_provider->start()
: other_provider->end();
if (this_endpoint == TextPatternRangeEndpoint_Start) {
start_ = other_provider_endpoint->Clone();
if (*start_ > *end_)
end_ = start_->Clone();
SetStart(other_provider_endpoint->Clone());
if (*start() > *end())
SetEnd(start()->Clone());
} else {
end_ = other_provider_endpoint->Clone();
if (*start_ > *end_)
start_ = end_->Clone();
SetEnd(other_provider_endpoint->Clone());
if (*start() > *end())
SetStart(end()->Clone());
}
return S_OK;
}
......@@ -813,8 +818,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::Select() {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_TEXTRANGE_SELECT);
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL();
AXPositionInstance selection_start = start_->Clone();
AXPositionInstance selection_end = end_->Clone();
AXPositionInstance selection_start = start()->Clone();
AXPositionInstance selection_end = end()->Clone();
// Blink only supports selections within a single tree. So if start_ and end_
// are in different trees, we can't directly pass them to the render process
......@@ -875,9 +880,9 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ScrollIntoView(BOOL align_to_top) {
UIA_VALIDATE_TEXTRANGEPROVIDER_CALL();
const AXPositionInstance start_common_ancestor =
start_->LowestCommonAncestor(*end_);
start()->LowestCommonAncestor(*end());
const AXPositionInstance end_common_ancestor =
end_->LowestCommonAncestor(*start_);
end()->LowestCommonAncestor(*start());
if (start_common_ancestor->IsNullPosition() ||
end_common_ancestor->IsNullPosition())
return E_INVALIDARG;
......@@ -914,8 +919,8 @@ HRESULT AXPlatformNodeTextRangeProviderWin::ScrollIntoView(BOOL align_to_top) {
root_frame_bounds.y() + root_frame_bounds.height());
}
if ((align_to_top && start_->GetAnchor()->IsText()) ||
(!align_to_top && end_->GetAnchor()->IsText())) {
if ((align_to_top && start()->GetAnchor()->IsText()) ||
(!align_to_top && end()->GetAnchor()->IsText())) {
const gfx::Rect text_range_frame_bounds =
common_ancestor_delegate->GetInnerTextRangeBoundsRect(
start_common_ancestor->text_offset(),
......@@ -955,7 +960,7 @@ HRESULT AXPlatformNodeTextRangeProviderWin::GetChildren(SAFEARRAY** children) {
std::vector<gfx::NativeViewAccessible> descendants;
const AXNode* common_anchor = start_->LowestCommonAnchor(*end_);
const AXNode* common_anchor = start()->LowestCommonAnchor(*end());
const AXTreeID tree_id = common_anchor->tree()->GetAXTreeID();
const AXNode::AXID node_id = common_anchor->id();
AXPlatformNodeDelegate* delegate = GetDelegate(tree_id, node_id);
......@@ -1036,7 +1041,7 @@ AXPlatformNodeTextRangeProviderWin::GetNextTextBoundaryPosition(
base::string16 AXPlatformNodeTextRangeProviderWin::GetString(
int max_count,
size_t* appended_newlines_count) {
AXNodeRange range(start_->Clone(), end_->Clone());
AXNodeRange range(start()->Clone(), end()->Clone());
return range.GetText(AXTextConcatenationBehavior::kAsInnerText, max_count,
false, appended_newlines_count);
}
......@@ -1125,7 +1130,7 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByPage(
int* units_moved) {
// Per UIA spec, if the document containing the current endpoint doesn't
// support pagination, default to document navigation.
AXPositionInstance common_ancestor = start_->LowestCommonAncestor(*end_);
AXPositionInstance common_ancestor = start()->LowestCommonAncestor(*end());
if (!common_ancestor->GetAnchor()->tree()->HasPaginationSupport())
return MoveEndpointByDocument(std::move(endpoint), count, units_moved);
......@@ -1190,7 +1195,7 @@ AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitHelper(
}
void AXPlatformNodeTextRangeProviderWin::NormalizeTextRange() {
if (!start_->IsValid() || !end_->IsValid())
if (!start()->IsValid() || !end()->IsValid())
return;
// If either endpoint is anchored to an ignored node,
......@@ -1201,63 +1206,63 @@ void AXPlatformNodeTextRangeProviderWin::NormalizeTextRange() {
// the TextPattern must be preserved so that the UIA client can handle
// scenarios such as determining which characters were deleted. So
// normalization must be bypassed.
if (HasCaretOrSelectionInPlainTextField(start_) ||
HasCaretOrSelectionInPlainTextField(end_)) {
if (HasCaretOrSelectionInPlainTextField(start()) ||
HasCaretOrSelectionInPlainTextField(end())) {
return;
}
AXPositionInstance normalized_start =
start_->AsLeafTextPositionBeforeCharacter();
start()->AsLeafTextPositionBeforeCharacter();
// For a degenerate range, the |end_| will always be the same as the
// normalized start, so there's no need to compute the normalized end.
// However, a degenerate range might go undetected if there's an ignored node
// (or many) between the two endpoints. For this reason, we need to
// compare the |end_| with both the |start_| and the |normalized_start|.
bool is_degenerate = *start_ == *end_ || *normalized_start == *end_;
bool is_degenerate = *start() == *end() || *normalized_start == *end();
AXPositionInstance normalized_end =
is_degenerate ? normalized_start->Clone()
: end_->AsLeafTextPositionAfterCharacter();
: end()->AsLeafTextPositionAfterCharacter();
if (!normalized_start->IsNullPosition() &&
!normalized_end->IsNullPosition()) {
start_ = std::move(normalized_start);
end_ = std::move(normalized_end);
SetStart(std::move(normalized_start));
SetEnd(std::move(normalized_end));
}
DCHECK_LE(*start_, *end_);
DCHECK_LE(*start(), *end());
}
void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredTextRange() {
if (!start_->IsValid() || !end_->IsValid())
if (!start()->IsValid() || !end()->IsValid())
return;
if (!start_->IsIgnored() && !end_->IsIgnored())
if (!start()->IsIgnored() && !end()->IsIgnored())
return;
if (start_->IsIgnored()) {
AXPositionInstance normalized_start =
start_->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
if (start()->IsIgnored()) {
AXPositionInstance normalized_start = start()->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveForward);
if (normalized_start->IsNullPosition()) {
normalized_start = start_->AsUnignoredPosition(
normalized_start = start()->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
}
if (!normalized_start->IsNullPosition())
start_ = std::move(normalized_start);
SetStart(std::move(normalized_start));
}
if (end_->IsIgnored()) {
if (end()->IsIgnored()) {
AXPositionInstance normalized_end =
end_->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
end()->AsUnignoredPosition(AXPositionAdjustmentBehavior::kMoveForward);
if (normalized_end->IsNullPosition()) {
normalized_end = end_->AsUnignoredPosition(
normalized_end = end()->AsUnignoredPosition(
AXPositionAdjustmentBehavior::kMoveBackward);
}
if (!normalized_end->IsNullPosition())
end_ = std::move(normalized_end);
SetEnd(std::move(normalized_end));
}
DCHECK_LE(*start_, *end_);
DCHECK_LE(*start(), *end());
}
AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetRootDelegate(
......@@ -1272,6 +1277,15 @@ AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetRootDelegate(
return root_platform_node->GetDelegate();
}
void AXPlatformNodeTextRangeProviderWin::SetStart(
AXPositionInstance new_start) {
endpoints_.SetStart(std::move(new_start));
}
void AXPlatformNodeTextRangeProviderWin::SetEnd(AXPositionInstance new_end) {
endpoints_.SetEnd(std::move(new_end));
}
AXNode* AXPlatformNodeTextRangeProviderWin::GetSelectionCommonAnchor() {
AXPlatformNodeDelegate* delegate = owner()->GetDelegate();
ui::AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
......@@ -1328,7 +1342,7 @@ void AXPlatformNodeTextRangeProviderWin::
AXPlatformNodeWin*
AXPlatformNodeTextRangeProviderWin::GetLowestAccessibleCommonPlatformNode()
const {
AXNode* common_anchor = start_->LowestCommonAnchor(*end_);
AXNode* common_anchor = start()->LowestCommonAnchor(*end());
if (!common_anchor)
return nullptr;
......@@ -1405,4 +1419,7 @@ bool AXPlatformNodeTextRangeProviderWin::ShouldReleaseTextAttributeAsSafearray(
!TextAttributeIsUiaReservedValue(attribute_value);
}
AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::TextRangeEndpoints() {}
AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::~TextRangeEndpoints() {}
} // namespace ui
......@@ -112,6 +112,8 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
base::string16 GetString(int max_count,
size_t* appended_newlines_count = nullptr);
AXPlatformNodeWin* owner() const;
const AXPositionInstance& start() const { return endpoints_.GetStart(); }
const AXPositionInstance& end() const { return endpoints_.GetEnd(); }
AXPlatformNodeDelegate* GetDelegate(
const AXPositionInstanceType* position) const;
AXPlatformNodeDelegate* GetDelegate(const AXTreeID tree_id,
......@@ -173,6 +175,9 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
bool HasCaretOrSelectionInPlainTextField(
const AXPositionInstance& position) const;
void SetStart(AXPositionInstance start);
void SetEnd(AXPositionInstance end);
static bool TextAttributeIsArrayType(TEXTATTRIBUTEID attribute_id);
static bool TextAttributeIsUiaReservedValue(
const base::win::VariantVector& vector);
......@@ -181,8 +186,23 @@ class AX_EXPORT __declspec(uuid("3071e40d-a10d-45ff-a59f-6e8e1138e2c1"))
const base::win::VariantVector& vector);
Microsoft::WRL::ComPtr<AXPlatformNodeWin> owner_;
AXPositionInstance start_;
AXPositionInstance end_;
class TextRangeEndpoints {
public:
TextRangeEndpoints();
~TextRangeEndpoints();
const AXPositionInstance& GetStart() const { return start_; }
const AXPositionInstance& GetEnd() const { return end_; }
void SetStart(AXPositionInstance new_start) {
start_ = std::move(new_start);
}
void SetEnd(AXPositionInstance new_end) { end_ = std::move(new_end); }
private:
AXPositionInstance start_;
AXPositionInstance end_;
};
TextRangeEndpoints endpoints_;
};
} // namespace ui
......
......@@ -165,12 +165,12 @@ class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
public:
const AXNodePosition::AXPositionInstance& GetStart(
const AXPlatformNodeTextRangeProviderWin* text_range) {
return text_range->start_;
return text_range->start();
}
const AXNodePosition::AXPositionInstance& GetEnd(
const AXPlatformNodeTextRangeProviderWin* text_range) {
return text_range->end_;
return text_range->end();
}
ui::AXPlatformNodeWin* GetOwner(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment