Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
test_ax_node_wrapper.cc
Go to the documentation of this file.
1// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <map>
8#include <utility>
9
10#include "ax/ax_action_data.h"
12#include "ax/ax_table_info.h"
13#include "ax/ax_tree_observer.h"
15#include "base/string_utils.h"
17
18namespace ui {
19
20namespace {
21
22// A global map from AXNodes to TestAXNodeWrappers.
23std::map<AXNode::AXID, TestAXNodeWrapper*> g_node_id_to_wrapper_map;
24
25// A global coordinate offset.
26gfx::Vector2d g_offset;
27
28// A global scale factor.
29float g_scale_factor = 1.0;
30
31// A global map that stores which node is focused on a determined tree.
32// - If a tree has no node being focused, there shouldn't be any entry on the
33// map associated with such tree, i.e. a pair {tree, nullptr} is invalid.
34// - For testing purposes, assume there is a single node being focused in the
35// entire tree and if such node is deleted, focus is completely lost.
36std::map<AXTree*, AXNode*> g_focused_node_in_tree;
37
38// A global indicating the last node which ShowContextMenu was called from.
39AXNode* g_node_from_last_show_context_menu;
40
41// A global indicating the last node which accessibility perform action
42// default action was called from.
43AXNode* g_node_from_last_default_action;
44
45// A global indicating that AXPlatformNodeDelegate objects are web content.
46bool g_is_web_content = false;
47
48// A map of hit test results - a map from source node ID to destination node
49// ID.
50std::map<AXNode::AXID, AXNode::AXID> g_hit_test_result;
51
52// A simple implementation of AXTreeObserver to catch when AXNodes are
53// deleted so we can delete their wrappers.
54class TestAXTreeObserver : public AXTreeObserver {
55 private:
56 void OnNodeDeleted(AXTree* tree, int32_t node_id) override {
57 const auto& iter = g_node_id_to_wrapper_map.find(node_id);
58 if (iter != g_node_id_to_wrapper_map.end()) {
59 TestAXNodeWrapper* wrapper = iter->second;
60 const auto& focus_iter = g_focused_node_in_tree.find(tree);
61 if (focus_iter != g_focused_node_in_tree.end() &&
62 focus_iter->second->id() == node_id) {
63 g_focused_node_in_tree.erase(tree);
64 }
65 delete wrapper;
66 g_node_id_to_wrapper_map.erase(node_id);
67 }
68 }
69};
70
71TestAXTreeObserver g_ax_tree_observer;
72
73} // namespace
74
75// static
77 if (!tree || !node)
78 return nullptr;
79
80 if (!tree->HasObserver(&g_ax_tree_observer))
81 tree->AddObserver(&g_ax_tree_observer);
82 auto iter = g_node_id_to_wrapper_map.find(node->id());
83 if (iter != g_node_id_to_wrapper_map.end())
84 return iter->second;
85 TestAXNodeWrapper* wrapper = new TestAXNodeWrapper(tree, node);
86 g_node_id_to_wrapper_map[node->id()] = wrapper;
87 return wrapper;
88}
89
90// static
94
95// static
97 return g_node_from_last_show_context_menu;
98}
99
100// static
102 return g_node_from_last_default_action;
103}
104
105// static
107 g_node_from_last_default_action = node;
108}
109
110// static
111std::unique_ptr<base::AutoReset<float>> TestAXNodeWrapper::SetScaleFactor(
112 float value) {
113 return std::make_unique<base::AutoReset<float>>(&g_scale_factor, value);
114}
115
116// static
118 g_is_web_content = is_web_content;
119}
120
121// static
123 AXNode::AXID dst_node_id) {
124 g_hit_test_result[src_node_id] = dst_node_id;
125}
126
127// static
129 g_hit_test_result.clear();
130}
131
133 platform_node_->Destroy();
134}
135
137 return node_->data();
138}
139
141 return tree_->data();
142}
143
147
154
158
160 TestAXNodeWrapper* parent_wrapper =
161 GetOrCreate(tree_, node_->GetUnignoredParent());
162 return parent_wrapper
163 ? parent_wrapper->ax_platform_node()->GetNativeViewAccessible()
164 : nullptr;
165}
166
170
172 TestAXNodeWrapper* child_wrapper = InternalGetChild(index);
173 return child_wrapper
174 ? child_wrapper->ax_platform_node()->GetNativeViewAccessible()
175 : nullptr;
176}
177
179 const AXCoordinateSystem coordinate_system,
180 const AXClippingBehavior clipping_behavior,
181 AXOffscreenResult* offscreen_result) const {
182 switch (coordinate_system) {
184 // For unit testing purposes, assume a device scale factor of 1 and fall
185 // through.
187 // We could optionally add clipping here if ever needed.
188 gfx::RectF bounds = GetLocation();
189 bounds.Offset(g_offset);
190
191 // For test behavior only, for bounds that are offscreen we currently do
192 // not apply clipping to the bounds but we still return the offscreen
193 // status.
194 if (offscreen_result) {
195 *offscreen_result = DetermineOffscreenResult(bounds);
196 }
197
198 return gfx::ToEnclosingRect(bounds);
199 }
203 return gfx::Rect();
204 }
205}
206
208 const int start_offset,
209 const int end_offset,
210 const AXCoordinateSystem coordinate_system,
211 const AXClippingBehavior clipping_behavior,
212 AXOffscreenResult* offscreen_result) const {
213 switch (coordinate_system) {
215 // For unit testing purposes, assume a device scale factor of 1 and fall
216 // through.
218 gfx::RectF bounds = GetLocation();
219 // This implementation currently only deals with text node that has role
220 // kInlineTextBox and kStaticText.
221 // For test purposes, assume node with kStaticText always has a single
222 // child with role kInlineTextBox.
224 bounds = GetInlineTextRect(start_offset, end_offset);
225 } else if (GetData().role == ax::mojom::Role::kStaticText &&
226 InternalChildCount() > 0) {
228 if (child != nullptr &&
230 bounds = child->GetInlineTextRect(start_offset, end_offset);
231 }
232 }
233
234 bounds.Offset(g_offset);
235
236 // For test behavior only, for bounds that are offscreen we currently do
237 // not apply clipping to the bounds but we still return the offscreen
238 // status.
239 if (offscreen_result) {
240 *offscreen_result = DetermineOffscreenResult(bounds);
241 }
242
243 return gfx::ToEnclosingRect(bounds);
244 }
248 return gfx::Rect();
249 }
250}
251
253 const int start_offset,
254 const int end_offset,
255 const AXCoordinateSystem coordinate_system,
256 const AXClippingBehavior clipping_behavior,
257 AXOffscreenResult* offscreen_result) const {
258 switch (coordinate_system) {
260 // For unit testing purposes, assume a device scale factor of 1 and fall
261 // through.
263 // Ignoring start, len, and clipped, as there's no clean way to map these
264 // via unit tests.
265 gfx::RectF bounds = GetLocation();
266 bounds.Offset(g_offset);
267 return gfx::ToEnclosingRect(bounds);
268 }
272 return gfx::Rect();
273 }
274}
275
276TestAXNodeWrapper* TestAXNodeWrapper::HitTestSyncInternal(int x, int y) {
277 if (g_hit_test_result.find(node_->id()) != g_hit_test_result.end()) {
278 int result_id = g_hit_test_result[node_->id()];
279 AXNode* result_node = tree_->GetFromId(result_id);
280 return GetOrCreate(tree_, result_node);
281 }
282
283 // Here we find the deepest child whose bounding box contains the given point.
284 // The assumptions are that there are no overlapping bounding rects and that
285 // all children have smaller bounding rects than their parents.
286 if (!GetClippedScreenBoundsRect().Contains(gfx::Rect(x, y, 0, 0)))
287 return nullptr;
288
289 for (int i = 0; i < GetChildCount(); i++) {
290 TestAXNodeWrapper* child = GetOrCreate(tree_, node_->children()[i]);
291 if (!child)
292 return nullptr;
293
294 TestAXNodeWrapper* result = child->HitTestSyncInternal(x, y);
295 if (result) {
296 return result;
297 }
298 }
299 return this;
300}
301
303 int screen_physical_pixel_x,
304 int screen_physical_pixel_y) const {
305 const TestAXNodeWrapper* wrapper =
306 const_cast<TestAXNodeWrapper*>(this)->HitTestSyncInternal(
307 screen_physical_pixel_x / g_scale_factor,
308 screen_physical_pixel_y / g_scale_factor);
309 return wrapper ? wrapper->ax_platform_node()->GetNativeViewAccessible()
310 : nullptr;
311}
312
314 auto focused = g_focused_node_in_tree.find(tree_);
315 if (focused != g_focused_node_in_tree.end() &&
316 focused->second->IsDescendantOf(node_)) {
317 return GetOrCreate(tree_, focused->second)
320 }
321 return nullptr;
322}
323
325 return minimized_;
326}
327
329 return g_is_web_content;
330}
331
332// Walk the AXTree and ensure that all wrappers are created
334 for (auto* child : node->children()) {
336 BuildAllWrappers(tree, child);
337 }
338}
339
341 native_event_target_ = gfx::kNullAcceleratedWidget;
342}
343
345 // Force creating all of the wrappers for this tree.
346 BuildAllWrappers(tree_, node_);
347
348 const auto iter = g_node_id_to_wrapper_map.find(id);
349 if (iter != g_node_id_to_wrapper_map.end())
350 return iter->second->ax_platform_node();
351
352 return nullptr;
353}
354
356 const ui::AXTreeID& ax_tree_id,
357 int32_t id) {
358 // TestAXNodeWrapper only supports one accessibility tree.
359 // Additional work would need to be done to support multiple trees.
360 BASE_CHECK(GetTreeData().tree_id == ax_tree_id);
361 return GetFromNodeID(id);
362}
363
365 return node_ ? static_cast<int>(node_->GetUnignoredIndexInParent()) : -1;
366}
367
368void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id,
369 ax::mojom::IntAttribute attribute,
370 int32_t value) {
371 if (!tree_)
372 return;
373
374 AXNode* node = tree_->GetFromId(node_id);
375 if (!node)
376 return;
377
378 AXNodeData new_data = node->data();
379 std::vector<std::pair<ax::mojom::IntAttribute, int32_t>>& attributes =
380 new_data.int_attributes;
381
382 auto it = std::remove_if(
383 attributes.begin(), attributes.end(),
384 [attribute](auto& pair) { return pair.first == attribute; });
385 attributes.erase(it, attributes.end());
386
387 new_data.AddIntAttribute(attribute, value);
388 node->SetData(new_data);
389}
390
391void TestAXNodeWrapper::ReplaceFloatAttribute(
393 float value) {
394 AXNodeData new_data = GetData();
395 std::vector<std::pair<ax::mojom::FloatAttribute, float>>& attributes =
396 new_data.float_attributes;
397
398 auto it = std::remove_if(
399 attributes.begin(), attributes.end(),
400 [attribute](auto& pair) { return pair.first == attribute; });
401 attributes.erase(it, attributes.end());
402
403 new_data.AddFloatAttribute(attribute, value);
404 node_->SetData(new_data);
405}
406
407void TestAXNodeWrapper::ReplaceBoolAttribute(ax::mojom::BoolAttribute attribute,
408 bool value) {
409 AXNodeData new_data = GetData();
410 std::vector<std::pair<ax::mojom::BoolAttribute, bool>>& attributes =
411 new_data.bool_attributes;
412
413 auto it = std::remove_if(
414 attributes.begin(), attributes.end(),
415 [attribute](auto& pair) { return pair.first == attribute; });
416 attributes.erase(it, attributes.end());
417
418 new_data.AddBoolAttribute(attribute, value);
419 node_->SetData(new_data);
420}
421
422void TestAXNodeWrapper::ReplaceStringAttribute(
424 std::string value) {
425 AXNodeData new_data = GetData();
426 std::vector<std::pair<ax::mojom::StringAttribute, std::string>>& attributes =
427 new_data.string_attributes;
428
429 auto it = std::remove_if(
430 attributes.begin(), attributes.end(),
431 [attribute](auto& pair) { return pair.first == attribute; });
432 attributes.erase(it, attributes.end());
433
434 new_data.AddStringAttribute(attribute, value);
435 node_->SetData(new_data);
436}
437
438void TestAXNodeWrapper::ReplaceTreeDataTextSelection(int32_t anchor_node_id,
439 int32_t anchor_offset,
440 int32_t focus_node_id,
441 int32_t focus_offset) {
442 if (!tree_)
443 return;
444
445 AXTreeData new_tree_data = GetTreeData();
446 new_tree_data.sel_anchor_object_id = anchor_node_id;
447 new_tree_data.sel_anchor_offset = anchor_offset;
448 new_tree_data.sel_focus_object_id = focus_node_id;
449 new_tree_data.sel_focus_offset = focus_offset;
450
451 tree_->UpdateData(new_tree_data);
452}
453
455 return node_->IsTable();
456}
457
458std::optional<int> TestAXNodeWrapper::GetTableRowCount() const {
459 return node_->GetTableRowCount();
460}
461
462std::optional<int> TestAXNodeWrapper::GetTableColCount() const {
463 return node_->GetTableColCount();
464}
465
466std::optional<int> TestAXNodeWrapper::GetTableAriaRowCount() const {
467 return node_->GetTableAriaRowCount();
468}
469
470std::optional<int> TestAXNodeWrapper::GetTableAriaColCount() const {
471 return node_->GetTableAriaColCount();
472}
473
474std::optional<int> TestAXNodeWrapper::GetTableCellCount() const {
475 return node_->GetTableCellCount();
476}
477
479 const {
480 return node_->GetTableHasColumnOrRowHeaderNode();
481}
482
483std::vector<AXNode::AXID> TestAXNodeWrapper::GetColHeaderNodeIds() const {
484 return node_->GetTableColHeaderNodeIds();
485}
486
488 int col_index) const {
489 return node_->GetTableColHeaderNodeIds(col_index);
490}
491
492std::vector<AXNode::AXID> TestAXNodeWrapper::GetRowHeaderNodeIds() const {
493 return node_->GetTableCellRowHeaderNodeIds();
494}
495
497 int row_index) const {
498 return node_->GetTableRowHeaderNodeIds(row_index);
499}
500
502 return node_->IsTableRow();
503}
504
505std::optional<int> TestAXNodeWrapper::GetTableRowRowIndex() const {
506 return node_->GetTableRowRowIndex();
507}
508
510 return node_->IsTableCellOrHeader();
511}
512
513std::optional<int> TestAXNodeWrapper::GetTableCellIndex() const {
514 return node_->GetTableCellIndex();
515}
516
517std::optional<int> TestAXNodeWrapper::GetTableCellColIndex() const {
518 return node_->GetTableCellColIndex();
519}
520
521std::optional<int> TestAXNodeWrapper::GetTableCellRowIndex() const {
522 return node_->GetTableCellRowIndex();
523}
524
525std::optional<int> TestAXNodeWrapper::GetTableCellColSpan() const {
526 return node_->GetTableCellColSpan();
527}
528
529std::optional<int> TestAXNodeWrapper::GetTableCellRowSpan() const {
530 return node_->GetTableCellRowSpan();
531}
532
534 return node_->GetTableCellAriaColIndex();
535}
536
538 return node_->GetTableCellAriaRowIndex();
539}
540
541std::optional<int32_t> TestAXNodeWrapper::GetCellId(int row_index,
542 int col_index) const {
543 AXNode* cell = node_->GetTableCellFromCoords(row_index, col_index);
544 if (!cell)
545 return std::nullopt;
546 return cell->id();
547}
548
549gfx::AcceleratedWidget
551 return native_event_target_;
552}
553
554std::optional<int32_t> TestAXNodeWrapper::CellIndexToId(int cell_index) const {
555 AXNode* cell = node_->GetTableCellFromIndex(cell_index);
556 if (!cell)
557 return std::nullopt;
558 return cell->id();
559}
560
564
568
570 const ui::AXActionData& data) {
571 switch (data.action) {
573 g_offset = gfx::Vector2d(data.target_point.x(), data.target_point.y());
574 return true;
576 int scroll_x_min =
578 int scroll_x_max =
580 int scroll_y_min =
582 int scroll_y_max =
584 int scroll_x =
585 base::ClampToRange(data.target_point.x(), scroll_x_min, scroll_x_max);
586 int scroll_y =
587 base::ClampToRange(data.target_point.y(), scroll_y_min, scroll_y_max);
588
589 ReplaceIntAttribute(node_->id(), ax::mojom::IntAttribute::kScrollX,
590 scroll_x);
591 ReplaceIntAttribute(node_->id(), ax::mojom::IntAttribute::kScrollY,
592 scroll_y);
593 return true;
594 }
597 g_offset = gfx::Vector2d(-offset.x(), -offset.y());
598 return true;
599 }
600
602 // If a default action such as a click is performed on an element, it
603 // could result in a selected state change. In which case, the element's
604 // selected state no longer comes from focus action, so we should set
605 // |kSelectedFromFocus| to false.
606 if (GetData().HasBoolAttribute(
609 false);
610
611 switch (GetData().role) {
614 bool current_value =
616 ReplaceBoolAttribute(ax::mojom::BoolAttribute::kSelected,
617 !current_value);
618 break;
619 }
622 if (GetData().GetCheckedState() == ax::mojom::CheckedState::kTrue)
623 ReplaceIntAttribute(
625 static_cast<int32_t>(ax::mojom::CheckedState::kFalse));
626 else if (GetData().GetCheckedState() ==
628 ReplaceIntAttribute(
630 static_cast<int32_t>(ax::mojom::CheckedState::kTrue));
631 break;
632 }
633 default:
634 break;
635 }
637 return true;
638 }
639
642 ReplaceFloatAttribute(ax::mojom::FloatAttribute::kValueForRange,
643 std::stof(data.value));
644 } else if (GetData().role == ax::mojom::Role::kTextField) {
645 ReplaceStringAttribute(ax::mojom::StringAttribute::kValue, data.value);
646 }
647 return true;
648
650 ReplaceIntAttribute(data.anchor_node_id,
652 data.anchor_offset);
653 ReplaceIntAttribute(data.focus_node_id,
655 data.focus_offset);
656 ReplaceTreeDataTextSelection(data.anchor_node_id, data.anchor_offset,
657 data.focus_node_id, data.focus_offset);
658 return true;
659 }
660
662 g_focused_node_in_tree[tree_] = node_;
663
664 // The platform has select follows focus behavior:
665 // https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_selection_follows_focus
666 // For test purpose, we support select follows focus for all elements, and
667 // not just single-selection container elements.
668 if (SupportsSelected(GetData().role)) {
669 ReplaceBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
671 true);
672 }
673
674 return true;
675 }
676
678 g_node_from_last_show_context_menu = node_;
679 return true;
680
681 default:
682 return true;
683 }
684}
685
687 const {
688 return base::ASCIIToUTF16("Unlabeled image");
689}
690
692 const AXNodeData& data = GetData();
693 switch (data.role) {
696 return base::ASCIIToUTF16("banner");
697
699 return base::ASCIIToUTF16("complementary");
700
703 return base::ASCIIToUTF16("content information");
704
707 if (data.HasStringAttribute(ax::mojom::StringAttribute::kName))
708 return base::ASCIIToUTF16("region");
709
710 default:
711 return {};
712 }
713}
714
716 const AXNodeData& data = GetData();
717
718 switch (data.role) {
720 return base::ASCIIToUTF16("article");
721
723 return base::ASCIIToUTF16("audio");
724
726 return base::ASCIIToUTF16("code");
727
729 return base::ASCIIToUTF16("color picker");
730
732 return base::ASCIIToUTF16("content information");
733
735 return base::ASCIIToUTF16("date picker");
736
738 std::string input_type;
739 if (data.GetStringAttribute(ax::mojom::StringAttribute::kInputType,
740 &input_type)) {
741 if (input_type == "datetime-local") {
742 return base::ASCIIToUTF16("local date and time picker");
743 } else if (input_type == "week") {
744 return base::ASCIIToUTF16("week picker");
745 }
746 }
747 return {};
748 }
749
751 return base::ASCIIToUTF16("details");
752
754 return base::ASCIIToUTF16("emphasis");
755
757 return base::ASCIIToUTF16("figure");
758
761 return base::ASCIIToUTF16("footer");
762
765 return base::ASCIIToUTF16("header");
766
768 return base::ASCIIToUTF16("highlight");
769
771 return base::ASCIIToUTF16("meter");
772
774 return base::ASCIIToUTF16("search box");
775
777 if (data.HasStringAttribute(ax::mojom::StringAttribute::kName))
778 return base::ASCIIToUTF16("section");
779
780 return {};
781 }
782
784 return base::ASCIIToUTF16("output");
785
787 return base::ASCIIToUTF16("strong");
788
790 std::string input_type;
791 if (data.GetStringAttribute(ax::mojom::StringAttribute::kInputType,
792 &input_type)) {
793 if (input_type == "email") {
794 return base::ASCIIToUTF16("email");
795 } else if (input_type == "tel") {
796 return base::ASCIIToUTF16("telephone");
797 } else if (input_type == "url") {
798 return base::ASCIIToUTF16("url");
799 }
800 }
801 return {};
802 }
803
805 return base::ASCIIToUTF16("time");
806
807 default:
808 return {};
809 }
810}
811
814 switch (status) {
816 return base::ASCIIToUTF16(
817 "To get missing image descriptions, open the context menu.");
819 return base::ASCIIToUTF16("Getting description...");
821 return base::ASCIIToUTF16(
822 "Appears to contain adult content. No description available.");
825 return base::ASCIIToUTF16("No description available.");
831 return std::u16string();
832 }
833
835 return std::u16string();
836}
837
839 const {
840 AXNode* current_node = node_;
841 while (current_node) {
842 if (current_node->data().role == ax::mojom::Role::kMark)
843 return base::ASCIIToUTF16("mark");
844 current_node = current_node->parent();
845 }
846 return std::u16string();
847}
848
852
854 ui::AXTree::Selection unignored_selection = GetUnignoredSelection();
855 int32_t focus_id = unignored_selection.focus_object_id;
856 AXNode* focus_object = tree_->GetFromId(focus_id);
857 if (!focus_object)
858 return false;
859
860 // Selection or caret will be visible in a focused editable area.
861 if (GetData().HasState(ax::mojom::State::kEditable)) {
862 return GetData().IsPlainTextField() ? focus_object == node_
863 : focus_object->IsDescendantOf(node_);
864 }
865
866 // The selection will be visible in non-editable content only if it is not
867 // collapsed into a caret.
868 return (focus_id != unignored_selection.anchor_object_id ||
869 unignored_selection.focus_offset !=
870 unignored_selection.anchor_offset) &&
871 focus_object->IsDescendantOf(node_);
872}
873
877 return GetNodesForNodeIds(tree_->GetReverseRelations(attr, GetData().id));
878}
879
885
887 return unique_id_;
888}
889
890TestAXNodeWrapper::TestAXNodeWrapper(AXTree* tree, AXNode* node)
891 : tree_(tree), node_(node), platform_node_(AXPlatformNode::Create(this)) {
892#if defined(OS_WIN)
893 native_event_target_ = gfx::kMockAcceleratedWidget;
894#else
895 native_event_target_ = gfx::kNullAcceleratedWidget;
896#endif
897}
898
900 return node_->IsOrderedSetItem();
901}
902
904 return node_->IsOrderedSet();
905}
906
907std::optional<int> TestAXNodeWrapper::GetPosInSet() const {
908 return node_->GetPosInSet();
909}
910
911std::optional<int> TestAXNodeWrapper::GetSetSize() const {
912 return node_->GetSetSize();
913}
914
918
920 return static_cast<int>(node_->GetUnignoredChildCount());
921}
922
924 BASE_CHECK(index >= 0);
926 return GetOrCreate(
927 tree_, node_->GetUnignoredChildAtIndex(static_cast<size_t>(index)));
928}
929
930// Recursive helper function for GetUIADescendants. Aggregates all of the
931// descendants for a given node within the descendants vector.
932void TestAXNodeWrapper::UIADescendants(
933 const AXNode* node,
934 std::vector<gfx::NativeViewAccessible>* descendants) const {
935 if (ShouldHideChildrenForUIA(node))
936 return;
937
938 for (auto it = node->UnignoredChildrenBegin();
939 it != node->UnignoredChildrenEnd(); ++it) {
940 descendants->emplace_back(ax_platform_node()
941 ->GetDelegate()
942 ->GetFromNodeID(it->id())
944 UIADescendants(it.get(), descendants);
945 }
946}
947
948const std::vector<gfx::NativeViewAccessible>
950 std::vector<gfx::NativeViewAccessible> descendants;
951 UIADescendants(node_, &descendants);
952 return descendants;
953}
954
955// static
956// Needs to stay in sync with AXPlatformNodeWin::ShouldHideChildrenForUIA.
957bool TestAXNodeWrapper::ShouldHideChildrenForUIA(const AXNode* node) {
958 if (!node)
959 return false;
960
961 auto role = node->data().role;
962
964 return true;
965
966 switch (role) {
969 return true;
970 default:
971 return false;
972 }
973}
974
975gfx::RectF TestAXNodeWrapper::GetInlineTextRect(const int start_offset,
976 const int end_offset) const {
977 BASE_DCHECK(start_offset >= 0 && end_offset >= 0 &&
978 start_offset <= end_offset);
979 const std::vector<int32_t>& character_offsets = GetData().GetIntListAttribute(
981 gfx::RectF location = GetLocation();
983
984 switch (static_cast<ax::mojom::WritingDirection>(
986 // Currently only kNone and kLtr are supported text direction.
989 int start_pixel_offset =
990 start_offset > 0 ? character_offsets[start_offset - 1] : location.x();
991 int end_pixel_offset =
992 end_offset > 0 ? character_offsets[end_offset - 1] : location.x();
993 bounds =
994 gfx::RectF(start_pixel_offset, location.y(),
995 end_pixel_offset - start_pixel_offset, location.height());
996 break;
997 }
998 default:
1000 }
1001 return bounds;
1002}
1003
1004AXOffscreenResult TestAXNodeWrapper::DetermineOffscreenResult(
1005 gfx::RectF bounds) const {
1006 if (!tree_ || !tree_->root())
1008
1009 const AXNodeData& root_web_area_node_data = tree_->root()->data();
1010 gfx::RectF root_web_area_bounds =
1011 root_web_area_node_data.relative_bounds.bounds;
1012
1013 // For testing, we only look at the current node's bound relative to the root
1014 // web area bounds to determine offscreen status. We currently do not look at
1015 // the bounds of the immediate parent of the node for determining offscreen
1016 // status.
1017 // We only determine offscreen result if the root web area bounds is actually
1018 // set in the test. We default the offscreen result of every other situation
1019 // to AXOffscreenResult::kOnscreen.
1020 if (!root_web_area_bounds.IsEmpty()) {
1021 bounds.Intersect(root_web_area_bounds);
1022 if (bounds.IsEmpty())
1024 }
1026}
1027
1028} // namespace ui
static sk_sp< Effect > Create()
bool IsEmpty() const
Definition rect_f.h:104
Vector2dF OffsetFromOrigin() const
Definition rect_f.h:77
constexpr float y() const
Definition rect_f.h:50
constexpr float height() const
Definition rect_f.h:56
constexpr float x() const
Definition rect_f.h:47
std::optional< int > GetSetSize()
Definition ax_node.cc:954
size_t GetUnignoredChildCount() const
Definition ax_node.cc:37
std::vector< AXNode::AXID > GetTableColHeaderNodeIds() const
Definition ax_node.cc:628
std::vector< AXNode::AXID > GetTableCellRowHeaderNodeIds() const
Definition ax_node.cc:864
UnignoredChildIterator UnignoredChildrenEnd() const
Definition ax_node.cc:316
bool IsCellOrHeaderOfARIATable() const
Definition ax_node.cc:882
bool IsOrderedSetItem() const
Definition ax_node.cc:940
std::optional< int > GetTableCellIndex() const
Definition ax_node.cc:758
AXID id() const
Definition ax_node.h:110
void SetData(const AXNodeData &src)
Definition ax_node.cc:373
std::optional< int > GetTableCellRowIndex() const
Definition ax_node.cc:784
size_t GetUnignoredIndexInParent() const
Definition ax_node.cc:66
bool IsCellOrHeaderOfARIAGrid() const
Definition ax_node.cc:895
bool IsTableCellOrHeader() const
Definition ax_node.cc:754
std::optional< int > GetTableCellAriaColIndex() const
Definition ax_node.cc:822
int32_t AXID
Definition ax_node.h:36
std::vector< AXNode::AXID > GetTableRowHeaderNodeIds(int row_index) const
Definition ax_node.cc:657
std::optional< int > GetTableRowCount() const
Definition ax_node.cc:551
std::optional< bool > GetTableHasColumnOrRowHeaderNode() const
Definition ax_node.cc:580
AXNode * GetUnignoredParent() const
Definition ax_node.cc:58
std::optional< int > GetTableRowRowIndex() const
Definition ax_node.cc:695
AXNode * GetUnignoredChildAtIndex(size_t index) const
Definition ax_node.cc:47
std::optional< int > GetTableCellAriaRowIndex() const
Definition ax_node.cc:834
std::optional< int > GetTableAriaColCount() const
Definition ax_node.cc:558
std::optional< int > GetTableColCount() const
Definition ax_node.cc:544
bool IsTableRow() const
Definition ax_node.cc:691
const std::vector< AXNode * > & children() const
Definition ax_node.h:113
std::optional< int > GetTableCellColSpan() const
Definition ax_node.cc:796
AXNode * parent() const
Definition ax_node.h:111
UnignoredChildIterator UnignoredChildrenBegin() const
Definition ax_node.cc:311
std::optional< int > GetTableCellRowSpan() const
Definition ax_node.cc:809
bool IsTable() const
Definition ax_node.cc:540
std::optional< int > GetTableCellCount() const
Definition ax_node.cc:572
bool IsOrderedSet() const
Definition ax_node.cc:944
std::optional< int > GetTableCellColIndex() const
Definition ax_node.cc:772
bool IsDescendantOf(const AXNode *ancestor) const
Definition ax_node.cc:407
AXNode * GetTableCellFromIndex(int index) const
Definition ax_node.cc:588
std::optional< int > GetPosInSet()
Definition ax_node.cc:949
AXNode * GetTableCellFromCoords(int row_index, int col_index) const
Definition ax_node.cc:611
const AXNodeData & data() const
Definition ax_node.h:112
std::optional< int > GetTableAriaRowCount() const
Definition ax_node.cc:565
gfx::Rect GetClippedScreenBoundsRect(AXOffscreenResult *offscreen_result=nullptr) const override
std::set< ui::AXPlatformNode * > GetNodesForNodeIds(const std::set< int32_t > &ids)
virtual AXPlatformNode * GetFromNodeID(int32_t id)=0
virtual gfx::NativeViewAccessible GetNativeViewAccessible()=0
virtual AXPlatformNodeDelegate * GetDelegate() const =0
virtual void Destroy()
std::unique_ptr< AXPosition< AXNodePosition, AXNode > > AXPositionInstance
static AXPositionInstance CreateTextPosition(AXTreeID tree_id, AXNode::AXID anchor_id, int text_offset, ax::mojom::TextAffinity affinity)
const AXTreeData & data() const
Definition ax_tree.h:59
std::set< int32_t > GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) const
Definition ax_tree.cc:922
AXNode * GetFromId(int32_t id) const override
Definition ax_tree.cc:728
void AddObserver(AXTreeObserver *observer)
Definition ax_tree.cc:708
AXNode * root() const
Definition ax_tree.h:57
Selection GetUnignoredSelection() const override
Definition ax_tree.cc:2345
virtual void UpdateData(const AXTreeData &data)
Definition ax_tree.cc:744
bool HasObserver(AXTreeObserver *observer)
Definition ax_tree.cc:712
const std::vector< gfx::NativeViewAccessible > GetUIADescendants() const override
bool AccessibilityPerformAction(const AXActionData &data) override
gfx::NativeViewAccessible GetParent() override
std::optional< int > GetTableCellColIndex() const override
const AXTreeData & GetTreeData() const override
bool IsMinimized() const override
const AXNodeData & GetData() const override
std::optional< int > GetTableRowCount() const override
std::optional< int > GetTableCellCount() const override
std::optional< int > GetSetSize() const override
bool IsWebContent() const override
gfx::NativeViewAccessible GetNativeViewAccessible() override
const AXTree::Selection GetUnignoredSelection() const override
std::u16string GetStyleNameAttributeAsLocalizedString() const override
std::optional< int > GetTableCellColSpan() const override
gfx::NativeViewAccessible HitTestSync(int screen_physical_pixel_x, int screen_physical_pixel_y) const override
std::u16string GetLocalizedStringForImageAnnotationStatus(ax::mojom::ImageAnnotationStatus status) const override
bool IsTable() const override
gfx::RectF GetLocation() const
std::vector< int32_t > GetRowHeaderNodeIds() const override
bool IsOrderedSetItem() const override
static void SetGlobalIsWebContent(bool is_web_content)
std::optional< int > GetTableCellAriaColIndex() const override
gfx::Rect GetHypertextRangeBoundsRect(const int start_offset, const int end_offset, const AXCoordinateSystem coordinate_system, const AXClippingBehavior clipping_behavior, AXOffscreenResult *offscreen_result) const override
static TestAXNodeWrapper * GetOrCreate(AXTree *tree, AXNode *node)
AXPlatformNode * GetFromNodeID(int32_t id) override
int GetChildCount() const override
std::optional< bool > GetTableHasColumnOrRowHeaderNode() const override
bool IsCellOrHeaderOfARIAGrid() const override
bool IsOrderedSet() const override
std::optional< int > GetTableCellRowIndex() const override
std::optional< int > GetPosInSet() const override
AXPlatformNode * GetFromTreeIDAndNodeID(const ui::AXTreeID &ax_tree_id, int32_t id) override
std::optional< int > GetTableCellRowSpan() const override
AXPlatformNode * ax_platform_node() const
std::optional< int > GetTableAriaColCount() const override
std::optional< int > GetTableColCount() const override
std::u16string GetLocalizedStringForRoleDescription() const override
std::u16string GetLocalizedRoleDescriptionForUnlabeledImage() const override
bool IsCellOrHeaderOfARIATable() const override
gfx::NativeViewAccessible GetFocus() override
bool IsTableCellOrHeader() const override
static void SetNodeFromLastDefaultAction(AXNode *node)
std::set< AXPlatformNode * > GetReverseRelations(ax::mojom::IntAttribute attr) override
const ui::AXUniqueId & GetUniqueId() const override
gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override
std::vector< int32_t > GetColHeaderNodeIds() const override
std::u16string GetLocalizedStringForLandmarkType() const override
std::optional< int32_t > GetCellId(int row_index, int col_index) const override
bool HasVisibleCaretOrSelection() const override
gfx::Rect GetBoundsRect(const AXCoordinateSystem coordinate_system, const AXClippingBehavior clipping_behavior, AXOffscreenResult *offscreen_result) const override
static const AXNode * GetNodeFromLastShowContextMenu()
bool IsTableRow() const override
std::optional< int > GetTableAriaRowCount() const override
TestAXNodeWrapper * InternalGetChild(int index) const
gfx::Rect GetInnerTextRangeBoundsRect(const int start_offset, const int end_offset, const AXCoordinateSystem coordinate_system, const AXClippingBehavior clipping_behavior, AXOffscreenResult *offscreen_result) const override
AXNodePosition::AXPositionInstance CreateTextPositionAt(int offset) const override
std::optional< int > GetTableCellIndex() const override
std::optional< int > GetTableRowRowIndex() const override
static void SetGlobalCoordinateOffset(const gfx::Vector2d &offset)
static const AXNode * GetNodeFromLastDefaultAction()
static std::unique_ptr< base::AutoReset< float > > SetScaleFactor(float value)
static void SetHitTestResult(AXNode::AXID src_node_id, AXNode::AXID dst_node_id)
bool ShouldIgnoreHoveredStateForTesting() override
std::optional< int32_t > CellIndexToId(int cell_index) const override
gfx::NativeViewAccessible ChildAtIndex(int index) override
std::optional< int > GetTableCellAriaRowIndex() const override
void BuildAllWrappers(AXTree *tree, AXNode *node)
uint8_t value
GAsyncResult * result
double y
double x
Optional< SkRect > bounds
Definition SkRecords.h:189
ImageAnnotationStatus
Definition ax_enums.h:1170
std::u16string ASCIIToUTF16(std::string src)
constexpr const T & ClampToRange(const T &value, const T &min, const T &max)
Definition ranges.h:15
Rect ToEnclosingRect(const RectF &r)
UnimplementedNativeViewAccessible * NativeViewAccessible
bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr)
bool SupportsSelected(const ax::mojom::Role role)
bool IsRangeValueSupported(const ax::mojom::Role role)
bool HasPresentationalChildren(const ax::mojom::Role role)
bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr)
Point offset
AXRelativeBounds relative_bounds
bool IsPlainTextField() const
void AddIntAttribute(ax::mojom::IntAttribute attribute, int32_t value)
std::vector< std::pair< ax::mojom::IntAttribute, int32_t > > int_attributes
bool GetBoolAttribute(ax::mojom::BoolAttribute attribute) const
ax::mojom::Role role
const std::vector< int32_t > & GetIntListAttribute(ax::mojom::IntListAttribute attribute) const
int GetIntAttribute(ax::mojom::IntAttribute attribute) const
#define BASE_DCHECK(condition)
Definition logging.h:63
#define BASE_UNREACHABLE()
Definition logging.h:69
#define BASE_CHECK(condition)
Definition logging.h:56