From 92b5980a7e3e56020824679826d99d2ef8a0ac2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20K=C3=B6hne?= Date: Mon, 9 Dec 2024 15:59:10 +0100 Subject: [PATCH] Use ICU from Windows SDK for codec support (QStringConverter) Windows has shipped a (limited) subset of ICU for quite a while: https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu- The C API for this subset uses non-standard names for headers and lib though, and is therefore not picked up by the ICU configure logic in CMake. This patch adds a separate configure test that enables the use of this ICU API, specifically for text codec support in QStringConverter. If a 'proper' ICU is enabled by the user, this still takes precedence. Also, note that MinGW-w64 misses the respective Windows API, and will therefore still use the old fallback. [ChangeLog][QtCore][Text] Qt on Windows now uses the ICU API of the Windows SDK for text codec support (if available and no 'full' ICU is configured). This greatly enhances the list of supported text codecs available. Fixes: QTBUG-132056 Change-Id: Id02ae9f8cf56dee8c34795c0e60d2113f319bfd9 Reviewed-by: Fabian Kosmale Reviewed-by: Thiago Macieira --- src/corelib/CMakeLists.txt | 5 +++++ src/corelib/configure.cmake | 21 +++++++++++++++++++ src/corelib/global/qconfig-bootstrapped.h | 1 + src/corelib/text/qstringconverter.cpp | 18 +++++++++------- .../qstringconverter/tst_qstringconverter.cpp | 4 ++-- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index db037c732dc..bfd4e547063 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -871,6 +871,11 @@ qt_internal_extend_target(Core CONDITION WIN32 text/qlocale_win.cpp ) +qt_internal_extend_target(Core CONDITION QT_FEATURE_winsdkicu + LIBRARIES + icu +) + qt_internal_extend_target(Core CONDITION WASM SOURCES text/qlocale_wasm.cpp diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index d08cf8763d2..a4a89d35907 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -515,6 +515,21 @@ renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_NOREPLACE | RENAME_WHITEO } ") +qt_config_compile_test(winsdkicu + LABEL "Windows SDK: ICU" + LIBRARIES icu + CODE +"#include + +int main(void) +{ + /* BEGIN TEST: */ + /* END TEST: */ + return 0; +} +" +) + # cpp_winrt qt_config_compile_test(cpp_winrt LABEL "cpp/winrt" @@ -666,6 +681,12 @@ qt_feature("icu" PRIVATE AUTODETECT NOT WIN32 CONDITION ICU_FOUND ) +qt_feature("winsdkicu" PRIVATE + LABEL "ICU (Windows SDK)" + AUTODETECT WIN32 + CONDITION TEST_winsdkicu + DISABLE QT_FEATURE_icu +) qt_feature("inotify" PUBLIC PRIVATE LABEL "inotify" CONDITION TEST_inotify OR TEST_fsnotify diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index a087835fcba..e2dbf9e2e40 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -94,5 +94,6 @@ #define QT_NO_TRANSLATION #define QT_FEATURE_translation -1 #define QT_NO_VARIANT -1 +#define QT_FEATURE_winsdkicu -1 #endif // QT_BOOTSTRAPPED diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 694aea19c6b..894e5608f28 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -19,7 +19,11 @@ #include #include #include -#endif +#define QT_USE_ICU_CODECS +#elif QT_CONFIG(winsdkicu) +#include +#define QT_USE_ICU_CODECS +#endif // QT_CONFIG(icu) || QT_CONFIG(winsdkicu) #ifdef Q_OS_WIN #include @@ -1836,7 +1840,7 @@ void QStringConverter::State::clear() noexcept void QStringConverter::State::reset() noexcept { if (flags & Flag::UsesIcu) { -#if QT_CONFIG(icu) +#if defined(QT_USE_ICU_CODECS) UConverter *converter = static_cast(d[0]); if (converter) ucnv_reset(converter); @@ -2152,7 +2156,7 @@ static bool nameMatch(const char *a, QAnyStringView b) */ -#if QT_CONFIG(icu) +#if defined(QT_USE_ICU_CODECS) // only derives from QStringConverter to get access to protected types struct QStringConverterICU : QStringConverter { @@ -2418,7 +2422,7 @@ QStringConverter::QStringConverter(QAnyStringView name, Flags f) auto e = encodingForName(name); if (e) iface = encodingInterfaces + int(*e); -#if QT_CONFIG(icu) +#if defined(QT_USE_ICU_CODECS) else iface = QStringConverterICU::make_icu_converter(&state, name); #endif @@ -2430,7 +2434,7 @@ const char *QStringConverter::name() const noexcept if (!iface) return nullptr; if (state.flags & QStringConverter::Flag::UsesIcu) { -#if QT_CONFIG(icu) +#if defined(QT_USE_ICU_CODECS) return static_cast(state.d[1]); #else return nullptr; @@ -2610,7 +2614,7 @@ std::optional QStringConverter::encodingForHtml(QByt static qsizetype availableCodecCount() { -#if !QT_CONFIG(icu) +#if !defined(QT_USE_ICU_CODECS) return QStringConverter::Encoding::LastEncoding; #else /* icu contains also the names of what Qt provides @@ -2637,7 +2641,7 @@ QStringList QStringConverter::availableCodecs() { auto availableCodec = [](qsizetype index) -> QString { - #if !QT_CONFIG(icu) + #if !defined(QT_USE_ICU_CODECS) return QString::fromLatin1(encodingInterfaces[index].name); #else if (index == 0) // "Locale", not provided by icu diff --git a/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp b/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp index 342c343a423..7f646888434 100644 --- a/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp +++ b/tests/auto/corelib/text/qstringconverter/tst_qstringconverter.cpp @@ -151,7 +151,7 @@ private slots: void convertL1U16(); -#if QT_CONFIG(icu) +#if QT_CONFIG(icu) || QT_CONFIG(winsdkicu) void roundtripIcu_data(); void roundtripIcu(); void icuInvalidCharacter_data(); @@ -501,7 +501,7 @@ void tst_QStringConverter::convertL1U8() } } -#if QT_CONFIG(icu) +#if QT_CONFIG(icu) || QT_CONFIG(winsdkicu) void tst_QStringConverter::roundtripIcu_data() {