Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
flutter_windows_engine_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <thread>
7
25#include "gmock/gmock.h"
26#include "gtest/gtest.h"
27
28// winbase.h defines GetCurrentTime as a macro.
29#undef GetCurrentTime
30
31namespace {
32// Process the next win32 message if there is one. This can be used to
33// pump the Windows platform thread task runner.
34void PumpMessage() {
35 ::MSG msg;
36 if (::GetMessage(&msg, nullptr, 0, 0)) {
37 ::TranslateMessage(&msg);
39 }
40}
41} // namespace
42
43namespace flutter {
44namespace testing {
45
46using ::testing::_;
47using ::testing::DoAll;
48using ::testing::NiceMock;
49using ::testing::Return;
50using ::testing::SetArgPointee;
51
53
54// The engine can be run without any views.
56 FlutterWindowsEngineBuilder builder{GetContext()};
57 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
58
59 EngineModifier modifier(engine.get());
60 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
61
62 ASSERT_TRUE(engine->Run());
63 ASSERT_EQ(engine->view(kImplicitViewId), nullptr);
64 ASSERT_EQ(engine->view(123), nullptr);
65}
66
67TEST_F(FlutterWindowsEngineTest, TaskRunnerDelayedTask) {
68 bool finished = false;
69 auto runner = std::make_unique<TaskRunner>(
70 [] {
71 return static_cast<uint64_t>(
73 },
74 [&](const FlutterTask*) { finished = true; });
75 runner->PostFlutterTask(
77 static_cast<uint64_t>((fml::TimePoint::Now().ToEpochDelta() +
79 .ToNanoseconds()));
81 while (!finished) {
82 PumpMessage();
83 }
84 auto duration = fml::TimePoint::Now() - start;
85 EXPECT_GE(duration, fml::TimeDelta::FromMilliseconds(50));
86}
87
88// https://github.com/flutter/flutter/issues/173843)
89TEST_F(FlutterWindowsEngineTest, TaskRunnerDoesNotDeadlock) {
90 auto runner = std::make_unique<TaskRunner>(
91 [] {
92 return static_cast<uint64_t>(
94 },
95 [&](const FlutterTask*) {});
96
97 struct RunnerHolder {
98 void PostTaskLoop() {
99 runner->PostTask([this] { PostTaskLoop(); });
100 }
101 std::unique_ptr<TaskRunner> runner;
102 };
103
104 RunnerHolder container{.runner = std::move(runner)};
105 // Spam flutter tasks.
106 container.PostTaskLoop();
107
108 const LPCWSTR class_name = L"FlutterTestWindowClass";
109 WNDCLASS wc = {0};
110 wc.lpfnWndProc = DefWindowProc;
111 wc.lpszClassName = class_name;
112 RegisterClass(&wc);
113
114 HWND window;
115 container.runner->PostTask([&] {
116 window = CreateWindowEx(0, class_name, L"Empty Window", WS_OVERLAPPEDWINDOW,
117 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr,
118 nullptr, nullptr, nullptr);
119 ShowWindow(window, SW_SHOW);
120 });
121
122 while (true) {
123 ::MSG msg;
124 if (::GetMessage(&msg, nullptr, 0, 0)) {
125 if (msg.message == WM_PAINT) {
126 break;
127 }
128 ::TranslateMessage(&msg);
129 ::DispatchMessage(&msg);
130 }
131 }
132
133 DestroyWindow(window);
134 UnregisterClassW(class_name, nullptr);
135}
136
137TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
138 FlutterWindowsEngineBuilder builder{GetContext()};
139 builder.AddDartEntrypointArgument("arg1");
140 builder.AddDartEntrypointArgument("arg2");
141
142 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
143
144 HMONITOR mock_monitor = reinterpret_cast<HMONITOR>(1);
145
146 MONITORINFOEXW monitor_info = {};
147 monitor_info.cbSize = sizeof(MONITORINFOEXW);
148 monitor_info.rcMonitor = {0, 0, 1920, 1080};
149 monitor_info.rcWork = {0, 0, 1920, 1080};
150 monitor_info.dwFlags = MONITORINFOF_PRIMARY;
151 wcscpy_s(monitor_info.szDevice, L"\\\\.\\DISPLAY1");
152
153 EXPECT_CALL(*windows_proc_table, GetMonitorInfoW(mock_monitor, _))
154 .WillRepeatedly(DoAll(SetArgPointee<1>(monitor_info), Return(TRUE)));
155
156 EXPECT_CALL(*windows_proc_table, EnumDisplayMonitors(nullptr, nullptr, _, _))
157 .WillRepeatedly([&](HDC hdc, LPCRECT lprcClip, MONITORENUMPROC lpfnEnum,
158 LPARAM dwData) {
159 lpfnEnum(mock_monitor, nullptr, &monitor_info.rcMonitor, dwData);
160 return TRUE;
161 });
162
163 EXPECT_CALL(*windows_proc_table, GetDpiForMonitor(mock_monitor, _))
164 .WillRepeatedly(Return(96));
165
166 // Mock locale information
167 EXPECT_CALL(*windows_proc_table, GetThreadPreferredUILanguages(_, _, _, _))
168 .WillRepeatedly(
169 [](DWORD flags, PULONG count, PZZWSTR languages, PULONG length) {
170 // We need to mock the locale information twice because the first
171 // call is to get the size and the second call is to fill the
172 // buffer.
173 if (languages == nullptr) {
174 // First call is to get the size
175 *count = 1; // One language
176 *length = 10; // "fr-FR\0\0" (double null-terminated)
177 return TRUE;
178 } else {
179 // Second call is to fill the buffer
180 *count = 1;
181 // Fill with "fr-FR\0\0" (double null-terminated)
182 wchar_t* lang_buffer = languages;
183 wcscpy(lang_buffer, L"fr-FR");
184 // Move past the first null terminator to add the second
185 lang_buffer += wcslen(L"fr-FR") + 1;
186 *lang_buffer = L'\0';
187 return TRUE;
188 }
189 });
190
191 builder.SetWindowsProcTable(windows_proc_table);
192
193 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
194 EngineModifier modifier(engine.get());
195
196 // The engine should be run with expected configuration values.
197 bool run_called = false;
198 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
199 Run, ([&run_called, engine_instance = engine.get()](
200 size_t version, const FlutterRendererConfig* config,
201 const FlutterProjectArgs* args, void* user_data,
202 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
203 run_called = true;
204 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
205
206 EXPECT_EQ(version, FLUTTER_ENGINE_VERSION);
207 EXPECT_NE(config, nullptr);
208 // We have an EGL manager, so this should be using OpenGL.
209 EXPECT_EQ(config->type, kOpenGL);
210 EXPECT_EQ(user_data, engine_instance);
211 // Spot-check arguments.
212 EXPECT_NE(args->assets_path, nullptr);
213 EXPECT_NE(args->icu_data_path, nullptr);
214 EXPECT_EQ(args->dart_entrypoint_argc, 2U);
215 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[0], "arg1"), 0);
216 EXPECT_EQ(strcmp(args->dart_entrypoint_argv[1], "arg2"), 0);
217 EXPECT_NE(args->platform_message_callback, nullptr);
218 EXPECT_NE(args->custom_task_runners, nullptr);
219 EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr);
220 EXPECT_EQ(args->custom_dart_entrypoint, nullptr);
221 EXPECT_NE(args->vsync_callback, nullptr);
222 EXPECT_EQ(args->update_semantics_callback, nullptr);
223 EXPECT_NE(args->update_semantics_callback2, nullptr);
224 EXPECT_EQ(args->update_semantics_node_callback, nullptr);
225 EXPECT_EQ(args->update_semantics_custom_action_callback, nullptr);
226 EXPECT_NE(args->view_focus_change_request_callback, nullptr);
227
228 args->custom_task_runners->thread_priority_setter(
230 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
231 THREAD_PRIORITY_ABOVE_NORMAL);
232 return kSuccess;
233 }));
234 // Accessibility updates must do nothing when the embedder engine is mocked
236 UpdateAccessibilityFeatures,
238 FlutterAccessibilityFeature flags) { return kSuccess; });
239
240 // It should send locale info.
241 bool update_locales_called = false;
243 UpdateLocales,
244 ([&update_locales_called](auto engine, const FlutterLocale** locales,
245 size_t locales_count) {
246 update_locales_called = true;
247
248 EXPECT_GT(locales_count, 0);
249 EXPECT_NE(locales, nullptr);
250
251 return kSuccess;
252 }));
253
254 // And it should send initial settings info.
255 bool settings_message_sent = false;
257 SendPlatformMessage,
258 ([&settings_message_sent](auto engine, auto message) {
259 if (std::string(message->channel) == std::string("flutter/settings")) {
260 settings_message_sent = true;
261 }
262
263 return kSuccess;
264 }));
265
266 // And it should send display info.
267 bool notify_display_update_called = false;
268
270 NotifyDisplayUpdate,
271 ([&notify_display_update_called](
273 const FlutterEngineDisplaysUpdateType update_type,
274 const FlutterEngineDisplay* embedder_displays,
275 size_t display_count) {
276 EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
277 notify_display_update_called = true;
278 return kSuccess;
279 }));
280
281 // Set the EGL manager to !nullptr to test ANGLE rendering.
282 modifier.SetEGLManager(std::make_unique<egl::MockManager>());
283
284 engine->Run();
285
286 EXPECT_TRUE(run_called);
287 EXPECT_TRUE(update_locales_called);
288 EXPECT_TRUE(settings_message_sent);
289 EXPECT_TRUE(notify_display_update_called);
290
291 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
292 // engine pointer that the overridden Run returned.
293 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
294 modifier.ReleaseEGLManager();
295}
296
297TEST_F(FlutterWindowsEngineTest, ConfiguresFrameVsync) {
298 FlutterWindowsEngineBuilder builder{GetContext()};
299 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
300 EngineModifier modifier(engine.get());
301 bool on_vsync_called = false;
302
303 modifier.embedder_api().GetCurrentTime =
304 MOCK_ENGINE_PROC(GetCurrentTime, ([]() -> uint64_t { return 1; }));
306 OnVsync,
307 ([&on_vsync_called, engine_instance = engine.get()](
308 FLUTTER_API_SYMBOL(FlutterEngine) engine, intptr_t baton,
309 uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos) {
310 EXPECT_EQ(baton, 1);
311 EXPECT_EQ(frame_start_time_nanos, 16600000);
312 EXPECT_EQ(frame_target_time_nanos, 33200000);
313 on_vsync_called = true;
314 return kSuccess;
315 }));
316 modifier.SetStartTime(0);
317 modifier.SetFrameInterval(16600000);
318
319 engine->OnVsync(1);
320
321 EXPECT_TRUE(on_vsync_called);
322}
323
324TEST_F(FlutterWindowsEngineTest, RunSkiaWithoutANGLEUsesSoftware) {
325 FlutterWindowsEngineBuilder builder{GetContext()};
327 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
328 EngineModifier modifier(engine.get());
329
331 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
332 ([engine_instance = engine.get()](
334 const FlutterEngineDisplaysUpdateType update_type,
335 const FlutterEngineDisplay* embedder_displays,
336 size_t display_count) { return kSuccess; }));
337
338 // The engine should be run with expected configuration values.
339 bool run_called = false;
340 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
341 Run, ([&run_called, engine_instance = engine.get()](
342 size_t version, const FlutterRendererConfig* config,
343 const FlutterProjectArgs* args, void* user_data,
344 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
345 run_called = true;
346 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
347 // We don't have an EGL Manager, so we should be using software.
348 EXPECT_EQ(config->type, kSoftware);
349 return kSuccess;
350 }));
351 // Accessibility updates must do nothing when the embedder engine is mocked
353 UpdateAccessibilityFeatures,
355 FlutterAccessibilityFeature flags) { return kSuccess; });
356
357 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
358 // initialized engine instance.
360 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
361 size_t locales_count) { return kSuccess; }));
363 MOCK_ENGINE_PROC(SendPlatformMessage,
364 ([](auto engine, auto message) { return kSuccess; }));
365
366 // Set the EGL manager to nullptr to test software fallback path.
367 modifier.SetEGLManager(nullptr);
368
369 engine->Run();
370
371 EXPECT_TRUE(run_called);
372
373 // Ensure that deallocation doesn't call the actual Shutdown with the bogus
374 // engine pointer that the overridden Run returned.
375 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
376}
377
378TEST_F(FlutterWindowsEngineTest, RunWithoutANGLEOnImpellerFailsToStart) {
379 FlutterWindowsEngineBuilder builder{GetContext()};
380 builder.SetSwitches({"--enable-impeller=true"});
381 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
382 EngineModifier modifier(engine.get());
383
385 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
386 ([engine_instance = engine.get()](
388 const FlutterEngineDisplaysUpdateType update_type,
389 const FlutterEngineDisplay* embedder_displays,
390 size_t display_count) { return kSuccess; }));
391
392 // Accessibility updates must do nothing when the embedder engine is mocked
394 UpdateAccessibilityFeatures,
396 FlutterAccessibilityFeature flags) { return kSuccess; });
397
398 // Stub out UpdateLocales and SendPlatformMessage as we don't have a fully
399 // initialized engine instance.
401 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
402 size_t locales_count) { return kSuccess; }));
404 MOCK_ENGINE_PROC(SendPlatformMessage,
405 ([](auto engine, auto message) { return kSuccess; }));
406
407 // Set the EGL manager to nullptr to test software fallback path.
408 modifier.SetEGLManager(nullptr);
409
410 EXPECT_FALSE(engine->Run());
411}
412
413TEST_F(FlutterWindowsEngineTest, RunWithDefaultEnablesImpeller) {
414 FlutterWindowsEngineBuilder builder{GetContext()};
416 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
417 EngineModifier modifier(engine.get());
418
420 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
421 ([engine_instance = engine.get()](
423 const FlutterEngineDisplaysUpdateType update_type,
424 const FlutterEngineDisplay* embedder_displays,
425 size_t display_count) { return kSuccess; }));
426
428 UpdateAccessibilityFeatures,
430 FlutterAccessibilityFeature flags) { return kSuccess; });
431
433 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
434 size_t locales_count) { return kSuccess; }));
435
437 MOCK_ENGINE_PROC(SendPlatformMessage,
438 ([](auto engine, auto message) { return kSuccess; }));
439
440 bool run_called = false;
441 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
442 Run, ([&run_called, engine_instance = engine.get()](
443 size_t version, const FlutterRendererConfig* config,
444 const FlutterProjectArgs* args, void* user_data,
445 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
446 run_called = true;
447 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
448
449 bool has_impeller_switch = false;
450 bool has_sdf_switch = false;
451 for (int i = 0; i < args->command_line_argc; ++i) {
452 if (strcmp(args->command_line_argv[i], "--enable-impeller") == 0) {
453 has_impeller_switch = true;
454 }
455 if (strcmp(args->command_line_argv[i], "--impeller-use-sdfs=true") ==
456 0) {
457 has_sdf_switch = true;
458 }
459 }
460 EXPECT_TRUE(has_impeller_switch);
461 EXPECT_TRUE(has_sdf_switch);
462 return kSuccess;
463 }));
464
465 // Set the EGL manager to !nullptr to test ANGLE rendering.
466 modifier.SetEGLManager(std::make_unique<egl::MockManager>());
467
468 engine->Run();
469
470 EXPECT_TRUE(run_called);
471
472 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
473 modifier.ReleaseEGLManager();
474}
475
476TEST_F(FlutterWindowsEngineTest, RunWithProjectFlagEnableImpeller) {
477 FlutterWindowsEngineBuilder builder{GetContext()};
479 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
480 EngineModifier modifier(engine.get());
481
483 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
484 ([](FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
485 const FlutterEngineDisplaysUpdateType update_type,
486 const FlutterEngineDisplay* embedder_displays,
487 size_t display_count) { return kSuccess; }));
488
490 UpdateAccessibilityFeatures,
492 FlutterAccessibilityFeature flags) { return kSuccess; });
493
495 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
496 size_t locales_count) { return kSuccess; }));
497
499 MOCK_ENGINE_PROC(SendPlatformMessage,
500 ([](auto engine, auto message) { return kSuccess; }));
501
502 bool run_called = false;
503 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
504 Run, ([&run_called](size_t version, const FlutterRendererConfig* config,
505 const FlutterProjectArgs* args, void* user_data,
506 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
507 run_called = true;
508 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
509
510 bool has_impeller_switch = false;
511 bool has_sdf_switch = false;
512 for (int i = 0; i < args->command_line_argc; ++i) {
513 if (strcmp(args->command_line_argv[i], "--enable-impeller") == 0) {
514 has_impeller_switch = true;
515 }
516 if (strcmp(args->command_line_argv[i], "--impeller-use-sdfs=true") ==
517 0) {
518 has_sdf_switch = true;
519 }
520 }
521 EXPECT_TRUE(has_impeller_switch);
522 EXPECT_TRUE(has_sdf_switch);
523 return kSuccess;
524 }));
525
526 // Set the EGL manager to !nullptr to test ANGLE rendering.
527 modifier.SetEGLManager(std::make_unique<egl::MockManager>());
528
529 engine->Run();
530
531 EXPECT_TRUE(run_called);
532
533 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
534 modifier.ReleaseEGLManager();
535}
536
537TEST_F(FlutterWindowsEngineTest, RunWithProjectFlagDisableImpeller) {
538 FlutterWindowsEngineBuilder builder{GetContext()};
540 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
541 EngineModifier modifier(engine.get());
542
544 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
545 ([](FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
546 const FlutterEngineDisplaysUpdateType update_type,
547 const FlutterEngineDisplay* embedder_displays,
548 size_t display_count) { return kSuccess; }));
549
551 UpdateAccessibilityFeatures,
553 FlutterAccessibilityFeature flags) { return kSuccess; });
554
556 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
557 size_t locales_count) { return kSuccess; }));
558
560 MOCK_ENGINE_PROC(SendPlatformMessage,
561 ([](auto engine, auto message) { return kSuccess; }));
562
563 bool run_called = false;
564 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
565 Run, ([&run_called](size_t version, const FlutterRendererConfig* config,
566 const FlutterProjectArgs* args, void* user_data,
567 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
568 run_called = true;
569 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
570
571 bool has_disable_impeller_switch = false;
572 for (int i = 0; i < args->command_line_argc; ++i) {
573 if (strcmp(args->command_line_argv[i], "--enable-impeller=false") ==
574 0) {
575 has_disable_impeller_switch = true;
576 }
577 }
578 EXPECT_TRUE(has_disable_impeller_switch);
579 return kSuccess;
580 }));
581
582 engine->Run();
583
584 EXPECT_TRUE(run_called);
585
586 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
587}
588
589TEST_F(FlutterWindowsEngineTest, RunWithCommandLineDisableImpeller) {
590 FlutterWindowsEngineBuilder builder{GetContext()};
591 builder.SetSwitches({"--enable-impeller=false"});
592 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
593 EngineModifier modifier(engine.get());
594
596 MOCK_ENGINE_PROC(NotifyDisplayUpdate,
597 ([](FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
598 const FlutterEngineDisplaysUpdateType update_type,
599 const FlutterEngineDisplay* embedder_displays,
600 size_t display_count) { return kSuccess; }));
601
603 UpdateAccessibilityFeatures,
605 FlutterAccessibilityFeature flags) { return kSuccess; });
606
608 UpdateLocales, ([](auto engine, const FlutterLocale** locales,
609 size_t locales_count) { return kSuccess; }));
610
612 MOCK_ENGINE_PROC(SendPlatformMessage,
613 ([](auto engine, auto message) { return kSuccess; }));
614
615 bool run_called = false;
616 modifier.embedder_api().Run = MOCK_ENGINE_PROC(
617 Run, ([&run_called](size_t version, const FlutterRendererConfig* config,
618 const FlutterProjectArgs* args, void* user_data,
619 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
620 run_called = true;
621 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
622
623 bool has_disable_impeller_switch = false;
624 for (int i = 0; i < args->command_line_argc; ++i) {
625 if (strcmp(args->command_line_argv[i], "--enable-impeller=false") ==
626 0) {
627 has_disable_impeller_switch = true;
628 }
629 }
630 EXPECT_TRUE(has_disable_impeller_switch);
631 return kSuccess;
632 }));
633
634 engine->Run();
635
636 EXPECT_TRUE(run_called);
637
638 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
639}
640
641TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithoutResponse) {
642 FlutterWindowsEngineBuilder builder{GetContext()};
643 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
644 EngineModifier modifier(engine.get());
645
646 const char* channel = "test";
647 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
648
649 // Without a response, SendPlatformMessage should be a simple pass-through.
650 bool called = false;
652 SendPlatformMessage, ([&called, test_message](auto engine, auto message) {
653 called = true;
654 EXPECT_STREQ(message->channel, "test");
655 EXPECT_EQ(message->message_size, test_message.size());
656 EXPECT_EQ(memcmp(message->message, test_message.data(),
657 message->message_size),
658 0);
659 EXPECT_EQ(message->response_handle, nullptr);
660 return kSuccess;
661 }));
662
663 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
664 nullptr, nullptr);
665 EXPECT_TRUE(called);
666}
667
668TEST_F(FlutterWindowsEngineTest, PlatformMessageRoundTrip) {
669 FlutterWindowsEngineBuilder builder{GetContext()};
670 builder.SetDartEntrypoint("hiPlatformChannels");
671
672 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
673 EngineModifier modifier(engine.get());
674 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
675
676 auto binary_messenger =
677 std::make_unique<BinaryMessengerImpl>(engine->messenger());
678
679 engine->Run();
680 bool did_call_callback = false;
681 bool did_call_reply = false;
682 bool did_call_dart_reply = false;
683 std::string channel = "hi";
684 binary_messenger->SetMessageHandler(
685 channel,
686 [&did_call_callback, &did_call_dart_reply](
687 const uint8_t* message, size_t message_size, BinaryReply reply) {
688 if (message_size == 5) {
689 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
690 char response[] = {'b', 'y', 'e'};
691 reply(reinterpret_cast<uint8_t*>(response), 3);
692 did_call_callback = true;
693 } else {
694 EXPECT_EQ(message_size, 3);
695 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
696 did_call_dart_reply = true;
697 }
698 });
699 char payload[] = {'h', 'e', 'l', 'l', 'o'};
700 binary_messenger->Send(
701 channel, reinterpret_cast<uint8_t*>(payload), 5,
702 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
703 EXPECT_EQ(reply_size, 5);
704 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
705 did_call_reply = true;
706 });
707 // Rely on timeout mechanism in CI.
708 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
709 engine->task_runner()->ProcessTasks();
710 }
711}
712
713TEST_F(FlutterWindowsEngineTest, PlatformMessageRespondOnDifferentThread) {
714 FlutterWindowsEngineBuilder builder{GetContext()};
715 builder.SetDartEntrypoint("hiPlatformChannels");
716
717 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
718
719 EngineModifier modifier(engine.get());
720 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
721
722 auto binary_messenger =
723 std::make_unique<BinaryMessengerImpl>(engine->messenger());
724
725 engine->Run();
726 bool did_call_callback = false;
727 bool did_call_reply = false;
728 bool did_call_dart_reply = false;
729 std::string channel = "hi";
730 std::unique_ptr<std::thread> reply_thread;
731 binary_messenger->SetMessageHandler(
732 channel,
733 [&did_call_callback, &did_call_dart_reply, &reply_thread](
734 const uint8_t* message, size_t message_size, BinaryReply reply) {
735 if (message_size == 5) {
736 EXPECT_EQ(message[0], static_cast<uint8_t>('h'));
737 reply_thread.reset(new std::thread([reply = std::move(reply)]() {
738 char response[] = {'b', 'y', 'e'};
739 reply(reinterpret_cast<uint8_t*>(response), 3);
740 }));
741 did_call_callback = true;
742 } else {
743 EXPECT_EQ(message_size, 3);
744 EXPECT_EQ(message[0], static_cast<uint8_t>('b'));
745 did_call_dart_reply = true;
746 }
747 });
748 char payload[] = {'h', 'e', 'l', 'l', 'o'};
749 binary_messenger->Send(
750 channel, reinterpret_cast<uint8_t*>(payload), 5,
751 [&did_call_reply](const uint8_t* reply, size_t reply_size) {
752 EXPECT_EQ(reply_size, 5);
753 EXPECT_EQ(reply[0], static_cast<uint8_t>('h'));
754 did_call_reply = true;
755 });
756 // Rely on timeout mechanism in CI.
757 while (!did_call_callback || !did_call_reply || !did_call_dart_reply) {
758 engine->task_runner()->ProcessTasks();
759 }
760 ASSERT_TRUE(reply_thread);
761 reply_thread->join();
762}
763
764TEST_F(FlutterWindowsEngineTest, SendPlatformMessageWithResponse) {
765 FlutterWindowsEngineBuilder builder{GetContext()};
766 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
767 EngineModifier modifier(engine.get());
768
769 const char* channel = "test";
770 const std::vector<uint8_t> test_message = {1, 2, 3, 4};
771 auto* dummy_response_handle =
772 reinterpret_cast<FlutterPlatformMessageResponseHandle*>(5);
773 const FlutterDesktopBinaryReply reply_handler = [](auto... args) {};
774 void* reply_user_data = reinterpret_cast<void*>(6);
775
776 // When a response is requested, a handle should be created, passed as part
777 // of the message, and then released.
778 bool create_response_handle_called = false;
781 PlatformMessageCreateResponseHandle,
782 ([&create_response_handle_called, &reply_handler, reply_user_data,
783 dummy_response_handle](auto engine, auto reply, auto user_data,
784 auto response_handle) {
785 create_response_handle_called = true;
786 EXPECT_EQ(reply, reply_handler);
787 EXPECT_EQ(user_data, reply_user_data);
788 EXPECT_NE(response_handle, nullptr);
789 *response_handle = dummy_response_handle;
790 return kSuccess;
791 }));
792 bool release_response_handle_called = false;
795 PlatformMessageReleaseResponseHandle,
796 ([&release_response_handle_called, dummy_response_handle](
797 auto engine, auto response_handle) {
798 release_response_handle_called = true;
799 EXPECT_EQ(response_handle, dummy_response_handle);
800 return kSuccess;
801 }));
802 bool send_message_called = false;
804 SendPlatformMessage, ([&send_message_called, test_message,
805 dummy_response_handle](auto engine, auto message) {
806 send_message_called = true;
807 EXPECT_STREQ(message->channel, "test");
808 EXPECT_EQ(message->message_size, test_message.size());
809 EXPECT_EQ(memcmp(message->message, test_message.data(),
810 message->message_size),
811 0);
812 EXPECT_EQ(message->response_handle, dummy_response_handle);
813 return kSuccess;
814 }));
815
816 engine->SendPlatformMessage(channel, test_message.data(), test_message.size(),
817 reply_handler, reply_user_data);
818 EXPECT_TRUE(create_response_handle_called);
819 EXPECT_TRUE(release_response_handle_called);
820 EXPECT_TRUE(send_message_called);
821}
822
824 FlutterWindowsEngineBuilder builder{GetContext()};
825 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
826 EngineModifier modifier(engine.get());
827
828 bool called = false;
829 std::string message = "Hello";
831 SendSemanticsAction, ([&called, &message](auto engine, auto info) {
832 called = true;
833 EXPECT_EQ(info->view_id, 456);
834 EXPECT_EQ(info->node_id, 42);
835 EXPECT_EQ(info->action, kFlutterSemanticsActionDismiss);
836 EXPECT_EQ(memcmp(info->data, message.c_str(), message.size()), 0);
837 EXPECT_EQ(info->data_length, message.size());
838 return kSuccess;
839 }));
840
841 auto data = fml::MallocMapping::Copy(message.c_str(), message.size());
842 engine->DispatchSemanticsAction(456, 42, kFlutterSemanticsActionDismiss,
843 std::move(data));
844 EXPECT_TRUE(called);
845}
846
847TEST_F(FlutterWindowsEngineTest, SetsThreadPriority) {
849 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
850 THREAD_PRIORITY_BELOW_NORMAL);
851
853 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
854 THREAD_PRIORITY_ABOVE_NORMAL);
855
857 EXPECT_EQ(GetThreadPriority(GetCurrentThread()),
858 THREAD_PRIORITY_ABOVE_NORMAL);
859
860 // FlutterThreadPriority::kNormal does not change thread priority, reset to 0
861 // here.
862 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
863
865 EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL);
866}
867
868TEST_F(FlutterWindowsEngineTest, AddPluginRegistrarDestructionCallback) {
869 FlutterWindowsEngineBuilder builder{GetContext()};
870 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
871 EngineModifier modifier(engine.get());
872
874 std::make_shared<MockKeyResponseController>());
875
876 engine->Run();
877
878 // Verify that destruction handlers don't overwrite each other.
879 int result1 = 0;
880 int result2 = 0;
881 engine->AddPluginRegistrarDestructionCallback(
883 auto result = reinterpret_cast<int*>(ref);
884 *result = 1;
885 },
886 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result1));
887 engine->AddPluginRegistrarDestructionCallback(
889 auto result = reinterpret_cast<int*>(ref);
890 *result = 2;
891 },
892 reinterpret_cast<FlutterDesktopPluginRegistrarRef>(&result2));
893
894 engine->Stop();
895 EXPECT_EQ(result1, 1);
896 EXPECT_EQ(result2, 2);
897}
898
900 FlutterWindowsEngineBuilder builder{GetContext()};
901 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
902 EngineModifier modifier(engine.get());
903
904 bool called = false;
905 modifier.embedder_api().ScheduleFrame =
906 MOCK_ENGINE_PROC(ScheduleFrame, ([&called](auto engine) {
907 called = true;
908 return kSuccess;
909 }));
910
911 engine->ScheduleFrame();
912 EXPECT_TRUE(called);
913}
914
915TEST_F(FlutterWindowsEngineTest, SetNextFrameCallback) {
916 FlutterWindowsEngineBuilder builder{GetContext()};
917 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
918 EngineModifier modifier(engine.get());
919
920 bool called = false;
922 SetNextFrameCallback, ([&called](auto engine, auto callback, auto data) {
923 called = true;
924 return kSuccess;
925 }));
926
927 engine->SetNextFrameCallback([]() {});
928 EXPECT_TRUE(called);
929}
930
931TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
932 FlutterWindowsEngineBuilder builder{GetContext()};
933 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
934 EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe");
935}
936
937// Ensure that after setting or resetting the high contrast feature,
938// the corresponding status flag can be retrieved from the engine.
939TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
940 auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
941 EXPECT_CALL(*windows_proc_table, GetHighContrastEnabled)
942 .WillOnce(Return(true))
943 .WillOnce(Return(false));
944
945 FlutterWindowsEngineBuilder builder{GetContext()};
946 builder.SetWindowsProcTable(windows_proc_table);
947 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
948 EngineModifier modifier(engine.get());
949
950 std::optional<FlutterAccessibilityFeature> engine_flags;
952 UpdateAccessibilityFeatures, ([&engine_flags](auto engine, auto flags) {
953 engine_flags = flags;
954 return kSuccess;
955 }));
957 SendPlatformMessage,
958 [](auto engine, const auto message) { return kSuccess; });
959
960 // 1: High contrast is enabled.
961 engine->UpdateHighContrastMode();
962
963 EXPECT_TRUE(engine->high_contrast_enabled());
964 EXPECT_TRUE(engine_flags.has_value());
965 EXPECT_TRUE(
966 engine_flags.value() &
968
969 // 2: High contrast is disabled.
970 engine_flags.reset();
971 engine->UpdateHighContrastMode();
972
973 EXPECT_FALSE(engine->high_contrast_enabled());
974 EXPECT_TRUE(engine_flags.has_value());
975 EXPECT_FALSE(
976 engine_flags.value() &
978}
979
980TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {
981 FlutterWindowsEngineBuilder builder{GetContext()};
982 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
983 EngineModifier modifier(engine.get());
984
986 PostRenderThreadTask, ([](auto engine, auto callback, auto context) {
988 return kSuccess;
989 }));
990
991 bool called = false;
992 engine->PostRasterThreadTask([&called]() { called = true; });
993
994 EXPECT_TRUE(called);
995}
996
997class MockFlutterWindowsView : public FlutterWindowsView {
998 public:
1000 std::unique_ptr<WindowBindingHandler> wbh)
1002 engine,
1003 std::move(wbh),
1004 false,
1005 BoxConstraints()) {}
1007
1009 NotifyWinEventWrapper,
1010 (ui::AXPlatformNodeWin*, ax::mojom::Event),
1011 (override));
1012 MOCK_METHOD(HWND, GetWindowHandle, (), (const, override));
1013 MOCK_METHOD(bool, Focus, (), (override));
1014
1015 private:
1016 FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
1017};
1018
1019// Verify the view is notified of accessibility announcements.
1020TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncement) {
1021 auto& context = GetContext();
1023 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
1024
1025 bool done = false;
1026 auto native_entry =
1027 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1028 context.AddNativeFunction("Signal", native_entry);
1029
1030 EnginePtr engine{builder.RunHeadless()};
1031 ASSERT_NE(engine, nullptr);
1032
1033 ui::AXPlatformNodeDelegateBase parent_delegate;
1034 AlertPlatformNodeDelegate delegate{parent_delegate};
1035
1036 auto window_binding_handler =
1037 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1038 EXPECT_CALL(*window_binding_handler, GetAlertDelegate)
1039 .WillOnce(Return(&delegate));
1040
1041 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
1042 MockFlutterWindowsView view{windows_engine,
1043 std::move(window_binding_handler)};
1044 EngineModifier modifier{windows_engine};
1045 modifier.SetImplicitView(&view);
1046
1047 windows_engine->UpdateSemanticsEnabled(true);
1048
1049 EXPECT_CALL(view, NotifyWinEventWrapper).Times(1);
1050
1051 // Rely on timeout mechanism in CI.
1052 while (!done) {
1053 windows_engine->task_runner()->ProcessTasks();
1054 }
1055}
1056
1057// Verify the app can send accessibility announcements while in headless mode.
1058TEST_F(FlutterWindowsEngineTest, AccessibilityAnnouncementHeadless) {
1059 auto& context = GetContext();
1061 builder.SetDartEntrypoint("sendAccessibilityAnnouncement");
1062
1063 bool done = false;
1064 auto native_entry =
1065 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1066 context.AddNativeFunction("Signal", native_entry);
1067
1068 EnginePtr engine{builder.RunHeadless()};
1069 ASSERT_NE(engine, nullptr);
1070
1071 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
1072 windows_engine->UpdateSemanticsEnabled(true);
1073
1074 // Rely on timeout mechanism in CI.
1075 while (!done) {
1076 windows_engine->task_runner()->ProcessTasks();
1077 }
1078}
1079
1080// Verify the engine does not crash if it receives an accessibility event
1081// it does not support yet.
1082TEST_F(FlutterWindowsEngineTest, AccessibilityTooltip) {
1083 fml::testing::LogCapture log_capture;
1084
1085 auto& context = GetContext();
1087 builder.SetDartEntrypoint("sendAccessibilityTooltipEvent");
1088
1089 bool done = false;
1090 auto native_entry =
1091 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1092 context.AddNativeFunction("Signal", native_entry);
1093
1094 ViewControllerPtr controller{builder.Run()};
1095 ASSERT_NE(controller, nullptr);
1096
1097 auto engine = FlutterDesktopViewControllerGetEngine(controller.get());
1098 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine);
1099 windows_engine->UpdateSemanticsEnabled(true);
1100
1101 // Rely on timeout mechanism in CI.
1102 while (!done) {
1103 windows_engine->task_runner()->ProcessTasks();
1104 }
1105
1106 // Verify no error was logged.
1107 // Regression test for:
1108 // https://github.com/flutter/flutter/issues/144274
1109 EXPECT_EQ(log_capture.str().find("tooltip"), std::string::npos);
1110}
1111
1113 public:
1117
1119 void,
1120 Quit,
1121 (std::optional<HWND>, std::optional<WPARAM>, std::optional<LPARAM>, UINT),
1122 (override));
1123 MOCK_METHOD(void, DispatchMessage, (HWND, UINT, WPARAM, LPARAM), (override));
1124 MOCK_METHOD(bool, IsLastWindowOfProcess, (), (override));
1126
1133
1134 std::function<void()> begin_processing_callback = nullptr;
1135};
1136
1138 FlutterWindowsEngineBuilder builder{GetContext()};
1139 builder.SetDartEntrypoint("exitTestExit");
1140 bool finished = false;
1141
1142 auto engine = builder.Build();
1143 auto window_binding_handler =
1144 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1145 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1146
1147 EngineModifier modifier(engine.get());
1148 modifier.SetImplicitView(&view);
1149 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1150 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1151 EXPECT_CALL(*handler, Quit)
1152 .WillOnce([&finished](std::optional<HWND> hwnd,
1153 std::optional<WPARAM> wparam,
1154 std::optional<LPARAM> lparam,
1155 UINT exit_code) { finished = exit_code == 0; });
1156 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
1157 modifier.SetLifecycleManager(std::move(handler));
1158
1159 engine->lifecycle_manager()->BeginProcessingExit();
1160
1161 engine->Run();
1162
1163 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1164 0);
1165
1166 // The test will only succeed when this while loop exits. Otherwise it will
1167 // timeout.
1168 while (!finished) {
1169 engine->task_runner()->ProcessTasks();
1170 }
1171}
1172
1174 FlutterWindowsEngineBuilder builder{GetContext()};
1175 builder.SetDartEntrypoint("exitTestCancel");
1176 bool did_call = false;
1177
1178 auto engine = builder.Build();
1179 auto window_binding_handler =
1180 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1181 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1182
1183 EngineModifier modifier(engine.get());
1184 modifier.SetImplicitView(&view);
1185 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1186 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1187 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillRepeatedly(Return(true));
1188 EXPECT_CALL(*handler, Quit).Times(0);
1189 modifier.SetLifecycleManager(std::move(handler));
1190 engine->lifecycle_manager()->BeginProcessingExit();
1191
1192 auto binary_messenger =
1193 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1194 binary_messenger->SetMessageHandler(
1195 "flutter/platform", [&did_call](const uint8_t* message,
1196 size_t message_size, BinaryReply reply) {
1197 std::string contents(message, message + message_size);
1198 EXPECT_NE(contents.find("\"method\":\"System.exitApplication\""),
1199 std::string::npos);
1200 EXPECT_NE(contents.find("\"type\":\"required\""), std::string::npos);
1201 EXPECT_NE(contents.find("\"exitCode\":0"), std::string::npos);
1202 did_call = true;
1203 char response[] = "";
1204 reply(reinterpret_cast<uint8_t*>(response), 0);
1205 });
1206
1207 engine->Run();
1208
1209 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1210 0);
1211
1212 while (!did_call) {
1213 engine->task_runner()->ProcessTasks();
1214 }
1215}
1216
1217// Flutter consumes the first WM_CLOSE message to allow the app to cancel the
1218// exit. If the app does not cancel the exit, Flutter synthesizes a second
1219// WM_CLOSE message.
1220TEST_F(FlutterWindowsEngineTest, TestExitSecondCloseMessage) {
1221 FlutterWindowsEngineBuilder builder{GetContext()};
1222 builder.SetDartEntrypoint("exitTestExit");
1223 bool second_close = false;
1224
1225 auto engine = builder.Build();
1226 auto window_binding_handler =
1227 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1228 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1229
1230 EngineModifier modifier(engine.get());
1231 modifier.SetImplicitView(&view);
1232 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1233 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1234 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(true));
1235 EXPECT_CALL(*handler, Quit)
1236 .WillOnce([handler_ptr = handler.get()](
1237 std::optional<HWND> hwnd, std::optional<WPARAM> wparam,
1238 std::optional<LPARAM> lparam, UINT exit_code) {
1239 handler_ptr->WindowsLifecycleManager::Quit(hwnd, wparam, lparam,
1240 exit_code);
1241 });
1242 EXPECT_CALL(*handler, DispatchMessage)
1243 .WillRepeatedly(
1244 [&engine](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1245 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1246 hwnd, msg, wparam, lparam);
1247 });
1248 modifier.SetLifecycleManager(std::move(handler));
1249 engine->lifecycle_manager()->BeginProcessingExit();
1250
1251 engine->Run();
1252
1253 // This delegate will be registered after the lifecycle manager, so it will be
1254 // called only when a message is not consumed by the lifecycle manager. This
1255 // should be called on the second, synthesized WM_CLOSE message that the
1256 // lifecycle manager posts.
1257 engine->window_proc_delegate_manager()->RegisterTopLevelWindowProcDelegate(
1258 [](HWND hwnd, UINT message, WPARAM wpar, LPARAM lpar, void* user_data,
1259 LRESULT* result) {
1260 switch (message) {
1261 case WM_CLOSE: {
1262 bool* called = reinterpret_cast<bool*>(user_data);
1263 *called = true;
1264 return true;
1265 }
1266 }
1267 return false;
1268 },
1269 reinterpret_cast<void*>(&second_close));
1270
1271 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1272 0);
1273
1274 while (!second_close) {
1275 engine->task_runner()->ProcessTasks();
1276 }
1277}
1278
1279TEST_F(FlutterWindowsEngineTest, TestExitCloseMultiWindow) {
1280 FlutterWindowsEngineBuilder builder{GetContext()};
1281 builder.SetDartEntrypoint("exitTestExit");
1282 bool finished = false;
1283
1284 auto engine = builder.Build();
1285 auto window_binding_handler =
1286 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1287 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1288
1289 EngineModifier modifier(engine.get());
1290 modifier.SetImplicitView(&view);
1291 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1292 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1293 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce([&finished]() {
1294 finished = true;
1295 return false;
1296 });
1297 // Quit should not be called when there is more than one window.
1298 EXPECT_CALL(*handler, Quit).Times(0);
1299 modifier.SetLifecycleManager(std::move(handler));
1300 engine->lifecycle_manager()->BeginProcessingExit();
1301
1302 engine->Run();
1303
1304 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1305 0);
1306
1307 while (!finished) {
1308 engine->task_runner()->ProcessTasks();
1309 }
1310}
1311
1312TEST_F(FlutterWindowsEngineTest, LifecycleManagerDisabledByDefault) {
1313 FlutterWindowsEngineBuilder builder{GetContext()};
1314
1315 auto engine = builder.Build();
1316 auto window_binding_handler =
1317 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1318 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1319
1320 EngineModifier modifier(engine.get());
1321 modifier.SetImplicitView(&view);
1322 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1323 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1324 EXPECT_CALL(*handler, IsLastWindowOfProcess).Times(0);
1325 modifier.SetLifecycleManager(std::move(handler));
1326
1327 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1328 0);
1329}
1330
1331TEST_F(FlutterWindowsEngineTest, EnableApplicationLifecycle) {
1332 FlutterWindowsEngineBuilder builder{GetContext()};
1333
1334 auto engine = builder.Build();
1335 auto window_binding_handler =
1336 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1337 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1338
1339 EngineModifier modifier(engine.get());
1340 modifier.SetImplicitView(&view);
1341 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1342 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1343 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1344 modifier.SetLifecycleManager(std::move(handler));
1345 engine->lifecycle_manager()->BeginProcessingExit();
1346
1347 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(0, WM_CLOSE, 0,
1348 0);
1349}
1350
1351TEST_F(FlutterWindowsEngineTest, ApplicationLifecycleExternalWindow) {
1352 FlutterWindowsEngineBuilder builder{GetContext()};
1353
1354 auto engine = builder.Build();
1355 auto window_binding_handler =
1356 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1357 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1358
1359 EngineModifier modifier(engine.get());
1360 modifier.SetImplicitView(&view);
1361 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1362 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1363 EXPECT_CALL(*handler, IsLastWindowOfProcess).WillOnce(Return(false));
1364 modifier.SetLifecycleManager(std::move(handler));
1365 engine->lifecycle_manager()->BeginProcessingExit();
1366
1367 engine->lifecycle_manager()->ExternalWindowMessage(0, WM_CLOSE, 0, 0);
1368}
1369
1370TEST_F(FlutterWindowsEngineTest, LifecycleStateTransition) {
1371 FlutterWindowsEngineBuilder builder{GetContext()};
1372
1373 auto engine = builder.Build();
1374 auto window_binding_handler =
1375 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1376 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1377
1378 EngineModifier modifier(engine.get());
1379 modifier.SetImplicitView(&view);
1380 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1381 engine->Run();
1382
1383 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1384 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1385
1386 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1387 PumpMessage();
1388 }
1389
1390 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1392
1393 engine->lifecycle_manager()->OnWindowStateEvent((HWND)1,
1395
1396 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1397 PumpMessage();
1398 }
1399
1400 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1402
1403 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1404 (HWND)1, WM_SIZE, SIZE_MINIMIZED, 0);
1405
1406 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1407 PumpMessage();
1408 }
1409
1410 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1412
1413 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1414 (HWND)1, WM_SIZE, SIZE_RESTORED, 0);
1415
1416 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1417 PumpMessage();
1418 }
1419
1420 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1422}
1423
1424TEST_F(FlutterWindowsEngineTest, ExternalWindowMessage) {
1425 FlutterWindowsEngineBuilder builder{GetContext()};
1426
1427 auto engine = builder.Build();
1428 auto window_binding_handler =
1429 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1430 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1431
1432 EngineModifier modifier(engine.get());
1433 modifier.SetImplicitView(&view);
1434 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1435 // Sets lifecycle state to resumed.
1436 engine->Run();
1437
1438 // Ensure HWND(1) is in the set of visible windows before hiding it.
1439 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1440 TRUE, NULL);
1441 engine->ProcessExternalWindowMessage(reinterpret_cast<HWND>(1), WM_SHOWWINDOW,
1442 FALSE, NULL);
1443
1444 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1445 PumpMessage();
1446 }
1447
1448 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1450}
1451
1453 FlutterWindowsEngineBuilder builder{GetContext()};
1454 HWND outer = reinterpret_cast<HWND>(1);
1455 HWND inner = reinterpret_cast<HWND>(2);
1456
1457 auto engine = builder.Build();
1458 auto window_binding_handler =
1459 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1460 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1461 ON_CALL(view, GetWindowHandle).WillByDefault([=]() { return inner; });
1462
1463 EngineModifier modifier(engine.get());
1464 modifier.SetImplicitView(&view);
1465 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1466 // Sets lifecycle state to resumed.
1467 engine->Run();
1468
1469 // Show both top-level and Flutter window.
1470 engine->window_proc_delegate_manager()->OnTopLevelWindowProc(
1471 outer, WM_SHOWWINDOW, TRUE, NULL);
1472 view.OnWindowStateEvent(inner, WindowStateEvent::kShow);
1473 view.OnWindowStateEvent(inner, WindowStateEvent::kFocus);
1474
1475 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1476 PumpMessage();
1477 }
1478
1479 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1481
1482 // Hide Flutter window, but not top level window.
1483 view.OnWindowStateEvent(inner, WindowStateEvent::kHide);
1484
1485 while (engine->lifecycle_manager()->IsUpdateStateScheduled()) {
1486 PumpMessage();
1487 }
1488
1489 // The top-level window is still visible, so we ought not enter hidden state.
1490 EXPECT_EQ(engine->lifecycle_manager()->GetLifecycleState(),
1492}
1493
1494TEST_F(FlutterWindowsEngineTest, EnableLifecycleState) {
1495 FlutterWindowsEngineBuilder builder{GetContext()};
1496 builder.SetDartEntrypoint("enableLifecycleTest");
1497 bool finished = false;
1498
1499 auto engine = builder.Build();
1500 auto window_binding_handler =
1501 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1502 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1503
1504 EngineModifier modifier(engine.get());
1505 modifier.SetImplicitView(&view);
1506 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1507 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1508 EXPECT_CALL(*handler, SetLifecycleState)
1509 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1510 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1511 });
1512 modifier.SetLifecycleManager(std::move(handler));
1513
1514 auto binary_messenger =
1515 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1516 // Mark the test only as completed on receiving an inactive state message.
1517 binary_messenger->SetMessageHandler(
1518 "flutter/unittest", [&finished](const uint8_t* message,
1519 size_t message_size, BinaryReply reply) {
1520 std::string contents(message, message + message_size);
1521 EXPECT_NE(contents.find("AppLifecycleState.inactive"),
1522 std::string::npos);
1523 finished = true;
1524 char response[] = "";
1525 reply(reinterpret_cast<uint8_t*>(response), 0);
1526 });
1527
1528 engine->Run();
1529
1530 // Test that setting the state before enabling lifecycle does nothing.
1531 HWND hwnd = reinterpret_cast<HWND>(1);
1532 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1533 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1534 EXPECT_FALSE(finished);
1535
1536 // Test that we can set the state afterwards.
1537
1538 engine->lifecycle_manager()->BeginProcessingLifecycle();
1539 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1540
1541 while (!finished) {
1542 engine->task_runner()->ProcessTasks();
1543 }
1544}
1545
1546TEST_F(FlutterWindowsEngineTest, LifecycleStateToFrom) {
1547 FlutterWindowsEngineBuilder builder{GetContext()};
1548 builder.SetDartEntrypoint("enableLifecycleToFrom");
1549 bool enabled_lifecycle = false;
1550 bool dart_responded = false;
1551
1552 auto engine = builder.Build();
1553 auto window_binding_handler =
1554 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1555 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1556
1557 EngineModifier modifier(engine.get());
1558 modifier.SetImplicitView(&view);
1559 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1560 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1561 EXPECT_CALL(*handler, SetLifecycleState)
1562 .WillRepeatedly([handler_ptr = handler.get()](AppLifecycleState state) {
1563 handler_ptr->WindowsLifecycleManager::SetLifecycleState(state);
1564 });
1565 handler->begin_processing_callback = [&]() { enabled_lifecycle = true; };
1566 modifier.SetLifecycleManager(std::move(handler));
1567
1568 auto binary_messenger =
1569 std::make_unique<BinaryMessengerImpl>(engine->messenger());
1570 binary_messenger->SetMessageHandler(
1571 "flutter/unittest",
1572 [&](const uint8_t* message, size_t message_size, BinaryReply reply) {
1573 std::string contents(message, message + message_size);
1574 EXPECT_NE(contents.find("AppLifecycleState."), std::string::npos);
1575 dart_responded = true;
1576 char response[] = "";
1577 reply(reinterpret_cast<uint8_t*>(response), 0);
1578 });
1579
1580 engine->Run();
1581
1582 while (!enabled_lifecycle) {
1583 engine->task_runner()->ProcessTasks();
1584 }
1585
1586 HWND hwnd = reinterpret_cast<HWND>(1);
1587 view.OnWindowStateEvent(hwnd, WindowStateEvent::kShow);
1588 view.OnWindowStateEvent(hwnd, WindowStateEvent::kHide);
1589
1590 while (!dart_responded) {
1591 engine->task_runner()->ProcessTasks();
1592 }
1593}
1594
1596 FlutterWindowsEngineBuilder builder{GetContext()};
1597 builder.SetDartEntrypoint("enableLifecycleToFrom");
1598
1599 auto engine = builder.Build();
1600 auto window_binding_handler =
1601 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1602 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1603
1604 EngineModifier modifier(engine.get());
1605 modifier.SetImplicitView(&view);
1606 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1607
1608 bool lifecycle_began = false;
1609 auto handler = std::make_unique<MockWindowsLifecycleManager>(engine.get());
1610 handler->begin_processing_callback = [&]() { lifecycle_began = true; };
1611 modifier.SetLifecycleManager(std::move(handler));
1612
1613 engine->Run();
1614
1615 while (!lifecycle_began) {
1616 engine->task_runner()->ProcessTasks();
1617 }
1618}
1619
1620TEST_F(FlutterWindowsEngineTest, ReceivePlatformViewMessage) {
1621 FlutterWindowsEngineBuilder builder{GetContext()};
1622 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1623 auto engine = builder.Build();
1624
1625 EngineModifier modifier{engine.get()};
1626 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1627
1628 bool received_call = false;
1629
1630 auto manager = std::make_unique<MockPlatformViewManager>(engine.get());
1631 EXPECT_CALL(*manager, AddPlatformView)
1632 .WillOnce([&](PlatformViewId id, std::string_view type_name) {
1633 received_call = true;
1634 return true;
1635 });
1636 modifier.SetPlatformViewPlugin(std::move(manager));
1637
1638 engine->Run();
1639
1640 while (!received_call) {
1641 engine->task_runner()->ProcessTasks();
1642 }
1643}
1644
1645TEST_F(FlutterWindowsEngineTest, AddViewFailureDoesNotHang) {
1646 FlutterWindowsEngineBuilder builder{GetContext()};
1647 auto engine = builder.Build();
1648
1649 EngineModifier modifier{engine.get()};
1650
1651 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1652 modifier.embedder_api().AddView = MOCK_ENGINE_PROC(
1653 AddView,
1655 const FlutterAddViewInfo* info) { return kInternalInconsistency; });
1656
1657 ASSERT_TRUE(engine->Run());
1658
1659 // Create the first view. This is the implicit view and isn't added to the
1660 // engine.
1661 auto implicit_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1662
1663 std::unique_ptr<FlutterWindowsView> implicit_view =
1664 engine->CreateView(std::move(implicit_window),
1665 /*is_sized_to_content=*/false, BoxConstraints());
1666
1667 EXPECT_TRUE(implicit_view);
1668
1669 // Create a second view. The embedder attempts to add it to the engine.
1670 auto second_window = std::make_unique<NiceMock<MockWindowBindingHandler>>();
1671
1672 EXPECT_DEBUG_DEATH(
1673 engine->CreateView(std::move(second_window),
1674 /*is_sized_to_content=*/false, BoxConstraints()),
1675 "FlutterEngineAddView returned an unexpected result");
1676}
1677
1678TEST_F(FlutterWindowsEngineTest, RemoveViewFailureDoesNotHang) {
1679 FlutterWindowsEngineBuilder builder{GetContext()};
1680 builder.SetDartEntrypoint("sendCreatePlatformViewMethod");
1681 auto engine = builder.Build();
1682
1683 EngineModifier modifier{engine.get()};
1684
1685 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1686 modifier.embedder_api().RemoveView = MOCK_ENGINE_PROC(
1687 RemoveView,
1689 const FlutterRemoveViewInfo* info) { return kInternalInconsistency; });
1690
1691 ASSERT_TRUE(engine->Run());
1692 EXPECT_DEBUG_DEATH(engine->RemoveView(123),
1693 "FlutterEngineRemoveView returned an unexpected result");
1694}
1695
1697 auto& context = GetContext();
1699 builder.SetDartEntrypoint("mergedUIThread");
1700 builder.SetUIThreadPolicy(FlutterDesktopUIThreadPolicy::RunOnPlatformThread);
1701
1702 std::optional<std::thread::id> ui_thread_id;
1703
1704 auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
1705 ui_thread_id = std::this_thread::get_id();
1706 });
1707 context.AddNativeFunction("Signal", native_entry);
1708
1709 EnginePtr engine{builder.RunHeadless()};
1710 while (!ui_thread_id) {
1711 PumpMessage();
1712 }
1713 ASSERT_EQ(*ui_thread_id, std::this_thread::get_id());
1714}
1715
1716TEST_F(FlutterWindowsEngineTest, OnViewFocusChangeRequest) {
1717 FlutterWindowsEngineBuilder builder{GetContext()};
1718 std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
1719 auto window_binding_handler =
1720 std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
1721 MockFlutterWindowsView view(engine.get(), std::move(window_binding_handler));
1722
1723 EngineModifier modifier(engine.get());
1724 modifier.SetImplicitView(&view);
1725
1727 request.view_id = kImplicitViewId;
1728
1729 EXPECT_CALL(view, Focus()).WillOnce(Return(true));
1730 modifier.OnViewFocusChangeRequest(&request);
1731}
1732
1733TEST_F(FlutterWindowsEngineTest, UpdateSemanticsMultiView) {
1734 auto& context = GetContext();
1736 builder.SetDartEntrypoint("sendSemanticsTreeInfo");
1737
1738 // Setup: a signal for when we have send out all of our semantics updates
1739 bool done = false;
1740 auto native_entry =
1741 CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { done = true; });
1742 context.AddNativeFunction("Signal", native_entry);
1743
1744 // Setup: Create the engine and two views + enable semantics
1745 EnginePtr engine{builder.RunHeadless()};
1746 ASSERT_NE(engine, nullptr);
1747
1748 auto window_binding_handler1 =
1749 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1750 auto window_binding_handler2 =
1751 std::make_unique<NiceMock<MockWindowBindingHandler>>();
1752
1753 // The following mocks are required by
1754 // FlutterWindowsView::CreateWindowMetricsEvent so that we create a valid
1755 // view.
1756 EXPECT_CALL(*window_binding_handler1, GetPhysicalWindowBounds)
1757 .WillRepeatedly(testing::Return(PhysicalWindowBounds{100, 100}));
1758 EXPECT_CALL(*window_binding_handler1, GetDpiScale)
1759 .WillRepeatedly(testing::Return(96.0));
1760 EXPECT_CALL(*window_binding_handler2, GetPhysicalWindowBounds)
1761 .WillRepeatedly(testing::Return(PhysicalWindowBounds{200, 200}));
1762 EXPECT_CALL(*window_binding_handler2, GetDpiScale)
1763 .WillRepeatedly(testing::Return(96.0));
1764
1765 auto windows_engine = reinterpret_cast<FlutterWindowsEngine*>(engine.get());
1766 EngineModifier modifier{windows_engine};
1767 modifier.embedder_api().RunsAOTCompiledDartCode = []() { return false; };
1768
1769 // We want to avoid adding an implicit view as the first view
1770 modifier.SetNextViewId(kImplicitViewId + 1);
1771
1772 auto view1 = windows_engine->CreateView(std::move(window_binding_handler1),
1773 /*is_sized_to_content=*/false,
1774 BoxConstraints());
1775 auto view2 = windows_engine->CreateView(std::move(window_binding_handler2),
1776 /*is_sized_to_content=*/false,
1777 BoxConstraints());
1778
1779 // Act: UpdateSemanticsEnabled will trigger the semantics updates
1780 // to get sent.
1781 windows_engine->UpdateSemanticsEnabled(true);
1782
1783 while (!done) {
1784 windows_engine->task_runner()->ProcessTasks();
1785 }
1786
1787 auto accessibility_bridge1 = view1->accessibility_bridge().lock();
1788 auto accessibility_bridge2 = view2->accessibility_bridge().lock();
1789
1790 // Expect: that the semantics trees are updated with their
1791 // respective nodes.
1792 while (
1793 !accessibility_bridge1->GetPlatformNodeFromTree(view1->view_id() + 1)) {
1794 windows_engine->task_runner()->ProcessTasks();
1795 }
1796
1797 while (
1798 !accessibility_bridge2->GetPlatformNodeFromTree(view2->view_id() + 1)) {
1799 windows_engine->task_runner()->ProcessTasks();
1800 }
1801
1802 // Rely on timeout mechanism in CI.
1803 auto tree1 = accessibility_bridge1->GetTree();
1804 auto tree2 = accessibility_bridge2->GetTree();
1805 EXPECT_NE(tree1->GetFromId(view1->view_id() + 1), nullptr);
1806 EXPECT_NE(tree2->GetFromId(view2->view_id() + 1), nullptr);
1807}
1808
1809} // namespace testing
1810} // namespace flutter
void SetLifecycleManager(std::unique_ptr< WindowsLifecycleManager > &&handler)
void SetFrameInterval(uint64_t frame_interval_nanos)
void OnViewFocusChangeRequest(const FlutterViewFocusChangeRequest *request)
void SetEGLManager(std::unique_ptr< egl::Manager > egl_manager)
void SetStartTime(uint64_t start_time_nanos)
Reset the start_time field that is used to align vsync events.
FlutterEngineProcTable & embedder_api()
void SetImplicitView(FlutterWindowsView *view)
virtual void Quit(std::optional< HWND > window, std::optional< WPARAM > wparam, std::optional< LPARAM > lparam, UINT exit_code)
virtual void SetLifecycleState(AppLifecycleState state)
void SetSwitches(std::vector< std::string > switches)
void SetImpellerSwitch(FlutterDesktopImpellerSwitch impeller_switch)
void SetWindowsProcTable(std::shared_ptr< WindowsProcTable > windows_proc_table)
MOCK_METHOD(bool, Focus,(),(override))
MOCK_METHOD(void, NotifyWinEventWrapper,(ui::AXPlatformNodeWin *, ax::mojom::Event),(override))
MockFlutterWindowsView(FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > wbh)
MOCK_METHOD(HWND, GetWindowHandle,(),(const, override))
MOCK_METHOD(void, DispatchMessage,(HWND, UINT, WPARAM, LPARAM),(override))
MOCK_METHOD(void, Quit,(std::optional< HWND >, std::optional< WPARAM >, std::optional< LPARAM >, UINT),(override))
MOCK_METHOD(void, SetLifecycleState,(AppLifecycleState),(override))
MOCK_METHOD(bool, IsLastWindowOfProcess,(),(override))
void SetDartEntrypoint(std::string_view entrypoint)
static MallocMapping Copy(const T *begin, const T *end)
Definition mapping.h:162
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
constexpr int64_t ToNanoseconds() const
Definition time_delta.h:61
constexpr TimeDelta ToEpochDelta() const
Definition time_point.h:52
static TimePoint Now()
Definition time_point.cc:49
std::string type_name
#define FLUTTER_API_SYMBOL(symbol)
Definition embedder.h:67
@ kOpenGL
Definition embedder.h:80
FlutterAccessibilityFeature
Definition embedder.h:91
@ kFlutterAccessibilityFeatureHighContrast
Request that UI be rendered with darker colors.
Definition embedder.h:105
@ kInternalInconsistency
Definition embedder.h:76
FlutterEngineDisplaysUpdateType
Definition embedder.h:2373
@ kFlutterEngineDisplaysUpdateTypeStartup
Definition embedder.h:2379
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
Definition embedder.h:378
@ kDisplay
Suitable for threads which generate data for the display.
Definition embedder.h:382
@ kNormal
Default priority level.
Definition embedder.h:380
@ kRaster
Suitable for thread which raster data.
Definition embedder.h:384
@ kFlutterSemanticsActionDismiss
A request that the node should be dismissed.
Definition embedder.h:167
#define FLUTTER_ENGINE_VERSION
Definition embedder.h:70
GLFWwindow * window
Definition main.cc:60
FlutterEngine engine
Definition main.cc:84
FlView * view
const char * message
if(engine==nullptr)
return TRUE
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar * channel
const gchar FlBinaryMessengerMessageHandler handler
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
@ RunOnPlatformThread
@ DefaultImpeller
@ EnabledImpeller
@ DisabledImpeller
int64_t PlatformViewId
FlutterDesktopBinaryReply callback
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
size_t length
TEST_F(DisplayListTest, Defaults)
std::unique_ptr< FlutterDesktopEngine, EngineDeleter > EnginePtr
std::unique_ptr< FlutterDesktopViewController, ViewControllerDeleter > ViewControllerPtr
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
constexpr int64_t kImplicitViewId
UINT GetDpiForMonitor(HMONITOR monitor)
Definition dpi_utils.cc:132
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
static void DispatchSemanticsAction(JNIEnv *env, jobject jcaller, jlong shell_holder, jint id, jint action, jobject args, jint args_position)
std::function< void(const uint8_t *reply, size_t reply_size)> BinaryReply
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
static void WindowsPlatformThreadPrioritySetter(FlutterThreadPriority priority)
static void ScheduleFrame(JNIEnv *env, jobject jcaller, jlong shell_holder)
Definition ref_ptr.h:261
#define MOCK_ENGINE_PROC(proc, mock_impl)
std::shared_ptr< ContextGLES > context
FlutterEngineScheduleFrameFnPtr ScheduleFrame
Definition embedder.h:3805
FlutterEnginePlatformMessageReleaseResponseHandleFnPtr PlatformMessageReleaseResponseHandle
Definition embedder.h:3781
FlutterEngineUpdateLocalesFnPtr UpdateLocales
Definition embedder.h:3798
FlutterEngineRunsAOTCompiledDartCodeFnPtr RunsAOTCompiledDartCode
Definition embedder.h:3799
FlutterEngineSetNextFrameCallbackFnPtr SetNextFrameCallback
Definition embedder.h:3806
FlutterEngineShutdownFnPtr Shutdown
Definition embedder.h:3770
FlutterEngineOnVsyncFnPtr OnVsync
Definition embedder.h:3790
FlutterEngineGetCurrentTimeFnPtr GetCurrentTime
Definition embedder.h:3796
FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate
Definition embedder.h:3804
FlutterEngineSendPlatformMessageFnPtr SendPlatformMessage
Definition embedder.h:3777
FlutterEnginePlatformMessageCreateResponseHandleFnPtr PlatformMessageCreateResponseHandle
Definition embedder.h:3779
FlutterEngineRunFnPtr Run
Definition embedder.h:3769
FlutterEngineUpdateAccessibilityFeaturesFnPtr UpdateAccessibilityFeatures
Definition embedder.h:3788
FlutterEnginePostRenderThreadTaskFnPtr PostRenderThreadTask
Definition embedder.h:3795
FlutterEngineSendSemanticsActionFnPtr SendSemanticsAction
Definition embedder.h:3810
FlutterRendererType type
Definition embedder.h:1038
FlutterViewId view_id
The identifier of the view that received the focus event.
Definition embedder.h:1257
std::string str() const
Definition logging.cc:102
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef controller)
const size_t start
#define CREATE_NATIVE_ENTRY(native_entry)
struct tagMSG MSG
LONG_PTR LRESULT
unsigned int UINT
LONG_PTR LPARAM
#define GetCurrentTime()
#define GetMessage
UINT_PTR WPARAM
#define DispatchMessage
unsigned long DWORD