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

Commit ea97a5e

Browse files
committed
[Embedder API] Introduce new semantics update callback
1 parent fb7cde6 commit ea97a5e

File tree

8 files changed

+483
-140
lines changed

8 files changed

+483
-140
lines changed

shell/platform/embedder/embedder.cc

Lines changed: 187 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,182 @@ void PopulateAOTSnapshotMappingCallbacks(
12531253
}
12541254
}
12551255

1256+
// Translates engine semantic nodes to embedder semantic nodes.
1257+
FlutterSemanticsNode CreateEmbedderSemanticsNode(
1258+
const flutter::SemanticsNode& node) {
1259+
SkMatrix transform = node.transform.asM33();
1260+
FlutterTransformation flutter_transform{
1261+
transform.get(SkMatrix::kMScaleX), transform.get(SkMatrix::kMSkewX),
1262+
transform.get(SkMatrix::kMTransX), transform.get(SkMatrix::kMSkewY),
1263+
transform.get(SkMatrix::kMScaleY), transform.get(SkMatrix::kMTransY),
1264+
transform.get(SkMatrix::kMPersp0), transform.get(SkMatrix::kMPersp1),
1265+
transform.get(SkMatrix::kMPersp2)};
1266+
return {
1267+
sizeof(FlutterSemanticsNode),
1268+
node.id,
1269+
static_cast<FlutterSemanticsFlag>(node.flags),
1270+
static_cast<FlutterSemanticsAction>(node.actions),
1271+
node.textSelectionBase,
1272+
node.textSelectionExtent,
1273+
node.scrollChildren,
1274+
node.scrollIndex,
1275+
node.scrollPosition,
1276+
node.scrollExtentMax,
1277+
node.scrollExtentMin,
1278+
node.elevation,
1279+
node.thickness,
1280+
node.label.c_str(),
1281+
node.hint.c_str(),
1282+
node.value.c_str(),
1283+
node.increasedValue.c_str(),
1284+
node.decreasedValue.c_str(),
1285+
static_cast<FlutterTextDirection>(node.textDirection),
1286+
FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
1287+
node.rect.fBottom},
1288+
flutter_transform,
1289+
node.childrenInTraversalOrder.size(),
1290+
node.childrenInTraversalOrder.data(),
1291+
node.childrenInHitTestOrder.data(),
1292+
node.customAccessibilityActions.size(),
1293+
node.customAccessibilityActions.data(),
1294+
node.platformViewId,
1295+
};
1296+
}
1297+
1298+
// Translates engine semantic custom actions to embedder semantic custom
1299+
// actions.
1300+
FlutterSemanticsCustomAction CreateEmbedderSemanticsCustomAction(
1301+
const flutter::CustomAccessibilityAction& action) {
1302+
return {
1303+
sizeof(FlutterSemanticsCustomAction),
1304+
action.id,
1305+
static_cast<FlutterSemanticsAction>(action.overrideId),
1306+
action.label.c_str(),
1307+
action.hint.c_str(),
1308+
};
1309+
}
1310+
1311+
// Create a callback to notify the embedder of semantic updates
1312+
// using the new embedder callback 'update_semantics_callback'.
1313+
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1314+
CreateNewEmbedderSemanticsUpdateCallback(
1315+
FlutterUpdateSemanticsCallback update_semantics_callback,
1316+
void* user_data) {
1317+
return [update_semantics_callback, user_data](
1318+
const flutter::SemanticsNodeUpdates& nodes,
1319+
const flutter::CustomAccessibilityActionUpdates& actions) {
1320+
std::vector<FlutterSemanticsNode> embedder_nodes;
1321+
for (const auto& value : nodes) {
1322+
embedder_nodes.push_back(CreateEmbedderSemanticsNode(value.second));
1323+
}
1324+
1325+
std::vector<FlutterSemanticsCustomAction> embedder_custom_actions;
1326+
for (const auto& value : actions) {
1327+
embedder_custom_actions.push_back(
1328+
CreateEmbedderSemanticsCustomAction(value.second));
1329+
}
1330+
1331+
FlutterSemanticsUpdate update{
1332+
.struct_size = sizeof(FlutterSemanticsUpdate),
1333+
.nodes_count = embedder_nodes.size(),
1334+
.nodes = embedder_nodes.data(),
1335+
.custom_actions_count = embedder_custom_actions.size(),
1336+
.custom_actions = embedder_custom_actions.data(),
1337+
};
1338+
1339+
update_semantics_callback(&update, user_data);
1340+
};
1341+
}
1342+
1343+
// Create a callback to notify the embedder of semantic updates
1344+
// using the legacy embedder callbacks 'update_semantics_node_callback' and
1345+
// 'update_semantics_custom_action_callback'.
1346+
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1347+
CreateLegacyEmbedderSemanticsUpdateCallback(
1348+
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback,
1349+
FlutterUpdateSemanticsCustomActionCallback
1350+
update_semantics_custom_action_callback,
1351+
void* user_data) {
1352+
return [update_semantics_node_callback,
1353+
update_semantics_custom_action_callback,
1354+
user_data](const flutter::SemanticsNodeUpdates& nodes,
1355+
const flutter::CustomAccessibilityActionUpdates& actions) {
1356+
// First, queue all node and custom action updates.
1357+
if (update_semantics_node_callback != nullptr) {
1358+
for (const auto& value : nodes) {
1359+
const FlutterSemanticsNode embedder_node =
1360+
CreateEmbedderSemanticsNode(value.second);
1361+
update_semantics_node_callback(&embedder_node, user_data);
1362+
}
1363+
}
1364+
1365+
if (update_semantics_custom_action_callback != nullptr) {
1366+
for (const auto& value : actions) {
1367+
const FlutterSemanticsCustomAction embedder_action =
1368+
CreateEmbedderSemanticsCustomAction(value.second);
1369+
update_semantics_custom_action_callback(&embedder_action, user_data);
1370+
}
1371+
}
1372+
1373+
// Second, mark node and action batches completed now that all
1374+
// updates are queued.
1375+
if (update_semantics_node_callback != nullptr) {
1376+
const FlutterSemanticsNode batch_end_sentinel = {
1377+
sizeof(FlutterSemanticsNode),
1378+
kFlutterSemanticsNodeIdBatchEnd,
1379+
};
1380+
update_semantics_node_callback(&batch_end_sentinel, user_data);
1381+
}
1382+
1383+
if (update_semantics_custom_action_callback != nullptr) {
1384+
const FlutterSemanticsCustomAction batch_end_sentinel = {
1385+
sizeof(FlutterSemanticsCustomAction),
1386+
kFlutterSemanticsCustomActionIdBatchEnd,
1387+
};
1388+
update_semantics_custom_action_callback(&batch_end_sentinel, user_data);
1389+
}
1390+
};
1391+
}
1392+
1393+
// Creates a callback that receives semantic updates from the engine
1394+
// and notifies the embedder's callback(s). Returns null if the embedder
1395+
// did not register any callbacks.
1396+
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1397+
CreateEmbedderSemanticsUpdateCallback(const FlutterProjectArgs* args,
1398+
void* user_data) {
1399+
// The embedder can register the new callback, or the legacy callbacks, or
1400+
// nothing at all. Handle the case where the embedder registered the 'new'
1401+
// callback.
1402+
if (SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr) {
1403+
return CreateNewEmbedderSemanticsUpdateCallback(
1404+
args->update_semantics_callback, user_data);
1405+
}
1406+
1407+
// Handle the case where the embedder registered 'legacy' callbacks.
1408+
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr;
1409+
if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
1410+
update_semantics_node_callback = args->update_semantics_node_callback;
1411+
}
1412+
1413+
FlutterUpdateSemanticsCustomActionCallback
1414+
update_semantics_custom_action_callback = nullptr;
1415+
if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
1416+
nullptr) {
1417+
update_semantics_custom_action_callback =
1418+
args->update_semantics_custom_action_callback;
1419+
}
1420+
1421+
if (update_semantics_node_callback != nullptr ||
1422+
update_semantics_custom_action_callback != nullptr) {
1423+
return CreateLegacyEmbedderSemanticsUpdateCallback(
1424+
update_semantics_node_callback, update_semantics_custom_action_callback,
1425+
user_data);
1426+
}
1427+
1428+
// Handle the case where the embedder registered no callbacks.
1429+
return nullptr;
1430+
}
1431+
12561432
FlutterEngineResult FlutterEngineRun(size_t version,
12571433
const FlutterRendererConfig* config,
12581434
const FlutterProjectArgs* args,
@@ -1400,113 +1576,20 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
14001576
settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
14011577
}
14021578

1403-
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr;
1404-
if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
1405-
update_semantics_node_callback = args->update_semantics_node_callback;
1406-
}
1407-
1408-
FlutterUpdateSemanticsCustomActionCallback
1409-
update_semantics_custom_action_callback = nullptr;
1410-
if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
1411-
nullptr) {
1412-
update_semantics_custom_action_callback =
1413-
args->update_semantics_custom_action_callback;
1579+
if (args->update_semantics_callback != nullptr &&
1580+
(args->update_semantics_node_callback != nullptr ||
1581+
args->update_semantics_custom_action_callback != nullptr)) {
1582+
return LOG_EMBEDDER_ERROR(
1583+
kInvalidArguments,
1584+
"Multiple semantics update callbacks provided. "
1585+
"Embedders should provide either `update_semantics_callback` "
1586+
"or both `update_semantics_nodes_callback` and "
1587+
"`update_semantics_custom_actions_callback`.");
14141588
}
14151589

14161590
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1417-
update_semantics_callback = nullptr;
1418-
if (update_semantics_node_callback != nullptr ||
1419-
update_semantics_custom_action_callback != nullptr) {
1420-
update_semantics_callback =
1421-
[update_semantics_node_callback,
1422-
update_semantics_custom_action_callback,
1423-
user_data](const flutter::SemanticsNodeUpdates& update,
1424-
const flutter::CustomAccessibilityActionUpdates& actions) {
1425-
// First, queue all node and custom action updates.
1426-
if (update_semantics_node_callback != nullptr) {
1427-
for (const auto& value : update) {
1428-
const auto& node = value.second;
1429-
SkMatrix transform = node.transform.asM33();
1430-
FlutterTransformation flutter_transform{
1431-
transform.get(SkMatrix::kMScaleX),
1432-
transform.get(SkMatrix::kMSkewX),
1433-
transform.get(SkMatrix::kMTransX),
1434-
transform.get(SkMatrix::kMSkewY),
1435-
transform.get(SkMatrix::kMScaleY),
1436-
transform.get(SkMatrix::kMTransY),
1437-
transform.get(SkMatrix::kMPersp0),
1438-
transform.get(SkMatrix::kMPersp1),
1439-
transform.get(SkMatrix::kMPersp2)};
1440-
const FlutterSemanticsNode embedder_node{
1441-
sizeof(FlutterSemanticsNode),
1442-
node.id,
1443-
static_cast<FlutterSemanticsFlag>(node.flags),
1444-
static_cast<FlutterSemanticsAction>(node.actions),
1445-
node.textSelectionBase,
1446-
node.textSelectionExtent,
1447-
node.scrollChildren,
1448-
node.scrollIndex,
1449-
node.scrollPosition,
1450-
node.scrollExtentMax,
1451-
node.scrollExtentMin,
1452-
node.elevation,
1453-
node.thickness,
1454-
node.label.c_str(),
1455-
node.hint.c_str(),
1456-
node.value.c_str(),
1457-
node.increasedValue.c_str(),
1458-
node.decreasedValue.c_str(),
1459-
static_cast<FlutterTextDirection>(node.textDirection),
1460-
FlutterRect{node.rect.fLeft, node.rect.fTop, node.rect.fRight,
1461-
node.rect.fBottom},
1462-
flutter_transform,
1463-
node.childrenInTraversalOrder.size(),
1464-
node.childrenInTraversalOrder.data(),
1465-
node.childrenInHitTestOrder.data(),
1466-
node.customAccessibilityActions.size(),
1467-
node.customAccessibilityActions.data(),
1468-
node.platformViewId,
1469-
node.tooltip.c_str(),
1470-
};
1471-
update_semantics_node_callback(&embedder_node, user_data);
1472-
}
1473-
}
1474-
1475-
if (update_semantics_custom_action_callback != nullptr) {
1476-
for (const auto& value : actions) {
1477-
const auto& action = value.second;
1478-
const FlutterSemanticsCustomAction embedder_action = {
1479-
sizeof(FlutterSemanticsCustomAction),
1480-
action.id,
1481-
static_cast<FlutterSemanticsAction>(action.overrideId),
1482-
action.label.c_str(),
1483-
action.hint.c_str(),
1484-
};
1485-
update_semantics_custom_action_callback(&embedder_action,
1486-
user_data);
1487-
}
1488-
}
1489-
1490-
// Second, mark node and action batches completed now that all
1491-
// updates are queued.
1492-
if (update_semantics_node_callback != nullptr) {
1493-
const FlutterSemanticsNode batch_end_sentinel = {
1494-
sizeof(FlutterSemanticsNode),
1495-
kFlutterSemanticsNodeIdBatchEnd,
1496-
};
1497-
update_semantics_node_callback(&batch_end_sentinel, user_data);
1498-
}
1499-
1500-
if (update_semantics_custom_action_callback != nullptr) {
1501-
const FlutterSemanticsCustomAction batch_end_sentinel = {
1502-
sizeof(FlutterSemanticsCustomAction),
1503-
kFlutterSemanticsCustomActionIdBatchEnd,
1504-
};
1505-
update_semantics_custom_action_callback(&batch_end_sentinel,
1506-
user_data);
1507-
}
1508-
};
1509-
}
1591+
update_semantics_callback =
1592+
CreateEmbedderSemanticsUpdateCallback(args, user_data);
15101593

15111594
flutter::PlatformViewEmbedder::PlatformMessageResponseCallback
15121595
platform_message_response_callback = nullptr;

0 commit comments

Comments
 (0)