57 {
58
59class AXRangePhysicalPixelRectDelegate : public AXRangeRectDelegate {
60 public:
61 explicit AXRangePhysicalPixelRectDelegate(
62 AXPlatformNodeTextRangeProviderWin* host)
64
66 AXTreeID tree_id,
67 AXNode::AXID node_id,
68 int start_offset,
69 int end_offset,
71 AXOffscreenResult* offscreen_result) override {
72 AXPlatformNodeDelegate* delegate = host_->GetDelegate(tree_id, node_id);
74 return delegate->GetInnerTextRangeBoundsRect(
76 clipping_behavior, offscreen_result);
77 }
78
80 AXNode::AXID node_id,
81 AXOffscreenResult* offscreen_result) override {
82 AXPlatformNodeDelegate* delegate = host_->GetDelegate(tree_id, node_id);
84 return delegate->GetBoundsRect(
87 }
88
89 private:
90 AXPlatformNodeTextRangeProviderWin* host_;
91};
92
93AXPlatformNodeTextRangeProviderWin::AXPlatformNodeTextRangeProviderWin() {}
94
95AXPlatformNodeTextRangeProviderWin::~AXPlatformNodeTextRangeProviderWin() {}
96
97ITextRangeProvider* AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
98 AXPositionInstance
start,
99 AXPositionInstance
end) {
100 CComObject<AXPlatformNodeTextRangeProviderWin>* text_range_provider = nullptr;
101 if (
SUCCEEDED(CComObject<AXPlatformNodeTextRangeProviderWin>::CreateInstance(
102 &text_range_provider))) {
104 text_range_provider->SetStart(std::move(
start));
105 text_range_provider->SetEnd(std::move(
end));
106 text_range_provider->AddRef();
107 return text_range_provider;
108 }
109
110 return nullptr;
111}
112
113ITextRangeProvider*
114AXPlatformNodeTextRangeProviderWin::CreateTextRangeProviderForTesting(
115 AXPlatformNodeWin* owner,
116 AXPositionInstance
start,
117 AXPositionInstance
end) {
118 Microsoft::WRL::ComPtr<ITextRangeProvider> text_range_provider =
119 CreateTextRangeProvider(
start->Clone(),
end->Clone());
120 Microsoft::WRL::ComPtr<AXPlatformNodeTextRangeProviderWin>
121 text_range_provider_win;
122 if (
SUCCEEDED(text_range_provider->QueryInterface(
123 IID_PPV_ARGS(&text_range_provider_win)))) {
124 text_range_provider_win->SetOwnerForTesting(owner);
125 return text_range_provider_win.Get();
126 }
127
128 return nullptr;
129}
130
131
132
133
134HRESULT AXPlatformNodeTextRangeProviderWin::Clone(ITextRangeProvider** clone) {
136
137 *clone = CreateTextRangeProvider(
start()->Clone(),
end()->Clone());
138 return S_OK;
139}
140
141HRESULT AXPlatformNodeTextRangeProviderWin::Compare(ITextRangeProvider* other,
144
145 Microsoft::WRL::ComPtr<AXPlatformNodeTextRangeProviderWin> other_provider;
146 if (other->QueryInterface(IID_PPV_ARGS(&other_provider)) != S_OK)
147 return UIA_E_INVALIDOPERATION;
148
149 if (*
start() == *(other_provider->start()) &&
150 *
end() == *(other_provider->end())) {
152 }
153 return S_OK;
154}
155
156HRESULT AXPlatformNodeTextRangeProviderWin::CompareEndpoints(
157 TextPatternRangeEndpoint this_endpoint,
158 ITextRangeProvider* other,
159 TextPatternRangeEndpoint other_endpoint,
162
163 Microsoft::WRL::ComPtr<AXPlatformNodeTextRangeProviderWin> other_provider;
164 if (other->QueryInterface(IID_PPV_ARGS(&other_provider)) != S_OK)
165 return UIA_E_INVALIDOPERATION;
166
167 const AXPositionInstance& this_provider_endpoint =
168 (this_endpoint == TextPatternRangeEndpoint_Start) ?
start() :
end();
169 const AXPositionInstance& other_provider_endpoint =
170 (other_endpoint == TextPatternRangeEndpoint_Start)
171 ? other_provider->start()
172 : other_provider->end();
173
174 std::optional<int> comparison =
175 this_provider_endpoint->CompareTo(*other_provider_endpoint);
176 if (!comparison)
177 return UIA_E_INVALIDOPERATION;
178
179 if (comparison.value() < 0)
181 else if (comparison.value() > 0)
183 else
185 return S_OK;
186}
187
188HRESULT AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnit(
189 TextUnit unit) {
190 return ExpandToEnclosingUnitImpl(unit);
191}
192
193HRESULT AXPlatformNodeTextRangeProviderWin::ExpandToEnclosingUnitImpl(
194 TextUnit unit) {
196 {
197 AXPositionInstance normalized_start =
start()->Clone();
198 AXPositionInstance normalized_end =
end()->Clone();
199 NormalizeTextRange(normalized_start, normalized_end);
200 SetStart(std::move(normalized_start));
201 SetEnd(std::move(normalized_end));
202 }
203
204
205
206
207 switch (unit) {
208 case TextUnit_Character: {
209
210
211 AXPositionInstance end_backup =
end()->Clone();
212 SetEnd(
start()->CreateNextCharacterPosition(
213 AXBoundaryBehavior::CrossBoundary));
214
215 if (
end()->IsNullPosition()) {
216
217
218 AXPositionInstance start_backup =
start()->Clone();
219 SetStart(
start()->CreatePreviousCharacterPosition(
220 AXBoundaryBehavior::CrossBoundary));
221
222 if (
start()->IsNullPosition()) {
223
224 SetStart(std::move(start_backup));
225 SetEnd(std::move(end_backup));
226 return S_OK;
227 }
228 SetEnd(
start()->CreateNextCharacterPosition(
229 AXBoundaryBehavior::CrossBoundary));
231 }
232
233 AXPositionInstance normalized_start =
start()->Clone();
234 AXPositionInstance normalized_end =
end()->Clone();
235 NormalizeTextRange(normalized_start, normalized_end);
236 SetStart(std::move(normalized_start));
237 SetEnd(std::move(normalized_end));
238 break;
239 }
240 case TextUnit_Format:
241 SetStart(
start()->CreatePreviousFormatStartPosition(
242 AXBoundaryBehavior::StopAtAnchorBoundary));
243 SetEnd(
start()->CreateNextFormatEndPosition(
244 AXBoundaryBehavior::StopAtAnchorBoundary));
245 break;
246 case TextUnit_Word: {
247 AXPositionInstance start_backup =
start()->Clone();
248 SetStart(
start()->CreatePreviousWordStartPosition(
249 AXBoundaryBehavior::StopAtAnchorBoundary));
250
251
252
253
254
255 SetEnd(
start()->CreateNextWordStartPosition(
256 AXBoundaryBehavior::StopAtAnchorBoundary));
257 break;
258 }
259 case TextUnit_Line:
260
261
262
263
264
265 SetStart(
start()->CreateBoundaryStartPosition(
266 AXBoundaryBehavior::StopIfAlreadyAtBoundary,
268 &AtEndOfLinePredicate));
269
270
271 SetEnd(
start()->CreateBoundaryEndPosition(
272 AXBoundaryBehavior::StopAtLastAnchorBoundary,
274 &AtEndOfLinePredicate));
275 break;
276 case TextUnit_Paragraph:
277 SetStart(
start()->CreatePreviousParagraphStartPosition(
278 AXBoundaryBehavior::StopIfAlreadyAtBoundary));
279 SetEnd(
start()->CreateNextParagraphStartPosition(
280 AXBoundaryBehavior::StopAtLastAnchorBoundary));
281 break;
282 case TextUnit_Page: {
283
284
285 const AXNode* common_anchor =
start()->LowestCommonAnchor(*
end());
286 if (common_anchor->tree()->HasPaginationSupport()) {
287 SetStart(
start()->CreatePreviousPageStartPosition(
288 AXBoundaryBehavior::StopAtAnchorBoundary));
289 SetEnd(
start()->CreateNextPageEndPosition(
290 AXBoundaryBehavior::StopAtAnchorBoundary));
291 break;
292 }
293 }
294 [[fallthrough]];
295 case TextUnit_Document:
296 SetStart(
297 start()->CreatePositionAtStartOfDocument()->AsLeafTextPosition());
298 SetEnd(
start()->CreatePositionAtEndOfDocument());
299 break;
300 default:
301 return UIA_E_NOTSUPPORTED;
302 }
305 return S_OK;
306}
307
308HRESULT AXPlatformNodeTextRangeProviderWin::FindAttribute(
309 TEXTATTRIBUTEID text_attribute_id,
310 VARIANT attribute_val,
312 ITextRangeProvider**
result) {
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
342
343
344 AXPositionInstance normalized_start =
start()->Clone();
345 AXPositionInstance normalized_end =
end()->Clone();
346 NormalizeTextRange(normalized_start, normalized_end);
347
349 AXPositionInstance matched_range_start = nullptr;
350 AXPositionInstance matched_range_end = nullptr;
351
352 std::vector<AXNodeRange> anchors;
353 AXNodeRange range(normalized_start->Clone(), normalized_end->Clone());
354 for (AXNodeRange leaf_text_range : range)
355 anchors.emplace_back(
std::move(leaf_text_range));
356
357 auto expand_match = [&matched_range_start, &matched_range_end, is_backward](
358 auto& current_start, auto& current_end) {
359
360
361
362 if (matched_range_start != nullptr && matched_range_end != nullptr) {
363
364
365 if (is_backward)
366 matched_range_start = current_start->Clone();
367 else
368 matched_range_end = current_end->Clone();
369 } else {
370
371
372 matched_range_start = current_start->Clone();
373 matched_range_end = current_end->Clone();
374 }
375 };
376
377 HRESULT hr_result =
378 is_backward
379 ? FindAttributeRange(text_attribute_id, attribute_val,
380 anchors.crbegin(), anchors.crend(), expand_match)
381 : FindAttributeRange(text_attribute_id, attribute_val,
382 anchors.cbegin(), anchors.cend(), expand_match);
384 return E_FAIL;
385
386 if (matched_range_start != nullptr && matched_range_end != nullptr)
387 *
result = CreateTextRangeProvider(std::move(matched_range_start),
388 std::move(matched_range_end));
389 return S_OK;
390}
391
392template <typename AnchorIterator, typename ExpandMatchLambda>
393HRESULT AXPlatformNodeTextRangeProviderWin::FindAttributeRange(
394 const TEXTATTRIBUTEID text_attribute_id,
395 VARIANT attribute_val,
396 const AnchorIterator first,
397 const AnchorIterator last,
398 ExpandMatchLambda expand_match) {
399 AXPlatformNodeWin* current_platform_node;
400 bool is_match_found = false;
401
402 for (auto it = first; it != last; ++it) {
403 const auto& current_start = it->anchor();
404 const auto& current_end = it->focus();
405
406 BASE_DCHECK(current_start->GetAnchor() == current_end->GetAnchor());
407
408 AXPlatformNodeDelegate* delegate = GetDelegate(current_start);
410
411 current_platform_node = static_cast<AXPlatformNodeWin*>(
412 delegate->GetFromNodeID(current_start->GetAnchor()->id()));
413
415 if (
FAILED(current_platform_node->GetTextAttributeValue(
416 text_attribute_id, current_start->text_offset(),
417 current_end->text_offset(), ¤t_attribute_value))) {
418 return E_FAIL;
419 }
420
421 if (!current_attribute_value.
Compare(attribute_val)) {
422
423
424
425 is_match_found = true;
426 expand_match(current_start, current_end);
427 } else if (is_match_found) {
428
429
430
431 break;
432 }
433 }
434 return S_OK;
435}
436
438 const std::u16string_view find_in,
439 size_t* find_start,
440 size_t* find_length,
441 bool backwards) {
442 size_t index =
443 backwards ? find_in.rfind(search_string) : find_in.find(search_string);
444 if (index == std::u16string::npos) {
445 return false;
446 }
447 *find_start = index;
448 *find_length = search_string.size();
449 return true;
450}
451
453 std::u16string_view find_in,
454 size_t* find_start,
455 size_t* find_length,
456 bool ignore_case,
457 bool backwards) {
458 UErrorCode status = U_ZERO_ERROR;
459 UCollator* col = ucol_open(uloc_getDefault(), &status);
460 UStringSearch* search = usearch_openFromCollator(
461 search_string.data(), search_string.size(), find_in.data(),
462 find_in.size(), col, nullptr, &status);
463 if (!U_SUCCESS(status)) {
464 if (search) {
465 usearch_close(search);
466 }
468 backwards);
469 }
470 UCollator* collator = usearch_getCollator(search);
471 ucol_setStrength(collator, ignore_case ? UCOL_PRIMARY : UCOL_TERTIARY);
472 usearch_reset(search);
473 status = U_ZERO_ERROR;
474 usearch_setText(search, find_in.data(), find_in.size(), &status);
475 if (!U_SUCCESS(status)) {
476 if (search) {
477 usearch_close(search);
478 }
480 backwards);
481 }
482 int32_t index = backwards ? usearch_last(search, &status)
483 : usearch_first(search, &status);
485 if (U_SUCCESS(status) && index != USEARCH_DONE) {
487 *find_start = static_cast<size_t>(index);
488 *find_length = static_cast<size_t>(usearch_getMatchedLength(search));
489 }
490 usearch_close(search);
492}
493
494HRESULT AXPlatformNodeTextRangeProviderWin::FindText(
495 BSTR string,
498 ITextRangeProvider**
result) {
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520 ScopedAXEmbeddedObjectBehaviorSetter ax_embedded_object_behavior(
521 AXEmbeddedObjectBehavior::kSuppressCharacter);
522
524 if (search_string.length() <= 0)
525 return E_INVALIDARG;
526
527 size_t appended_newlines_count = 0;
528 std::u16string text_range = GetString(-1, &appended_newlines_count);
529 size_t find_start;
530 size_t find_length;
531 if (
StringSearch(search_string, text_range, &find_start, &find_length,
532 ignore_case, backwards) &&
533 find_length > appended_newlines_count) {
534
535
536
537
538
539
540 const AXNode* common_anchor =
start()->LowestCommonAnchor(*
end());
541 AXPositionInstance start_ancestor_position =
542 start()->CreateAncestorPosition(common_anchor,
544 BASE_DCHECK(!start_ancestor_position->IsNullPosition());
545 AXPositionInstance end_ancestor_position =
end()->CreateAncestorPosition(
547 BASE_DCHECK(!end_ancestor_position->IsNullPosition());
548 const AXNode* anchor = start_ancestor_position->GetAnchor();
550 const int start_offset =
551 start_ancestor_position->text_offset() + find_start;
552 const int end_offset = start_offset + find_length - appended_newlines_count;
553 const int max_end_offset = end_ancestor_position->text_offset();
554 BASE_DCHECK(start_offset <= end_offset && end_offset <= max_end_offset);
555
556 AXPositionInstance
start =
558 anchor->tree()->GetAXTreeID(), anchor->id(), start_offset,
560 ->AsLeafTextPosition();
561 AXPositionInstance
end =
563 anchor->tree()->GetAXTreeID(), anchor->id(), end_offset,
565 ->AsLeafTextPosition();
566
568 }
569 return S_OK;
570}
571
572HRESULT AXPlatformNodeTextRangeProviderWin::GetAttributeValue(
573 TEXTATTRIBUTEID attribute_id,
574 VARIANT* value) {
576
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593 if (attribute_id == UIA_IsReadOnlyAttributeId &&
594 start()->anchor_id() !=
end()->anchor_id() &&
595 start()->AtEndOfParagraph() &&
end()->AtStartOfParagraph() &&
596 *
start()->CreateNextCharacterPosition(
597 AXBoundaryBehavior::CrossBoundary) == *
end()) {
598 AXPlatformNodeWin* common_anchor = GetLowestAccessibleCommonPlatformNode();
600
601 HRESULT hr = common_anchor->GetTextAttributeValue(
602 attribute_id, std::nullopt, std::nullopt, &attribute_value);
603
605 return E_FAIL;
606
608 return S_OK;
609 }
610
611
612
613 AXPositionInstance normalized_start =
start()->Clone();
614 AXPositionInstance normalized_end =
end()->Clone();
615 NormalizeTextRange(normalized_start, normalized_end);
616
617
618 const auto end_leaf_text_position = normalized_end->AsLeafTextPosition();
619 auto end = end_leaf_text_position->CreateNextAnchorPosition();
620
621
622 for (auto it = normalized_start->AsLeafTextPosition();
623 it->anchor_id() !=
end->anchor_id() || it->tree_id() !=
end->tree_id();
624 it = it->CreateNextAnchorPosition()) {
625
626
627
629 if (it->IsNullPosition())
630 return E_FAIL;
631
632 AXPlatformNodeDelegate* delegate = GetDelegate(it.get());
634
635 AXPlatformNodeWin* platform_node = static_cast<AXPlatformNodeWin*>(
636 delegate->GetFromNodeID(it->anchor_id()));
638
639
640
641 platform_node = static_cast<AXPlatformNodeWin*>(
642 AXPlatformNode::FromNativeViewAccessible(
643 platform_node->GetDelegate()->GetLowestPlatformAncestor()));
645
647 const bool at_end_leaf_text_anchor =
648 it->anchor_id() == end_leaf_text_position->anchor_id() &&
649 it->tree_id() == end_leaf_text_position->tree_id();
650 const std::optional<int> start_offset =
651 it->IsTextPosition() ? std::make_optional(it->text_offset())
653 const std::optional<int> end_offset =
654 at_end_leaf_text_anchor
655 ? std::make_optional(end_leaf_text_position->text_offset())
657 HRESULT hr = platform_node->GetTextAttributeValue(
658 attribute_id, start_offset, end_offset, ¤t_value);
660 return E_FAIL;
661
662 if (attribute_value.
Type() == VT_EMPTY) {
663 attribute_value = std::move(current_value);
664 } else if (attribute_value != current_value) {
665 V_VT(value) = VT_UNKNOWN;
666 return ::UiaGetReservedMixedAttributeValue(&V_UNKNOWN(value));
667 }
668 }
669
670 if (ShouldReleaseTextAttributeAsSafearray(attribute_id, attribute_value))
672 else
674 return S_OK;
675}
676
677HRESULT AXPlatformNodeTextRangeProviderWin::GetBoundingRectangles(
678 SAFEARRAY** screen_physical_pixel_rectangles) {
680
681 *screen_physical_pixel_rectangles = nullptr;
682 AXNodeRange range(
start()->Clone(),
end()->Clone());
683 AXRangePhysicalPixelRectDelegate rect_delegate(this);
684 std::vector<gfx::Rect> rects = range.GetRects(&rect_delegate);
685
686
687 SAFEARRAY* safe_array = SafeArrayCreateVector(
688 VT_R8 , 0 , rects.size() * 4);
689
690 if (!safe_array)
691 return E_OUTOFMEMORY;
692
693 if (rects.size() > 0) {
694 double* double_array = nullptr;
695 HRESULT hr = SafeArrayAccessData(safe_array,
696 reinterpret_cast<void**>(&double_array));
697
699 for (size_t rect_index = 0; rect_index < rects.size(); rect_index++) {
701 double_array[rect_index * 4] =
rect.x();
702 double_array[rect_index * 4 + 1] =
rect.y();
703 double_array[rect_index * 4 + 2] =
rect.width();
704 double_array[rect_index * 4 + 3] =
rect.height();
705 }
706 hr = SafeArrayUnaccessData(safe_array);
707 }
708
711 SafeArrayDestroy(safe_array);
712 return E_FAIL;
713 }
714 }
715
716 *screen_physical_pixel_rectangles = safe_array;
717 return S_OK;
718}
719
720HRESULT AXPlatformNodeTextRangeProviderWin::GetEnclosingElement(
721 IRawElementProviderSimple** element) {
723
724 AXPlatformNodeWin* enclosing_node = GetLowestAccessibleCommonPlatformNode();
725 if (!enclosing_node)
726 return UIA_E_ELEMENTNOTAVAILABLE;
727
728 enclosing_node->GetNativeViewAccessible()->QueryInterface(
729 IID_PPV_ARGS(element));
730
732 return S_OK;
733}
734
735HRESULT AXPlatformNodeTextRangeProviderWin::GetText(
int max_count, BSTR*
text) {
737
738
739
740 if (max_count < -1)
741 return E_INVALIDARG;
742
744 if (!full_text.empty()) {
745 size_t length = full_text.length();
746
747 if (max_count != -1 && max_count <
static_cast<int>(
length))
748 *
text = SysAllocStringLen(full_text.c_str(), max_count);
749 else
750 *
text = SysAllocStringLen(full_text.c_str(),
length);
751 } else {
752 *
text = SysAllocString(L
"");
753 }
754 return S_OK;
755}
756
757HRESULT AXPlatformNodeTextRangeProviderWin::Move(TextUnit unit,
759 int* units_moved) {
761
762
764 return S_OK;
765
766
767 auto start_backup =
start()->Clone();
768 auto end_backup =
end()->Clone();
769 bool is_degenerate_range = (*
start() == *
end());
770
771
772
773 int start_units_moved = 0;
774 HRESULT hr = MoveEndpointByUnitImpl(TextPatternRangeEndpoint_Start, unit,
775 count, &start_units_moved);
776
777 bool succeeded_move =
SUCCEEDED(hr) && start_units_moved != 0;
778 if (succeeded_move) {
779 SetEnd(
start()->Clone());
780 if (!is_degenerate_range) {
781 bool forwards =
count > 0;
782 if (forwards &&
start()->AtEndOfDocument()) {
783
784
785
786 int current_start_units_moved = 0;
787 hr = MoveEndpointByUnitImpl(TextPatternRangeEndpoint_Start, unit, -1,
788 ¤t_start_units_moved);
789 start_units_moved -= 1;
790 succeeded_move =
SUCCEEDED(hr) && current_start_units_moved == -1 &&
791 start_units_moved > 0;
792 } else {
793
794
795
796 int end_units_moved = 0;
797 hr = MoveEndpointByUnitImpl(TextPatternRangeEndpoint_End, unit, 1,
798 &end_units_moved);
799 succeeded_move =
SUCCEEDED(hr) && end_units_moved == 1;
800 }
801
802
803
804
805 if (
start()->anchor_id() !=
end()->anchor_id() &&
806 (unit == TextUnit_Character || unit == TextUnit_Word)) {
807 ExpandToEnclosingUnitImpl(unit);
808 }
809 }
810 }
811
812 if (!succeeded_move) {
813 SetStart(std::move(start_backup));
814 SetEnd(std::move(end_backup));
815 start_units_moved = 0;
817 return hr;
818 }
819
820 *units_moved = start_units_moved;
821 return S_OK;
822}
823
824HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnit(
825 TextPatternRangeEndpoint endpoint,
826 TextUnit unit,
828 int* units_moved) {
829 return MoveEndpointByUnitImpl(endpoint, unit,
count, units_moved);
830}
831
832HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitImpl(
833 TextPatternRangeEndpoint endpoint,
834 TextUnit unit,
836 int* units_moved) {
838
839
841 *units_moved = 0;
842 return S_OK;
843 }
844
845 bool is_start_endpoint = endpoint == TextPatternRangeEndpoint_Start;
846 AXPositionInstance position_to_move =
847 is_start_endpoint ?
start()->Clone() :
end()->Clone();
848
849 AXPositionInstance new_position;
850
851
852 switch (unit) {
853 case TextUnit_Character:
854 new_position =
855 MoveEndpointByCharacter(position_to_move,
count, units_moved);
856 break;
857 case TextUnit_Word:
858 new_position = MoveEndpointByWord(position_to_move,
count, units_moved);
859 break;
860 case TextUnit_Line:
861 new_position = MoveEndpointByLine(position_to_move, is_start_endpoint,
863 break;
864 case TextUnit_Paragraph:
865 new_position = MoveEndpointByParagraph(
866 position_to_move, is_start_endpoint,
count, units_moved);
867 break;
868 case TextUnit_Page:
869 new_position = MoveEndpointByPage(position_to_move, is_start_endpoint,
871 break;
872 case TextUnit_Document:
873 new_position =
874 MoveEndpointByDocument(position_to_move,
count, units_moved);
875 break;
876 default:
877 return UIA_E_NOTSUPPORTED;
878 }
879 if (is_start_endpoint)
880 SetStart(std::move(new_position));
881 else
882 SetEnd(std::move(new_position));
883
884
885
886 std::optional<int> endpoint_comparison =
887 AXNodeRange::CompareEndpoints(
start().
get(),
end().
get());
889
890 if (endpoint_comparison.value_or(0) > 0) {
891 if (is_start_endpoint)
892 SetEnd(
start()->Clone());
893 else
894 SetStart(
end()->Clone());
895 }
896 return S_OK;
897}
898
899HRESULT AXPlatformNodeTextRangeProviderWin::MoveEndpointByRange(
900 TextPatternRangeEndpoint this_endpoint,
901 ITextRangeProvider* other,
902 TextPatternRangeEndpoint other_endpoint) {
904
905 Microsoft::WRL::ComPtr<AXPlatformNodeTextRangeProviderWin> other_provider;
906 if (other->QueryInterface(IID_PPV_ARGS(&other_provider)) != S_OK)
907 return UIA_E_INVALIDOPERATION;
908
909 const AXPositionInstance& other_provider_endpoint =
910 (other_endpoint == TextPatternRangeEndpoint_Start)
911 ? other_provider->start()
912 : other_provider->end();
913
914 if (this_endpoint == TextPatternRangeEndpoint_Start) {
915 SetStart(other_provider_endpoint->Clone());
917 SetEnd(
start()->Clone());
918 } else {
919 SetEnd(other_provider_endpoint->Clone());
921 SetStart(
end()->Clone());
922 }
923 return S_OK;
924}
925
926HRESULT AXPlatformNodeTextRangeProviderWin::Select() {
928
929 AXPositionInstance selection_start =
start()->Clone();
930 AXPositionInstance selection_end =
end()->Clone();
931
932
933
934
935 if (selection_start->tree_id() != selection_end->tree_id()) {
936
937
938 selection_start = selection_end->CreatePositionAtStartOfAXTree();
939 }
940
943 BASE_DCHECK(selection_start->tree_id() == selection_end->tree_id());
944
945
946
947
948
949 if (selection_start->GetAnchor()->IsInListMarker() ||
950 selection_end->GetAnchor()->IsInListMarker()) {
951 return S_OK;
952 }
953
954 AXPlatformNodeDelegate* delegate =
955 GetDelegate(selection_start->tree_id(), selection_start->anchor_id());
957
958 AXNodeRange new_selection_range(std::move(selection_start),
959 std::move(selection_end));
960 RemoveFocusFromPreviousSelectionIfNeeded(new_selection_range);
961
962 AXActionData action_data;
963 action_data.anchor_node_id = new_selection_range.anchor()->anchor_id();
964 action_data.anchor_offset = new_selection_range.anchor()->text_offset();
965 action_data.focus_node_id = new_selection_range.focus()->anchor_id();
966 action_data.focus_offset = new_selection_range.focus()->text_offset();
968
969 delegate->AccessibilityPerformAction(action_data);
970 return S_OK;
971}
972
973HRESULT AXPlatformNodeTextRangeProviderWin::AddToSelection() {
974
975 return UIA_E_INVALIDOPERATION;
976}
977
978HRESULT
979AXPlatformNodeTextRangeProviderWin::RemoveFromSelection() {
980
981 return UIA_E_INVALIDOPERATION;
982}
983
984HRESULT AXPlatformNodeTextRangeProviderWin::ScrollIntoView(
BOOL align_to_top) {
986
987 const AXPositionInstance start_common_ancestor =
988 start()->LowestCommonAncestor(*
end());
989 const AXPositionInstance end_common_ancestor =
990 end()->LowestCommonAncestor(*
start());
991 if (start_common_ancestor->IsNullPosition() ||
992 end_common_ancestor->IsNullPosition()) {
993 return E_INVALIDARG;
994 }
995
996 const AXNode* common_ancestor_anchor = start_common_ancestor->GetAnchor();
997 BASE_DCHECK(common_ancestor_anchor == end_common_ancestor->GetAnchor());
998
999 const AXTreeID common_ancestor_tree_id = start_common_ancestor->tree_id();
1000 const AXPlatformNodeDelegate* root_delegate =
1001 GetRootDelegate(common_ancestor_tree_id);
1003 const gfx::Rect root_frame_bounds = root_delegate->GetBoundsRect(
1004 AXCoordinateSystem::kFrame, AXClippingBehavior::kUnclipped);
1006
1007 const AXPlatformNode* common_ancestor_platform_node =
1008 GetOwner()->GetDelegate()->GetFromTreeIDAndNodeID(
1009 common_ancestor_tree_id, common_ancestor_anchor->id());
1011 AXPlatformNodeDelegate* common_ancestor_delegate =
1012 common_ancestor_platform_node->GetDelegate();
1014 const gfx::Rect text_range_container_frame_bounds =
1015 common_ancestor_delegate->GetBoundsRect(AXCoordinateSystem::kFrame,
1016 AXClippingBehavior::kUnclipped);
1018
1020 if (align_to_top) {
1021 target_point =
gfx::Point(root_frame_bounds.
x(), root_frame_bounds.
y());
1022 } else {
1023 target_point =
1025 root_frame_bounds.
y() + root_frame_bounds.
height());
1026 }
1027
1028 if ((align_to_top &&
start()->GetAnchor()->
IsText()) ||
1029 (!align_to_top &&
end()->GetAnchor()->
IsText())) {
1030 const gfx::Rect text_range_frame_bounds =
1031 common_ancestor_delegate->GetInnerTextRangeBoundsRect(
1032 start_common_ancestor->text_offset(),
1033 end_common_ancestor->text_offset(), AXCoordinateSystem::kFrame,
1034 AXClippingBehavior::kUnclipped);
1036
1037 if (align_to_top) {
1038 target_point.
Offset(0, -(text_range_container_frame_bounds.
height() -
1039 text_range_frame_bounds.
height()));
1040 } else {
1041 target_point.
Offset(0, -text_range_frame_bounds.
height());
1042 }
1043 } else {
1044 if (!align_to_top)
1045 target_point.
Offset(0, -text_range_container_frame_bounds.
height());
1046 }
1047
1048 const gfx::Rect root_screen_bounds = root_delegate->GetBoundsRect(
1049 AXCoordinateSystem::kScreenDIPs, AXClippingBehavior::kUnclipped);
1052
1053 AXActionData action_data;
1055 action_data.target_node_id = common_ancestor_anchor->id();
1056 action_data.target_point = target_point;
1057 if (!common_ancestor_delegate->AccessibilityPerformAction(action_data))
1058 return E_FAIL;
1059 return S_OK;
1060}
1061
1062
1063
1064
1065HRESULT AXPlatformNodeTextRangeProviderWin::GetChildren(SAFEARRAY** children) {
1067 std::vector<gfx::NativeViewAccessible> descendants;
1068
1069 AXPlatformNodeWin* start_anchor =
1070 GetPlatformNodeFromAXNode(
start()->GetAnchor());
1071 AXPlatformNodeWin* end_anchor = GetPlatformNodeFromAXNode(
end()->GetAnchor());
1072 AXPlatformNodeWin* common_anchor = GetLowestAccessibleCommonPlatformNode();
1073 if (!common_anchor || !start_anchor || !end_anchor)
1074 return UIA_E_ELEMENTNOTAVAILABLE;
1075
1076 SAFEARRAY* safe_array = SafeArrayCreateVector(VT_UNKNOWN, 0, 0);
1077
1078
1079
1080
1081 *children = safe_array;
1082 return S_OK;
1083}
1084
1085
1086bool AXPlatformNodeTextRangeProviderWin::AtStartOfLinePredicate(
1087 const AXPositionInstance& position) {
1088 return !position->IsIgnored() && position->AtStartOfAnchor() &&
1089 (position->AtStartOfLine() || position->AtStartOfInlineBlock());
1090}
1091
1092
1093bool AXPlatformNodeTextRangeProviderWin::AtEndOfLinePredicate(
1094 const AXPositionInstance& position) {
1095 return !position->IsIgnored() && position->AtEndOfAnchor() &&
1096 (position->AtEndOfLine() || position->AtStartOfInlineBlock());
1097}
1098
1099
1100AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1101AXPlatformNodeTextRangeProviderWin::GetNextTextBoundaryPosition(
1102 const AXPositionInstance& position,
1106
1108 switch (boundary_type) {
1110 return position->CreateBoundaryStartPosition(
options, boundary_direction,
1111 &AtStartOfLinePredicate,
1112 &AtEndOfLinePredicate);
1114 return position->CreateBoundaryEndPosition(
options, boundary_direction,
1115 &AtStartOfLinePredicate,
1116 &AtEndOfLinePredicate);
1117 default:
1118 return position->CreatePositionAtTextBoundary(
1119 boundary_type, boundary_direction,
options);
1120 }
1121}
1122
1123std::u16string AXPlatformNodeTextRangeProviderWin::GetString(
1124 int max_count,
1125 size_t* appended_newlines_count) {
1126 AXNodeRange range(
start()->Clone(),
end()->Clone());
1127 return range.GetText(AXTextConcatenationBehavior::kAsTextContent, max_count,
1128 false, appended_newlines_count);
1129}
1130
1131AXPlatformNodeWin* AXPlatformNodeTextRangeProviderWin::GetOwner() const {
1132
1133
1134 if (owner_for_test_.Get())
1135 return owner_for_test_.Get();
1136
1137 const AXPositionInstance& position =
1139
1140 if (position->IsNullPosition())
1141 return nullptr;
1142
1143 const AXNode* anchor = position->GetAnchor();
1145 const AXTreeManager* tree_manager =
1146 AXTreeManagerMap::GetInstance().GetManager(anchor->tree()->GetAXTreeID());
1148 const AXPlatformTreeManager* platform_tree_manager =
1149 static_cast<const AXPlatformTreeManager*>(tree_manager);
1150 return static_cast<AXPlatformNodeWin*>(
1151 platform_tree_manager->GetPlatformNodeFromTree(*anchor));
1152}
1153
1154AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetDelegate(
1155 const AXPositionInstanceType* position) const {
1156 return GetDelegate(position->tree_id(), position->anchor_id());
1157}
1158
1159AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetDelegate(
1160 const AXTreeID tree_id,
1161 const AXNode::AXID node_id) const {
1162 AXPlatformNode* platform_node =
1163 GetOwner()->GetDelegate()->GetFromTreeIDAndNodeID(tree_id, node_id);
1164 if (!platform_node)
1165 return nullptr;
1166
1167 return platform_node->GetDelegate();
1168}
1169
1170AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1171AXPlatformNodeTextRangeProviderWin::MoveEndpointByCharacter(
1172 const AXPositionInstance& endpoint,
1174 int* units_moved) {
1175 return MoveEndpointByUnitHelper(std::move(endpoint),
1177 units_moved);
1178}
1179
1180AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1181AXPlatformNodeTextRangeProviderWin::MoveEndpointByWord(
1182 const AXPositionInstance& endpoint,
1184 int* units_moved) {
1185 return MoveEndpointByUnitHelper(std::move(endpoint),
1187 units_moved);
1188}
1189
1190AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1191AXPlatformNodeTextRangeProviderWin::MoveEndpointByLine(
1192 const AXPositionInstance& endpoint,
1193 bool is_start_endpoint,
1195 int* units_moved) {
1196 return MoveEndpointByUnitHelper(std::move(endpoint),
1197 is_start_endpoint
1200 count, units_moved);
1201}
1202
1203AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1204AXPlatformNodeTextRangeProviderWin::MoveEndpointByParagraph(
1205 const AXPositionInstance& endpoint,
1206 const bool is_start_endpoint,
1208 int* units_moved) {
1209 return MoveEndpointByUnitHelper(std::move(endpoint),
1210 is_start_endpoint
1213 count, units_moved);
1214}
1215
1216AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1217AXPlatformNodeTextRangeProviderWin::MoveEndpointByPage(
1218 const AXPositionInstance& endpoint,
1219 const bool is_start_endpoint,
1221 int* units_moved) {
1222
1223
1224
1225
1226
1227
1228 AXPositionInstance common_ancestor =
start()->LowestCommonAncestor(*
end());
1229 if (!common_ancestor->GetAnchor()->tree()->HasPaginationSupport())
1230 return MoveEndpointByDocument(std::move(endpoint),
count, units_moved);
1231
1232 return MoveEndpointByUnitHelper(std::move(endpoint),
1233 is_start_endpoint
1236 count, units_moved);
1237}
1238
1239AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1240AXPlatformNodeTextRangeProviderWin::MoveEndpointByDocument(
1241 const AXPositionInstance& endpoint,
1243 int* units_moved) {
1245
1247 *units_moved = !endpoint->AtStartOfDocument() ? -1 : 0;
1248
1249 return endpoint->CreatePositionAtStartOfDocument();
1250 }
1251 *units_moved = !endpoint->AtEndOfDocument() ? 1 : 0;
1252 return endpoint->CreatePositionAtEndOfDocument();
1253}
1254
1255AXPlatformNodeTextRangeProviderWin::AXPositionInstance
1256AXPlatformNodeTextRangeProviderWin::MoveEndpointByUnitHelper(
1257 const AXPositionInstance& endpoint,
1260 int* units_moved) {
1265
1266 const AXNode* initial_endpoint = endpoint->GetAnchor();
1267
1268
1269
1270
1271 AXPositionInstance current_endpoint = endpoint->AsLeafTextPosition();
1272 AXPositionInstance next_endpoint = GetNextTextBoundaryPosition(
1273 current_endpoint, boundary_type,
1274 AXBoundaryBehavior::StopAtLastAnchorBoundary, boundary_direction);
1276
1277 bool is_ignored_for_text_navigation = false;
1278 int iteration = 0;
1279
1280
1281
1282
1283
1284 while (iteration < std::abs(
count) &&
1285 !(next_endpoint->GetAnchor() == current_endpoint->GetAnchor() &&
1286 *next_endpoint == *current_endpoint)) {
1287 is_ignored_for_text_navigation = false;
1288 current_endpoint = std::move(next_endpoint);
1289
1290 next_endpoint = GetNextTextBoundaryPosition(
1291 current_endpoint, boundary_type,
1292 AXBoundaryBehavior::StopAtLastAnchorBoundary, boundary_direction);
1294
1295
1296
1297
1298
1299
1300
1301 is_ignored_for_text_navigation =
1303 current_endpoint->GetAnchor()->data().role !=
1305 if (!is_ignored_for_text_navigation)
1306 iteration++;
1307 }
1308
1309 *units_moved = (
count > 0) ? iteration : -iteration;
1310
1311 if (is_ignored_for_text_navigation &&
1312 initial_endpoint != current_endpoint->GetAnchor()) {
1313
1314
1315
1316 *units_moved += (
count > 0) ? 1 : -1;
1317 }
1318
1319 return current_endpoint;
1320}
1321
1322void AXPlatformNodeTextRangeProviderWin::NormalizeTextRange(
1323 AXPositionInstance&
start,
1324 AXPositionInstance&
end) {
1325 if (!
start->IsValid() || !
end->IsValid())
1326 return;
1327
1328
1329
1330 NormalizeAsUnignoredTextRange(
start,
end);
1331
1333 AXPositionInstance normalized_start =
1335 :
start->AsLeafTextPositionBeforeCharacter();
1336
1337
1338
1339
1340
1341
1343 AXPositionInstance normalized_end =
1345 :
end->AsLeafTextPositionAfterCharacter();
1346
1347 if (!normalized_start->IsNullPosition() &&
1348 !normalized_end->IsNullPosition()) {
1349 start = std::move(normalized_start);
1350 end = std::move(normalized_end);
1351 }
1352
1354}
1355
1356
1357void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredPosition(
1358 AXPositionInstance& position) {
1359 if (position->IsNullPosition() || !position->IsValid())
1360 return;
1361
1362 if (position->IsIgnored()) {
1363 AXPositionInstance normalized_position = position->AsUnignoredPosition(
1364 AXPositionAdjustmentBehavior::kMoveForward);
1365 if (normalized_position->IsNullPosition()) {
1366 normalized_position = position->AsUnignoredPosition(
1367 AXPositionAdjustmentBehavior::kMoveBackward);
1368 }
1369
1370 if (!normalized_position->IsNullPosition())
1371 position = std::move(normalized_position);
1372 }
1374}
1375
1376
1377void AXPlatformNodeTextRangeProviderWin::NormalizeAsUnignoredTextRange(
1378 AXPositionInstance&
start,
1379 AXPositionInstance&
end) {
1380 if (!
start->IsValid() || !
end->IsValid())
1381 return;
1382
1383 if (!
start->IsIgnored() && !
end->IsIgnored())
1384 return;
1385 NormalizeAsUnignoredPosition(
start);
1386 NormalizeAsUnignoredPosition(
end);
1388}
1389
1390AXPlatformNodeDelegate* AXPlatformNodeTextRangeProviderWin::GetRootDelegate(
1392 const AXTreeManager* ax_tree_manager =
1393 AXTreeManagerMap::GetInstance().GetManager(tree_id);
1395 AXNode* root_node = ax_tree_manager->GetRootAsAXNode();
1396 const AXPlatformNode* root_platform_node =
1397 GetOwner()->GetDelegate()->GetFromTreeIDAndNodeID(tree_id,
1398 root_node->id());
1400 return root_platform_node->GetDelegate();
1401}
1402
1403void AXPlatformNodeTextRangeProviderWin::SetStart(
1404 AXPositionInstance new_start) {
1405 endpoints_.SetStart(std::move(new_start));
1406}
1407
1408void AXPlatformNodeTextRangeProviderWin::SetEnd(AXPositionInstance new_end) {
1409 endpoints_.SetEnd(std::move(new_end));
1410}
1411
1412void AXPlatformNodeTextRangeProviderWin::SetOwnerForTesting(
1413 AXPlatformNodeWin* owner) {
1414 owner_for_test_ = owner;
1415}
1416
1417AXNode* AXPlatformNodeTextRangeProviderWin::GetSelectionCommonAnchor() {
1418 AXPlatformNodeDelegate* delegate = GetOwner()->GetDelegate();
1419 AXTree::Selection unignored_selection = delegate->GetUnignoredSelection();
1420 AXPlatformNode* anchor_object =
1421 delegate->GetFromNodeID(unignored_selection.anchor_object_id);
1422 AXPlatformNode* focus_object =
1423 delegate->GetFromNodeID(unignored_selection.focus_object_id);
1424
1425 if (!anchor_object || !focus_object)
1426 return nullptr;
1427
1428 AXNodePosition::AXPositionInstance
start =
1429 anchor_object->GetDelegate()->CreateTextPositionAt(
1430 unignored_selection.anchor_offset);
1431 AXNodePosition::AXPositionInstance
end =
1432 focus_object->GetDelegate()->CreateTextPositionAt(
1433 unignored_selection.focus_offset);
1434
1435 return start->LowestCommonAnchor(*
end);
1436}
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448void AXPlatformNodeTextRangeProviderWin::
1449 RemoveFocusFromPreviousSelectionIfNeeded(const AXNodeRange& new_selection) {
1450 const AXNode* old_selection_node = GetSelectionCommonAnchor();
1451 const AXNode* new_selection_node =
1452 new_selection.anchor()->LowestCommonAnchor(*new_selection.focus());
1453
1454 if (!old_selection_node)
1455 return;
1456
1457 if (!new_selection_node ||
1460 AXPlatformNodeDelegate* root_delegate =
1461 GetRootDelegate(old_selection_node->tree()->GetAXTreeID());
1463
1464 AXActionData focus_action;
1466 root_delegate->AccessibilityPerformAction(focus_action);
1467 }
1468}
1469
1470AXPlatformNodeWin*
1471AXPlatformNodeTextRangeProviderWin::GetPlatformNodeFromAXNode(
1472 const AXNode* node) const {
1473 if (!node)
1474 return nullptr;
1475
1476
1477 AXPlatformNodeWin* platform_node =
1478 static_cast<AXPlatformNodeWin*>(AXPlatformNode::FromNativeViewAccessible(
1479 GetDelegate(node->tree()->GetAXTreeID(), node->id())
1480 ->GetNativeViewAccessible()));
1482
1483 return platform_node;
1484}
1485
1486AXPlatformNodeWin*
1487AXPlatformNodeTextRangeProviderWin::GetLowestAccessibleCommonPlatformNode()
1488 const {
1489 AXNode* common_anchor =
start()->LowestCommonAnchor(*
end());
1490 if (!common_anchor)
1491 return nullptr;
1492
1493 return GetPlatformNodeFromAXNode(common_anchor)->GetLowestAccessibleElement();
1494}
1495
1496
1497bool AXPlatformNodeTextRangeProviderWin::TextAttributeIsArrayType(
1498 TEXTATTRIBUTEID attribute_id) {
1499
1500 return attribute_id == UIA_AnnotationObjectsAttributeId ||
1501 attribute_id == UIA_AnnotationTypesAttributeId ||
1502 attribute_id == UIA_TabsAttributeId;
1503}
1504
1505
1506bool AXPlatformNodeTextRangeProviderWin::TextAttributeIsUiaReservedValue(
1508
1509 if (vector.
Type() != VT_UNKNOWN)
1510 return false;
1511
1513 {
1514 Microsoft::WRL::ComPtr<IUnknown> mixed_attribute_value;
1515 HRESULT hr = ::UiaGetReservedMixedAttributeValue(&mixed_attribute_value);
1517 mixed_attribute_value_variant.
Set(mixed_attribute_value.Get());
1518 }
1519
1521 {
1522 Microsoft::WRL::ComPtr<IUnknown> not_supported_value;
1523 HRESULT hr = ::UiaGetReservedNotSupportedValue(¬_supported_value);
1525 not_supported_value_variant.
Set(not_supported_value.Get());
1526 }
1527
1528 return !vector.
Compare(mixed_attribute_value_variant) ||
1529 !vector.
Compare(not_supported_value_variant);
1530}
1531
1532
1533bool AXPlatformNodeTextRangeProviderWin::ShouldReleaseTextAttributeAsSafearray(
1534 TEXTATTRIBUTEID attribute_id,
1536
1537
1538 return TextAttributeIsArrayType(attribute_id) &&
1539 !TextAttributeIsUiaReservedValue(attribute_value);
1540}
1541
1542AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::TextRangeEndpoints() {
1543 start_ = AXNodePosition::CreateNullPosition();
1544 end_ = AXNodePosition::CreateNullPosition();
1545}
1546
1547AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::~TextRangeEndpoints() {
1548 SetStart(AXNodePosition::CreateNullPosition());
1549 SetEnd(AXNodePosition::CreateNullPosition());
1550}
1551
1552void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::SetStart(
1553 AXPositionInstance new_start) {
1554 bool did_tree_change = start_->tree_id() != new_start->tree_id();
1555
1556
1557
1558 if (did_tree_change && start_->kind() != AXPositionKind::NULL_POSITION &&
1559 start_->tree_id() != end_->tree_id()) {
1560 RemoveObserver(start_->tree_id());
1561 }
1562
1563 start_ = std::move(new_start);
1564
1565 if (did_tree_change && !start_->IsNullPosition() &&
1566 start_->tree_id() != end_->tree_id()) {
1567 AddObserver(start_->tree_id());
1568 }
1569}
1570
1571void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::SetEnd(
1572 AXPositionInstance new_end) {
1573 bool did_tree_change = end_->tree_id() != new_end->tree_id();
1574
1575
1576
1577 if (did_tree_change && end_->kind() != AXPositionKind::NULL_POSITION &&
1578 end_->tree_id() != start_->tree_id()) {
1579 RemoveObserver(end_->tree_id());
1580 }
1581
1582 end_ = std::move(new_end);
1583
1584 if (did_tree_change && !end_->IsNullPosition() &&
1585 start_->tree_id() != end_->tree_id()) {
1586 AddObserver(end_->tree_id());
1587 }
1588}
1589
1590void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::AddObserver(
1591 const AXTreeID tree_id) {
1592 AXTreeManager* ax_tree_manager =
1593 AXTreeManagerMap::GetInstance().GetManager(tree_id);
1595 ax_tree_manager->GetTree()->AddObserver(this);
1596}
1597
1598void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::RemoveObserver(
1599 const AXTreeID tree_id) {
1600 AXTreeManager* ax_tree_manager =
1601 AXTreeManagerMap::GetInstance().GetManager(tree_id);
1602 if (ax_tree_manager)
1603 ax_tree_manager->GetTree()->RemoveObserver(this);
1604}
1605
1606
1607
1608void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::
1609 OnSubtreeWillBeDeleted(AXTree* tree, AXNode* node) {
1610
1611
1612
1613
1614
1617 BASE_DCHECK(tree->GetAXTreeID() == node->tree()->GetAXTreeID());
1618
1619 AdjustEndpointForSubtreeDeletion(tree, node, true );
1620 AdjustEndpointForSubtreeDeletion(tree, node, false );
1621}
1622
1623void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::
1624 AdjustEndpointForSubtreeDeletion(AXTree* tree,
1625 const AXNode* const node,
1626 bool is_start_endpoint) {
1627 AXPositionInstance endpoint =
1628 is_start_endpoint ? start_->Clone() : end_->Clone();
1629 if (tree->GetAXTreeID() != endpoint->tree_id())
1630 return;
1631
1632
1633
1634
1635 AXNode* endpoint_anchor = endpoint->GetAnchor();
1636 if (!node->parent() || !endpoint_anchor) {
1637 is_start_endpoint ? SetStart(AXNodePosition::CreateNullPosition())
1638 : SetEnd(AXNodePosition::CreateNullPosition());
1639 return;
1640 }
1641
1642 DeletionOfInterest deletion_of_interest = {tree->GetAXTreeID(), node->id()};
1643
1644
1645
1646
1647 if (endpoint->kind() == AXPositionKind::TREE_POSITION &&
1648 endpoint_anchor == node->parent()) {
1649 if (is_start_endpoint)
1650 validation_necessary_for_start_ = deletion_of_interest;
1651 else
1652 validation_necessary_for_end_ = deletion_of_interest;
1653 return;
1654 }
1655
1656
1657
1658
1659
1660 if (!endpoint_anchor->IsDescendantOfCrossingTreeBoundary(node))
1661 return;
1662
1663 AXPositionInstance new_endpoint = endpoint->CreateAncestorPosition(
1665
1666
1667
1668 new_endpoint = new_endpoint->CreateParentPosition();
1669 AXPositionInstance other_endpoint =
1670 is_start_endpoint ? end_->Clone() : start_->Clone();
1671
1672
1673
1674 NormalizeAsUnignoredPosition(new_endpoint);
1675 NormalizeAsUnignoredPosition(other_endpoint);
1678
1679
1680
1681
1682
1683 endpoint_anchor = new_endpoint->GetAnchor();
1684 if (!endpoint_anchor ||
1685 endpoint_anchor->IsDescendantOfCrossingTreeBoundary(node))
1686 new_endpoint = AXNodePosition::CreateNullPosition();
1687
1688
1689
1690
1691
1692
1693
1694 if (is_start_endpoint) {
1695 if (*other_endpoint < *new_endpoint)
1696 SetEnd(new_endpoint->Clone());
1697
1698 SetStart(std::move(new_endpoint));
1699 validation_necessary_for_start_ = deletion_of_interest;
1700 } else {
1701 if (*new_endpoint < *other_endpoint)
1702 SetStart(new_endpoint->Clone());
1703
1704 SetEnd(std::move(new_endpoint));
1705 validation_necessary_for_end_ = deletion_of_interest;
1706 }
1707}
1708
1709
1710
1711void AXPlatformNodeTextRangeProviderWin::TextRangeEndpoints::OnNodeDeleted(
1712 AXTree* tree,
1713 AXNode::AXID node_id) {
1715
1716 if (validation_necessary_for_start_.has_value() &&
1717 validation_necessary_for_start_->tree_id == tree->GetAXTreeID() &&
1718 validation_necessary_for_start_->node_id == node_id) {
1719 if (!start_->IsNullPosition() && start_->GetAnchor()->data().id != 0)
1720 SetStart(start_->AsValidPosition());
1721 else
1722 SetStart(AXNodePosition::CreateNullPosition());
1723
1724 validation_necessary_for_start_ = std::nullopt;
1725 }
1726
1727 if (validation_necessary_for_end_.has_value() &&
1728 validation_necessary_for_end_->tree_id == tree->GetAXTreeID() &&
1729 validation_necessary_for_end_->node_id == node_id) {
1730 if (!end_->IsNullPosition() && end_->GetAnchor()->data().id != 0)
1731 SetEnd(end_->AsValidPosition());
1732 else
1733 SetEnd(AXNodePosition::CreateNullPosition());
1734
1735 validation_necessary_for_end_ = std::nullopt;
1736 }
1737}
1738
1739}
static bool match(const char *needle, const char *haystack)
static bool is_degenerate(const SkPath &path)
void Set(const wchar_t *str)
VARIANT ReleaseAsSafearrayVariant()
int Compare(const VARIANT &other, bool ignore_case=false) const
VARIANT ReleaseAsScalarVariant()
void Offset(int delta_x, int delta_y)
constexpr int height() const
Vector2d OffsetFromOrigin() const
static AXPositionInstance CreateTextPosition(AXTreeID tree_id, AXNode::AXID anchor_id, int text_offset, ax::mojom::TextAffinity affinity)
sk_sp< SkBlender > blender SkRect rect
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service host
std::u16string WideStringToUtf16(const std::wstring_view str)
std::wstring Utf16ToWideString(const std::u16string_view str)
static bool StringSearchBasic(const std::u16string_view search_string, const std::u16string_view find_in, size_t *find_start, size_t *find_length, bool backwards)
bool StringSearch(std::u16string_view search_string, std::u16string_view find_in, size_t *find_start, size_t *find_length, bool ignore_case, bool backwards)
bool IsText(ax::mojom::Role role)
#define BASE_DCHECK(condition)