Skip to content

Commit 3e4c41c

Browse files
Use Windows Display Language (flutter#43341)
Get the Windows Display Language for locale selection instead of the preferred languages. flutter/flutter#129786 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Loïc Sharma <[email protected]>
1 parent 2039988 commit 3e4c41c

12 files changed

+65
-179
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3235,8 +3235,6 @@ ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc + .
32353235
ORIGIN: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h + ../../../flutter/LICENSE
32363236
ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.cc + ../../../flutter/LICENSE
32373237
ORIGIN: ../../../flutter/shell/platform/windows/windows_proc_table.h + ../../../flutter/LICENSE
3238-
ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.cc + ../../../flutter/LICENSE
3239-
ORIGIN: ../../../flutter/shell/platform/windows/windows_registry.h + ../../../flutter/LICENSE
32403238
ORIGIN: ../../../flutter/shell/platform/windows/windowsx_shim.h + ../../../flutter/LICENSE
32413239
ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.cc + ../../../flutter/LICENSE
32423240
ORIGIN: ../../../flutter/shell/profiling/sampling_profiler.h + ../../../flutter/LICENSE
@@ -5939,8 +5937,6 @@ FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.cc
59395937
FILE: ../../../flutter/shell/platform/windows/windows_lifecycle_manager.h
59405938
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc
59415939
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h
5942-
FILE: ../../../flutter/shell/platform/windows/windows_registry.cc
5943-
FILE: ../../../flutter/shell/platform/windows/windows_registry.h
59445940
FILE: ../../../flutter/shell/platform/windows/windowsx_shim.h
59455941
FILE: ../../../flutter/shell/profiling/sampling_profiler.cc
59465942
FILE: ../../../flutter/shell/profiling/sampling_profiler.h

shell/platform/windows/BUILD.gn

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ source_set("flutter_windows_source") {
107107
"windows_lifecycle_manager.h",
108108
"windows_proc_table.cc",
109109
"windows_proc_table.h",
110-
"windows_registry.cc",
111-
"windows_registry.h",
112110
"windowsx_shim.h",
113111
]
114112

shell/platform/windows/flutter_windows_engine.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,9 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) {
156156

157157
} // namespace
158158

159-
FlutterWindowsEngine::FlutterWindowsEngine(
160-
const FlutterProjectBundle& project,
161-
std::unique_ptr<WindowsRegistry> registry)
159+
FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
162160
: project_(std::make_unique<FlutterProjectBundle>(project)),
163161
aot_data_(nullptr, nullptr),
164-
windows_registry_(std::move(registry)),
165162
lifecycle_manager_(std::make_unique<WindowsLifecycleManager>(this)) {
166163
embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
167164
FlutterEngineGetProcAddresses(&embedder_api_);
@@ -572,7 +569,7 @@ void FlutterWindowsEngine::SetLifecycleState(flutter::AppLifecycleState state) {
572569

573570
void FlutterWindowsEngine::SendSystemLocales() {
574571
std::vector<LanguageInfo> languages =
575-
GetPreferredLanguageInfo(*windows_registry_);
572+
GetPreferredLanguageInfo(windows_proc_table_);
576573
std::vector<FlutterLocale> flutter_locales;
577574
flutter_locales.reserve(languages.size());
578575
for (const auto& info : languages) {

shell/platform/windows/flutter_windows_engine.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#include "flutter/shell/platform/windows/window_proc_delegate_manager.h"
3838
#include "flutter/shell/platform/windows/window_state.h"
3939
#include "flutter/shell/platform/windows/windows_lifecycle_manager.h"
40-
#include "flutter/shell/platform/windows/windows_registry.h"
40+
#include "flutter/shell/platform/windows/windows_proc_table.h"
4141
#include "third_party/rapidjson/include/rapidjson/document.h"
4242

4343
namespace flutter {
@@ -77,13 +77,8 @@ static void WindowsPlatformThreadPrioritySetter(
7777
// run in headless mode.
7878
class FlutterWindowsEngine {
7979
public:
80-
// Creates a new Flutter engine with an injectible windows registry.
81-
FlutterWindowsEngine(const FlutterProjectBundle& project,
82-
std::unique_ptr<WindowsRegistry> windows_registry);
83-
8480
// Creates a new Flutter engine object configured to run |project|.
85-
explicit FlutterWindowsEngine(const FlutterProjectBundle& project)
86-
: FlutterWindowsEngine(project, std::make_unique<WindowsRegistry>()) {}
81+
explicit FlutterWindowsEngine(const FlutterProjectBundle& project);
8782

8883
virtual ~FlutterWindowsEngine();
8984

@@ -405,12 +400,11 @@ class FlutterWindowsEngine {
405400
// The on frame drawn callback.
406401
fml::closure next_frame_callback_;
407402

408-
// Wrapper providing Windows registry access.
409-
std::unique_ptr<WindowsRegistry> windows_registry_;
410-
411403
// Handler for top level window messages.
412404
std::unique_ptr<WindowsLifecycleManager> lifecycle_manager_;
413405

406+
WindowsProcTable windows_proc_table_;
407+
414408
FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsEngine);
415409
};
416410

shell/platform/windows/system_utils.cc

Lines changed: 12 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
namespace flutter {
1414

1515
std::vector<LanguageInfo> GetPreferredLanguageInfo(
16-
const WindowsRegistry& registry) {
17-
std::vector<std::wstring> languages = GetPreferredLanguages(registry);
16+
const WindowsProcTable& windows_proc_table) {
17+
std::vector<std::wstring> languages =
18+
GetPreferredLanguages(windows_proc_table);
1819
std::vector<LanguageInfo> language_info;
1920
language_info.reserve(languages.size());
2021

@@ -24,63 +25,29 @@ std::vector<LanguageInfo> GetPreferredLanguageInfo(
2425
return language_info;
2526
}
2627

27-
std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry,
28-
ULONG buffer_size) {
29-
std::wstring buffer(buffer_size, '\0');
30-
if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey,
31-
kGetPreferredLanguageRegValue,
32-
RRF_RT_REG_MULTI_SZ, NULL, buffer.data(),
33-
&buffer_size) != ERROR_SUCCESS) {
34-
return std::wstring();
35-
}
36-
return buffer;
37-
}
38-
39-
std::wstring GetPreferredLanguagesFromMUI() {
40-
ULONG buffer_size;
28+
std::wstring GetPreferredLanguagesFromMUI(
29+
const WindowsProcTable& windows_proc_table) {
30+
ULONG buffer_size = 0;
4131
ULONG count = 0;
4232
DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK;
43-
if (!GetThreadPreferredUILanguages(flags, &count, nullptr, &buffer_size)) {
33+
if (!windows_proc_table.GetThreadPreferredUILanguages(flags, &count, nullptr,
34+
&buffer_size)) {
4435
return std::wstring();
4536
}
4637
std::wstring buffer(buffer_size, '\0');
47-
if (!GetThreadPreferredUILanguages(flags, &count, buffer.data(),
48-
&buffer_size)) {
38+
if (!windows_proc_table.GetThreadPreferredUILanguages(
39+
flags, &count, buffer.data(), &buffer_size)) {
4940
return std::wstring();
5041
}
5142
return buffer;
5243
}
5344

5445
std::vector<std::wstring> GetPreferredLanguages(
55-
const WindowsRegistry& registry) {
46+
const WindowsProcTable& windows_proc_table) {
5647
std::vector<std::wstring> languages;
57-
BOOL languages_from_registry = TRUE;
58-
ULONG buffer_size = 0;
59-
ULONG count = 0;
60-
DWORD flags = MUI_LANGUAGE_NAME | MUI_UI_FALLBACK;
61-
62-
// Determine where languages are defined and get buffer length
63-
if (registry.GetRegistryValue(HKEY_CURRENT_USER, kGetPreferredLanguageRegKey,
64-
kGetPreferredLanguageRegValue,
65-
RRF_RT_REG_MULTI_SZ, NULL, NULL,
66-
&buffer_size) != ERROR_SUCCESS) {
67-
languages_from_registry = FALSE;
68-
}
69-
70-
// Multi-string must be at least 3-long if non-empty,
71-
// as a multi-string is terminated with 2 nulls.
72-
//
73-
// See:
74-
// https://learn.microsoft.com/windows/win32/sysinfo/registry-value-types
75-
if (languages_from_registry && buffer_size < 3) {
76-
languages_from_registry = FALSE;
77-
}
7848

7949
// Initialize the buffer
80-
std::wstring buffer =
81-
languages_from_registry
82-
? GetPreferredLanguagesFromRegistry(registry, buffer_size)
83-
: GetPreferredLanguagesFromMUI();
50+
std::wstring buffer = GetPreferredLanguagesFromMUI(windows_proc_table);
8451

8552
// Extract the individual languages from the buffer.
8653
size_t start = 0;

shell/platform/windows/system_utils.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <string>
1111
#include <vector>
1212

13-
#include "flutter/shell/platform/windows/windows_registry.h"
13+
#include "flutter/shell/platform/windows/windows_proc_table.h"
1414

1515
namespace flutter {
1616

@@ -29,20 +29,17 @@ struct LanguageInfo {
2929
// Returns the list of user-preferred languages, in preference order,
3030
// parsed into LanguageInfo structures.
3131
std::vector<LanguageInfo> GetPreferredLanguageInfo(
32-
const WindowsRegistry& registry);
33-
34-
// Retrieve the preferred languages from the registry.
35-
std::wstring GetPreferredLanguagesFromRegistry(const WindowsRegistry& registry,
36-
ULONG buffer_size);
32+
const WindowsProcTable& windows_proc_table);
3733

3834
// Retrieve the preferred languages from the MUI API.
39-
std::wstring GetPreferredLanguagesFromMUI();
35+
std::wstring GetPreferredLanguagesFromMUI(
36+
const WindowsProcTable& windows_proc_table);
4037

4138
// Returns the list of user-preferred languages, in preference order.
4239
// The language names are as described at:
4340
// https://docs.microsoft.com/en-us/windows/win32/intl/language-names
4441
std::vector<std::wstring> GetPreferredLanguages(
45-
const WindowsRegistry& registry);
42+
const WindowsProcTable& windows_proc_table);
4643

4744
// Parses a Windows language name into its components.
4845
LanguageInfo ParseLanguageName(std::wstring language_name);

shell/platform/windows/system_utils_unittests.cc

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,47 @@
77

88
#include "flutter/fml/macros.h"
99
#include "flutter/shell/platform/windows/system_utils.h"
10+
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
1011
#include "gtest/gtest.h"
1112

1213
namespace flutter {
1314
namespace testing {
1415

15-
class MockWindowsRegistry : public WindowsRegistry {
16-
public:
17-
MockWindowsRegistry() = default;
18-
virtual ~MockWindowsRegistry() = default;
19-
20-
virtual LSTATUS GetRegistryValue(HKEY hkey,
21-
LPCWSTR key,
22-
LPCWSTR value,
23-
DWORD flags,
24-
LPDWORD type,
25-
PVOID data,
26-
LPDWORD data_size) const {
27-
using namespace std::string_literals;
28-
static const std::wstring locales =
29-
L"en-US\0zh-Hans-CN\0ja\0zh-Hant-TW\0he\0\0"s;
30-
static DWORD locales_len = locales.size() * sizeof(wchar_t);
31-
if (data != nullptr) {
32-
if (*data_size < locales_len) {
33-
return ERROR_MORE_DATA;
34-
}
35-
std::memcpy(data, locales.data(), locales_len);
36-
*data_size = locales_len;
37-
} else if (data_size != NULL) {
38-
*data_size = locales_len;
39-
}
40-
return ERROR_SUCCESS;
41-
}
42-
43-
private:
44-
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsRegistry);
45-
};
46-
4716
TEST(SystemUtils, GetPreferredLanguageInfo) {
48-
WindowsRegistry registry;
49-
std::vector<LanguageInfo> languages = GetPreferredLanguageInfo(registry);
17+
WindowsProcTable proc_table;
18+
std::vector<LanguageInfo> languages =
19+
GetPreferredLanguageInfo(WindowsProcTable());
5020
// There should be at least one language.
5121
ASSERT_GE(languages.size(), 1);
5222
// The info should have a valid languge.
5323
EXPECT_GE(languages[0].language.size(), 2);
5424
}
5525

5626
TEST(SystemUtils, GetPreferredLanguages) {
57-
WindowsRegistry registry;
58-
std::vector<std::wstring> languages = GetPreferredLanguages(registry);
27+
MockWindowsProcTable proc_table;
28+
ON_CALL(proc_table, GetThreadPreferredUILanguages)
29+
.WillByDefault(
30+
[](DWORD flags, PULONG count, PZZWSTR languages, PULONG size) {
31+
// Languages string ends in a double-null.
32+
static const wchar_t lang[] = L"en-US\0";
33+
static const size_t lang_len = sizeof(lang) / sizeof(wchar_t);
34+
static const int cnt = 1;
35+
if (languages == nullptr) {
36+
*size = lang_len;
37+
*count = cnt;
38+
} else if (*size >= lang_len) {
39+
memcpy(languages, lang, lang_len * sizeof(wchar_t));
40+
}
41+
return TRUE;
42+
});
43+
std::vector<std::wstring> languages = GetPreferredLanguages(proc_table);
5944
// There should be at least one language.
6045
ASSERT_GE(languages.size(), 1);
6146
// The language should be non-empty.
6247
EXPECT_FALSE(languages[0].empty());
6348
// There should not be a trailing null from the parsing step.
6449
EXPECT_EQ(languages[0].size(), wcslen(languages[0].c_str()));
65-
66-
// Test mock results
67-
MockWindowsRegistry mock_registry;
68-
languages = GetPreferredLanguages(mock_registry);
69-
ASSERT_EQ(languages.size(), 5);
70-
ASSERT_EQ(languages[0], std::wstring(L"en-US"));
71-
ASSERT_EQ(languages[1], std::wstring(L"zh-Hans-CN"));
72-
ASSERT_EQ(languages[2], std::wstring(L"ja"));
73-
ASSERT_EQ(languages[3], std::wstring(L"zh-Hant-TW"));
74-
ASSERT_EQ(languages[4], std::wstring(L"he"));
50+
EXPECT_EQ(languages[0], L"en-US");
7551
}
7652

7753
TEST(SystemUtils, ParseLanguageNameGeneric) {

shell/platform/windows/testing/mock_windows_proc_table.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class MockWindowsProcTable : public WindowsProcTable {
2121
MOCK_METHOD2(GetPointerType,
2222
BOOL(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type));
2323

24+
MOCK_CONST_METHOD4(GetThreadPreferredUILanguages,
25+
LRESULT(DWORD, PULONG, PZZWSTR, PULONG));
26+
2427
private:
2528
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable);
2629
};

shell/platform/windows/windows_proc_table.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ BOOL WindowsProcTable::GetPointerType(UINT32 pointer_id,
2525
return get_pointer_type_.value()(pointer_id, pointer_type);
2626
}
2727

28+
LRESULT WindowsProcTable::GetThreadPreferredUILanguages(DWORD flags,
29+
PULONG count,
30+
PZZWSTR languages,
31+
PULONG length) const {
32+
return ::GetThreadPreferredUILanguages(flags, count, languages, length);
33+
}
34+
2835
} // namespace flutter

shell/platform/windows/windows_proc_table.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
namespace flutter {
1414

1515
// Lookup table for Windows APIs that aren't available on all versions of
16-
// Windows.
16+
// Windows, or for mocking Windows API calls.
1717
class WindowsProcTable {
1818
public:
1919
WindowsProcTable();
@@ -26,6 +26,15 @@ class WindowsProcTable {
2626
virtual BOOL GetPointerType(UINT32 pointer_id,
2727
POINTER_INPUT_TYPE* pointer_type);
2828

29+
// Get the preferred languages for the thread, and optionally the process,
30+
// and system, in that order, depending on the flags.
31+
// See
32+
// https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-getthreadpreferreduilanguages
33+
virtual LRESULT GetThreadPreferredUILanguages(DWORD flags,
34+
PULONG count,
35+
PZZWSTR languages,
36+
PULONG length) const;
37+
2938
private:
3039
using GetPointerType_ = BOOL __stdcall(UINT32 pointerId,
3140
POINTER_INPUT_TYPE* pointerType);

0 commit comments

Comments
 (0)