5#ifndef UI_ACCESSIBILITY_AX_RANGE_H_
6#define UI_ACCESSIBILITY_AX_RANGE_H_
50template <
class AXPositionType>
56 : anchor_(AXPositionType::CreateNullPosition()),
57 focus_(AXPositionType::CreateNullPosition()) {}
60 anchor_ =
anchor ? std::move(
anchor) : AXPositionType::CreateNullPosition();
61 focus_ =
focus ? std::move(
focus) : AXPositionType::CreateNullPosition();
67 anchor_.swap(other.anchor_);
68 focus_.swap(other.focus_);
87 anchor_ = AXPositionType::CreateNullPosition();
88 focus_ = AXPositionType::CreateNullPosition();
89 anchor_.swap(other.anchor_);
90 focus_.swap(other.focus_);
99 *focus_ == *other.
focus();
118 const AXPositionType* second) {
119 std::optional<int> tree_position_comparison =
120 first->AsTreePosition()->CompareTo(*second->AsTreePosition());
124 return (tree_position_comparison.value_or(1) != 0)
125 ? tree_position_comparison
126 : first->CompareTo(*second);
131 ?
AXRange(focus_->Clone(), anchor_->Clone())
132 :
AXRange(anchor_->Clone(), focus_->Clone());
137 ?
AXRange(focus_->Clone(), anchor_->Clone())
138 :
AXRange(anchor_->Clone(), focus_->Clone());
146 return !
IsNull() && anchor_->GetAnchor() == focus_->GetAnchor() &&
147 anchor_->IsLeafTextPosition() && focus_->IsLeafTextPosition();
152 return anchor_->IsNullPosition() || focus_->IsNullPosition();
156 return "Range\nAnchor:" + anchor_->ToString() +
157 "\nFocus:" + focus_->ToString();
193 class Iterator :
public std::iterator<std::input_iterator_tag, AXRange> {
196 : current_start_(AXPositionType::CreateNullPosition()),
197 iterator_end_(AXPositionType::CreateNullPosition()) {}
200 if (
end && !
end->IsNullPosition()) {
201 current_start_ = !
start ? AXPositionType::CreateNullPosition()
202 :
start->AsLeafTextPosition();
203 iterator_end_ =
end->AsLeafTextPosition();
205 current_start_ = AXPositionType::CreateNullPosition();
206 iterator_end_ = AXPositionType::CreateNullPosition();
213 : current_start_(
std::move(other.current_start_)),
214 iterator_end_(
std::move(other.iterator_end_)) {}
219 return current_start_->GetAnchor() == other.current_start_->GetAnchor() &&
220 iterator_end_->GetAnchor() == other.iterator_end_->GetAnchor() &&
221 *current_start_ == *other.current_start_ &&
222 *iterator_end_ == *other.iterator_end_;
230 if (current_start_->GetAnchor() == iterator_end_->GetAnchor()) {
231 current_start_ = AXPositionType::CreateNullPosition();
233 current_start_ = current_start_->CreateNextLeafTreePosition();
242 (current_start_->GetAnchor() != iterator_end_->GetAnchor())
243 ? current_start_->CreatePositionAtEndOfAnchor()
244 : iterator_end_->Clone();
247 AXRange current_leaf_text_range(current_start_->AsTextPosition(),
248 current_end->AsTextPosition());
250 return std::move(current_leaf_text_range);
262 return Iterator(std::move(forward_range.anchor_),
263 std::move(forward_range.focus_));
270 return Iterator(
nullptr, std::move(forward_range.focus_));
281 bool include_ignored =
false,
282 size_t* appended_newlines_count =
nullptr)
const {
283 if (max_count == 0 ||
IsNull())
284 return std::u16string();
286 std::optional<int> endpoint_comparison =
288 if (!endpoint_comparison)
289 return std::u16string();
292 ? anchor_->AsLeafTextPosition()
293 : focus_->AsLeafTextPosition();
295 ? focus_->AsLeafTextPosition()
296 : anchor_->AsLeafTextPosition();
298 std::u16string range_text;
299 size_t computed_newlines_count = 0;
300 bool is_first_non_whitespace_leaf =
true;
301 bool crossed_paragraph_boundary =
false;
302 bool is_first_unignored_leaf =
true;
303 bool found_trailing_newline =
false;
305 while (!
start->IsNullPosition()) {
309 if (include_ignored || !
start->IsIgnored()) {
310 if (concatenation_behavior ==
312 !
start->IsInWhiteSpace()) {
313 if (is_first_non_whitespace_leaf) {
318 crossed_paragraph_boundary =
319 !is_first_unignored_leaf &&
start->AtStartOfParagraph();
324 if (crossed_paragraph_boundary && !found_trailing_newline) {
326 computed_newlines_count++;
329 is_first_non_whitespace_leaf =
false;
330 crossed_paragraph_boundary =
false;
333 int current_end_offset = (
start->GetAnchor() !=
end->GetAnchor())
334 ?
start->MaxTextOffset()
335 :
end->text_offset();
337 if (current_end_offset >
start->text_offset()) {
338 int characters_to_append =
340 ?
std::min(max_count -
static_cast<int>(range_text.length()),
341 current_end_offset -
start->text_offset())
342 : current_end_offset -
start->text_offset();
344 range_text +=
start->GetText().substr(
start->text_offset(),
345 characters_to_append);
348 found_trailing_newline =
349 start->IsInLineBreak() ||
350 (found_trailing_newline &&
start->IsInWhiteSpace());
354 static_cast<int>(range_text.length()) <= max_count);
355 is_first_unignored_leaf =
false;
358 if (
start->GetAnchor() ==
end->GetAnchor() ||
359 static_cast<int>(range_text.length()) == max_count) {
361 }
else if (concatenation_behavior ==
363 !crossed_paragraph_boundary && !is_first_non_whitespace_leaf) {
364 start =
start->CreateNextLeafTextPosition(&crossed_paragraph_boundary);
370 if (appended_newlines_count)
371 *appended_newlines_count = computed_newlines_count;
379 std::vector<gfx::Rect> rects;
381 for (
const AXRange& leaf_text_range : *
this) {
383 AXPositionType* current_line_start = leaf_text_range.
anchor();
384 AXPositionType* current_line_end = leaf_text_range.
focus();
391 (current_line_start->IsInLineBreak() ||
392 current_line_start->IsInTextObject())
394 current_line_start->tree_id(),
395 current_line_start->anchor_id(),
396 current_line_start->text_offset(),
397 current_line_end->text_offset(),
400 current_line_start->anchor_id(),
414 rects.push_back(current_rect);
424template <
class AXPositionType>
virtual gfx::Rect GetInnerTextRangeBoundsRect(AXTreeID tree_id, AXNode::AXID node_id, int start_offset, int end_offset, ui::AXClippingBehavior clipping_behavior, AXOffscreenResult *offscreen_result)=0
virtual gfx::Rect GetBoundsRect(AXTreeID tree_id, AXNode::AXID node_id, AXOffscreenResult *offscreen_result)=0
bool operator!=(const Iterator &other) const
Iterator(AXPositionInstance start, AXPositionInstance end)
AXRange operator*() const
Iterator(Iterator &&other)
bool operator==(const Iterator &other) const
Iterator(const Iterator &other)=delete
AXPositionType * anchor() const
AXRange & operator=(const AXRange &other)=delete
std::vector< gfx::Rect > GetRects(AXRangeRectDelegate *delegate) const
static std::optional< int > CompareEndpoints(const AXPositionType *first, const AXPositionType *second)
std::string ToString() const
AXRange AsForwardRange() const
bool IsLeafTextRange() const
virtual ~AXRange()=default
std::u16string GetText(AXTextConcatenationBehavior concatenation_behavior=AXTextConcatenationBehavior::kAsTextContent, int max_count=-1, bool include_ignored=false, size_t *appended_newlines_count=nullptr) const
std::unique_ptr< AXPositionType > AXPositionInstance
AXPositionType * focus() const
AXRange(AXPositionInstance anchor, AXPositionInstance focus)
bool operator==(const AXRange &other) const
AXRange & operator=(AXRange &&other)
AXRange(const AXRange &other)=delete
bool operator!=(const AXRange &other) const
AXRange AsBackwardRange() const
static float min(float r, float g, float b)
std::u16string ASCIIToUTF16(std::string src)
std::ostream & operator<<(std::ostream &os, AXEventGenerator::Event event)
AXTextConcatenationBehavior
#define BASE_DCHECK(condition)