From a565bc97337a3bfc3a027f46aa2dec3e9a6f8618 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Mon, 2 Apr 2018 11:37:19 -0400 Subject: [PATCH] Clip character drawing to its own cell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: To calculate string width, Konsole uses character cell widths. Rendering engine uses actual characters widths for this purpose. Those sizes are equal in fixed-width fonts, as long as the font has specific character. Since no font contains all Unicode characters, some of them are taken from different fonts and their sizes differ from their cell size. This can lead to different results depending on how text line is split into strings. It can be assumed that characters in Basic Latin block in every fixed-width font are really fixed-width, and can be rendered as one string. All other characters are rendered separately, and their rendering surface is limited to their cell. Before/After screenshots: {F5749612} BUG: 361547 Test Plan: Paste this: `⸻test` in konsole and highlight different parts of the string In a text editor paste this: ``` | A | | ⸻ | | ⟹ | | ⧠ | ``` and move cursor vertically through characters column Reviewers: #konsole, hindenburg Reviewed By: #konsole, hindenburg Subscribers: hindenburg, ngraham, #konsole Tags: #konsole Differential Revision: https://phabricator.kde.org/D11237 --- src/TerminalDisplay.cpp | 61 ++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp index ad0d1c0f..0caa3997 100644 --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -940,11 +940,13 @@ void TerminalDisplay::drawCharacters(QPainter& painter, // This still allows RTL characters to be rendered in the RTL way. painter.setLayoutDirection(Qt::LeftToRight); + painter.setClipRect(rect); if (_bidiEnabled) { painter.drawText(rect.x(), rect.y() + _fontAscent + _lineSpacing, text); } else { painter.drawText(rect.x(), rect.y() + _fontAscent + _lineSpacing, LTR_OVERRIDE_CHAR + text); } + painter.setClipping(false); } } @@ -1631,39 +1633,42 @@ void TerminalDisplay::drawContents(QPainter& paint, const QRect& rect) const CharacterColor currentBackground = _image[loc(x, y)].backgroundColor; const RenditionFlags currentRendition = _image[loc(x, y)].rendition; - while (x + len <= rlx && - _image[loc(x + len, y)].foregroundColor == currentForeground && - _image[loc(x + len, y)].backgroundColor == currentBackground && - (_image[loc(x + len, y)].rendition & ~RE_EXTENDED_CHAR) == (currentRendition & ~RE_EXTENDED_CHAR) && - (_image[ qMin(loc(x + len, y) + 1, _imageSize) ].character == 0) == doubleWidth && - _image[loc(x + len, y)].isLineChar() == lineDraw) { - const quint16 c = _image[loc(x + len, y)].character; - if ((_image[loc(x + len, y)].rendition & RE_EXTENDED_CHAR) != 0) { - // sequence of characters - ushort extendedCharLength = 0; - const ushort* chars = ExtendedCharTable::instance.lookupExtendedChar(c, extendedCharLength); - if (chars != nullptr) { - Q_ASSERT(extendedCharLength > 1); - bufferSize += extendedCharLength - 1; - unistr.resize(bufferSize); - disstrU = unistr.data(); - for (int index = 0 ; index < extendedCharLength ; index++) { + if(_image[loc(x, y)].character <= 0x7e) { + while (x + len <= rlx && + _image[loc(x + len, y)].foregroundColor == currentForeground && + _image[loc(x + len, y)].backgroundColor == currentBackground && + (_image[loc(x + len, y)].rendition & ~RE_EXTENDED_CHAR) == (currentRendition & ~RE_EXTENDED_CHAR) && + (_image[ qMin(loc(x + len, y) + 1, _imageSize) ].character == 0) == doubleWidth && + _image[loc(x + len, y)].isLineChar() == lineDraw && + _image[loc(x + len, y)].character <= 0x7e) { + const quint16 c = _image[loc(x + len, y)].character; + if ((_image[loc(x + len, y)].rendition & RE_EXTENDED_CHAR) != 0) { + // sequence of characters + ushort extendedCharLength = 0; + const ushort* chars = ExtendedCharTable::instance.lookupExtendedChar(c, extendedCharLength); + if (chars != nullptr) { + Q_ASSERT(extendedCharLength > 1); + bufferSize += extendedCharLength - 1; + unistr.resize(bufferSize); + disstrU = unistr.data(); + for (int index = 0 ; index < extendedCharLength ; index++) { + Q_ASSERT(p < bufferSize); + disstrU[p++] = chars[index]; + } + } + } else { + // single character + if (c != 0u) { Q_ASSERT(p < bufferSize); - disstrU[p++] = chars[index]; + disstrU[p++] = c; //fontMap(c); } } - } else { - // single character - if (c != 0u) { - Q_ASSERT(p < bufferSize); - disstrU[p++] = c; //fontMap(c); - } - } - if (doubleWidth) { // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition - len++; // Skip trailing part of multi-column character + if (doubleWidth) { // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition + len++; // Skip trailing part of multi-column character + } + len++; } - len++; } if ((x + len < _usedColumns) && (_image[loc(x + len, y)].character == 0u)) { len++; // Adjust for trailing part of multi-column character