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

Commit 4d30835

Browse files
committed
[Embedder API] Introduce new update semantics callback
1 parent 96f0f5a commit 4d30835

8 files changed

Lines changed: 674 additions & 36 deletions

File tree

shell/platform/common/accessibility_bridge.cc

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,26 @@ AccessibilityBridge::~AccessibilityBridge() {
3636
tree_->RemoveObserver(static_cast<ui::AXTreeObserver*>(this));
3737
}
3838

39+
void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(
40+
const FlutterSemanticsNode2* node) {
41+
pending_semantics_node_updates_[node->id] = FromFlutterSemanticsNode(node);
42+
}
43+
44+
void AccessibilityBridge::AddFlutterSemanticsCustomActionUpdate(
45+
const FlutterSemanticsCustomAction2* action) {
46+
pending_semantics_custom_action_updates_[action->id] =
47+
FromFlutterSemanticsCustomAction(action);
48+
}
49+
50+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
51+
// See: https://github.com/flutter/flutter/issues/121176
3952
void AccessibilityBridge::AddFlutterSemanticsNodeUpdate(
4053
const FlutterSemanticsNode* node) {
4154
pending_semantics_node_updates_[node->id] = FromFlutterSemanticsNode(node);
4255
}
4356

57+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
58+
// See: https://github.com/flutter/flutter/issues/121176
4459
void AccessibilityBridge::AddFlutterSemanticsCustomActionUpdate(
4560
const FlutterSemanticsCustomAction* action) {
4661
pending_semantics_custom_action_updates_[action->id] =
@@ -576,6 +591,74 @@ void AccessibilityBridge::SetTreeData(const SemanticsNode& node,
576591
}
577592
}
578593

594+
AccessibilityBridge::SemanticsNode
595+
AccessibilityBridge::FromFlutterSemanticsNode(
596+
const FlutterSemanticsNode2* flutter_node) {
597+
SemanticsNode result;
598+
result.id = flutter_node->id;
599+
result.flags = flutter_node->flags;
600+
result.actions = flutter_node->actions;
601+
result.text_selection_base = flutter_node->text_selection_base;
602+
result.text_selection_extent = flutter_node->text_selection_extent;
603+
result.scroll_child_count = flutter_node->scroll_child_count;
604+
result.scroll_index = flutter_node->scroll_index;
605+
result.scroll_position = flutter_node->scroll_position;
606+
result.scroll_extent_max = flutter_node->scroll_extent_max;
607+
result.scroll_extent_min = flutter_node->scroll_extent_min;
608+
result.elevation = flutter_node->elevation;
609+
result.thickness = flutter_node->thickness;
610+
if (flutter_node->label) {
611+
result.label = std::string(flutter_node->label);
612+
}
613+
if (flutter_node->hint) {
614+
result.hint = std::string(flutter_node->hint);
615+
}
616+
if (flutter_node->value) {
617+
result.value = std::string(flutter_node->value);
618+
}
619+
if (flutter_node->increased_value) {
620+
result.increased_value = std::string(flutter_node->increased_value);
621+
}
622+
if (flutter_node->decreased_value) {
623+
result.decreased_value = std::string(flutter_node->decreased_value);
624+
}
625+
if (flutter_node->tooltip) {
626+
result.tooltip = std::string(flutter_node->tooltip);
627+
}
628+
result.text_direction = flutter_node->text_direction;
629+
result.rect = flutter_node->rect;
630+
result.transform = flutter_node->transform;
631+
if (flutter_node->child_count > 0) {
632+
result.children_in_traversal_order = std::vector<int32_t>(
633+
flutter_node->children_in_traversal_order,
634+
flutter_node->children_in_traversal_order + flutter_node->child_count);
635+
}
636+
if (flutter_node->custom_accessibility_actions_count > 0) {
637+
result.custom_accessibility_actions = std::vector<int32_t>(
638+
flutter_node->custom_accessibility_actions,
639+
flutter_node->custom_accessibility_actions +
640+
flutter_node->custom_accessibility_actions_count);
641+
}
642+
return result;
643+
}
644+
645+
AccessibilityBridge::SemanticsCustomAction
646+
AccessibilityBridge::FromFlutterSemanticsCustomAction(
647+
const FlutterSemanticsCustomAction2* flutter_custom_action) {
648+
SemanticsCustomAction result;
649+
result.id = flutter_custom_action->id;
650+
result.override_action = flutter_custom_action->override_action;
651+
if (flutter_custom_action->label) {
652+
result.label = std::string(flutter_custom_action->label);
653+
}
654+
if (flutter_custom_action->hint) {
655+
result.hint = std::string(flutter_custom_action->hint);
656+
}
657+
return result;
658+
}
659+
660+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
661+
// See: https://github.com/flutter/flutter/issues/121176
579662
AccessibilityBridge::SemanticsNode
580663
AccessibilityBridge::FromFlutterSemanticsNode(
581664
const FlutterSemanticsNode* flutter_node) {
@@ -627,6 +710,9 @@ AccessibilityBridge::FromFlutterSemanticsNode(
627710
return result;
628711
}
629712

713+
// TODO(loicsharma): Remove this as FlutterSemanticsCustomAction is
714+
// deprecated.
715+
// See: https://github.com/flutter/flutter/issues/121176
630716
AccessibilityBridge::SemanticsCustomAction
631717
AccessibilityBridge::FromFlutterSemanticsCustomAction(
632718
const FlutterSemanticsCustomAction* flutter_custom_action) {

shell/platform/common/accessibility_bridge.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,27 @@ class AccessibilityBridge
6161
/// To flush the pending updates, call the CommitUpdates().
6262
///
6363
/// @param[in] node A pointer to the semantics node update.
64+
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2* node);
65+
66+
//------------------------------------------------------------------------------
67+
/// @brief Adds a custom semantics action update to the pending semantics
68+
/// update. Calling this method alone will NOT update the
69+
/// semantics tree. To flush the pending updates, call the
70+
/// CommitUpdates().
71+
///
72+
/// @param[in] action A pointer to the custom semantics action
73+
/// update.
74+
void AddFlutterSemanticsCustomActionUpdate(
75+
const FlutterSemanticsCustomAction2* action);
76+
77+
//------------------------------------------------------------------------------
78+
/// @brief Adds a semantics node update to the pending semantics update.
79+
/// Calling this method alone will NOT update the semantics tree.
80+
/// To flush the pending updates, call the CommitUpdates().
81+
///
82+
/// @param[in] node A pointer to the semantics node update.
83+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
84+
// See: https://github.com/flutter/flutter/issues/121176
6485
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode* node);
6586

6687
//------------------------------------------------------------------------------
@@ -71,6 +92,9 @@ class AccessibilityBridge
7192
///
7293
/// @param[in] action A pointer to the custom semantics action
7394
/// update.
95+
// TODO(loicsharma): Remove this as FlutterSemanticsCustomAction is
96+
// deprecated.
97+
// See: https://github.com/flutter/flutter/issues/121176
7498
void AddFlutterSemanticsCustomActionUpdate(
7599
const FlutterSemanticsCustomAction* action);
76100

@@ -251,8 +275,19 @@ class AccessibilityBridge
251275
void SetTooltipFromFlutterUpdate(ui::AXNodeData& node_data,
252276
const SemanticsNode& node);
253277
void SetTreeData(const SemanticsNode& node, ui::AXTreeUpdate& tree_update);
278+
SemanticsNode FromFlutterSemanticsNode(
279+
const FlutterSemanticsNode2* flutter_node);
280+
SemanticsCustomAction FromFlutterSemanticsCustomAction(
281+
const FlutterSemanticsCustomAction2* flutter_custom_action);
282+
283+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
284+
// See: https://github.com/flutter/flutter/issues/121176
254285
SemanticsNode FromFlutterSemanticsNode(
255286
const FlutterSemanticsNode* flutter_node);
287+
288+
// TODO(loicsharma): Remove this as FlutterSemanticsCustomAction is
289+
// deprecated.
290+
// See: https://github.com/flutter/flutter/issues/121176
256291
SemanticsCustomAction FromFlutterSemanticsCustomAction(
257292
const FlutterSemanticsCustomAction* flutter_custom_action);
258293

shell/platform/embedder/embedder.cc

Lines changed: 131 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
13101353
FlutterSemanticsCustomAction 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'.
13271382
flutter::PlatformViewEmbedder::UpdateSemanticsCallback
13281383
CreateNewEmbedderSemanticsUpdateCallback(
13291384
FlutterUpdateSemanticsCallback update_semantics_callback,
@@ -1354,6 +1409,54 @@ 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+
for (const auto& value : nodes) {
1423+
embedder_nodes.push_back(CreateEmbedderSemanticsNode2(value.second));
1424+
}
1425+
1426+
std::vector<FlutterSemanticsCustomAction2> embedder_custom_actions;
1427+
for (const auto& value : actions) {
1428+
embedder_custom_actions.push_back(
1429+
CreateEmbedderSemanticsCustomAction2(value.second));
1430+
}
1431+
1432+
// Provide the embedder an array of pointers to maintain full forward and
1433+
// backward compatibility even if new members are added to semantic structs.
1434+
std::vector<FlutterSemanticsNode2*> embedder_node_pointers;
1435+
std::vector<FlutterSemanticsCustomAction2*> embedder_custom_action_pointers;
1436+
1437+
embedder_node_pointers.reserve(embedder_nodes.size());
1438+
embedder_custom_action_pointers.reserve(embedder_custom_actions.size());
1439+
1440+
for (auto& node : embedder_nodes) {
1441+
embedder_node_pointers.push_back(&node);
1442+
}
1443+
1444+
for (auto& action : embedder_custom_actions) {
1445+
embedder_custom_action_pointers.push_back(&action);
1446+
}
1447+
1448+
FlutterSemanticsUpdate2 update{
1449+
.struct_size = sizeof(FlutterSemanticsUpdate2),
1450+
.nodes_count = embedder_node_pointers.size(),
1451+
.nodes = embedder_node_pointers.data(),
1452+
.custom_actions_count = embedder_custom_action_pointers.size(),
1453+
.custom_actions = embedder_custom_action_pointers.data(),
1454+
};
1455+
1456+
update_semantics_callback(&update, user_data);
1457+
};
1458+
}
1459+
13571460
// Create a callback to notify the embedder of semantic updates
13581461
// using the legacy embedder callbacks 'update_semantics_node_callback' and
13591462
// 'update_semantics_custom_action_callback'.
@@ -1413,6 +1516,11 @@ CreateEmbedderSemanticsUpdateCallback(const FlutterProjectArgs* args,
14131516
// The embedder can register the new callback, or the legacy callbacks, or
14141517
// nothing at all. Handle the case where the embedder registered the 'new'
14151518
// callback.
1519+
if (SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr) {
1520+
return CreateNewEmbedderSemanticsUpdateCallback2(
1521+
args->update_semantics_callback2, user_data);
1522+
}
1523+
14161524
if (SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr) {
14171525
return CreateNewEmbedderSemanticsUpdateCallback(
14181526
args->update_semantics_callback, user_data);
@@ -1590,15 +1698,27 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
15901698
settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
15911699
}
15921700

1593-
if (args->update_semantics_callback != nullptr &&
1594-
(args->update_semantics_node_callback != nullptr ||
1595-
args->update_semantics_custom_action_callback != nullptr)) {
1701+
bool has_update_semantics_2_callback =
1702+
SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr;
1703+
bool has_update_semantics_callback =
1704+
SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr;
1705+
bool has_legacy_update_semantics_callback =
1706+
SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr ||
1707+
SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
1708+
nullptr;
1709+
1710+
int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0) +
1711+
(has_update_semantics_callback ? 1 : 0) +
1712+
(has_legacy_update_semantics_callback ? 1 : 0);
1713+
1714+
if (semantic_callback_count > 1) {
15961715
return LOG_EMBEDDER_ERROR(
15971716
kInvalidArguments,
15981717
"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`.");
1718+
"Embedders should provide either `update_semantics_callback2`, "
1719+
"`update_semantics_callback`, or both "
1720+
"`update_semantics_node_callback` and "
1721+
"`update_semantics_custom_action_callback`.");
16021722
}
16031723

16041724
flutter::PlatformViewEmbedder::UpdateSemanticsCallback

0 commit comments

Comments
 (0)