[Windows] Make the engine own a map of views (flutter/engine#51017)

Updates Windows engine's data structures to use a map of views.

This is a refactoring with no semantic changes. Flutter Windows's APIs restrict users to 0 or 1 view only - it is not possible to create multiple views yet.

_One small step for Windows. One giant leap for multi-view._

Part of https://github.com/flutter/flutter/issues/143765
Part of https://github.com/flutter/flutter/issues/142845

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Loïc Sharma
2024-02-27 15:28:00 -08:00
committed by GitHub
parent cdeb8166a2
commit 12228ffd98
4 changed files with 36 additions and 14 deletions

View File

@@ -496,7 +496,7 @@ std::unique_ptr<FlutterWindowsView> FlutterWindowsEngine::CreateView(
auto view = std::make_unique<FlutterWindowsView>(
kImplicitViewId, this, std::move(window), windows_proc_table_);
view_ = view.get();
views_[kImplicitViewId] = view.get();
InitializeKeyboard();
return std::move(view);
@@ -531,9 +531,12 @@ std::chrono::nanoseconds FlutterWindowsEngine::FrameInterval() {
}
FlutterWindowsView* FlutterWindowsEngine::view(FlutterViewId view_id) const {
FML_DCHECK(view_id == kImplicitViewId);
auto iterator = views_.find(view_id);
if (iterator == views_.end()) {
return nullptr;
}
return view_;
return iterator->second;
}
// Returns the currently configured Plugin Registrar.
@@ -672,7 +675,7 @@ void FlutterWindowsEngine::SendSystemLocales() {
}
void FlutterWindowsEngine::InitializeKeyboard() {
if (view_ == nullptr) {
if (views_.empty()) {
FML_LOG(ERROR) << "Cannot initialize keyboard on Windows headless mode.";
}
@@ -762,15 +765,15 @@ void FlutterWindowsEngine::UpdateSemanticsEnabled(bool enabled) {
if (engine_ && semantics_enabled_ != enabled) {
semantics_enabled_ = enabled;
embedder_api_.UpdateSemanticsEnabled(engine_, enabled);
if (view_) {
view_->UpdateSemanticsEnabled(enabled);
for (auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
iterator->second->UpdateSemanticsEnabled(enabled);
}
}
}
void FlutterWindowsEngine::OnPreEngineRestart() {
// Reset the keyboard's state on hot restart.
if (view_) {
if (!views_.empty()) {
InitializeKeyboard();
}
}
@@ -827,7 +830,9 @@ void FlutterWindowsEngine::OnQuit(std::optional<HWND> hwnd,
}
void FlutterWindowsEngine::OnDwmCompositionChanged() {
view_->OnDwmCompositionChanged();
for (auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
iterator->second->OnDwmCompositionChanged();
}
}
void FlutterWindowsEngine::OnWindowStateEvent(HWND hwnd,

View File

@@ -11,6 +11,7 @@
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "flutter/fml/closure.h"
@@ -119,12 +120,13 @@ class FlutterWindowsEngine {
// Returns false if stopping the engine fails, or if it was not running.
virtual bool Stop();
// Create the view that is displaying this engine's content.
// Create a view that can display this engine's content.
std::unique_ptr<FlutterWindowsView> CreateView(
std::unique_ptr<WindowBindingHandler> window);
// The view displaying this engine's content, if any. This will be null for
// headless engines.
// Get a view that displays this engine's content.
//
// Returns null if the view does not exist.
FlutterWindowsView* view(FlutterViewId view_id) const;
// Returns the currently configured Plugin Registrar.
@@ -349,8 +351,8 @@ class FlutterWindowsEngine {
// AOT data, if any.
UniqueAotDataPtr aot_data_;
// The view displaying the content running in this engine, if any.
FlutterWindowsView* view_ = nullptr;
// The views displaying the content running in this engine, if any.
std::unordered_map<FlutterViewId, FlutterWindowsView*> views_;
// Task runner for tasks posted from the engine.
std::unique_ptr<TaskRunner> task_runner_;

View File

@@ -34,6 +34,19 @@ using ::testing::Return;
class FlutterWindowsEngineTest : public WindowsTest {};
// The engine can be run without any views.
TEST_F(FlutterWindowsEngineTest, RunHeadless) {
FlutterWindowsEngineBuilder builder{GetContext()};
std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
EngineModifier modifier(engine.get());
modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
ASSERT_TRUE(engine->Run());
ASSERT_EQ(engine->view(kImplicitViewId), nullptr);
ASSERT_EQ(engine->view(123), nullptr);
}
TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
FlutterWindowsEngineBuilder builder{GetContext()};
builder.AddDartEntrypointArgument("arg1");

View File

@@ -39,7 +39,9 @@ class EngineModifier {
// Override the engine's implicit view. This is the "default" view
// that Flutter apps render to.
void SetImplicitView(FlutterWindowsView* view) { engine_->view_ = view; }
void SetImplicitView(FlutterWindowsView* view) {
engine_->views_[kImplicitViewId] = view;
}
/// Reset the start_time field that is used to align vsync events.
void SetStartTime(uint64_t start_time_nanos) {