diff options
author | Michele Calgaro <[email protected]> | 2025-01-30 23:40:14 +0900 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2025-01-30 23:40:14 +0900 |
commit | 7cfbc48c37f3289a5437c63c05ce614024b3f70c (patch) | |
tree | b2e8b1afb2524ce72c2103e203e91f43a5a8c1cc | |
parent | c5cda03125a6d34c179d968011083bceb87976bd (diff) | |
download | tqt3-fix/unicode-editing.tar.gz tqt3-fix/unicode-editing.zip |
Fix editing of text containing surrogate characters.fix/unicode-editing
This relates to issue #162.
Signed-off-by: Michele Calgaro <[email protected]>
-rw-r--r-- | src/kernel/tqscriptengine.cpp | 21 | ||||
-rw-r--r-- | src/kernel/tqtextengine.cpp | 107 | ||||
-rw-r--r-- | src/widgets/tqlineedit.cpp | 14 |
3 files changed, 83 insertions, 59 deletions
diff --git a/src/kernel/tqscriptengine.cpp b/src/kernel/tqscriptengine.cpp index 588596716..ff05d123b 100644 --- a/src/kernel/tqscriptengine.cpp +++ b/src/kernel/tqscriptengine.cpp @@ -288,10 +288,21 @@ static void heuristicSetGlyphAttributes(TQShaperItem *item, const TQChar *uc, in Q_ASSERT(item->num_glyphs <= length); unsigned short *logClusters = item->log_clusters; - - int i; - for (i = 0; i < length; ++i) - logClusters[i] = i; + int glyph_pos = 0; + for (int i = 0; i < length; i++) + { + if (uc[i].isHighSurrogate() && i < (length - 1) && uc[i+1].isLowSurrogate()) + { + logClusters[i] = glyph_pos; + logClusters[++i] = glyph_pos; + } + else + { + logClusters[i] = glyph_pos; + } + ++glyph_pos; + } + Q_ASSERT(glyph_pos == item->num_glyphs); // first char in a run is never (treated as) a mark int cStart = 0; @@ -307,7 +318,7 @@ static void heuristicSetGlyphAttributes(TQShaperItem *item, const TQChar *uc, in } int lastCat = ::category(uc[0]); - for (i = 1; i < length; ++i) { + for (int i = 1; i < length; ++i) { int cat = ::category(uc[i]); if (qIsZeroWidthChar(uc[i].unicode())) { item->attributes[i].mark = FALSE; diff --git a/src/kernel/tqtextengine.cpp b/src/kernel/tqtextengine.cpp index 05cdbcc13..5fbf306ab 100644 --- a/src/kernel/tqtextengine.cpp +++ b/src/kernel/tqtextengine.cpp @@ -800,72 +800,77 @@ static void calcLineBreaks(const TQString &str, TQCharAttributes *charAttributes { int len = str.length(); if (!len) - return; + return; const TQChar *uc = str.unicode(); int cls = lineBreakClass(*uc); if (cls >= TQUnicodeTables::LineBreak_CM) - cls = TQUnicodeTables::LineBreak_ID; + cls = TQUnicodeTables::LineBreak_ID; charAttributes[0].softBreak = FALSE; charAttributes[0].whiteSpace = (cls == TQUnicodeTables::LineBreak_SP); charAttributes[0].charStop = TRUE; - for (int i = 1; i < len; ++i) { - int ncls = ::lineBreakClass(uc[i]); - int category = ::category(uc[i]); - if (category == TQChar::Mark_NonSpacing) - goto nsm; - - if (category == TQChar::Other_Surrogate) { - // char stop only on first pair - if (uc[i].isHighSurrogate() && i < (len - 1) && uc[i + 1].isLowSurrogate()) - goto nsm; - // ### correctly handle second surrogate - } - - if (ncls == TQUnicodeTables::LineBreak_SP) { - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = TRUE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } + bool prevIsHighSurrogate = uc[0].isHighSurrogate(); + for (int i = 1; i < len; ++i) + { + // Don't stop on low surrogate characters of complete valid pairs + if (prevIsHighSurrogate && uc[i].isLowSurrogate()) + { + prevIsHighSurrogate = false; + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = FALSE; + continue; + } + prevIsHighSurrogate = uc[i].isHighSurrogate(); + int ncls = ::lineBreakClass(uc[i]); + int category = ::category(uc[i]); + if (category == TQChar::Mark_NonSpacing) + { + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = FALSE; + continue; + } - if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) { - // two complex chars (thai or lao), thai_attributes might override, but here - // we do a best guess - charAttributes[i].softBreak = TRUE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } - { - int tcls = ncls; - if (tcls >= TQUnicodeTables::LineBreak_SA) - tcls = TQUnicodeTables::LineBreak_ID; - if (cls >= TQUnicodeTables::LineBreak_SA) - cls = TQUnicodeTables::LineBreak_ID; - - bool softBreak; - int brk = breakTable[cls][tcls]; - if (brk == Ibk) - softBreak = (cls == TQUnicodeTables::LineBreak_SP); - else - softBreak = (brk == Dbk); -// tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); - charAttributes[i].softBreak = softBreak; + if (ncls == TQUnicodeTables::LineBreak_SP) { + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = TRUE; + charAttributes[i].charStop = TRUE; + cls = ncls; + continue; + } + + if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) + { + // two complex chars (thai or lao), thai_attributes might override, but here + // we do a best guess + charAttributes[i].softBreak = TRUE; charAttributes[i].whiteSpace = FALSE; charAttributes[i].charStop = TRUE; cls = ncls; + continue; } - continue; - nsm: - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = FALSE; + + int tcls = ncls; + if (tcls >= TQUnicodeTables::LineBreak_SA) + tcls = TQUnicodeTables::LineBreak_ID; + if (cls >= TQUnicodeTables::LineBreak_SA) + cls = TQUnicodeTables::LineBreak_ID; + + bool softBreak; + int brk = breakTable[cls][tcls]; + if (brk == Ibk) + softBreak = (cls == TQUnicodeTables::LineBreak_SP); + else + softBreak = (brk == Dbk); + // tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); + charAttributes[i].softBreak = softBreak; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = TRUE; + cls = ncls; } } diff --git a/src/widgets/tqlineedit.cpp b/src/widgets/tqlineedit.cpp index 2267706d4..94cc54bc8 100644 --- a/src/widgets/tqlineedit.cpp +++ b/src/widgets/tqlineedit.cpp @@ -860,10 +860,18 @@ void TQLineEdit::backspace() if ( d->hasSelectedText() ) { d->removeSelectedText(); } else if ( d->cursor ) { + --d->cursor; + if ( d->maskData ) { + d->cursor = d->prevMaskBlank( d->cursor ); + } + // second half of a surrogate, check if we have the first half as well, + // if yes delete both at once + if (d->cursor > 0 && d->text.at(d->cursor).isLowSurrogate() && + d->text.at(d->cursor - 1).isHighSurrogate()) { + d->del(true); --d->cursor; - if ( d->maskData ) - d->cursor = d->prevMaskBlank( d->cursor ); - d->del( TRUE ); + } + d->del(true); } d->finishChange( priorState ); } |