aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/ScintillaHistory.html4
-rwxr-xr-xgtk/PlatGTK.cxx41
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;
}