Skip to content

Commit

Permalink
Queue all semantic nodes & actions before completing batch (flutter#3…
Browse files Browse the repository at this point in the history
  • Loading branch information
loic-sharma committed Sep 6, 2022
1 parent 5e9e0e0 commit f8902a7
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 129 deletions.
6 changes: 3 additions & 3 deletions shell/platform/common/accessibility_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void AccessibilityBridge::CommitUpdates() {

for (size_t i = results.size(); i > 0; i--) {
for (SemanticsNode node : results[i - 1]) {
ConvertFluterUpdate(node, update);
ConvertFlutterUpdate(node, update);
}
}

Expand Down Expand Up @@ -191,8 +191,8 @@ void AccessibilityBridge::GetSubTreeList(SemanticsNode target,
}
}

void AccessibilityBridge::ConvertFluterUpdate(const SemanticsNode& node,
ui::AXTreeUpdate& tree_update) {
void AccessibilityBridge::ConvertFlutterUpdate(const SemanticsNode& node,
ui::AXTreeUpdate& tree_update) {
ui::AXNodeData node_data;
node_data.id = node.id;
SetRoleFromFlutterUpdate(node_data, node);
Expand Down
4 changes: 2 additions & 2 deletions shell/platform/common/accessibility_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ class AccessibilityBridge

void InitAXTree(const ui::AXTreeUpdate& initial_state);
void GetSubTreeList(SemanticsNode target, std::vector<SemanticsNode>& result);
void ConvertFluterUpdate(const SemanticsNode& node,
ui::AXTreeUpdate& tree_update);
void ConvertFlutterUpdate(const SemanticsNode& node,
ui::AXTreeUpdate& tree_update);
void SetRoleFromFlutterUpdate(ui::AXNodeData& node_data,
const SemanticsNode& node);
void SetStateFromFlutterUpdate(ui::AXNodeData& node_data,
Expand Down
173 changes: 97 additions & 76 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1245,88 +1245,110 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
}

flutter::PlatformViewEmbedder::UpdateSemanticsNodesCallback
update_semantics_nodes_callback = nullptr;
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr;
if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
update_semantics_nodes_callback =
[ptr = args->update_semantics_node_callback,
user_data](flutter::SemanticsNodeUpdates update) {
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<FlutterSemanticsFlag>(node.flags),
static_cast<FlutterSemanticsAction>(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<FlutterTextDirection>(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,
};
ptr(&embedder_node, user_data);
}
const FlutterSemanticsNode batch_end_sentinel = {
sizeof(FlutterSemanticsNode),
kFlutterSemanticsNodeIdBatchEnd,
};
ptr(&batch_end_sentinel, user_data);
};
update_semantics_node_callback = args->update_semantics_node_callback;
}

flutter::PlatformViewEmbedder::UpdateSemanticsCustomActionsCallback
update_semantics_custom_actions_callback = nullptr;
FlutterUpdateSemanticsCustomActionCallback
update_semantics_custom_action_callback = nullptr;
if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
nullptr) {
update_semantics_custom_actions_callback =
[ptr = args->update_semantics_custom_action_callback,
user_data](flutter::CustomAccessibilityActionUpdates actions) {
for (const auto& value : actions) {
const auto& action = value.second;
const FlutterSemanticsCustomAction embedder_action = {
update_semantics_custom_action_callback =
args->update_semantics_custom_action_callback;
}

flutter::PlatformViewEmbedder::UpdateSemanticsCallback
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](flutter::SemanticsNodeUpdates update,
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<FlutterSemanticsFlag>(node.flags),
static_cast<FlutterSemanticsAction>(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<FlutterTextDirection>(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,
};
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<FlutterSemanticsAction>(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),
action.id,
static_cast<FlutterSemanticsAction>(action.overrideId),
action.label.c_str(),
action.hint.c_str(),
kFlutterSemanticsCustomActionIdBatchEnd,
};
ptr(&embedder_action, user_data);
update_semantics_custom_action_callback(&batch_end_sentinel,
user_data);
}
const FlutterSemanticsCustomAction batch_end_sentinel = {
sizeof(FlutterSemanticsCustomAction),
kFlutterSemanticsCustomActionIdBatchEnd,
};
ptr(&batch_end_sentinel, user_data);
};
}

Expand Down Expand Up @@ -1421,8 +1443,7 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,

flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
{
update_semantics_nodes_callback, //
update_semantics_custom_actions_callback, //
update_semantics_callback, //
platform_message_response_callback, //
vsync_callback, //
compute_platform_resolved_locale_callback, //
Expand Down
10 changes: 3 additions & 7 deletions shell/platform/embedder/platform_view_embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,9 @@ PlatformViewEmbedder::~PlatformViewEmbedder() = default;
void PlatformViewEmbedder::UpdateSemantics(
flutter::SemanticsNodeUpdates update,
flutter::CustomAccessibilityActionUpdates actions) {
if (platform_dispatch_table_.update_semantics_nodes_callback != nullptr) {
platform_dispatch_table_.update_semantics_nodes_callback(std::move(update));
}
if (platform_dispatch_table_.update_semantics_custom_actions_callback !=
nullptr) {
platform_dispatch_table_.update_semantics_custom_actions_callback(
std::move(actions));
if (platform_dispatch_table_.update_semantics_callback != nullptr) {
platform_dispatch_table_.update_semantics_callback(std::move(update),
std::move(actions));
}
}

Expand Down
11 changes: 4 additions & 7 deletions shell/platform/embedder/platform_view_embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ namespace flutter {

class PlatformViewEmbedder final : public PlatformView {
public:
using UpdateSemanticsNodesCallback =
std::function<void(flutter::SemanticsNodeUpdates update)>;
using UpdateSemanticsCustomActionsCallback =
std::function<void(flutter::CustomAccessibilityActionUpdates actions)>;
using UpdateSemanticsCallback =
std::function<void(flutter::SemanticsNodeUpdates update,
flutter::CustomAccessibilityActionUpdates actions)>;
using PlatformMessageResponseCallback =
std::function<void(std::unique_ptr<PlatformMessage>)>;
using ComputePlatformResolvedLocaleCallback =
Expand All @@ -43,9 +42,7 @@ class PlatformViewEmbedder final : public PlatformView {
using OnPreEngineRestartCallback = std::function<void()>;

struct PlatformDispatchTable {
UpdateSemanticsNodesCallback update_semantics_nodes_callback; // optional
UpdateSemanticsCustomActionsCallback
update_semantics_custom_actions_callback; // optional
UpdateSemanticsCallback update_semantics_callback; // optional
PlatformMessageResponseCallback
platform_message_response_callback; // optional
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional
Expand Down
61 changes: 34 additions & 27 deletions shell/platform/embedder/tests/embedder_a11y_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,40 +120,47 @@ TEST_F(EmbedderA11yTest, A11yTreeIsConsistent) {
latch.Wait();

// Wait for UpdateSemantics callback on platform (current) thread.
int node_count = 0;
int node_batch_end_count = 0;
context.SetSemanticsNodeCallback(
[&node_count, &node_batch_end_count](const FlutterSemanticsNode* node) {
if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
++node_batch_end_count;
} else {
++node_count;
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_EQ(0, node->platform_view_id);
}
}
});
int action_batch_end_count = 0;

int node_count = 0;
context.SetSemanticsNodeCallback([&](const FlutterSemanticsNode* node) {
if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
++node_batch_end_count;
} else {
// Batches should be completed after all nodes are received.
ASSERT_EQ(0, node_batch_end_count);
ASSERT_EQ(0, action_batch_end_count);

++node_count;
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_EQ(0, node->platform_view_id);
}
}
});

int action_count = 0;
int action_batch_end_count = 0;
context.SetSemanticsCustomActionCallback(
[&action_count,
&action_batch_end_count](const FlutterSemanticsCustomAction* action) {
[&](const FlutterSemanticsCustomAction* action) {
if (action->id == kFlutterSemanticsCustomActionIdBatchEnd) {
++action_batch_end_count;
} else {
// Batches should be completed after all actions are received.
ASSERT_EQ(0, node_batch_end_count);
ASSERT_EQ(0, action_batch_end_count);

++action_count;
}
});
Expand Down
8 changes: 4 additions & 4 deletions shell/platform/embedder/tests/embedder_test_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ void EmbedderTestContext::AddNativeCallback(const char* name,
}

void EmbedderTestContext::SetSemanticsNodeCallback(
const SemanticsNodeCallback& update_semantics_node_callback) {
update_semantics_node_callback_ = update_semantics_node_callback;
SemanticsNodeCallback update_semantics_node_callback) {
update_semantics_node_callback_ = std::move(update_semantics_node_callback);
}

void EmbedderTestContext::SetSemanticsCustomActionCallback(
const SemanticsActionCallback& update_semantics_custom_action_callback) {
SemanticsActionCallback update_semantics_custom_action_callback) {
update_semantics_custom_action_callback_ =
update_semantics_custom_action_callback;
std::move(update_semantics_custom_action_callback);
}

void EmbedderTestContext::SetPlatformMessageCallback(
Expand Down
5 changes: 2 additions & 3 deletions shell/platform/embedder/tests/embedder_test_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ class EmbedderTestContext {

void AddNativeCallback(const char* name, Dart_NativeFunction function);

void SetSemanticsNodeCallback(
const SemanticsNodeCallback& update_semantics_node);
void SetSemanticsNodeCallback(SemanticsNodeCallback update_semantics_node);

void SetSemanticsCustomActionCallback(
const SemanticsActionCallback& semantics_custom_action);
SemanticsActionCallback semantics_custom_action);

void SetPlatformMessageCallback(
const std::function<void(const FlutterPlatformMessage*)>& callback);
Expand Down

0 comments on commit f8902a7

Please sign in to comment.