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 // 2021.2.10 Framework adapted to ACE.
5 // Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved.
6
7 #define FML_USED_ON_EMBEDDER
8
9 #include "flutter/fml/build_config.h"
10 #include "flutter/fml/make_copyable.h"
11 #include "flutter/fml/native_library.h"
12
13 #if OS_WIN
14 #define FLUTTER_EXPORT __declspec(dllexport)
15 #else // OS_WIN
16 #define FLUTTER_EXPORT __attribute__((visibility("default")))
17 #endif // OS_WIN
18
19 extern "C" {
20 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
21 // Used for debugging dart:* sources.
22 extern const uint8_t kPlatformStrongDill[];
23 extern const intptr_t kPlatformStrongDillSize;
24 #endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
25 }
26
27 #include "flutter/assets/directory_asset_bundle.h"
28 #include "flutter/common/task_runners.h"
29 #include "flutter/fml/command_line.h"
30 #include "flutter/fml/file.h"
31 #include "flutter/fml/make_copyable.h"
32 #include "flutter/fml/message_loop.h"
33 #include "flutter/fml/paths.h"
34 #include "flutter/fml/trace_event.h"
35 #include "flutter/shell/common/persistent_cache.h"
36 #include "flutter/shell/common/rasterizer.h"
37 #include "flutter/shell/common/switches.h"
38 #include "flutter/shell/platform/embedder/embedder.h"
39 #include "flutter/shell/platform/embedder/embedder_engine.h"
40 #include "flutter/shell/platform/embedder/embedder_platform_message_response.h"
41 #include "flutter/shell/platform/embedder/embedder_render_target.h"
42 #include "flutter/shell/platform/embedder/embedder_safe_access.h"
43 #include "flutter/shell/platform/embedder/embedder_task_runner.h"
44 #include "flutter/shell/platform/embedder/embedder_thread_host.h"
45 #include "flutter/shell/platform/embedder/platform_view_embedder.h"
46
47 #include <iostream>
48
49 #ifdef USE_GLFW_WINDOW
50 namespace {
51
52 HandleTouchEventCallback g_HandleTouchEventCallback;
53
54 }
55 #endif
56
LogEmbedderError(FlutterEngineResult code,const char * name,const char * function,const char * file,int line)57 static FlutterEngineResult LogEmbedderError(FlutterEngineResult code,
58 const char* name,
59 const char* function,
60 const char* file,
61 int line) {
62 FML_LOG(ERROR) << "Returning error '" << name << "' (" << code
63 << ") from Flutter Embedder API call to '" << function
64 << "'. Origin: " << file << ":" << line;
65 return code;
66 }
67
68 #define LOG_EMBEDDER_ERROR(code) \
69 LogEmbedderError(code, #code, __FUNCTION__, __FILE__, __LINE__)
70
IsOpenGLRendererConfigValid(const FlutterRendererConfig * config)71 static bool IsOpenGLRendererConfigValid(const FlutterRendererConfig* config) {
72 if (config->type != kOpenGL) {
73 return false;
74 }
75
76 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
77
78 if (SAFE_ACCESS(open_gl_config, make_current, nullptr) == nullptr ||
79 SAFE_ACCESS(open_gl_config, clear_current, nullptr) == nullptr ||
80 SAFE_ACCESS(open_gl_config, present, nullptr) == nullptr ||
81 SAFE_ACCESS(open_gl_config, fbo_callback, nullptr) == nullptr) {
82 return false;
83 }
84
85 return true;
86 }
87
IsSoftwareRendererConfigValid(const FlutterRendererConfig * config)88 static bool IsSoftwareRendererConfigValid(const FlutterRendererConfig* config) {
89 if (config->type != kSoftware) {
90 return false;
91 }
92
93 const FlutterSoftwareRendererConfig* software_config = &config->software;
94
95 if (SAFE_ACCESS(software_config, surface_present_callback, nullptr) ==
96 nullptr) {
97 return false;
98 }
99
100 return true;
101 }
102
IsRendererValid(const FlutterRendererConfig * config)103 static bool IsRendererValid(const FlutterRendererConfig* config) {
104 if (config == nullptr) {
105 return false;
106 }
107
108 switch (config->type) {
109 case kOpenGL:
110 return IsOpenGLRendererConfigValid(config);
111 case kSoftware:
112 return IsSoftwareRendererConfigValid(config);
113 default:
114 return false;
115 }
116
117 return false;
118 }
119
120 #if OS_LINUX || OS_WIN
DefaultGLProcResolver(const char * name)121 static void* DefaultGLProcResolver(const char* name) {
122 static fml::RefPtr<fml::NativeLibrary> proc_library =
123 #if OS_LINUX
124 fml::NativeLibrary::CreateForCurrentProcess();
125 #elif OS_WIN // OS_LINUX
126 fml::NativeLibrary::Create("opengl32.dll");
127 #endif // OS_WIN
128 return static_cast<void*>(
129 const_cast<uint8_t*>(proc_library->ResolveSymbol(name)));
130 }
131 #endif // OS_LINUX || OS_WIN
132
133 static flutter::Shell::CreateCallback<flutter::PlatformView>
InferOpenGLPlatformViewCreationCallback(const FlutterRendererConfig * config,void * user_data,flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table,std::unique_ptr<flutter::EmbedderExternalViewEmbedder> external_view_embedder)134 InferOpenGLPlatformViewCreationCallback(
135 const FlutterRendererConfig* config,
136 void* user_data,
137 flutter::PlatformViewEmbedder::PlatformDispatchTable
138 platform_dispatch_table,
139 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
140 external_view_embedder) {
141 if (config->type != kOpenGL) {
142 return nullptr;
143 }
144
145 auto gl_make_current = [ptr = config->open_gl.make_current,
146 user_data]() -> bool { return ptr(user_data); };
147
148 auto gl_clear_current = [ptr = config->open_gl.clear_current,
149 user_data]() -> bool { return ptr(user_data); };
150
151 auto gl_present = [ptr = config->open_gl.present, user_data]() -> bool {
152 return ptr(user_data);
153 };
154
155 auto gl_send_surface = [ptr = config->open_gl.send_current_surface,
156 user_data](const void* pixels, const size_t size,
157 const int32_t width,
158 const int32_t height) -> bool {
159 return ptr(pixels, size, width, height);
160 };
161
162 auto gl_fbo_callback = [ptr = config->open_gl.fbo_callback,
163 user_data]() -> intptr_t { return ptr(user_data); };
164
165 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
166 std::function<bool()> gl_make_resource_current_callback = nullptr;
167 if (SAFE_ACCESS(open_gl_config, make_resource_current, nullptr) != nullptr) {
168 gl_make_resource_current_callback =
169 [ptr = config->open_gl.make_resource_current, user_data]() {
170 return ptr(user_data);
171 };
172 }
173
174 std::function<SkMatrix(void)> gl_surface_transformation_callback = nullptr;
175 if (SAFE_ACCESS(open_gl_config, surface_transformation, nullptr) != nullptr) {
176 gl_surface_transformation_callback =
177 [ptr = config->open_gl.surface_transformation, user_data]() {
178 FlutterTransformation transformation = ptr(user_data);
179 return SkMatrix::MakeAll(transformation.scaleX, //
180 transformation.skewX, //
181 transformation.transX, //
182 transformation.skewY, //
183 transformation.scaleY, //
184 transformation.transY, //
185 transformation.pers0, //
186 transformation.pers1, //
187 transformation.pers2 //
188 );
189 };
190 }
191
192 flutter::GPUSurfaceGLDelegate::GLProcResolver gl_proc_resolver = nullptr;
193 if (SAFE_ACCESS(open_gl_config, gl_proc_resolver, nullptr) != nullptr) {
194 gl_proc_resolver = [ptr = config->open_gl.gl_proc_resolver,
195 user_data](const char* gl_proc_name) {
196 return ptr(user_data, gl_proc_name);
197 };
198 } else {
199 #if OS_LINUX || OS_WIN
200 gl_proc_resolver = DefaultGLProcResolver;
201 #endif
202 }
203
204 bool fbo_reset_after_present =
205 SAFE_ACCESS(open_gl_config, fbo_reset_after_present, false);
206
207 flutter::EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table = {
208 gl_make_current, // gl_make_current_callback
209 gl_clear_current, // gl_clear_current_callback
210 gl_present, // gl_present_callback
211 gl_send_surface, // gl_send_surface_callback
212 gl_fbo_callback, // gl_fbo_callback
213 gl_make_resource_current_callback, // gl_make_resource_current_callback
214 gl_surface_transformation_callback, // gl_surface_transformation_callback
215 gl_proc_resolver, // gl_proc_resolver
216 };
217
218 return fml::MakeCopyable(
219 [gl_dispatch_table, fbo_reset_after_present, platform_dispatch_table,
220 external_view_embedder =
221 std::move(external_view_embedder)](flutter::Shell& shell) mutable {
222 return std::make_unique<flutter::PlatformViewEmbedder>(
223 shell, // delegate
224 shell.GetTaskRunners(), // task runners
225 gl_dispatch_table, // embedder GL dispatch table
226 fbo_reset_after_present, // fbo reset after present
227 platform_dispatch_table, // embedder platform dispatch table
228 std::move(external_view_embedder) // external view embedder
229 );
230 });
231 }
232
233 static flutter::Shell::CreateCallback<flutter::PlatformView>
InferSoftwarePlatformViewCreationCallback(const FlutterRendererConfig * config,void * user_data,flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table,std::unique_ptr<flutter::EmbedderExternalViewEmbedder> external_view_embedder)234 InferSoftwarePlatformViewCreationCallback(
235 const FlutterRendererConfig* config,
236 void* user_data,
237 flutter::PlatformViewEmbedder::PlatformDispatchTable
238 platform_dispatch_table,
239 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
240 external_view_embedder) {
241 if (config->type != kSoftware) {
242 return nullptr;
243 }
244
245 auto software_present_backing_store =
246 [ptr = config->software.surface_present_callback, user_data](
247 const void* allocation, size_t row_bytes, size_t height) -> bool {
248 return ptr(user_data, allocation, row_bytes, height);
249 };
250
251 flutter::EmbedderSurfaceSoftware::SoftwareDispatchTable
252 software_dispatch_table = {
253 software_present_backing_store, // required
254 };
255
256 return fml::MakeCopyable(
257 [software_dispatch_table, platform_dispatch_table,
258 external_view_embedder =
259 std::move(external_view_embedder)](flutter::Shell& shell) mutable {
260 return std::make_unique<flutter::PlatformViewEmbedder>(
261 shell, // delegate
262 shell.GetTaskRunners(), // task runners
263 software_dispatch_table, // software dispatch table
264 platform_dispatch_table, // platform dispatch table
265 std::move(external_view_embedder) // external view embedder
266 );
267 });
268 }
269
270 static flutter::Shell::CreateCallback<flutter::PlatformView>
InferPlatformViewCreationCallback(const FlutterRendererConfig * config,void * user_data,flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table,std::unique_ptr<flutter::EmbedderExternalViewEmbedder> external_view_embedder)271 InferPlatformViewCreationCallback(
272 const FlutterRendererConfig* config,
273 void* user_data,
274 flutter::PlatformViewEmbedder::PlatformDispatchTable
275 platform_dispatch_table,
276 std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
277 external_view_embedder) {
278 if (config == nullptr) {
279 return nullptr;
280 }
281
282 switch (config->type) {
283 case kOpenGL:
284 return InferOpenGLPlatformViewCreationCallback(
285 config, user_data, platform_dispatch_table,
286 std::move(external_view_embedder));
287 case kSoftware:
288 return InferSoftwarePlatformViewCreationCallback(
289 config, user_data, platform_dispatch_table,
290 std::move(external_view_embedder));
291 default:
292 return nullptr;
293 }
294 return nullptr;
295 }
296
MakeSkSurfaceFromBackingStore(GrContext * context,const FlutterBackingStoreConfig & config,const FlutterOpenGLTexture * texture)297 static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
298 GrContext* context,
299 const FlutterBackingStoreConfig& config,
300 const FlutterOpenGLTexture* texture) {
301 GrGLTextureInfo texture_info;
302 texture_info.fTarget = texture->target;
303 texture_info.fID = texture->name;
304 texture_info.fFormat = texture->format;
305
306 GrBackendTexture backend_texture(config.size.width, //
307 config.size.height, //
308 GrMipMapped::kNo, //
309 texture_info //
310 );
311
312 SkSurfaceProps surface_properties(
313 SkSurfaceProps::InitType::kLegacyFontHost_InitType);
314
315 auto surface = SkSurface::MakeFromBackendTexture(
316 context, // context
317 backend_texture, // back-end texture
318 kTopLeft_GrSurfaceOrigin, // surface origin
319 1, // sample count
320 kN32_SkColorType, // color type
321 SkColorSpace::MakeSRGB(), // color space
322 &surface_properties, // surface properties
323 static_cast<SkSurface::TextureReleaseProc>(
324 texture->destruction_callback), // release proc
325 texture->user_data // release context
326 );
327
328 if (!surface) {
329 FML_LOG(ERROR) << "Could not wrap embedder supplied render texture.";
330 texture->destruction_callback(texture->user_data);
331 return nullptr;
332 }
333
334 return surface;
335 }
336
MakeSkSurfaceFromBackingStore(GrContext * context,const FlutterBackingStoreConfig & config,const FlutterOpenGLFramebuffer * framebuffer)337 static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
338 GrContext* context,
339 const FlutterBackingStoreConfig& config,
340 const FlutterOpenGLFramebuffer* framebuffer) {
341 GrGLFramebufferInfo framebuffer_info = {};
342 framebuffer_info.fFormat = framebuffer->target;
343 framebuffer_info.fFBOID = framebuffer->name;
344
345 GrBackendRenderTarget backend_render_target(
346 config.size.width, // width
347 config.size.height, // height
348 1, // sample count
349 0, // stencil bits
350 framebuffer_info // framebuffer info
351 );
352
353 SkSurfaceProps surface_properties(
354 SkSurfaceProps::InitType::kLegacyFontHost_InitType);
355
356 auto surface = SkSurface::MakeFromBackendRenderTarget(
357 context, // context
358 backend_render_target, // backend render target
359 kTopLeft_GrSurfaceOrigin, // surface origin
360 kN32_SkColorType, // color type
361 SkColorSpace::MakeSRGB(), // color space
362 &surface_properties, // surface properties
363 static_cast<SkSurface::RenderTargetReleaseProc>(
364 framebuffer->destruction_callback), // release proc
365 framebuffer->user_data // release context
366 );
367
368 if (!surface) {
369 FML_LOG(ERROR) << "Could not wrap embedder supplied frame-buffer.";
370 framebuffer->destruction_callback(framebuffer->user_data);
371 return nullptr;
372 }
373 return surface;
374 }
375
MakeSkSurfaceFromBackingStore(GrContext * context,const FlutterBackingStoreConfig & config,const FlutterSoftwareBackingStore * software)376 static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
377 GrContext* context,
378 const FlutterBackingStoreConfig& config,
379 const FlutterSoftwareBackingStore* software) {
380 const auto image_info =
381 SkImageInfo::MakeN32Premul(config.size.width, config.size.height);
382
383 struct Captures {
384 VoidCallback destruction_callback;
385 void* user_data;
386 };
387 auto captures = std::make_unique<Captures>();
388 captures->destruction_callback = software->destruction_callback;
389 captures->user_data = software->user_data;
390 auto release_proc = [](void* pixels, void* context) {
391 auto captures = reinterpret_cast<Captures*>(context);
392 captures->destruction_callback(captures->user_data);
393 };
394
395 auto surface = SkSurface::MakeRasterDirectReleaseProc(
396 image_info, // image info
397 const_cast<void*>(software->allocation), // pixels
398 software->row_bytes, // row bytes
399 release_proc, // release proc
400 captures.release() // release context
401 );
402
403 if (!surface) {
404 FML_LOG(ERROR)
405 << "Could not wrap embedder supplied software render buffer.";
406 software->destruction_callback(software->user_data);
407 return nullptr;
408 }
409 return surface;
410 }
411
412 static std::unique_ptr<flutter::EmbedderRenderTarget>
CreateEmbedderRenderTarget(const FlutterCompositor * compositor,const FlutterBackingStoreConfig & config,GrContext * context)413 CreateEmbedderRenderTarget(const FlutterCompositor* compositor,
414 const FlutterBackingStoreConfig& config,
415 GrContext* context) {
416 FlutterBackingStore backing_store = {};
417 backing_store.struct_size = sizeof(backing_store);
418
419 // Safe access checks on the compositor struct have been performed in
420 // InferExternalViewEmbedderFromArgs and are not necessary here.
421 auto c_create_callback = compositor->create_backing_store_callback;
422 auto c_collect_callback = compositor->collect_backing_store_callback;
423
424 if (!c_create_callback(&config, &backing_store, compositor->user_data)) {
425 FML_LOG(ERROR) << "Could not create the embedder backing store.";
426 return nullptr;
427 }
428
429 if (backing_store.struct_size != sizeof(backing_store)) {
430 FML_LOG(ERROR) << "Embedder modified the backing store struct size.";
431 return nullptr;
432 }
433
434 // In case we return early without creating an embedder render target, the
435 // embedder has still given us ownership of its baton which we must return
436 // back to it. If this method is successful, the closure is released when the
437 // render target is eventually released.
438 fml::ScopedCleanupClosure collect_callback(
439 [c_collect_callback, backing_store, user_data = compositor->user_data]() {
440 c_collect_callback(&backing_store, user_data);
441 });
442
443 // No safe access checks on the renderer are necessary since we allocated
444 // the struct.
445
446 sk_sp<SkSurface> render_surface;
447
448 switch (backing_store.type) {
449 case kFlutterBackingStoreTypeOpenGL:
450 switch (backing_store.open_gl.type) {
451 case kFlutterOpenGLTargetTypeTexture:
452 render_surface = MakeSkSurfaceFromBackingStore(
453 context, config, &backing_store.open_gl.texture);
454 break;
455 case kFlutterOpenGLTargetTypeFramebuffer:
456 render_surface = MakeSkSurfaceFromBackingStore(
457 context, config, &backing_store.open_gl.framebuffer);
458 break;
459 }
460 break;
461 case kFlutterBackingStoreTypeSoftware:
462 render_surface = MakeSkSurfaceFromBackingStore(context, config,
463 &backing_store.software);
464 break;
465 };
466
467 if (!render_surface) {
468 FML_LOG(ERROR) << "Could not create a surface from an embedder provided "
469 "render target.";
470 return nullptr;
471 }
472
473 return std::make_unique<flutter::EmbedderRenderTarget>(
474 backing_store, std::move(render_surface), collect_callback.Release());
475 }
476
477 static std::pair<std::unique_ptr<flutter::EmbedderExternalViewEmbedder>,
478 bool /* halt engine launch if true */>
InferExternalViewEmbedderFromArgs(const FlutterCompositor * compositor)479 InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor) {
480 if (compositor == nullptr) {
481 return {nullptr, false};
482 }
483
484 auto c_create_callback =
485 SAFE_ACCESS(compositor, create_backing_store_callback, nullptr);
486 auto c_collect_callback =
487 SAFE_ACCESS(compositor, collect_backing_store_callback, nullptr);
488 auto c_present_callback =
489 SAFE_ACCESS(compositor, present_layers_callback, nullptr);
490
491 // Make sure the required callbacks are present
492 if (!c_create_callback || !c_collect_callback || !c_present_callback) {
493 FML_LOG(ERROR) << "Required compositor callbacks absent.";
494 return {nullptr, true};
495 }
496
497 FlutterCompositor captured_compositor = *compositor;
498
499 flutter::EmbedderExternalViewEmbedder::CreateRenderTargetCallback
500 create_render_target_callback =
501 [captured_compositor](GrContext* context, const auto& config) {
502 return CreateEmbedderRenderTarget(&captured_compositor, config,
503 context);
504 };
505
506 flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback =
507 [c_present_callback,
508 user_data = compositor->user_data](const auto& layers) {
509 return c_present_callback(
510 const_cast<const FlutterLayer**>(layers.data()), layers.size(),
511 user_data);
512 };
513
514 return {std::make_unique<flutter::EmbedderExternalViewEmbedder>(
515 create_render_target_callback, present_callback),
516 false};
517 }
518
519 struct _FlutterPlatformMessageResponseHandle {
520 fml::RefPtr<flutter::PlatformMessage> message;
521 };
522
FlutterEngineRun(const FlutterRendererConfig * config,const FlutterProjectArgs * args,void * user_data,FLUTTER_API_SYMBOL (FlutterEngine)* engine_out)523 FlutterEngineResult FlutterEngineRun(const FlutterRendererConfig* config,
524 const FlutterProjectArgs* args,
525 void* user_data,
526 FLUTTER_API_SYMBOL(FlutterEngine) *
527 engine_out) {
528 auto result =
529 FlutterEngineInitialize(config, args, user_data, engine_out);
530
531 if (result != kSuccess) {
532 return result;
533 }
534
535 return FlutterEngineRunInitialized(*engine_out);
536 }
537
FlutterEngineInitialize(const FlutterRendererConfig * config,const FlutterProjectArgs * args,void * user_data,FLUTTER_API_SYMBOL (FlutterEngine)* engine_out)538 FlutterEngineResult FlutterEngineInitialize(const FlutterRendererConfig* config,
539 const FlutterProjectArgs* args,
540 void* user_data,
541 FLUTTER_API_SYMBOL(FlutterEngine) *
542 engine_out) {
543 // Step 0: Figure out arguments for shell creation.
544 if (engine_out == nullptr) {
545 return LOG_EMBEDDER_ERROR(kInvalidArguments);
546 }
547
548 if (args == nullptr) {
549 return LOG_EMBEDDER_ERROR(kInvalidArguments);
550 }
551
552 if (!IsRendererValid(config)) {
553 FML_LOG(WARNING) << "Invalid renderer config.";
554 return LOG_EMBEDDER_ERROR(kInvalidArguments);
555 }
556
557 flutter::Settings settings;
558 settings.task_observer_add = [](intptr_t key, fml::closure callback) {
559 fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
560 };
561 settings.task_observer_remove = [](intptr_t key) {
562 fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
563 };
564
565 flutter::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr;
566 if (SAFE_ACCESS(args, vsync_callback, nullptr) != nullptr) {
567 vsync_callback = [ptr = args->vsync_callback, user_data](intptr_t baton) {
568 return ptr(user_data, baton);
569 };
570 }
571
572 auto external_view_embedder_result =
573 InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
574 if (external_view_embedder_result.second) {
575 return LOG_EMBEDDER_ERROR(kInvalidArguments);
576 }
577
578 flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
579 {
580 vsync_callback,
581 };
582
583 auto on_create_platform_view = InferPlatformViewCreationCallback(
584 config, user_data, platform_dispatch_table,
585 std::move(external_view_embedder_result.first));
586
587 if (!on_create_platform_view) {
588 return LOG_EMBEDDER_ERROR(kInvalidArguments);
589 }
590
591 flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
592 [](flutter::Shell& shell) {
593 return std::make_unique<flutter::Rasterizer>(shell,
594 shell.GetTaskRunners());
595 };
596
597 // TODO(chinmaygarde): This is the wrong spot for this. It belongs in the
598 // platform view jump table.
599 flutter::EmbedderExternalTextureGL::ExternalTextureCallback
600 external_texture_callback;
601 if (config->type == kOpenGL) {
602 const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
603 if (SAFE_ACCESS(open_gl_config, gl_external_texture_frame_callback,
604 nullptr) != nullptr) {
605 external_texture_callback =
606 [ptr = open_gl_config->gl_external_texture_frame_callback, user_data](
607 int64_t texture_identifier, GrContext* context,
608 const SkISize& size) -> sk_sp<SkImage> {
609 FlutterOpenGLTexture texture = {};
610
611 if (!ptr(user_data, texture_identifier, size.width(), size.height(),
612 &texture)) {
613 return nullptr;
614 }
615
616 GrGLTextureInfo gr_texture_info = {texture.target, texture.name,
617 texture.format};
618
619 GrBackendTexture gr_backend_texture(size.width(), size.height(),
620 GrMipMapped::kNo, gr_texture_info);
621 SkImage::TextureReleaseProc release_proc = texture.destruction_callback;
622 auto image = SkImage::MakeFromTexture(
623 context, // context
624 gr_backend_texture, // texture handle
625 kTopLeft_GrSurfaceOrigin, // origin
626 kRGBA_8888_SkColorType, // color type
627 kPremul_SkAlphaType, // alpha type
628 nullptr, // colorspace
629 release_proc, // texture release proc
630 texture.user_data // texture release context
631 );
632
633 if (!image) {
634 // In case Skia rejects the image, call the release proc so that
635 // embedders can perform collection of intermediates.
636 if (release_proc) {
637 release_proc(texture.user_data);
638 }
639 FML_LOG(ERROR) << "Could not create external texture.";
640 return nullptr;
641 }
642
643 return image;
644 };
645 }
646 }
647
648 auto thread_host =
649 flutter::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
650 SAFE_ACCESS(args, custom_task_runners, nullptr));
651
652 if (!thread_host || !thread_host->IsValid()) {
653 FML_LOG(ERROR) << "Could not setup or infer thread configuration to run "
654 "the Flutter engine on.";
655 return LOG_EMBEDDER_ERROR(kInvalidArguments);
656 }
657
658 auto task_runners = thread_host->GetTaskRunners();
659
660 if (!task_runners.IsValid()) {
661 FML_LOG(ERROR) << "Task runner configuration specified is invalid.";
662 return LOG_EMBEDDER_ERROR(kInvalidArguments);
663 }
664
665 flutter::RunConfiguration run_configuration;
666 // Create the engine but don't launch the shell or run the root isolate.
667 auto embedder_engine = std::make_unique<flutter::EmbedderEngine>(
668 std::move(thread_host), //
669 std::move(task_runners), //
670 std::move(settings), //
671 std::move(run_configuration), //
672 on_create_platform_view, //
673 on_create_rasterizer, //
674 external_texture_callback //
675 );
676
677 // Release the ownership of the embedder engine to the caller.
678 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(
679 embedder_engine.release());
680 return kSuccess;
681 }
682
FlutterEngineRunInitialized(FLUTTER_API_SYMBOL (FlutterEngine)engine)683 FlutterEngineResult FlutterEngineRunInitialized(
684 FLUTTER_API_SYMBOL(FlutterEngine) engine) {
685 if (!engine) {
686 return LOG_EMBEDDER_ERROR(kInvalidArguments);
687 }
688
689 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
690
691 // The engine must not already be running. Initialize may only be called once
692 // on an engine instance.
693 if (embedder_engine->IsValid()) {
694 return LOG_EMBEDDER_ERROR(kInvalidArguments);
695 }
696
697 // Step 1: Launch the shell.
698 if (!embedder_engine->LaunchShell()) {
699 FML_LOG(ERROR) << "Could not launch the engine using supplied "
700 "initialization arguments.";
701 return LOG_EMBEDDER_ERROR(kInvalidArguments);
702 }
703
704 // Step 2: Tell the platform view to initialize itself.
705 if (!embedder_engine->NotifyCreated()) {
706 return LOG_EMBEDDER_ERROR(kInvalidArguments);
707 }
708
709 // Step 3: Launch the root isolate.
710 if (!embedder_engine->RunRootIsolate()) {
711 return LOG_EMBEDDER_ERROR(kInvalidArguments);
712 }
713
714 return kSuccess;
715 }
716
717 FLUTTER_EXPORT
FlutterEngineDeinitialize(FLUTTER_API_SYMBOL (FlutterEngine)engine)718 FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine)
719 engine) {
720 if (engine == nullptr) {
721 return LOG_EMBEDDER_ERROR(kInvalidArguments);
722 }
723 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
724 embedder_engine->NotifyDestroyed();
725 embedder_engine->CollectShell();
726 return kSuccess;
727 }
728
FlutterEngineShutdown(FLUTTER_API_SYMBOL (FlutterEngine)engine)729 FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine)
730 engine) {
731 auto result = FlutterEngineDeinitialize(engine);
732 if (result != kSuccess) {
733 return result;
734 }
735 auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
736 delete embedder_engine;
737 return kSuccess;
738 }
739
FlutterEngineSetIdleNotificationCallback(FLUTTER_API_SYMBOL (FlutterEngine)engine,const IdleCallback & idle_notification_callback)740 FlutterEngineResult FlutterEngineSetIdleNotificationCallback(
741 FLUTTER_API_SYMBOL(FlutterEngine) engine,
742 const IdleCallback& idle_notification_callback) {
743 if (engine == nullptr || idle_notification_callback == nullptr) {
744 return LOG_EMBEDDER_ERROR(kInvalidArguments);
745 }
746
747 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->SetIdleNotificationCallback(
748 idle_notification_callback)
749 ? kSuccess
750 : LOG_EMBEDDER_ERROR(kInvalidArguments);
751 }
752
FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL (FlutterEngine)engine,const FlutterWindowMetricsEvent * flutter_metrics)753 FlutterEngineResult FlutterEngineSendWindowMetricsEvent(
754 FLUTTER_API_SYMBOL(FlutterEngine) engine,
755 const FlutterWindowMetricsEvent* flutter_metrics) {
756 if (engine == nullptr || flutter_metrics == nullptr) {
757 return LOG_EMBEDDER_ERROR(kInvalidArguments);
758 }
759
760 flutter::ViewportMetrics metrics;
761
762 metrics.physical_width = SAFE_ACCESS(flutter_metrics, width, 0.0);
763 metrics.physical_height = SAFE_ACCESS(flutter_metrics, height, 0.0);
764 metrics.device_pixel_ratio = SAFE_ACCESS(flutter_metrics, pixel_ratio, 1.0);
765
766 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->SetViewportMetrics(
767 std::move(metrics))
768 ? kSuccess
769 : LOG_EMBEDDER_ERROR(kInvalidArguments);
770 }
771
772 // Returns the flutter::PointerData::Change for the given FlutterPointerPhase.
ToPointerDataChange(FlutterPointerPhase phase)773 inline flutter::PointerData::Change ToPointerDataChange(
774 FlutterPointerPhase phase) {
775 switch (phase) {
776 case kCancel:
777 return flutter::PointerData::Change::kCancel;
778 case kUp:
779 return flutter::PointerData::Change::kUp;
780 case kDown:
781 return flutter::PointerData::Change::kDown;
782 case kMove:
783 return flutter::PointerData::Change::kMove;
784 case kAdd:
785 return flutter::PointerData::Change::kAdd;
786 case kRemove:
787 return flutter::PointerData::Change::kRemove;
788 case kHover:
789 return flutter::PointerData::Change::kHover;
790 }
791 return flutter::PointerData::Change::kCancel;
792 }
793
794 // Returns the flutter::PointerData::DeviceKind for the given
795 // FlutterPointerDeviceKind.
ToPointerDataKind(FlutterPointerDeviceKind device_kind)796 inline flutter::PointerData::DeviceKind ToPointerDataKind(
797 FlutterPointerDeviceKind device_kind) {
798 switch (device_kind) {
799 case kFlutterPointerDeviceKindMouse:
800 return flutter::PointerData::DeviceKind::kMouse;
801 case kFlutterPointerDeviceKindTouch:
802 return flutter::PointerData::DeviceKind::kTouch;
803 }
804 return flutter::PointerData::DeviceKind::kMouse;
805 }
806
807 // Returns the flutter::PointerData::SignalKind for the given
808 // FlutterPointerSignaKind.
ToPointerDataSignalKind(FlutterPointerSignalKind kind)809 inline flutter::PointerData::SignalKind ToPointerDataSignalKind(
810 FlutterPointerSignalKind kind) {
811 switch (kind) {
812 case kFlutterPointerSignalKindNone:
813 return flutter::PointerData::SignalKind::kNone;
814 case kFlutterPointerSignalKindScroll:
815 return flutter::PointerData::SignalKind::kScroll;
816 }
817 return flutter::PointerData::SignalKind::kNone;
818 }
819
820 // Returns the buttons to synthesize for a PointerData from a
821 // FlutterPointerEvent with no type or buttons set.
PointerDataButtonsForLegacyEvent(flutter::PointerData::Change change)822 inline int64_t PointerDataButtonsForLegacyEvent(
823 flutter::PointerData::Change change) {
824 switch (change) {
825 case flutter::PointerData::Change::kDown:
826 case flutter::PointerData::Change::kMove:
827 // These kinds of change must have a non-zero `buttons`, otherwise gesture
828 // recognizers will ignore these events.
829 return flutter::kPointerButtonMousePrimary;
830 case flutter::PointerData::Change::kCancel:
831 case flutter::PointerData::Change::kAdd:
832 case flutter::PointerData::Change::kRemove:
833 case flutter::PointerData::Change::kHover:
834 case flutter::PointerData::Change::kUp:
835 return 0;
836 }
837 return 0;
838 }
839
FlutterEngineSendPointerEvent(FLUTTER_API_SYMBOL (FlutterEngine)engine,const FlutterPointerEvent * pointers,size_t events_count)840 FlutterEngineResult FlutterEngineSendPointerEvent(
841 FLUTTER_API_SYMBOL(FlutterEngine) engine,
842 const FlutterPointerEvent* pointers,
843 size_t events_count) {
844 if (engine == nullptr || pointers == nullptr || events_count == 0) {
845 return LOG_EMBEDDER_ERROR(kInvalidArguments);
846 }
847
848 auto packet = std::make_unique<flutter::PointerDataPacket>(events_count);
849
850 const FlutterPointerEvent* current = pointers;
851
852 for (size_t i = 0; i < events_count; ++i) {
853 flutter::PointerData pointer_data;
854 pointer_data.Clear();
855 pointer_data.time_stamp = SAFE_ACCESS(current, timestamp, 0);
856 pointer_data.change = ToPointerDataChange(
857 SAFE_ACCESS(current, phase, FlutterPointerPhase::kCancel));
858 pointer_data.physical_x = SAFE_ACCESS(current, x, 0.0);
859 pointer_data.physical_y = SAFE_ACCESS(current, y, 0.0);
860 pointer_data.device = SAFE_ACCESS(current, device, 0);
861 pointer_data.signal_kind = ToPointerDataSignalKind(
862 SAFE_ACCESS(current, signal_kind, kFlutterPointerSignalKindNone));
863 pointer_data.scroll_delta_x = SAFE_ACCESS(current, scroll_delta_x, 0.0);
864 pointer_data.scroll_delta_y = SAFE_ACCESS(current, scroll_delta_y, 0.0);
865 FlutterPointerDeviceKind device_kind = SAFE_ACCESS(current, device_kind, 0);
866 // For backwards compatibility with embedders written before the device kind
867 // and buttons were exposed, if the device kind is not set treat it as a
868 // mouse, with a synthesized primary button state based on the phase.
869 if (device_kind == 0) {
870 pointer_data.kind = flutter::PointerData::DeviceKind::kMouse;
871 pointer_data.buttons =
872 PointerDataButtonsForLegacyEvent(pointer_data.change);
873 } else {
874 pointer_data.kind = ToPointerDataKind(device_kind);
875 if (pointer_data.kind == flutter::PointerData::DeviceKind::kTouch) {
876 // For touch events, set the button internally rather than requiring
877 // it at the API level, since it's a confusing construction to expose.
878 if (pointer_data.change == flutter::PointerData::Change::kDown ||
879 pointer_data.change == flutter::PointerData::Change::kMove) {
880 pointer_data.buttons = flutter::kPointerButtonTouchContact;
881 }
882 } else {
883 // Buttons use the same mask values, so pass them through directly.
884 pointer_data.buttons = SAFE_ACCESS(current, buttons, 0);
885 }
886 }
887 packet->SetPointerData(i, pointer_data);
888 current = reinterpret_cast<const FlutterPointerEvent*>(
889 reinterpret_cast<const uint8_t*>(current) + current->struct_size);
890 }
891
892 #ifdef USE_GLFW_WINDOW
893 if (g_HandleTouchEventCallback && g_HandleTouchEventCallback(packet)) {
894 return kSuccess;
895 }
896
897 return LOG_EMBEDDER_ERROR(kInvalidArguments);
898 #else
899 return kSuccess;
900 #endif
901 }
902
FlutterEngineSendPlatformMessage(FLUTTER_API_SYMBOL (FlutterEngine)engine,const FlutterPlatformMessage * flutter_message)903 FlutterEngineResult FlutterEngineSendPlatformMessage(
904 FLUTTER_API_SYMBOL(FlutterEngine) engine,
905 const FlutterPlatformMessage* flutter_message) {
906 if (engine == nullptr || flutter_message == nullptr) {
907 return LOG_EMBEDDER_ERROR(kInvalidArguments);
908 }
909
910 if (SAFE_ACCESS(flutter_message, channel, nullptr) == nullptr) {
911 return LOG_EMBEDDER_ERROR(kInvalidArguments);
912 }
913
914 size_t message_size = SAFE_ACCESS(flutter_message, message_size, 0);
915 const uint8_t* message_data = SAFE_ACCESS(flutter_message, message, nullptr);
916
917 if (message_size != 0 && message_data == nullptr) {
918 return LOG_EMBEDDER_ERROR(kInvalidArguments);
919 }
920
921 const FlutterPlatformMessageResponseHandle* response_handle =
922 SAFE_ACCESS(flutter_message, response_handle, nullptr);
923
924 fml::RefPtr<flutter::PlatformMessageResponse> response;
925 if (response_handle && response_handle->message) {
926 response = response_handle->message->response();
927 }
928
929 fml::RefPtr<flutter::PlatformMessage> message;
930 if (message_size == 0) {
931 message = fml::MakeRefCounted<flutter::PlatformMessage>(
932 flutter_message->channel, response);
933 } else {
934 message = fml::MakeRefCounted<flutter::PlatformMessage>(
935 flutter_message->channel,
936 std::vector<uint8_t>(message_data, message_data + message_size),
937 response);
938 }
939
940 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
941 ->SendPlatformMessage(std::move(message))
942 ? kSuccess
943 : LOG_EMBEDDER_ERROR(kInvalidArguments);
944 }
945
FlutterPlatformMessageCreateResponseHandle(FLUTTER_API_SYMBOL (FlutterEngine)engine,FlutterDataCallback data_callback,void * user_data,FlutterPlatformMessageResponseHandle ** response_out)946 FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
947 FLUTTER_API_SYMBOL(FlutterEngine) engine,
948 FlutterDataCallback data_callback,
949 void* user_data,
950 FlutterPlatformMessageResponseHandle** response_out) {
951 if (engine == nullptr || data_callback == nullptr ||
952 response_out == nullptr) {
953 return LOG_EMBEDDER_ERROR(kInvalidArguments);
954 }
955
956 flutter::EmbedderPlatformMessageResponse::Callback response_callback =
957 [user_data, data_callback](const uint8_t* data, size_t size) {
958 data_callback(data, size, user_data);
959 };
960
961 auto platform_task_runner = reinterpret_cast<flutter::EmbedderEngine*>(engine)
962 ->GetTaskRunners()
963 .GetPlatformTaskRunner();
964
965 auto handle = new FlutterPlatformMessageResponseHandle();
966
967 handle->message = fml::MakeRefCounted<flutter::PlatformMessage>(
968 "", // The channel is empty and unused as the response handle is going to
969 // referenced directly in the |FlutterEngineSendPlatformMessage| with
970 // the container message discarded.
971 fml::MakeRefCounted<flutter::EmbedderPlatformMessageResponse>(
972 std::move(platform_task_runner), response_callback));
973 *response_out = handle;
974 return kSuccess;
975 }
976
FlutterPlatformMessageReleaseResponseHandle(FLUTTER_API_SYMBOL (FlutterEngine)engine,FlutterPlatformMessageResponseHandle * response)977 FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(
978 FLUTTER_API_SYMBOL(FlutterEngine) engine,
979 FlutterPlatformMessageResponseHandle* response) {
980 if (engine == nullptr || response == nullptr) {
981 return LOG_EMBEDDER_ERROR(kInvalidArguments);
982 }
983 delete response;
984 return kSuccess;
985 }
986
FlutterEngineSendPlatformMessageResponse(FLUTTER_API_SYMBOL (FlutterEngine)engine,const FlutterPlatformMessageResponseHandle * handle,const uint8_t * data,size_t data_length)987 FlutterEngineResult FlutterEngineSendPlatformMessageResponse(
988 FLUTTER_API_SYMBOL(FlutterEngine) engine,
989 const FlutterPlatformMessageResponseHandle* handle,
990 const uint8_t* data,
991 size_t data_length) {
992 if (data_length != 0 && data == nullptr) {
993 return LOG_EMBEDDER_ERROR(kInvalidArguments);
994 }
995
996 auto response = handle->message->response();
997
998 if (response) {
999 if (data_length == 0) {
1000 response->CompleteEmpty();
1001 } else {
1002 response->Complete(std::make_unique<fml::DataMapping>(
1003 std::vector<uint8_t>({data, data + data_length})));
1004 }
1005 }
1006
1007 delete handle;
1008
1009 return kSuccess;
1010 }
1011
__FlutterEngineFlushPendingTasksNow()1012 FlutterEngineResult __FlutterEngineFlushPendingTasksNow() {
1013 fml::MessageLoop::GetCurrent().RunExpiredTasksNow();
1014 return kSuccess;
1015 }
1016
FlutterEngineRegisterExternalTexture(FLUTTER_API_SYMBOL (FlutterEngine)engine,int64_t texture_identifier)1017 FlutterEngineResult FlutterEngineRegisterExternalTexture(
1018 FLUTTER_API_SYMBOL(FlutterEngine) engine,
1019 int64_t texture_identifier) {
1020 if (engine == nullptr || texture_identifier == 0) {
1021 return LOG_EMBEDDER_ERROR(kInvalidArguments);
1022 }
1023 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->RegisterTexture(
1024 texture_identifier)) {
1025 return LOG_EMBEDDER_ERROR(kInternalInconsistency);
1026 }
1027 return kSuccess;
1028 }
1029
FlutterEngineUnregisterExternalTexture(FLUTTER_API_SYMBOL (FlutterEngine)engine,int64_t texture_identifier)1030 FlutterEngineResult FlutterEngineUnregisterExternalTexture(
1031 FLUTTER_API_SYMBOL(FlutterEngine) engine,
1032 int64_t texture_identifier) {
1033 if (engine == nullptr || texture_identifier == 0) {
1034 return kInvalidArguments;
1035 }
1036
1037 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->UnregisterTexture(
1038 texture_identifier)) {
1039 return LOG_EMBEDDER_ERROR(kInternalInconsistency);
1040 }
1041
1042 return kSuccess;
1043 }
1044
FlutterEngineMarkExternalTextureFrameAvailable(FLUTTER_API_SYMBOL (FlutterEngine)engine,int64_t texture_identifier)1045 FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable(
1046 FLUTTER_API_SYMBOL(FlutterEngine) engine,
1047 int64_t texture_identifier) {
1048 if (engine == nullptr || texture_identifier == 0) {
1049 return LOG_EMBEDDER_ERROR(kInvalidArguments);
1050 }
1051 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)
1052 ->MarkTextureFrameAvailable(texture_identifier)) {
1053 return LOG_EMBEDDER_ERROR(kInternalInconsistency);
1054 }
1055 return kSuccess;
1056 }
1057
FlutterEngineOnVsync(FLUTTER_API_SYMBOL (FlutterEngine)engine,intptr_t baton,uint64_t frame_start_time_nanos,uint64_t frame_target_time_nanos)1058 FlutterEngineResult FlutterEngineOnVsync(FLUTTER_API_SYMBOL(FlutterEngine)
1059 engine,
1060 intptr_t baton,
1061 uint64_t frame_start_time_nanos,
1062 uint64_t frame_target_time_nanos) {
1063 if (engine == nullptr) {
1064 return LOG_EMBEDDER_ERROR(kInvalidArguments);
1065 }
1066
1067 TRACE_EVENT0("flutter", "FlutterEngineOnVsync");
1068
1069 auto start_time = fml::TimePoint::FromEpochDelta(
1070 fml::TimeDelta::FromNanoseconds(frame_start_time_nanos));
1071
1072 auto target_time = fml::TimePoint::FromEpochDelta(
1073 fml::TimeDelta::FromNanoseconds(frame_target_time_nanos));
1074
1075 if (!reinterpret_cast<flutter::EmbedderEngine*>(engine)->OnVsyncEvent(
1076 baton, start_time, target_time)) {
1077 return LOG_EMBEDDER_ERROR(kInternalInconsistency);
1078 }
1079
1080 return kSuccess;
1081 }
1082
FlutterEngineTraceEventDurationBegin(const char * name)1083 void FlutterEngineTraceEventDurationBegin(const char* name) {
1084 fml::tracing::TraceEvent0("flutter", name);
1085 }
1086
FlutterEngineTraceEventDurationEnd(const char * name)1087 void FlutterEngineTraceEventDurationEnd(const char* name) {
1088 fml::tracing::TraceEventEnd(name);
1089 }
1090
FlutterEngineTraceEventInstant(const char * name)1091 void FlutterEngineTraceEventInstant(const char* name) {
1092 fml::tracing::TraceEventInstant0("flutter", name);
1093 }
1094
FlutterEnginePostRenderThreadTask(FLUTTER_API_SYMBOL (FlutterEngine)engine,VoidCallback callback,void * baton)1095 FlutterEngineResult FlutterEnginePostRenderThreadTask(
1096 FLUTTER_API_SYMBOL(FlutterEngine) engine,
1097 VoidCallback callback,
1098 void* baton) {
1099 if (engine == nullptr || callback == nullptr) {
1100 return LOG_EMBEDDER_ERROR(kInvalidArguments);
1101 }
1102
1103 auto task = [callback, baton]() { callback(baton); };
1104
1105 return reinterpret_cast<flutter::EmbedderEngine*>(engine)
1106 ->PostRenderThreadTask(task)
1107 ? kSuccess
1108 : LOG_EMBEDDER_ERROR(kInternalInconsistency);
1109 }
1110
FlutterEngineGetCurrentTime()1111 uint64_t FlutterEngineGetCurrentTime() {
1112 return fml::TimePoint::Now().ToEpochDelta().ToNanoseconds();
1113 }
1114
FlutterEngineRunTask(FLUTTER_API_SYMBOL (FlutterEngine)engine,const FlutterTask * task)1115 FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine)
1116 engine,
1117 const FlutterTask* task) {
1118 if (engine == nullptr) {
1119 return LOG_EMBEDDER_ERROR(kInvalidArguments);
1120 }
1121
1122 return reinterpret_cast<flutter::EmbedderEngine*>(engine)->RunTask(task)
1123 ? kSuccess
1124 : LOG_EMBEDDER_ERROR(kInvalidArguments);
1125 }
1126
1127 #ifdef USE_GLFW_WINDOW
FlutterEngineRegisterHandleTouchEventCallback(HandleTouchEventCallback && callback)1128 void FlutterEngineRegisterHandleTouchEventCallback(HandleTouchEventCallback&& callback) {
1129 g_HandleTouchEventCallback = std::move(callback);
1130 }
1131 #endif
1132