From 328c57674df33e52d5f64ef824a1a0c1d0e3bd86 Mon Sep 17 00:00:00 2001 From: Loic Sharma Date: Thu, 3 Nov 2022 16:11:38 -0700 Subject: [PATCH] [macOS] Move to new update semantics embedder API --- .../macos/framework/Source/FlutterEngine.mm | 60 +++++++--------- .../framework/Source/FlutterEngineTest.mm | 69 ++++++++----------- 2 files changed, 53 insertions(+), 76 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index c077930e6f18f..632bda5033349 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -299,16 +299,11 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { flutterArguments.command_line_argc = static_cast(argv.size()); flutterArguments.command_line_argv = argv.empty() ? nullptr : argv.data(); flutterArguments.platform_message_callback = (FlutterPlatformMessageCallback)OnPlatformMessage; - flutterArguments.update_semantics_node_callback = [](const FlutterSemanticsNode* node, - void* user_data) { + flutterArguments.update_semantics_callback = [](const FlutterSemanticsUpdate* update, + void* user_data) { FlutterEngine* engine = (__bridge FlutterEngine*)user_data; - [engine updateSemanticsNode:node]; + [engine updateSemantics:update]; }; - flutterArguments.update_semantics_custom_action_callback = - [](const FlutterSemanticsCustomAction* action, void* user_data) { - FlutterEngine* engine = (__bridge FlutterEngine*)user_data; - [engine updateSemanticsCustomActions:action]; - }; flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String; flutterArguments.shutdown_dart_vm_when_done = true; flutterArguments.dart_entrypoint_argc = dartEntrypointArgs.size(); @@ -913,37 +908,34 @@ - (BOOL)unregisterTextureWithID:(int64_t)textureID { return _embedderAPI.UnregisterExternalTexture(_engine, textureID) == kSuccess; } -- (void)updateSemanticsNode:(const FlutterSemanticsNode*)node { +- (void)updateSemantics:(const FlutterSemanticsUpdate*)update { NSAssert(_bridge, @"The accessibility bridge must be initialized."); - if (node->id == kFlutterSemanticsNodeIdBatchEnd) { - return; + for (size_t i = 0; i < update->nodes_count; i++) { + const FlutterSemanticsNode* node = &update->nodes[i]; + _bridge->AddFlutterSemanticsNodeUpdate(node); } - _bridge->AddFlutterSemanticsNodeUpdate(node); -} -- (void)updateSemanticsCustomActions:(const FlutterSemanticsCustomAction*)action { - NSAssert(_bridge, @"The accessibility bridge must be initialized."); - if (action->id == kFlutterSemanticsNodeIdBatchEnd) { - // Custom action with id = kFlutterSemanticsNodeIdBatchEnd indicates this is - // the end of the update batch. - _bridge->CommitUpdates(); - // Accessibility tree can only be used when the view is loaded. - if (!self.viewController.viewLoaded) { - return; - } - // Attaches the accessibility root to the flutter view. - auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock(); - if (root) { - if ([self.viewController.flutterView.accessibilityChildren count] == 0) { - NSAccessibilityElement* native_root = root->GetNativeViewAccessible(); - self.viewController.flutterView.accessibilityChildren = @[ native_root ]; - } - } else { - self.viewController.flutterView.accessibilityChildren = nil; - } + for (size_t i = 0; i < update->custom_actions_count; i++) { + const FlutterSemanticsCustomAction* action = &update->custom_actions[i]; + _bridge->AddFlutterSemanticsCustomActionUpdate(action); + } + + _bridge->CommitUpdates(); + + // Accessibility tree can only be used when the view is loaded. + if (!self.viewController.viewLoaded) { return; } - _bridge->AddFlutterSemanticsCustomActionUpdate(action); + // Attaches the accessibility root to the flutter view. + auto root = _bridge->GetFlutterPlatformNodeDelegateFromID(0).lock(); + if (root) { + if ([self.viewController.flutterView.accessibilityChildren count] == 0) { + NSAccessibilityElement* native_root = root->GetNativeViewAccessible(); + self.viewController.flutterView.accessibilityChildren = @[ native_root ]; + } + } else { + self.viewController.flutterView.accessibilityChildren = nil; + } } #pragma mark - Task runner integration diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index bcedd7cbd2116..8f9992a5369f9 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -165,14 +165,12 @@ @interface FlutterEngine (Test) FlutterEngine* engine = GetFlutterEngine(); // Capture the update callbacks before the embedder API initializes. auto original_init = engine.embedderAPI.Initialize; - std::function update_node_callback; - std::function update_action_callback; + std::function update_semantics_callback; engine.embedderAPI.Initialize = MOCK_ENGINE_PROC( - Initialize, ([&update_action_callback, &update_node_callback, &original_init]( + Initialize, ([&update_semantics_callback, &original_init]( size_t version, const FlutterRendererConfig* config, const FlutterProjectArgs* args, void* user_data, auto engine_out) { - update_node_callback = args->update_semantics_node_callback; - update_action_callback = args->update_semantics_custom_action_callback; + update_semantics_callback = args->update_semantics_callback; return original_init(version, config, args, user_data, engine_out); })); EXPECT_TRUE([engine runWithEntrypoint:@"main"]); @@ -210,7 +208,6 @@ @interface FlutterEngine (Test) int32_t children[] = {1}; root.children_in_traversal_order = children; root.custom_accessibility_actions_count = 0; - update_node_callback(&root, (void*)CFBridgingRetain(engine)); FlutterSemanticsNode child1; child1.id = 1; @@ -226,15 +223,13 @@ @interface FlutterEngine (Test) child1.tooltip = ""; child1.child_count = 0; child1.custom_accessibility_actions_count = 0; - update_node_callback(&child1, (void*)CFBridgingRetain(engine)); - FlutterSemanticsNode node_batch_end; - node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine)); - - FlutterSemanticsCustomAction action_batch_end; - action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine)); + FlutterSemanticsUpdate update; + update.nodes_count = 2; + FlutterSemanticsNode nodes[] = {root, child1}; + update.nodes = nodes; + update.custom_actions_count = 0; + update_semantics_callback(&update, (__bridge void*)engine); // Verify the accessibility tree is attached to the flutter view. EXPECT_EQ([engine.viewController.flutterView.accessibilityChildren count], 1u); @@ -267,14 +262,12 @@ @interface FlutterEngine (Test) FlutterEngine* engine = GetFlutterEngine(); // Capture the update callbacks before the embedder API initializes. auto original_init = engine.embedderAPI.Initialize; - std::function update_node_callback; - std::function update_action_callback; + std::function update_semantics_callback; engine.embedderAPI.Initialize = MOCK_ENGINE_PROC( - Initialize, ([&update_action_callback, &update_node_callback, &original_init]( + Initialize, ([&update_semantics_callback, &original_init]( size_t version, const FlutterRendererConfig* config, const FlutterProjectArgs* args, void* user_data, auto engine_out) { - update_node_callback = args->update_semantics_node_callback; - update_action_callback = args->update_semantics_custom_action_callback; + update_semantics_callback = args->update_semantics_callback; return original_init(version, config, args, user_data, engine_out); })); EXPECT_TRUE([engine runWithEntrypoint:@"main"]); @@ -305,7 +298,6 @@ @interface FlutterEngine (Test) int32_t children[] = {1}; root.children_in_traversal_order = children; root.custom_accessibility_actions_count = 0; - update_node_callback(&root, (void*)CFBridgingRetain(engine)); FlutterSemanticsNode child1; child1.id = 1; @@ -321,15 +313,13 @@ @interface FlutterEngine (Test) child1.tooltip = ""; child1.child_count = 0; child1.custom_accessibility_actions_count = 0; - update_node_callback(&child1, (void*)CFBridgingRetain(engine)); - - FlutterSemanticsNode node_batch_end; - node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine)); - FlutterSemanticsCustomAction action_batch_end; - action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine)); + FlutterSemanticsUpdate update; + update.nodes_count = 2; + FlutterSemanticsNode nodes[] = {root, child1}; + update.nodes = nodes; + update.custom_actions_count = 0; + update_semantics_callback(&update, (__bridge void*)engine); // No crashes. EXPECT_EQ(engine.viewController, nil); @@ -351,14 +341,12 @@ @interface FlutterEngine (Test) FlutterEngine* engine = GetFlutterEngine(); // Capture the update callbacks before the embedder API initializes. auto original_init = engine.embedderAPI.Initialize; - std::function update_node_callback; - std::function update_action_callback; + std::function update_semantics_callback; engine.embedderAPI.Initialize = MOCK_ENGINE_PROC( - Initialize, ([&update_action_callback, &update_node_callback, &original_init]( + Initialize, ([&update_semantics_callback, &original_init]( size_t version, const FlutterRendererConfig* config, const FlutterProjectArgs* args, void* user_data, auto engine_out) { - update_node_callback = args->update_semantics_node_callback; - update_action_callback = args->update_semantics_custom_action_callback; + update_semantics_callback = args->update_semantics_callback; return original_init(version, config, args, user_data, engine_out); })); EXPECT_TRUE([engine runWithEntrypoint:@"main"]); @@ -396,7 +384,6 @@ @interface FlutterEngine (Test) int32_t children[] = {1}; root.children_in_traversal_order = children; root.custom_accessibility_actions_count = 0; - update_node_callback(&root, (void*)CFBridgingRetain(engine)); FlutterSemanticsNode child1; child1.id = 1; @@ -412,15 +399,13 @@ @interface FlutterEngine (Test) child1.tooltip = ""; child1.child_count = 0; child1.custom_accessibility_actions_count = 0; - update_node_callback(&child1, (void*)CFBridgingRetain(engine)); - - FlutterSemanticsNode node_batch_end; - node_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_node_callback(&node_batch_end, (void*)CFBridgingRetain(engine)); - FlutterSemanticsCustomAction action_batch_end; - action_batch_end.id = kFlutterSemanticsNodeIdBatchEnd; - update_action_callback(&action_batch_end, (void*)CFBridgingRetain(engine)); + FlutterSemanticsUpdate update; + update.nodes_count = 2; + FlutterSemanticsNode nodes[] = {root, child1}; + update.nodes = nodes; + update.custom_actions_count = 0; + update_semantics_callback(&update, (__bridge void*)engine); auto native_root = engine.accessibilityBridge.lock()->GetFlutterPlatformNodeDelegateFromID(0); EXPECT_FALSE(native_root.expired());