Skip to content

Commit

Permalink
Fixed the problem with characters like '⧸' (U+29F8) (#565)
Browse files Browse the repository at this point in the history
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 lxqt/qterminal#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.
  • Loading branch information
tsujan authored Nov 25, 2024
1 parent df7297b commit 0c06598
Showing 1 changed file with 22 additions and 9 deletions.
31 changes: 22 additions & 9 deletions lib/TerminalDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 0c06598

Please sign in to comment.