Flutter Linux Embedder
fl_engine_test.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 // Included first as it collides with the X11 headers.
6 #include "gtest/gtest.h"
7 
8 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
13 
14 // MOCK_ENGINE_PROC is leaky by design
15 // NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
16 
17 // Checks notifying display updates works.
18 TEST(FlEngineTest, NotifyDisplayUpdate) {
19  g_autoptr(FlDartProject) project = fl_dart_project_new();
20  g_autoptr(FlEngine) engine = fl_engine_new(project);
21 
22  g_autoptr(GError) error = nullptr;
23  EXPECT_TRUE(fl_engine_start(engine, &error));
24  EXPECT_EQ(error, nullptr);
25 
26  bool called = false;
27  fl_engine_get_embedder_api(engine)->NotifyDisplayUpdate = MOCK_ENGINE_PROC(
28  NotifyDisplayUpdate,
29  ([&called](auto engine, FlutterEngineDisplaysUpdateType update_type,
30  const FlutterEngineDisplay* displays, size_t displays_length) {
31  called = true;
32  EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
33  EXPECT_EQ(displays_length, 2u);
34 
35  EXPECT_EQ(displays[0].display_id, 1u);
36  EXPECT_EQ(displays[0].refresh_rate, 60);
37  EXPECT_EQ(displays[0].width, 1024u);
38  EXPECT_EQ(displays[0].height, 768u);
39  EXPECT_EQ(displays[0].device_pixel_ratio, 1.0);
40 
41  EXPECT_EQ(displays[1].display_id, 2u);
42  EXPECT_EQ(displays[1].refresh_rate, 120);
43  EXPECT_EQ(displays[1].width, 3840u);
44  EXPECT_EQ(displays[1].height, 2160u);
45  EXPECT_EQ(displays[1].device_pixel_ratio, 2.0);
46 
47  return kSuccess;
48  }));
49 
50  FlutterEngineDisplay displays[2] = {
51  {
52  .struct_size = sizeof(FlutterEngineDisplay),
53  .display_id = 1,
54  .single_display = false,
55  .refresh_rate = 60.0,
56  .width = 1024,
57  .height = 768,
58  .device_pixel_ratio = 1.0,
59  },
60  {
61  .struct_size = sizeof(FlutterEngineDisplay),
62  .display_id = 2,
63  .single_display = false,
64  .refresh_rate = 120.0,
65  .width = 3840,
66  .height = 2160,
67  .device_pixel_ratio = 2.0,
68  }};
69  fl_engine_notify_display_update(engine, displays, 2);
70 
71  EXPECT_TRUE(called);
72 }
73 
74 // Checks sending window metrics events works.
75 TEST(FlEngineTest, WindowMetrics) {
76  g_autoptr(FlDartProject) project = fl_dart_project_new();
77  g_autoptr(FlEngine) engine = fl_engine_new(project);
78 
79  g_autoptr(GError) error = nullptr;
80  EXPECT_TRUE(fl_engine_start(engine, &error));
81  EXPECT_EQ(error, nullptr);
82 
83  bool called = false;
84  fl_engine_get_embedder_api(engine)->SendWindowMetricsEvent = MOCK_ENGINE_PROC(
85  SendWindowMetricsEvent,
86  ([&called](auto engine, const FlutterWindowMetricsEvent* event) {
87  called = true;
88  EXPECT_EQ(event->display_id, 99u);
89  EXPECT_EQ(event->view_id, 1);
90  EXPECT_EQ(event->width, static_cast<size_t>(3840));
91  EXPECT_EQ(event->height, static_cast<size_t>(2160));
92  EXPECT_EQ(event->pixel_ratio, 2.0);
93 
94  return kSuccess;
95  }));
96 
97  fl_engine_send_window_metrics_event(engine, 99, 1, 3840, 2160, 2.0);
98 
99  EXPECT_TRUE(called);
100 }
101 
102 // Checks sending mouse pointer events works.
103 TEST(FlEngineTest, MousePointer) {
104  g_autoptr(FlDartProject) project = fl_dart_project_new();
105  g_autoptr(FlEngine) engine = fl_engine_new(project);
106 
107  bool called = false;
108  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
109  SendPointerEvent,
110  ([&called](auto engine, const FlutterPointerEvent* events,
111  size_t events_count) {
112  called = true;
113  EXPECT_EQ(events_count, static_cast<size_t>(1));
114  EXPECT_EQ(events[0].view_id, 1);
115  EXPECT_EQ(events[0].phase, kDown);
116  EXPECT_EQ(events[0].timestamp, static_cast<size_t>(1234567890));
117  EXPECT_EQ(events[0].x, 800);
118  EXPECT_EQ(events[0].y, 600);
119  EXPECT_EQ(events[0].device, static_cast<int32_t>(0));
120  EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindScroll);
121  EXPECT_EQ(events[0].scroll_delta_x, 1.2);
122  EXPECT_EQ(events[0].scroll_delta_y, -3.4);
123  EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindMouse);
124  EXPECT_EQ(events[0].buttons, kFlutterPointerButtonMouseSecondary);
125 
126  return kSuccess;
127  }));
128 
129  g_autoptr(GError) error = nullptr;
130  EXPECT_TRUE(fl_engine_start(engine, &error));
131  EXPECT_EQ(error, nullptr);
132  fl_engine_send_mouse_pointer_event(engine, 1, kDown, 1234567890, 800, 600,
133  kFlutterPointerDeviceKindMouse, 1.2, -3.4,
134  kFlutterPointerButtonMouseSecondary);
135 
136  EXPECT_TRUE(called);
137 }
138 
139 // Checks sending pan/zoom events works.
140 TEST(FlEngineTest, PointerPanZoom) {
141  g_autoptr(FlDartProject) project = fl_dart_project_new();
142  g_autoptr(FlEngine) engine = fl_engine_new(project);
143 
144  bool called = false;
145  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
146  SendPointerEvent,
147  ([&called](auto engine, const FlutterPointerEvent* events,
148  size_t events_count) {
149  called = true;
150  EXPECT_EQ(events_count, static_cast<size_t>(1));
151  EXPECT_EQ(events[0].view_id, 1);
152  EXPECT_EQ(events[0].phase, kPanZoomUpdate);
153  EXPECT_EQ(events[0].timestamp, static_cast<size_t>(1234567890));
154  EXPECT_EQ(events[0].x, 800);
155  EXPECT_EQ(events[0].y, 600);
156  EXPECT_EQ(events[0].device, static_cast<int32_t>(1));
157  EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindNone);
158  EXPECT_EQ(events[0].pan_x, 1.5);
159  EXPECT_EQ(events[0].pan_y, 2.5);
160  EXPECT_EQ(events[0].scale, 3.5);
161  EXPECT_EQ(events[0].rotation, 4.5);
162  EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindTrackpad);
163  EXPECT_EQ(events[0].buttons, 0);
164 
165  return kSuccess;
166  }));
167 
168  g_autoptr(GError) error = nullptr;
169  EXPECT_TRUE(fl_engine_start(engine, &error));
170  EXPECT_EQ(error, nullptr);
171  fl_engine_send_pointer_pan_zoom_event(engine, 1, 1234567890, 800, 600,
172  kPanZoomUpdate, 1.5, 2.5, 3.5, 4.5);
173 
174  EXPECT_TRUE(called);
175 }
176 
177 // Checks dispatching a semantics action works.
178 TEST(FlEngineTest, DispatchSemanticsAction) {
179  g_autoptr(FlDartProject) project = fl_dart_project_new();
180  g_autoptr(FlEngine) engine = fl_engine_new(project);
181 
182  bool called = false;
183  fl_engine_get_embedder_api(engine)->DispatchSemanticsAction =
184  MOCK_ENGINE_PROC(
185  DispatchSemanticsAction,
186  ([&called](auto engine, uint64_t id, FlutterSemanticsAction action,
187  const uint8_t* data, size_t data_length) {
188  EXPECT_EQ(id, static_cast<uint64_t>(42));
189  EXPECT_EQ(action, kFlutterSemanticsActionTap);
190  EXPECT_EQ(data_length, static_cast<size_t>(4));
191  EXPECT_EQ(data[0], 't');
192  EXPECT_EQ(data[1], 'e');
193  EXPECT_EQ(data[2], 's');
194  EXPECT_EQ(data[3], 't');
195  called = true;
196 
197  return kSuccess;
198  }));
199 
200  g_autoptr(GError) error = nullptr;
201  EXPECT_TRUE(fl_engine_start(engine, &error));
202  EXPECT_EQ(error, nullptr);
203  g_autoptr(GBytes) data = g_bytes_new_static("test", 4);
204  fl_engine_dispatch_semantics_action(engine, 42, kFlutterSemanticsActionTap,
205  data);
206 
207  EXPECT_TRUE(called);
208 }
209 
210 // Checks sending platform messages works.
211 TEST(FlEngineTest, PlatformMessage) {
212  g_autoptr(FlDartProject) project = fl_dart_project_new();
213  g_autoptr(FlEngine) engine = fl_engine_new(project);
214 
215  bool called = false;
216  FlutterEngineSendPlatformMessageFnPtr old_handler =
217  fl_engine_get_embedder_api(engine)->SendPlatformMessage;
218  fl_engine_get_embedder_api(engine)->SendPlatformMessage = MOCK_ENGINE_PROC(
219  SendPlatformMessage,
220  ([&called, old_handler](auto engine,
221  const FlutterPlatformMessage* message) {
222  if (strcmp(message->channel, "test") != 0) {
223  return old_handler(engine, message);
224  }
225 
226  called = true;
227 
228  EXPECT_EQ(message->message_size, static_cast<size_t>(4));
229  EXPECT_EQ(message->message[0], 't');
230  EXPECT_EQ(message->message[1], 'e');
231  EXPECT_EQ(message->message[2], 's');
232  EXPECT_EQ(message->message[3], 't');
233 
234  return kSuccess;
235  }));
236 
237  g_autoptr(GError) error = nullptr;
238  EXPECT_TRUE(fl_engine_start(engine, &error));
239  EXPECT_EQ(error, nullptr);
240  g_autoptr(GBytes) message = g_bytes_new_static("test", 4);
241  fl_engine_send_platform_message(engine, "test", message, nullptr, nullptr,
242  nullptr);
243 
244  EXPECT_TRUE(called);
245 }
246 
247 // Checks sending platform message responses works.
248 TEST(FlEngineTest, PlatformMessageResponse) {
249  g_autoptr(FlDartProject) project = fl_dart_project_new();
250  g_autoptr(FlEngine) engine = fl_engine_new(project);
251 
252  bool called = false;
253  fl_engine_get_embedder_api(engine)->SendPlatformMessageResponse =
254  MOCK_ENGINE_PROC(
255  SendPlatformMessageResponse,
256  ([&called](auto engine,
257  const FlutterPlatformMessageResponseHandle* handle,
258  const uint8_t* data, size_t data_length) {
259  called = true;
260 
261  EXPECT_EQ(
262  handle,
263  reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(
264  42));
265  EXPECT_EQ(data_length, static_cast<size_t>(4));
266  EXPECT_EQ(data[0], 't');
267  EXPECT_EQ(data[1], 'e');
268  EXPECT_EQ(data[2], 's');
269  EXPECT_EQ(data[3], 't');
270 
271  return kSuccess;
272  }));
273 
274  g_autoptr(GError) error = nullptr;
275  EXPECT_TRUE(fl_engine_start(engine, &error));
276  EXPECT_EQ(error, nullptr);
277  g_autoptr(GBytes) response = g_bytes_new_static("test", 4);
279  engine, reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(42),
280  response, &error));
281  EXPECT_EQ(error, nullptr);
282 
283  EXPECT_TRUE(called);
284 }
285 
286 // Checks settings handler sends settings on startup.
287 TEST(FlEngineTest, SettingsHandler) {
288  g_autoptr(FlDartProject) project = fl_dart_project_new();
289  g_autoptr(FlEngine) engine = fl_engine_new(project);
290 
291  bool called = false;
292  fl_engine_get_embedder_api(engine)->SendPlatformMessage = MOCK_ENGINE_PROC(
293  SendPlatformMessage,
294  ([&called](auto engine, const FlutterPlatformMessage* message) {
295  called = true;
296 
297  EXPECT_STREQ(message->channel, "flutter/settings");
298 
299  g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new();
300  g_autoptr(GBytes) data =
301  g_bytes_new(message->message, message->message_size);
302  g_autoptr(GError) error = nullptr;
303  g_autoptr(FlValue) settings = fl_message_codec_decode_message(
304  FL_MESSAGE_CODEC(codec), data, &error);
305  EXPECT_NE(settings, nullptr);
306  EXPECT_EQ(error, nullptr);
307 
308  FlValue* text_scale_factor =
309  fl_value_lookup_string(settings, "textScaleFactor");
310  EXPECT_NE(text_scale_factor, nullptr);
311  EXPECT_EQ(fl_value_get_type(text_scale_factor), FL_VALUE_TYPE_FLOAT);
312 
313  FlValue* always_use_24hr_format =
314  fl_value_lookup_string(settings, "alwaysUse24HourFormat");
315  EXPECT_NE(always_use_24hr_format, nullptr);
316  EXPECT_EQ(fl_value_get_type(always_use_24hr_format),
318 
319  FlValue* platform_brightness =
320  fl_value_lookup_string(settings, "platformBrightness");
321  EXPECT_NE(platform_brightness, nullptr);
322  EXPECT_EQ(fl_value_get_type(platform_brightness), FL_VALUE_TYPE_STRING);
323 
324  return kSuccess;
325  }));
326 
327  g_autoptr(GError) error = nullptr;
328  EXPECT_TRUE(fl_engine_start(engine, &error));
329  EXPECT_EQ(error, nullptr);
330 
331  EXPECT_TRUE(called);
332 }
333 
334 void on_pre_engine_restart_cb(FlEngine* engine, gpointer user_data) {
335  int* count = reinterpret_cast<int*>(user_data);
336  *count += 1;
337 }
338 
339 // Checks restarting the engine invokes the correct callback.
340 TEST(FlEngineTest, OnPreEngineRestart) {
341  g_autoptr(FlDartProject) project = fl_dart_project_new();
342  g_autoptr(FlEngine) engine = fl_engine_new(project);
343 
344  OnPreEngineRestartCallback callback;
345  void* callback_user_data;
346 
347  bool called = false;
348  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
349  Initialize, ([&callback, &callback_user_data, &called](
350  size_t version, const FlutterRendererConfig* config,
351  const FlutterProjectArgs* args, void* user_data,
352  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
353  called = true;
354  callback = args->on_pre_engine_restart_callback;
355  callback_user_data = user_data;
356 
357  return kSuccess;
358  }));
359  fl_engine_get_embedder_api(engine)->RunInitialized =
360  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
361 
362  g_autoptr(GError) error = nullptr;
363  EXPECT_TRUE(fl_engine_start(engine, &error));
364  EXPECT_EQ(error, nullptr);
365 
366  EXPECT_TRUE(called);
367  EXPECT_NE(callback, nullptr);
368 
369  // The following call has no effect but should not crash.
370  callback(callback_user_data);
371 
372  int count = 0;
373 
374  // Set handler so that:
375  //
376  // * When the engine restarts, count += 1;
377  // * When the engine is freed, count += 10.
378  g_signal_connect(engine, "on-pre-engine-restart",
379  G_CALLBACK(on_pre_engine_restart_cb), &count);
380 
381  callback(callback_user_data);
382  EXPECT_EQ(count, 1);
383 }
384 
385 TEST(FlEngineTest, DartEntrypointArgs) {
386  GPtrArray* args_array = g_ptr_array_new();
387  g_ptr_array_add(args_array, const_cast<char*>("arg_one"));
388  g_ptr_array_add(args_array, const_cast<char*>("arg_two"));
389  g_ptr_array_add(args_array, const_cast<char*>("arg_three"));
390  g_ptr_array_add(args_array, nullptr);
391  gchar** args = reinterpret_cast<gchar**>(g_ptr_array_free(args_array, false));
392 
393  g_autoptr(FlDartProject) project = fl_dart_project_new();
395  g_autoptr(FlEngine) engine = fl_engine_new(project);
396 
397  bool called = false;
398  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
399  Initialize, ([&called, &set_args = args](
400  size_t version, const FlutterRendererConfig* config,
401  const FlutterProjectArgs* args, void* user_data,
402  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
403  called = true;
404  EXPECT_NE(set_args, args->dart_entrypoint_argv);
405  EXPECT_EQ(args->dart_entrypoint_argc, 3);
406 
407  return kSuccess;
408  }));
409  fl_engine_get_embedder_api(engine)->RunInitialized =
410  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
411 
412  g_autoptr(GError) error = nullptr;
413  EXPECT_TRUE(fl_engine_start(engine, &error));
414  EXPECT_EQ(error, nullptr);
415 
416  EXPECT_TRUE(called);
417 }
418 
419 TEST(FlEngineTest, EngineId) {
420  g_autoptr(FlDartProject) project = fl_dart_project_new();
421  g_autoptr(FlEngine) engine = fl_engine_new(project);
422  int64_t engine_id;
423  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
424  Initialize,
425  ([&engine_id](size_t version, const FlutterRendererConfig* config,
426  const FlutterProjectArgs* args, void* user_data,
427  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
428  engine_id = args->engine_id;
429  return kSuccess;
430  }));
431  fl_engine_get_embedder_api(engine)->RunInitialized =
432  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
433 
434  g_autoptr(GError) error = nullptr;
435  EXPECT_TRUE(fl_engine_start(engine, &error));
436  EXPECT_EQ(error, nullptr);
437  EXPECT_TRUE(engine_id != 0);
438 
439  EXPECT_EQ(fl_engine_for_id(engine_id), engine);
440 }
441 
442 TEST(FlEngineTest, Locales) {
443  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
444  g_setenv("LANGUAGE", "de:en_US", TRUE);
445  g_autoptr(FlDartProject) project = fl_dart_project_new();
446 
447  g_autoptr(FlEngine) engine = fl_engine_new(project);
448 
449  bool called = false;
450  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
451  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
452  size_t locales_count) {
453  called = true;
454 
455  EXPECT_EQ(locales_count, static_cast<size_t>(4));
456 
457  EXPECT_STREQ(locales[0]->language_code, "de");
458  EXPECT_STREQ(locales[0]->country_code, nullptr);
459  EXPECT_STREQ(locales[0]->script_code, nullptr);
460  EXPECT_STREQ(locales[0]->variant_code, nullptr);
461 
462  EXPECT_STREQ(locales[1]->language_code, "en");
463  EXPECT_STREQ(locales[1]->country_code, "US");
464  EXPECT_STREQ(locales[1]->script_code, nullptr);
465  EXPECT_STREQ(locales[1]->variant_code, nullptr);
466 
467  EXPECT_STREQ(locales[2]->language_code, "en");
468  EXPECT_STREQ(locales[2]->country_code, nullptr);
469  EXPECT_STREQ(locales[2]->script_code, nullptr);
470  EXPECT_STREQ(locales[2]->variant_code, nullptr);
471 
472  EXPECT_STREQ(locales[3]->language_code, "C");
473  EXPECT_STREQ(locales[3]->country_code, nullptr);
474  EXPECT_STREQ(locales[3]->script_code, nullptr);
475  EXPECT_STREQ(locales[3]->variant_code, nullptr);
476 
477  return kSuccess;
478  }));
479 
480  g_autoptr(GError) error = nullptr;
481  EXPECT_TRUE(fl_engine_start(engine, &error));
482  EXPECT_EQ(error, nullptr);
483 
484  EXPECT_TRUE(called);
485 
486  if (initial_language) {
487  g_setenv("LANGUAGE", initial_language, TRUE);
488  } else {
489  g_unsetenv("LANGUAGE");
490  }
491 }
492 
493 TEST(FlEngineTest, CLocale) {
494  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
495  g_setenv("LANGUAGE", "C", TRUE);
496  g_autoptr(FlDartProject) project = fl_dart_project_new();
497 
498  g_autoptr(FlEngine) engine = fl_engine_new(project);
499 
500  bool called = false;
501  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
502  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
503  size_t locales_count) {
504  called = true;
505 
506  EXPECT_EQ(locales_count, static_cast<size_t>(1));
507 
508  EXPECT_STREQ(locales[0]->language_code, "C");
509  EXPECT_STREQ(locales[0]->country_code, nullptr);
510  EXPECT_STREQ(locales[0]->script_code, nullptr);
511  EXPECT_STREQ(locales[0]->variant_code, nullptr);
512 
513  return kSuccess;
514  }));
515 
516  g_autoptr(GError) error = nullptr;
517  EXPECT_TRUE(fl_engine_start(engine, &error));
518  EXPECT_EQ(error, nullptr);
519 
520  EXPECT_TRUE(called);
521 
522  if (initial_language) {
523  g_setenv("LANGUAGE", initial_language, TRUE);
524  } else {
525  g_unsetenv("LANGUAGE");
526  }
527 }
528 
529 TEST(FlEngineTest, DuplicateLocale) {
530  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
531  g_setenv("LANGUAGE", "en:en", TRUE);
532  g_autoptr(FlDartProject) project = fl_dart_project_new();
533 
534  g_autoptr(FlEngine) engine = fl_engine_new(project);
535 
536  bool called = false;
537  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
538  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
539  size_t locales_count) {
540  called = true;
541 
542  EXPECT_EQ(locales_count, static_cast<size_t>(2));
543 
544  EXPECT_STREQ(locales[0]->language_code, "en");
545  EXPECT_STREQ(locales[0]->country_code, nullptr);
546  EXPECT_STREQ(locales[0]->script_code, nullptr);
547  EXPECT_STREQ(locales[0]->variant_code, nullptr);
548 
549  EXPECT_STREQ(locales[1]->language_code, "C");
550  EXPECT_STREQ(locales[1]->country_code, nullptr);
551  EXPECT_STREQ(locales[1]->script_code, nullptr);
552  EXPECT_STREQ(locales[1]->variant_code, nullptr);
553 
554  return kSuccess;
555  }));
556 
557  g_autoptr(GError) error = nullptr;
558  EXPECT_TRUE(fl_engine_start(engine, &error));
559  EXPECT_EQ(error, nullptr);
560 
561  EXPECT_TRUE(called);
562 
563  if (initial_language) {
564  g_setenv("LANGUAGE", initial_language, TRUE);
565  } else {
566  g_unsetenv("LANGUAGE");
567  }
568 }
569 
570 TEST(FlEngineTest, EmptyLocales) {
571  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
572  g_setenv("LANGUAGE", "de:: :en_US", TRUE);
573  g_autoptr(FlDartProject) project = fl_dart_project_new();
574 
575  g_autoptr(FlEngine) engine = fl_engine_new(project);
576 
577  bool called = false;
578  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
579  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
580  size_t locales_count) {
581  called = true;
582 
583  EXPECT_EQ(locales_count, static_cast<size_t>(4));
584 
585  EXPECT_STREQ(locales[0]->language_code, "de");
586  EXPECT_STREQ(locales[0]->country_code, nullptr);
587  EXPECT_STREQ(locales[0]->script_code, nullptr);
588  EXPECT_STREQ(locales[0]->variant_code, nullptr);
589 
590  EXPECT_STREQ(locales[1]->language_code, "en");
591  EXPECT_STREQ(locales[1]->country_code, "US");
592  EXPECT_STREQ(locales[1]->script_code, nullptr);
593  EXPECT_STREQ(locales[1]->variant_code, nullptr);
594 
595  EXPECT_STREQ(locales[2]->language_code, "en");
596  EXPECT_STREQ(locales[2]->country_code, nullptr);
597  EXPECT_STREQ(locales[2]->script_code, nullptr);
598  EXPECT_STREQ(locales[2]->variant_code, nullptr);
599 
600  EXPECT_STREQ(locales[3]->language_code, "C");
601  EXPECT_STREQ(locales[3]->country_code, nullptr);
602  EXPECT_STREQ(locales[3]->script_code, nullptr);
603  EXPECT_STREQ(locales[3]->variant_code, nullptr);
604 
605  return kSuccess;
606  }));
607 
608  g_autoptr(GError) error = nullptr;
609  EXPECT_TRUE(fl_engine_start(engine, &error));
610  EXPECT_EQ(error, nullptr);
611 
612  EXPECT_TRUE(called);
613 
614  if (initial_language) {
615  g_setenv("LANGUAGE", initial_language, TRUE);
616  } else {
617  g_unsetenv("LANGUAGE");
618  }
619 }
620 
621 static void add_view_cb(GObject* object,
622  GAsyncResult* result,
623  gpointer user_data) {
624  g_autoptr(GError) error = nullptr;
625  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
626  EXPECT_TRUE(r);
627  EXPECT_EQ(error, nullptr);
628 
629  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
630 }
631 
632 TEST(FlEngineTest, AddView) {
633  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
634 
635  g_autoptr(FlDartProject) project = fl_dart_project_new();
636  g_autoptr(FlEngine) engine = fl_engine_new(project);
637 
638  bool called = false;
639  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
640  AddView, ([&called](auto engine, const FlutterAddViewInfo* info) {
641  called = true;
642  EXPECT_EQ(info->view_metrics->width, 123u);
643  EXPECT_EQ(info->view_metrics->height, 456u);
644  EXPECT_EQ(info->view_metrics->pixel_ratio, 2.0);
645 
646  FlutterAddViewResult result;
647  result.struct_size = sizeof(FlutterAddViewResult);
648  result.added = true;
649  result.user_data = info->user_data;
650  info->add_view_callback(&result);
651 
652  return kSuccess;
653  }));
654 
655  FlutterViewId view_id =
656  fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_cb, loop);
657  EXPECT_GT(view_id, 0);
658  EXPECT_TRUE(called);
659 
660  // Blocks here until add_view_cb is called.
661  g_main_loop_run(loop);
662 }
663 
664 static void add_view_error_cb(GObject* object,
665  GAsyncResult* result,
666  gpointer user_data) {
667  g_autoptr(GError) error = nullptr;
668  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
669  EXPECT_FALSE(r);
670  EXPECT_NE(error, nullptr);
671 
672  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
673 }
674 
675 TEST(FlEngineTest, AddViewError) {
676  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
677 
678  g_autoptr(FlDartProject) project = fl_dart_project_new();
679  g_autoptr(FlEngine) engine = fl_engine_new(project);
680 
681  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
682  AddView, ([](auto engine, const FlutterAddViewInfo* info) {
683  FlutterAddViewResult result;
684  result.struct_size = sizeof(FlutterAddViewResult);
685  result.added = false;
686  result.user_data = info->user_data;
687  info->add_view_callback(&result);
688 
689  return kSuccess;
690  }));
691 
692  FlutterViewId view_id = fl_engine_add_view(engine, 123, 456, 2.0, nullptr,
693  add_view_error_cb, loop);
694  EXPECT_GT(view_id, 0);
695 
696  // Blocks here until add_view_error_cb is called.
697  g_main_loop_run(loop);
698 }
699 
700 static void add_view_engine_error_cb(GObject* object,
701  GAsyncResult* result,
702  gpointer user_data) {
703  g_autoptr(GError) error = nullptr;
704  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
705  EXPECT_FALSE(r);
706  EXPECT_NE(error, nullptr);
707 
708  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
709 }
710 
711 TEST(FlEngineTest, AddViewEngineError) {
712  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
713 
714  g_autoptr(FlDartProject) project = fl_dart_project_new();
715  g_autoptr(FlEngine) engine = fl_engine_new(project);
716 
717  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
718  AddView, ([](auto engine, const FlutterAddViewInfo* info) {
719  return kInvalidArguments;
720  }));
721 
722  FlutterViewId view_id = fl_engine_add_view(engine, 123, 456, 2.0, nullptr,
724  EXPECT_GT(view_id, 0);
725 
726  // Blocks here until remove_view_engine_error_cb is called.
727  g_main_loop_run(loop);
728 }
729 
730 static void remove_view_cb(GObject* object,
731  GAsyncResult* result,
732  gpointer user_data) {
733  g_autoptr(GError) error = nullptr;
734  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
735  EXPECT_TRUE(r);
736  EXPECT_EQ(error, nullptr);
737 
738  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
739 }
740 
741 TEST(FlEngineTest, RemoveView) {
742  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
743 
744  g_autoptr(FlDartProject) project = fl_dart_project_new();
745  g_autoptr(FlEngine) engine = fl_engine_new(project);
746 
747  bool called = false;
748  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
749  RemoveView, ([&called](auto engine, const FlutterRemoveViewInfo* info) {
750  called = true;
751  EXPECT_EQ(info->view_id, 123);
752 
753  FlutterRemoveViewResult result;
754  result.struct_size = sizeof(FlutterRemoveViewResult);
755  result.removed = true;
756  result.user_data = info->user_data;
757  info->remove_view_callback(&result);
758 
759  return kSuccess;
760  }));
761 
762  fl_engine_remove_view(engine, 123, nullptr, remove_view_cb, loop);
763  EXPECT_TRUE(called);
764 
765  // Blocks here until remove_view_cb is called.
766  g_main_loop_run(loop);
767 }
768 
769 static void remove_view_error_cb(GObject* object,
770  GAsyncResult* result,
771  gpointer user_data) {
772  g_autoptr(GError) error = nullptr;
773  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
774  EXPECT_FALSE(r);
775  EXPECT_NE(error, nullptr);
776 
777  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
778 }
779 
780 TEST(FlEngineTest, RemoveViewError) {
781  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
782 
783  g_autoptr(FlDartProject) project = fl_dart_project_new();
784  g_autoptr(FlEngine) engine = fl_engine_new(project);
785 
786  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
787  RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
788  FlutterRemoveViewResult result;
789  result.struct_size = sizeof(FlutterRemoveViewResult);
790  result.removed = false;
791  result.user_data = info->user_data;
792  info->remove_view_callback(&result);
793 
794  return kSuccess;
795  }));
796 
797  fl_engine_remove_view(engine, 123, nullptr, remove_view_error_cb, loop);
798 
799  // Blocks here until remove_view_error_cb is called.
800  g_main_loop_run(loop);
801 }
802 
803 static void remove_view_engine_error_cb(GObject* object,
804  GAsyncResult* result,
805  gpointer user_data) {
806  g_autoptr(GError) error = nullptr;
807  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
808  EXPECT_FALSE(r);
809  EXPECT_NE(error, nullptr);
810 
811  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
812 }
813 
814 TEST(FlEngineTest, RemoveViewEngineError) {
815  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
816 
817  g_autoptr(FlDartProject) project = fl_dart_project_new();
818  g_autoptr(FlEngine) engine = fl_engine_new(project);
819 
820  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
821  RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
822  return kInvalidArguments;
823  }));
824 
826  loop);
827 
828  // Blocks here until remove_view_engine_error_cb is called.
829  g_main_loop_run(loop);
830 }
831 
832 TEST(FlEngineTest, SendKeyEvent) {
833  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
834 
835  g_autoptr(FlDartProject) project = fl_dart_project_new();
836  g_autoptr(FlEngine) engine = fl_engine_new(project);
837 
838  g_autoptr(GError) error = nullptr;
839  EXPECT_TRUE(fl_engine_start(engine, &error));
840  EXPECT_EQ(error, nullptr);
841 
842  bool called;
843  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
844  SendKeyEvent,
845  ([&called](auto engine, const FlutterKeyEvent* event,
846  FlutterKeyEventCallback callback, void* user_data) {
847  called = true;
848  EXPECT_EQ(event->timestamp, 1234);
849  EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
850  EXPECT_EQ(event->physical, static_cast<uint64_t>(42));
851  EXPECT_EQ(event->logical, static_cast<uint64_t>(123));
852  EXPECT_TRUE(event->synthesized);
853  EXPECT_EQ(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
854  callback(TRUE, user_data);
855  return kSuccess;
856  }));
857 
858  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
859  .timestamp = 1234,
860  .type = kFlutterKeyEventTypeUp,
861  .physical = 42,
862  .logical = 123,
863  .character = nullptr,
864  .synthesized = true,
865  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
867  engine, &event, nullptr,
868  [](GObject* object, GAsyncResult* result, gpointer user_data) {
869  gboolean handled;
870  g_autoptr(GError) error = nullptr;
871  EXPECT_TRUE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
872  &handled, &error));
873  EXPECT_EQ(error, nullptr);
874  EXPECT_TRUE(handled);
875  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
876  },
877  loop);
878 
879  g_main_loop_run(loop);
880  EXPECT_TRUE(called);
881 }
882 
883 TEST(FlEngineTest, SendKeyEventNotHandled) {
884  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
885 
886  g_autoptr(FlDartProject) project = fl_dart_project_new();
887  g_autoptr(FlEngine) engine = fl_engine_new(project);
888 
889  g_autoptr(GError) error = nullptr;
890  EXPECT_TRUE(fl_engine_start(engine, &error));
891  EXPECT_EQ(error, nullptr);
892 
893  bool called;
894  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
895  SendKeyEvent,
896  ([&called](auto engine, const FlutterKeyEvent* event,
897  FlutterKeyEventCallback callback, void* user_data) {
898  called = true;
899  callback(FALSE, user_data);
900  return kSuccess;
901  }));
902 
903  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
904  .timestamp = 1234,
905  .type = kFlutterKeyEventTypeUp,
906  .physical = 42,
907  .logical = 123,
908  .character = nullptr,
909  .synthesized = true,
910  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
912  engine, &event, nullptr,
913  [](GObject* object, GAsyncResult* result, gpointer user_data) {
914  gboolean handled;
915  g_autoptr(GError) error = nullptr;
916  EXPECT_TRUE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
917  &handled, &error));
918  EXPECT_EQ(error, nullptr);
919  EXPECT_FALSE(handled);
920  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
921  },
922  loop);
923 
924  g_main_loop_run(loop);
925  EXPECT_TRUE(called);
926 }
927 
928 TEST(FlEngineTest, SendKeyEventError) {
929  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
930 
931  g_autoptr(FlDartProject) project = fl_dart_project_new();
932  g_autoptr(FlEngine) engine = fl_engine_new(project);
933 
934  g_autoptr(GError) error = nullptr;
935  EXPECT_TRUE(fl_engine_start(engine, &error));
936  EXPECT_EQ(error, nullptr);
937 
938  bool called;
939  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
940  SendKeyEvent,
941  ([&called](auto engine, const FlutterKeyEvent* event,
942  FlutterKeyEventCallback callback, void* user_data) {
943  called = true;
944  return kInvalidArguments;
945  }));
946 
947  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
948  .timestamp = 1234,
949  .type = kFlutterKeyEventTypeUp,
950  .physical = 42,
951  .logical = 123,
952  .character = nullptr,
953  .synthesized = true,
954  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
956  engine, &event, nullptr,
957  [](GObject* object, GAsyncResult* result, gpointer user_data) {
958  gboolean handled;
959  g_autoptr(GError) error = nullptr;
960  EXPECT_FALSE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
961  &handled, &error));
962  EXPECT_NE(error, nullptr);
963  EXPECT_STREQ(error->message, "Failed to send key event");
964  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
965  },
966  loop);
967 
968  g_main_loop_run(loop);
969  EXPECT_TRUE(called);
970 }
971 
972 TEST(FlEngineTest, ChildObjects) {
973  g_autoptr(FlDartProject) project = fl_dart_project_new();
974  g_autoptr(FlEngine) engine = fl_engine_new(project);
975 
976  // Check objects exist before engine started.
977  EXPECT_NE(fl_engine_get_binary_messenger(engine), nullptr);
978  EXPECT_NE(fl_engine_get_renderer(engine), nullptr);
979  EXPECT_NE(fl_engine_get_display_monitor(engine), nullptr);
980  EXPECT_NE(fl_engine_get_task_runner(engine), nullptr);
981  EXPECT_NE(fl_engine_get_keyboard_manager(engine), nullptr);
982  EXPECT_NE(fl_engine_get_mouse_cursor_handler(engine), nullptr);
983  EXPECT_NE(fl_engine_get_windowing_handler(engine), nullptr);
984 }
985 
986 // NOLINTEND(clang-analyzer-core.StackAddressEscape)
fl_engine_get_embedder_api
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:721
TEST
TEST(FlEngineTest, NotifyDisplayUpdate)
Definition: fl_engine_test.cc:18
type
uint8_t type
Definition: fl_standard_message_codec_test.cc:1115
fl_engine_send_key_event_finish
gboolean fl_engine_send_key_event_finish(FlEngine *self, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_engine.cc:1187
fl_engine_get_keyboard_manager
FlKeyboardManager * fl_engine_get_keyboard_manager(FlEngine *self)
Definition: fl_engine.cc:1289
add_view_engine_error_cb
static void add_view_engine_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:700
fl_string_codec.h
fl_engine_get_renderer
FlRenderer * fl_engine_get_renderer(FlEngine *self)
Definition: fl_engine.cc:597
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
fl_json_message_codec_new
G_MODULE_EXPORT FlJsonMessageCodec * fl_json_message_codec_new()
Definition: fl_json_message_codec.cc:306
fl_json_message_codec.h
fl_engine_remove_view
void fl_engine_remove_view(FlEngine *self, FlutterViewId view_id, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:788
fl_engine_dispatch_semantics_action
void fl_engine_dispatch_semantics_action(FlEngine *self, uint64_t id, FlutterSemanticsAction action, GBytes *data)
Definition: fl_engine.cc:1204
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:50
fl_value_lookup_string
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:811
fl_engine_get_binary_messenger
G_MODULE_EXPORT FlBinaryMessenger * fl_engine_get_binary_messenger(FlEngine *self)
Definition: fl_engine.cc:1246
fl_engine_send_key_event
void fl_engine_send_key_event(FlEngine *self, const FlutterKeyEvent *event, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:1164
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
fl_message_codec_decode_message
G_MODULE_EXPORT FlValue * fl_message_codec_decode_message(FlMessageCodec *self, GBytes *message, GError **error)
Definition: fl_message_codec.cc:33
fl_value_get_type
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:466
fl_engine_add_view_finish
gboolean fl_engine_add_view_finish(FlEngine *self, GAsyncResult *result, GError **error)
Definition: fl_engine.cc:781
fl_engine_remove_view_finish
gboolean fl_engine_remove_view_finish(FlEngine *self, GAsyncResult *result, GError **error)
Definition: fl_engine.cc:813
FL_VALUE_TYPE_STRING
@ FL_VALUE_TYPE_STRING
Definition: fl_value.h:68
fl_dart_project_set_dart_entrypoint_arguments
G_MODULE_EXPORT void fl_dart_project_set_dart_entrypoint_arguments(FlDartProject *self, char **argv)
Definition: fl_dart_project.cc:110
fl_engine_private.h
remove_view_engine_error_cb
static void remove_view_engine_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:803
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_engine_add_view
FlutterViewId fl_engine_add_view(FlEngine *self, size_t width, size_t height, double pixel_ratio, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:738
fl_engine_get_mouse_cursor_handler
FlMouseCursorHandler * fl_engine_get_mouse_cursor_handler(FlEngine *self)
Definition: fl_engine.cc:1299
fl_engine_get_display_monitor
FlDisplayMonitor * fl_engine_get_display_monitor(FlEngine *self)
Definition: fl_engine.cc:602
add_view_error_cb
static void add_view_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:664
add_view_cb
static void add_view_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:621
height
const uint8_t uint32_t uint32_t * height
Definition: fl_pixel_buffer_texture_test.cc:39
remove_view_cb
static void remove_view_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:730
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:580
fl_engine_get_windowing_handler
FlWindowingHandler * fl_engine_get_windowing_handler(FlEngine *self)
Definition: fl_engine.cc:1284
args
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Definition: fl_event_channel.h:89
fl_engine.h
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
fl_engine_for_id
FlEngine * fl_engine_for_id(int64_t id)
Definition: fl_engine.cc:567
fl_engine_get_task_runner
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
Definition: fl_engine.cc:1252
fl_engine_send_pointer_pan_zoom_event
void fl_engine_send_pointer_pan_zoom_event(FlEngine *self, FlutterViewId view_id, size_t timestamp, double x, double y, FlutterPointerPhase phase, double pan_x, double pan_y, double scale, double rotation)
Definition: fl_engine.cc:1125
fl_engine_send_platform_message
void fl_engine_send_platform_message(FlEngine *self, const gchar *channel, GBytes *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:871
on_pre_engine_restart_cb
void on_pre_engine_restart_cb(FlEngine *engine, gpointer user_data)
Definition: fl_engine_test.cc:334
fl_engine_start
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:607
FL_VALUE_TYPE_FLOAT
@ FL_VALUE_TYPE_FLOAT
Definition: fl_value.h:67
fl_engine_notify_display_update
void fl_engine_notify_display_update(FlEngine *self, const FlutterEngineDisplay *displays, size_t displays_length)
Definition: fl_engine.cc:725
remove_view_error_cb
static void remove_view_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
Definition: fl_engine_test.cc:769
fl_engine_send_window_metrics_event
void fl_engine_send_window_metrics_event(FlEngine *self, FlutterEngineDisplayId display_id, FlutterViewId view_id, size_t width, size_t height, double pixel_ratio)
Definition: fl_engine.cc:939
width
const uint8_t uint32_t * width
Definition: fl_pixel_buffer_texture_test.cc:38
fl_engine_send_mouse_pointer_event
void fl_engine_send_mouse_pointer_event(FlEngine *self, FlutterViewId view_id, FlutterPointerPhase phase, size_t timestamp, double x, double y, FlutterPointerDeviceKind device_kind, double scroll_delta_x, double scroll_delta_y, int64_t buttons)
Definition: fl_engine.cc:961
FL_VALUE_TYPE_BOOL
@ FL_VALUE_TYPE_BOOL
Definition: fl_value.h:65
fl_engine_send_platform_message_response
gboolean fl_engine_send_platform_message_response(FlEngine *self, const FlutterPlatformMessageResponseHandle *handle, GBytes *response, GError **error)
Definition: fl_engine.cc:839