diff options
-rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
-rwxr-xr-x | gtk/PlatGTK.cxx | 41 |
2 files changed, 37 insertions, 8 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index b8a1ad66b..bf0254cbc 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -589,6 +589,10 @@ <a href="https://sourceforge.net/p/scintilla/bugs/2335/">Bug #2335</a>. </li> <li> + Fix failures on GTK with non-UTF-8 text when multi-threading due to + character set conversion code that was not thread-safe. + </li> + <li> Fix crash when printing on Win32 in bidirectional mode with a non-empty selection. </li> </ul> diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index 87c57abcd..e73e4678d 100755 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -896,14 +896,34 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI PLATFORM_ASSERT(static_cast<size_t>(i) == text.length()); } else { int positionsCalculated = 0; + const char *charSetID = CharacterSetID(PFont(font_)->characterSet); + std::string utfForm; + { + gsize bytesRead = 0; + gsize bytesWritten = 0; + GError *error = nullptr; + UniqueStr textInUTF8(g_convert(text.data(), text.length(), + "UTF-8", charSetID, + &bytesRead, + &bytesWritten, + &error)); + if ((bytesWritten > 0) && (bytesRead == text.length()) && !error) { + // Extra allocation here but avoiding it makes code more complex + utfForm.assign(textInUTF8.get(), bytesWritten); + } + if (error) { +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: %s.\n", error->message); +#endif + g_error_free(error); + } + } if (et == EncodingType::dbcs) { - SetConverter(PFont(font_)->characterSet); - std::string utfForm = UTF8FromIconv(conv, text); if (!utfForm.empty()) { // Convert to UTF-8 so can ask Pango for widths, then // Loop through UTF-8 and DBCS forms, taking account of different // character byte lengths. - Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); + Converter convMeasure("UCS-2", charSetID, false); int i = 0; ClusterIterator iti(layoutMeasure.get(), utfForm); int clusterStart = iti.curIndex; @@ -915,7 +935,7 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; - const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); + const int places = g_utf8_strlen(utfForm.data() + clusterStart, clusterEnd - clusterStart); int place = 1; while (clusterStart < clusterEnd) { size_t lenChar = MultiByteLenFromIconv(convMeasure, text.data()+i, text.length()-i); @@ -933,12 +953,13 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI if (positionsCalculated < 1) { const size_t lenPositions = text.length(); // Either 8-bit or DBCS conversion failed so treat as 8-bit. - SetConverter(PFont(font_)->characterSet); const bool rtlCheck = PFont(font_)->characterSet == CharacterSet::Hebrew || PFont(font_)->characterSet == CharacterSet::Arabic; - std::string utfForm = UTF8FromIconv(conv, text); if (utfForm.empty()) { utfForm = UTF8FromLatin1(text); +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: Fall back to Latin1 [%s]\n", utfForm.c_str()); +#endif } size_t i = 0; // Each 8-bit input character may take 1 or 2 bytes in UTF-8 @@ -953,9 +974,13 @@ void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSI while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; - const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); - if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) { + const int ligatureLength = g_utf8_strlen(utfForm.data() + clusterStart, clusterEnd - clusterStart); + if (((i + ligatureLength) > lenPositions) || + (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3)))) { // Something has gone wrong: exit quickly but pretend all the characters are equally spaced: +#ifdef DEBUG + fprintf(stderr, "MeasureWidths: result too long.\n"); +#endif EquallySpaced(layoutMeasure.get(), positions, lenPositions); return; } |