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

Commit ecbeecb

Browse files
committed
Add completion callback to Shell::AddView
1 parent f8c79f9 commit ecbeecb

File tree

10 files changed

+234
-36
lines changed

10 files changed

+234
-36
lines changed

lib/ui/window/platform_configuration.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,18 @@ void PlatformConfiguration::DidCreateIsolate() {
8383
Dart_GetField(library, tonic::ToDart("_reportTimings")));
8484
}
8585

86-
void PlatformConfiguration::AddView(int64_t view_id,
86+
bool PlatformConfiguration::AddView(int64_t view_id,
8787
const ViewportMetrics& view_metrics) {
8888
auto [view_iterator, insertion_happened] =
8989
metrics_.emplace(view_id, view_metrics);
90-
FML_DCHECK(insertion_happened);
90+
if (!insertion_happened) {
91+
FML_LOG(ERROR) << "View #" << view_id << " already exists.";
92+
return false;
93+
}
9194

9295
std::shared_ptr<tonic::DartState> dart_state = add_view_.dart_state().lock();
9396
if (!dart_state) {
94-
return;
97+
return false;
9598
}
9699
tonic::DartState::Scope scope(dart_state);
97100
tonic::CheckAndHandleError(tonic::DartInvoke(
@@ -119,6 +122,7 @@ void PlatformConfiguration::AddView(int64_t view_id,
119122
tonic::ToDart(view_metrics.physical_display_features_state),
120123
tonic::ToDart(view_metrics.display_id),
121124
}));
125+
return true;
122126
}
123127

124128
bool PlatformConfiguration::RemoveView(int64_t view_id) {

lib/ui/window/platform_configuration.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ class PlatformConfigurationClient {
263263
/// to and from the Dart code in Flutter's framework.
264264
///
265265
/// It handles communication between the engine and the framework,
266-
/// and owns the main window.
266+
/// and owns the views' metrics.
267267
///
268268
/// It communicates with the RuntimeController through the use of a
269269
/// PlatformConfigurationClient interface, which the
@@ -315,7 +315,9 @@ class PlatformConfiguration final {
315315
/// @param[in] view_id The ID of the new view.
316316
/// @param[in] viewport_metrics The initial viewport metrics for the view.
317317
///
318-
void AddView(int64_t view_id, const ViewportMetrics& view_metrics);
318+
/// @return Whether the view was added.
319+
///
320+
bool AddView(int64_t view_id, const ViewportMetrics& view_metrics);
319321

320322
//----------------------------------------------------------------------------
321323
/// @brief Notify the framework that a view is no longer available.

runtime/runtime_controller.cc

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,29 @@ bool RuntimeController::FlushRuntimeStateToIsolate() {
121121
FML_DCHECK(!has_flushed_runtime_state_)
122122
<< "FlushRuntimeStateToIsolate is called more than once somehow.";
123123
has_flushed_runtime_state_ = true;
124+
125+
auto platform_configuration = GetPlatformConfigurationIfAvailable();
126+
if (!platform_configuration) {
127+
return false;
128+
}
129+
124130
for (auto const& [view_id, viewport_metrics] :
125131
platform_data_.viewport_metrics_for_views) {
126-
if (!AddView(view_id, viewport_metrics)) {
132+
bool added = platform_configuration->AddView(view_id, viewport_metrics);
133+
134+
// Callbacks will have been already invoked if the engine was restarted.
135+
if (pending_add_view_callbacks_.find(view_id) !=
136+
pending_add_view_callbacks_.end()) {
137+
pending_add_view_callbacks_[view_id](added);
138+
pending_add_view_callbacks_.erase(view_id);
139+
}
140+
141+
if (!added) {
127142
return false;
128143
}
129144
}
145+
146+
FML_DCHECK(pending_add_view_callbacks_.empty());
130147
return SetLocales(platform_data_.locale_data) &&
131148
SetSemanticsEnabled(platform_data_.semantics_enabled) &&
132149
SetAccessibilityFeatures(
@@ -136,16 +153,22 @@ bool RuntimeController::FlushRuntimeStateToIsolate() {
136153
SetDisplays(platform_data_.displays);
137154
}
138155

139-
bool RuntimeController::AddView(int64_t view_id,
140-
const ViewportMetrics& view_metrics) {
156+
void RuntimeController::AddView(int64_t view_id,
157+
const ViewportMetrics& view_metrics,
158+
AddViewCallback callback) {
141159
platform_data_.viewport_metrics_for_views[view_id] = view_metrics;
142-
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
143-
platform_configuration->AddView(view_id, view_metrics);
144160

145-
return true;
161+
// If the Dart isolate is not running, |FlushRuntimeStateToIsolate| will
162+
// add the view when the isolate is started.
163+
auto* platform_configuration = GetPlatformConfigurationIfAvailable();
164+
if (!platform_configuration) {
165+
FML_DCHECK(has_flushed_runtime_state_ == false);
166+
pending_add_view_callbacks_[view_id] = std::move(callback);
167+
return;
146168
}
147169

148-
return false;
170+
bool added = platform_configuration->AddView(view_id, view_metrics);
171+
callback(added);
149172
}
150173

151174
bool RuntimeController::RemoveView(int64_t view_id) {

runtime/runtime_controller.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class Window;
5050
///
5151
class RuntimeController : public PlatformConfigurationClient {
5252
public:
53+
/// A callback that's invoked after this `RuntimeController` attempts to
54+
/// add a view to the Dart isolate. The `added` parameter is true if the add
55+
/// operation succeeds.
56+
using AddViewCallback = std::function<void(bool added)>;
57+
5358
//----------------------------------------------------------------------------
5459
/// @brief Creates a new instance of a runtime controller. This is
5560
/// usually only done by the engine instance associated with the
@@ -176,10 +181,17 @@ class RuntimeController : public PlatformConfigurationClient {
176181
/// including the implicit view. Adding a view that already exists
177182
/// triggers an assertion.
178183
///
184+
/// If the isolate is not running, the view will be saved and
185+
/// flushed to the isolate when it starts.
186+
///
179187
/// @param[in] view_id The ID of the new view.
180188
/// @param[in] viewport_metrics The initial viewport metrics for the view.
189+
/// @param[in] callback Callback that will be invoked after the add
190+
/// operation is attempted.
181191
///
182-
bool AddView(int64_t view_id, const ViewportMetrics& view_metrics);
192+
void AddView(int64_t view_id,
193+
const ViewportMetrics& view_metrics,
194+
AddViewCallback callback);
183195

184196
//----------------------------------------------------------------------------
185197
/// @brief Notify the isolate that a view is no longer available.
@@ -191,6 +203,9 @@ class RuntimeController : public PlatformConfigurationClient {
191203
///
192204
/// @param[in] view_id The ID of the view.
193205
///
206+
/// @return If the remove view operation was forwarded to the running
207+
/// isolate.
208+
///
194209
bool RemoveView(int64_t view_id);
195210

196211
//----------------------------------------------------------------------------
@@ -660,6 +675,11 @@ class RuntimeController : public PlatformConfigurationClient {
660675
std::shared_ptr<PlatformIsolateManager>(new PlatformIsolateManager());
661676
bool has_flushed_runtime_state_ = false;
662677

678+
// Callbacks when `AddView` was called before the Dart isolate is launched.
679+
//
680+
// These views will be added when `FlushRuntimeStateToIsolate` is called.
681+
std::unordered_map<int64_t, AddViewCallback> pending_add_view_callbacks_;
682+
663683
// Tracks the views that have been called `Render` during a frame.
664684
//
665685
// If all views that have been registered by `AddView` have been called

shell/common/engine.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,10 @@ tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
297297
return runtime_controller_->GetLastError();
298298
}
299299

300-
void Engine::AddView(int64_t view_id, const ViewportMetrics& view_metrics) {
301-
runtime_controller_->AddView(view_id, view_metrics);
300+
void Engine::AddView(int64_t view_id,
301+
const ViewportMetrics& view_metrics,
302+
std::function<void(bool added)> callback) {
303+
runtime_controller_->AddView(view_id, view_metrics, std::move(callback));
302304
}
303305

304306
bool Engine::RemoveView(int64_t view_id) {

shell/common/engine.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,12 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
721721
///
722722
/// @param[in] view_id The ID of the new view.
723723
/// @param[in] viewport_metrics The initial viewport metrics for the view.
724+
/// @param[in] callback Callback that will be invoked once
725+
/// the engine attempts to add the view.
724726
///
725-
void AddView(int64_t view_id, const ViewportMetrics& view_metrics);
727+
void AddView(int64_t view_id,
728+
const ViewportMetrics& view_metrics,
729+
std::function<void(bool added)> callback);
726730

727731
//----------------------------------------------------------------------------
728732
/// @brief Notify the Flutter application that a view is no

shell/common/engine_animator_unittests.cc

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,10 @@ TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders) {
313313
engine_context->Run(std::move(configuration));
314314

315315
engine_context->EngineTaskSync([](Engine& engine) {
316-
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0});
317-
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0});
316+
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
317+
[](bool added) { ASSERT_TRUE(added); });
318+
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
319+
[](bool added) { ASSERT_TRUE(added); });
318320
});
319321

320322
native_latch.Wait();
@@ -368,8 +370,10 @@ TEST_F(EngineAnimatorTest, IgnoresOutOfFrameRenders) {
368370
std::move(animator));
369371

370372
engine_context->EngineTaskSync([](Engine& engine) {
371-
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0});
372-
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0});
373+
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
374+
[](bool added) { ASSERT_TRUE(added); });
375+
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
376+
[](bool added) { ASSERT_TRUE(added); });
373377
});
374378

375379
auto configuration = RunConfiguration::InferFromSettings(settings_);
@@ -444,7 +448,8 @@ TEST_F(EngineAnimatorTest, IgnoresDuplicateRenders) {
444448
std::move(animator));
445449

446450
engine_context->EngineTaskSync([](Engine& engine) {
447-
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1, 10, 10, 22, 0});
451+
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1, 10, 10, 22, 0},
452+
[](bool added) { ASSERT_TRUE(added); });
448453
});
449454

450455
auto configuration = RunConfiguration::InferFromSettings(settings_);
@@ -504,7 +509,8 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitsImplicitViewBeforeDrawFrameEnds) {
504509
std::move(animator));
505510

506511
engine_context->EngineTaskSync([](Engine& engine) {
507-
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0});
512+
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0},
513+
[](bool added) { ASSERT_TRUE(added); });
508514
});
509515

510516
auto configuration = RunConfiguration::InferFromSettings(settings_);
@@ -568,7 +574,8 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitWarmUpImplicitView) {
568574
engine.ScheduleFrame(true);
569575
// Add the implicit view so that the engine recognizes it and that its
570576
// metrics is not empty.
571-
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0});
577+
engine.AddView(kFlutterImplicitViewId, ViewportMetrics{1.0, 10, 10, 1, 0},
578+
[](bool added) { ASSERT_TRUE(added); });
572579
});
573580
continuation_ready_latch.Wait();
574581

@@ -634,9 +641,12 @@ TEST_F(EngineAnimatorTest, AnimatorSubmitPartialViewsForWarmUp) {
634641
// Schedule a frame to make the animator create a continuation.
635642
engine.ScheduleFrame(true);
636643
// Add multiple views.
637-
engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0});
638-
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0});
639-
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0});
644+
engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0},
645+
[](bool added) { ASSERT_TRUE(added); });
646+
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0},
647+
[](bool added) { ASSERT_TRUE(added); });
648+
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0},
649+
[](bool added) { ASSERT_TRUE(added); });
640650
});
641651

642652
continuation_ready_latch.Wait();

shell/common/shell.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,11 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
754754
weak_rasterizer_ = rasterizer_->GetWeakPtr();
755755
weak_platform_view_ = platform_view_->GetWeakPtr();
756756

757-
engine_->AddView(kFlutterImplicitViewId, ViewportMetrics{});
757+
// Add the implicit view with empty metrics.
758+
engine_->AddView(kFlutterImplicitViewId, ViewportMetrics{}, [](bool added) {
759+
FML_DCHECK(added) << "Failed to add the implicit view";
760+
});
761+
758762
// Setup the time-consuming default font manager right after engine created.
759763
if (!settings_.prefetched_default_font_manager) {
760764
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(),
@@ -2102,7 +2106,9 @@ bool Shell::OnServiceProtocolReloadAssetFonts(
21022106
return true;
21032107
}
21042108

2105-
void Shell::AddView(int64_t view_id, const ViewportMetrics& viewport_metrics) {
2109+
void Shell::AddView(int64_t view_id,
2110+
const ViewportMetrics& viewport_metrics,
2111+
AddViewCallback callback) {
21062112
TRACE_EVENT0("flutter", "Shell::AddView");
21072113
FML_DCHECK(is_set_up_);
21082114
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
@@ -2112,10 +2118,11 @@ void Shell::AddView(int64_t view_id, const ViewportMetrics& viewport_metrics) {
21122118

21132119
task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr(), //
21142120
viewport_metrics, //
2115-
view_id //
2121+
view_id, //
2122+
callback = std::move(callback) //
21162123
] {
21172124
if (engine) {
2118-
engine->AddView(view_id, viewport_metrics);
2125+
engine->AddView(view_id, viewport_metrics, callback);
21192126
}
21202127
});
21212128
}

shell/common/shell.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class Shell final : public PlatformView::Delegate,
133133
const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch,
134134
impeller::RuntimeStageBackend runtime_stage_type)>
135135
EngineCreateCallback;
136+
using AddViewCallback = std::function<void(bool added)>;
136137
using RemoveViewCallback = std::function<void(bool removed)>;
137138

138139
//----------------------------------------------------------------------------
@@ -317,8 +318,12 @@ class Shell final : public PlatformView::Delegate,
317318
///
318319
/// @param[in] view_id The view ID of the new view.
319320
/// @param[in] viewport_metrics The initial viewport metrics for the view.
321+
/// @param[in] callback The callback that's invoked once the engine
322+
/// has attempted to add the view.
320323
///
321-
void AddView(int64_t view_id, const ViewportMetrics& viewport_metrics);
324+
void AddView(int64_t view_id,
325+
const ViewportMetrics& viewport_metrics,
326+
AddViewCallback callback);
322327

323328
/// @brief Deallocates resources for a non-implicit view.
324329
///

0 commit comments

Comments
 (0)