From 0c065980fa64cbf41cc040980020fe1db6bde589 Mon Sep 17 00:00:00 2001 From: tsujan Date: Mon, 25 Nov 2024 23:48:45 +0330 Subject: [PATCH] =?UTF-8?q?Fixed=20the=20problem=20with=20characters=20lik?= =?UTF-8?q?e=20'=E2=A7=B8'=20(U+29F8)=20(#565)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As Qt explains in https://doc.qt.io/qt-6/qfont.html#StyleStrategy-enum, "if the font selected for a certain writing system does not contain a character requested to draw, then Qt automatically chooses a similar looking font that contains the character." This caused a problem for us because the width of the replacing character might be smaller than the monospace width, while the code expected the same width. The patch fixes the issue by checking the width and adding simple conditions if it's smaller than expected. To test it, you could use a string like `aabb⧸aabb⧸aabb⧸aabb⧸aabb` ('⧸' is *not* an ordinary slash). Previously, the characters were moved on making selections or moving the text cursor. Fixes https://github.com/lxqt/qterminal/issues/1186 NOTE: There is still a rare issue with another kind of character that isn't related to this PR. I might investigate it later. --- lib/TerminalDisplay.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/TerminalDisplay.cpp b/lib/TerminalDisplay.cpp index ee1982b3..2e6dd3f8 100644 --- a/lib/TerminalDisplay.cpp +++ b/lib/TerminalDisplay.cpp @@ -1145,6 +1145,7 @@ void TerminalDisplay::updateImage() } } + QFontMetrics fm(font()); if (!_resizing) // not while _resizing, we're expecting a paintEvent for (x = 0; x < columnsToUpdate; ++x) { @@ -1164,6 +1165,7 @@ void TerminalDisplay::updateImage() disstrU[p++] = c; //fontMap(c); bool lineDraw = isLineChar(c); bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0); + bool smallWidth = fm.horizontalAdvance(QChar(c)) < _fontWidth; cr = newLine[x].rendition; _clipboard = newLine[x].backgroundColor; if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor; @@ -1176,14 +1178,20 @@ void TerminalDisplay::updateImage() continue; // Skip trailing part of multi-col chars. bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0); - - if ( ch.foregroundColor != cf || - ch.backgroundColor != _clipboard || - ch.rendition != cr || - !dirtyMask[x+len] || - isLineChar(c) != lineDraw || - nextIsDoubleWidth != doubleWidth ) - break; + bool nextIsSmallWidth = newLine[x+len].character + ? fm.horizontalAdvance(QChar(newLine[x+len].character)) < _fontWidth + : false; + + if (ch.foregroundColor != cf || + ch.backgroundColor != _clipboard || + ch.rendition != cr || + !dirtyMask[x+len] || + isLineChar(c) != lineDraw || + nextIsDoubleWidth != doubleWidth || + smallWidth || nextIsSmallWidth) + { + break; + } disstrU[p++] = c; //fontMap(c); } @@ -1648,6 +1656,7 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) int rlx = qMin(_usedColumns-1, qMax(0,(rect.right() - tLx - _leftMargin ) / _fontWidth)); int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight)); + QFontMetrics fm(font()); const int bufferSize = _usedColumns; std::wstring unistr; unistr.reserve(bufferSize); @@ -1691,16 +1700,20 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) bool lineDraw = isLineChar(c); bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0); + bool smallWidth = c ? fm.horizontalAdvance(QChar(c)) < _fontWidth : false; CharacterColor currentForeground = _image[loc(x,y)].foregroundColor; CharacterColor currentBackground = _image[loc(x,y)].backgroundColor; quint8 currentRendition = _image[loc(x,y)].rendition; + quint32 nxtC; while (x+len <= rlx && _image[loc(x+len,y)].foregroundColor == currentForeground && _image[loc(x+len,y)].backgroundColor == currentBackground && _image[loc(x+len,y)].rendition == currentRendition && (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth && - isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment! + !smallWidth && + !((nxtC = _image[loc(x+len,y)].character) && fm.horizontalAdvance(QChar(nxtC)) < _fontWidth) && + isLineChar(c = _image[loc(x+len,y)].character) == lineDraw) // Assignment! { if (c) unistr[p++] = c; //fontMap(c);