Provide batching for semantics updates (flutter/engine#7988)

Some embedders prefer to minimise the number of semantics node/custom
action updates sent back to the host platform -- for example due to
expensive serialisation mechanisms, etc.

This patch provides a 'batch end' signal that provides embedders with an
indication of when a self-consistent set of semantics node or custom action
updates have been sent.

We overload the node/action ID with information that conveys a batch end
by using an ID (-1) that is never allotted to semantics nodes by the
framework.
This commit is contained in:
Chris Bracken 2019-02-27 12:12:45 -08:00 committed by GitHub
parent a2f03be41a
commit 0d1a8035df
3 changed files with 49 additions and 7 deletions

View File

@ -448,6 +448,11 @@ FlutterEngineResult FlutterEngineRun(size_t version,
};
ptr(&embedder_node, user_data);
}
const FlutterSemanticsNode batch_end_sentinel = {
sizeof(FlutterSemanticsNode),
kFlutterSemanticsNodeIdBatchEnd,
};
ptr(&batch_end_sentinel, user_data);
};
}
@ -469,6 +474,11 @@ FlutterEngineResult FlutterEngineRun(size_t version,
};
ptr(&embedder_action, user_data);
}
const FlutterSemanticsCustomAction batch_end_sentinel = {
sizeof(FlutterSemanticsCustomAction),
kFlutterSemanticsCustomActionIdBatchEnd,
};
ptr(&batch_end_sentinel, user_data);
};
}

View File

@ -319,6 +319,10 @@ typedef struct {
double bottom;
} FlutterRect;
// |FlutterSemanticsNode| ID used as a sentinel to signal the end of a batch of
// semantics node updates.
const int32_t kFlutterSemanticsNodeIdBatchEnd = -1;
// A node that represents some semantic data.
//
// The semantics tree is maintained during the semantics phase of the pipeline
@ -386,6 +390,10 @@ typedef struct {
const int32_t* custom_accessibility_actions;
} FlutterSemanticsNode;
// |FlutterSemanticsCustomAction| ID used as a sentinel to signal the end of a
// batch of semantics custom action updates.
const int32_t kFlutterSemanticsCustomActionIdBatchEnd = -1;
// A custom semantics action, or action override.
//
// Custom actions can be registered by applications in order to provide
@ -496,14 +504,23 @@ typedef struct {
// immediately after the root isolate has been created and marked runnable.
VoidCallback root_isolate_create_callback;
// The callback invoked by the engine in order to give the embedder the
// chance to respond to semantics node updates from the Dart application. The
// callback will be invoked on the thread on which the |FlutterEngineRun|
// chance to respond to semantics node updates from the Dart application.
// Semantics node updates are sent in batches terminated by a 'batch end'
// callback that is passed a sentinel |FlutterSemanticsNode| whose |id| field
// has the value |kFlutterSemanticsNodeIdBatchEnd|.
//
// The callback will be invoked on the thread on which the |FlutterEngineRun|
// call is made.
FlutterUpdateSemanticsNodeCallback update_semantics_node_callback;
// The callback invoked by the engine in order to give the embedder the
// chance to respond to updates to semantics custom actions from the Dart
// application. The callback will be invoked on the thread on which the
// |FlutterEngineRun| call is made.
// application. Custom action updates are sent in batches terminated by a
// 'batch end' callback that is passed a sentinel
// |FlutterSemanticsCustomAction| whose |id| field has the value
// |kFlutterSemanticsCustomActionIdBatchEnd|.
//
// The callback will be invoked on the thread on which the |FlutterEngineRun|
// call is made.
FlutterUpdateSemanticsCustomActionCallback
update_semantics_custom_action_callback;
// Path to a directory used to store data that is cached across runs of a

View File

@ -151,17 +151,32 @@ TEST(EmbedderTest, CanLaunchAndShutdownWithValidProjectArgs) {
// Wait for UpdateSemantics callback on platform (current) thread.
int node_count = 0;
int node_batch_end_count = 0;
test_data.on_semantics_update =
[&node_count](const FlutterSemanticsNode* node) { ++node_count; };
[&node_count, &node_batch_end_count](const FlutterSemanticsNode* node) {
if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
++node_batch_end_count;
} else {
++node_count;
}
};
int action_count = 0;
int action_batch_end_count = 0;
test_data.on_custom_action_update =
[&action_count](const FlutterSemanticsCustomAction* action) {
++action_count;
[&action_count,
&action_batch_end_count](const FlutterSemanticsCustomAction* action) {
if (action->id == kFlutterSemanticsCustomActionIdBatchEnd) {
++action_batch_end_count;
} else {
++action_count;
}
};
g_latch.Wait();
fml::MessageLoop::GetCurrent().RunExpiredTasksNow();
ASSERT_EQ(4, node_count);
ASSERT_EQ(1, node_batch_end_count);
ASSERT_EQ(1, action_count);
ASSERT_EQ(1, action_batch_end_count);
// Dispatch a tap to semantics node 42. Wait for NotifySemanticsAction.
g_test_data_callback = [](Dart_NativeArguments args) {