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