| // 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/lib/ui/window/window.h" |
| #include "third_party/tonic/dart_state.h" |
| #include "third_party/tonic/logging/dart_invoke.h" |
| |
| namespace flutter { |
| |
| namespace { |
| |
| // Avoid copying the contents of messages beyond a certain size. |
| const int kMessageCopyThreshold = 1000; |
| |
| void MessageDataFinalizer(void* isolate_callback_data, |
| Dart_WeakPersistentHandle handle, |
| void* peer) { |
| std::vector<uint8_t>* data = reinterpret_cast<std::vector<uint8_t>*>(peer); |
| delete data; |
| } |
| |
| Dart_Handle WrapByteData(std::vector<uint8_t> data) { |
| if (data.size() < kMessageCopyThreshold) { |
| return ToByteData(data); |
| } else { |
| std::vector<uint8_t>* heap_data = new std::vector<uint8_t>(std::move(data)); |
| return Dart_NewExternalTypedDataWithFinalizer( |
| Dart_TypedData_kByteData, heap_data->data(), heap_data->size(), |
| heap_data, heap_data->size(), MessageDataFinalizer); |
| } |
| } |
| |
| Dart_Handle WrapByteData(std::unique_ptr<fml::Mapping> mapping) { |
| std::vector<uint8_t> data(mapping->GetSize()); |
| memcpy(data.data(), mapping->GetMapping(), mapping->GetSize()); |
| return WrapByteData(std::move(data)); |
| } |
| |
| } // anonymous namespace |
| |
| PlatformMessageResponseDart::PlatformMessageResponseDart( |
| tonic::DartPersistentValue callback, |
| fml::RefPtr<fml::TaskRunner> ui_task_runner) |
| : callback_(std::move(callback)), |
| ui_task_runner_(std::move(ui_task_runner)) {} |
| |
| 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) { |
| if (callback_.is_empty()) |
| return; |
| FML_DCHECK(!is_complete_); |
| is_complete_ = true; |
| ui_task_runner_->PostTask(fml::MakeCopyable( |
| [callback = std::move(callback_), data = std::move(data)]() mutable { |
| std::shared_ptr<tonic::DartState> dart_state = |
| callback.dart_state().lock(); |
| if (!dart_state) |
| return; |
| tonic::DartState::Scope scope(dart_state); |
| |
| Dart_Handle byte_buffer = WrapByteData(std::move(data)); |
| tonic::DartInvoke(callback.Release(), {byte_buffer}); |
| })); |
| } |
| |
| void PlatformMessageResponseDart::CompleteEmpty() { |
| if (callback_.is_empty()) |
| return; |
| FML_DCHECK(!is_complete_); |
| is_complete_ = true; |
| ui_task_runner_->PostTask( |
| fml::MakeCopyable([callback = std::move(callback_)]() mutable { |
| 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(), {Dart_Null()}); |
| })); |
| } |
| |
| } // namespace flutter |