mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Desktop embedder ComputePlatformResolvedLocale entrypoint (#19597)
This commit is contained in:
parent
b1142063fc
commit
e55af0ebfb
@ -6,6 +6,9 @@
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/closure.h"
|
||||
@ -910,6 +913,54 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
|
||||
};
|
||||
}
|
||||
|
||||
flutter::PlatformViewEmbedder::ComputePlatformResolvedLocaleCallback
|
||||
compute_platform_resolved_locale_callback = nullptr;
|
||||
if (SAFE_ACCESS(args, compute_platform_resolved_locale_callback, nullptr) !=
|
||||
nullptr) {
|
||||
compute_platform_resolved_locale_callback =
|
||||
[ptr = args->compute_platform_resolved_locale_callback](
|
||||
const std::vector<std::string>& supported_locales_data) {
|
||||
const size_t number_of_strings_per_locale = 3;
|
||||
size_t locale_count =
|
||||
supported_locales_data.size() / number_of_strings_per_locale;
|
||||
std::vector<FlutterLocale> supported_locales;
|
||||
std::vector<const FlutterLocale*> supported_locales_ptr;
|
||||
for (size_t i = 0; i < locale_count; ++i) {
|
||||
supported_locales.push_back(
|
||||
{.struct_size = sizeof(FlutterLocale),
|
||||
.language_code =
|
||||
supported_locales_data[i * number_of_strings_per_locale +
|
||||
0]
|
||||
.c_str(),
|
||||
.country_code =
|
||||
supported_locales_data[i * number_of_strings_per_locale +
|
||||
1]
|
||||
.c_str(),
|
||||
.script_code =
|
||||
supported_locales_data[i * number_of_strings_per_locale +
|
||||
2]
|
||||
.c_str(),
|
||||
.variant_code = nullptr});
|
||||
supported_locales_ptr.push_back(&supported_locales[i]);
|
||||
}
|
||||
|
||||
const FlutterLocale* result =
|
||||
ptr(supported_locales_ptr.data(), locale_count);
|
||||
|
||||
std::unique_ptr<std::vector<std::string>> out =
|
||||
std::make_unique<std::vector<std::string>>();
|
||||
if (result) {
|
||||
std::string language_code(SAFE_ACCESS(result, language_code, ""));
|
||||
if (language_code != "") {
|
||||
out->push_back(language_code);
|
||||
out->emplace_back(SAFE_ACCESS(result, country_code, ""));
|
||||
out->emplace_back(SAFE_ACCESS(result, script_code, ""));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
}
|
||||
|
||||
auto external_view_embedder_result =
|
||||
InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
|
||||
if (external_view_embedder_result.second) {
|
||||
@ -919,10 +970,11 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
|
||||
|
||||
flutter::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table =
|
||||
{
|
||||
update_semantics_nodes_callback, //
|
||||
update_semantics_custom_actions_callback, //
|
||||
platform_message_response_callback, //
|
||||
vsync_callback, //
|
||||
update_semantics_nodes_callback, //
|
||||
update_semantics_custom_actions_callback, //
|
||||
platform_message_response_callback, //
|
||||
vsync_callback, //
|
||||
compute_platform_resolved_locale_callback, //
|
||||
};
|
||||
|
||||
auto on_create_platform_view = InferPlatformViewCreationCallback(
|
||||
@ -1058,17 +1110,17 @@ FlutterEngineResult FlutterEngineRunInitialized(
|
||||
|
||||
auto embedder_engine = reinterpret_cast<flutter::EmbedderEngine*>(engine);
|
||||
|
||||
// The engine must not already be running. Initialize may only be called once
|
||||
// on an engine instance.
|
||||
// The engine must not already be running. Initialize may only be called
|
||||
// once on an engine instance.
|
||||
if (embedder_engine->IsValid()) {
|
||||
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid.");
|
||||
}
|
||||
|
||||
// Step 1: Launch the shell.
|
||||
if (!embedder_engine->LaunchShell()) {
|
||||
return LOG_EMBEDDER_ERROR(
|
||||
kInvalidArguments,
|
||||
"Could not launch the engine using supplied initialization arguments.");
|
||||
return LOG_EMBEDDER_ERROR(kInvalidArguments,
|
||||
"Could not launch the engine using supplied "
|
||||
"initialization arguments.");
|
||||
}
|
||||
|
||||
// Step 2: Tell the platform view to initialize itself.
|
||||
@ -1193,8 +1245,8 @@ inline int64_t PointerDataButtonsForLegacyEvent(
|
||||
switch (change) {
|
||||
case flutter::PointerData::Change::kDown:
|
||||
case flutter::PointerData::Change::kMove:
|
||||
// These kinds of change must have a non-zero `buttons`, otherwise gesture
|
||||
// recognizers will ignore these events.
|
||||
// These kinds of change must have a non-zero `buttons`, otherwise
|
||||
// gesture recognizers will ignore these events.
|
||||
return flutter::kPointerButtonMousePrimary;
|
||||
case flutter::PointerData::Change::kCancel:
|
||||
case flutter::PointerData::Change::kAdd:
|
||||
@ -1236,16 +1288,17 @@ FlutterEngineResult FlutterEngineSendPointerEvent(
|
||||
pointer_data.physical_delta_x = 0.0;
|
||||
pointer_data.physical_delta_y = 0.0;
|
||||
pointer_data.device = SAFE_ACCESS(current, device, 0);
|
||||
// Pointer identifier will be generated in pointer_data_packet_converter.cc.
|
||||
// Pointer identifier will be generated in
|
||||
// pointer_data_packet_converter.cc.
|
||||
pointer_data.pointer_identifier = 0;
|
||||
pointer_data.signal_kind = ToPointerDataSignalKind(
|
||||
SAFE_ACCESS(current, signal_kind, kFlutterPointerSignalKindNone));
|
||||
pointer_data.scroll_delta_x = SAFE_ACCESS(current, scroll_delta_x, 0.0);
|
||||
pointer_data.scroll_delta_y = SAFE_ACCESS(current, scroll_delta_y, 0.0);
|
||||
FlutterPointerDeviceKind device_kind = SAFE_ACCESS(current, device_kind, 0);
|
||||
// For backwards compatibility with embedders written before the device kind
|
||||
// and buttons were exposed, if the device kind is not set treat it as a
|
||||
// mouse, with a synthesized primary button state based on the phase.
|
||||
// For backwards compatibility with embedders written before the device
|
||||
// kind and buttons were exposed, if the device kind is not set treat it
|
||||
// as a mouse, with a synthesized primary button state based on the phase.
|
||||
if (device_kind == 0) {
|
||||
pointer_data.kind = flutter::PointerData::DeviceKind::kMouse;
|
||||
pointer_data.buttons =
|
||||
@ -1356,9 +1409,9 @@ FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(
|
||||
auto handle = new FlutterPlatformMessageResponseHandle();
|
||||
|
||||
handle->message = fml::MakeRefCounted<flutter::PlatformMessage>(
|
||||
"", // The channel is empty and unused as the response handle is going to
|
||||
// referenced directly in the |FlutterEngineSendPlatformMessage| with
|
||||
// the container message discarded.
|
||||
"", // The channel is empty and unused as the response handle is going
|
||||
// to referenced directly in the |FlutterEngineSendPlatformMessage|
|
||||
// with the container message discarded.
|
||||
fml::MakeRefCounted<flutter::EmbedderPlatformMessageResponse>(
|
||||
std::move(platform_task_runner), response_callback));
|
||||
*response_out = handle;
|
||||
@ -1791,14 +1844,14 @@ FlutterEngineResult FlutterEnginePostDartObject(
|
||||
peer->trampoline = callback;
|
||||
// This finalizer is set so that in case of failure of the
|
||||
// Dart_PostCObject below, we collect the peer. The embedder is still
|
||||
// responsible for collecting the buffer in case of non-kSuccess returns
|
||||
// from this method. This finalizer must be released in case of kSuccess
|
||||
// returns from this method.
|
||||
// responsible for collecting the buffer in case of non-kSuccess
|
||||
// returns from this method. This finalizer must be released in case
|
||||
// of kSuccess returns from this method.
|
||||
typed_data_finalizer.SetClosure([peer]() {
|
||||
// This is the tiny object we use as the peer to the Dart call so that
|
||||
// we can attach the a trampoline to the embedder supplied callback.
|
||||
// In case of error, we need to collect this object lest we introduce
|
||||
// a tiny leak.
|
||||
// This is the tiny object we use as the peer to the Dart call so
|
||||
// that we can attach the a trampoline to the embedder supplied
|
||||
// callback. In case of error, we need to collect this object lest
|
||||
// we introduce a tiny leak.
|
||||
delete peer;
|
||||
});
|
||||
dart_object.type = Dart_CObject_kExternalTypedData;
|
||||
|
||||
@ -861,6 +861,10 @@ typedef struct {
|
||||
const char* variant_code;
|
||||
} FlutterLocale;
|
||||
|
||||
typedef const FlutterLocale* (*FlutterComputePlatformResolvedLocaleCallback)(
|
||||
const FlutterLocale** /* supported_locales*/,
|
||||
size_t /* Number of locales*/);
|
||||
|
||||
typedef int64_t FlutterEngineDartPort;
|
||||
|
||||
typedef enum {
|
||||
@ -1205,6 +1209,17 @@ typedef struct {
|
||||
///
|
||||
/// Embedders can provide either snapshot buffers or aot_data, but not both.
|
||||
FlutterEngineAOTData aot_data;
|
||||
|
||||
/// A callback that computes the locale the platform would natively resolve
|
||||
/// to.
|
||||
///
|
||||
/// The input parameter is an array of FlutterLocales which represent the
|
||||
/// locales supported by the app. One of the input supported locales should
|
||||
/// be selected and returned to best match with the user/device's preferred
|
||||
/// locale. The implementation should produce a result that as closely
|
||||
/// matches what the platform would natively resolve to as possible.
|
||||
FlutterComputePlatformResolvedLocaleCallback
|
||||
compute_platform_resolved_locale_callback;
|
||||
} FlutterProjectArgs;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -97,6 +97,11 @@ std::unique_ptr<VsyncWaiter> PlatformViewEmbedder::CreateVSyncWaiter() {
|
||||
std::unique_ptr<std::vector<std::string>>
|
||||
PlatformViewEmbedder::ComputePlatformResolvedLocales(
|
||||
const std::vector<std::string>& supported_locale_data) {
|
||||
if (platform_dispatch_table_.compute_platform_resolved_locale_callback !=
|
||||
nullptr) {
|
||||
return platform_dispatch_table_.compute_platform_resolved_locale_callback(
|
||||
supported_locale_data);
|
||||
}
|
||||
std::unique_ptr<std::vector<std::string>> out =
|
||||
std::make_unique<std::vector<std::string>>();
|
||||
return out;
|
||||
|
||||
@ -25,6 +25,9 @@ class PlatformViewEmbedder final : public PlatformView {
|
||||
std::function<void(flutter::CustomAccessibilityActionUpdates actions)>;
|
||||
using PlatformMessageResponseCallback =
|
||||
std::function<void(fml::RefPtr<flutter::PlatformMessage>)>;
|
||||
using ComputePlatformResolvedLocaleCallback =
|
||||
std::function<std::unique_ptr<std::vector<std::string>>(
|
||||
const std::vector<std::string>& supported_locale_data)>;
|
||||
|
||||
struct PlatformDispatchTable {
|
||||
UpdateSemanticsNodesCallback update_semantics_nodes_callback; // optional
|
||||
@ -33,6 +36,8 @@ class PlatformViewEmbedder final : public PlatformView {
|
||||
PlatformMessageResponseCallback
|
||||
platform_message_response_callback; // optional
|
||||
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional
|
||||
ComputePlatformResolvedLocaleCallback
|
||||
compute_platform_resolved_locale_callback;
|
||||
};
|
||||
|
||||
// Creates a platform view that sets up an OpenGL rasterizer.
|
||||
|
||||
@ -80,6 +80,7 @@ EmbedderConfigBuilder::EmbedderConfigBuilder(
|
||||
SetAssetsPath();
|
||||
SetIsolateCreateCallbackHook();
|
||||
SetSemanticsCallbackHooks();
|
||||
SetLocalizationCallbackHooks();
|
||||
AddCommandLineArgument("--disable-observatory");
|
||||
|
||||
if (preference == InitializationPreference::kSnapshotsInitialize ||
|
||||
@ -157,6 +158,11 @@ void EmbedderConfigBuilder::SetSemanticsCallbackHooks() {
|
||||
EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook();
|
||||
}
|
||||
|
||||
void EmbedderConfigBuilder::SetLocalizationCallbackHooks() {
|
||||
project_args_.compute_platform_resolved_locale_callback =
|
||||
EmbedderTestContext::GetComputePlatformResolvedLocaleCallbackHook();
|
||||
}
|
||||
|
||||
void EmbedderConfigBuilder::SetDartEntrypoint(std::string entrypoint) {
|
||||
if (entrypoint.size() == 0) {
|
||||
return;
|
||||
|
||||
@ -59,6 +59,8 @@ class EmbedderConfigBuilder {
|
||||
|
||||
void SetSemanticsCallbackHooks();
|
||||
|
||||
void SetLocalizationCallbackHooks();
|
||||
|
||||
void SetDartEntrypoint(std::string entrypoint);
|
||||
|
||||
void AddCommandLineArgument(std::string arg);
|
||||
|
||||
@ -160,6 +160,14 @@ EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook() {
|
||||
};
|
||||
}
|
||||
|
||||
FlutterComputePlatformResolvedLocaleCallback
|
||||
EmbedderTestContext::GetComputePlatformResolvedLocaleCallbackHook() {
|
||||
return [](const FlutterLocale** supported_locales,
|
||||
size_t length) -> const FlutterLocale* {
|
||||
return supported_locales[0];
|
||||
};
|
||||
}
|
||||
|
||||
void EmbedderTestContext::SetupOpenGLSurface(SkISize surface_size) {
|
||||
FML_CHECK(!gl_surface_);
|
||||
gl_surface_ = std::make_unique<TestGLSurface>(surface_size);
|
||||
|
||||
@ -112,6 +112,9 @@ class EmbedderTestContext {
|
||||
static FlutterUpdateSemanticsCustomActionCallback
|
||||
GetUpdateSemanticsCustomActionCallbackHook();
|
||||
|
||||
static FlutterComputePlatformResolvedLocaleCallback
|
||||
GetComputePlatformResolvedLocaleCallbackHook();
|
||||
|
||||
void SetupAOTMappingsIfNecessary();
|
||||
|
||||
void SetupAOTDataIfNecessary();
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#define FML_USED_ON_EMBEDDER
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "embedder.h"
|
||||
#include "embedder_engine.h"
|
||||
@ -2889,6 +2890,33 @@ TEST_F(EmbedderTest, CanUpdateLocales) {
|
||||
check_latch.Wait();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, LocalizationCallbacksCalled) {
|
||||
auto& context = GetEmbedderContext();
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
context.AddIsolateCreateCallback([&latch]() { latch.Signal(); });
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetSoftwareRendererConfig();
|
||||
auto engine = builder.LaunchEngine();
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
// Wait for the root isolate to launch.
|
||||
latch.Wait();
|
||||
|
||||
flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
|
||||
std::vector<std::string> supported_locales;
|
||||
supported_locales.push_back("es");
|
||||
supported_locales.push_back("MX");
|
||||
supported_locales.push_back("");
|
||||
auto result = shell.GetPlatformView()->ComputePlatformResolvedLocales(
|
||||
supported_locales);
|
||||
|
||||
ASSERT_EQ((*result).size(), supported_locales.size()); // 3
|
||||
ASSERT_EQ((*result)[0], supported_locales[0]);
|
||||
ASSERT_EQ((*result)[1], supported_locales[1]);
|
||||
ASSERT_EQ((*result)[2], supported_locales[2]);
|
||||
|
||||
engine.reset();
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, CanQueryDartAOTMode) {
|
||||
ASSERT_EQ(FlutterEngineRunsAOTCompiledDartCode(),
|
||||
flutter::DartVM::IsRunningPrecompiledCode());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user