Flutter Windows Embedder
flutter_platform_node_delegate_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "flutter/third_party/accessibility/ax/ax_action_data.h"
8 #include "gtest/gtest.h"
9 
11 
12 namespace flutter {
13 namespace testing {
14 
15 TEST(FlutterPlatformNodeDelegateTest, NodeDelegateHasUniqueId) {
16  std::shared_ptr<TestAccessibilityBridge> bridge =
17  std::make_shared<TestAccessibilityBridge>();
18 
19  // Add node 0: root.
20  FlutterSemanticsNode2 node0{sizeof(FlutterSemanticsNode2), 0};
21  std::vector<int32_t> node0_children{1};
22  FlutterSemanticsFlags emptyFlags = FlutterSemanticsFlags{};
23  node0.child_count = node0_children.size();
24  node0.children_in_traversal_order = node0_children.data();
25  node0.children_in_hit_test_order = node0_children.data();
26  node0.flags2 = &emptyFlags;
27 
28  // Add node 1: text child of node 0.
29  FlutterSemanticsNode2 node1{sizeof(FlutterSemanticsNode2), 1};
30  node1.label = "prefecture";
31  node1.value = "Kyoto";
32  node1.flags2 = &emptyFlags;
33 
34  bridge->AddFlutterSemanticsNodeUpdate(node0);
35  bridge->AddFlutterSemanticsNodeUpdate(node1);
36  bridge->CommitUpdates();
37 
38  auto node0_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
39  auto node1_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
40  EXPECT_TRUE(node0_delegate->GetUniqueId() != node1_delegate->GetUniqueId());
41 }
42 
43 TEST(FlutterPlatformNodeDelegateTest, canPerfomActions) {
44  std::shared_ptr<TestAccessibilityBridge> bridge =
45  std::make_shared<TestAccessibilityBridge>();
46  FlutterSemanticsNode2 root;
47  root.id = 0;
48  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
49  flags.is_text_field = true;
50  root.flags2 = &flags;
51  root.actions = static_cast<FlutterSemanticsAction>(0);
52  root.text_selection_base = -1;
53  root.text_selection_extent = -1;
54  root.label = "root";
55  root.hint = "";
56  root.value = "";
57  root.increased_value = "";
58  root.decreased_value = "";
59  root.tooltip = "";
60  root.child_count = 0;
61  root.custom_accessibility_actions_count = 0;
62  bridge->AddFlutterSemanticsNodeUpdate(root);
63 
64  bridge->CommitUpdates();
65 
66  auto accessibility = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
67  // Performs an AXAction.
68  ui::AXActionData action_data;
69  action_data.action = ax::mojom::Action::kDoDefault;
70  accessibility->AccessibilityPerformAction(action_data);
71  EXPECT_EQ(bridge->performed_actions.size(), size_t{1});
72  EXPECT_EQ(bridge->performed_actions[0],
73  FlutterSemanticsAction::kFlutterSemanticsActionTap);
74 
75  action_data.action = ax::mojom::Action::kFocus;
76  accessibility->AccessibilityPerformAction(action_data);
77  EXPECT_EQ(bridge->performed_actions.size(), size_t{2});
78  EXPECT_EQ(
79  bridge->performed_actions[1],
80  FlutterSemanticsAction::kFlutterSemanticsActionDidGainAccessibilityFocus);
81 
82  action_data.action = ax::mojom::Action::kScrollToMakeVisible;
83  accessibility->AccessibilityPerformAction(action_data);
84  EXPECT_EQ(bridge->performed_actions.size(), size_t{3});
85  EXPECT_EQ(bridge->performed_actions[2],
86  FlutterSemanticsAction::kFlutterSemanticsActionShowOnScreen);
87 }
88 
89 TEST(FlutterPlatformNodeDelegateTest, canGetAXNode) {
90  // Set up a flutter accessibility node.
91  std::shared_ptr<TestAccessibilityBridge> bridge =
92  std::make_shared<TestAccessibilityBridge>();
93  FlutterSemanticsNode2 root;
94  root.id = 0;
95  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
96  flags.is_text_field = true;
97  root.flags2 = &flags;
98  root.actions = static_cast<FlutterSemanticsAction>(0);
99  root.text_selection_base = -1;
100  root.text_selection_extent = -1;
101  root.label = "root";
102  root.hint = "";
103  root.value = "";
104  root.increased_value = "";
105  root.decreased_value = "";
106  root.tooltip = "";
107  root.child_count = 0;
108  root.custom_accessibility_actions_count = 0;
109  bridge->AddFlutterSemanticsNodeUpdate(root);
110 
111  bridge->CommitUpdates();
112 
113  auto accessibility = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
114  EXPECT_EQ(accessibility->GetData().id, 0);
115 }
116 
117 TEST(FlutterPlatformNodeDelegateTest, canCalculateBoundsCorrectly) {
118  std::shared_ptr<TestAccessibilityBridge> bridge =
119  std::make_shared<TestAccessibilityBridge>();
120  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
121  FlutterSemanticsNode2 root;
122  root.id = 0;
123  root.label = "root";
124  root.hint = "";
125  root.value = "";
126  root.increased_value = "";
127  root.decreased_value = "";
128  root.tooltip = "";
129  root.child_count = 1;
130  root.flags2 = &flags;
131  int32_t children[] = {1};
132  root.children_in_traversal_order = children;
133  root.custom_accessibility_actions_count = 0;
134  root.rect = {0, 0, 100, 100}; // LTRB
135  root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
136  bridge->AddFlutterSemanticsNodeUpdate(root);
137 
138  FlutterSemanticsNode2 child1;
139  child1.id = 1;
140  child1.label = "child 1";
141  child1.hint = "";
142  child1.value = "";
143  child1.increased_value = "";
144  child1.decreased_value = "";
145  child1.tooltip = "";
146  child1.child_count = 0;
147  child1.flags2 = &flags;
148  child1.custom_accessibility_actions_count = 0;
149  child1.rect = {0, 0, 50, 50}; // LTRB
150  child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
151  bridge->AddFlutterSemanticsNodeUpdate(child1);
152 
153  bridge->CommitUpdates();
154  auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
155  ui::AXOffscreenResult result;
156  gfx::Rect bounds =
157  child1_node->GetBoundsRect(ui::AXCoordinateSystem::kScreenDIPs,
158  ui::AXClippingBehavior::kClipped, &result);
159  EXPECT_EQ(bounds.x(), 0);
160  EXPECT_EQ(bounds.y(), 0);
161  EXPECT_EQ(bounds.width(), 25);
162  EXPECT_EQ(bounds.height(), 25);
163  EXPECT_EQ(result, ui::AXOffscreenResult::kOnscreen);
164 }
165 
166 TEST(FlutterPlatformNodeDelegateTest, canCalculateOffScreenBoundsCorrectly) {
167  std::shared_ptr<TestAccessibilityBridge> bridge =
168  std::make_shared<TestAccessibilityBridge>();
169  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
170  FlutterSemanticsNode2 root;
171  root.id = 0;
172  root.label = "root";
173  root.hint = "";
174  root.value = "";
175  root.increased_value = "";
176  root.decreased_value = "";
177  root.tooltip = "";
178  root.child_count = 1;
179  root.flags2 = &flags;
180  int32_t children[] = {1};
181  root.children_in_traversal_order = children;
182  root.custom_accessibility_actions_count = 0;
183  root.rect = {0, 0, 100, 100}; // LTRB
184  root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
185  bridge->AddFlutterSemanticsNodeUpdate(root);
186 
187  FlutterSemanticsNode2 child1;
188  child1.id = 1;
189  child1.label = "child 1";
190  child1.hint = "";
191  child1.value = "";
192  child1.increased_value = "";
193  child1.decreased_value = "";
194  child1.tooltip = "";
195  child1.child_count = 0;
196  child1.flags2 = &flags;
197  child1.custom_accessibility_actions_count = 0;
198  child1.rect = {90, 90, 100, 100}; // LTRB
199  child1.transform = {2, 0, 0, 0, 2, 0, 0, 0, 1};
200  bridge->AddFlutterSemanticsNodeUpdate(child1);
201 
202  bridge->CommitUpdates();
203  auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
204  ui::AXOffscreenResult result;
205  gfx::Rect bounds =
206  child1_node->GetBoundsRect(ui::AXCoordinateSystem::kScreenDIPs,
207  ui::AXClippingBehavior::kUnclipped, &result);
208  EXPECT_EQ(bounds.x(), 180);
209  EXPECT_EQ(bounds.y(), 180);
210  EXPECT_EQ(bounds.width(), 20);
211  EXPECT_EQ(bounds.height(), 20);
212  EXPECT_EQ(result, ui::AXOffscreenResult::kOffscreen);
213 }
214 
215 TEST(FlutterPlatformNodeDelegateTest, canUseOwnerBridge) {
216  std::shared_ptr<TestAccessibilityBridge> bridge =
217  std::make_shared<TestAccessibilityBridge>();
218  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
219  FlutterSemanticsNode2 root;
220  root.id = 0;
221  root.label = "root";
222  root.hint = "";
223  root.value = "";
224  root.increased_value = "";
225  root.decreased_value = "";
226  root.tooltip = "";
227  root.child_count = 1;
228  root.flags2 = &flags;
229  int32_t children[] = {1};
230  root.children_in_traversal_order = children;
231  root.custom_accessibility_actions_count = 0;
232  root.rect = {0, 0, 100, 100}; // LTRB
233  root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
234  bridge->AddFlutterSemanticsNodeUpdate(root);
235 
236  FlutterSemanticsNode2 child1;
237  child1.id = 1;
238  child1.label = "child 1";
239  child1.hint = "";
240  child1.value = "";
241  child1.increased_value = "";
242  child1.decreased_value = "";
243  child1.tooltip = "";
244  child1.child_count = 0;
245  child1.flags2 = &flags;
246  child1.custom_accessibility_actions_count = 0;
247  child1.rect = {0, 0, 50, 50}; // LTRB
248  child1.transform = {0.5, 0, 0, 0, 0.5, 0, 0, 0, 1};
249  bridge->AddFlutterSemanticsNodeUpdate(child1);
250 
251  bridge->CommitUpdates();
252  auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
253  auto owner_bridge = child1_node->GetOwnerBridge().lock();
254 
255  bool result;
256  gfx::RectF bounds = owner_bridge->RelativeToGlobalBounds(
257  child1_node->GetAXNode(), result, true);
258  EXPECT_EQ(bounds.x(), 0);
259  EXPECT_EQ(bounds.y(), 0);
260  EXPECT_EQ(bounds.width(), 25);
261  EXPECT_EQ(bounds.height(), 25);
262  EXPECT_EQ(result, false);
263 }
264 
265 TEST(FlutterPlatformNodeDelegateTest, selfIsLowestPlatformAncestor) {
266  std::shared_ptr<TestAccessibilityBridge> bridge =
267  std::make_shared<TestAccessibilityBridge>();
268  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
269  FlutterSemanticsNode2 root;
270  root.id = 0;
271  root.label = "root";
272  root.hint = "";
273  root.value = "";
274  root.increased_value = "";
275  root.decreased_value = "";
276  root.tooltip = "";
277  root.child_count = 0;
278  root.flags2 = &flags;
279  root.children_in_traversal_order = nullptr;
280  root.custom_accessibility_actions_count = 0;
281  bridge->AddFlutterSemanticsNodeUpdate(root);
282 
283  bridge->CommitUpdates();
284  auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
285  auto lowest_platform_ancestor = root_node->GetLowestPlatformAncestor();
286  EXPECT_EQ(root_node->GetNativeViewAccessible(), lowest_platform_ancestor);
287 }
288 
289 TEST(FlutterPlatformNodeDelegateTest, canGetFromNodeID) {
290  std::shared_ptr<TestAccessibilityBridge> bridge =
291  std::make_shared<TestAccessibilityBridge>();
292  FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
293  FlutterSemanticsNode2 root;
294  root.id = 0;
295  root.label = "root";
296  root.hint = "";
297  root.value = "";
298  root.increased_value = "";
299  root.decreased_value = "";
300  root.tooltip = "";
301  root.child_count = 1;
302  root.flags2 = &flags;
303  int32_t children[] = {1};
304  root.children_in_traversal_order = children;
305  root.custom_accessibility_actions_count = 0;
306  bridge->AddFlutterSemanticsNodeUpdate(root);
307 
308  FlutterSemanticsNode2 child1;
309  child1.id = 1;
310  child1.label = "child 1";
311  child1.hint = "";
312  child1.value = "";
313  child1.increased_value = "";
314  child1.decreased_value = "";
315  child1.tooltip = "";
316  child1.child_count = 0;
317  child1.flags2 = &flags;
318  child1.custom_accessibility_actions_count = 0;
319  bridge->AddFlutterSemanticsNodeUpdate(child1);
320 
321  bridge->CommitUpdates();
322  auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
323  auto child1_node = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
324  auto node_by_id = root_node->GetFromNodeID(1);
325  EXPECT_EQ(child1_node->GetPlatformNode(), node_by_id);
326 }
327 
328 } // namespace testing
329 } // namespace flutter
TEST(AccessibilityBridgeWindows, GetParent)