|  | // Copyright 2015 The Chromium 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/runtime/runtime_controller.h" | 
|  |  | 
|  | #include "flutter/fml/message_loop.h" | 
|  | #include "flutter/glue/trace_event.h" | 
|  | #include "flutter/lib/ui/compositing/scene.h" | 
|  | #include "flutter/lib/ui/ui_dart_state.h" | 
|  | #include "flutter/lib/ui/window/window.h" | 
|  | #include "flutter/runtime/runtime_delegate.h" | 
|  | #include "lib/tonic/dart_message_handler.h" | 
|  |  | 
|  | #ifdef ERROR | 
|  | #undef ERROR | 
|  | #endif | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | RuntimeController::RuntimeController( | 
|  | RuntimeDelegate& p_client, | 
|  | DartVM* p_vm, | 
|  | fxl::RefPtr<DartSnapshot> p_isolate_snapshot, | 
|  | fxl::RefPtr<DartSnapshot> p_shared_snapshot, | 
|  | TaskRunners p_task_runners, | 
|  | fml::WeakPtr<GrContext> p_resource_context, | 
|  | fxl::RefPtr<flow::SkiaUnrefQueue> p_unref_queue, | 
|  | std::string p_advisory_script_uri, | 
|  | std::string p_advisory_script_entrypoint) | 
|  | : RuntimeController(p_client, | 
|  | p_vm, | 
|  | std::move(p_isolate_snapshot), | 
|  | std::move(p_shared_snapshot), | 
|  | std::move(p_task_runners), | 
|  | std::move(p_resource_context), | 
|  | std::move(p_unref_queue), | 
|  | std::move(p_advisory_script_uri), | 
|  | std::move(p_advisory_script_entrypoint), | 
|  | WindowData{/* default window data */}) {} | 
|  |  | 
|  | RuntimeController::RuntimeController( | 
|  | RuntimeDelegate& p_client, | 
|  | DartVM* p_vm, | 
|  | fxl::RefPtr<DartSnapshot> p_isolate_snapshot, | 
|  | fxl::RefPtr<DartSnapshot> p_shared_snapshot, | 
|  | TaskRunners p_task_runners, | 
|  | fml::WeakPtr<GrContext> p_resource_context, | 
|  | fxl::RefPtr<flow::SkiaUnrefQueue> p_unref_queue, | 
|  | std::string p_advisory_script_uri, | 
|  | std::string p_advisory_script_entrypoint, | 
|  | WindowData p_window_data) | 
|  | : client_(p_client), | 
|  | vm_(p_vm), | 
|  | isolate_snapshot_(std::move(p_isolate_snapshot)), | 
|  | shared_snapshot_(std::move(p_shared_snapshot)), | 
|  | task_runners_(p_task_runners), | 
|  | resource_context_(p_resource_context), | 
|  | unref_queue_(p_unref_queue), | 
|  | advisory_script_uri_(p_advisory_script_uri), | 
|  | advisory_script_entrypoint_(p_advisory_script_entrypoint), | 
|  | window_data_(std::move(p_window_data)), | 
|  | root_isolate_( | 
|  | DartIsolate::CreateRootIsolate(vm_, | 
|  | isolate_snapshot_, | 
|  | shared_snapshot_, | 
|  | task_runners_, | 
|  | std::make_unique<Window>(this), | 
|  | resource_context_, | 
|  | unref_queue_, | 
|  | p_advisory_script_uri, | 
|  | p_advisory_script_entrypoint)) { | 
|  | root_isolate_->SetReturnCodeCallback([this](uint32_t code) { | 
|  | root_isolate_return_code_ = {true, code}; | 
|  | }); | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | tonic::DartState::Scope scope(root_isolate_.get()); | 
|  | window->DidCreateIsolate(); | 
|  | if (!FlushRuntimeStateToIsolate()) { | 
|  | FXL_DLOG(ERROR) << "Could not setup intial isolate state."; | 
|  | } | 
|  | } else { | 
|  | FXL_DCHECK(false) << "RuntimeController created without window binding."; | 
|  | } | 
|  | FXL_DCHECK(Dart_CurrentIsolate() == nullptr); | 
|  | } | 
|  |  | 
|  | RuntimeController::~RuntimeController() { | 
|  | FXL_DCHECK(Dart_CurrentIsolate() == nullptr); | 
|  | if (root_isolate_) { | 
|  | root_isolate_->SetReturnCodeCallback(nullptr); | 
|  | auto result = root_isolate_->Shutdown(); | 
|  | if (!result) { | 
|  | FXL_DLOG(ERROR) << "Could not shutdown the root isolate."; | 
|  | } | 
|  | root_isolate_ = {}; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool RuntimeController::IsRootIsolateRunning() const { | 
|  | if (root_isolate_) { | 
|  | return root_isolate_->GetPhase() == DartIsolate::Phase::Running; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RuntimeController> RuntimeController::Clone() const { | 
|  | return std::unique_ptr<RuntimeController>(new RuntimeController( | 
|  | client_,                      // | 
|  | vm_,                          // | 
|  | isolate_snapshot_,            // | 
|  | shared_snapshot_,             // | 
|  | task_runners_,                // | 
|  | resource_context_,            // | 
|  | unref_queue_,                 // | 
|  | advisory_script_uri_,         // | 
|  | advisory_script_entrypoint_,  // | 
|  | window_data_                  // | 
|  | )); | 
|  | } | 
|  |  | 
|  | bool RuntimeController::FlushRuntimeStateToIsolate() { | 
|  | return SetViewportMetrics(window_data_.viewport_metrics) && | 
|  | SetLocale(window_data_.language_code, window_data_.country_code) && | 
|  | SetSemanticsEnabled(window_data_.semantics_enabled) && | 
|  | SetAssistiveTechnologyEnabled( | 
|  | window_data_.assistive_technology_enabled); | 
|  | } | 
|  |  | 
|  | bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { | 
|  | window_data_.viewport_metrics = metrics; | 
|  |  | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->UpdateWindowMetrics(metrics); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::SetLocale(const std::string& language_code, | 
|  | const std::string& country_code) { | 
|  | window_data_.language_code = language_code; | 
|  | window_data_.country_code = country_code; | 
|  |  | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->UpdateLocale(window_data_.language_code, window_data_.country_code); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::SetUserSettingsData(const std::string& data) { | 
|  | window_data_.user_settings_data = data; | 
|  |  | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->UpdateUserSettingsData(window_data_.user_settings_data); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::SetSemanticsEnabled(bool enabled) { | 
|  | window_data_.semantics_enabled = enabled; | 
|  |  | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->UpdateSemanticsEnabled(window_data_.semantics_enabled); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::SetAssistiveTechnologyEnabled(bool enabled) { | 
|  | window_data_.assistive_technology_enabled = enabled; | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->UpdateAssistiveTechnologyEnabled( | 
|  | window_data_.assistive_technology_enabled); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::BeginFrame(fxl::TimePoint frame_time) { | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->BeginFrame(frame_time); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::NotifyIdle(int64_t deadline) { | 
|  | if (!root_isolate_) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | tonic::DartState::Scope scope(root_isolate_.get()); | 
|  | Dart_NotifyIdle(deadline); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::DispatchPlatformMessage( | 
|  | fxl::RefPtr<PlatformMessage> message) { | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", | 
|  | "mode", "basic"); | 
|  | window->DispatchPlatformMessage(std::move(message)); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::DispatchPointerDataPacket( | 
|  | const PointerDataPacket& packet) { | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", | 
|  | "mode", "basic"); | 
|  | window->DispatchPointerDataPacket(packet); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::DispatchSemanticsAction(int32_t id, | 
|  | SemanticsAction action, | 
|  | std::vector<uint8_t> args) { | 
|  | TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", | 
|  | "basic"); | 
|  | if (auto window = GetWindowIfAvailable()) { | 
|  | window->DispatchSemanticsAction(id, action, std::move(args)); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Window* RuntimeController::GetWindowIfAvailable() { | 
|  | return root_isolate_ ? root_isolate_->window() : nullptr; | 
|  | } | 
|  |  | 
|  | std::string RuntimeController::DefaultRouteName() { | 
|  | return client_.DefaultRouteName(); | 
|  | } | 
|  |  | 
|  | void RuntimeController::ScheduleFrame() { | 
|  | client_.ScheduleFrame(); | 
|  | } | 
|  |  | 
|  | void RuntimeController::Render(Scene* scene) { | 
|  | client_.Render(scene->takeLayerTree()); | 
|  | } | 
|  |  | 
|  | void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { | 
|  | if (window_data_.semantics_enabled) { | 
|  | client_.UpdateSemantics(update->takeNodes(), update->takeActions()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RuntimeController::HandlePlatformMessage( | 
|  | fxl::RefPtr<PlatformMessage> message) { | 
|  | client_.HandlePlatformMessage(std::move(message)); | 
|  | } | 
|  |  | 
|  | FontCollection& RuntimeController::GetFontCollection() { | 
|  | return client_.GetFontCollection(); | 
|  | } | 
|  |  | 
|  | Dart_Port RuntimeController::GetMainPort() { | 
|  | return root_isolate_ ? root_isolate_->main_port() : ILLEGAL_PORT; | 
|  | } | 
|  |  | 
|  | std::string RuntimeController::GetIsolateName() { | 
|  | return root_isolate_ ? root_isolate_->debug_name() : ""; | 
|  | } | 
|  |  | 
|  | bool RuntimeController::HasLivePorts() { | 
|  | if (!root_isolate_) { | 
|  | return false; | 
|  | } | 
|  | tonic::DartState::Scope scope(root_isolate_.get()); | 
|  | return Dart_HasLivePorts(); | 
|  | } | 
|  |  | 
|  | tonic::DartErrorHandleType RuntimeController::GetLastError() { | 
|  | return root_isolate_ ? root_isolate_->GetLastError() : tonic::kNoError; | 
|  | } | 
|  |  | 
|  | fml::WeakPtr<DartIsolate> RuntimeController::GetRootIsolate() { | 
|  | return root_isolate_; | 
|  | } | 
|  |  | 
|  | std::pair<bool, uint32_t> RuntimeController::GetRootIsolateReturnCode() { | 
|  | return root_isolate_return_code_; | 
|  | } | 
|  |  | 
|  | }  // namespace blink |