@@ -1268,10 +1268,10 @@ FlutterSemanticsNode CreateEmbedderSemanticsNode(
12681268 transform.get (SkMatrix::kMScaleY ), transform.get (SkMatrix::kMTransY ),
12691269 transform.get (SkMatrix::kMPersp0 ), transform.get (SkMatrix::kMPersp1 ),
12701270 transform.get (SkMatrix::kMPersp2 )};
1271+
12711272 // Do not add new members to FlutterSemanticsNode.
12721273 // This would break the forward compatibility of FlutterSemanticsUpdate.
1273- // TODO(loicsharma): Introduce FlutterSemanticsNode2.
1274- // https://github.com/flutter/flutter/issues/121176
1274+ // All new members must be added to FlutterSemanticsNode2 instead.
12751275 return {
12761276 sizeof (FlutterSemanticsNode),
12771277 node.id ,
@@ -1305,14 +1305,56 @@ FlutterSemanticsNode CreateEmbedderSemanticsNode(
13051305 };
13061306}
13071307
1308+ // Translates engine semantic nodes to embedder semantic nodes.
1309+ FlutterSemanticsNode2 CreateEmbedderSemanticsNode2 (
1310+ const flutter::SemanticsNode& node) {
1311+ SkMatrix transform = node.transform .asM33 ();
1312+ FlutterTransformation flutter_transform{
1313+ transform.get (SkMatrix::kMScaleX ), transform.get (SkMatrix::kMSkewX ),
1314+ transform.get (SkMatrix::kMTransX ), transform.get (SkMatrix::kMSkewY ),
1315+ transform.get (SkMatrix::kMScaleY ), transform.get (SkMatrix::kMTransY ),
1316+ transform.get (SkMatrix::kMPersp0 ), transform.get (SkMatrix::kMPersp1 ),
1317+ transform.get (SkMatrix::kMPersp2 )};
1318+ return {
1319+ sizeof (FlutterSemanticsNode2),
1320+ node.id ,
1321+ static_cast <FlutterSemanticsFlag>(node.flags ),
1322+ static_cast <FlutterSemanticsAction>(node.actions ),
1323+ node.textSelectionBase ,
1324+ node.textSelectionExtent ,
1325+ node.scrollChildren ,
1326+ node.scrollIndex ,
1327+ node.scrollPosition ,
1328+ node.scrollExtentMax ,
1329+ node.scrollExtentMin ,
1330+ node.elevation ,
1331+ node.thickness ,
1332+ node.label .c_str (),
1333+ node.hint .c_str (),
1334+ node.value .c_str (),
1335+ node.increasedValue .c_str (),
1336+ node.decreasedValue .c_str (),
1337+ static_cast <FlutterTextDirection>(node.textDirection ),
1338+ FlutterRect{node.rect .fLeft , node.rect .fTop , node.rect .fRight ,
1339+ node.rect .fBottom },
1340+ flutter_transform,
1341+ node.childrenInTraversalOrder .size (),
1342+ node.childrenInTraversalOrder .data (),
1343+ node.childrenInHitTestOrder .data (),
1344+ node.customAccessibilityActions .size (),
1345+ node.customAccessibilityActions .data (),
1346+ node.platformViewId ,
1347+ node.tooltip .c_str (),
1348+ };
1349+ }
1350+
13081351// Translates engine semantic custom actions to embedder semantic custom
13091352// actions.
13101353FlutterSemanticsCustomAction CreateEmbedderSemanticsCustomAction (
13111354 const flutter::CustomAccessibilityAction& action) {
13121355 // Do not add new members to FlutterSemanticsCustomAction.
13131356 // This would break the forward compatibility of FlutterSemanticsUpdate.
1314- // TODO(loicsharma): Introduce FlutterSemanticsCustomAction2.
1315- // https://github.com/flutter/flutter/issues/121176
1357+ // All new members must be added to FlutterSemanticsCustomAction2 instead.
13161358 return {
13171359 sizeof (FlutterSemanticsCustomAction),
13181360 action.id ,
@@ -1322,8 +1364,21 @@ FlutterSemanticsCustomAction CreateEmbedderSemanticsCustomAction(
13221364 };
13231365}
13241366
1367+ // Translates engine semantic custom actions to embedder semantic custom
1368+ // actions.
1369+ FlutterSemanticsCustomAction2 CreateEmbedderSemanticsCustomAction2 (
1370+ const flutter::CustomAccessibilityAction& action) {
1371+ return {
1372+ sizeof (FlutterSemanticsCustomAction2),
1373+ action.id ,
1374+ static_cast <FlutterSemanticsAction>(action.overrideId ),
1375+ action.label .c_str (),
1376+ action.hint .c_str (),
1377+ };
1378+ }
1379+
13251380// Create a callback to notify the embedder of semantic updates
1326- // using the new embedder callback 'update_semantics_callback'.
1381+ // using the deprecated embedder callback 'update_semantics_callback'.
13271382flutter::PlatformViewEmbedder::UpdateSemanticsCallback
13281383CreateNewEmbedderSemanticsUpdateCallback (
13291384 FlutterUpdateSemanticsCallback update_semantics_callback,
@@ -1354,6 +1409,58 @@ CreateNewEmbedderSemanticsUpdateCallback(
13541409 };
13551410}
13561411
1412+ // Create a callback to notify the embedder of semantic updates
1413+ // using the new embedder callback 'update_semantics_callback2'.
1414+ flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1415+ CreateNewEmbedderSemanticsUpdateCallback2 (
1416+ FlutterUpdateSemanticsCallback2 update_semantics_callback,
1417+ void * user_data) {
1418+ return [update_semantics_callback, user_data](
1419+ const flutter::SemanticsNodeUpdates& nodes,
1420+ const flutter::CustomAccessibilityActionUpdates& actions) {
1421+ std::vector<FlutterSemanticsNode2> embedder_nodes;
1422+ std::vector<FlutterSemanticsCustomAction2> embedder_custom_actions;
1423+
1424+ embedder_nodes.reserve (nodes.size ());
1425+ embedder_custom_actions.reserve (actions.size ());
1426+
1427+ for (const auto & value : nodes) {
1428+ embedder_nodes.push_back (CreateEmbedderSemanticsNode2 (value.second ));
1429+ }
1430+
1431+ for (const auto & value : actions) {
1432+ embedder_custom_actions.push_back (
1433+ CreateEmbedderSemanticsCustomAction2 (value.second ));
1434+ }
1435+
1436+ // Provide the embedder an array of pointers to maintain full forward and
1437+ // backward compatibility even if new members are added to semantic structs.
1438+ std::vector<FlutterSemanticsNode2*> embedder_node_pointers;
1439+ std::vector<FlutterSemanticsCustomAction2*> embedder_custom_action_pointers;
1440+
1441+ embedder_node_pointers.reserve (embedder_nodes.size ());
1442+ embedder_custom_action_pointers.reserve (embedder_custom_actions.size ());
1443+
1444+ for (auto & node : embedder_nodes) {
1445+ embedder_node_pointers.push_back (&node);
1446+ }
1447+
1448+ for (auto & action : embedder_custom_actions) {
1449+ embedder_custom_action_pointers.push_back (&action);
1450+ }
1451+
1452+ FlutterSemanticsUpdate2 update{
1453+ .struct_size = sizeof (FlutterSemanticsUpdate2),
1454+ .node_count = embedder_node_pointers.size (),
1455+ .nodes = embedder_node_pointers.data (),
1456+ .custom_action_count = embedder_custom_action_pointers.size (),
1457+ .custom_actions = embedder_custom_action_pointers.data (),
1458+ };
1459+
1460+ update_semantics_callback (&update, user_data);
1461+ };
1462+ }
1463+
13571464// Create a callback to notify the embedder of semantic updates
13581465// using the legacy embedder callbacks 'update_semantics_node_callback' and
13591466// 'update_semantics_custom_action_callback'.
@@ -1413,6 +1520,11 @@ CreateEmbedderSemanticsUpdateCallback(const FlutterProjectArgs* args,
14131520 // The embedder can register the new callback, or the legacy callbacks, or
14141521 // nothing at all. Handle the case where the embedder registered the 'new'
14151522 // callback.
1523+ if (SAFE_ACCESS (args, update_semantics_callback2, nullptr ) != nullptr ) {
1524+ return CreateNewEmbedderSemanticsUpdateCallback2 (
1525+ args->update_semantics_callback2 , user_data);
1526+ }
1527+
14161528 if (SAFE_ACCESS (args, update_semantics_callback, nullptr ) != nullptr ) {
14171529 return CreateNewEmbedderSemanticsUpdateCallback (
14181530 args->update_semantics_callback , user_data);
@@ -1590,15 +1702,27 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
15901702 settings.log_tag = SAFE_ACCESS (args, log_tag, nullptr );
15911703 }
15921704
1593- if (args->update_semantics_callback != nullptr &&
1594- (args->update_semantics_node_callback != nullptr ||
1595- args->update_semantics_custom_action_callback != nullptr )) {
1705+ bool has_update_semantics_2_callback =
1706+ SAFE_ACCESS (args, update_semantics_callback2, nullptr ) != nullptr ;
1707+ bool has_update_semantics_callback =
1708+ SAFE_ACCESS (args, update_semantics_callback, nullptr ) != nullptr ;
1709+ bool has_legacy_update_semantics_callback =
1710+ SAFE_ACCESS (args, update_semantics_node_callback, nullptr ) != nullptr ||
1711+ SAFE_ACCESS (args, update_semantics_custom_action_callback, nullptr ) !=
1712+ nullptr ;
1713+
1714+ int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0 ) +
1715+ (has_update_semantics_callback ? 1 : 0 ) +
1716+ (has_legacy_update_semantics_callback ? 1 : 0 );
1717+
1718+ if (semantic_callback_count > 1 ) {
15961719 return LOG_EMBEDDER_ERROR (
15971720 kInvalidArguments ,
15981721 " Multiple semantics update callbacks provided. "
1599- " Embedders should provide either `update_semantics_callback` "
1600- " or both `update_semantics_nodes_callback` and "
1601- " `update_semantics_custom_actions_callback`." );
1722+ " Embedders should provide either `update_semantics_callback2`, "
1723+ " `update_semantics_callback`, or both "
1724+ " `update_semantics_node_callback` and "
1725+ " `update_semantics_custom_action_callback`." );
16021726 }
16031727
16041728 flutter::PlatformViewEmbedder::UpdateSemanticsCallback
0 commit comments