summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichele Calgaro <[email protected]>2025-01-30 23:40:14 +0900
committerMichele Calgaro <[email protected]>2025-01-30 23:40:14 +0900
commit7cfbc48c37f3289a5437c63c05ce614024b3f70c (patch)
treeb2e8b1afb2524ce72c2103e203e91f43a5a8c1cc
parentc5cda03125a6d34c179d968011083bceb87976bd (diff)
downloadtqt3-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.cpp21
-rw-r--r--src/kernel/tqtextengine.cpp107
-rw-r--r--src/widgets/tqlineedit.cpp14
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 );
}