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

Commit 6597218

Browse files
authored
[Embedder API] Introduce new update semantics callback (#39807)
[Embedder API] Introduce new update semantics callback
1 parent 253076d commit 6597218

8 files changed

+691
-48
lines changed

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
@@ -54,6 +54,27 @@ class AccessibilityBridge
5454
/// To flush the pending updates, call the CommitUpdates().
5555
///
5656
/// @param[in] node A reference to the semantics node update.
57+
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode2& node);
58+
59+
//------------------------------------------------------------------------------
60+
/// @brief Adds a custom semantics action update to the pending semantics
61+
/// update. Calling this method alone will NOT update the
62+
/// semantics tree. To flush the pending updates, call the
63+
/// CommitUpdates().
64+
///
65+
/// @param[in] action A reference to the custom semantics action
66+
/// update.
67+
void AddFlutterSemanticsCustomActionUpdate(
68+
const FlutterSemanticsCustomAction2& action);
69+
70+
//------------------------------------------------------------------------------
71+
/// @brief Adds a semantics node update to the pending semantics update.
72+
/// Calling this method alone will NOT update the semantics tree.
73+
/// To flush the pending updates, call the CommitUpdates().
74+
///
75+
/// @param[in] node A reference to the semantics node update.
76+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
77+
// See: https://github.com/flutter/flutter/issues/121176
5778
void AddFlutterSemanticsNodeUpdate(const FlutterSemanticsNode& node);
5879

5980
//------------------------------------------------------------------------------
@@ -64,6 +85,9 @@ class AccessibilityBridge
6485
///
6586
/// @param[in] action A reference to the custom semantics action
6687
/// update.
88+
// TODO(loicsharma): Remove this as FlutterSemanticsCustomAction is
89+
// deprecated.
90+
// See: https://github.com/flutter/flutter/issues/121176
6791
void AddFlutterSemanticsCustomActionUpdate(
6892
const FlutterSemanticsCustomAction& action);
6993

@@ -244,8 +268,19 @@ class AccessibilityBridge
244268
void SetTooltipFromFlutterUpdate(ui::AXNodeData& node_data,
245269
const SemanticsNode& node);
246270
void SetTreeData(const SemanticsNode& node, ui::AXTreeUpdate& tree_update);
271+
SemanticsNode FromFlutterSemanticsNode(
272+
const FlutterSemanticsNode2& flutter_node);
273+
SemanticsCustomAction FromFlutterSemanticsCustomAction(
274+
const FlutterSemanticsCustomAction2& flutter_custom_action);
275+
276+
// TODO(loicsharma): Remove this as FlutterSemanticsNode is deprecated.
277+
// See: https://github.com/flutter/flutter/issues/121176
247278
SemanticsNode FromFlutterSemanticsNode(
248279
const FlutterSemanticsNode& flutter_node);
280+
281+
// TODO(loicsharma): Remove this as FlutterSemanticsCustomAction is
282+
// deprecated.
283+
// See: https://github.com/flutter/flutter/issues/121176
249284
SemanticsCustomAction FromFlutterSemanticsCustomAction(
250285
const FlutterSemanticsCustomAction& flutter_custom_action);
251286

shell/platform/embedder/embedder.cc

Lines changed: 135 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,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

Comments
 (0)