Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1a79e86

Browse files
authored
[macOS] Move to new update semantics embedder API (#37404)
1 parent c290de6 commit 1a79e86

File tree

2 files changed

+53
-76
lines changed

2 files changed

+53
-76
lines changed

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -299,16 +299,11 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
299299
flutterArguments.command_line_argc = static_cast<int>(argv.size());
300300
flutterArguments.command_line_argv = argv.empty() ? nullptr : argv.data();
301301
flutterArguments.platform_message_callback = (FlutterPlatformMessageCallback)OnPlatformMessage;
302-
flutterArguments.update_semantics_node_callback = [](const FlutterSemanticsNode* node,
303-
void* user_data) {
302+
flutterArguments.update_semantics_callback = [](const FlutterSemanticsUpdate* update,
303+
void* user_data) {
304304
FlutterEngine* engine = (__bridge FlutterEngine*)user_data;
305-
[engine updateSemanticsNode:node];
305+
[engine updateSemantics:update];
306306
};
307-
flutterArguments.update_semantics_custom_action_callback =
308-
[](const FlutterSemanticsCustomAction* action, void* user_data) {
309-
FlutterEngine* engine = (__bridge FlutterEngine*)user_data;
310-
[engine updateSemanticsCustomActions:action];
311-
};
312307
flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String;
313308
flutterArguments.shutdown_dart_vm_when_done = true;
314309
flutterArguments.dart_entrypoint_argc = dartEntrypointArgs.size();
@@ -913,37 +908,34 @@ - (BOOL)unregisterTextureWithID:(int64_t)textureID {
913908
return _embedderAPI.UnregisterExternalTexture(_engine, textureID) == kSuccess;
914909
}
915910

916-
- (void)updateSemanticsNode:(const FlutterSemanticsNode*)node {
911+
- (void)updateSemantics:(const FlutterSemanticsUpdate*)update {
917912
NSAssert(_bridge, @"The accessibility bridge must be initialized.");
918-
if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
919-
return;
913+
for (size_t i = 0; i < update->nodes_count; i++) {
914+
const FlutterSemanticsNode* node = &update->nodes[i];
915+
_bridge->AddFlutterSemanticsNodeUpdate(node);
920916
}
921-
_bridge->AddFlutterSemanticsNodeUpdate(node);
922-
}
923917

924-
- (void)updateSemanticsCustomActions:(const FlutterSemanticsCustomAction*)action {
925-
NSAssert(_bridge, @"The accessibility bridge must be initialized.");
926-
if (action->id == kFlutterSemanticsNodeIdBatchEnd) {
927-
// Custom action with id = kFlutterSemanticsNodeIdBatchEnd indicates this is
928-
// the end of the update batch.
929-
_bridge->CommitUpdates();
930-
// Accessibility tree can only be used when the view is loaded.
931-
if (!self.viewController.viewLoaded) {
932-
return;
933-
}
934-
// Attaches the accessibility root to the flutter view.
935-
auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
936-
if (root) {
937-
if ([self.viewController.flutterView.accessibilityChildren count] == 0) {
938-
NSAccessibilityElement* native_root = root->GetNativeViewAccessible();
939-
self.viewController.flutterView.accessibilityChildren = @[ native_root ];
940-
}
941-
} else {
942-
self.viewController.flutterView.accessibilityChildren = nil;
943-
}
918+
for (size_t i = 0; i < update->custom_actions_count; i++) {
919+
const FlutterSemanticsCustomAction* action = &update->custom_actions[i];
920+
_bridge->AddFlutterSemanticsCustomActionUpdate(action);
921+
}
922+
923+
_bridge->CommitUpdates();
924+
925+
// Accessibility tree can only be used when the view is loaded.
926+
if (!self.viewController.viewLoaded) {
944927
return;
945928
}
946-
_bridge->AddFlutterSemanticsCustomActionUpdate(action);
929+
// Attaches the accessibility root to the flutter view.
930+
auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
931+
if (root) {
932+
if ([self.viewController.flutterView.accessibilityChildren count] == 0) {
933+
NSAccessibilityElement* native_root = root->GetNativeViewAccessible();
934+
self.viewController.flutterView.accessibilityChildren = @[ native_root ];
935+
}
936+
} else {
937+
self.viewController.flutterView.accessibilityChildren = nil;
938+
}
947939
}
948940

949941
#pragma mark - Task runner integration

shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,12 @@ @interface FlutterEngine (Test)
165165
FlutterEngine* engine = GetFlutterEngine();
166166
// Capture the update callbacks before the embedder API initializes.
167167
auto original_init = engine.embedderAPI.Initialize;
168-
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
169-
std::function<void(const FlutterSemanticsCustomAction*, void*)> update_action_callback;
168+
std::function<void(const FlutterSemanticsUpdate*, void*)> update_semantics_callback;
170169
engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
171-
Initialize, ([&update_action_callback, &update_node_callback, &original_init](
170+
Initialize, ([&update_semantics_callback, &original_init](
172171
size_t version, const FlutterRendererConfig* config,
173172
const FlutterProjectArgs* args, void* user_data, auto engine_out) {
174-
update_node_callback = args->update_semantics_node_callback;
175-
update_action_callback = args->update_semantics_custom_action_callback;
173+
update_semantics_callback = args->update_semantics_callback;
176174
return original_init(version, config, args, user_data, engine_out);
177175
}));
178176
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
@@ -210,7 +208,6 @@ @interface FlutterEngine (Test)
210208
int32_t children[] = {1};
211209
root.children_in_traversal_order = children;
212210
root.custom_accessibility_actions_count = 0;
213-
update_node_callback(&root, (void*)CFBridgingRetain(engine));
214211

215212
FlutterSemanticsNode child1;
216213
child1.id = 1;
@@ -226,15 +223,13 @@ @interface FlutterEngine (Test)
226223
child1.tooltip = "";
227224
child1.child_count = 0;
228225
child1.custom_accessibility_actions_count = 0;
229-
update_node_callback(&child1, (void*)CFBridgingRetain(engine));
230226

231-
FlutterSemanticsNode node_batch_end;
232-
node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
233-
update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine));
234-
235-
FlutterSemanticsCustomAction action_batch_end;
236-
action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
237-
update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine));
227+
FlutterSemanticsUpdate update;
228+
update.nodes_count = 2;
229+
FlutterSemanticsNode nodes[] = {root, child1};
230+
update.nodes = nodes;
231+
update.custom_actions_count = 0;
232+
update_semantics_callback(&update, (__bridge void*)engine);
238233

239234
// Verify the accessibility tree is attached to the flutter view.
240235
EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 1u);
@@ -267,14 +262,12 @@ @interface FlutterEngine (Test)
267262
FlutterEngine* engine = GetFlutterEngine();
268263
// Capture the update callbacks before the embedder API initializes.
269264
auto original_init = engine.embedderAPI.Initialize;
270-
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
271-
std::function<void(const FlutterSemanticsCustomAction*, void*)> update_action_callback;
265+
std::function<void(const FlutterSemanticsUpdate*, void*)> update_semantics_callback;
272266
engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
273-
Initialize, ([&update_action_callback, &update_node_callback, &original_init](
267+
Initialize, ([&update_semantics_callback, &original_init](
274268
size_t version, const FlutterRendererConfig* config,
275269
const FlutterProjectArgs* args, void* user_data, auto engine_out) {
276-
update_node_callback = args->update_semantics_node_callback;
277-
update_action_callback = args->update_semantics_custom_action_callback;
270+
update_semantics_callback = args->update_semantics_callback;
278271
return original_init(version, config, args, user_data, engine_out);
279272
}));
280273
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
@@ -305,7 +298,6 @@ @interface FlutterEngine (Test)
305298
int32_t children[] = {1};
306299
root.children_in_traversal_order = children;
307300
root.custom_accessibility_actions_count = 0;
308-
update_node_callback(&root, (void*)CFBridgingRetain(engine));
309301

310302
FlutterSemanticsNode child1;
311303
child1.id = 1;
@@ -321,15 +313,13 @@ @interface FlutterEngine (Test)
321313
child1.tooltip = "";
322314
child1.child_count = 0;
323315
child1.custom_accessibility_actions_count = 0;
324-
update_node_callback(&child1, (void*)CFBridgingRetain(engine));
325-
326-
FlutterSemanticsNode node_batch_end;
327-
node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
328-
update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine));
329316

330-
FlutterSemanticsCustomAction action_batch_end;
331-
action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
332-
update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine));
317+
FlutterSemanticsUpdate update;
318+
update.nodes_count = 2;
319+
FlutterSemanticsNode nodes[] = {root, child1};
320+
update.nodes = nodes;
321+
update.custom_actions_count = 0;
322+
update_semantics_callback(&update, (__bridge void*)engine);
333323

334324
// No crashes.
335325
EXPECT_EQ(engine.viewController, nil);
@@ -351,14 +341,12 @@ @interface FlutterEngine (Test)
351341
FlutterEngine* engine = GetFlutterEngine();
352342
// Capture the update callbacks before the embedder API initializes.
353343
auto original_init = engine.embedderAPI.Initialize;
354-
std::function<void(const FlutterSemanticsNode*, void*)> update_node_callback;
355-
std::function<void(const FlutterSemanticsCustomAction*, void*)> update_action_callback;
344+
std::function<void(const FlutterSemanticsUpdate*, void*)> update_semantics_callback;
356345
engine.embedderAPI.Initialize = MOCK_ENGINE_PROC(
357-
Initialize, ([&update_action_callback, &update_node_callback, &original_init](
346+
Initialize, ([&update_semantics_callback, &original_init](
358347
size_t version, const FlutterRendererConfig* config,
359348
const FlutterProjectArgs* args, void* user_data, auto engine_out) {
360-
update_node_callback = args->update_semantics_node_callback;
361-
update_action_callback = args->update_semantics_custom_action_callback;
349+
update_semantics_callback = args->update_semantics_callback;
362350
return original_init(version, config, args, user_data, engine_out);
363351
}));
364352
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
@@ -396,7 +384,6 @@ @interface FlutterEngine (Test)
396384
int32_t children[] = {1};
397385
root.children_in_traversal_order = children;
398386
root.custom_accessibility_actions_count = 0;
399-
update_node_callback(&root, (void*)CFBridgingRetain(engine));
400387

401388
FlutterSemanticsNode child1;
402389
child1.id = 1;
@@ -412,15 +399,13 @@ @interface FlutterEngine (Test)
412399
child1.tooltip = "";
413400
child1.child_count = 0;
414401
child1.custom_accessibility_actions_count = 0;
415-
update_node_callback(&child1, (void*)CFBridgingRetain(engine));
416-
417-
FlutterSemanticsNode node_batch_end;
418-
node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
419-
update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine));
420402

421-
FlutterSemanticsCustomAction action_batch_end;
422-
action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd;
423-
update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine));
403+
FlutterSemanticsUpdate update;
404+
update.nodes_count = 2;
405+
FlutterSemanticsNode nodes[] = {root, child1};
406+
update.nodes = nodes;
407+
update.custom_actions_count = 0;
408+
update_semantics_callback(&update, (__bridge void*)engine);
424409

425410
auto native_root = engine.accessibilityBridge.lock()->GetFlutterPlatformNodeDelegateFromID(0);
426411
EXPECT_FALSE(native_root.expired());

0 commit comments

Comments
 (0)