// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/shell/platform/embedder/embedder_engine.h" #include "flutter/fml/make_copyable.h" #include "flutter/shell/platform/embedder/vsync_waiter_embedder.h" namespace flutter { struct ShellArgs { Settings settings; Shell::CreateCallback on_create_platform_view; Shell::CreateCallback on_create_rasterizer; ShellArgs(Settings p_settings, Shell::CreateCallback p_on_create_platform_view, Shell::CreateCallback p_on_create_rasterizer) : settings(std::move(p_settings)), on_create_platform_view(std::move(p_on_create_platform_view)), on_create_rasterizer(std::move(p_on_create_rasterizer)) {} }; EmbedderEngine::EmbedderEngine( std::unique_ptr thread_host, flutter::TaskRunners task_runners, flutter::Settings settings, RunConfiguration run_configuration, Shell::CreateCallback on_create_platform_view, Shell::CreateCallback on_create_rasterizer, EmbedderExternalTextureGL::ExternalTextureCallback external_texture_callback) : thread_host_(std::move(thread_host)), task_runners_(task_runners), run_configuration_(std::move(run_configuration)), shell_args_(std::make_unique(std::move(settings), on_create_platform_view, on_create_rasterizer)), external_texture_callback_(external_texture_callback) {} EmbedderEngine::~EmbedderEngine() = default; bool EmbedderEngine::LaunchShell() { if (!shell_args_) { FML_DLOG(ERROR) << "Invalid shell arguments."; return false; } if (shell_) { FML_DLOG(ERROR) << "Shell already initialized"; } shell_ = Shell::Create(task_runners_, shell_args_->settings, shell_args_->on_create_platform_view, shell_args_->on_create_rasterizer); // Reset the args no matter what. They will never be used to initialize a // shell again. shell_args_.reset(); return IsValid(); } bool EmbedderEngine::CollectShell() { shell_.reset(); return IsValid(); } bool EmbedderEngine::RunRootIsolate() { if (!IsValid() || !run_configuration_.IsValid()) { return false; } shell_->RunEngine(std::move(run_configuration_)); return true; } bool EmbedderEngine::IsValid() const { return static_cast(shell_); } const TaskRunners& EmbedderEngine::GetTaskRunners() const { return task_runners_; } bool EmbedderEngine::NotifyCreated() { if (!IsValid()) { return false; } shell_->GetPlatformView()->NotifyCreated(); return true; } bool EmbedderEngine::NotifyDestroyed() { if (!IsValid()) { return false; } shell_->GetPlatformView()->NotifyDestroyed(); return true; } bool EmbedderEngine::SetViewportMetrics(flutter::ViewportMetrics metrics) { if (!IsValid()) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->SetViewportMetrics(std::move(metrics)); return true; } bool EmbedderEngine::DispatchPointerDataPacket( std::unique_ptr packet) { if (!IsValid() || !packet) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->DispatchPointerDataPacket(std::move(packet)); return true; } bool EmbedderEngine::SendPlatformMessage( fml::RefPtr message) { if (!IsValid() || !message) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->DispatchPlatformMessage(message); return true; } bool EmbedderEngine::RegisterTexture(int64_t texture) { if (!IsValid() || !external_texture_callback_) { return false; } shell_->GetPlatformView()->RegisterTexture( std::make_unique(texture, external_texture_callback_)); return true; } bool EmbedderEngine::UnregisterTexture(int64_t texture) { if (!IsValid() || !external_texture_callback_) { return false; } shell_->GetPlatformView()->UnregisterTexture(texture); return true; } bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) { if (!IsValid() || !external_texture_callback_) { return false; } shell_->GetPlatformView()->MarkTextureFrameAvailable(texture); return true; } bool EmbedderEngine::SetSemanticsEnabled(bool enabled) { if (!IsValid()) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->SetSemanticsEnabled(enabled); return true; } bool EmbedderEngine::SetAccessibilityFeatures(int32_t flags) { if (!IsValid()) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->SetAccessibilityFeatures(flags); return true; } bool EmbedderEngine::DispatchSemanticsAction(int id, flutter::SemanticsAction action, std::vector args) { if (!IsValid()) { return false; } auto platform_view = shell_->GetPlatformView(); if (!platform_view) { return false; } platform_view->DispatchSemanticsAction(id, action, std::move(args)); return true; } bool EmbedderEngine::OnVsyncEvent(intptr_t baton, fml::TimePoint frame_start_time, fml::TimePoint frame_target_time) { if (!IsValid()) { return false; } return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time, frame_target_time); } bool EmbedderEngine::ReloadSystemFonts() { if (!IsValid()) { return false; } return shell_->ReloadSystemFonts(); } bool EmbedderEngine::PostRenderThreadTask(const fml::closure& task) { if (!IsValid()) { return false; } shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(task); return true; } bool EmbedderEngine::RunTask(const FlutterTask* task) { // The shell doesn't need to be running or valid for access to the thread // host. This is why there is no `IsValid` check here. This allows embedders // to perform custom task runner interop before the shell is running. if (task == nullptr) { return false; } return thread_host_->PostTask(reinterpret_cast(task->runner), task->task); } bool EmbedderEngine::PostTaskOnEngineManagedNativeThreads( std::function closure) const { if (!IsValid() || closure == nullptr) { return false; } const auto trampoline = [closure](FlutterNativeThreadType type, fml::RefPtr runner) { runner->PostTask([closure, type] { closure(type); }); }; // Post the task to all thread host threads. const auto& task_runners = shell_->GetTaskRunners(); trampoline(kFlutterNativeThreadTypeRender, task_runners.GetRasterTaskRunner()); trampoline(kFlutterNativeThreadTypeWorker, task_runners.GetIOTaskRunner()); trampoline(kFlutterNativeThreadTypeUI, task_runners.GetUITaskRunner()); trampoline(kFlutterNativeThreadTypePlatform, task_runners.GetPlatformTaskRunner()); // Post the task to all worker threads. auto vm = shell_->GetDartVM(); vm->GetConcurrentMessageLoop()->PostTaskToAllWorkers( [closure]() { closure(kFlutterNativeThreadTypeWorker); }); return true; } Shell& EmbedderEngine::GetShell() { FML_DCHECK(shell_); return *shell_.get(); } } // namespace flutter