diff options
author | Michele Calgaro <[email protected]> | 2025-01-30 23:40:14 +0900 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2025-02-13 22:39:51 +0900 |
commit | 67cb0f6762768ee0d32adef1d7307ff7bb985407 (patch) | |
tree | 9c391724f3eae5ba2b8279ea9de6245a1f44d25b | |
parent | fd79f0c8b020ff0c60b62c83745beb030ef38997 (diff) | |
download | tqt3-67cb0f6762768ee0d32adef1d7307ff7bb985407.tar.gz tqt3-67cb0f6762768ee0d32adef1d7307ff7bb985407.zip |
Fix editing of text containing surrogate characters.r14.1.x
This relates to issue #162.
Signed-off-by: Michele Calgaro <[email protected]>
(cherry picked from commit 9c648bea9bfb1113c070a05b36f78ff006d0877a)
-rw-r--r-- | doc/html/qfontmetrics-h.html | 2 | ||||
-rw-r--r-- | src/kernel/qrichtext.cpp | 33 | ||||
-rw-r--r-- | src/kernel/qrichtext_p.cpp | 12 | ||||
-rw-r--r-- | src/widgets/qlineedit.cpp | 14 | ||||
-rw-r--r-- | src/widgets/qtextedit.cpp | 16 |
5 files changed, 60 insertions, 17 deletions
diff --git a/doc/html/qfontmetrics-h.html b/doc/html/qfontmetrics-h.html index f034b77f5..a9a6f6e58 100644 --- a/doc/html/qfontmetrics-h.html +++ b/doc/html/qfontmetrics-h.html @@ -119,7 +119,7 @@ public: int width( char c ) const { return width( (TQChar) c ); } #endif - int charWidth( const TQString &str, int pos ) const; + int charWidth( const TQString &str, int pos ) const; TQRect boundingRect( const TQString &, int len = -1 ) const; TQRect boundingRect( TQChar ) const; TQRect boundingRect( int x, int y, int w, int h, int flags, diff --git a/src/kernel/qrichtext.cpp b/src/kernel/qrichtext.cpp index 4609a340b..6f09cc185 100644 --- a/src/kernel/qrichtext.cpp +++ b/src/kernel/qrichtext.cpp @@ -221,12 +221,19 @@ TQTextCursor *TQTextDeleteCommand::execute( TQTextCursor *c ) cursor.setParagraph( s ); cursor.setIndex( index ); int len = text.size(); + if ( c ) *c = cursor; if ( doc ) { doc->setSelectionStart( TQTextDocument::Temp, cursor ); for ( int i = 0; i < len; ++i ) + { + if (text[i].c.isHighSurrogate() && i < (len - 1) && text[i + 1].c.isLowSurrogate()) + { + ++i; // This is required for correct advancement when handling surrogate pairs + } cursor.gotoNextLetter(); + } doc->setSelectionEnd( TQTextDocument::Temp, cursor ); doc->removeSelectedText( TQTextDocument::Temp, &cursor ); if ( c ) @@ -1250,9 +1257,17 @@ bool TQTextCursor::removePreviousChar() { tmpX = -1; if ( !atParagStart() ) { - para->remove( idx-1, 1 ); + if (para->at(idx - 1)->c.isLowSurrogate() && idx > 1 && para->at(idx - 2)->c.isHighSurrogate()) + { + para->remove(idx - 2, 2); + idx -= 2; + } + else + { + para->remove(idx - 1, 1); + idx--; + } int h = para->rect().height(); - idx--; // shouldn't be needed, just to make sure. fixCursorPosition(); para->format( -1, TRUE ); @@ -4009,6 +4024,7 @@ int TQTextString::width( int idx ) const { int w = 0; TQTextStringChar *c = &at( idx ); + // '!c->charStop' already takes care of low surrogate chars if ( !c->charStop || c->c.unicode() == 0xad || c->c.unicode() == 0x2028 ) return 0; #ifndef TQT_NO_TEXTCUSTOMITEM @@ -4292,10 +4308,10 @@ void TQTextParagraph::format( int start, bool doMove ) if ( !str || str->length() == 0 || !formatter() ) return; - if ( hasdoc && - document()->preProcessor() && - ( needPreProcess || state == -1 ) ) + if ( hasdoc && document()->preProcessor() && ( needPreProcess || state == -1 ) ) + { document()->preProcessor()->process( document(), this, invalid <= 0 ? 0 : invalid ); + } needPreProcess = FALSE; if ( invalid == -1 ) @@ -5784,6 +5800,7 @@ int TQTextFormatterBreakWords::format( TQTextDocument *doc, TQTextParagraph *par lastChr = c->c; lastFormat = c->format(); } + bool lastWasOwnLineCustomItem = lastBreak == -2; bool hadBreakableChar = lastBreak != -1; bool lastWasHardBreak = lastChr == TQChar_linesep; @@ -5793,6 +5810,12 @@ int TQTextFormatterBreakWords::format( TQTextDocument *doc, TQTextParagraph *par c->format()->setPainter( painter ); c = &string->at( i ); + // Skip over low surrogate chars + if (c->c.isLowSurrogate()) + { + continue; + } + if (lastFormat != c->format() && !c->c.isSpace() && lastFormat->font().italic() && !c->format()->font().italic()) { int rb = lastFormat->fontMetrics().rightBearing(lastChr); diff --git a/src/kernel/qrichtext_p.cpp b/src/kernel/qrichtext_p.cpp index 022eb13de..5a6eca7cf 100644 --- a/src/kernel/qrichtext_p.cpp +++ b/src/kernel/qrichtext_p.cpp @@ -114,15 +114,15 @@ int TQTextCursor::x() const return 0; TQTextStringChar *c = para->at( idx ); int curx = c->x; - if ( !c->rightToLeft && - c->c.isSpace() && - idx > 0 && - para->at( idx - 1 )->c != '\t' && - !c->lineStart && - ( para->alignment() & TQt::AlignJustify ) == TQt::AlignJustify ) + if ( !c->rightToLeft && c->c.isSpace() && idx > 0 && para->at( idx - 1 )->c != '\t' && + !c->lineStart && ( para->alignment() & TQt::AlignJustify ) == TQt::AlignJustify ) + { curx = para->at( idx - 1 )->x + para->string()->width( idx - 1 ); + } if ( c->rightToLeft ) + { curx += para->string()->width( idx ); + } return curx; } diff --git a/src/widgets/qlineedit.cpp b/src/widgets/qlineedit.cpp index bcf9b2d0d..eba3f6b20 100644 --- a/src/widgets/qlineedit.cpp +++ b/src/widgets/qlineedit.cpp @@ -877,10 +877,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 ); } diff --git a/src/widgets/qtextedit.cpp b/src/widgets/qtextedit.cpp index bac58af15..73e800be8 100644 --- a/src/widgets/qtextedit.cpp +++ b/src/widgets/qtextedit.cpp @@ -1783,8 +1783,20 @@ void TQTextEdit::doKeyboardAction( KeyboardAction action ) undoRedoInfo.index = cursor->index(); undoRedoInfo.d->text = TQString::null; } - undoRedoInfo.d->text.insert( 0, cursor->paragraph()->at( cursor->index()-1 ), TRUE ); - undoRedoInfo.index = cursor->index()-1; + int cur_idx = cursor->index(); + const TQTextParagraph *para = cursor->paragraph(); + if (para->at(cur_idx - 1)->c.isLowSurrogate() && cur_idx > 1 && + para->at(cur_idx - 2)->c.isHighSurrogate()) + { + undoRedoInfo.d->text.insert( 0, para->at(cur_idx - 1), TRUE ); + undoRedoInfo.d->text.insert( 0, para->at(cur_idx - 2), TRUE ); + undoRedoInfo.index = cursor->index() - 2; + } + else + { + undoRedoInfo.d->text.insert( 0, para->at(cur_idx - 1), TRUE ); + undoRedoInfo.index = cursor->index() - 1; + } } cursor->removePreviousChar(); lastFormatted = cursor->paragraph(); |