blob: 66c07c31c36ed2c7063542484b9a34dee1665213 [file] [log] [blame]
// 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