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#define FML_USED_ON_EMBEDDER
6#define RAPIDJSON_HAS_STDSTRING 1
7
8#include <cstring>
9#include <iostream>
10#include <memory>
11#include <set>
12#include <string>
13#include <vector>
14
15#include "flutter/fml/build_config.h"
16#include "flutter/fml/closure.h"
17#include "flutter/fml/make_copyable.h"
18#include "flutter/fml/native_library.h"
19#include "flutter/fml/thread.h"
20#include "third_party/dart/runtime/bin/elf_loader.h"
21#include "third_party/dart/runtime/include/dart_native_api.h"
22#include "third_party/skia/include/core/SkSurface.h"
23#include "third_party/skia/include/gpu/GrBackendSurface.h"
24#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
25
26#if !defined(FLUTTER_NO_EXPORT)
27#if FML_OS_WIN
28#define FLUTTER_EXPORT __declspec(dllexport)
29#else // FML_OS_WIN
30#define FLUTTER_EXPORT __attribute__((visibility("default")))
31#endif // FML_OS_WIN
32#endif // !FLUTTER_NO_EXPORT
33
34extern "C" {
35#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
36// Used for debugging dart:* sources.
37extern const uint8_t kPlatformStrongDill[];
38extern const intptr_t kPlatformStrongDillSize;
39#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
40}
41
42#include "flutter/assets/directory_asset_bundle.h"
43#include "flutter/common/graphics/persistent_cache.h"
44#include "flutter/common/task_runners.h"
45#include "flutter/fml/command_line.h"
46#include "flutter/fml/file.h"
47#include "flutter/fml/make_copyable.h"
48#include "flutter/fml/message_loop.h"
49#include "flutter/fml/paths.h"
50#include "flutter/fml/trace_event.h"
51#include "flutter/shell/common/rasterizer.h"
52#include "flutter/shell/common/switches.h"
53#include "flutter/shell/platform/embedder/embedder.h"
54#include "flutter/shell/platform/embedder/embedder_engine.h"
55#include "flutter/shell/platform/embedder/embedder_external_texture_resolver.h"
56#include "flutter/shell/platform/embedder/embedder_platform_message_response.h"
57#include "flutter/shell/platform/embedder/embedder_render_target.h"
58#include "flutter/shell/platform/embedder/embedder_render_target_skia.h"
59#include "flutter/shell/platform/embedder/embedder_struct_macros.h"
60#include "flutter/shell/platform/embedder/embedder_task_runner.h"
61#include "flutter/shell/platform/embedder/embedder_thread_host.h"
62#include "flutter/shell/platform/embedder/pixel_formats.h"
63#include "flutter/shell/platform/embedder/platform_view_embedder.h"
64#include "rapidjson/rapidjson.h"
65#include "rapidjson/writer.h"
66
67// Note: the IMPELLER_SUPPORTS_RENDERING may be defined even when the
68// embedder/BUILD.gn variable impeller_supports_rendering is disabled.
69#ifdef SHELL_ENABLE_GL
70#include "flutter/shell/platform/embedder/embedder_external_texture_gl.h"
71#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
72#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
73#ifdef IMPELLER_SUPPORTS_RENDERING
74#include "flutter/shell/platform/embedder/embedder_render_target_impeller.h" // nogncheck
75#include "flutter/shell/platform/embedder/embedder_surface_gl_impeller.h" // nogncheck
76#include "impeller/core/texture.h" // nogncheck
77#include "impeller/renderer/backend/gles/context_gles.h" // nogncheck
78#include "impeller/renderer/backend/gles/texture_gles.h" // nogncheck
79#include "impeller/renderer/context.h" // nogncheck
80#include "impeller/renderer/render_target.h" // nogncheck
81#endif // IMPELLER_SUPPORTS_RENDERING
82#endif // SHELL_ENABLE_GL
83
84#ifdef SHELL_ENABLE_METAL
85#include "flutter/shell/platform/embedder/embedder_surface_metal.h"
86#include "third_party/skia/include/ports/SkCFObject.h"
87#ifdef IMPELLER_SUPPORTS_RENDERING
88#include "flutter/shell/platform/embedder/embedder_render_target_impeller.h" // nogncheck
89#include "flutter/shell/platform/embedder/embedder_surface_metal_impeller.h" // nogncheck
90#include "impeller/core/texture.h" // nogncheck
91#include "impeller/renderer/backend/metal/texture_wrapper_mtl.h" // nogncheck
92#include "impeller/renderer/render_target.h" // nogncheck
93#endif // IMPELLER_SUPPORTS_RENDERING
94#endif // SHELL_ENABLE_METAL
95
96const int32_t kFlutterSemanticsNodeIdBatchEnd = -1;
97const int32_t kFlutterSemanticsCustomActionIdBatchEnd = -1;
98
99static constexpr int64_t kFlutterImplicitViewId = 0;
100
101// A message channel to send platform-independent FlutterKeyData to the
102// framework.
103//
104// This should be kept in sync with the following variables:
105//
106// - lib/ui/platform_dispatcher.dart, _kFlutterKeyDataChannel
107// - shell/platform/darwin/ios/framework/Source/FlutterEngine.mm,
108// FlutterKeyDataChannel
109// - io/flutter/embedding/android/KeyData.java,
110// CHANNEL
111//
112// Not to be confused with "flutter/keyevent", which is used to send raw
113// key event data in a platform-dependent format.
114//
115// ## Format
116//
117// Send: KeyDataPacket.data().
118//
119// Expected reply: Whether the event is handled. Exactly 1 byte long, with value
120// 1 for handled, and 0 for not. Malformed value is considered false.
121const char* kFlutterKeyDataChannel = "flutter/keydata";
122
123static FlutterEngineResult LogEmbedderError(FlutterEngineResult code,
124 const char* reason,
125 const char* code_name,
126 const char* function,
127 const char* file,
128 int line) {
129#if FML_OS_WIN
130 constexpr char kSeparator = '\\';
131#else
132 constexpr char kSeparator = '/';
133#endif
134 const auto file_base =
135 (::strrchr(s: file, c: kSeparator) ? strrchr(s: file, c: kSeparator) + 1 : file);
136 char error[256] = {};
137 snprintf(s: error, maxlen: (sizeof(error) / sizeof(char)),
138 format: "%s (%d): '%s' returned '%s'. %s", file_base, line, function,
139 code_name, reason);
140 std::cerr << error << std::endl;
141 return code;
142}
143
144#define LOG_EMBEDDER_ERROR(code, reason) \
145 LogEmbedderError(code, reason, #code, __FUNCTION__, __FILE__, __LINE__)
146
147static bool IsOpenGLRendererConfigValid(const FlutterRendererConfig* config) {
148 if (config->type != kOpenGL) {
149 return false;
150 }
151
152 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
153
154 if (!SAFE_EXISTS(open_gl_config, make_current) ||
155 !SAFE_EXISTS(open_gl_config, clear_current) ||
156 !SAFE_EXISTS_ONE_OF(open_gl_config, fbo_callback,
157 fbo_with_frame_info_callback) ||
158 !SAFE_EXISTS_ONE_OF(open_gl_config, present, present_with_info)) {
159 return false;
160 }
161
162 return true;
163}
164
165static bool IsSoftwareRendererConfigValid(const FlutterRendererConfig* config) {
166 if (config->type != kSoftware) {
167 return false;
168 }
169
170 const FlutterSoftwareRendererConfig* software_config = &config->software;
171
172 if (SAFE_ACCESS(software_config, surface_present_callback, nullptr) ==
173 nullptr) {
174 return false;
175 }
176
177 return true;
178}
179
180static bool IsMetalRendererConfigValid(const FlutterRendererConfig* config) {
181 if (config->type != kMetal) {
182 return false;
183 }
184
185 const FlutterMetalRendererConfig* metal_config = &config->metal;
186
187 bool device = SAFE_ACCESS(metal_config, device, nullptr);
188 bool command_queue =
189 SAFE_ACCESS(metal_config, present_command_queue, nullptr);
190
191 bool present = SAFE_ACCESS(metal_config, present_drawable_callback, nullptr);
192 bool get_texture =
193 SAFE_ACCESS(metal_config, get_next_drawable_callback, nullptr);
194
195 return device && command_queue && present && get_texture;
196}
197
198static bool IsVulkanRendererConfigValid(const FlutterRendererConfig* config) {
199 if (config->type != kVulkan) {
200 return false;
201 }
202
203 const FlutterVulkanRendererConfig* vulkan_config = &config->vulkan;
204
205 if (!SAFE_EXISTS(vulkan_config, instance) ||
206 !SAFE_EXISTS(vulkan_config, physical_device) ||
207 !SAFE_EXISTS(vulkan_config, device) ||
208 !SAFE_EXISTS(vulkan_config, queue) ||
209 !SAFE_EXISTS(vulkan_config, get_instance_proc_address_callback) ||
210 !SAFE_EXISTS(vulkan_config, get_next_image_callback) ||
211 !SAFE_EXISTS(vulkan_config, present_image_callback)) {
212 return false;
213 }
214
215 return true;
216}
217
218static bool IsRendererValid(const FlutterRendererConfig* config) {
219 if (config == nullptr) {
220 return false;
221 }
222
223 switch (config->type) {
224 case kOpenGL:
225 return IsOpenGLRendererConfigValid(config);
226 case kSoftware:
227 return IsSoftwareRendererConfigValid(config);
228 case kMetal:
229 return IsMetalRendererConfigValid(config);
230 case kVulkan:
231 return IsVulkanRendererConfigValid(config);
232 default:
233 return false;
234 }
235
236 return false;
237}
238
239#if FML_OS_LINUX || FML_OS_WIN
240static void* DefaultGLProcResolver(const char* name) {
241 static fml::RefPtr<fml::NativeLibrary> proc_library =
242#if FML_OS_LINUX
243 fml::NativeLibrary::CreateForCurrentProcess();
244#elif FML_OS_WIN // FML_OS_LINUX
245 fml::NativeLibrary::Create("opengl32.dll");
246#endif // FML_OS_WIN
247 return static_cast<void*>(
248 const_cast<uint8_t*>(proc_library->ResolveSymbol(symbol: name)));
249}
250#endif // FML_OS_LINUX || FML_OS_WIN
251
252#ifdef SHELL_ENABLE_GL
253// Auxiliary function used to translate rectangles of type SkIRect to
254// FlutterRect.
255static FlutterRect SkIRectToFlutterRect(const SkIRect sk_rect) {
256 FlutterRect flutter_rect = {.left: static_cast<double>(sk_rect.fLeft),
257 .top: static_cast<double>(sk_rect.fTop),
258 .right: static_cast<double>(sk_rect.fRight),
259 .bottom: static_cast<double>(sk_rect.fBottom)};
260 return flutter_rect;
261}
262
263// Auxiliary function used to translate rectangles of type FlutterRect to
264// SkIRect.
265static const SkIRect FlutterRectToSkIRect(FlutterRect flutter_rect) {
266 SkIRect rect = {.fLeft: static_cast<int32_t>(flutter_rect.left),
267 .fTop: static_cast<int32_t>(flutter_rect.top),
268 .fRight: static_cast<int32_t>(flutter_rect.right),
269 .fBottom: static_cast<int32_t>(flutter_rect.bottom)};
270 return rect;
271}
272#endif
273
274static inline flutter::Shell::CreateCallback<flutter::PlatformView>
275InferOpenGLPlatformViewCreationCallback(
276 const FlutterRendererConfig* config,
277 void* user_data,
278 const flutter::PlatformViewEmbedder::PlatformDispatchTable&
279 platform_dispatch_table,
280 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
281 external_view_embedder,
282 bool enable_impeller) {
283#ifdef SHELL_ENABLE_GL
284 if (config->type != kOpenGL) {
285 return nullptr;
286 }
287
288 auto gl_make_current = [ptr = config->open_gl.make_current,
289 user_data]() -> bool { return ptr(user_data); };
290
291 auto gl_clear_current = [ptr = config->open_gl.clear_current,
292 user_data]() -> bool { return ptr(user_data); };
293
294 auto gl_present =
295 [present = config->open_gl.present,
296 present_with_info = config->open_gl.present_with_info,
297 user_data](flutter::GLPresentInfo gl_present_info) -> bool {
298 if (present) {
299 return present(user_data);
300 } else {
301 // Format the frame and buffer damages accordingly. Note that, since the
302 // current compute damage algorithm only returns one rectangle for damage
303 // we are assuming the number of rectangles provided in frame and buffer
304 // damage are always 1. Once the function that computes damage implements
305 // support for multiple damage rectangles, GLPresentInfo should also
306 // contain the number of damage rectangles.
307 const size_t num_rects = 1;
308
309 std::array<FlutterRect, num_rects> frame_damage_rect = {
310 SkIRectToFlutterRect(sk_rect: *(gl_present_info.frame_damage))};
311 std::array<FlutterRect, num_rects> buffer_damage_rect = {
312 SkIRectToFlutterRect(sk_rect: *(gl_present_info.buffer_damage))};
313
314 FlutterDamage frame_damage{
315 .struct_size = sizeof(FlutterDamage),
316 .num_rects = frame_damage_rect.size(),
317 .damage = frame_damage_rect.data(),
318 };
319 FlutterDamage buffer_damage{
320 .struct_size = sizeof(FlutterDamage),
321 .num_rects = buffer_damage_rect.size(),
322 .damage = buffer_damage_rect.data(),
323 };
324
325 // Construct the present information concerning the frame being rendered.
326 FlutterPresentInfo present_info = {
327 .struct_size = sizeof(FlutterPresentInfo),
328 .fbo_id = gl_present_info.fbo_id,
329 .frame_damage = frame_damage,
330 .buffer_damage = buffer_damage,
331 };
332
333 return present_with_info(user_data, &present_info);
334 }
335 };
336
337 auto gl_fbo_callback =
338 [fbo_callback = config->open_gl.fbo_callback,
339 fbo_with_frame_info_callback =
340 config->open_gl.fbo_with_frame_info_callback,
341 user_data](flutter::GLFrameInfo gl_frame_info) -> intptr_t {
342 if (fbo_callback) {
343 return fbo_callback(user_data);
344 } else {
345 FlutterFrameInfo frame_info = {};
346 frame_info.struct_size = sizeof(FlutterFrameInfo);
347 frame_info.size = {.width: gl_frame_info.width, .height: gl_frame_info.height};
348 return fbo_with_frame_info_callback(user_data, &frame_info);
349 }
350 };
351
352 auto gl_populate_existing_damage =
353 [populate_existing_damage = config->open_gl.populate_existing_damage,
354 user_data](intptr_t id) -> flutter::GLFBOInfo {
355 // If no populate_existing_damage was provided, disable partial
356 // repaint.
357 if (!populate_existing_damage) {
358 return flutter::GLFBOInfo{
359 .fbo_id = static_cast<uint32_t>(id),
360 .partial_repaint_enabled = false,
361 .existing_damage = SkIRect::MakeEmpty(),
362 };
363 }
364
365 // Given the FBO's ID, get its existing damage.
366 FlutterDamage existing_damage;
367 populate_existing_damage(user_data, id, &existing_damage);
368
369 bool partial_repaint_enabled = true;
370 SkIRect existing_damage_rect;
371
372 // Verify that at least one damage rectangle was provided.
373 if (existing_damage.num_rects <= 0 || existing_damage.damage == nullptr) {
374 FML_LOG(INFO) << "No damage was provided. Forcing full repaint.";
375 existing_damage_rect = SkIRect::MakeEmpty();
376 partial_repaint_enabled = false;
377 } else if (existing_damage.num_rects > 1) {
378 // Log message notifying users that multi-damage is not yet available in
379 // case they try to make use of it.
380 FML_LOG(INFO) << "Damage with multiple rectangles not yet supported. "
381 "Repainting the whole frame.";
382 existing_damage_rect = SkIRect::MakeEmpty();
383 partial_repaint_enabled = false;
384 } else {
385 existing_damage_rect = FlutterRectToSkIRect(flutter_rect: *(existing_damage.damage));
386 }
387
388 // Pass the information about this FBO to the rendering backend.
389 return flutter::GLFBOInfo{
390 .fbo_id = static_cast<uint32_t>(id),
391 .partial_repaint_enabled = partial_repaint_enabled,
392 .existing_damage = existing_damage_rect,
393 };
394 };
395
396 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
397 std::function<bool()> gl_make_resource_current_callback = nullptr;
398 if (SAFE_ACCESS(open_gl_config, make_resource_current, nullptr) != nullptr) {
399 gl_make_resource_current_callback =
400 [ptr = config->open_gl.make_resource_current, user_data]() {
401 return ptr(user_data);
402 };
403 }
404
405 std::function<SkMatrix(void)> gl_surface_transformation_callback = nullptr;
406 if (SAFE_ACCESS(open_gl_config, surface_transformation, nullptr) != nullptr) {
407 gl_surface_transformation_callback =
408 [ptr = config->open_gl.surface_transformation, user_data]() {
409 FlutterTransformation transformation = ptr(user_data);
410 return SkMatrix::MakeAll(scaleX: transformation.scaleX, //
411 skewX: transformation.skewX, //
412 transX: transformation.transX, //
413 skewY: transformation.skewY, //
414 scaleY: transformation.scaleY, //
415 transY: transformation.transY, //
416 pers0: transformation.pers0, //
417 pers1: transformation.pers1, //
418 pers2: transformation.pers2 //
419 );
420 };
421
422 // If there is an external view embedder, ask it to apply the surface
423 // transformation to its surfaces as well.
424 if (external_view_embedder) {
425 external_view_embedder->SetSurfaceTransformationCallback(
426 gl_surface_transformation_callback);
427 }
428 }
429
430 flutter::GPUSurfaceGLDelegate::GLProcResolver gl_proc_resolver = nullptr;
431 if (SAFE_ACCESS(open_gl_config, gl_proc_resolver, nullptr) != nullptr) {
432 gl_proc_resolver = [ptr = config->open_gl.gl_proc_resolver,
433 user_data](const char* gl_proc_name) {
434 return ptr(user_data, gl_proc_name);
435 };
436 } else {
437#if FML_OS_LINUX || FML_OS_WIN
438 gl_proc_resolver = DefaultGLProcResolver;
439#endif
440 }
441
442 bool fbo_reset_after_present =
443 SAFE_ACCESS(open_gl_config, fbo_reset_after_present, false);
444
445 flutter::EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table = {
446 .gl_make_current_callback: gl_make_current, // gl_make_current_callback
447 .gl_clear_current_callback: gl_clear_current, // gl_clear_current_callback
448 .gl_present_callback: gl_present, // gl_present_callback
449 .gl_fbo_callback: gl_fbo_callback, // gl_fbo_callback
450 .gl_make_resource_current_callback: gl_make_resource_current_callback, // gl_make_resource_current_callback
451 .gl_surface_transformation_callback: gl_surface_transformation_callback, // gl_surface_transformation_callback
452 .gl_proc_resolver: gl_proc_resolver, // gl_proc_resolver
453 .gl_populate_existing_damage: gl_populate_existing_damage, // gl_populate_existing_damage
454 };
455
456 return fml::MakeCopyable(
457 lambda: [gl_dispatch_table, fbo_reset_after_present, platform_dispatch_table,
458 enable_impeller,
459 external_view_embedder =
460 std::move(external_view_embedder)](flutter::Shell& shell) mutable {
461 std::shared_ptr<flutter::EmbedderExternalViewEmbedder> view_embedder =
462 std::move(external_view_embedder);
463 if (enable_impeller) {
464 return std::make_unique<flutter::PlatformViewEmbedder>(
465 args&: shell, // delegate
466 args: shell.GetTaskRunners(), // task runners
467 args: std::make_unique<flutter::EmbedderSurfaceGLImpeller>(
468 args&: gl_dispatch_table, args&: fbo_reset_after_present,
469 args&: view_embedder), // embedder_surface
470 args: platform_dispatch_table, // embedder platform dispatch table
471 args&: view_embedder // external view embedder
472 );
473 }
474 return std::make_unique<flutter::PlatformViewEmbedder>(
475 args&: shell, // delegate
476 args: shell.GetTaskRunners(), // task runners
477 args: std::make_unique<flutter::EmbedderSurfaceGL>(
478 args&: gl_dispatch_table, args&: fbo_reset_after_present,
479 args&: view_embedder), // embedder_surface
480 args: platform_dispatch_table, // embedder platform dispatch table
481 args&: view_embedder // external view embedder
482 );
483 });
484#else
485 return nullptr;
486#endif
487}
488
489static flutter::Shell::CreateCallback<flutter::PlatformView>
490InferMetalPlatformViewCreationCallback(
491 const FlutterRendererConfig* config,
492 void* user_data,
493 const flutter::PlatformViewEmbedder::PlatformDispatchTable&
494 platform_dispatch_table,
495 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
496 external_view_embedder,
497 bool enable_impeller) {
498 if (config->type != kMetal) {
499 return nullptr;
500 }
501
502#ifdef SHELL_ENABLE_METAL
503 std::function<bool(flutter::GPUMTLTextureInfo texture)> metal_present =
504 [ptr = config->metal.present_drawable_callback,
505 user_data](flutter::GPUMTLTextureInfo texture) {
506 FlutterMetalTexture embedder_texture;
507 embedder_texture.struct_size = sizeof(FlutterMetalTexture);
508 embedder_texture.texture = texture.texture;
509 embedder_texture.texture_id = texture.texture_id;
510 embedder_texture.user_data = texture.destruction_context;
511 embedder_texture.destruction_callback = texture.destruction_callback;
512 return ptr(user_data, &embedder_texture);
513 };
514 auto metal_get_texture =
515 [ptr = config->metal.get_next_drawable_callback,
516 user_data](const SkISize& frame_size) -> flutter::GPUMTLTextureInfo {
517 FlutterFrameInfo frame_info = {};
518 frame_info.struct_size = sizeof(FlutterFrameInfo);
519 frame_info.size = {static_cast<uint32_t>(frame_size.width()),
520 static_cast<uint32_t>(frame_size.height())};
521 flutter::GPUMTLTextureInfo texture_info;
522
523 FlutterMetalTexture metal_texture = ptr(user_data, &frame_info);
524 texture_info.texture_id = metal_texture.texture_id;
525 texture_info.texture = metal_texture.texture;
526 texture_info.destruction_callback = metal_texture.destruction_callback;
527 texture_info.destruction_context = metal_texture.user_data;
528 return texture_info;
529 };
530
531 std::shared_ptr<flutter::EmbedderExternalViewEmbedder> view_embedder =
532 std::move(external_view_embedder);
533
534 std::unique_ptr<flutter::EmbedderSurface> embedder_surface;
535
536 if (enable_impeller) {
537 flutter::EmbedderSurfaceMetalImpeller::MetalDispatchTable
538 metal_dispatch_table = {
539 .present = metal_present,
540 .get_texture = metal_get_texture,
541 };
542 embedder_surface = std::make_unique<flutter::EmbedderSurfaceMetalImpeller>(
543 const_cast<flutter::GPUMTLDeviceHandle>(config->metal.device),
544 const_cast<flutter::GPUMTLCommandQueueHandle>(
545 config->metal.present_command_queue),
546 metal_dispatch_table, view_embedder);
547 } else {
548 flutter::EmbedderSurfaceMetal::MetalDispatchTable metal_dispatch_table = {
549 .present = metal_present,
550 .get_texture = metal_get_texture,
551 };
552 embedder_surface = std::make_unique<flutter::EmbedderSurfaceMetal>(
553 const_cast<flutter::GPUMTLDeviceHandle>(config->metal.device),
554 const_cast<flutter::GPUMTLCommandQueueHandle>(
555 config->metal.present_command_queue),
556 metal_dispatch_table, view_embedder);
557 }
558
559 // The static leak checker gets confused by the use of fml::MakeCopyable.
560 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
561 return fml::MakeCopyable(
562 [embedder_surface = std::move(embedder_surface), platform_dispatch_table,
563 external_view_embedder = view_embedder](flutter::Shell& shell) mutable {
564 return std::make_unique<flutter::PlatformViewEmbedder>(
565 shell, // delegate
566 shell.GetTaskRunners(), // task runners
567 std::move(embedder_surface), // embedder surface
568 platform_dispatch_table, // platform dispatch table
569 std::move(external_view_embedder) // external view embedder
570 );
571 });
572#else
573 return nullptr;
574#endif
575}
576
577static flutter::Shell::CreateCallback<flutter::PlatformView>
578InferVulkanPlatformViewCreationCallback(
579 const FlutterRendererConfig* config,
580 void* user_data,
581 const flutter::PlatformViewEmbedder::PlatformDispatchTable&
582 platform_dispatch_table,
583 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
584 external_view_embedder) {
585 if (config->type != kVulkan) {
586 return nullptr;
587 }
588
589#ifdef SHELL_ENABLE_VULKAN
590 std::function<void*(VkInstance, const char*)>
591 vulkan_get_instance_proc_address =
592 [ptr = config->vulkan.get_instance_proc_address_callback, user_data](
593 VkInstance instance, const char* proc_name) -> void* {
594 return ptr(user_data, instance, proc_name);
595 };
596
597 auto vulkan_get_next_image =
598 [ptr = config->vulkan.get_next_image_callback,
599 user_data](const SkISize& frame_size) -> FlutterVulkanImage {
600 FlutterFrameInfo frame_info = {
601 .struct_size = sizeof(FlutterFrameInfo),
602 .size = {.width: static_cast<uint32_t>(frame_size.width()),
603 .height: static_cast<uint32_t>(frame_size.height())},
604 };
605
606 return ptr(user_data, &frame_info);
607 };
608
609 auto vulkan_present_image_callback =
610 [ptr = config->vulkan.present_image_callback, user_data](
611 VkImage image, VkFormat format) -> bool {
612 FlutterVulkanImage image_desc = {
613 .struct_size = sizeof(FlutterVulkanImage),
614 .image = reinterpret_cast<uint64_t>(image),
615 .format = static_cast<uint32_t>(format),
616 };
617 return ptr(user_data, &image_desc);
618 };
619
620 auto vk_instance = static_cast<VkInstance>(config->vulkan.instance);
621 auto proc_addr =
622 vulkan_get_instance_proc_address(vk_instance, "vkGetInstanceProcAddr");
623
624 flutter::EmbedderSurfaceVulkan::VulkanDispatchTable vulkan_dispatch_table = {
625 .get_instance_proc_address =
626 reinterpret_cast<PFN_vkGetInstanceProcAddr>(proc_addr),
627 .get_next_image = vulkan_get_next_image,
628 .present_image = vulkan_present_image_callback,
629 };
630
631 std::shared_ptr<flutter::EmbedderExternalViewEmbedder> view_embedder =
632 std::move(external_view_embedder);
633
634 std::unique_ptr<flutter::EmbedderSurfaceVulkan> embedder_surface =
635 std::make_unique<flutter::EmbedderSurfaceVulkan>(
636 args: config->vulkan.version, args&: vk_instance,
637 args: config->vulkan.enabled_instance_extension_count,
638 args: config->vulkan.enabled_instance_extensions,
639 args: config->vulkan.enabled_device_extension_count,
640 args: config->vulkan.enabled_device_extensions,
641 args: static_cast<VkPhysicalDevice>(config->vulkan.physical_device),
642 args: static_cast<VkDevice>(config->vulkan.device),
643 args: config->vulkan.queue_family_index,
644 args: static_cast<VkQueue>(config->vulkan.queue), args&: vulkan_dispatch_table,
645 args&: view_embedder);
646
647 return fml::MakeCopyable(
648 lambda: [embedder_surface = std::move(embedder_surface), platform_dispatch_table,
649 external_view_embedder =
650 std::move(view_embedder)](flutter::Shell& shell) mutable {
651 return std::make_unique<flutter::PlatformViewEmbedder>(
652 args&: shell, // delegate
653 args: shell.GetTaskRunners(), // task runners
654 args: std::move(embedder_surface), // embedder surface
655 args: platform_dispatch_table, // platform dispatch table
656 args: std::move(external_view_embedder) // external view embedder
657 );
658 });
659#else
660 return nullptr;
661#endif
662}
663
664static flutter::Shell::CreateCallback<flutter::PlatformView>
665InferSoftwarePlatformViewCreationCallback(
666 const FlutterRendererConfig* config,
667 void* user_data,
668 const flutter::PlatformViewEmbedder::PlatformDispatchTable&
669 platform_dispatch_table,
670 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
671 external_view_embedder) {
672 if (config->type != kSoftware) {
673 return nullptr;
674 }
675
676 auto software_present_backing_store =
677 [ptr = config->software.surface_present_callback, user_data](
678 const void* allocation, size_t row_bytes, size_t height) -> bool {
679 return ptr(user_data, allocation, row_bytes, height);
680 };
681
682 flutter::EmbedderSurfaceSoftware::SoftwareDispatchTable
683 software_dispatch_table = {
684 .software_present_backing_store: software_present_backing_store, // required
685 };
686
687 return fml::MakeCopyable(
688 lambda: [software_dispatch_table, platform_dispatch_table,
689 external_view_embedder =
690 std::move(external_view_embedder)](flutter::Shell& shell) mutable {
691 return std::make_unique<flutter::PlatformViewEmbedder>(
692 args&: shell, // delegate
693 args: shell.GetTaskRunners(), // task runners
694 args&: software_dispatch_table, // software dispatch table
695 args: platform_dispatch_table, // platform dispatch table
696 args: std::move(external_view_embedder) // external view embedder
697 );
698 });
699}
700
701static flutter::Shell::CreateCallback<flutter::PlatformView>
702InferPlatformViewCreationCallback(
703 const FlutterRendererConfig* config,
704 void* user_data,
705 const flutter::PlatformViewEmbedder::PlatformDispatchTable&
706 platform_dispatch_table,
707 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
708 external_view_embedder,
709 bool enable_impeller) {
710 if (config == nullptr) {
711 return nullptr;
712 }
713
714 switch (config->type) {
715 case kOpenGL:
716 return InferOpenGLPlatformViewCreationCallback(
717 config, user_data, platform_dispatch_table,
718 external_view_embedder: std::move(external_view_embedder), enable_impeller);
719 case kSoftware:
720 return InferSoftwarePlatformViewCreationCallback(
721 config, user_data, platform_dispatch_table,
722 external_view_embedder: std::move(external_view_embedder));
723 case kMetal:
724 return InferMetalPlatformViewCreationCallback(
725 config, user_data, platform_dispatch_table,
726 external_view_embedder: std::move(external_view_embedder), enable_impeller);
727 case kVulkan:
728 return InferVulkanPlatformViewCreationCallback(
729 config, user_data, platform_dispatch_table,
730 external_view_embedder: std::move(external_view_embedder));
731 default:
732 return nullptr;
733 }
734 return nullptr;
735}
736
737static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
738 GrDirectContext* context,
739 const FlutterBackingStoreConfig& config,
740 const FlutterOpenGLTexture* texture) {
741#ifdef SHELL_ENABLE_GL
742 GrGLTextureInfo texture_info;
743 texture_info.fTarget = texture->target;
744 texture_info.fID = texture->name;
745 texture_info.fFormat = texture->format;
746
747 auto backend_texture = GrBackendTextures::MakeGL(width: config.size.width, //
748 height: config.size.height, //
749 skgpu::Mipmapped::kNo, //
750 glInfo: texture_info //
751 );
752
753 SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
754
755 auto surface = SkSurfaces::WrapBackendTexture(
756 context, // context
757 backendTexture: backend_texture, // back-end texture
758 origin: kBottomLeft_GrSurfaceOrigin, // surface origin
759 sampleCnt: 1, // sample count
760 colorType: kN32_SkColorType, // color type
761 colorSpace: SkColorSpace::MakeSRGB(), // color space
762 surfaceProps: &surface_properties, // surface properties
763 textureReleaseProc: static_cast<SkSurfaces::TextureReleaseProc>(
764 texture->destruction_callback), // release proc
765 releaseContext: texture->user_data // release context
766 );
767
768 if (!surface) {
769 FML_LOG(ERROR) << "Could not wrap embedder supplied render texture.";
770 return nullptr;
771 }
772
773 return surface;
774#else
775 return nullptr;
776#endif
777}
778
779static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
780 GrDirectContext* context,
781 const FlutterBackingStoreConfig& config,
782 const FlutterOpenGLFramebuffer* framebuffer) {
783#ifdef SHELL_ENABLE_GL
784 GrGLFramebufferInfo framebuffer_info = {};
785 framebuffer_info.fFormat = framebuffer->target;
786 framebuffer_info.fFBOID = framebuffer->name;
787
788 auto backend_render_target =
789 GrBackendRenderTargets::MakeGL(width: config.size.width, // width
790 height: config.size.height, // height
791 sampleCnt: 1, // sample count
792 stencilBits: 0, // stencil bits
793 glInfo: framebuffer_info // framebuffer info
794 );
795
796 SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
797
798 auto surface = SkSurfaces::WrapBackendRenderTarget(
799 context, // context
800 backendRenderTarget: backend_render_target, // backend render target
801 origin: kBottomLeft_GrSurfaceOrigin, // surface origin
802 colorType: kN32_SkColorType, // color type
803 colorSpace: SkColorSpace::MakeSRGB(), // color space
804 surfaceProps: &surface_properties, // surface properties
805 releaseProc: static_cast<SkSurfaces::RenderTargetReleaseProc>(
806 framebuffer->destruction_callback), // release proc
807 releaseContext: framebuffer->user_data // release context
808 );
809
810 if (!surface) {
811 FML_LOG(ERROR) << "Could not wrap embedder supplied frame-buffer.";
812 return nullptr;
813 }
814 return surface;
815#else
816 return nullptr;
817#endif
818}
819
820static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
821 GrDirectContext* context,
822 const FlutterBackingStoreConfig& config,
823 const FlutterSoftwareBackingStore* software) {
824 const auto image_info =
825 SkImageInfo::MakeN32Premul(width: config.size.width, height: config.size.height);
826
827 struct Captures {
828 VoidCallback destruction_callback;
829 void* user_data;
830 };
831 auto captures = std::make_unique<Captures>();
832 captures->destruction_callback = software->destruction_callback;
833 captures->user_data = software->user_data;
834 auto release_proc = [](void* pixels, void* context) {
835 auto captures = reinterpret_cast<Captures*>(context);
836 if (captures->destruction_callback) {
837 captures->destruction_callback(captures->user_data);
838 }
839 delete captures;
840 };
841
842 auto surface =
843 SkSurfaces::WrapPixels(imageInfo: image_info, // image info
844 pixels: const_cast<void*>(software->allocation), // pixels
845 rowBytes: software->row_bytes, // row bytes
846 release_proc, // release proc
847 context: captures.get() // get context
848 );
849
850 if (!surface) {
851 FML_LOG(ERROR)
852 << "Could not wrap embedder supplied software render buffer.";
853 if (software->destruction_callback) {
854 software->destruction_callback(software->user_data);
855 }
856 return nullptr;
857 }
858 if (surface) {
859 captures.release(); // Skia has assumed ownership of the struct.
860 }
861 return surface;
862}
863
864static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
865 GrDirectContext* context,
866 const FlutterBackingStoreConfig& config,
867 const FlutterSoftwareBackingStore2* software) {
868 const auto color_info = getSkColorInfo(pixfmt: software->pixel_format);
869 if (!color_info) {
870 return nullptr;
871 }
872
873 const auto image_info = SkImageInfo::Make(
874 dimensions: SkISize::Make(w: config.size.width, h: config.size.height), colorInfo: *color_info);
875
876 struct Captures {
877 VoidCallback destruction_callback;
878 void* user_data;
879 };
880 auto captures = std::make_unique<Captures>();
881 captures->destruction_callback = software->destruction_callback;
882 captures->user_data = software->user_data;
883 auto release_proc = [](void* pixels, void* context) {
884 auto captures = reinterpret_cast<Captures*>(context);
885 if (captures->destruction_callback) {
886 captures->destruction_callback(captures->user_data);
887 }
888 };
889
890 auto surface =
891 SkSurfaces::WrapPixels(imageInfo: image_info, // image info
892 pixels: const_cast<void*>(software->allocation), // pixels
893 rowBytes: software->row_bytes, // row bytes
894 release_proc, // release proc
895 context: captures.release() // release context
896 );
897
898 if (!surface) {
899 FML_LOG(ERROR)
900 << "Could not wrap embedder supplied software render buffer.";
901 if (software->destruction_callback) {
902 software->destruction_callback(software->user_data);
903 }
904 return nullptr;
905 }
906 return surface;
907}
908
909static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
910 GrDirectContext* context,
911 const FlutterBackingStoreConfig& config,
912 const FlutterMetalBackingStore* metal) {
913#ifdef SHELL_ENABLE_METAL
914 GrMtlTextureInfo texture_info;
915 if (!metal->texture.texture) {
916 FML_LOG(ERROR) << "Embedder supplied null Metal texture.";
917 return nullptr;
918 }
919 sk_cfp<FlutterMetalTextureHandle> mtl_texture;
920 mtl_texture.retain(metal->texture.texture);
921 texture_info.fTexture = mtl_texture;
922 GrBackendTexture backend_texture(config.size.width, //
923 config.size.height, //
924 GrMipMapped::kNo, //
925 texture_info //
926 );
927
928 SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
929
930 auto surface = SkSurfaces::WrapBackendTexture(
931 context, // context
932 backend_texture, // back-end texture
933 kTopLeft_GrSurfaceOrigin, // surface origin
934 // TODO(dnfield): Update this when embedders support MSAA, see
935 // https://github.com/flutter/flutter/issues/100392
936 1, // sample count
937 kBGRA_8888_SkColorType, // color type
938 nullptr, // color space
939 &surface_properties, // surface properties
940 static_cast<SkSurfaces::TextureReleaseProc>(
941 metal->texture.destruction_callback), // release proc
942 metal->texture.user_data // release context
943 );
944
945 if (!surface) {
946 FML_LOG(ERROR) << "Could not wrap embedder supplied Metal render texture.";
947 return nullptr;
948 }
949
950 return surface;
951#else
952 return nullptr;
953#endif
954}
955
956static std::unique_ptr<flutter::EmbedderRenderTarget>
957MakeRenderTargetFromBackingStoreImpeller(
958 FlutterBackingStore backing_store,
959 const fml::closure& on_release,
960 const std::shared_ptr<impeller::AiksContext>& aiks_context,
961 const FlutterBackingStoreConfig& config,
962 const FlutterOpenGLFramebuffer* framebuffer) {
963#if defined(SHELL_ENABLE_GL) && defined(IMPELLER_SUPPORTS_RENDERING)
964
965 const auto& gl_context =
966 impeller::ContextGLES::Cast(base&: *aiks_context->GetContext());
967 const auto size = impeller::ISize(config.size.width, config.size.height);
968
969 impeller::TextureDescriptor color0_tex;
970 color0_tex.type = impeller::TextureType::kTexture2D;
971 color0_tex.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
972 color0_tex.size = size;
973 color0_tex.usage = static_cast<impeller::TextureUsageMask>(
974 impeller::TextureUsage::kRenderTarget);
975 color0_tex.sample_count = impeller::SampleCount::kCount1;
976 color0_tex.storage_mode = impeller::StorageMode::kDevicePrivate;
977
978 impeller::ColorAttachment color0;
979 color0.texture = std::make_shared<impeller::TextureGLES>(
980 args: gl_context.GetReactor(), args&: color0_tex,
981 args: impeller::TextureGLES::IsWrapped::kWrapped);
982 color0.clear_color = impeller::Color::DarkSlateGray();
983 color0.load_action = impeller::LoadAction::kClear;
984 color0.store_action = impeller::StoreAction::kStore;
985
986 impeller::TextureDescriptor stencil0_tex;
987 stencil0_tex.type = impeller::TextureType::kTexture2D;
988 stencil0_tex.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
989 stencil0_tex.size = size;
990 stencil0_tex.usage = static_cast<impeller::TextureUsageMask>(
991 impeller::TextureUsage::kRenderTarget);
992 stencil0_tex.sample_count = impeller::SampleCount::kCount1;
993
994 impeller::StencilAttachment stencil0;
995 stencil0.clear_stencil = 0;
996 stencil0.texture = std::make_shared<impeller::TextureGLES>(
997 args: gl_context.GetReactor(), args&: stencil0_tex,
998 args: impeller::TextureGLES::IsWrapped::kWrapped);
999 stencil0.load_action = impeller::LoadAction::kClear;
1000 stencil0.store_action = impeller::StoreAction::kDontCare;
1001
1002 impeller::RenderTarget render_target_desc;
1003
1004 render_target_desc.SetColorAttachment(attachment: color0, index: 0u);
1005 render_target_desc.SetStencilAttachment(stencil0);
1006
1007 return std::make_unique<flutter::EmbedderRenderTargetImpeller>(
1008 args&: backing_store, args: aiks_context,
1009 args: std::make_unique<impeller::RenderTarget>(args: std::move(render_target_desc)),
1010 args: on_release);
1011#else
1012 return nullptr;
1013#endif
1014}
1015
1016static std::unique_ptr<flutter::EmbedderRenderTarget>
1017MakeRenderTargetFromBackingStoreImpeller(
1018 FlutterBackingStore backing_store,
1019 const fml::closure& on_release,
1020 const std::shared_ptr<impeller::AiksContext>& aiks_context,
1021 const FlutterBackingStoreConfig& config,
1022 const FlutterMetalBackingStore* metal) {
1023#if defined(SHELL_ENABLE_METAL) && defined(IMPELLER_SUPPORTS_RENDERING)
1024 if (!metal->texture.texture) {
1025 FML_LOG(ERROR) << "Embedder supplied null Metal texture.";
1026 return nullptr;
1027 }
1028
1029 const auto size = impeller::ISize(config.size.width, config.size.height);
1030
1031 impeller::TextureDescriptor resolve_tex_desc;
1032 resolve_tex_desc.size = size;
1033 resolve_tex_desc.sample_count = impeller::SampleCount::kCount1;
1034 resolve_tex_desc.storage_mode = impeller::StorageMode::kDevicePrivate;
1035 resolve_tex_desc.usage =
1036 static_cast<uint64_t>(impeller::TextureUsage::kRenderTarget) |
1037 static_cast<uint64_t>(impeller::TextureUsage::kShaderRead);
1038
1039 auto resolve_tex = impeller::WrapTextureMTL(
1040 resolve_tex_desc, metal->texture.texture,
1041 [callback = metal->texture.destruction_callback,
1042 user_data = metal->texture.user_data]() { callback(user_data); });
1043 if (!resolve_tex) {
1044 FML_LOG(ERROR) << "Could not wrap embedder supplied Metal render texture.";
1045 return nullptr;
1046 }
1047 resolve_tex->SetLabel("ImpellerBackingStoreResolve");
1048
1049 impeller::TextureDescriptor msaa_tex_desc;
1050 msaa_tex_desc.storage_mode = impeller::StorageMode::kDeviceTransient;
1051 msaa_tex_desc.type = impeller::TextureType::kTexture2DMultisample;
1052 msaa_tex_desc.sample_count = impeller::SampleCount::kCount4;
1053 msaa_tex_desc.format = resolve_tex->GetTextureDescriptor().format;
1054 msaa_tex_desc.size = size;
1055 msaa_tex_desc.usage =
1056 static_cast<uint64_t>(impeller::TextureUsage::kRenderTarget);
1057
1058 auto msaa_tex =
1059 aiks_context->GetContext()->GetResourceAllocator()->CreateTexture(
1060 msaa_tex_desc);
1061 if (!msaa_tex) {
1062 FML_LOG(ERROR) << "Could not allocate MSAA color texture.";
1063 return nullptr;
1064 }
1065 msaa_tex->SetLabel("ImpellerBackingStoreColorMSAA");
1066
1067 impeller::ColorAttachment color0;
1068 color0.texture = msaa_tex;
1069 color0.clear_color = impeller::Color::DarkSlateGray();
1070 color0.load_action = impeller::LoadAction::kClear;
1071 color0.store_action = impeller::StoreAction::kMultisampleResolve;
1072 color0.resolve_texture = resolve_tex;
1073
1074 impeller::RenderTarget render_target_desc;
1075 render_target_desc.SetColorAttachment(color0, 0u);
1076
1077 return std::make_unique<flutter::EmbedderRenderTargetImpeller>(
1078 backing_store, aiks_context,
1079 std::make_unique<impeller::RenderTarget>(std::move(render_target_desc)),
1080 on_release);
1081#else
1082 return nullptr;
1083#endif
1084}
1085
1086static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
1087 GrDirectContext* context,
1088 const FlutterBackingStoreConfig& config,
1089 const FlutterVulkanBackingStore* vulkan) {
1090#ifdef SHELL_ENABLE_VULKAN
1091 if (!vulkan->image) {
1092 FML_LOG(ERROR) << "Embedder supplied null Vulkan image.";
1093 return nullptr;
1094 }
1095 GrVkImageInfo image_info = {
1096 .fImage = reinterpret_cast<VkImage>(vulkan->image->image),
1097 .fImageTiling = VK_IMAGE_TILING_OPTIMAL,
1098 .fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1099 .fFormat = static_cast<VkFormat>(vulkan->image->format),
1100 .fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
1101 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1102 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1103 VK_IMAGE_USAGE_SAMPLED_BIT,
1104 .fSampleCount = 1,
1105 .fLevelCount = 1,
1106 };
1107 GrBackendTexture backend_texture(config.size.width, //
1108 config.size.height, //
1109 image_info //
1110 );
1111
1112 SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
1113
1114 auto surface = SkSurfaces::WrapBackendTexture(
1115 context, // context
1116 backendTexture: backend_texture, // back-end texture
1117 origin: kTopLeft_GrSurfaceOrigin, // surface origin
1118 sampleCnt: 1, // sample count
1119 colorType: flutter::GPUSurfaceVulkan::ColorTypeFromFormat(
1120 format: static_cast<VkFormat>(vulkan->image->format)), // color type
1121 colorSpace: SkColorSpace::MakeSRGB(), // color space
1122 surfaceProps: &surface_properties, // surface properties
1123 textureReleaseProc: static_cast<SkSurfaces::TextureReleaseProc>(
1124 vulkan->destruction_callback), // release proc
1125 releaseContext: vulkan->user_data // release context
1126 );
1127
1128 if (!surface) {
1129 FML_LOG(ERROR) << "Could not wrap embedder supplied Vulkan render texture.";
1130 return nullptr;
1131 }
1132
1133 return surface;
1134#else
1135 return nullptr;
1136#endif
1137}
1138
1139static std::unique_ptr<flutter::EmbedderRenderTarget>
1140MakeRenderTargetFromSkSurface(FlutterBackingStore backing_store,
1141 sk_sp<SkSurface> skia_surface,
1142 fml::closure on_release) {
1143 if (!skia_surface) {
1144 return nullptr;
1145 }
1146 return std::make_unique<flutter::EmbedderRenderTargetSkia>(
1147 args&: backing_store, args: std::move(skia_surface), args: std::move(on_release));
1148}
1149
1150static std::unique_ptr<flutter::EmbedderRenderTarget>
1151CreateEmbedderRenderTarget(
1152 const FlutterCompositor* compositor,
1153 const FlutterBackingStoreConfig& config,
1154 GrDirectContext* context,
1155 const std::shared_ptr<impeller::AiksContext>& aiks_context,
1156 bool enable_impeller) {
1157 FlutterBackingStore backing_store = {};
1158 backing_store.struct_size = sizeof(backing_store);
1159
1160 // Safe access checks on the compositor struct have been performed in
1161 // InferExternalViewEmbedderFromArgs and are not necessary here.
1162 auto c_create_callback = compositor->create_backing_store_callback;
1163 auto c_collect_callback = compositor->collect_backing_store_callback;
1164
1165 {
1166 TRACE_EVENT0("flutter", "FlutterCompositorCreateBackingStore");
1167 if (!c_create_callback(&config, &backing_store, compositor->user_data)) {
1168 FML_LOG(ERROR) << "Could not create the embedder backing store.";
1169 return nullptr;
1170 }
1171 }
1172
1173 if (backing_store.struct_size != sizeof(backing_store)) {
1174 FML_LOG(ERROR) << "Embedder modified the backing store struct size.";
1175 return nullptr;
1176 }
1177
1178 // In case we return early without creating an embedder render target, the
1179 // embedder has still given us ownership of its baton which we must return
1180 // back to it. If this method is successful, the closure is released when the
1181 // render target is eventually released.
1182 fml::ScopedCleanupClosure collect_callback(
1183 [c_collect_callback, backing_store, user_data = compositor->user_data]() {
1184 TRACE_EVENT0("flutter", "FlutterCompositorCollectBackingStore");
1185 c_collect_callback(&backing_store, user_data);
1186 });
1187
1188 // No safe access checks on the renderer are necessary since we allocated
1189 // the struct.
1190
1191 std::unique_ptr<flutter::EmbedderRenderTarget> render_target;
1192
1193 switch (backing_store.type) {
1194 case kFlutterBackingStoreTypeOpenGL: {
1195 switch (backing_store.open_gl.type) {
1196 case kFlutterOpenGLTargetTypeTexture: {
1197 auto skia_surface = MakeSkSurfaceFromBackingStore(
1198 context, config, texture: &backing_store.open_gl.texture);
1199 render_target = MakeRenderTargetFromSkSurface(
1200 backing_store, skia_surface: std::move(skia_surface),
1201 on_release: collect_callback.Release());
1202 break;
1203 }
1204 case kFlutterOpenGLTargetTypeFramebuffer: {
1205 if (enable_impeller) {
1206 render_target = MakeRenderTargetFromBackingStoreImpeller(
1207 backing_store, on_release: collect_callback.Release(), aiks_context, config,
1208 framebuffer: &backing_store.open_gl.framebuffer);
1209 break;
1210 } else {
1211 auto skia_surface = MakeSkSurfaceFromBackingStore(
1212 context, config, framebuffer: &backing_store.open_gl.framebuffer);
1213 render_target = MakeRenderTargetFromSkSurface(
1214 backing_store, skia_surface: std::move(skia_surface),
1215 on_release: collect_callback.Release());
1216 break;
1217 }
1218 }
1219 }
1220 break;
1221 }
1222 case kFlutterBackingStoreTypeSoftware: {
1223 auto skia_surface = MakeSkSurfaceFromBackingStore(
1224 context, config, software: &backing_store.software);
1225 render_target = MakeRenderTargetFromSkSurface(
1226 backing_store, skia_surface: std::move(skia_surface), on_release: collect_callback.Release());
1227 break;
1228 }
1229 case kFlutterBackingStoreTypeSoftware2: {
1230 auto skia_surface = MakeSkSurfaceFromBackingStore(
1231 context, config, software: &backing_store.software2);
1232 render_target = MakeRenderTargetFromSkSurface(
1233 backing_store, skia_surface: std::move(skia_surface), on_release: collect_callback.Release());
1234 break;
1235 }
1236 case kFlutterBackingStoreTypeMetal: {
1237 if (enable_impeller) {
1238 render_target = MakeRenderTargetFromBackingStoreImpeller(
1239 backing_store, on_release: collect_callback.Release(), aiks_context, config,
1240 metal: &backing_store.metal);
1241 } else {
1242 auto skia_surface = MakeSkSurfaceFromBackingStore(context, config,
1243 metal: &backing_store.metal);
1244 render_target = MakeRenderTargetFromSkSurface(
1245 backing_store, skia_surface: std::move(skia_surface), on_release: collect_callback.Release());
1246 }
1247 break;
1248 }
1249 case kFlutterBackingStoreTypeVulkan: {
1250 auto skia_surface =
1251 MakeSkSurfaceFromBackingStore(context, config, vulkan: &backing_store.vulkan);
1252 render_target = MakeRenderTargetFromSkSurface(
1253 backing_store, skia_surface: std::move(skia_surface), on_release: collect_callback.Release());
1254 break;
1255 }
1256 };
1257
1258 if (!render_target) {
1259 FML_LOG(ERROR) << "Could not create a surface from an embedder provided "
1260 "render target.";
1261 }
1262 return render_target;
1263}
1264
1265static std::pair<std::unique_ptr<flutter::EmbedderExternalViewEmbedder>,
1266 bool /* halt engine launch if true */>
1267InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
1268 bool enable_impeller) {
1269 if (compositor == nullptr) {
1270 return {nullptr, false};
1271 }
1272
1273 auto c_create_callback =
1274 SAFE_ACCESS(compositor, create_backing_store_callback, nullptr);
1275 auto c_collect_callback =
1276 SAFE_ACCESS(compositor, collect_backing_store_callback, nullptr);
1277 auto c_present_callback =
1278 SAFE_ACCESS(compositor, present_layers_callback, nullptr);
1279 bool avoid_backing_store_cache =
1280 SAFE_ACCESS(compositor, avoid_backing_store_cache, false);
1281
1282 // Make sure the required callbacks are present
1283 if (!c_create_callback || !c_collect_callback || !c_present_callback) {
1284 FML_LOG(ERROR) << "Required compositor callbacks absent.";
1285 return {nullptr, true};
1286 }
1287
1288 FlutterCompositor captured_compositor = *compositor;
1289
1290 flutter::EmbedderExternalViewEmbedder::CreateRenderTargetCallback
1291 create_render_target_callback =
1292 [captured_compositor, enable_impeller](
1293 GrDirectContext* context,
1294 const std::shared_ptr<impeller::AiksContext>& aiks_context,
1295 const auto& config) {
1296 return CreateEmbedderRenderTarget(&captured_compositor, config,
1297 context, aiks_context,
1298 enable_impeller);
1299 };
1300
1301 flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback =
1302 [c_present_callback,
1303 user_data = compositor->user_data](const auto& layers) {
1304 TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
1305 return c_present_callback(
1306 const_cast<const FlutterLayer**>(layers.data()), layers.size(),
1307 user_data);
1308 };
1309
1310 return {std::make_unique<flutter::EmbedderExternalViewEmbedder>(
1311 args&: avoid_backing_store_cache, args&: create_render_target_callback,
1312 args&: present_callback),
1313 false};
1314}
1315
1316struct _FlutterPlatformMessageResponseHandle {
1317 std::unique_ptr<flutter::PlatformMessage> message;
1318};
1319
1320struct LoadedElfDeleter {
1321 void operator()(Dart_LoadedElf* elf) {
1322 if (elf) {
1323 ::Dart_UnloadELF(loaded: elf);
1324 }
1325 }
1326};
1327
1328using UniqueLoadedElf = std::unique_ptr<Dart_LoadedElf, LoadedElfDeleter>;
1329
1330struct _FlutterEngineAOTData {
1331 UniqueLoadedElf loaded_elf = nullptr;
1332 const uint8_t* vm_snapshot_data = nullptr;
1333 const uint8_t* vm_snapshot_instrs = nullptr;
1334 const uint8_t* vm_isolate_data = nullptr;
1335 const uint8_t* vm_isolate_instrs = nullptr;
1336};
1337
1338FlutterEngineResult FlutterEngineCreateAOTData(
1339 const FlutterEngineAOTDataSource* source,
1340 FlutterEngineAOTData* data_out) {
1341 if (!flutter::DartVM::IsRunningPrecompiledCode()) {
1342 return LOG_EMBEDDER_ERROR(kInvalidArguments,
1343 "AOT data can only be created in AOT mode.");
1344 } else if (!source) {
1345 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null source specified.");
1346 } else if (!data_out) {
1347 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null data_out specified.");
1348 }
1349
1350 switch (source->type) {
1351 case kFlutterEngineAOTDataSourceTypeElfPath: {
1352 if (!source->elf_path || !fml::IsFile(path: source->elf_path)) {
1353 return LOG_EMBEDDER_ERROR(kInvalidArguments,
1354 "Invalid ELF path specified.");
1355 }
1356
1357 auto aot_data = std::make_unique<_FlutterEngineAOTData>();
1358 const char* error = nullptr;
1359
1360#if OS_FUCHSIA
1361 // TODO(gw280): https://github.com/flutter/flutter/issues/50285
1362 // Dart doesn't implement Dart_LoadELF on Fuchsia
1363 Dart_LoadedElf* loaded_elf = nullptr;
1364#else
1365 Dart_LoadedElf* loaded_elf = Dart_LoadELF(
1366 filename: source->elf_path, // file path
1367 file_offset: 0, // file offset
1368 error: &error, // error (out)
1369 vm_snapshot_data: &aot_data->vm_snapshot_data, // vm snapshot data (out)
1370 vm_snapshot_instrs: &aot_data->vm_snapshot_instrs, // vm snapshot instr (out)
1371 vm_isolate_data: &aot_data->vm_isolate_data, // vm isolate data (out)
1372 vm_isolate_instrs: &aot_data->vm_isolate_instrs // vm isolate instr (out)
1373 );
1374#endif
1375
1376 if (loaded_elf == nullptr) {
1377 return LOG_EMBEDDER_ERROR(kInvalidArguments, error);
1378 }
1379
1380 aot_data->loaded_elf.reset(p: loaded_elf);
1381
1382 *data_out = aot_data.release();
1383 return kSuccess;
1384 }
1385 }
1386
1387 return LOG_EMBEDDER_ERROR(
1388 kInvalidArguments,
1389 "Invalid FlutterEngineAOTDataSourceType type specified.");
1390}
1391
1392FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data) {
1393 if (!data) {
1394 // Deleting a null object should be a no-op.
1395 return kSuccess;
1396 }
1397
1398 // Created in a unique pointer in `FlutterEngineCreateAOTData`.
1399 delete data;
1400 return kSuccess;
1401}
1402
1403// Constructs appropriate mapping callbacks if JIT snapshot locations have been
1404// explictly specified.
1405void PopulateJITSnapshotMappingCallbacks(const FlutterProjectArgs* args,
1406 flutter::Settings& settings) {
1407 auto make_mapping_callback = [](const char* path, bool executable) {
1408 return [path, executable]() {
1409 if (executable) {
1410 return fml::FileMapping::CreateReadExecute(path);
1411 } else {
1412 return fml::FileMapping::CreateReadOnly(path);
1413 }
1414 };
1415 };
1416
1417 // Users are allowed to specify only certain snapshots if they so desire.
1418 if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) != nullptr) {
1419 settings.vm_snapshot_data = make_mapping_callback(
1420 reinterpret_cast<const char*>(args->vm_snapshot_data), false);
1421 }
1422
1423 if (SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) != nullptr) {
1424 settings.vm_snapshot_instr = make_mapping_callback(
1425 reinterpret_cast<const char*>(args->vm_snapshot_instructions), true);
1426 }
1427
1428 if (SAFE_ACCESS(args, isolate_snapshot_data, nullptr) != nullptr) {
1429 settings.isolate_snapshot_data = make_mapping_callback(
1430 reinterpret_cast<const char*>(args->isolate_snapshot_data), false);
1431 }
1432
1433 if (SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr) != nullptr) {
1434 settings.isolate_snapshot_instr = make_mapping_callback(
1435 reinterpret_cast<const char*>(args->isolate_snapshot_instructions),
1436 true);
1437 }
1438
1439#if !OS_FUCHSIA && (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG)
1440 settings.dart_library_sources_kernel = []() {
1441 return std::make_unique<fml::NonOwnedMapping>(args: kPlatformStrongDill,
1442 args: kPlatformStrongDillSize);
1443 };
1444#endif // !OS_FUCHSIA && (FLUTTER_RUNTIME_MODE ==
1445 // FLUTTER_RUNTIME_MODE_DEBUG)
1446}
1447
1448void PopulateAOTSnapshotMappingCallbacks(
1449 const FlutterProjectArgs* args,
1450 flutter::Settings& settings) { // NOLINT(google-runtime-references)
1451 // There are no ownership concerns here as all mappings are owned by the
1452 // embedder and not the engine.
1453 auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
1454 return [mapping, size]() {
1455 return std::make_unique<fml::NonOwnedMapping>(args: mapping, args: size);
1456 };
1457 };
1458
1459 if (SAFE_ACCESS(args, aot_data, nullptr) != nullptr) {
1460 settings.vm_snapshot_data =
1461 make_mapping_callback(args->aot_data->vm_snapshot_data, 0);
1462
1463 settings.vm_snapshot_instr =
1464 make_mapping_callback(args->aot_data->vm_snapshot_instrs, 0);
1465
1466 settings.isolate_snapshot_data =
1467 make_mapping_callback(args->aot_data->vm_isolate_data, 0);
1468
1469 settings.isolate_snapshot_instr =
1470 make_mapping_callback(args->aot_data->vm_isolate_instrs, 0);
1471 }
1472
1473 if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) != nullptr) {
1474 settings.vm_snapshot_data = make_mapping_callback(
1475 args->vm_snapshot_data, SAFE_ACCESS(args, vm_snapshot_data_size, 0));
1476 }
1477
1478 if (SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) != nullptr) {
1479 settings.vm_snapshot_instr = make_mapping_callback(
1480 args->vm_snapshot_instructions,
1481 SAFE_ACCESS(args, vm_snapshot_instructions_size, 0));
1482 }
1483
1484 if (SAFE_ACCESS(args, isolate_snapshot_data, nullptr) != nullptr) {
1485 settings.isolate_snapshot_data =
1486 make_mapping_callback(args->isolate_snapshot_data,
1487 SAFE_ACCESS(args, isolate_snapshot_data_size, 0));
1488 }
1489
1490 if (SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr) != nullptr) {
1491 settings.isolate_snapshot_instr = make_mapping_callback(
1492 args->isolate_snapshot_instructions,
1493 SAFE_ACCESS(args, isolate_snapshot_instructions_size, 0));
1494 }
1495}
1496
1497// Translates engine semantic nodes to embedder semantic nodes.
1498FlutterSemanticsNode CreateEmbedderSemanticsNode(
1499 const flutter::SemanticsNode& node) {
1500 SkMatrix transform = node.transform.asM33();
1501 FlutterTransformation flutter_transform{
1502 .scaleX: transform.get(index: SkMatrix::kMScaleX), .skewX: transform.get(index: SkMatrix::kMSkewX),
1503 .transX: transform.get(index: SkMatrix::kMTransX), .skewY: transform.get(index: SkMatrix::kMSkewY),
1504 .scaleY: transform.get(index: SkMatrix::kMScaleY), .transY: transform.get(index: SkMatrix::kMTransY),
1505 .pers0: transform.get(index: SkMatrix::kMPersp0), .pers1: transform.get(index: SkMatrix::kMPersp1),
1506 .pers2: transform.get(index: SkMatrix::kMPersp2)};
1507
1508 // Do not add new members to FlutterSemanticsNode.
1509 // This would break the forward compatibility of FlutterSemanticsUpdate.
1510 // All new members must be added to FlutterSemanticsNode2 instead.
1511 return {
1512 .struct_size: sizeof(FlutterSemanticsNode),
1513 .id: node.id,
1514 .flags: static_cast<FlutterSemanticsFlag>(node.flags),
1515 .actions: static_cast<FlutterSemanticsAction>(node.actions),
1516 .text_selection_base: node.textSelectionBase,
1517 .text_selection_extent: node.textSelectionExtent,
1518 .scroll_child_count: node.scrollChildren,
1519 .scroll_index: node.scrollIndex,
1520 .scroll_position: node.scrollPosition,
1521 .scroll_extent_max: node.scrollExtentMax,
1522 .scroll_extent_min: node.scrollExtentMin,
1523 .elevation: node.elevation,
1524 .thickness: node.thickness,
1525 .label: node.label.c_str(),
1526 .hint: node.hint.c_str(),
1527 .value: node.value.c_str(),
1528 .increased_value: node.increasedValue.c_str(),
1529 .decreased_value: node.decreasedValue.c_str(),
1530 .text_direction: static_cast<FlutterTextDirection>(node.textDirection),
1531 .rect: FlutterRect{.left: node.rect.fLeft, .top: node.rect.fTop, .right: node.rect.fRight,
1532 .bottom: node.rect.fBottom},
1533 .transform: flutter_transform,
1534 .child_count: node.childrenInTraversalOrder.size(),
1535 .children_in_traversal_order: node.childrenInTraversalOrder.data(),
1536 .children_in_hit_test_order: node.childrenInHitTestOrder.data(),
1537 .custom_accessibility_actions_count: node.customAccessibilityActions.size(),
1538 .custom_accessibility_actions: node.customAccessibilityActions.data(),
1539 .platform_view_id: node.platformViewId,
1540 .tooltip: node.tooltip.c_str(),
1541 };
1542}
1543
1544// Translates engine semantic nodes to embedder semantic nodes.
1545FlutterSemanticsNode2 CreateEmbedderSemanticsNode2(
1546 const flutter::SemanticsNode& node) {
1547 SkMatrix transform = node.transform.asM33();
1548 FlutterTransformation flutter_transform{
1549 .scaleX: transform.get(index: SkMatrix::kMScaleX), .skewX: transform.get(index: SkMatrix::kMSkewX),
1550 .transX: transform.get(index: SkMatrix::kMTransX), .skewY: transform.get(index: SkMatrix::kMSkewY),
1551 .scaleY: transform.get(index: SkMatrix::kMScaleY), .transY: transform.get(index: SkMatrix::kMTransY),
1552 .pers0: transform.get(index: SkMatrix::kMPersp0), .pers1: transform.get(index: SkMatrix::kMPersp1),
1553 .pers2: transform.get(index: SkMatrix::kMPersp2)};
1554 return {
1555 .struct_size: sizeof(FlutterSemanticsNode2),
1556 .id: node.id,
1557 .flags: static_cast<FlutterSemanticsFlag>(node.flags),
1558 .actions: static_cast<FlutterSemanticsAction>(node.actions),
1559 .text_selection_base: node.textSelectionBase,
1560 .text_selection_extent: node.textSelectionExtent,
1561 .scroll_child_count: node.scrollChildren,
1562 .scroll_index: node.scrollIndex,
1563 .scroll_position: node.scrollPosition,
1564 .scroll_extent_max: node.scrollExtentMax,
1565 .scroll_extent_min: node.scrollExtentMin,
1566 .elevation: node.elevation,
1567 .thickness: node.thickness,
1568 .label: node.label.c_str(),
1569 .hint: node.hint.c_str(),
1570 .value: node.value.c_str(),
1571 .increased_value: node.increasedValue.c_str(),
1572 .decreased_value: node.decreasedValue.c_str(),
1573 .text_direction: static_cast<FlutterTextDirection>(node.textDirection),
1574 .rect: FlutterRect{.left: node.rect.fLeft, .top: node.rect.fTop, .right: node.rect.fRight,
1575 .bottom: node.rect.fBottom},
1576 .transform: flutter_transform,
1577 .child_count: node.childrenInTraversalOrder.size(),
1578 .children_in_traversal_order: node.childrenInTraversalOrder.data(),
1579 .children_in_hit_test_order: node.childrenInHitTestOrder.data(),
1580 .custom_accessibility_actions_count: node.customAccessibilityActions.size(),
1581 .custom_accessibility_actions: node.customAccessibilityActions.data(),
1582 .platform_view_id: node.platformViewId,
1583 .tooltip: node.tooltip.c_str(),
1584 };
1585}
1586
1587// Translates engine semantic custom actions to embedder semantic custom
1588// actions.
1589FlutterSemanticsCustomAction CreateEmbedderSemanticsCustomAction(
1590 const flutter::CustomAccessibilityAction& action) {
1591 // Do not add new members to FlutterSemanticsCustomAction.
1592 // This would break the forward compatibility of FlutterSemanticsUpdate.
1593 // All new members must be added to FlutterSemanticsCustomAction2 instead.
1594 return {
1595 .struct_size: sizeof(FlutterSemanticsCustomAction),
1596 .id: action.id,
1597 .override_action: static_cast<FlutterSemanticsAction>(action.overrideId),
1598 .label: action.label.c_str(),
1599 .hint: action.hint.c_str(),
1600 };
1601}
1602
1603// Translates engine semantic custom actions to embedder semantic custom
1604// actions.
1605FlutterSemanticsCustomAction2 CreateEmbedderSemanticsCustomAction2(
1606 const flutter::CustomAccessibilityAction& action) {
1607 return {
1608 .struct_size: sizeof(FlutterSemanticsCustomAction2),
1609 .id: action.id,
1610 .override_action: static_cast<FlutterSemanticsAction>(action.overrideId),
1611 .label: action.label.c_str(),
1612 .hint: action.hint.c_str(),
1613 };
1614}
1615
1616// Create a callback to notify the embedder of semantic updates
1617// using the deprecated embedder callback 'update_semantics_callback'.
1618flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1619CreateNewEmbedderSemanticsUpdateCallback(
1620 FlutterUpdateSemanticsCallback update_semantics_callback,
1621 void* user_data) {
1622 return [update_semantics_callback, user_data](
1623 const flutter::SemanticsNodeUpdates& nodes,
1624 const flutter::CustomAccessibilityActionUpdates& actions) {
1625 std::vector<FlutterSemanticsNode> embedder_nodes;
1626 for (const auto& value : nodes) {
1627 embedder_nodes.push_back(x: CreateEmbedderSemanticsNode(node: value.second));
1628 }
1629
1630 std::vector<FlutterSemanticsCustomAction> embedder_custom_actions;
1631 for (const auto& value : actions) {
1632 embedder_custom_actions.push_back(
1633 x: CreateEmbedderSemanticsCustomAction(action: value.second));
1634 }
1635
1636 FlutterSemanticsUpdate update{
1637 .struct_size = sizeof(FlutterSemanticsUpdate),
1638 .nodes_count = embedder_nodes.size(),
1639 .nodes = embedder_nodes.data(),
1640 .custom_actions_count = embedder_custom_actions.size(),
1641 .custom_actions = embedder_custom_actions.data(),
1642 };
1643
1644 update_semantics_callback(&update, user_data);
1645 };
1646}
1647
1648// Create a callback to notify the embedder of semantic updates
1649// using the new embedder callback 'update_semantics_callback2'.
1650flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1651CreateNewEmbedderSemanticsUpdateCallback2(
1652 FlutterUpdateSemanticsCallback2 update_semantics_callback,
1653 void* user_data) {
1654 return [update_semantics_callback, user_data](
1655 const flutter::SemanticsNodeUpdates& nodes,
1656 const flutter::CustomAccessibilityActionUpdates& actions) {
1657 std::vector<FlutterSemanticsNode2> embedder_nodes;
1658 std::vector<FlutterSemanticsCustomAction2> embedder_custom_actions;
1659
1660 embedder_nodes.reserve(n: nodes.size());
1661 embedder_custom_actions.reserve(n: actions.size());
1662
1663 for (const auto& value : nodes) {
1664 embedder_nodes.push_back(x: CreateEmbedderSemanticsNode2(node: value.second));
1665 }
1666
1667 for (const auto& value : actions) {
1668 embedder_custom_actions.push_back(
1669 x: CreateEmbedderSemanticsCustomAction2(action: value.second));
1670 }
1671
1672 // Provide the embedder an array of pointers to maintain full forward and
1673 // backward compatibility even if new members are added to semantic structs.
1674 std::vector<FlutterSemanticsNode2*> embedder_node_pointers;
1675 std::vector<FlutterSemanticsCustomAction2*> embedder_custom_action_pointers;
1676
1677 embedder_node_pointers.reserve(n: embedder_nodes.size());
1678 embedder_custom_action_pointers.reserve(n: embedder_custom_actions.size());
1679
1680 for (auto& node : embedder_nodes) {
1681 embedder_node_pointers.push_back(x: &node);
1682 }
1683
1684 for (auto& action : embedder_custom_actions) {
1685 embedder_custom_action_pointers.push_back(x: &action);
1686 }
1687
1688 FlutterSemanticsUpdate2 update{
1689 .struct_size = sizeof(FlutterSemanticsUpdate2),
1690 .node_count = embedder_node_pointers.size(),
1691 .nodes = embedder_node_pointers.data(),
1692 .custom_action_count = embedder_custom_action_pointers.size(),
1693 .custom_actions = embedder_custom_action_pointers.data(),
1694 };
1695
1696 update_semantics_callback(&update, user_data);
1697 };
1698}
1699
1700// Create a callback to notify the embedder of semantic updates
1701// using the legacy embedder callbacks 'update_semantics_node_callback' and
1702// 'update_semantics_custom_action_callback'.
1703flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1704CreateLegacyEmbedderSemanticsUpdateCallback(
1705 FlutterUpdateSemanticsNodeCallback update_semantics_node_callback,
1706 FlutterUpdateSemanticsCustomActionCallback
1707 update_semantics_custom_action_callback,
1708 void* user_data) {
1709 return [update_semantics_node_callback,
1710 update_semantics_custom_action_callback,
1711 user_data](const flutter::SemanticsNodeUpdates& nodes,
1712 const flutter::CustomAccessibilityActionUpdates& actions) {
1713 // First, queue all node and custom action updates.
1714 if (update_semantics_node_callback != nullptr) {
1715 for (const auto& value : nodes) {
1716 const FlutterSemanticsNode embedder_node =
1717 CreateEmbedderSemanticsNode(node: value.second);
1718 update_semantics_node_callback(&embedder_node, user_data);
1719 }
1720 }
1721
1722 if (update_semantics_custom_action_callback != nullptr) {
1723 for (const auto& value : actions) {
1724 const FlutterSemanticsCustomAction embedder_action =
1725 CreateEmbedderSemanticsCustomAction(action: value.second);
1726 update_semantics_custom_action_callback(&embedder_action, user_data);
1727 }
1728 }
1729
1730 // Second, mark node and action batches completed now that all
1731 // updates are queued.
1732 if (update_semantics_node_callback != nullptr) {
1733 const FlutterSemanticsNode batch_end_sentinel = {
1734 .struct_size: sizeof(FlutterSemanticsNode),
1735 .id: kFlutterSemanticsNodeIdBatchEnd,
1736 };
1737 update_semantics_node_callback(&batch_end_sentinel, user_data);
1738 }
1739
1740 if (update_semantics_custom_action_callback != nullptr) {
1741 const FlutterSemanticsCustomAction batch_end_sentinel = {
1742 .struct_size: sizeof(FlutterSemanticsCustomAction),
1743 .id: kFlutterSemanticsCustomActionIdBatchEnd,
1744 };
1745 update_semantics_custom_action_callback(&batch_end_sentinel, user_data);
1746 }
1747 };
1748}
1749
1750// Creates a callback that receives semantic updates from the engine
1751// and notifies the embedder's callback(s). Returns null if the embedder
1752// did not register any callbacks.
1753flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1754CreateEmbedderSemanticsUpdateCallback(const FlutterProjectArgs* args,
1755 void* user_data) {
1756 // The embedder can register the new callback, or the legacy callbacks, or
1757 // nothing at all. Handle the case where the embedder registered the 'new'
1758 // callback.
1759 if (SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr) {
1760 return CreateNewEmbedderSemanticsUpdateCallback2(
1761 update_semantics_callback: args->update_semantics_callback2, user_data);
1762 }
1763
1764 if (SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr) {
1765 return CreateNewEmbedderSemanticsUpdateCallback(
1766 update_semantics_callback: args->update_semantics_callback, user_data);
1767 }
1768
1769 // Handle the case where the embedder registered 'legacy' callbacks.
1770 FlutterUpdateSemanticsNodeCallback update_semantics_node_callback = nullptr;
1771 if (SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr) {
1772 update_semantics_node_callback = args->update_semantics_node_callback;
1773 }
1774
1775 FlutterUpdateSemanticsCustomActionCallback
1776 update_semantics_custom_action_callback = nullptr;
1777 if (SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
1778 nullptr) {
1779 update_semantics_custom_action_callback =
1780 args->update_semantics_custom_action_callback;
1781 }
1782
1783 if (update_semantics_node_callback != nullptr ||
1784 update_semantics_custom_action_callback != nullptr) {
1785 return CreateLegacyEmbedderSemanticsUpdateCallback(
1786 update_semantics_node_callback, update_semantics_custom_action_callback,
1787 user_data);
1788 }
1789
1790 // Handle the case where the embedder registered no callbacks.
1791 return nullptr;
1792}
1793
1794FlutterEngineResult FlutterEngineRun(size_t version,
1795 const FlutterRendererConfig* config,
1796 const FlutterProjectArgs* args,
1797 void* user_data,
1798 FLUTTER_API_SYMBOL(FlutterEngine) *
1799 engine_out) {
1800 auto result =
1801 FlutterEngineInitialize(version, config, args, user_data, engine_out);
1802
1803 if (result != kSuccess) {
1804 return result;
1805 }
1806
1807 return FlutterEngineRunInitialized(engine: *engine_out);
1808}
1809
1810FlutterEngineResult FlutterEngineInitialize(size_t version,
1811 const FlutterRendererConfig* config,
1812 const FlutterProjectArgs* args,
1813 void* user_data,
1814 FLUTTER_API_SYMBOL(FlutterEngine) *
1815 engine_out) {
1816 // Step 0: Figure out arguments for shell creation.
1817 if (version != FLUTTER_ENGINE_VERSION) {
1818 return LOG_EMBEDDER_ERROR(
1819 kInvalidLibraryVersion,
1820 "Flutter embedder version mismatch. There has been a breaking change. "
1821 "Please consult the changelog and update the embedder.");
1822 }
1823
1824 if (engine_out == nullptr) {
1825 return LOG_EMBEDDER_ERROR(kInvalidArguments,
1826 "The engine out parameter was missing.");
1827 }
1828
1829 if (args == nullptr) {
1830 return LOG_EMBEDDER_ERROR(kInvalidArguments,
1831 "The Flutter project arguments were missing.");
1832 }
1833
1834 if (SAFE_ACCESS(args, assets_path, nullptr) == nullptr) {
1835 return LOG_EMBEDDER_ERROR(
1836 kInvalidArguments,
1837 "The assets path in the Flutter project arguments was missing.");
1838 }
1839
1840 if (SAFE_ACCESS(args, main_path__unused__, nullptr) != nullptr) {
1841 FML_LOG(WARNING)
1842 << "FlutterProjectArgs.main_path is deprecated and should be set null.";
1843 }
1844
1845 if (SAFE_ACCESS(args, packages_path__unused__, nullptr) != nullptr) {
1846 FML_LOG(WARNING) << "FlutterProjectArgs.packages_path is deprecated and "
1847 "should be set null.";
1848 }
1849
1850 if (!IsRendererValid(config)) {
1851 return LOG_EMBEDDER_ERROR(kInvalidArguments,
1852 "The renderer configuration was invalid.");
1853 }
1854
1855 std::string icu_data_path;
1856 if (SAFE_ACCESS(args, icu_data_path, nullptr) != nullptr) {
1857 icu_data_path = SAFE_ACCESS(args, icu_data_path, nullptr);
1858 }
1859
1860 if (SAFE_ACCESS(args, persistent_cache_path, nullptr) != nullptr) {
1861 std::string persistent_cache_path =
1862 SAFE_ACCESS(args, persistent_cache_path, nullptr);
1863 flutter::PersistentCache::SetCacheDirectoryPath(persistent_cache_path);
1864 }
1865
1866 if (SAFE_ACCESS(args, is_persistent_cache_read_only, false)) {
1867 flutter::PersistentCache::gIsReadOnly = true;
1868 }
1869
1870 fml::CommandLine command_line;
1871 if (SAFE_ACCESS(args, command_line_argc, 0) != 0 &&
1872 SAFE_ACCESS(args, command_line_argv, nullptr) != nullptr) {
1873 command_line = fml::CommandLineFromArgcArgv(
1874 SAFE_ACCESS(args, command_line_argc, 0),
1875 SAFE_ACCESS(args, command_line_argv, nullptr));
1876 }
1877
1878 flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
1879
1880 if (SAFE_ACCESS(args, aot_data, nullptr)) {
1881 if (SAFE_ACCESS(args, vm_snapshot_data, nullptr) ||
1882 SAFE_ACCESS(args, vm_snapshot_instructions, nullptr) ||
1883 SAFE_ACCESS(args, isolate_snapshot_data, nullptr) ||
1884 SAFE_ACCESS(args, isolate_snapshot_instructions, nullptr)) {
1885 return LOG_EMBEDDER_ERROR(
1886 kInvalidArguments,
1887 "Multiple AOT sources specified. Embedders should provide either "
1888 "*_snapshot_* buffers or aot_data, not both.");
1889 }
1890 }
1891
1892 if (flutter::DartVM::IsRunningPrecompiledCode()) {
1893 PopulateAOTSnapshotMappingCallbacks(args, settings);
1894 } else {
1895 PopulateJITSnapshotMappingCallbacks(args, settings);
1896 }
1897
1898 settings.icu_data_path = icu_data_path;
1899 settings.assets_path = args->assets_path;
1900 settings.leak_vm = !SAFE_ACCESS(args, shutdown_dart_vm_when_done, false);
1901 settings.old_gen_heap_size = SAFE_ACCESS(args, dart_old_gen_heap_size, -1);
1902
1903 if (!flutter::DartVM::IsRunningPrecompiledCode()) {
1904 // Verify the assets path contains Dart 2 kernel assets.
1905 const std::string kApplicationKernelSnapshotFileName = "kernel_blob.bin";
1906 std::string application_kernel_path = fml::paths::JoinPaths(
1907 components: {settings.assets_path, kApplicationKernelSnapshotFileName});
1908 if (!fml::IsFile(path: application_kernel_path)) {
1909 return LOG_EMBEDDER_ERROR(
1910 kInvalidArguments,
1911 "Not running in AOT mode but could not resolve the kernel binary.");
1912 }
1913 settings.application_kernel_asset = kApplicationKernelSnapshotFileName;
1914 }
1915
1916 settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
1917 fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
1918 };
1919 settings.task_observer_remove = [](intptr_t key) {
1920 fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
1921 };
1922 if (SAFE_ACCESS(args, root_isolate_create_callback, nullptr) != nullptr) {
1923 VoidCallback callback =
1924 SAFE_ACCESS(args, root_isolate_create_callback, nullptr);
1925 settings.root_isolate_create_callback =
1926 [callback, user_data](const auto& isolate) { callback(user_data); };
1927 }
1928 if (SAFE_ACCESS(args, log_message_callback, nullptr) != nullptr) {
1929 FlutterLogMessageCallback callback =
1930 SAFE_ACCESS(args, log_message_callback, nullptr);
1931 settings.log_message_callback = [callback, user_data](
1932 const std::string& tag,
1933 const std::string& message) {
1934 callback(tag.c_str(), message.c_str(), user_data);
1935 };
1936 }
1937 if (SAFE_ACCESS(args, log_tag, nullptr) != nullptr) {
1938 settings.log_tag = SAFE_ACCESS(args, log_tag, nullptr);
1939 }
1940
1941 bool has_update_semantics_2_callback =
1942 SAFE_ACCESS(args, update_semantics_callback2, nullptr) != nullptr;
1943 bool has_update_semantics_callback =
1944 SAFE_ACCESS(args, update_semantics_callback, nullptr) != nullptr;
1945 bool has_legacy_update_semantics_callback =
1946 SAFE_ACCESS(args, update_semantics_node_callback, nullptr) != nullptr ||
1947 SAFE_ACCESS(args, update_semantics_custom_action_callback, nullptr) !=
1948 nullptr;
1949
1950 int semantic_callback_count = (has_update_semantics_2_callback ? 1 : 0) +
1951 (has_update_semantics_callback ? 1 : 0) +
1952 (has_legacy_update_semantics_callback ? 1 : 0);
1953
1954 if (semantic_callback_count > 1) {
1955 return LOG_EMBEDDER_ERROR(
1956 kInvalidArguments,
1957 "Multiple semantics update callbacks provided. "
1958 "Embedders should provide either `update_semantics_callback2`, "
1959 "`update_semantics_callback`, or both "
1960 "`update_semantics_node_callback` and "
1961 "`update_semantics_custom_action_callback`.");
1962 }
1963
1964 flutter::PlatformViewEmbedder::UpdateSemanticsCallback
1965 update_semantics_callback =
1966 CreateEmbedderSemanticsUpdateCallback(args, user_data);
1967
1968 flutter::PlatformViewEmbedder::PlatformMessageResponseCallback
1969 platform_message_response_callback = nullptr;
1970 if (SAFE_ACCESS(args, platform_message_callback, nullptr) != nullptr) {
1971 platform_message_response_callback =
1972 [ptr = args->platform_message_callback,
1973 user_data](std::unique_ptr<flutter::PlatformMessage> message) {
1974 auto handle = new FlutterPlatformMessageResponseHandle();
1975 const FlutterPlatformMessage incoming_message = {
1976 .struct_size: sizeof(FlutterPlatformMessage), // struct_size
1977 .channel: message->channel().c_str(), // channel
1978 .message: message->data().GetMapping(), // message
1979 .message_size: message->data().GetSize(), // message_size
1980 .response_handle: handle, // response_handle
1981 };
1982 handle->message = std::move(message);
1983 return ptr(&incoming_message, user_data);
1984 };
1985 }
1986
1987 flutter::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr;
1988 if (SAFE_ACCESS(args, vsync_callback, nullptr) != nullptr) {
1989 vsync_callback = [ptr = args->vsync_callback, user_data](intptr_t baton) {
1990 return ptr(user_data, baton);
1991 };
1992 }
1993
1994 flutter::PlatformViewEmbedder::ComputePlatformResolvedLocaleCallback
1995 compute_platform_resolved_locale_callback = nullptr;
1996 if (SAFE_ACCESS(args, compute_platform_resolved_locale_callback, nullptr) !=
1997 nullptr) {
1998 compute_platform_resolved_locale_callback =
1999 [ptr = args->compute_platform_resolved_locale_callback](
2000 const std::vector<std::string>& supported_locales_data) {
2001 const size_t number_of_strings_per_locale = 3;
2002 size_t locale_count =
2003 supported_locales_data.size() / number_of_strings_per_locale;
2004 std::vector<FlutterLocale> supported_locales;
2005 std::vector<const FlutterLocale*> supported_locales_ptr;
2006 for (size_t i = 0; i < locale_count; ++i) {
2007 supported_locales.push_back(
2008 x: {.struct_size = sizeof(FlutterLocale),
2009 .language_code =
2010 supported_locales_data[i * number_of_strings_per_locale +
2011 0]
2012 .c_str(),
2013 .country_code =
2014 supported_locales_data[i * number_of_strings_per_locale +
2015 1]
2016 .c_str(),
2017 .script_code =
2018 supported_locales_data[i * number_of_strings_per_locale +
2019 2]
2020 .c_str(),
2021 .variant_code = nullptr});
2022 supported_locales_ptr.push_back(x: &supported_locales[i]);
2023 }
2024
2025 const FlutterLocale* result =
2026 ptr(supported_locales_ptr.data(), locale_count);
2027
2028 std::unique_ptr<std::vector<std::string>> out =
2029 std::make_unique<std::vector<std::string>>();
2030 if (result) {
2031 std::string language_code(SAFE_ACCESS(result, language_code, ""));
2032 if (language_code != "") {
2033 out->push_back(x: language_code);
2034 out->emplace_back(SAFE_ACCESS(result, country_code, ""));
2035 out->emplace_back(SAFE_ACCESS(result, script_code, ""));
2036 }
2037 }
2038 return out;
2039 };
2040 }
2041
2042 flutter::PlatformViewEmbedder::OnPreEngineRestartCallback
2043 on_pre_engine_restart_callback = nullptr;
2044 if (SAFE_ACCESS(args, on_pre_engine_restart_callback, nullptr) != nullptr) {
2045 on_pre_engine_restart_callback = [ptr =
2046 args->on_pre_engine_restart_callback,
2047 user_data]() { return ptr(user_data); };
2048 }
2049
2050 auto external_view_embedder_result = InferExternalViewEmbedderFromArgs(
2051 SAFE_ACCESS(args, compositor, nullptr), enable_impeller: settings.enable_impeller);
2052 if (external_view_embedder_result.second) {
2053 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2054 "Compositor arguments were invalid.");
2055 }
2056
2057 flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
2058 {
2059 .update_semantics_callback: update_semantics_callback, //
2060 .platform_message_response_callback: platform_message_response_callback, //
2061 .vsync_callback: vsync_callback, //
2062 .compute_platform_resolved_locale_callback: compute_platform_resolved_locale_callback, //
2063 .on_pre_engine_restart_callback: on_pre_engine_restart_callback, //
2064 };
2065
2066 auto on_create_platform_view = InferPlatformViewCreationCallback(
2067 config, user_data, platform_dispatch_table,
2068 external_view_embedder: std::move(external_view_embedder_result.first), enable_impeller: settings.enable_impeller);
2069
2070 if (!on_create_platform_view) {
2071 return LOG_EMBEDDER_ERROR(
2072 kInternalInconsistency,
2073 "Could not infer platform view creation callback.");
2074 }
2075
2076 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
2077 [](flutter::Shell& shell) {
2078 return std::make_unique<flutter::Rasterizer>(args&: shell);
2079 };
2080
2081 using ExternalTextureResolver = flutter::EmbedderExternalTextureResolver;
2082 std::unique_ptr<ExternalTextureResolver> external_texture_resolver;
2083 external_texture_resolver = std::make_unique<ExternalTextureResolver>();
2084
2085#ifdef SHELL_ENABLE_GL
2086 flutter::EmbedderExternalTextureGL::ExternalTextureCallback
2087 external_texture_callback;
2088 if (config->type == kOpenGL) {
2089 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
2090 if (SAFE_ACCESS(open_gl_config, gl_external_texture_frame_callback,
2091 nullptr) != nullptr) {
2092 external_texture_callback =
2093 [ptr = open_gl_config->gl_external_texture_frame_callback, user_data](
2094 int64_t texture_identifier, size_t width,
2095 size_t height) -> std::unique_ptr<FlutterOpenGLTexture> {
2096 std::unique_ptr<FlutterOpenGLTexture> texture =
2097 std::make_unique<FlutterOpenGLTexture>();
2098 if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
2099 return nullptr;
2100 }
2101 return texture;
2102 };
2103 external_texture_resolver =
2104 std::make_unique<ExternalTextureResolver>(args&: external_texture_callback);
2105 }
2106 }
2107#endif
2108#ifdef SHELL_ENABLE_METAL
2109 flutter::EmbedderExternalTextureMetal::ExternalTextureCallback
2110 external_texture_metal_callback;
2111 if (config->type == kMetal) {
2112 const FlutterMetalRendererConfig* metal_config = &config->metal;
2113 if (SAFE_ACCESS(metal_config, external_texture_frame_callback, nullptr)) {
2114 external_texture_metal_callback =
2115 [ptr = metal_config->external_texture_frame_callback, user_data](
2116 int64_t texture_identifier, size_t width,
2117 size_t height) -> std::unique_ptr<FlutterMetalExternalTexture> {
2118 std::unique_ptr<FlutterMetalExternalTexture> texture =
2119 std::make_unique<FlutterMetalExternalTexture>();
2120 texture->struct_size = sizeof(FlutterMetalExternalTexture);
2121 if (!ptr(user_data, texture_identifier, width, height, texture.get())) {
2122 return nullptr;
2123 }
2124 return texture;
2125 };
2126 external_texture_resolver = std::make_unique<ExternalTextureResolver>(
2127 external_texture_metal_callback);
2128 }
2129 }
2130#endif
2131 auto custom_task_runners = SAFE_ACCESS(args, custom_task_runners, nullptr);
2132 auto thread_config_callback = [&custom_task_runners](
2133 const fml::Thread::ThreadConfig& config) {
2134 fml::Thread::SetCurrentThreadName(config);
2135 if (!custom_task_runners || !custom_task_runners->thread_priority_setter) {
2136 return;
2137 }
2138 FlutterThreadPriority priority = FlutterThreadPriority::kNormal;
2139 switch (config.priority) {
2140 case fml::Thread::ThreadPriority::BACKGROUND:
2141 priority = FlutterThreadPriority::kBackground;
2142 break;
2143 case fml::Thread::ThreadPriority::NORMAL:
2144 priority = FlutterThreadPriority::kNormal;
2145 break;
2146 case fml::Thread::ThreadPriority::DISPLAY:
2147 priority = FlutterThreadPriority::kDisplay;
2148 break;
2149 case fml::Thread::ThreadPriority::RASTER:
2150 priority = FlutterThreadPriority::kRaster;
2151 break;
2152 }
2153 custom_task_runners->thread_priority_setter(priority);
2154 };
2155 auto thread_host =
2156 flutter::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
2157 custom_task_runners, config_setter: thread_config_callback);
2158
2159 if (!thread_host || !thread_host->IsValid()) {
2160 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2161 "Could not set up or infer thread configuration "
2162 "to run the Flutter engine on.");
2163 }
2164
2165 auto task_runners = thread_host->GetTaskRunners();
2166
2167 if (!task_runners.IsValid()) {
2168 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2169 "Task runner configuration was invalid.");
2170 }
2171
2172 auto run_configuration =
2173 flutter::RunConfiguration::InferFromSettings(settings);
2174
2175 if (SAFE_ACCESS(args, custom_dart_entrypoint, nullptr) != nullptr) {
2176 auto dart_entrypoint = std::string{args->custom_dart_entrypoint};
2177 if (!dart_entrypoint.empty()) {
2178 run_configuration.SetEntrypoint(std::move(dart_entrypoint));
2179 }
2180 }
2181
2182 if (SAFE_ACCESS(args, dart_entrypoint_argc, 0) > 0) {
2183 if (SAFE_ACCESS(args, dart_entrypoint_argv, nullptr) == nullptr) {
2184 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2185 "Could not determine Dart entrypoint arguments "
2186 "as dart_entrypoint_argc "
2187 "was set, but dart_entrypoint_argv was null.");
2188 }
2189 std::vector<std::string> arguments(args->dart_entrypoint_argc);
2190 for (int i = 0; i < args->dart_entrypoint_argc; ++i) {
2191 arguments[i] = std::string{args->dart_entrypoint_argv[i]};
2192 }
2193 run_configuration.SetEntrypointArgs(std::move(arguments));
2194 }
2195
2196 if (!run_configuration.IsValid()) {
2197 return LOG_EMBEDDER_ERROR(
2198 kInvalidArguments,
2199 "Could not infer the Flutter project to run from given arguments.");
2200 }
2201
2202 // Create the engine but don't launch the shell or run the root isolate.
2203 auto embedder_engine = std::make_unique<flutter::EmbedderEngine>(
2204 args: std::move(thread_host), //
2205 args: std::move(task_runners), //
2206 args: std::move(settings), //
2207 args: std::move(run_configuration), //
2208 args&: on_create_platform_view, //
2209 args&: on_create_rasterizer, //
2210 args: std::move(external_texture_resolver) //
2211 );
2212
2213 // Release the ownership of the embedder engine to the caller.
2214 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(
2215 embedder_engine.release());
2216 return kSuccess;
2217}
2218
2219FlutterEngineResult FlutterEngineRunInitialized(
2220 FLUTTER_API_SYMBOL(FlutterEngine) engine) {
2221 if (!engine) {
2222 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2223 }
2224
2225 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
2226
2227 // The engine must not already be running. Initialize may only be called
2228 // once on an engine instance.
2229 if (embedder_engine->IsValid()) {
2230 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2231 }
2232
2233 // Step 1: Launch the shell.
2234 if (!embedder_engine->LaunchShell()) {
2235 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2236 "Could not launch the engine using supplied "
2237 "initialization arguments.");
2238 }
2239
2240 // Step 2: Tell the platform view to initialize itself.
2241 if (!embedder_engine->NotifyCreated()) {
2242 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2243 "Could not create platform view components.");
2244 }
2245
2246 // Step 3: Launch the root isolate.
2247 if (!embedder_engine->RunRootIsolate()) {
2248 return LOG_EMBEDDER_ERROR(
2249 kInvalidArguments,
2250 "Could not run the root isolate of the Flutter application using the "
2251 "project arguments specified.");
2252 }
2253
2254 return kSuccess;
2255}
2256
2257FLUTTER_EXPORT
2258FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine)
2259 engine) {
2260 if (engine == nullptr) {
2261 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2262 }
2263
2264 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
2265 embedder_engine->NotifyDestroyed();
2266 embedder_engine->CollectShell();
2267 return kSuccess;
2268}
2269
2270FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
2271 engine) {
2272 auto result = FlutterEngineDeinitialize(engine);
2273 if (result != kSuccess) {
2274 return result;
2275 }
2276 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
2277 delete embedder_engine;
2278 return kSuccess;
2279}
2280
2281FlutterEngineResult FlutterEngineSendWindowMetricsEvent(
2282 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2283 const FlutterWindowMetricsEvent* flutter_metrics) {
2284 if (engine == nullptr || flutter_metrics == nullptr) {
2285 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2286 }
2287 // TODO(dkwingsmt): Use a real view ID when multiview is supported.
2288 int64_t view_id = kFlutterImplicitViewId;
2289
2290 flutter::ViewportMetrics metrics;
2291
2292 metrics.physical_width = SAFE_ACCESS(flutter_metrics, width, 0.0);
2293 metrics.physical_height = SAFE_ACCESS(flutter_metrics, height, 0.0);
2294 metrics.device_pixel_ratio = SAFE_ACCESS(flutter_metrics, pixel_ratio, 1.0);
2295 metrics.physical_view_inset_top =
2296 SAFE_ACCESS(flutter_metrics, physical_view_inset_top, 0.0);
2297 metrics.physical_view_inset_right =
2298 SAFE_ACCESS(flutter_metrics, physical_view_inset_right, 0.0);
2299 metrics.physical_view_inset_bottom =
2300 SAFE_ACCESS(flutter_metrics, physical_view_inset_bottom, 0.0);
2301 metrics.physical_view_inset_left =
2302 SAFE_ACCESS(flutter_metrics, physical_view_inset_left, 0.0);
2303 metrics.display_id = SAFE_ACCESS(flutter_metrics, display_id, 0);
2304
2305 if (metrics.device_pixel_ratio <= 0.0) {
2306 return LOG_EMBEDDER_ERROR(
2307 kInvalidArguments,
2308 "Device pixel ratio was invalid. It must be greater than zero.");
2309 }
2310
2311 if (metrics.physical_view_inset_top < 0 ||
2312 metrics.physical_view_inset_right < 0 ||
2313 metrics.physical_view_inset_bottom < 0 ||
2314 metrics.physical_view_inset_left < 0) {
2315 return LOG_EMBEDDER_ERROR(
2316 kInvalidArguments,
2317 "Physical view insets are invalid. They must be non-negative.");
2318 }
2319
2320 if (metrics.physical_view_inset_top > metrics.physical_height ||
2321 metrics.physical_view_inset_right > metrics.physical_width ||
2322 metrics.physical_view_inset_bottom > metrics.physical_height ||
2323 metrics.physical_view_inset_left > metrics.physical_width) {
2324 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2325 "Physical view insets are invalid. They cannot "
2326 "be greater than physical height or width.");
2327 }
2328
2329 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->SetViewportMetrics(
2330 view_id, metrics)
2331 ? kSuccess
2332 : LOG_EMBEDDER_ERROR(kInvalidArguments,
2333 "Viewport metrics were invalid.");
2334}
2335
2336// Returns the flutter::PointerData::Change for the given FlutterPointerPhase.
2337inline flutter::PointerData::Change ToPointerDataChange(
2338 FlutterPointerPhase phase) {
2339 switch (phase) {
2340 case kCancel:
2341 return flutter::PointerData::Change::kCancel;
2342 case kUp:
2343 return flutter::PointerData::Change::kUp;
2344 case kDown:
2345 return flutter::PointerData::Change::kDown;
2346 case kMove:
2347 return flutter::PointerData::Change::kMove;
2348 case kAdd:
2349 return flutter::PointerData::Change::kAdd;
2350 case kRemove:
2351 return flutter::PointerData::Change::kRemove;
2352 case kHover:
2353 return flutter::PointerData::Change::kHover;
2354 case kPanZoomStart:
2355 return flutter::PointerData::Change::kPanZoomStart;
2356 case kPanZoomUpdate:
2357 return flutter::PointerData::Change::kPanZoomUpdate;
2358 case kPanZoomEnd:
2359 return flutter::PointerData::Change::kPanZoomEnd;
2360 }
2361 return flutter::PointerData::Change::kCancel;
2362}
2363
2364// Returns the flutter::PointerData::DeviceKind for the given
2365// FlutterPointerDeviceKind.
2366inline flutter::PointerData::DeviceKind ToPointerDataKind(
2367 FlutterPointerDeviceKind device_kind) {
2368 switch (device_kind) {
2369 case kFlutterPointerDeviceKindMouse:
2370 return flutter::PointerData::DeviceKind::kMouse;
2371 case kFlutterPointerDeviceKindTouch:
2372 return flutter::PointerData::DeviceKind::kTouch;
2373 case kFlutterPointerDeviceKindStylus:
2374 return flutter::PointerData::DeviceKind::kStylus;
2375 case kFlutterPointerDeviceKindTrackpad:
2376 return flutter::PointerData::DeviceKind::kTrackpad;
2377 }
2378 return flutter::PointerData::DeviceKind::kMouse;
2379}
2380
2381// Returns the flutter::PointerData::SignalKind for the given
2382// FlutterPointerSignaKind.
2383inline flutter::PointerData::SignalKind ToPointerDataSignalKind(
2384 FlutterPointerSignalKind kind) {
2385 switch (kind) {
2386 case kFlutterPointerSignalKindNone:
2387 return flutter::PointerData::SignalKind::kNone;
2388 case kFlutterPointerSignalKindScroll:
2389 return flutter::PointerData::SignalKind::kScroll;
2390 case kFlutterPointerSignalKindScrollInertiaCancel:
2391 return flutter::PointerData::SignalKind::kScrollInertiaCancel;
2392 case kFlutterPointerSignalKindScale:
2393 return flutter::PointerData::SignalKind::kScale;
2394 }
2395 return flutter::PointerData::SignalKind::kNone;
2396}
2397
2398// Returns the buttons to synthesize for a PointerData from a
2399// FlutterPointerEvent with no type or buttons set.
2400inline int64_t PointerDataButtonsForLegacyEvent(
2401 flutter::PointerData::Change change) {
2402 switch (change) {
2403 case flutter::PointerData::Change::kDown:
2404 case flutter::PointerData::Change::kMove:
2405 // These kinds of change must have a non-zero `buttons`, otherwise
2406 // gesture recognizers will ignore these events.
2407 return flutter::kPointerButtonMousePrimary;
2408 case flutter::PointerData::Change::kCancel:
2409 case flutter::PointerData::Change::kAdd:
2410 case flutter::PointerData::Change::kRemove:
2411 case flutter::PointerData::Change::kHover:
2412 case flutter::PointerData::Change::kUp:
2413 case flutter::PointerData::Change::kPanZoomStart:
2414 case flutter::PointerData::Change::kPanZoomUpdate:
2415 case flutter::PointerData::Change::kPanZoomEnd:
2416 return 0;
2417 }
2418 return 0;
2419}
2420
2421FlutterEngineResult FlutterEngineSendPointerEvent(
2422 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2423 const FlutterPointerEvent* pointers,
2424 size_t events_count) {
2425 if (engine == nullptr) {
2426 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2427 }
2428
2429 if (pointers == nullptr || events_count == 0) {
2430 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid pointer events.");
2431 }
2432
2433 auto packet = std::make_unique<flutter::PointerDataPacket>(args&: events_count);
2434
2435 const FlutterPointerEvent* current = pointers;
2436
2437 for (size_t i = 0; i < events_count; ++i) {
2438 flutter::PointerData pointer_data;
2439 pointer_data.Clear();
2440 // this is currely in use only on android embedding.
2441 pointer_data.embedder_id = 0;
2442 pointer_data.time_stamp = SAFE_ACCESS(current, timestamp, 0);
2443 pointer_data.change = ToPointerDataChange(
2444 SAFE_ACCESS(current, phase, FlutterPointerPhase::kCancel));
2445 pointer_data.physical_x = SAFE_ACCESS(current, x, 0.0);
2446 pointer_data.physical_y = SAFE_ACCESS(current, y, 0.0);
2447 // Delta will be generated in pointer_data_packet_converter.cc.
2448 pointer_data.physical_delta_x = 0.0;
2449 pointer_data.physical_delta_y = 0.0;
2450 pointer_data.device = SAFE_ACCESS(current, device, 0);
2451 // Pointer identifier will be generated in
2452 // pointer_data_packet_converter.cc.
2453 pointer_data.pointer_identifier = 0;
2454 pointer_data.signal_kind = ToPointerDataSignalKind(
2455 SAFE_ACCESS(current, signal_kind, kFlutterPointerSignalKindNone));
2456 pointer_data.scroll_delta_x = SAFE_ACCESS(current, scroll_delta_x, 0.0);
2457 pointer_data.scroll_delta_y = SAFE_ACCESS(current, scroll_delta_y, 0.0);
2458 FlutterPointerDeviceKind device_kind = SAFE_ACCESS(current, device_kind, 0);
2459 // For backwards compatibility with embedders written before the device
2460 // kind and buttons were exposed, if the device kind is not set treat it
2461 // as a mouse, with a synthesized primary button state based on the phase.
2462 if (device_kind == 0) {
2463 pointer_data.kind = flutter::PointerData::DeviceKind::kMouse;
2464 pointer_data.buttons =
2465 PointerDataButtonsForLegacyEvent(change: pointer_data.change);
2466
2467 } else {
2468 pointer_data.kind = ToPointerDataKind(device_kind);
2469 if (pointer_data.kind == flutter::PointerData::DeviceKind::kTouch) {
2470 // For touch events, set the button internally rather than requiring
2471 // it at the API level, since it's a confusing construction to expose.
2472 if (pointer_data.change == flutter::PointerData::Change::kDown ||
2473 pointer_data.change == flutter::PointerData::Change::kMove) {
2474 pointer_data.buttons = flutter::kPointerButtonTouchContact;
2475 }
2476 } else {
2477 // Buttons use the same mask values, so pass them through directly.
2478 pointer_data.buttons = SAFE_ACCESS(current, buttons, 0);
2479 }
2480 }
2481 pointer_data.pan_x = SAFE_ACCESS(current, pan_x, 0.0);
2482 pointer_data.pan_y = SAFE_ACCESS(current, pan_y, 0.0);
2483 // Delta will be generated in pointer_data_packet_converter.cc.
2484 pointer_data.pan_delta_x = 0.0;
2485 pointer_data.pan_delta_y = 0.0;
2486 pointer_data.scale = SAFE_ACCESS(current, scale, 0.0);
2487 pointer_data.rotation = SAFE_ACCESS(current, rotation, 0.0);
2488 packet->SetPointerData(i, data: pointer_data);
2489 current = reinterpret_cast<const FlutterPointerEvent*>(
2490 reinterpret_cast<const uint8_t*>(current) + current->struct_size);
2491 }
2492
2493 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
2494 ->DispatchPointerDataPacket(packet: std::move(packet))
2495 ? kSuccess
2496 : LOG_EMBEDDER_ERROR(kInternalInconsistency,
2497 "Could not dispatch pointer events to the "
2498 "running Flutter application.");
2499}
2500
2501static inline flutter::KeyEventType MapKeyEventType(
2502 FlutterKeyEventType event_kind) {
2503 switch (event_kind) {
2504 case kFlutterKeyEventTypeUp:
2505 return flutter::KeyEventType::kUp;
2506 case kFlutterKeyEventTypeDown:
2507 return flutter::KeyEventType::kDown;
2508 case kFlutterKeyEventTypeRepeat:
2509 return flutter::KeyEventType::kRepeat;
2510 }
2511 return flutter::KeyEventType::kUp;
2512}
2513
2514// Send a platform message to the framework.
2515//
2516// The `data_callback` will be invoked with `user_data`, and must not be empty.
2517static FlutterEngineResult InternalSendPlatformMessage(
2518 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2519 const char* channel,
2520 const uint8_t* data,
2521 size_t size,
2522 FlutterDataCallback data_callback,
2523 void* user_data) {
2524 FlutterEngineResult result;
2525
2526 FlutterPlatformMessageResponseHandle* response_handle;
2527 result = FlutterPlatformMessageCreateResponseHandle(
2528 engine, data_callback, user_data, response_out: &response_handle);
2529 if (result != kSuccess) {
2530 return result;
2531 }
2532
2533 const FlutterPlatformMessage message = {
2534 .struct_size: sizeof(FlutterPlatformMessage), // struct_size
2535 .channel: channel, // channel
2536 .message: data, // message
2537 .message_size: size, // message_size
2538 .response_handle: response_handle, // response_handle
2539 };
2540
2541 result = FlutterEngineSendPlatformMessage(engine, message: &message);
2542 // Whether `SendPlatformMessage` succeeds or not, the response handle must be
2543 // released.
2544 FlutterEngineResult release_result =
2545 FlutterPlatformMessageReleaseResponseHandle(engine, response: response_handle);
2546 if (result != kSuccess) {
2547 return result;
2548 }
2549
2550 return release_result;
2551}
2552
2553FlutterEngineResult FlutterEngineSendKeyEvent(FLUTTER_API_SYMBOL(FlutterEngine)
2554 engine,
2555 const FlutterKeyEvent* event,
2556 FlutterKeyEventCallback callback,
2557 void* user_data) {
2558 if (engine == nullptr) {
2559 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2560 }
2561
2562 if (event == nullptr) {
2563 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid key event.");
2564 }
2565
2566 const char* character = SAFE_ACCESS(event, character, nullptr);
2567
2568 flutter::KeyData key_data;
2569 key_data.Clear();
2570 key_data.timestamp = static_cast<uint64_t>(SAFE_ACCESS(event, timestamp, 0));
2571 key_data.type = MapKeyEventType(
2572 SAFE_ACCESS(event, type, FlutterKeyEventType::kFlutterKeyEventTypeUp));
2573 key_data.physical = SAFE_ACCESS(event, physical, 0);
2574 key_data.logical = SAFE_ACCESS(event, logical, 0);
2575 key_data.synthesized = SAFE_ACCESS(event, synthesized, false);
2576
2577 auto packet = std::make_unique<flutter::KeyDataPacket>(args&: key_data, args&: character);
2578
2579 struct MessageData {
2580 FlutterKeyEventCallback callback;
2581 void* user_data;
2582 };
2583
2584 MessageData* message_data =
2585 new MessageData{.callback = callback, .user_data = user_data};
2586
2587 return InternalSendPlatformMessage(
2588 engine, channel: kFlutterKeyDataChannel, data: packet->data().data(),
2589 size: packet->data().size(),
2590 data_callback: [](const uint8_t* data, size_t size, void* user_data) {
2591 auto message_data = std::unique_ptr<MessageData>(
2592 reinterpret_cast<MessageData*>(user_data));
2593 if (message_data->callback == nullptr) {
2594 return;
2595 }
2596 bool handled = false;
2597 if (size == 1) {
2598 handled = *data != 0;
2599 }
2600 message_data->callback(handled, message_data->user_data);
2601 },
2602 user_data: message_data);
2603}
2604
2605FlutterEngineResult FlutterEngineSendPlatformMessage(
2606 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2607 const FlutterPlatformMessage* flutter_message) {
2608 if (engine == nullptr) {
2609 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2610 }
2611
2612 if (flutter_message == nullptr) {
2613 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid message argument.");
2614 }
2615
2616 if (SAFE_ACCESS(flutter_message, channel, nullptr) == nullptr) {
2617 return LOG_EMBEDDER_ERROR(
2618 kInvalidArguments, "Message argument did not specify a valid channel.");
2619 }
2620
2621 size_t message_size = SAFE_ACCESS(flutter_message, message_size, 0);
2622 const uint8_t* message_data = SAFE_ACCESS(flutter_message, message, nullptr);
2623
2624 if (message_size != 0 && message_data == nullptr) {
2625 return LOG_EMBEDDER_ERROR(
2626 kInvalidArguments,
2627 "Message size was non-zero but the message data was nullptr.");
2628 }
2629
2630 const FlutterPlatformMessageResponseHandle* response_handle =
2631 SAFE_ACCESS(flutter_message, response_handle, nullptr);
2632
2633 fml::RefPtr<flutter::PlatformMessageResponse> response;
2634 if (response_handle && response_handle->message) {
2635 response = response_handle->message->response();
2636 }
2637
2638 std::unique_ptr<flutter::PlatformMessage> message;
2639 if (message_size == 0) {
2640 message = std::make_unique<flutter::PlatformMessage>(
2641 args: flutter_message->channel, args&: response);
2642 } else {
2643 message = std::make_unique<flutter::PlatformMessage>(
2644 args: flutter_message->channel,
2645 args: fml::MallocMapping::Copy(begin: message_data, length: message_size), args&: response);
2646 }
2647
2648 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
2649 ->SendPlatformMessage(message: std::move(message))
2650 ? kSuccess
2651 : LOG_EMBEDDER_ERROR(kInternalInconsistency,
2652 "Could not send a message to the running "
2653 "Flutter application.");
2654}
2655
2656FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
2657 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2658 FlutterDataCallback data_callback,
2659 void* user_data,
2660 FlutterPlatformMessageResponseHandle** response_out) {
2661 if (engine == nullptr) {
2662 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2663 }
2664
2665 if (data_callback == nullptr || response_out == nullptr) {
2666 return LOG_EMBEDDER_ERROR(
2667 kInvalidArguments, "Data callback or the response handle was invalid.");
2668 }
2669
2670 flutter::EmbedderPlatformMessageResponse::Callback response_callback =
2671 [user_data, data_callback](const uint8_t* data, size_t size) {
2672 data_callback(data, size, user_data);
2673 };
2674
2675 auto platform_task_runner = reinterpret_cast<flutter::EmbedderEngine*>(engine)
2676 ->GetTaskRunners()
2677 .GetPlatformTaskRunner();
2678
2679 auto handle = new FlutterPlatformMessageResponseHandle();
2680
2681 handle->message = std::make_unique<flutter::PlatformMessage>(
2682 args: "", // The channel is empty and unused as the response handle is going
2683 // to referenced directly in the |FlutterEngineSendPlatformMessage|
2684 // with the container message discarded.
2685 args: fml::MakeRefCounted<flutter::EmbedderPlatformMessageResponse>(
2686 args: std::move(platform_task_runner), args&: response_callback));
2687 *response_out = handle;
2688 return kSuccess;
2689}
2690
2691FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
2692 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2693 FlutterPlatformMessageResponseHandle* response) {
2694 if (engine == nullptr) {
2695 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2696 }
2697
2698 if (response == nullptr) {
2699 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid response handle.");
2700 }
2701 delete response;
2702 return kSuccess;
2703}
2704
2705// Note: This can execute on any thread.
2706FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
2707 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2708 const FlutterPlatformMessageResponseHandle* handle,
2709 const uint8_t* data,
2710 size_t data_length) {
2711 if (data_length != 0 && data == nullptr) {
2712 return LOG_EMBEDDER_ERROR(
2713 kInvalidArguments,
2714 "Data size was non zero but the pointer to the data was null.");
2715 }
2716
2717 auto response = handle->message->response();
2718
2719 if (response) {
2720 if (data_length == 0) {
2721 response->CompleteEmpty();
2722 } else {
2723 response->Complete(data: std::make_unique<fml::DataMapping>(
2724 args: std::vector<uint8_t>({data, data + data_length})));
2725 }
2726 }
2727
2728 delete handle;
2729
2730 return kSuccess;
2731}
2732
2733FlutterEngineResult __FlutterEngineFlushPendingTasksNow() {
2734 fml::MessageLoop::GetCurrent().RunExpiredTasksNow();
2735 return kSuccess;
2736}
2737
2738FlutterEngineResult FlutterEngineRegisterExternalTexture(
2739 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2740 int64_t texture_identifier) {
2741 if (engine == nullptr) {
2742 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2743 }
2744
2745 if (texture_identifier == 0) {
2746 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2747 "Texture identifier was invalid.");
2748 }
2749 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->RegisterTexture(
2750 texture: texture_identifier)) {
2751 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2752 "Could not register the specified texture.");
2753 }
2754 return kSuccess;
2755}
2756
2757FlutterEngineResult FlutterEngineUnregisterExternalTexture(
2758 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2759 int64_t texture_identifier) {
2760 if (engine == nullptr) {
2761 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
2762 }
2763
2764 if (texture_identifier == 0) {
2765 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2766 "Texture identifier was invalid.");
2767 }
2768
2769 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->UnregisterTexture(
2770 texture: texture_identifier)) {
2771 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2772 "Could not un-register the specified texture.");
2773 }
2774
2775 return kSuccess;
2776}
2777
2778FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable(
2779 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2780 int64_t texture_identifier) {
2781 if (engine == nullptr) {
2782 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2783 }
2784 if (texture_identifier == 0) {
2785 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid texture identifier.");
2786 }
2787 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)
2788 ->MarkTextureFrameAvailable(texture: texture_identifier)) {
2789 return LOG_EMBEDDER_ERROR(
2790 kInternalInconsistency,
2791 "Could not mark the texture frame as being available.");
2792 }
2793 return kSuccess;
2794}
2795
2796FlutterEngineResult FlutterEngineUpdateSemanticsEnabled(
2797 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2798 bool enabled) {
2799 if (engine == nullptr) {
2800 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2801 }
2802 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->SetSemanticsEnabled(
2803 enabled)) {
2804 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2805 "Could not update semantics state.");
2806 }
2807 return kSuccess;
2808}
2809
2810FlutterEngineResult FlutterEngineUpdateAccessibilityFeatures(
2811 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2812 FlutterAccessibilityFeature flags) {
2813 if (engine == nullptr) {
2814 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2815 }
2816 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)
2817 ->SetAccessibilityFeatures(flags)) {
2818 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2819 "Could not update accessibility features.");
2820 }
2821 return kSuccess;
2822}
2823
2824FlutterEngineResult FlutterEngineDispatchSemanticsAction(
2825 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2826 uint64_t node_id,
2827 FlutterSemanticsAction action,
2828 const uint8_t* data,
2829 size_t data_length) {
2830 if (engine == nullptr) {
2831 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2832 }
2833 auto engine_action = static_cast<flutter::SemanticsAction>(action);
2834 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)
2835 ->DispatchSemanticsAction(
2836 node_id, action: engine_action,
2837 args: fml::MallocMapping::Copy(begin: data, length: data_length))) {
2838 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2839 "Could not dispatch semantics action.");
2840 }
2841 return kSuccess;
2842}
2843
2844FlutterEngineResult FlutterEngineOnVsync(FLUTTER_API_SYMBOL(FlutterEngine)
2845 engine,
2846 intptr_t baton,
2847 uint64_t frame_start_time_nanos,
2848 uint64_t frame_target_time_nanos) {
2849 if (engine == nullptr) {
2850 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2851 }
2852
2853 TRACE_EVENT0("flutter", "FlutterEngineOnVsync");
2854
2855 auto start_time = fml::TimePoint::FromEpochDelta(
2856 ticks: fml::TimeDelta::FromNanoseconds(nanos: frame_start_time_nanos));
2857
2858 auto target_time = fml::TimePoint::FromEpochDelta(
2859 ticks: fml::TimeDelta::FromNanoseconds(nanos: frame_target_time_nanos));
2860
2861 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->OnVsyncEvent(
2862 baton, frame_start_time: start_time, frame_target_time: target_time)) {
2863 return LOG_EMBEDDER_ERROR(
2864 kInternalInconsistency,
2865 "Could not notify the running engine instance of a Vsync event.");
2866 }
2867
2868 return kSuccess;
2869}
2870
2871FlutterEngineResult FlutterEngineReloadSystemFonts(
2872 FLUTTER_API_SYMBOL(FlutterEngine) engine) {
2873 if (engine == nullptr) {
2874 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2875 }
2876
2877 TRACE_EVENT0("flutter", "FlutterEngineReloadSystemFonts");
2878
2879 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)
2880 ->ReloadSystemFonts()) {
2881 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
2882 "Could not reload system fonts.");
2883 }
2884
2885 return kSuccess;
2886}
2887
2888void FlutterEngineTraceEventDurationBegin(const char* name) {
2889 fml::tracing::TraceEvent0(category_group: "flutter", name, /*flow_id_count=*/0,
2890 /*flow_id=*/flow_ids: nullptr);
2891}
2892
2893void FlutterEngineTraceEventDurationEnd(const char* name) {
2894 fml::tracing::TraceEventEnd(name);
2895}
2896
2897void FlutterEngineTraceEventInstant(const char* name) {
2898 fml::tracing::TraceEventInstant0(category_group: "flutter", name, /*flow_id_count=*/0,
2899 /*flow_id=*/flow_ids: nullptr);
2900}
2901
2902FlutterEngineResult FlutterEnginePostRenderThreadTask(
2903 FLUTTER_API_SYMBOL(FlutterEngine) engine,
2904 VoidCallback callback,
2905 void* baton) {
2906 if (engine == nullptr) {
2907 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2908 }
2909
2910 if (callback == nullptr) {
2911 return LOG_EMBEDDER_ERROR(kInvalidArguments,
2912 "Render thread callback was null.");
2913 }
2914
2915 auto task = [callback, baton]() { callback(baton); };
2916
2917 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
2918 ->PostRenderThreadTask(task)
2919 ? kSuccess
2920 : LOG_EMBEDDER_ERROR(kInternalInconsistency,
2921 "Could not post the render thread task.");
2922}
2923
2924uint64_t FlutterEngineGetCurrentTime() {
2925 return fml::TimePoint::Now().ToEpochDelta().ToNanoseconds();
2926}
2927
2928FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine)
2929 engine,
2930 const FlutterTask* task) {
2931 if (engine == nullptr) {
2932 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2933 }
2934
2935 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->RunTask(task)
2936 ? kSuccess
2937 : LOG_EMBEDDER_ERROR(kInvalidArguments,
2938 "Could not run the specified task.");
2939}
2940
2941static bool DispatchJSONPlatformMessage(FLUTTER_API_SYMBOL(FlutterEngine)
2942 engine,
2943 const rapidjson::Document& document,
2944 const std::string& channel_name) {
2945 if (channel_name.empty()) {
2946 return false;
2947 }
2948
2949 rapidjson::StringBuffer buffer;
2950 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
2951
2952 if (!document.Accept(handler&: writer)) {
2953 return false;
2954 }
2955
2956 const char* message = buffer.GetString();
2957
2958 if (message == nullptr || buffer.GetSize() == 0) {
2959 return false;
2960 }
2961
2962 auto platform_message = std::make_unique<flutter::PlatformMessage>(
2963 args: channel_name.c_str(), // channel
2964 args: fml::MallocMapping::Copy(begin: message,
2965 length: buffer.GetSize()), // message
2966 args: nullptr // response
2967 );
2968
2969 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
2970 ->SendPlatformMessage(message: std::move(platform_message));
2971}
2972
2973FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine)
2974 engine,
2975 const FlutterLocale** locales,
2976 size_t locales_count) {
2977 if (engine == nullptr) {
2978 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
2979 }
2980
2981 if (locales_count == 0) {
2982 return kSuccess;
2983 }
2984
2985 if (locales == nullptr) {
2986 return LOG_EMBEDDER_ERROR(kInvalidArguments, "No locales were specified.");
2987 }
2988
2989 rapidjson::Document document;
2990 auto& allocator = document.GetAllocator();
2991
2992 document.SetObject();
2993 document.AddMember(name: "method", value: "setLocale", allocator);
2994
2995 rapidjson::Value args(rapidjson::kArrayType);
2996 args.Reserve(newCapacity: locales_count * 4, allocator);
2997 for (size_t i = 0; i < locales_count; ++i) {
2998 const FlutterLocale* locale = locales[i];
2999 const char* language_code_str = SAFE_ACCESS(locale, language_code, nullptr);
3000 if (language_code_str == nullptr || ::strlen(s: language_code_str) == 0) {
3001 return LOG_EMBEDDER_ERROR(
3002 kInvalidArguments,
3003 "Language code is required but not present in FlutterLocale.");
3004 }
3005
3006 const char* country_code_str = SAFE_ACCESS(locale, country_code, "");
3007 const char* script_code_str = SAFE_ACCESS(locale, script_code, "");
3008 const char* variant_code_str = SAFE_ACCESS(locale, variant_code, "");
3009
3010 rapidjson::Value language_code, country_code, script_code, variant_code;
3011
3012 language_code.SetString(s: language_code_str, allocator);
3013 country_code.SetString(s: country_code_str ? country_code_str : "", allocator);
3014 script_code.SetString(s: script_code_str ? script_code_str : "", allocator);
3015 variant_code.SetString(s: variant_code_str ? variant_code_str : "", allocator);
3016
3017 // Required.
3018 args.PushBack(value&: language_code, allocator);
3019 args.PushBack(value&: country_code, allocator);
3020 args.PushBack(value&: script_code, allocator);
3021 args.PushBack(value&: variant_code, allocator);
3022 }
3023 document.AddMember(name: "args", value&: args, allocator);
3024
3025 return DispatchJSONPlatformMessage(engine, document, channel_name: "flutter/localization")
3026 ? kSuccess
3027 : LOG_EMBEDDER_ERROR(kInternalInconsistency,
3028 "Could not send message to update locale of "
3029 "a running Flutter application.");
3030}
3031
3032bool FlutterEngineRunsAOTCompiledDartCode(void) {
3033 return flutter::DartVM::IsRunningPrecompiledCode();
3034}
3035
3036FlutterEngineResult FlutterEnginePostDartObject(
3037 FLUTTER_API_SYMBOL(FlutterEngine) engine,
3038 FlutterEngineDartPort port,
3039 const FlutterEngineDartObject* object) {
3040 if (engine == nullptr) {
3041 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
3042 }
3043
3044 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->IsValid()) {
3045 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine not running.");
3046 }
3047
3048 if (port == ILLEGAL_PORT) {
3049 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3050 "Attempted to post to an illegal port.");
3051 }
3052
3053 if (object == nullptr) {
3054 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3055 "Invalid Dart object to post.");
3056 }
3057
3058 Dart_CObject dart_object = {};
3059 fml::ScopedCleanupClosure typed_data_finalizer;
3060
3061 switch (object->type) {
3062 case kFlutterEngineDartObjectTypeNull:
3063 dart_object.type = Dart_CObject_kNull;
3064 break;
3065 case kFlutterEngineDartObjectTypeBool:
3066 dart_object.type = Dart_CObject_kBool;
3067 dart_object.value.as_bool = object->bool_value;
3068 break;
3069 case kFlutterEngineDartObjectTypeInt32:
3070 dart_object.type = Dart_CObject_kInt32;
3071 dart_object.value.as_int32 = object->int32_value;
3072 break;
3073 case kFlutterEngineDartObjectTypeInt64:
3074 dart_object.type = Dart_CObject_kInt64;
3075 dart_object.value.as_int64 = object->int64_value;
3076 break;
3077 case kFlutterEngineDartObjectTypeDouble:
3078 dart_object.type = Dart_CObject_kDouble;
3079 dart_object.value.as_double = object->double_value;
3080 break;
3081 case kFlutterEngineDartObjectTypeString:
3082 if (object->string_value == nullptr) {
3083 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3084 "kFlutterEngineDartObjectTypeString must be "
3085 "a null terminated string but was null.");
3086 }
3087 dart_object.type = Dart_CObject_kString;
3088 dart_object.value.as_string = const_cast<char*>(object->string_value);
3089 break;
3090 case kFlutterEngineDartObjectTypeBuffer: {
3091 auto* buffer = SAFE_ACCESS(object->buffer_value, buffer, nullptr);
3092 if (buffer == nullptr) {
3093 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3094 "kFlutterEngineDartObjectTypeBuffer must "
3095 "specify a buffer but found nullptr.");
3096 }
3097 auto buffer_size = SAFE_ACCESS(object->buffer_value, buffer_size, 0);
3098 auto callback =
3099 SAFE_ACCESS(object->buffer_value, buffer_collect_callback, nullptr);
3100 auto user_data = SAFE_ACCESS(object->buffer_value, user_data, nullptr);
3101
3102 // The user has provided a callback, let them manage the lifecycle of
3103 // the underlying data. If not, copy it out from the provided buffer.
3104
3105 if (callback == nullptr) {
3106 dart_object.type = Dart_CObject_kTypedData;
3107 dart_object.value.as_typed_data.type = Dart_TypedData_kUint8;
3108 dart_object.value.as_typed_data.length = buffer_size;
3109 dart_object.value.as_typed_data.values = buffer;
3110 } else {
3111 struct ExternalTypedDataPeer {
3112 void* user_data = nullptr;
3113 VoidCallback trampoline = nullptr;
3114 };
3115 auto peer = new ExternalTypedDataPeer();
3116 peer->user_data = user_data;
3117 peer->trampoline = callback;
3118 // This finalizer is set so that in case of failure of the
3119 // Dart_PostCObject below, we collect the peer. The embedder is still
3120 // responsible for collecting the buffer in case of non-kSuccess
3121 // returns from this method. This finalizer must be released in case
3122 // of kSuccess returns from this method.
3123 typed_data_finalizer.SetClosure([peer]() {
3124 // This is the tiny object we use as the peer to the Dart call so
3125 // that we can attach the a trampoline to the embedder supplied
3126 // callback. In case of error, we need to collect this object lest
3127 // we introduce a tiny leak.
3128 delete peer;
3129 });
3130 dart_object.type = Dart_CObject_kExternalTypedData;
3131 dart_object.value.as_external_typed_data.type = Dart_TypedData_kUint8;
3132 dart_object.value.as_external_typed_data.length = buffer_size;
3133 dart_object.value.as_external_typed_data.data = buffer;
3134 dart_object.value.as_external_typed_data.peer = peer;
3135 dart_object.value.as_external_typed_data.callback =
3136 +[](void* unused_isolate_callback_data, void* peer) {
3137 auto typed_peer = reinterpret_cast<ExternalTypedDataPeer*>(peer);
3138 typed_peer->trampoline(typed_peer->user_data);
3139 delete typed_peer;
3140 };
3141 }
3142 } break;
3143 default:
3144 return LOG_EMBEDDER_ERROR(
3145 kInvalidArguments,
3146 "Invalid FlutterEngineDartObjectType type specified.");
3147 }
3148
3149 if (!Dart_PostCObject(port_id: port, message: &dart_object)) {
3150 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
3151 "Could not post the object to the Dart VM.");
3152 }
3153
3154 // On a successful call, the VM takes ownership of and is responsible for
3155 // invoking the finalizer.
3156 typed_data_finalizer.Release();
3157 return kSuccess;
3158}
3159
3160FlutterEngineResult FlutterEngineNotifyLowMemoryWarning(
3161 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine) {
3162 auto engine = reinterpret_cast<flutter::EmbedderEngine*>(raw_engine);
3163 if (engine == nullptr || !engine->IsValid()) {
3164 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine was invalid.");
3165 }
3166
3167 engine->GetShell().NotifyLowMemoryWarning();
3168
3169 rapidjson::Document document;
3170 auto& allocator = document.GetAllocator();
3171
3172 document.SetObject();
3173 document.AddMember(name: "type", value: "memoryPressure", allocator);
3174
3175 return DispatchJSONPlatformMessage(engine: raw_engine, document, channel_name: "flutter/system")
3176 ? kSuccess
3177 : LOG_EMBEDDER_ERROR(
3178 kInternalInconsistency,
3179 "Could not dispatch the low memory notification message.");
3180}
3181
3182FlutterEngineResult FlutterEnginePostCallbackOnAllNativeThreads(
3183 FLUTTER_API_SYMBOL(FlutterEngine) engine,
3184 FlutterNativeThreadCallback callback,
3185 void* user_data) {
3186 if (engine == nullptr) {
3187 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
3188 }
3189
3190 if (callback == nullptr) {
3191 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3192 "Invalid native thread callback.");
3193 }
3194
3195 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
3196 ->PostTaskOnEngineManagedNativeThreads(
3197 closure: [callback, user_data](FlutterNativeThreadType type) {
3198 callback(type, user_data);
3199 })
3200 ? kSuccess
3201 : LOG_EMBEDDER_ERROR(kInvalidArguments,
3202 "Internal error while attempting to post "
3203 "tasks to all threads.");
3204}
3205
3206namespace {
3207static bool ValidDisplayConfiguration(const FlutterEngineDisplay* displays,
3208 size_t display_count) {
3209 std::set<FlutterEngineDisplayId> display_ids;
3210 for (size_t i = 0; i < display_count; i++) {
3211 if (displays[i].single_display && display_count != 1) {
3212 return false;
3213 }
3214 display_ids.insert(v: displays[i].display_id);
3215 }
3216
3217 return display_ids.size() == display_count;
3218}
3219} // namespace
3220
3221FlutterEngineResult FlutterEngineNotifyDisplayUpdate(
3222 FLUTTER_API_SYMBOL(FlutterEngine) raw_engine,
3223 const FlutterEngineDisplaysUpdateType update_type,
3224 const FlutterEngineDisplay* embedder_displays,
3225 size_t display_count) {
3226 if (raw_engine == nullptr) {
3227 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
3228 }
3229
3230 if (!ValidDisplayConfiguration(displays: embedder_displays, display_count)) {
3231 return LOG_EMBEDDER_ERROR(
3232 kInvalidArguments,
3233 "Invalid FlutterEngineDisplay configuration specified.");
3234 }
3235
3236 auto engine = reinterpret_cast<flutter::EmbedderEngine*>(raw_engine);
3237
3238 switch (update_type) {
3239 case kFlutterEngineDisplaysUpdateTypeStartup: {
3240 std::vector<std::unique_ptr<flutter::Display>> displays;
3241 const auto* display = embedder_displays;
3242 for (size_t i = 0; i < display_count; i++) {
3243 displays.push_back(x: std::make_unique<flutter::Display>(
3244 SAFE_ACCESS(display, display_id, i), //
3245 SAFE_ACCESS(display, refresh_rate, 0), //
3246 SAFE_ACCESS(display, width, 0), //
3247 SAFE_ACCESS(display, height, 0), //
3248 SAFE_ACCESS(display, device_pixel_ratio, 1)));
3249 display = reinterpret_cast<const FlutterEngineDisplay*>(
3250 reinterpret_cast<const uint8_t*>(display) + display->struct_size);
3251 }
3252 engine->GetShell().OnDisplayUpdates(displays: std::move(displays));
3253 return kSuccess;
3254 }
3255 default:
3256 return LOG_EMBEDDER_ERROR(
3257 kInvalidArguments,
3258 "Invalid FlutterEngineDisplaysUpdateType type specified.");
3259 }
3260}
3261
3262FlutterEngineResult FlutterEngineScheduleFrame(FLUTTER_API_SYMBOL(FlutterEngine)
3263 engine) {
3264 if (engine == nullptr) {
3265 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
3266 }
3267
3268 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->ScheduleFrame()
3269 ? kSuccess
3270 : LOG_EMBEDDER_ERROR(kInvalidArguments,
3271 "Could not schedule frame.");
3272}
3273
3274FlutterEngineResult FlutterEngineSetNextFrameCallback(
3275 FLUTTER_API_SYMBOL(FlutterEngine) engine,
3276 VoidCallback callback,
3277 void* user_data) {
3278 if (engine == nullptr) {
3279 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle.");
3280 }
3281
3282 if (callback == nullptr) {
3283 return LOG_EMBEDDER_ERROR(kInvalidArguments,
3284 "Next frame callback was null.");
3285 }
3286
3287 flutter::EmbedderEngine* embedder_engine =
3288 reinterpret_cast<flutter::EmbedderEngine*>(engine);
3289
3290 fml::WeakPtr<flutter::PlatformView> weak_platform_view =
3291 embedder_engine->GetShell().GetPlatformView();
3292
3293 if (!weak_platform_view) {
3294 return LOG_EMBEDDER_ERROR(kInternalInconsistency,
3295 "Platform view unavailable.");
3296 }
3297
3298 weak_platform_view->SetNextFrameCallback(
3299 [callback, user_data]() { callback(user_data); });
3300
3301 return kSuccess;
3302}
3303
3304FlutterEngineResult FlutterEngineGetProcAddresses(
3305 FlutterEngineProcTable* table) {
3306 if (!table) {
3307 return LOG_EMBEDDER_ERROR(kInvalidArguments, "Null table specified.");
3308 }
3309#define SET_PROC(member, function) \
3310 if (STRUCT_HAS_MEMBER(table, member)) { \
3311 table->member = &function; \
3312 }
3313
3314 SET_PROC(CreateAOTData, FlutterEngineCreateAOTData);
3315 SET_PROC(CollectAOTData, FlutterEngineCollectAOTData);
3316 SET_PROC(Run, FlutterEngineRun);
3317 SET_PROC(Shutdown, FlutterEngineShutdown);
3318 SET_PROC(Initialize, FlutterEngineInitialize);
3319 SET_PROC(Deinitialize, FlutterEngineDeinitialize);
3320 SET_PROC(RunInitialized, FlutterEngineRunInitialized);
3321 SET_PROC(SendWindowMetricsEvent, FlutterEngineSendWindowMetricsEvent);
3322 SET_PROC(SendPointerEvent, FlutterEngineSendPointerEvent);
3323 SET_PROC(SendKeyEvent, FlutterEngineSendKeyEvent);
3324 SET_PROC(SendPlatformMessage, FlutterEngineSendPlatformMessage);
3325 SET_PROC(PlatformMessageCreateResponseHandle,
3326 FlutterPlatformMessageCreateResponseHandle);
3327 SET_PROC(PlatformMessageReleaseResponseHandle,
3328 FlutterPlatformMessageReleaseResponseHandle);
3329 SET_PROC(SendPlatformMessageResponse,
3330 FlutterEngineSendPlatformMessageResponse);
3331 SET_PROC(RegisterExternalTexture, FlutterEngineRegisterExternalTexture);
3332 SET_PROC(UnregisterExternalTexture, FlutterEngineUnregisterExternalTexture);
3333 SET_PROC(MarkExternalTextureFrameAvailable,
3334 FlutterEngineMarkExternalTextureFrameAvailable);
3335 SET_PROC(UpdateSemanticsEnabled, FlutterEngineUpdateSemanticsEnabled);
3336 SET_PROC(UpdateAccessibilityFeatures,
3337 FlutterEngineUpdateAccessibilityFeatures);
3338 SET_PROC(DispatchSemanticsAction, FlutterEngineDispatchSemanticsAction);
3339 SET_PROC(OnVsync, FlutterEngineOnVsync);
3340 SET_PROC(ReloadSystemFonts, FlutterEngineReloadSystemFonts);
3341 SET_PROC(TraceEventDurationBegin, FlutterEngineTraceEventDurationBegin);
3342 SET_PROC(TraceEventDurationEnd, FlutterEngineTraceEventDurationEnd);
3343 SET_PROC(TraceEventInstant, FlutterEngineTraceEventInstant);
3344 SET_PROC(PostRenderThreadTask, FlutterEnginePostRenderThreadTask);
3345 SET_PROC(GetCurrentTime, FlutterEngineGetCurrentTime);
3346 SET_PROC(RunTask, FlutterEngineRunTask);
3347 SET_PROC(UpdateLocales, FlutterEngineUpdateLocales);
3348 SET_PROC(RunsAOTCompiledDartCode, FlutterEngineRunsAOTCompiledDartCode);
3349 SET_PROC(PostDartObject, FlutterEnginePostDartObject);
3350 SET_PROC(NotifyLowMemoryWarning, FlutterEngineNotifyLowMemoryWarning);
3351 SET_PROC(PostCallbackOnAllNativeThreads,
3352 FlutterEnginePostCallbackOnAllNativeThreads);
3353 SET_PROC(NotifyDisplayUpdate, FlutterEngineNotifyDisplayUpdate);
3354 SET_PROC(ScheduleFrame, FlutterEngineScheduleFrame);
3355 SET_PROC(SetNextFrameCallback, FlutterEngineSetNextFrameCallback);
3356#undef SET_PROC
3357
3358 return kSuccess;
3359}
3360

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/flutter/shell/platform/embedder/embedder.cc