4 #include "flutter/testing/testing.h"
16 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
17 #include "flutter/third_party/accessibility/ax/ax_action_data.h"
24 NSString* fixtures = @(testing::GetFixturesPath());
26 initWithAssetsPath:fixtures
27 ICUDataPath:[fixtures stringByAppendingString:
@"/icudtl.dat"]];
35 engine.semanticsEnabled = YES;
36 auto bridge = viewController.accessibilityBridge.lock();
38 FlutterSemanticsNode2 root;
40 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
42 root.actions =
static_cast<FlutterSemanticsAction
>(0);
43 root.text_selection_base = -1;
44 root.text_selection_extent = -1;
45 root.label =
"accessibility";
48 root.increased_value =
"";
49 root.decreased_value =
"";
52 root.custom_accessibility_actions_count = 0;
53 bridge->AddFlutterSemanticsNodeUpdate(root);
55 bridge->CommitUpdates();
57 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
59 NSAccessibilityElement* native_accessibility =
60 root_platform_node_delegate->GetNativeViewAccessible();
61 std::string value = [native_accessibility.accessibilityValue UTF8String];
62 EXPECT_TRUE(value ==
"accessibility");
63 EXPECT_EQ(native_accessibility.accessibilityRole, NSAccessibilityStaticTextRole);
64 EXPECT_EQ([native_accessibility.accessibilityChildren count], 0u);
65 [engine shutDownEngine];
71 engine.semanticsEnabled = YES;
72 auto bridge = viewController.accessibilityBridge.lock();
74 FlutterSemanticsNode2 root;
77 static_cast<FlutterSemanticsFlag
>(FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField |
78 FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly);
79 root.actions =
static_cast<FlutterSemanticsAction
>(0);
80 root.text_selection_base = 1;
81 root.text_selection_extent = 3;
85 root.value =
"selectable text";
86 root.increased_value =
"";
87 root.decreased_value =
"";
90 root.custom_accessibility_actions_count = 0;
91 bridge->AddFlutterSemanticsNodeUpdate(root);
93 bridge->CommitUpdates();
95 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
97 NSAccessibilityElement* native_accessibility =
98 root_platform_node_delegate->GetNativeViewAccessible();
99 std::string value = [native_accessibility.accessibilityValue UTF8String];
100 EXPECT_EQ(value,
"selectable text");
101 EXPECT_EQ(native_accessibility.accessibilityRole, NSAccessibilityStaticTextRole);
102 EXPECT_EQ([native_accessibility.accessibilityChildren count], 0u);
103 NSRange selection = native_accessibility.accessibilitySelectedTextRange;
104 EXPECT_EQ(selection.location, 1u);
105 EXPECT_EQ(selection.length, 2u);
106 std::string selected_text = [native_accessibility.accessibilitySelectedText UTF8String];
107 EXPECT_EQ(selected_text,
"el");
113 engine.semanticsEnabled = YES;
114 auto bridge = viewController.accessibilityBridge.lock();
116 FlutterSemanticsNode2 root;
119 static_cast<FlutterSemanticsFlag
>(FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField |
120 FlutterSemanticsFlag::kFlutterSemanticsFlagIsReadOnly);
121 root.actions =
static_cast<FlutterSemanticsAction
>(0);
122 root.text_selection_base = -1;
123 root.text_selection_extent = -1;
127 root.value =
"selectable text";
128 root.increased_value =
"";
129 root.decreased_value =
"";
131 root.child_count = 0;
132 root.custom_accessibility_actions_count = 0;
133 bridge->AddFlutterSemanticsNodeUpdate(root);
135 bridge->CommitUpdates();
137 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
139 NSAccessibilityElement* native_accessibility =
140 root_platform_node_delegate->GetNativeViewAccessible();
141 NSRange selection = native_accessibility.accessibilitySelectedTextRange;
142 EXPECT_TRUE(selection.location == NSNotFound);
143 EXPECT_EQ(selection.length, 0u);
154 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
155 styleMask:NSBorderlessWindowMask
156 backing:NSBackingStoreBuffered
158 window.contentView = viewController.view;
160 engine.semanticsEnabled = YES;
161 auto bridge = viewController.accessibilityBridge.lock();
163 FlutterSemanticsNode2 root;
168 root.increased_value =
"";
169 root.decreased_value =
"";
171 root.child_count = 1;
172 int32_t children[] = {1};
173 root.children_in_traversal_order = children;
174 root.custom_accessibility_actions_count = 0;
175 bridge->AddFlutterSemanticsNodeUpdate(root);
177 FlutterSemanticsNode2 child1;
179 child1.label =
"child 1";
182 child1.increased_value =
"";
183 child1.decreased_value =
"";
185 child1.child_count = 0;
186 child1.custom_accessibility_actions_count = 0;
187 bridge->AddFlutterSemanticsNodeUpdate(child1);
189 bridge->CommitUpdates();
191 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
194 FlutterSemanticsAction called_action;
197 engine.embedderAPI.DispatchSemanticsAction = MOCK_ENGINE_PROC(
198 DispatchSemanticsAction,
199 ([&called_id, &called_action](
auto engine, uint64_t
id, FlutterSemanticsAction action,
200 const uint8_t* data,
size_t data_length) {
202 called_action = action;
207 ui::AXActionData action_data;
208 action_data.action = ax::mojom::Action::kDoDefault;
209 root_platform_node_delegate->AccessibilityPerformAction(action_data);
211 EXPECT_EQ(called_action, FlutterSemanticsAction::kFlutterSemanticsActionTap);
212 EXPECT_EQ(called_id, 1u);
214 [engine setViewController:nil];
215 [engine shutDownEngine];
223 [viewController loadView];
227 viewController.textInputPlugin.string =
@"textfield";
229 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
230 styleMask:NSBorderlessWindowMask
231 backing:NSBackingStoreBuffered
233 window.contentView = viewController.view;
234 engine.semanticsEnabled = YES;
236 auto bridge = viewController.accessibilityBridge.lock();
238 FlutterSemanticsNode2 root;
240 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
241 root.actions =
static_cast<FlutterSemanticsAction
>(0);
245 root.increased_value =
"";
246 root.decreased_value =
"";
248 root.child_count = 1;
249 int32_t children[] = {1};
250 root.children_in_traversal_order = children;
251 root.custom_accessibility_actions_count = 0;
252 root.rect = {0, 0, 100, 100};
253 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
254 bridge->AddFlutterSemanticsNodeUpdate(root);
256 double rectSize = 50;
257 double transformFactor = 0.5;
259 FlutterSemanticsNode2 child1;
261 child1.flags = FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField;
262 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
265 child1.value =
"textfield";
266 child1.increased_value =
"";
267 child1.decreased_value =
"";
269 child1.text_selection_base = -1;
270 child1.text_selection_extent = -1;
271 child1.child_count = 0;
272 child1.custom_accessibility_actions_count = 0;
273 child1.rect = {0, 0, rectSize, rectSize};
274 child1.transform = {transformFactor, 0, 0, 0, transformFactor, 0, 0, 0, 1};
275 bridge->AddFlutterSemanticsNodeUpdate(child1);
277 bridge->CommitUpdates();
279 auto child_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
281 id native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
282 EXPECT_EQ([native_accessibility isKindOfClass:[
FlutterTextField class]], YES);
285 NSView* view = viewController.flutterView;
286 CGRect scaledBounds = [view convertRectToBacking:view.bounds];
287 CGSize scaledSize = scaledBounds.size;
288 double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
290 double expectedFrameSize = rectSize * transformFactor / pixelRatio;
291 EXPECT_EQ(NSEqualRects(native_text_field.frame, NSMakeRect(0, 600 - expectedFrameSize,
292 expectedFrameSize, expectedFrameSize)),
295 [native_text_field startEditing];
296 EXPECT_EQ([native_text_field.stringValue isEqualToString:
@"textfield"], YES);
302 [viewController loadView];
305 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
306 styleMask:NSBorderlessWindowMask
307 backing:NSBackingStoreBuffered
309 window.contentView = viewController.view;
310 engine.semanticsEnabled = YES;
312 auto bridge = viewController.accessibilityBridge.lock();
314 FlutterSemanticsNode2 root;
316 root.flags =
static_cast<FlutterSemanticsFlag
>(0);
317 root.actions =
static_cast<FlutterSemanticsAction
>(0);
321 root.increased_value =
"";
322 root.decreased_value =
"";
324 root.child_count = 1;
325 int32_t children[] = {1};
326 root.children_in_traversal_order = children;
327 root.custom_accessibility_actions_count = 0;
328 root.rect = {0, 0, 100, 100};
329 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
330 bridge->AddFlutterSemanticsNodeUpdate(root);
332 double rectSize = 50;
333 double transformFactor = 0.5;
335 FlutterSemanticsNode2 child1;
337 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
338 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
341 child1.value =
"textfield";
342 child1.increased_value =
"";
343 child1.decreased_value =
"";
345 child1.text_selection_base = -1;
346 child1.text_selection_extent = -1;
347 child1.child_count = 0;
348 child1.custom_accessibility_actions_count = 0;
349 child1.rect = {0, 0, rectSize, rectSize};
350 child1.transform = {transformFactor, 0, 0, 0, transformFactor, 0, 0, 0, 1};
351 bridge->AddFlutterSemanticsNodeUpdate(child1);
353 bridge->CommitUpdates();
355 auto child_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
357 id native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
358 EXPECT_TRUE([[native_accessibility className] isEqualToString:
@"AXPlatformNodeCocoa"]);
361 child1.flags = FlutterSemanticsFlag::kFlutterSemanticsFlagIsTextField;
362 bridge->AddFlutterSemanticsNodeUpdate(child1);
363 bridge->CommitUpdates();
365 native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
368 child1.flags =
static_cast<FlutterSemanticsFlag
>(0);
369 bridge->AddFlutterSemanticsNodeUpdate(child1);
370 bridge->CommitUpdates();
372 native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
373 EXPECT_TRUE([[native_accessibility className] isEqualToString:
@"AXPlatformNodeCocoa"]);