| // 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/lib/ui/window/platform_message_response_dart.h" |
| |
| #include <utility> |
| |
| #include "flutter/common/task_runners.h" |
| #include "flutter/fml/make_copyable.h" |
| #include "flutter/fml/trace_event.h" |
| #include "third_party/tonic/dart_state.h" |
| #include "third_party/tonic/logging/dart_invoke.h" |
| #include "third_party/tonic/typed_data/dart_byte_data.h" |
| |
| static std::atomic<uint64_t> platform_message_counter = 1; |
| |
| namespace flutter { |
| namespace { |
| |
| void MappingFinalizer(void* isolate_callback_data, void* peer) { |
| delete static_cast<fml::Mapping*>(peer); |
| } |
| |
| template <typename Callback, typename TaskRunner, typename Result> |
| void PostCompletion(Callback&& callback, |
| const TaskRunner& ui_task_runner, |
| bool* is_complete, |
| const std::string& channel, |
| Result&& result) { |
| if (callback.is_empty()) { |
| return; |
| } |
| FML_DCHECK(!*is_complete); |
| *is_complete = true; |
| uint64_t platform_message_id = platform_message_counter.fetch_add(1); |
| TRACE_EVENT_ASYNC_BEGIN1("flutter", "PlatformChannel ScheduleResult", |
| platform_message_id, "channel", channel.c_str()); |
| ui_task_runner->PostTask(fml::MakeCopyable( |
| [callback = std::move(callback), platform_message_id, |
| result = std::move(result), channel = channel]() mutable { |
| TRACE_EVENT_ASYNC_END0("flutter", "PlatformChannel ScheduleResult", |
| platform_message_id); |
| std::shared_ptr<tonic::DartState> dart_state = |
| callback.dart_state().lock(); |
| if (!dart_state) { |
| return; |
| } |
| tonic::DartState::Scope scope(dart_state); |
| tonic::DartInvoke(callback.Release(), {result()}); |
| })); |
| } |
| } // namespace |
| |
| PlatformMessageResponseDart::PlatformMessageResponseDart( |
| tonic::DartPersistentValue callback, |
| fml::RefPtr<fml::TaskRunner> ui_task_runner, |
| const std::string& channel) |
| : callback_(std::move(callback)), |
| ui_task_runner_(std::move(ui_task_runner)), |
| channel_(channel) {} |
| |
| PlatformMessageResponseDart::~PlatformMessageResponseDart() { |
| if (!callback_.is_empty()) { |
| ui_task_runner_->PostTask(fml::MakeCopyable( |
| [callback = std::move(callback_)]() mutable { callback.Clear(); })); |
| } |
| } |
| |
| void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) { |
| PostCompletion( |
| std::move(callback_), ui_task_runner_, &is_complete_, channel_, |
| [data = std::move(data)]() mutable { |
| Dart_Handle byte_buffer; |
| intptr_t size = data->GetSize(); |
| if (data->GetSize() > tonic::DartByteData::kExternalSizeThreshold) { |
| const void* mapping = data->GetMapping(); |
| byte_buffer = Dart_NewUnmodifiableExternalTypedDataWithFinalizer( |
| /*type=*/Dart_TypedData_kByteData, |
| /*data=*/mapping, |
| /*length=*/size, |
| /*peer=*/data.release(), |
| /*external_allocation_size=*/size, |
| /*callback=*/MappingFinalizer); |
| } else { |
| Dart_Handle mutable_byte_buffer = |
| tonic::DartByteData::Create(data->GetMapping(), data->GetSize()); |
| Dart_Handle ui_lib = Dart_LookupLibrary( |
| tonic::DartConverter<std::string>().ToDart("dart:ui")); |
| FML_DCHECK(!(Dart_IsNull(ui_lib) || Dart_IsError(ui_lib))); |
| byte_buffer = Dart_Invoke(ui_lib, |
| tonic::DartConverter<std::string>().ToDart( |
| "_wrapUnmodifiableByteData"), |
| 1, &mutable_byte_buffer); |
| FML_DCHECK(!(Dart_IsNull(byte_buffer) || Dart_IsError(byte_buffer))); |
| } |
| |
| return byte_buffer; |
| }); |
| } |
| |
| void PlatformMessageResponseDart::CompleteEmpty() { |
| PostCompletion(std::move(callback_), ui_task_runner_, &is_complete_, channel_, |
| [] { return Dart_Null(); }); |
| } |
| |
| } // namespace flutter |