From 19ca03c21c2cf69fdec4dd8d6a03b92eb96314ca Mon Sep 17 00:00:00 2001 From: Ievgenii Meshcheriakov Date: Mon, 9 Jan 2023 16:04:36 +0100 Subject: QUnicodeTools: Use thread-safe libthai API Use th_brk_new()/th_brk_find_breaks() instead of non-thread-safe th_brk(). The new API is available in libthai since version 0.1.25 released on 2016-06-28. [ChangeLog][QtCore] Correct line wrapping of Thai text now requires libthai version 0.1.25 or above. Fixes: QTBUG-105544 Pick-to: 6.5 Change-Id: I723050bef9f4e6445c946125c74c99e50addadef Reviewed-by: Qt CI Bot Reviewed-by: Marc Mutz --- src/corelib/text/qunicodetools.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/corelib/text/qunicodetools.cpp b/src/corelib/text/qunicodetools.cpp index 32e791563f..4e6215e872 100644 --- a/src/corelib/text/qunicodetools.cpp +++ b/src/corelib/text/qunicodetools.cpp @@ -1402,11 +1402,19 @@ struct thcell_t { unsigned char hilo; /**< upper/lower vowel/diacritic */ unsigned char top; /**< top-level mark */ }; -typedef int (*th_brk_def) (const unsigned char*, int*, size_t); +typedef struct _ThBrk ThBrk; +typedef ThBrk *(*th_brk_new_def)(const char *); +typedef int (*th_brk_find_breaks_def)(ThBrk *, const unsigned char *, int *, size_t); typedef size_t (*th_next_cell_def) (const unsigned char *, size_t, struct thcell_t *, int); +// Global state for th_brk_find_breaks(). +// Note: even if signature for th_brk_find_breaks() suggests otherwise, the +// state is read-only, and so it is safe to use it from multiple threads after +// initialization. This is also stated in the libthai documentation. +Q_CONSTINIT static ThBrk *th_state = nullptr; + /* libthai related function handles */ -Q_CONSTINIT static th_brk_def th_brk = nullptr; +Q_CONSTINIT static th_brk_find_breaks_def th_brk_find_breaks = nullptr; Q_CONSTINIT static th_next_cell_def th_next_cell = nullptr; static int init_libthai() { @@ -1416,12 +1424,19 @@ static int init_libthai() { if (!initialized.loadAcquire()) { const auto locker = std::scoped_lock(mutex); if (!initialized.loadAcquire()) { - th_brk = reinterpret_cast(QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_brk")); + th_brk_find_breaks = reinterpret_cast( + QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_brk_find_breaks")); th_next_cell = (th_next_cell_def)QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_next_cell"); + + auto th_brk_new = reinterpret_cast( + QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_brk_new")); + if (th_brk_new) + th_state = th_brk_new(nullptr); + initialized.storeRelease(true); } } - if (th_brk && th_next_cell) + if (th_brk_find_breaks && th_next_cell && th_state) return 1; else #endif @@ -1487,7 +1502,8 @@ static void thaiAssignAttributes(const char16_t *string, qsizetype len, QCharAtt attributes[0].wordBreak = true; attributes[0].wordStart = true; attributes[0].wordEnd = false; - numbreaks = th_brk(reinterpret_cast(cstr), break_positions, brp_size); + numbreaks = th_brk_find_breaks(th_state, reinterpret_cast(cstr), + break_positions, brp_size); for (i = 0; i < numbreaks; ++i) { attributes[break_positions[i]].wordBreak = true; attributes[break_positions[i]].wordStart = true; -- cgit v1.2.3