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

Commit 12f2abc

Browse files
authored
[Embedder API] Remove view (#51400)
Adds `FlutterEngineRemoveView` to the embedder API. This will be used to destroy a view. The embedder API does not allow embedders to create multiple views yet. Design doc: https://flutter.dev/go/multi-view-embedder-apis Part of flutter/flutter#144806 Part of flutter/flutter#142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 016206d commit 12f2abc

File tree

11 files changed

+177
-19
lines changed

11 files changed

+177
-19
lines changed

lib/ui/window/platform_configuration.cc

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,26 +121,28 @@ void PlatformConfiguration::AddView(int64_t view_id,
121121
}));
122122
}
123123

124-
void PlatformConfiguration::RemoveView(int64_t view_id) {
124+
bool PlatformConfiguration::RemoveView(int64_t view_id) {
125125
if (view_id == kFlutterImplicitViewId) {
126-
FML_LOG(ERROR) << "The implicit view #" << view_id << " cannot be removed.";
127-
FML_DCHECK(false);
128-
return;
126+
FML_LOG(FATAL) << "The implicit view #" << view_id << " cannot be removed.";
127+
return false;
129128
}
130129
size_t erased_elements = metrics_.erase(view_id);
131-
FML_DCHECK(erased_elements != 0) << "View #" << view_id << " doesn't exist.";
132-
(void)erased_elements; // Suppress unused variable warning
130+
if (erased_elements == 0) {
131+
FML_LOG(ERROR) << "View #" << view_id << " doesn't exist.";
132+
return false;
133+
}
133134

134135
std::shared_ptr<tonic::DartState> dart_state =
135136
remove_view_.dart_state().lock();
136137
if (!dart_state) {
137-
return;
138+
return false;
138139
}
139140
tonic::DartState::Scope scope(dart_state);
140141
tonic::CheckAndHandleError(
141142
tonic::DartInvoke(remove_view_.Get(), {
142143
tonic::ToDart(view_id),
143144
}));
145+
return true;
144146
}
145147

146148
bool PlatformConfiguration::UpdateViewMetrics(

lib/ui/window/platform_configuration.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ class PlatformConfiguration final {
327327
///
328328
/// @param[in] view_id The ID of the view.
329329
///
330-
void RemoveView(int64_t view_id);
330+
/// @return Whether the view was removed.
331+
///
332+
bool RemoveView(int64_t view_id);
331333

332334
//----------------------------------------------------------------------------
333335
/// @brief Update the view metrics for the specified view.

runtime/runtime_controller.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@ bool RuntimeController::AddView(int64_t view_id,
151151
bool RuntimeController::RemoveView(int64_t view_id) {
152152
platform_data_.viewport_metrics_for_views.erase(view_id);
153153
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
154-
platform_configuration->RemoveView(view_id);
155-
return true;
154+
return platform_configuration->RemoveView(view_id);
156155
}
157156

158157
return false;

shell/common/engine.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ void Engine::AddView(int64_t view_id, const ViewportMetrics& view_metrics) {
301301
runtime_controller_->AddView(view_id, view_metrics);
302302
}
303303

304-
void Engine::RemoveView(int64_t view_id) {
305-
runtime_controller_->RemoveView(view_id);
304+
bool Engine::RemoveView(int64_t view_id) {
305+
return runtime_controller_->RemoveView(view_id);
306306
}
307307

308308
void Engine::SetViewportMetrics(int64_t view_id,

shell/common/engine.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,9 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
735735
///
736736
/// @param[in] view_id The ID of the view.
737737
///
738-
void RemoveView(int64_t view_id);
738+
/// @return Whether the view was removed.
739+
///
740+
bool RemoveView(int64_t view_id);
739741

740742
//----------------------------------------------------------------------------
741743
/// @brief Updates the viewport metrics for a view. The viewport metrics

shell/common/shell.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,7 +2120,7 @@ void Shell::AddView(int64_t view_id, const ViewportMetrics& viewport_metrics) {
21202120
});
21212121
}
21222122

2123-
void Shell::RemoveView(int64_t view_id) {
2123+
void Shell::RemoveView(int64_t view_id, RemoveViewCallback callback) {
21242124
TRACE_EVENT0("flutter", "Shell::RemoveView");
21252125
FML_DCHECK(is_set_up_);
21262126
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
@@ -2133,10 +2133,12 @@ void Shell::RemoveView(int64_t view_id) {
21332133
[&task_runners = task_runners_, //
21342134
engine = engine_->GetWeakPtr(), //
21352135
rasterizer = rasterizer_->GetWeakPtr(), //
2136-
view_id //
2136+
view_id, //
2137+
callback = std::move(callback) //
21372138
] {
21382139
if (engine) {
2139-
engine->RemoveView(view_id);
2140+
bool removed = engine->RemoveView(view_id);
2141+
callback(removed);
21402142
}
21412143
// Don't wait for the raster task here, which only cleans up memory and
21422144
// does not affect functionality. Make sure it is done after Dart

shell/common/shell.h

Lines changed: 4 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 RemoveViewCallback = std::function<void(bool removed)>;
136137

137138
//----------------------------------------------------------------------------
138139
/// @brief Creates a shell instance using the provided settings. The
@@ -330,8 +331,10 @@ class Shell final : public PlatformView::Delegate,
330331
/// `kFlutterImplicitViewId` triggers an assertion.
331332
///
332333
/// @param[in] view_id The view ID of the view to be removed.
334+
/// @param[in] callback The callback that's invoked once the engine has
335+
/// attempted to remove the view.
333336
///
334-
void RemoveView(int64_t view_id);
337+
void RemoveView(int64_t view_id, RemoveViewCallback callback);
335338

336339
//----------------------------------------------------------------------------
337340
/// @brief Captures a screenshot and optionally Base64 encodes the data

shell/common/shell_unittests.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,8 +4511,9 @@ TEST_F(ShellTest, ShellCanAddViewOrRemoveView) {
45114511
ASSERT_EQ(viewIds.size(), 2u);
45124512
ASSERT_EQ(viewIds[1], 2ll);
45134513

4514-
PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(),
4515-
[&shell] { shell->RemoveView(2); });
4514+
PostSync(shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell] {
4515+
shell->RemoveView(2, [](bool removed) { ASSERT_TRUE(removed); });
4516+
});
45164517
reportLatch.Wait();
45174518
ASSERT_TRUE(hasImplicitView);
45184519
ASSERT_EQ(viewIds.size(), 1u);

shell/platform/embedder/embedder.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,6 +2138,44 @@ FlutterEngineResult FlutterEngineRunInitialized(
21382138
return kSuccess;
21392139
}
21402140

2141+
FLUTTER_EXPORT
2142+
FlutterEngineResult FlutterEngineRemoveView(FLUTTER_API_SYMBOL(FlutterEngine)
2143+
engine,
2144+
const FlutterRemoveViewInfo* info) {
2145+
if (!engine) {
2146+
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2147+
}
2148+
if (!info || !info->remove_view_callback) {
2149+
return LOG_EMBEDDER_ERROR(kInvalidArguments,
2150+
"Remove view info handle was invalid.");
2151+
}
2152+
2153+
if (info->view_id == kFlutterImplicitViewId) {
2154+
return LOG_EMBEDDER_ERROR(
2155+
kInvalidArguments,
2156+
"Remove view info was invalid. The implicit view cannot be removed.");
2157+
}
2158+
2159+
// The engine must be running to remove a view.
2160+
auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
2161+
if (!embedder_engine->IsValid()) {
2162+
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2163+
}
2164+
2165+
flutter::Shell::RemoveViewCallback callback =
2166+
[c_callback = info->remove_view_callback,
2167+
user_data = info->user_data](bool removed) {
2168+
FlutterRemoveViewResult result = {};
2169+
result.struct_size = sizeof(FlutterRemoveViewResult);
2170+
result.removed = removed;
2171+
result.user_data = user_data;
2172+
c_callback(&result);
2173+
};
2174+
2175+
embedder_engine->GetShell().RemoveView(info->view_id, callback);
2176+
return kSuccess;
2177+
}
2178+
21412179
FLUTTER_EXPORT
21422180
FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine)
21432181
engine) {

shell/platform/embedder/embedder.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,53 @@ typedef struct {
831831
};
832832
} FlutterRendererConfig;
833833

834+
typedef struct {
835+
/// The size of this struct.
836+
/// Must be sizeof(FlutterRemoveViewResult).
837+
size_t struct_size;
838+
839+
/// True if the remove view operation succeeded.
840+
bool removed;
841+
842+
/// The |FlutterRemoveViewInfo.user_data|.
843+
void* user_data;
844+
} FlutterRemoveViewResult;
845+
846+
/// The callback invoked by the engine when the engine has attempted to remove
847+
/// a view.
848+
///
849+
/// The |FlutterRemoveViewResult| will be deallocated once the callback returns.
850+
typedef void (*FlutterRemoveViewCallback)(
851+
const FlutterRemoveViewResult* /* result */);
852+
853+
typedef struct {
854+
/// The size of this struct.
855+
/// Must be sizeof(FlutterRemoveViewInfo).
856+
size_t struct_size;
857+
858+
/// The identifier for the view to remove.
859+
///
860+
/// The implicit view cannot be removed if it is enabled.
861+
FlutterViewId view_id;
862+
863+
/// A baton that is not interpreted by the engine in any way.
864+
/// It will be given back to the embedder in |remove_view_callback|.
865+
/// Embedder resources may be associated with this baton.
866+
void* user_data;
867+
868+
/// Called once the engine has attempted to remove the view.
869+
/// This callback is required.
870+
///
871+
/// The embedder must not destroy the underlying surface until the callback is
872+
/// invoked with a `removed` value of `true`.
873+
///
874+
/// This callback is invoked on an internal engine managed thread.
875+
/// Embedders must re-thread if necessary.
876+
///
877+
/// The |result| argument will be deallocated when the callback returns.
878+
FlutterRemoveViewCallback remove_view_callback;
879+
} FlutterRemoveViewInfo;
880+
834881
/// Display refers to a graphics hardware system consisting of a framebuffer,
835882
/// typically a monitor or a screen. This ID is unique per display and is
836883
/// stable until the Flutter application restarts.
@@ -2458,6 +2505,25 @@ FLUTTER_EXPORT
24582505
FlutterEngineResult FlutterEngineRunInitialized(
24592506
FLUTTER_API_SYMBOL(FlutterEngine) engine);
24602507

2508+
//------------------------------------------------------------------------------
2509+
/// @brief Removes a view.
2510+
///
2511+
/// This is an asynchronous operation. The view's resources must not
2512+
/// be cleaned up until the |remove_view_callback| is invoked with
2513+
/// a |removed| value of `true`.
2514+
///
2515+
/// @param[in] engine A running engine instance.
2516+
/// @param[in] info The remove view arguments. This can be deallocated
2517+
/// once |FlutterEngineRemoveView| returns, before
2518+
/// |remove_view_callback| is invoked.
2519+
///
2520+
/// @return The result of *starting* the asynchronous operation. If
2521+
/// `kSuccess`, the |remove_view_callback| will be invoked.
2522+
FLUTTER_EXPORT
2523+
FlutterEngineResult FlutterEngineRemoveView(FLUTTER_API_SYMBOL(FlutterEngine)
2524+
engine,
2525+
const FlutterRemoveViewInfo* info);
2526+
24612527
FLUTTER_EXPORT
24622528
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(
24632529
FLUTTER_API_SYMBOL(FlutterEngine) engine,

0 commit comments

Comments
 (0)