mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
* systems/settings channel split * merge textScaleFactor and alwaysUse24HourFormat into flutter/settings channel * add debugOverrideAlwaysUse24HourFormat * implement textScaleFactor on iOS * address comments * remove debugOverrideAlwaysUse24HourFormat * clang-format
285 lines
9.0 KiB
C++
285 lines
9.0 KiB
C++
// 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/lib/ui/window/window.h"
|
|
|
|
#include "flutter/lib/ui/compositing/scene.h"
|
|
#include "flutter/lib/ui/ui_dart_state.h"
|
|
#include "flutter/lib/ui/window/platform_message_response_dart.h"
|
|
#include "lib/tonic/converter/dart_converter.h"
|
|
#include "lib/tonic/dart_args.h"
|
|
#include "lib/tonic/dart_library_natives.h"
|
|
#include "lib/tonic/dart_microtask_queue.h"
|
|
#include "lib/tonic/logging/dart_invoke.h"
|
|
#include "lib/tonic/typed_data/dart_byte_data.h"
|
|
|
|
using tonic::DartInvokeField;
|
|
using tonic::DartState;
|
|
using tonic::StdStringToDart;
|
|
using tonic::ToDart;
|
|
|
|
namespace blink {
|
|
namespace {
|
|
|
|
Dart_Handle ToByteData(const std::vector<uint8_t>& buffer) {
|
|
Dart_Handle data_handle =
|
|
Dart_NewTypedData(Dart_TypedData_kByteData, buffer.size());
|
|
if (Dart_IsError(data_handle))
|
|
return data_handle;
|
|
|
|
Dart_TypedData_Type type;
|
|
void* data = nullptr;
|
|
intptr_t num_bytes = 0;
|
|
FXL_CHECK(!Dart_IsError(
|
|
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_bytes)));
|
|
|
|
memcpy(data, buffer.data(), num_bytes);
|
|
Dart_TypedDataReleaseData(data_handle);
|
|
return data_handle;
|
|
}
|
|
|
|
void DefaultRouteName(Dart_NativeArguments args) {
|
|
std::string routeName =
|
|
UIDartState::Current()->window()->client()->DefaultRouteName();
|
|
Dart_SetReturnValue(args, StdStringToDart(routeName));
|
|
}
|
|
|
|
void ScheduleFrame(Dart_NativeArguments args) {
|
|
UIDartState::Current()->window()->client()->ScheduleFrame();
|
|
}
|
|
|
|
void Render(Dart_NativeArguments args) {
|
|
Dart_Handle exception = nullptr;
|
|
Scene* scene =
|
|
tonic::DartConverter<Scene*>::FromArguments(args, 1, exception);
|
|
if (exception) {
|
|
Dart_ThrowException(exception);
|
|
return;
|
|
}
|
|
UIDartState::Current()->window()->client()->Render(scene);
|
|
}
|
|
|
|
void UpdateSemantics(Dart_NativeArguments args) {
|
|
Dart_Handle exception = nullptr;
|
|
SemanticsUpdate* update =
|
|
tonic::DartConverter<SemanticsUpdate*>::FromArguments(args, 1, exception);
|
|
if (exception) {
|
|
Dart_ThrowException(exception);
|
|
return;
|
|
}
|
|
UIDartState::Current()->window()->client()->UpdateSemantics(update);
|
|
}
|
|
|
|
void SendPlatformMessage(Dart_Handle window,
|
|
const std::string& name,
|
|
Dart_Handle callback,
|
|
const tonic::DartByteData& data) {
|
|
UIDartState* dart_state = UIDartState::Current();
|
|
|
|
fxl::RefPtr<PlatformMessageResponse> response;
|
|
if (!Dart_IsNull(callback)) {
|
|
response = fxl::MakeRefCounted<PlatformMessageResponseDart>(
|
|
tonic::DartPersistentValue(dart_state, callback));
|
|
}
|
|
if (Dart_IsNull(data.dart_handle())) {
|
|
UIDartState::Current()->window()->client()->HandlePlatformMessage(
|
|
fxl::MakeRefCounted<PlatformMessage>(name, response));
|
|
} else {
|
|
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
|
|
|
|
UIDartState::Current()->window()->client()->HandlePlatformMessage(
|
|
fxl::MakeRefCounted<PlatformMessage>(
|
|
name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
|
|
response));
|
|
}
|
|
}
|
|
|
|
void _SendPlatformMessage(Dart_NativeArguments args) {
|
|
tonic::DartCallStatic(&SendPlatformMessage, args);
|
|
}
|
|
|
|
void RespondToPlatformMessage(Dart_Handle window,
|
|
int response_id,
|
|
const tonic::DartByteData& data) {
|
|
if (Dart_IsNull(data.dart_handle())) {
|
|
UIDartState::Current()->window()->CompletePlatformMessageEmptyResponse(
|
|
response_id);
|
|
} else {
|
|
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
|
|
UIDartState::Current()->window()->CompletePlatformMessageResponse(
|
|
response_id,
|
|
std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
|
|
}
|
|
}
|
|
|
|
void _RespondToPlatformMessage(Dart_NativeArguments args) {
|
|
tonic::DartCallStatic(&RespondToPlatformMessage, args);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
WindowClient::~WindowClient() {}
|
|
|
|
Window::Window(WindowClient* client) : client_(client) {}
|
|
|
|
Window::~Window() {}
|
|
|
|
void Window::DidCreateIsolate() {
|
|
library_.Set(DartState::Current(), Dart_LookupLibrary(ToDart("dart:ui")));
|
|
}
|
|
|
|
void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) {
|
|
viewport_metrics_ = metrics;
|
|
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
DartInvokeField(
|
|
library_.value(), "_updateWindowMetrics",
|
|
{
|
|
ToDart(metrics.device_pixel_ratio),
|
|
ToDart(static_cast<double>(metrics.physical_width)),
|
|
ToDart(static_cast<double>(metrics.physical_height)),
|
|
ToDart(static_cast<double>(metrics.physical_padding_top)),
|
|
ToDart(static_cast<double>(metrics.physical_padding_right)),
|
|
ToDart(static_cast<double>(metrics.physical_padding_bottom)),
|
|
ToDart(static_cast<double>(metrics.physical_padding_left)),
|
|
});
|
|
}
|
|
|
|
void Window::UpdateLocale(const std::string& language_code,
|
|
const std::string& country_code) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
DartInvokeField(library_.value(), "_updateLocale",
|
|
{
|
|
StdStringToDart(language_code),
|
|
StdStringToDart(country_code),
|
|
});
|
|
}
|
|
|
|
void Window::UpdateUserSettingsData(const std::string& data) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
DartInvokeField(library_.value(), "_updateUserSettingsData",
|
|
{
|
|
StdStringToDart(data),
|
|
});
|
|
}
|
|
|
|
void Window::UpdateSemanticsEnabled(bool enabled) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
DartInvokeField(library_.value(), "_updateSemanticsEnabled",
|
|
{ToDart(enabled)});
|
|
}
|
|
|
|
void Window::DispatchPlatformMessage(fxl::RefPtr<PlatformMessage> message) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
Dart_Handle data_handle =
|
|
(message->hasData()) ? ToByteData(message->data()) : Dart_Null();
|
|
if (Dart_IsError(data_handle))
|
|
return;
|
|
|
|
int response_id = 0;
|
|
if (auto response = message->response()) {
|
|
response_id = next_response_id_++;
|
|
pending_responses_[response_id] = response;
|
|
}
|
|
|
|
DartInvokeField(
|
|
library_.value(), "_dispatchPlatformMessage",
|
|
{ToDart(message->channel()), data_handle, ToDart(response_id)});
|
|
}
|
|
|
|
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
Dart_Handle data_handle = ToByteData(packet.data());
|
|
if (Dart_IsError(data_handle))
|
|
return;
|
|
DartInvokeField(library_.value(), "_dispatchPointerDataPacket",
|
|
{data_handle});
|
|
}
|
|
|
|
void Window::DispatchSemanticsAction(int32_t id, SemanticsAction action) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
DartInvokeField(library_.value(), "_dispatchSemanticsAction",
|
|
{ToDart(id), ToDart(static_cast<int32_t>(action))});
|
|
}
|
|
|
|
void Window::BeginFrame(fxl::TimePoint frameTime) {
|
|
tonic::DartState* dart_state = library_.dart_state().get();
|
|
if (!dart_state)
|
|
return;
|
|
tonic::DartState::Scope scope(dart_state);
|
|
|
|
int64_t microseconds = (frameTime - fxl::TimePoint()).ToMicroseconds();
|
|
|
|
DartInvokeField(library_.value(), "_beginFrame",
|
|
{
|
|
Dart_NewInteger(microseconds),
|
|
});
|
|
|
|
tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks();
|
|
|
|
DartInvokeField(library_.value(), "_drawFrame", {});
|
|
}
|
|
|
|
void Window::CompletePlatformMessageEmptyResponse(int response_id) {
|
|
if (!response_id)
|
|
return;
|
|
auto it = pending_responses_.find(response_id);
|
|
if (it == pending_responses_.end())
|
|
return;
|
|
auto response = std::move(it->second);
|
|
pending_responses_.erase(it);
|
|
response->CompleteEmpty();
|
|
}
|
|
|
|
void Window::CompletePlatformMessageResponse(int response_id,
|
|
std::vector<uint8_t> data) {
|
|
if (!response_id)
|
|
return;
|
|
auto it = pending_responses_.find(response_id);
|
|
if (it == pending_responses_.end())
|
|
return;
|
|
auto response = std::move(it->second);
|
|
pending_responses_.erase(it);
|
|
response->Complete(std::move(data));
|
|
}
|
|
|
|
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
|
|
natives->Register({
|
|
{"Window_defaultRouteName", DefaultRouteName, 1, true},
|
|
{"Window_scheduleFrame", ScheduleFrame, 1, true},
|
|
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
|
|
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
|
|
{"Window_render", Render, 2, true},
|
|
{"Window_updateSemantics", UpdateSemantics, 2, true},
|
|
});
|
|
}
|
|
|
|
} // namespace blink
|