From f3ad50c810b5becb00a1cac7ee4e5bb8157a13d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Tue, 20 Feb 2024 08:41:46 -0800 Subject: [PATCH] [Windows] Make the engine create the view (flutter/engine#50673) This makes the Windows engine create views. Benefits: 1. This will allow the engine to assign IDs to views as it creates them. This will be added in a subsequent change 2. Previously views needed special logic to not crash if they were used before an engine was attached to them. Now, views are always attached to an engine. Part of https://github.com/flutter/flutter/issues/137267 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 --- .../accessibility_bridge_windows_unittests.cc | 55 ++-- .../windows/compositor_opengl_unittests.cc | 8 +- .../windows/compositor_software_unittests.cc | 11 +- .../windows/cursor_handler_unittests.cc | 11 +- .../windows/flutter_window_unittests.cc | 16 +- .../shell/platform/windows/flutter_windows.cc | 5 +- .../windows/flutter_windows_engine.cc | 10 +- .../platform/windows/flutter_windows_engine.h | 5 +- .../flutter_windows_engine_unittests.cc | 68 ++-- .../platform/windows/flutter_windows_view.cc | 37 +-- .../platform/windows/flutter_windows_view.h | 8 +- .../windows/flutter_windows_view_unittests.cc | 305 ++++++++---------- .../platform/windows/keyboard_unittests.cc | 19 +- .../windows/platform_handler_unittests.cc | 10 +- .../windows/testing/engine_modifier.h | 8 + .../windows/text_input_plugin_unittest.cc | 12 +- 16 files changed, 290 insertions(+), 298 deletions(-) diff --git a/engine/src/flutter/shell/platform/windows/accessibility_bridge_windows_unittests.cc b/engine/src/flutter/shell/platform/windows/accessibility_bridge_windows_unittests.cc index 5b839720c46..ca540e2d50b 100644 --- a/engine/src/flutter/shell/platform/windows/accessibility_bridge_windows_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/accessibility_bridge_windows_unittests.cc @@ -26,6 +26,7 @@ namespace flutter { namespace testing { namespace { +using ::testing::NiceMock; // A structure representing a Win32 MSAA event targeting a specified node. struct MsaaEvent { @@ -88,8 +89,9 @@ class AccessibilityBridgeWindowsSpy : public AccessibilityBridgeWindows { // AccessibilityBridgeWindowsSpy. class FlutterWindowsViewSpy : public FlutterWindowsView { public: - explicit FlutterWindowsViewSpy(std::unique_ptr handler) - : FlutterWindowsView(std::move(handler)) {} + FlutterWindowsViewSpy(FlutterWindowsEngine* engine, + std::unique_ptr handler) + : FlutterWindowsView(engine, std::move(handler)) {} protected: virtual std::shared_ptr @@ -187,10 +189,10 @@ void ExpectWinEventFromAXEvent(int32_t node_id, ui::AXEventGenerator::Event ax_event, ax::mojom::Event expected_event) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = GetAccessibilityBridgeSpy(view); @@ -208,10 +210,10 @@ void ExpectWinEventFromAXEventOnFocusNode(int32_t node_id, ax::mojom::Event expected_event, int32_t focus_id) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = GetAccessibilityBridgeSpy(view); @@ -234,10 +236,10 @@ void ExpectWinEventFromAXEventOnFocusNode(int32_t node_id, TEST(AccessibilityBridgeWindows, GetParent) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = view.accessibility_bridge().lock(); @@ -251,10 +253,10 @@ TEST(AccessibilityBridgeWindows, GetParent) { TEST(AccessibilityBridgeWindows, GetParentOnRootRetunsNullptr) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = view.accessibility_bridge().lock(); @@ -266,17 +268,16 @@ TEST(AccessibilityBridgeWindows, GetParentOnRootRetunsNullptr) { TEST(AccessibilityBridgeWindows, DispatchAccessibilityAction) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = view.accessibility_bridge().lock(); PopulateAXTree(bridge); FlutterSemanticsAction actual_action = kFlutterSemanticsActionTap; - EngineModifier modifier(view.GetEngine()); modifier.embedder_api().DispatchSemanticsAction = MOCK_ENGINE_PROC( DispatchSemanticsAction, ([&actual_action](FLUTTER_API_SYMBOL(FlutterEngine) engine, uint64_t id, @@ -303,10 +304,10 @@ TEST(AccessibilityBridgeWindows, OnAccessibilityEventChildrenChanged) { TEST(AccessibilityBridgeWindows, OnAccessibilityEventFocusChanged) { auto engine = GetTestEngine(); - auto window_binding_handler = - std::make_unique<::testing::NiceMock>(); - FlutterWindowsViewSpy view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + FlutterWindowsViewSpy view{ + engine.get(), std::make_unique>()}; + EngineModifier modifier{engine.get()}; + modifier.SetImplicitView(&view); view.OnUpdateSemanticsEnabled(true); auto bridge = GetAccessibilityBridgeSpy(view); diff --git a/engine/src/flutter/shell/platform/windows/compositor_opengl_unittests.cc b/engine/src/flutter/shell/platform/windows/compositor_opengl_unittests.cc index bfa307533e7..9a596f9cc0e 100644 --- a/engine/src/flutter/shell/platform/windows/compositor_opengl_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/compositor_opengl_unittests.cc @@ -84,7 +84,7 @@ class CompositorOpenGLTest : public WindowsTest { FlutterWindowsEngineBuilder builder{GetContext()}; engine_ = builder.Build(); - EngineModifier modifier(engine_.get()); + EngineModifier modifier{engine_.get()}; modifier.SetEGLManager(std::move(egl_manager)); } @@ -95,7 +95,8 @@ class CompositorOpenGLTest : public WindowsTest { EXPECT_CALL(*window.get(), SetView).Times(1); EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr)); - view_ = std::make_unique(std::move(window)); + view_ = + std::make_unique(engine_.get(), std::move(window)); if (add_surface) { auto surface = std::make_unique(); @@ -107,7 +108,8 @@ class CompositorOpenGLTest : public WindowsTest { modifier.SetSurface(std::move(surface)); } - engine_->SetView(view_.get()); + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); } private: diff --git a/engine/src/flutter/shell/platform/windows/compositor_software_unittests.cc b/engine/src/flutter/shell/platform/windows/compositor_software_unittests.cc index bef9fca3061..27b0f485338 100644 --- a/engine/src/flutter/shell/platform/windows/compositor_software_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/compositor_software_unittests.cc @@ -22,8 +22,9 @@ using ::testing::Return; class MockFlutterWindowsView : public FlutterWindowsView { public: - MockFlutterWindowsView(std::unique_ptr window) - : FlutterWindowsView(std::move(window)) {} + MockFlutterWindowsView(FlutterWindowsEngine* engine, + std::unique_ptr window) + : FlutterWindowsView(engine, std::move(window)) {} virtual ~MockFlutterWindowsView() = default; MOCK_METHOD(bool, @@ -59,9 +60,11 @@ class CompositorSoftwareTest : public WindowsTest { EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr)); engine_ = builder.Build(); - view_ = std::make_unique(std::move(window)); + view_ = std::make_unique(engine_.get(), + std::move(window)); - engine_->SetView(view_.get()); + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); } private: diff --git a/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc b/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc index 459ea0635b8..d7dfda4230a 100644 --- a/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/testing/engine_modifier.h" #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" #include "flutter/shell/platform/windows/testing/test_binary_messenger.h" @@ -73,14 +74,16 @@ class CursorHandlerTest : public WindowsTest { FlutterWindowsEngineBuilder builder{GetContext()}; auto window = std::make_unique(); + EXPECT_CALL(*window.get(), SetView).Times(1); + EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr)); window_ = window.get(); - EXPECT_CALL(*window_, SetView).Times(1); - engine_ = builder.Build(); - view_ = std::make_unique(std::move(window)); + view_ = + std::make_unique(engine_.get(), std::move(window)); - engine_->SetView(view_.get()); + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); } private: diff --git a/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc index 270f4fe718c..7589e1e89cc 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc @@ -4,6 +4,7 @@ #include "flutter/fml/macros.h" #include "flutter/shell/platform/windows/flutter_window.h" +#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler_delegate.h" #include "flutter/shell/platform/windows/testing/windows_test.h" @@ -26,7 +27,7 @@ static constexpr int32_t kDefaultPointerDeviceId = 0; class MockFlutterWindow : public FlutterWindow { public: MockFlutterWindow(bool reset_view_on_exit = true) - : FlutterWindow(), reset_view_on_exit_(reset_view_on_exit) { + : reset_view_on_exit_(reset_view_on_exit) { ON_CALL(*this, GetDpiScale()) .WillByDefault(Return(this->FlutterWindow::GetDpiScale())); } @@ -95,8 +96,9 @@ class MockFlutterWindow : public FlutterWindow { class MockFlutterWindowsView : public FlutterWindowsView { public: - MockFlutterWindowsView(std::unique_ptr window_binding) - : FlutterWindowsView(std::move(window_binding)) {} + MockFlutterWindowsView(FlutterWindowsEngine* engine, + std::unique_ptr window_binding) + : FlutterWindowsView(engine, std::move(window_binding)) {} ~MockFlutterWindowsView() {} MOCK_METHOD(void, @@ -313,12 +315,14 @@ TEST_F(FlutterWindowTest, AccessibilityNodeWithoutView) { // Ensure that announcing the alert propagates the message to the alert node. // Different screen readers use different properties for alerts. TEST_F(FlutterWindowTest, AlertNode) { - std::unique_ptr win32window = - std::make_unique(); + std::unique_ptr engine = + FlutterWindowsEngineBuilder{GetContext()}.Build(); + auto win32window = std::make_unique(); EXPECT_CALL(*win32window.get(), GetAxFragmentRootDelegate()) .WillRepeatedly(Return(nullptr)); EXPECT_CALL(*win32window.get(), OnWindowStateEvent).Times(AnyNumber()); - MockFlutterWindowsView view(std::move(win32window)); + EXPECT_CALL(*win32window.get(), GetWindowHandle).Times(AnyNumber()); + MockFlutterWindowsView view{engine.get(), std::move(win32window)}; std::wstring message = L"Test alert"; EXPECT_CALL(view, NotifyWinEventWrapper(_, ax::mojom::Event::kAlert)) .Times(1); diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows.cc b/engine/src/flutter/shell/platform/windows/flutter_windows.cc index 0f293c497c6..baed42490d3 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows.cc @@ -82,12 +82,11 @@ FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate( width, height, engine_ptr->windows_proc_table()); auto engine = std::unique_ptr(engine_ptr); - auto view = std::make_unique( - std::move(window_wrapper), engine_ptr->windows_proc_table()); + std::unique_ptr view = + engine->CreateView(std::move(window_wrapper)); auto controller = std::make_unique( std::move(engine), std::move(view)); - controller->view()->SetEngine(controller->engine()); controller->view()->CreateRenderSurface(); if (!controller->engine()->running()) { if (!controller->engine()->Run()) { diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc index a5766c16577..89a806a40f5 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -483,9 +483,15 @@ bool FlutterWindowsEngine::Stop() { return false; } -void FlutterWindowsEngine::SetView(FlutterWindowsView* view) { - view_ = view; +std::unique_ptr FlutterWindowsEngine::CreateView( + std::unique_ptr window) { + auto view = std::make_unique(this, std::move(window), + windows_proc_table_); + + view_ = view.get(); InitializeKeyboard(); + + return std::move(view); } void FlutterWindowsEngine::OnVsync(intptr_t baton) { diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h index 3914978f9fc..24f07658862 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h @@ -111,8 +111,9 @@ class FlutterWindowsEngine { // Returns false if stopping the engine fails, or if it was not running. virtual bool Stop(); - // Sets the view that is displaying this engine's content. - void SetView(FlutterWindowsView* view); + // Create the view that is displaying this engine's content. + std::unique_ptr CreateView( + std::unique_ptr window); // The view displaying this engine's content, if any. This will be null for // headless engines. diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc index e44a5592dc1..8862fe2e5f9 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -578,6 +578,9 @@ TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) { engine_flags = flags; return kSuccess; })); + modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + [](auto engine, const auto message) { return kSuccess; }); // 1: High contrast is enabled. engine->UpdateHighContrastMode(); @@ -618,8 +621,9 @@ TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) { class MockFlutterWindowsView : public FlutterWindowsView { public: - MockFlutterWindowsView(std::unique_ptr wbh) - : FlutterWindowsView(std::move(wbh)) {} + MockFlutterWindowsView(FlutterWindowsEngine* engine, + std::unique_ptr wbh) + : FlutterWindowsView(engine, std::move(wbh)) {} ~MockFlutterWindowsView() {} MOCK_METHOD(void, @@ -643,10 +647,10 @@ TEST_F(FlutterWindowsEngineTest, AlertPlatformMessage) { AlertPlatformNodeDelegate delegate(parent_delegate); EXPECT_CALL(*window_binding_handler, GetAlertDelegate) .WillRepeatedly(Return(&delegate)); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto binary_messenger = @@ -706,10 +710,10 @@ TEST_F(FlutterWindowsEngineTest, TestExit) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed)); @@ -743,10 +747,10 @@ TEST_F(FlutterWindowsEngineTest, TestExitCancel) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed)); @@ -791,10 +795,10 @@ TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed)); @@ -853,10 +857,10 @@ TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed)); @@ -885,10 +889,10 @@ TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0); @@ -904,10 +908,10 @@ TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false)); @@ -924,10 +928,10 @@ TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false)); @@ -943,10 +947,10 @@ TEST_F(FlutterWindowsEngineTest, AppStartsInResumedState) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState(AppLifecycleState::kResumed)) @@ -961,10 +965,10 @@ TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; engine->Run(); @@ -990,10 +994,10 @@ TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; // Sets lifecycle state to resumed. engine->Run(); @@ -1016,11 +1020,11 @@ TEST_F(FlutterWindowsEngineTest, InnerWindowHidden) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); ON_CALL(view, GetWindowHandle).WillByDefault([=]() { return inner; }); - view.SetEngine(engine.get()); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; // Sets lifecycle state to resumed. engine->Run(); @@ -1050,10 +1054,10 @@ TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState) @@ -1103,10 +1107,10 @@ TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; auto handler = std::make_unique(engine.get()); EXPECT_CALL(*handler, SetLifecycleState) @@ -1150,10 +1154,10 @@ TEST_F(FlutterWindowsEngineTest, ChannelListenedTo) { auto engine = builder.Build(); auto window_binding_handler = std::make_unique<::testing::NiceMock>(); - MockFlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler)); EngineModifier modifier(engine.get()); + modifier.SetImplicitView(&view); modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; }; bool lifecycle_began = false; diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc index a373bc244ba..5c8d209feb9 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc @@ -84,9 +84,10 @@ void UpdateVsync(const FlutterWindowsEngine& engine, } // namespace FlutterWindowsView::FlutterWindowsView( + FlutterWindowsEngine* engine, std::unique_ptr window_binding, std::shared_ptr windows_proc_table) - : windows_proc_table_(std::move(windows_proc_table)) { + : engine_(engine), windows_proc_table_(std::move(windows_proc_table)) { if (windows_proc_table_ == nullptr) { windows_proc_table_ = std::make_shared(); } @@ -97,33 +98,17 @@ FlutterWindowsView::FlutterWindowsView( } FlutterWindowsView::~FlutterWindowsView() { - if (engine_) { - // The view owns the child window. - // Notify the engine the view's child window will no longer be visible. - engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide); + // The view owns the child window. + // Notify the engine the view's child window will no longer be visible. + engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide); - // The engine renders into the view's surface. The engine must be - // shutdown before the view's resources can be destroyed. - engine_->Stop(); - } + // The engine renders into the view's surface. The engine must be + // shutdown before the view's resources can be destroyed. + engine_->Stop(); DestroyRenderSurface(); } -void FlutterWindowsView::SetEngine(FlutterWindowsEngine* engine) { - FML_DCHECK(engine_ == nullptr); - FML_DCHECK(engine != nullptr); - - engine_ = engine; - - engine_->SetView(this); - - PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); - - SendWindowMetrics(bounds.width, bounds.height, - binding_handler_->GetDpiScale()); -} - bool FlutterWindowsView::OnEmptyFrameGenerated() { // Called on the raster thread. std::unique_lock lock(resize_mutex_); @@ -670,7 +655,7 @@ bool FlutterWindowsView::PresentSoftwareBitmap(const void* allocation, void FlutterWindowsView::CreateRenderSurface() { FML_DCHECK(surface_ == nullptr); - if (engine_ && engine_->egl_manager()) { + if (engine_->egl_manager()) { PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); surface_ = engine_->egl_manager()->CreateWindowSurface( GetWindowHandle(), bounds.width, bounds.height); @@ -789,9 +774,7 @@ void FlutterWindowsView::OnDwmCompositionChanged() { } void FlutterWindowsView::OnWindowStateEvent(HWND hwnd, WindowStateEvent event) { - if (engine_) { - engine_->OnWindowStateEvent(hwnd, event); - } + engine_->OnWindowStateEvent(hwnd, event); } bool FlutterWindowsView::NeedsVsync() const { diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h index 62ccb70c394..787197df98b 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h @@ -32,19 +32,13 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { public: // Creates a FlutterWindowsView with the given implementor of // WindowBindingHandler. - // - // In order for object to render Flutter content the SetEngine method must be - // called with a valid FlutterWindowsEngine instance. FlutterWindowsView( + FlutterWindowsEngine* engine, std::unique_ptr window_binding, std::shared_ptr windows_proc_table = nullptr); virtual ~FlutterWindowsView(); - // Configures the window instance with an instance of a running Flutter - // engine. - void SetEngine(FlutterWindowsEngine* engine); - // Creates rendering surface for Flutter engine to draw into. // Should be called before calling FlutterEngineRun using this view. void CreateRenderSurface(); diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_view_unittests.cc index 92c0416ec69..d8810c5066d 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view_unittests.cc @@ -80,8 +80,10 @@ FlutterProjectBundle GetTestProject() { // Returns an engine instance configured with test project path values, and // overridden methods for sending platform messages, so that the engine can // respond as if the framework were connected. -std::unique_ptr GetTestEngine() { - auto engine = std::make_unique(GetTestProject()); +std::unique_ptr GetTestEngine( + std::shared_ptr windows_proc_table = nullptr) { + auto engine = std::make_unique( + GetTestProject(), std::move(windows_proc_table)); EngineModifier modifier(engine.get()); @@ -113,7 +115,9 @@ std::unique_ptr GetTestEngine() { class MockFlutterWindowsEngine : public FlutterWindowsEngine { public: - MockFlutterWindowsEngine() : FlutterWindowsEngine(GetTestProject()) {} + explicit MockFlutterWindowsEngine( + std::shared_ptr windows_proc_table = nullptr) + : FlutterWindowsEngine(GetTestProject(), std::move(windows_proc_table)) {} MOCK_METHOD(bool, running, (), (const)); MOCK_METHOD(bool, Stop, (), ()); @@ -137,13 +141,13 @@ TEST(FlutterWindowsViewTest, SubMenuExpandedState) { auto window_binding_handler = std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = + engine->CreateView(std::move(window_binding_handler)); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); FlutterSemanticsNode2 root{sizeof(FlutterSemanticsNode2), 0}; @@ -237,19 +241,23 @@ TEST(FlutterWindowsViewTest, Shutdown) { std::make_unique>(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); + auto surface_ptr = surface.get(); - FlutterWindowsView view(std::move(window_binding_handler)); - EngineModifier engine_modifier(engine.get()); - ViewModifier view_modifier(&view); + EngineModifier modifier{engine.get()}; + modifier.SetEGLManager(std::move(egl_manager)); - // The engine must be stopped before the surface can be destroyed. - InSequence s; - EXPECT_CALL(*engine.get(), Stop).Times(1); - EXPECT_CALL(*surface.get(), Destroy).Times(1); + { + std::unique_ptr view = + engine->CreateView(std::move(window_binding_handler)); - engine_modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); - view_modifier.SetSurface(std::move(surface)); + ViewModifier view_modifier{view.get()}; + view_modifier.SetSurface(std::move(surface)); + + // The engine must be stopped before the surface can be destroyed. + InSequence s; + EXPECT_CALL(*engine.get(), Stop).Times(1); + EXPECT_CALL(*surface_ptr, Destroy).Times(1); + } } TEST(FlutterWindowsViewTest, KeySequence) { @@ -257,13 +265,11 @@ TEST(FlutterWindowsViewTest, KeySequence) { test_response = false; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); - view.OnKey(kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false, - [](bool handled) {}); + view->OnKey(kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false, + [](bool handled) {}); EXPECT_EQ(key_event_logs.size(), 2); EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder); @@ -287,10 +293,10 @@ TEST(FlutterWindowsViewTest, EnableSemantics) { auto window_binding_handler = std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = + engine->CreateView(std::move(window_binding_handler)); - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); EXPECT_TRUE(semantics_enabled); } @@ -304,13 +310,13 @@ TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdate) { auto window_binding_handler = std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = + engine->CreateView(std::move(window_binding_handler)); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); // Add root node. @@ -401,15 +407,13 @@ TEST(FlutterWindowsViewTest, AddSemanticsNodeUpdateWithChildren) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); // Add root node. @@ -599,15 +603,13 @@ TEST(FlutterWindowsViewTest, NonZeroSemanticsRoot) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); // Add root node. @@ -731,15 +733,13 @@ TEST(FlutterWindowsViewTest, AccessibilityHitTesting) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); // Add root node at origin. Size 500x500. @@ -814,12 +814,11 @@ TEST(FlutterWindowsViewTest, AccessibilityHitTesting) { } TEST(FlutterWindowsViewTest, WindowResizeTests) { - std::unique_ptr engine = GetTestEngine(); - EngineModifier engine_modifier(engine.get()); + auto windows_proc_table = std::make_shared>(); + std::unique_ptr engine = + GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; - auto window_binding_handler = - std::make_unique>(); - auto windows_proc_table = std::make_shared(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); auto resized_surface = std::make_unique(); @@ -837,11 +836,12 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(true)); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - ViewModifier view_modifier(&view); engine_modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); + + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + ViewModifier view_modifier{view.get()}; view_modifier.SetSurface(std::move(surface)); fml::AutoResetWaitableEvent metrics_sent_latch; @@ -857,7 +857,7 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { std::thread([&resized_latch, &view]() { // Start the window resize. This sends the new window metrics // and then blocks until another thread completes the window resize. - EXPECT_TRUE(view.OnWindowSizeChanged(500, 500)); + EXPECT_TRUE(view->OnWindowSizeChanged(500, 500)); resized_latch.Signal(); }).detach(); @@ -865,19 +865,18 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { metrics_sent_latch.Wait(); // Complete the window resize by reporting a frame with the new window size. - ASSERT_TRUE(view.OnFrameGenerated(500, 500)); - view.OnFramePresented(); + ASSERT_TRUE(view->OnFrameGenerated(500, 500)); + view->OnFramePresented(); resized_latch.Wait(); } // Verify that an empty frame completes a view resize. TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { - std::unique_ptr engine = GetTestEngine(); - EngineModifier engine_modifier(engine.get()); + auto windows_proc_table = std::make_shared>(); + std::unique_ptr engine = + GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; - auto window_binding_handler = - std::make_unique>(); - auto windows_proc_table = std::make_shared(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); auto resized_surface = std::make_unique(); @@ -895,13 +894,6 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { EXPECT_CALL(*resized_surface_ptr, Destroy).WillOnce(Return(true)); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - ViewModifier view_modifier(&view); - engine_modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); - view_modifier.SetSurface(std::move(surface)); - fml::AutoResetWaitableEvent metrics_sent_latch; engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC( SendWindowMetricsEvent, @@ -911,11 +903,18 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { return kSuccess; })); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + ViewModifier view_modifier{view.get()}; + engine_modifier.SetEGLManager(std::move(egl_manager)); + view_modifier.SetSurface(std::move(surface)); + fml::AutoResetWaitableEvent resized_latch; std::thread([&resized_latch, &view]() { // Start the window resize. This sends the new window metrics // and then blocks until another thread completes the window resize. - EXPECT_TRUE(view.OnWindowSizeChanged(500, 500)); + EXPECT_TRUE(view->OnWindowSizeChanged(500, 500)); resized_latch.Signal(); }).detach(); @@ -923,8 +922,8 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { metrics_sent_latch.Wait(); // Complete the window resize by reporting an empty frame. - view.OnEmptyFrameGenerated(); - view.OnFramePresented(); + view->OnEmptyFrameGenerated(); + view->OnFramePresented(); resized_latch.Wait(); } @@ -935,31 +934,28 @@ TEST(FlutterWindowsViewTest, WindowResizeRace) { std::unique_ptr engine = GetTestEngine(); EngineModifier engine_modifier(engine.get()); - auto window_binding_handler = - std::make_unique>(); - auto windows_proc_table = std::make_shared(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(true)); EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(true)); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - ViewModifier view_modifier(&view); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + ViewModifier view_modifier{view.get()}; engine_modifier.SetEGLManager(std::move(egl_manager)); view_modifier.SetSurface(std::move(surface)); - view.SetEngine(engine.get()); // Begin a frame. - ASSERT_TRUE(view.OnFrameGenerated(100, 100)); + ASSERT_TRUE(view->OnFrameGenerated(100, 100)); // Inject a window resize between the frame generation and // frame presentation. The new size invalidates the current frame. fml::AutoResetWaitableEvent resized_latch; std::thread([&resized_latch, &view]() { // The resize is never completed. The view times out and returns false. - EXPECT_FALSE(view.OnWindowSizeChanged(500, 500)); + EXPECT_FALSE(view->OnWindowSizeChanged(500, 500)); resized_latch.Signal(); }).detach(); @@ -969,7 +965,7 @@ TEST(FlutterWindowsViewTest, WindowResizeRace) { // Complete the invalidated frame while a resize is pending. Although this // might mean that we presented a frame with the wrong size, this should not // crash the app. - view.OnFramePresented(); + view->OnFramePresented(); } // Window resize should succeed even if the render surface could not be created @@ -978,9 +974,6 @@ TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) { std::unique_ptr engine = GetTestEngine(); EngineModifier engine_modifier(engine.get()); - auto window_binding_handler = - std::make_unique>(); - auto windows_proc_table = std::make_shared(); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -988,12 +981,12 @@ TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) { EXPECT_CALL(*surface.get(), IsValid).WillRepeatedly(Return(false)); EXPECT_CALL(*surface.get(), Destroy).WillOnce(Return(false)); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - ViewModifier view_modifier(&view); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + ViewModifier view_modifier{view.get()}; engine_modifier.SetEGLManager(std::move(egl_manager)); view_modifier.SetSurface(std::move(surface)); - view.SetEngine(engine.get()); auto metrics_sent = false; engine_modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC( @@ -1003,7 +996,7 @@ TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) { return kSuccess; })); - view.OnWindowSizeChanged(500, 500); + view->OnWindowSizeChanged(500, 500); } // Window resize should succeed even if EGL initialized successfully @@ -1012,17 +1005,14 @@ TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) { std::unique_ptr engine = GetTestEngine(); EngineModifier modifier(engine.get()); - auto window_binding_handler = - std::make_unique>(); - auto windows_proc_table = std::make_shared(); auto egl_manager = std::make_unique(); EXPECT_CALL(*egl_manager.get(), CreateWindowSurface).Times(0); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); auto metrics_sent = false; modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC( @@ -1032,15 +1022,15 @@ TEST(FlutterWindowsViewTest, WindowResizeWithoutSurface) { return kSuccess; })); - view.OnWindowSizeChanged(500, 500); + view->OnWindowSizeChanged(500, 500); } TEST(FlutterWindowsViewTest, WindowRepaintTests) { std::unique_ptr engine = GetTestEngine(); EngineModifier modifier(engine.get()); - FlutterWindowsView view(std::make_unique(100, 100)); - view.SetEngine(engine.get()); + FlutterWindowsView view{engine.get(), + std::make_unique(100, 100)}; bool schedule_frame_called = false; modifier.embedder_api().ScheduleFrame = @@ -1067,15 +1057,13 @@ TEST(FlutterWindowsViewTest, CheckboxNativeState) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); FlutterSemanticsNode2 root{sizeof(FlutterSemanticsNode2), 0}; @@ -1213,15 +1201,13 @@ TEST(FlutterWindowsViewTest, SwitchNativeState) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); FlutterSemanticsNode2 root{sizeof(FlutterSemanticsNode2), 0}; @@ -1332,15 +1318,13 @@ TEST(FlutterWindowsViewTest, TooltipNodeData) { return kSuccess; }; - auto window_binding_handler = - std::make_unique>(); - FlutterWindowsView view(std::move(window_binding_handler)); - view.SetEngine(engine.get()); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); // Enable semantics to instantiate accessibility bridge. - view.OnUpdateSemanticsEnabled(true); + view->OnUpdateSemanticsEnabled(true); - auto bridge = view.accessibility_bridge().lock(); + auto bridge = view->accessibility_bridge().lock(); ASSERT_TRUE(bridge); FlutterSemanticsNode2 root{sizeof(FlutterSemanticsNode2), 0}; @@ -1384,10 +1368,8 @@ TEST(FlutterWindowsViewTest, TooltipNodeData) { // Don't block until the v-blank if it is disabled by the window. // The surface is updated on the platform thread at startup. TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) { - auto engine = std::make_unique(); - auto window_binding_handler = - std::make_unique>(); auto windows_proc_table = std::make_shared(); + auto engine = std::make_unique(windows_proc_table); auto egl_manager = std::make_unique(); egl::MockContext render_context; auto surface = std::make_unique(); @@ -1403,10 +1385,6 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) { .WillOnce(Return(&render_context)); EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(true)); - EngineModifier engine_modifier(engine.get()); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - InSequence s; EXPECT_CALL(*egl_manager.get(), CreateWindowSurface) .WillOnce(Return(std::move(surface))); @@ -1417,19 +1395,20 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAtStartup) { EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); - engine_modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); + EngineModifier modifier{engine.get()}; + modifier.SetEGLManager(std::move(egl_manager)); - view.CreateRenderSurface(); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + view->CreateRenderSurface(); } // Blocks until the v-blank if it is enabled by the window. // The surface is updated on the platform thread at startup. TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) { - auto engine = std::make_unique(); - auto window_binding_handler = - std::make_unique>(); auto windows_proc_table = std::make_shared(); + auto engine = std::make_unique(windows_proc_table); auto egl_manager = std::make_unique(); egl::MockContext render_context; auto surface = std::make_unique(); @@ -1444,10 +1423,6 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) { .WillOnce(Return(&render_context)); EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(true)); - EngineModifier modifier(engine.get()); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - InSequence s; EXPECT_CALL(*egl_manager.get(), CreateWindowSurface) .WillOnce(Return(std::move(surface))); @@ -1458,19 +1433,20 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAtStartup) { EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); + EngineModifier modifier{engine.get()}; modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); - view.CreateRenderSurface(); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + view->CreateRenderSurface(); } // Don't block until the v-blank if it is disabled by the window. // The surface is updated on the raster thread if the engine is running. TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { - auto engine = std::make_unique(); - auto window_binding_handler = - std::make_unique>(); auto windows_proc_table = std::make_shared(); + auto engine = std::make_unique(windows_proc_table); auto egl_manager = std::make_unique(); egl::MockContext render_context; auto surface = std::make_unique(); @@ -1484,10 +1460,6 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { .WillOnce(Return(&render_context)); EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(true)); - EngineModifier modifier(engine.get()); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - InSequence s; EXPECT_CALL(*egl_manager.get(), CreateWindowSurface) .WillOnce(Return(std::move(surface))); @@ -1502,19 +1474,20 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); + EngineModifier modifier{engine.get()}; modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); - view.CreateRenderSurface(); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + view->CreateRenderSurface(); } // Blocks until the v-blank if it is enabled by the window. // The surface is updated on the raster thread if the engine is running. TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { - auto engine = std::make_unique(); - auto window_binding_handler = - std::make_unique>(); auto windows_proc_table = std::make_shared(); + auto engine = std::make_unique(windows_proc_table); auto egl_manager = std::make_unique(); egl::MockContext render_context; auto surface = std::make_unique(); @@ -1529,10 +1502,6 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { .WillOnce(Return(&render_context)); EXPECT_CALL(*surface_ptr, IsValid).WillOnce(Return(true)); - EngineModifier modifier(engine.get()); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - InSequence s; EXPECT_CALL(*egl_manager.get(), CreateWindowSurface) .WillOnce(Return(std::move(surface))); @@ -1548,20 +1517,21 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); + EngineModifier modifier{engine.get()}; modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); - view.CreateRenderSurface(); + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + + view->CreateRenderSurface(); } // Desktop Window Manager composition can be disabled on Windows 7. // If this happens, the app must synchronize with the vsync to prevent // screen tearing. TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) { - auto engine = std::make_unique(); - auto window_binding_handler = - std::make_unique>(); auto windows_proc_table = std::make_shared(); + auto engine = std::make_unique(windows_proc_table); auto egl_manager = std::make_unique(); egl::MockContext render_context; auto surface = std::make_unique(); @@ -1584,11 +1554,6 @@ TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) { EXPECT_CALL(*surface_ptr, IsValid).WillRepeatedly(Return(true)); - EngineModifier engine_modifier(engine.get()); - FlutterWindowsView view(std::move(window_binding_handler), - std::move(windows_proc_table)); - ViewModifier view_modifier(&view); - InSequence s; EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(true)).WillOnce(Return(true)); @@ -1601,12 +1566,16 @@ TEST(FlutterWindowsViewTest, UpdatesVSyncOnDwmUpdates) { EXPECT_CALL(*engine.get(), Stop).Times(1); EXPECT_CALL(*surface_ptr, Destroy).Times(1); + EngineModifier engine_modifier{engine.get()}; engine_modifier.SetEGLManager(std::move(egl_manager)); - view.SetEngine(engine.get()); + + std::unique_ptr view = engine->CreateView( + std::make_unique>()); + ViewModifier view_modifier{view.get()}; view_modifier.SetSurface(std::move(surface)); - view.GetEngine()->OnDwmCompositionChanged(); - view.GetEngine()->OnDwmCompositionChanged(); + engine->OnDwmCompositionChanged(); + engine->OnDwmCompositionChanged(); } } // namespace testing diff --git a/engine/src/flutter/shell/platform/windows/keyboard_unittests.cc b/engine/src/flutter/shell/platform/windows/keyboard_unittests.cc index 7265dd5d2db..fff6b6e7dcc 100644 --- a/engine/src/flutter/shell/platform/windows/keyboard_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/keyboard_unittests.cc @@ -336,9 +336,11 @@ typedef struct { // A FlutterWindowsView that spies on text. class TestFlutterWindowsView : public FlutterWindowsView { public: - TestFlutterWindowsView(std::function on_key_call, - std::unique_ptr window) - : on_key_call_(on_key_call), FlutterWindowsView(std::move(window)) {} + TestFlutterWindowsView(FlutterWindowsEngine* engine, + std::unique_ptr window, + std::function on_key_call) + : on_key_call_(on_key_call), + FlutterWindowsView(engine, std::move(window)) {} void OnText(const std::u16string& text) override { on_key_call_(KeyCall{ @@ -363,11 +365,16 @@ class KeyboardTester { map_virtual_key_layout_(LayoutDefault) { engine_ = GetTestEngine(context); view_ = std::make_unique( - [this](KeyCall key_call) { key_calls.push_back(key_call); }, + engine_.get(), // The WindowBindingHandler is used for window size and such, and // doesn't affect keyboard. - std::make_unique<::testing::NiceMock>()); - view_->SetEngine(engine_.get()); + std::make_unique<::testing::NiceMock>(), + [this](KeyCall key_call) { key_calls.push_back(key_call); }); + + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); + modifier.InitializeKeyboard(); + window_ = std::make_unique( view_.get(), [this](UINT virtual_key) -> SHORT { return map_virtual_key_layout_(virtual_key, MAPVK_VK_TO_CHAR); diff --git a/engine/src/flutter/shell/platform/windows/platform_handler_unittests.cc b/engine/src/flutter/shell/platform/windows/platform_handler_unittests.cc index 35cb70368c1..ca99d1779a1 100644 --- a/engine/src/flutter/shell/platform/windows/platform_handler_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/platform_handler_unittests.cc @@ -9,6 +9,7 @@ #include "flutter/fml/macros.h" #include "flutter/shell/platform/common/json_method_codec.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/testing/engine_modifier.h" #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" #include "flutter/shell/platform/windows/testing/test_binary_messenger.h" @@ -152,10 +153,13 @@ class PlatformHandlerTest : public WindowsTest { FlutterWindowsEngineBuilder builder{GetContext()}; auto window = std::make_unique>(); - view_ = std::make_unique(std::move(window)); - engine_ = builder.Build(); - engine_->SetView(view_.get()); + engine_ = builder.Build(); + view_ = + std::make_unique(engine_.get(), std::move(window)); + + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); } private: diff --git a/engine/src/flutter/shell/platform/windows/testing/engine_modifier.h b/engine/src/flutter/shell/platform/windows/testing/engine_modifier.h index e9fd3b8833e..d070dc10993 100644 --- a/engine/src/flutter/shell/platform/windows/testing/engine_modifier.h +++ b/engine/src/flutter/shell/platform/windows/testing/engine_modifier.h @@ -37,6 +37,10 @@ class EngineModifier { engine_->egl_manager_ = std::move(egl_manager); } + // Override the engine's implicit view. This is the "default" view + // that Flutter apps render to. + void SetImplicitView(FlutterWindowsView* view) { engine_->view_ = view; } + /// Reset the start_time field that is used to align vsync events. void SetStartTime(uint64_t start_time_nanos) { engine_->start_time_ = std::chrono::nanoseconds(start_time_nanos); @@ -64,6 +68,10 @@ class EngineModifier { // restart. This resets the keyboard's state if it exists. void Restart() { engine_->OnPreEngineRestart(); } + // Initialize they keyboard and text input subsystems or reset them them if + // they are already initialized. + void InitializeKeyboard() { engine_->InitializeKeyboard(); } + void SetLifecycleManager(std::unique_ptr&& handler) { engine_->lifecycle_manager_ = std::move(handler); } diff --git a/engine/src/flutter/shell/platform/windows/text_input_plugin_unittest.cc b/engine/src/flutter/shell/platform/windows/text_input_plugin_unittest.cc index de8104454da..2e078cc0864 100644 --- a/engine/src/flutter/shell/platform/windows/text_input_plugin_unittest.cc +++ b/engine/src/flutter/shell/platform/windows/text_input_plugin_unittest.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/common/json_message_codec.h" #include "flutter/shell/platform/common/json_method_codec.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/testing/engine_modifier.h" #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" #include "flutter/shell/platform/windows/testing/test_binary_messenger.h" @@ -104,8 +105,9 @@ static std::unique_ptr EncodedEditingState( class MockFlutterWindowsView : public FlutterWindowsView { public: - MockFlutterWindowsView(std::unique_ptr window) - : FlutterWindowsView(std::move(window)) {} + MockFlutterWindowsView(FlutterWindowsEngine* engine, + std::unique_ptr window) + : FlutterWindowsView(engine, std::move(window)) {} virtual ~MockFlutterWindowsView() = default; MOCK_METHOD(void, OnCursorRectUpdated, (const Rect&), (override)); @@ -143,9 +145,11 @@ class TextInputPluginTest : public WindowsTest { EXPECT_CALL(*window, GetWindowHandle).WillRepeatedly(Return(nullptr)); engine_ = builder.Build(); - view_ = std::make_unique(std::move(window)); + view_ = std::make_unique(engine_.get(), + std::move(window)); - engine_->SetView(view_.get()); + EngineModifier modifier{engine_.get()}; + modifier.SetImplicitView(view_.get()); } private: