diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 3511162c89d40..3e1f69533c605 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1253,182 +1253,6 @@ void PopulateAOTSnapshotMappingCallbacks( } } -// Translates engine semantic nodes to embedder semantic nodes. -FlutterSemanticsNode CreateEmbedderSemanticsNode( - const flutter::SemanticsNode& node) { - SkMatrix transform = node.transform.asM33(); - FlutterTransformation flutter_transform{ - transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX), - transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY), - transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY), - transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1), - transform.get(SkMatrix::kMPersp2)}; - return { - sizeof(FlutterSemanticsNode), - node.id, - static_cast(node.flags), - static_cast(node.actions), - node.textSelectionBase, - node.textSelectionExtent, - node.scrollChildren, - node.scrollIndex, - node.scrollPosition, - node.scrollExtentMax, - node.scrollExtentMin, - node.elevation, - node.thickness, - node.label.c_str(), - node.hint.c_str(), - node.value.c_str(), - node.increasedValue.c_str(), - node.decreasedValue.c_str(), - static_cast(node.textDirection), - FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight, - node.rect.fBottom}, - flutter_transform, - node.childrenInTraversalOrder.size(), - node.childrenInTraversalOrder.data(), - node.childrenInHitTestOrder.data(), - node.customAccessibilityActions.size(), - node.customAccessibilityActions.data(), - node.platformViewId, - }; -} - -// Translates engine semantic custom actions to embedder semantic custom -// actions. -FlutterSemanticsCustomAction CreateEmbedderSemanticsCustomAction( - const flutter::CustomAccessibilityAction& action) { - return { - sizeof(FlutterSemanticsCustomAction), - action.id, - static_cast(action.overrideId), - action.label.c_str(), - action.hint.c_str(), - }; -} - -// Create a callback to notify the embedder of semantic updates -// using the new embedder callback 'update_semantics_callback'. -flutter::PlatformViewEmbedder::UpdateSemanticsCallback -CreateNewEmbedderSemanticsUpdateCallback( - FlutterUpdateSemanticsCallback update_semantics_callback, - void* user_data) { - return [update_semantics_callback, user_data]( - const flutter::SemanticsNodeUpdates& nodes, - const flutter::CustomAccessibilityActionUpdates& actions) { - std::vector embedder_nodes; - for (const auto& value : nodes) { - embedder_nodes.push_back(CreateEmbedderSemanticsNode(value.second)); - } - - std::vector embedder_custom_actions; - for (const auto& value : actions) { - embedder_custom_actions.push_back( - CreateEmbedderSemanticsCustomAction(value.second)); - } - - FlutterSemanticsUpdate update{ - .struct_size = sizeof(FlutterSemanticsUpdate), - .nodes_count = embedder_nodes.size(), - .nodes = embedder_nodes.data(), - .custom_actions_count = embedder_custom_actions.size(), - .custom_actions = embedder_custom_actions.data(), - }; - - update_semantics_callback(&update, user_data); - }; -} - -// Create a callback to notify the embedder of semantic updates -// using the legacy embedder callbacks 'update_semantics_node_callback' and -// 'update_semantics_custom_action_callback'. -flutter::PlatformViewEmbedder::UpdateSemanticsCallback -CreateLegacyEmbedderSemanticsUpdateCallback( - FlutterUpdateSemanticsNodeCallback update_semantics_node_callback, - FlutterUpdateSemanticsCustomActionCallback - update_semantics_custom_action_callback, - void* user_data) { - return [update_semantics_node_callback, - update_semantics_custom_action_callback, - user_data](const flutter::SemanticsNodeUpdates& nodes, - const flutter::CustomAccessibilityActionUpdates& actions) { - // First, queue all node and custom action updates. - if (update_semantics_node_callback != nullptr) { - for (const auto& value : nodes) { - const FlutterSemanticsNode embedder_node = - CreateEmbedderSemanticsNode(value.second); - update_semantics_node_callback(&embedder_node, user_data); - } - } - - if (update_semantics_custom_action_callback != nullptr) { - for (const auto& value : actions) { - const FlutterSemanticsCustomAction embedder_action = - CreateEmbedderSemanticsCustomAction(value.second); - update_semantics_custom_action_callback(&embedder_action, user_data); - } - } - - // Second, mark node and action batches completed now that all - // updates are queued. - if (update_semantics_node_callback != nullptr) { - const FlutterSemanticsNode batch_end_sentinel = { - sizeof(FlutterSemanticsNode), - kFlutterSemanticsNodeIdBatchEnd, - }; - update_semantics_node_callback(&batch_end_sentinel, user_data); - } - - if (update_semantics_custom_action_callback != nullptr) { - const FlutterSemanticsCustomAction batch_end_sentinel = { - sizeof(FlutterSemanticsCustomAction), - kFlutterSemanticsCustomActionIdBatchEnd, - }; - update_semantics_custom_action_callback(&batch_end_sentinel, user_data); - } - }; -} - -// Creates a callback that receives semantic updates from the engine -// and notifies the embedder's callback(s). Returns null if the embedder -// did not register any callbacks. -flutter::PlatformViewEmbedder::UpdateSemanticsCallback -CreateEmbedderSemanticsUpdateCallback(const FlutterProjectArgs* args, - void* user_data) { - // The embedder can register the new callback, or the legacy callbacks, or - // nothing at all. Handle the case where the embedder registered the 'new' - // callback. - if (SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr) { - return CreateNewEmbedderSemanticsUpdateCallback( - args->update_semantics_callback, user_data); - } - - // Handle the case where the embedder registered 'legacy' callbacks. - FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr; - if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) { - update_semantics_node_callback = args->update_semantics_node_callback; - } - - FlutterUpdateSemanticsCustomActionCallback - update_semantics_custom_action_callback = nullptr; - if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) != - nullptr) { - update_semantics_custom_action_callback = - args->update_semantics_custom_action_callback; - } - - if (update_semantics_node_callback != nullptr || - update_semantics_custom_action_callback != nullptr) { - return CreateLegacyEmbedderSemanticsUpdateCallback( - update_semantics_node_callback, update_semantics_custom_action_callback, - user_data); - } - - // Handle the case where the embedder registered no callbacks. - return nullptr; -} - FlutterEngineResult FlutterEngineRun(size_t version, const FlutterRendererConfig* config, const FlutterProjectArgs* args, @@ -1576,20 +1400,113 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr); } - if (args->update_semantics_callback != nullptr && - (args->update_semantics_node_callback != nullptr || - args->update_semantics_custom_action_callback != nullptr)) { - return LOG_EMBEDDER_ERROR( - kInvalidArguments, - "Multiple semantics update callbacks provided. " - "Embedders should provide either `update_semantics_callback` " - "or both `update_semantics_nodes_callback` and " - "`update_semantics_custom_actions_callback`."); + FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr; + if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) { + update_semantics_node_callback = args->update_semantics_node_callback; + } + + FlutterUpdateSemanticsCustomActionCallback + update_semantics_custom_action_callback = nullptr; + if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) != + nullptr) { + update_semantics_custom_action_callback = + args->update_semantics_custom_action_callback; } flutter::PlatformViewEmbedder::UpdateSemanticsCallback - update_semantics_callback = - CreateEmbedderSemanticsUpdateCallback(args, user_data); + update_semantics_callback = nullptr; + if (update_semantics_node_callback != nullptr || + update_semantics_custom_action_callback != nullptr) { + update_semantics_callback = + [update_semantics_node_callback, + update_semantics_custom_action_callback, + user_data](const flutter::SemanticsNodeUpdates& update, + const flutter::CustomAccessibilityActionUpdates& actions) { + // First, queue all node and custom action updates. + if (update_semantics_node_callback != nullptr) { + for (const auto& value : update) { + const auto& node = value.second; + SkMatrix transform = node.transform.asM33(); + FlutterTransformation flutter_transform{ + transform.get(SkMatrix::kMScaleX), + transform.get(SkMatrix::kMSkewX), + transform.get(SkMatrix::kMTransX), + transform.get(SkMatrix::kMSkewY), + transform.get(SkMatrix::kMScaleY), + transform.get(SkMatrix::kMTransY), + transform.get(SkMatrix::kMPersp0), + transform.get(SkMatrix::kMPersp1), + transform.get(SkMatrix::kMPersp2)}; + const FlutterSemanticsNode embedder_node{ + sizeof(FlutterSemanticsNode), + node.id, + static_cast(node.flags), + static_cast(node.actions), + node.textSelectionBase, + node.textSelectionExtent, + node.scrollChildren, + node.scrollIndex, + node.scrollPosition, + node.scrollExtentMax, + node.scrollExtentMin, + node.elevation, + node.thickness, + node.label.c_str(), + node.hint.c_str(), + node.value.c_str(), + node.increasedValue.c_str(), + node.decreasedValue.c_str(), + static_cast(node.textDirection), + FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight, + node.rect.fBottom}, + flutter_transform, + node.childrenInTraversalOrder.size(), + node.childrenInTraversalOrder.data(), + node.childrenInHitTestOrder.data(), + node.customAccessibilityActions.size(), + node.customAccessibilityActions.data(), + node.platformViewId, + node.tooltip.c_str(), + }; + update_semantics_node_callback(&embedder_node, user_data); + } + } + + if (update_semantics_custom_action_callback != nullptr) { + for (const auto& value : actions) { + const auto& action = value.second; + const FlutterSemanticsCustomAction embedder_action = { + sizeof(FlutterSemanticsCustomAction), + action.id, + static_cast(action.overrideId), + action.label.c_str(), + action.hint.c_str(), + }; + update_semantics_custom_action_callback(&embedder_action, + user_data); + } + } + + // Second, mark node and action batches completed now that all + // updates are queued. + if (update_semantics_node_callback != nullptr) { + const FlutterSemanticsNode batch_end_sentinel = { + sizeof(FlutterSemanticsNode), + kFlutterSemanticsNodeIdBatchEnd, + }; + update_semantics_node_callback(&batch_end_sentinel, user_data); + } + + if (update_semantics_custom_action_callback != nullptr) { + const FlutterSemanticsCustomAction batch_end_sentinel = { + sizeof(FlutterSemanticsCustomAction), + kFlutterSemanticsCustomActionIdBatchEnd, + }; + update_semantics_custom_action_callback(&batch_end_sentinel, + user_data); + } + }; + } flutter::PlatformViewEmbedder::PlatformMessageResponseCallback platform_message_response_callback = nullptr; diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 7bef2e521be5d..c9e7bc27bb5a5 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1031,8 +1031,7 @@ typedef void (*FlutterDataCallback)(const uint8_t* /* data */, typedef int64_t FlutterPlatformViewIdentifier; /// `FlutterSemanticsNode` ID used as a sentinel to signal the end of a batch of -/// semantics node updates. This is unused if using -/// `FlutterUpdateSemanticsCallback`. +/// semantics node updates. FLUTTER_EXPORT extern const int32_t kFlutterSemanticsNodeIdBatchEnd; @@ -1041,7 +1040,7 @@ extern const int32_t kFlutterSemanticsNodeIdBatchEnd; /// The semantics tree is maintained during the semantics phase of the pipeline /// (i.e., during PipelineOwner.flushSemantics), which happens after /// compositing. Updates are then pushed to embedders via the registered -/// `FlutterUpdateSemanticsCallback`. +/// `FlutterUpdateSemanticsNodeCallback`. typedef struct { /// The size of this struct. Must be sizeof(FlutterSemanticsNode). size_t struct_size; @@ -1110,8 +1109,7 @@ typedef struct { } FlutterSemanticsNode; /// `FlutterSemanticsCustomAction` ID used as a sentinel to signal the end of a -/// batch of semantics custom action updates. This is unused if using -/// `FlutterUpdateSemanticsCallback`. +/// batch of semantics custom action updates. FLUTTER_EXPORT extern const int32_t kFlutterSemanticsCustomActionIdBatchEnd; @@ -1138,20 +1136,6 @@ typedef struct { const char* hint; } FlutterSemanticsCustomAction; -/// A batch of updates to semantics nodes and custom actions. -typedef struct { - /// The size of the struct. Must be sizeof(FlutterSemanticsUpdate). - size_t struct_size; - /// The number of semantics node updates. - size_t nodes_count; - // Array of semantics nodes. Has length `nodes_count`. - FlutterSemanticsNode* nodes; - /// The number of semantics custom action updates. - size_t custom_actions_count; - /// Array of semantics custom actions. Has length `custom_actions_count`. - FlutterSemanticsCustomAction* custom_actions; -} FlutterSemanticsUpdate; - typedef void (*FlutterUpdateSemanticsNodeCallback)( const FlutterSemanticsNode* /* semantics node */, void* /* user data */); @@ -1160,10 +1144,6 @@ typedef void (*FlutterUpdateSemanticsCustomActionCallback)( const FlutterSemanticsCustomAction* /* semantics custom action */, void* /* user data */); -typedef void (*FlutterUpdateSemanticsCallback)( - const FlutterSemanticsUpdate* /* semantics update */, - void* /* user data*/); - typedef struct _FlutterTaskRunner* FlutterTaskRunner; typedef struct { @@ -1759,32 +1739,24 @@ typedef struct { /// The callback invoked by the engine in root isolate scope. Called /// immediately after the root isolate has been created and marked runnable. VoidCallback root_isolate_create_callback; - /// The legacy callback invoked by the engine in order to give the embedder - /// the chance to respond to semantics node updates from the Dart application. + /// The callback invoked by the engine in order to give the embedder the + /// chance to respond to semantics node updates from the Dart application. /// Semantics node updates are sent in batches terminated by a 'batch end' /// callback that is passed a sentinel `FlutterSemanticsNode` whose `id` field /// has the value `kFlutterSemanticsNodeIdBatchEnd`. /// /// The callback will be invoked on the thread on which the `FlutterEngineRun` /// call is made. - /// - /// @deprecated Prefer using `update_semantics_callback` instead. If this - /// calback is provided, `update_semantics_callback` must not - /// be provided. FlutterUpdateSemanticsNodeCallback update_semantics_node_callback; - /// The legacy callback invoked by the engine in order to give the embedder - /// the chance to respond to updates to semantics custom actions from the Dart - /// application. Custom action updates are sent in batches terminated by a + /// The callback invoked by the engine in order to give the embedder the + /// chance to respond to updates to semantics custom actions from the Dart + /// application. Custom action updates are sent in batches terminated by a /// 'batch end' callback that is passed a sentinel /// `FlutterSemanticsCustomAction` whose `id` field has the value /// `kFlutterSemanticsCustomActionIdBatchEnd`. /// /// The callback will be invoked on the thread on which the `FlutterEngineRun` /// call is made. - /// - /// @deprecated Prefer using `update_semantics_callback` instead. If this - /// calback is provided, `update_semantics_callback` must not - /// be provided. FlutterUpdateSemanticsCustomActionCallback update_semantics_custom_action_callback; /// Path to a directory used to store data that is cached across runs of a @@ -1921,17 +1893,6 @@ typedef struct { // // The first argument is the `user_data` from `FlutterEngineInitialize`. OnPreEngineRestartCallback on_pre_engine_restart_callback; - - /// The callback invoked by the engine in order to give the embedder the - /// chance to respond to updates to semantics nodes and custom actions from - /// the Dart application. - /// - /// The callback will be invoked on the thread on which the `FlutterEngineRun` - /// call is made. - /// - /// If this callback is provided, update_semantics_node_callback and - /// update_semantics_custom_action_callback must not be provided. - FlutterUpdateSemanticsCallback update_semantics_callback; } FlutterProjectArgs; #ifndef FLUTTER_ENGINE_NO_PROTOTYPES @@ -2273,8 +2234,8 @@ FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable( /// @param[in] engine A running engine instance. /// @param[in] enabled When enabled, changes to the semantic contents of the /// window are sent via the -/// `FlutterUpdateSemanticsCallback` registered to -/// `update_semantics_callback` in +/// `FlutterUpdateSemanticsNodeCallback` registered to +/// `update_semantics_node_callback` in /// `FlutterProjectArgs`. /// /// @return The result of the call. diff --git a/shell/platform/embedder/tests/embedder_a11y_unittests.cc b/shell/platform/embedder/tests/embedder_a11y_unittests.cc index 21db35a31e12c..87f0c8f38e67d 100644 --- a/shell/platform/embedder/tests/embedder_a11y_unittests.cc +++ b/shell/platform/embedder/tests/embedder_a11y_unittests.cc @@ -24,21 +24,6 @@ namespace testing { using EmbedderA11yTest = testing::EmbedderTest; -TEST_F(EmbedderTest, CannotProvideNewAndLegacySemanticsCallback) { - EmbedderConfigBuilder builder( - GetEmbedderContext(EmbedderTestContextType::kSoftwareContext)); - builder.SetSoftwareRendererConfig(); - builder.GetProjectArgs().update_semantics_callback = - [](const FlutterSemanticsUpdate* update, void* user_data) {}; - builder.GetProjectArgs().update_semantics_node_callback = - [](const FlutterSemanticsNode* update, void* user_data) {}; - builder.GetProjectArgs().update_semantics_custom_action_callback = - [](const FlutterSemanticsCustomAction* update, void* user_data) {}; - auto engine = builder.InitializeEngine(); - ASSERT_FALSE(engine.is_valid()); - engine.reset(); -} - TEST_F(EmbedderA11yTest, A11yTreeIsConsistent) { #if defined(OS_FUCHSIA) GTEST_SKIP() << "This test crashes on Fuchsia. https://fxbug.dev/87493 "; @@ -83,35 +68,6 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistent) { notify_semantics_action_callback(args); }))); - fml::AutoResetWaitableEvent semantics_update_latch; - context.SetSemanticsUpdateCallback([&](const FlutterSemanticsUpdate* update) { - ASSERT_EQ(size_t(4), update->nodes_count); - ASSERT_EQ(size_t(1), update->custom_actions_count); - - for (size_t i = 0; i < update->nodes_count; i++) { - const FlutterSemanticsNode* node = update->nodes + i; - - ASSERT_EQ(1.0, node->transform.scaleX); - ASSERT_EQ(2.0, node->transform.skewX); - ASSERT_EQ(3.0, node->transform.transX); - ASSERT_EQ(4.0, node->transform.skewY); - ASSERT_EQ(5.0, node->transform.scaleY); - ASSERT_EQ(6.0, node->transform.transY); - ASSERT_EQ(7.0, node->transform.pers0); - ASSERT_EQ(8.0, node->transform.pers1); - ASSERT_EQ(9.0, node->transform.pers2); - - if (node->id == 128) { - ASSERT_EQ(0x3f3, node->platform_view_id); - } else { - ASSERT_NE(kFlutterSemanticsNodeIdBatchEnd, node->id); - ASSERT_EQ(0, node->platform_view_id); - } - } - - semantics_update_latch.Signal(); - }); - EmbedderConfigBuilder builder(context); builder.SetSoftwareRendererConfig(); builder.SetDartEntrypoint("a11y_main"); @@ -168,93 +124,6 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistent) { latch.Wait(); // Wait for UpdateSemantics callback on platform (current) thread. - latch.Wait(); - fml::MessageLoop::GetCurrent().RunExpiredTasksNow(); - semantics_update_latch.Wait(); - - // Dispatch a tap to semantics node 42. Wait for NotifySemanticsAction. - notify_semantics_action_callback = [&](Dart_NativeArguments args) { - int64_t node_id = 0; - Dart_GetNativeIntegerArgument(args, 0, &node_id); - ASSERT_EQ(42, node_id); - - int64_t action_id; - auto handle = Dart_GetNativeIntegerArgument(args, 1, &action_id); - ASSERT_FALSE(Dart_IsError(handle)); - ASSERT_EQ(static_cast(flutter::SemanticsAction::kTap), action_id); - - Dart_Handle semantic_args = Dart_GetNativeArgument(args, 2); - int64_t data; - Dart_Handle dart_int = Dart_ListGetAt(semantic_args, 0); - Dart_IntegerToInt64(dart_int, &data); - ASSERT_EQ(2, data); - - dart_int = Dart_ListGetAt(semantic_args, 1); - Dart_IntegerToInt64(dart_int, &data); - ASSERT_EQ(1, data); - latch.Signal(); - }; - std::vector bytes({2, 1}); - result = FlutterEngineDispatchSemanticsAction( - engine.get(), 42, kFlutterSemanticsActionTap, &bytes[0], bytes.size()); - ASSERT_EQ(result, FlutterEngineResult::kSuccess); - latch.Wait(); - - // Disable semantics. Wait for NotifySemanticsEnabled(false). - notify_semantics_enabled_callback = [&](Dart_NativeArguments args) { - bool enabled = true; - Dart_GetNativeBooleanArgument(args, 0, &enabled); - ASSERT_FALSE(enabled); - latch.Signal(); - }; - result = FlutterEngineUpdateSemanticsEnabled(engine.get(), false); - ASSERT_EQ(result, FlutterEngineResult::kSuccess); - latch.Wait(); -} - -TEST_F(EmbedderA11yTest, A11yTreeIsConsistentUsingLegacyCallbacks) { - auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); - - fml::AutoResetWaitableEvent latch; - - // Called by the Dart text fixture on the UI thread to signal that the C++ - // unittest should resume. - context.AddNativeCallback( - "SignalNativeTest", CREATE_NATIVE_ENTRY(([&latch](Dart_NativeArguments) { - latch.Signal(); - }))); - - // Called by test fixture on UI thread to pass data back to this test. - NativeEntry notify_semantics_enabled_callback; - context.AddNativeCallback( - "NotifySemanticsEnabled", - CREATE_NATIVE_ENTRY( - ([¬ify_semantics_enabled_callback](Dart_NativeArguments args) { - ASSERT_NE(notify_semantics_enabled_callback, nullptr); - notify_semantics_enabled_callback(args); - }))); - - NativeEntry notify_accessibility_features_callback; - context.AddNativeCallback( - "NotifyAccessibilityFeatures", - CREATE_NATIVE_ENTRY(( - [¬ify_accessibility_features_callback](Dart_NativeArguments args) { - ASSERT_NE(notify_accessibility_features_callback, nullptr); - notify_accessibility_features_callback(args); - }))); - - NativeEntry notify_semantics_action_callback; - context.AddNativeCallback( - "NotifySemanticsAction", - CREATE_NATIVE_ENTRY( - ([¬ify_semantics_action_callback](Dart_NativeArguments args) { - ASSERT_NE(notify_semantics_action_callback, nullptr); - notify_semantics_action_callback(args); - }))); - - fml::AutoResetWaitableEvent semantics_node_latch; - fml::AutoResetWaitableEvent semantics_action_latch; - int node_batch_end_count = 0; int action_batch_end_count = 0; @@ -262,7 +131,6 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistentUsingLegacyCallbacks) { context.SetSemanticsNodeCallback([&](const FlutterSemanticsNode* node) { if (node->id == kFlutterSemanticsNodeIdBatchEnd) { ++node_batch_end_count; - semantics_node_latch.Signal(); } else { // Batches should be completed after all nodes are received. ASSERT_EQ(0, node_batch_end_count); @@ -292,7 +160,6 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistentUsingLegacyCallbacks) { [&](const FlutterSemanticsCustomAction* action) { if (action->id == kFlutterSemanticsCustomActionIdBatchEnd) { ++action_batch_end_count; - semantics_action_latch.Signal(); } else { // Batches should be completed after all actions are received. ASSERT_EQ(0, node_batch_end_count); @@ -302,66 +169,8 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistentUsingLegacyCallbacks) { } }); - EmbedderConfigBuilder builder(context); - builder.SetSoftwareRendererConfig(); - builder.SetDartEntrypoint("a11y_main"); - - auto engine = builder.LaunchEngine(); - ASSERT_TRUE(engine.is_valid()); - - // Wait for initial NotifySemanticsEnabled(false). - notify_semantics_enabled_callback = [&](Dart_NativeArguments args) { - bool enabled = true; - auto handle = Dart_GetNativeBooleanArgument(args, 0, &enabled); - ASSERT_FALSE(Dart_IsError(handle)); - ASSERT_FALSE(enabled); - latch.Signal(); - }; - latch.Wait(); - - // Prepare to NotifyAccessibilityFeatures call - fml::AutoResetWaitableEvent notify_features_latch; - notify_accessibility_features_callback = [&](Dart_NativeArguments args) { - bool enabled = true; - auto handle = Dart_GetNativeBooleanArgument(args, 0, &enabled); - ASSERT_FALSE(Dart_IsError(handle)); - ASSERT_FALSE(enabled); - notify_features_latch.Signal(); - }; - - // Enable semantics. Wait for NotifySemanticsEnabled(true). - notify_semantics_enabled_callback = [&](Dart_NativeArguments args) { - bool enabled = false; - auto handle = Dart_GetNativeBooleanArgument(args, 0, &enabled); - ASSERT_FALSE(Dart_IsError(handle)); - ASSERT_TRUE(enabled); - latch.Signal(); - }; - auto result = FlutterEngineUpdateSemanticsEnabled(engine.get(), true); - ASSERT_EQ(result, FlutterEngineResult::kSuccess); - latch.Wait(); - - // Wait for initial accessibility features (reduce_motion == false) - notify_features_latch.Wait(); - - // Set accessibility features: (reduce_motion == true) - notify_accessibility_features_callback = [&](Dart_NativeArguments args) { - bool enabled = false; - auto handle = Dart_GetNativeBooleanArgument(args, 0, &enabled); - ASSERT_FALSE(Dart_IsError(handle)); - ASSERT_TRUE(enabled); - latch.Signal(); - }; - result = FlutterEngineUpdateAccessibilityFeatures( - engine.get(), kFlutterAccessibilityFeatureReduceMotion); - ASSERT_EQ(result, FlutterEngineResult::kSuccess); - latch.Wait(); - - // Wait for UpdateSemantics callback on platform (current) thread. latch.Wait(); fml::MessageLoop::GetCurrent().RunExpiredTasksNow(); - semantics_node_latch.Wait(); - semantics_action_latch.Wait(); ASSERT_EQ(4, node_count); ASSERT_EQ(1, node_batch_end_count); ASSERT_EQ(1, action_count); diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index d61b5ffb63370..92ff07a81291a 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -247,12 +247,10 @@ void EmbedderConfigBuilder::SetIsolateCreateCallbackHook() { } void EmbedderConfigBuilder::SetSemanticsCallbackHooks() { - project_args_.update_semantics_callback = - context_.GetUpdateSemanticsCallbackHook(); project_args_.update_semantics_node_callback = - context_.GetUpdateSemanticsNodeCallbackHook(); + EmbedderTestContext::GetUpdateSemanticsNodeCallbackHook(); project_args_.update_semantics_custom_action_callback = - context_.GetUpdateSemanticsCustomActionCallbackHook(); + EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook(); } void EmbedderConfigBuilder::SetLogMessageCallbackHook() { diff --git a/shell/platform/embedder/tests/embedder_test_context.cc b/shell/platform/embedder/tests/embedder_test_context.cc index 904eed9cb77c5..261eb0f6b980f 100644 --- a/shell/platform/embedder/tests/embedder_test_context.cc +++ b/shell/platform/embedder/tests/embedder_test_context.cc @@ -121,11 +121,6 @@ void EmbedderTestContext::AddNativeCallback(const char* name, native_resolver_->AddNativeCallback({name}, function); } -void EmbedderTestContext::SetSemanticsUpdateCallback( - SemanticsUpdateCallback update_semantics_callback) { - update_semantics_callback_ = std::move(update_semantics_callback); -} - void EmbedderTestContext::SetSemanticsNodeCallback( SemanticsNodeCallback update_semantics_node_callback) { update_semantics_node_callback_ = std::move(update_semantics_node_callback); @@ -154,44 +149,22 @@ void EmbedderTestContext::SetLogMessageCallback( log_message_callback_ = callback; } -FlutterUpdateSemanticsCallback -EmbedderTestContext::GetUpdateSemanticsCallbackHook() { - if (update_semantics_callback_ == nullptr) { - return nullptr; - } - - return [](const FlutterSemanticsUpdate* update, void* user_data) { - auto context = reinterpret_cast(user_data); - if (context->update_semantics_callback_) { - context->update_semantics_callback_(update); - } - }; -} - FlutterUpdateSemanticsNodeCallback EmbedderTestContext::GetUpdateSemanticsNodeCallbackHook() { - if (update_semantics_node_callback_ == nullptr) { - return nullptr; - } - return [](const FlutterSemanticsNode* semantics_node, void* user_data) { auto context = reinterpret_cast(user_data); - if (context->update_semantics_node_callback_) { - context->update_semantics_node_callback_(semantics_node); + if (auto callback = context->update_semantics_node_callback_) { + callback(semantics_node); } }; } FlutterUpdateSemanticsCustomActionCallback EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook() { - if (update_semantics_custom_action_callback_ == nullptr) { - return nullptr; - } - return [](const FlutterSemanticsCustomAction* action, void* user_data) { auto context = reinterpret_cast(user_data); - if (context->update_semantics_custom_action_callback_) { - context->update_semantics_custom_action_callback_(action); + if (auto callback = context->update_semantics_custom_action_callback_) { + callback(action); } }; } @@ -199,8 +172,8 @@ EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook() { FlutterLogMessageCallback EmbedderTestContext::GetLogMessageCallbackHook() { return [](const char* tag, const char* message, void* user_data) { auto context = reinterpret_cast(user_data); - if (context->log_message_callback_) { - context->log_message_callback_(tag, message); + if (auto callback = context->log_message_callback_) { + callback(tag, message); } }; } diff --git a/shell/platform/embedder/tests/embedder_test_context.h b/shell/platform/embedder/tests/embedder_test_context.h index 53c117447e467..8577abbdbb301 100644 --- a/shell/platform/embedder/tests/embedder_test_context.h +++ b/shell/platform/embedder/tests/embedder_test_context.h @@ -24,8 +24,6 @@ namespace flutter { namespace testing { -using SemanticsUpdateCallback = - std::function; using SemanticsNodeCallback = std::function; using SemanticsActionCallback = std::function; @@ -71,8 +69,6 @@ class EmbedderTestContext { void AddIsolateCreateCallback(const fml::closure& closure); - void SetSemanticsUpdateCallback(SemanticsUpdateCallback update_semantics); - void AddNativeCallback(const char* name, Dart_NativeFunction function); void SetSemanticsNodeCallback(SemanticsNodeCallback update_semantics_node); @@ -124,7 +120,6 @@ class EmbedderTestContext { UniqueAOTData aot_data_; std::vector isolate_create_callbacks_; std::shared_ptr native_resolver_; - SemanticsUpdateCallback update_semantics_callback_; SemanticsNodeCallback update_semantics_node_callback_; SemanticsActionCallback update_semantics_custom_action_callback_; std::function platform_message_callback_; @@ -136,11 +131,10 @@ class EmbedderTestContext { static VoidCallback GetIsolateCreateCallbackHook(); - FlutterUpdateSemanticsCallback GetUpdateSemanticsCallbackHook(); - - FlutterUpdateSemanticsNodeCallback GetUpdateSemanticsNodeCallbackHook(); + static FlutterUpdateSemanticsNodeCallback + GetUpdateSemanticsNodeCallbackHook(); - FlutterUpdateSemanticsCustomActionCallback + static FlutterUpdateSemanticsCustomActionCallback GetUpdateSemanticsCustomActionCallbackHook(); static FlutterLogMessageCallback GetLogMessageCallbackHook(); diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 1cd2fc408c330..9ecdcabe7e655 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -321,23 +321,25 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { auto host = static_cast(user_data); host->view()->OnPreEngineRestart(); }; - args.update_semantics_callback = [](const FlutterSemanticsUpdate* update, - void* user_data) { + args.update_semantics_node_callback = [](const FlutterSemanticsNode* node, + void* user_data) { auto host = static_cast(user_data); - - for (size_t i = 0; i < update->nodes_count; i++) { - const FlutterSemanticsNode* node = &update->nodes[i]; - host->accessibility_bridge_->AddFlutterSemanticsNodeUpdate(node); - } - - for (size_t i = 0; i < update->custom_actions_count; i++) { - const FlutterSemanticsCustomAction* action = &update->custom_actions[i]; - host->accessibility_bridge_->AddFlutterSemanticsCustomActionUpdate( - action); + if (!node || node->id == kFlutterSemanticsNodeIdBatchEnd) { + host->accessibility_bridge_->CommitUpdates(); + return; } - - host->accessibility_bridge_->CommitUpdates(); + host->accessibility_bridge_->AddFlutterSemanticsNodeUpdate(node); }; + args.update_semantics_custom_action_callback = + [](const FlutterSemanticsCustomAction* action, void* user_data) { + auto host = static_cast(user_data); + if (!action || action->id == kFlutterSemanticsNodeIdBatchEnd) { + host->accessibility_bridge_->CommitUpdates(); + return; + } + host->accessibility_bridge_->AddFlutterSemanticsCustomActionUpdate( + action); + }; args.root_isolate_create_callback = [](void* user_data) { auto host = static_cast(user_data); if (host->root_isolate_create_callback_) { diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc index 9714bd8767144..b0d63aaf6223f 100644 --- a/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -77,9 +77,6 @@ TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) { EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr); EXPECT_EQ(args->custom_dart_entrypoint, nullptr); EXPECT_NE(args->vsync_callback, nullptr); - EXPECT_NE(args->update_semantics_callback, nullptr); - EXPECT_EQ(args->update_semantics_node_callback, nullptr); - EXPECT_EQ(args->update_semantics_custom_action_callback, nullptr); args->custom_task_runners->thread_priority_setter( FlutterThreadPriority::kRaster);