Commit 76f879cd authored by Matan Ziv-Av's avatar Matan Ziv-Av Committed by Kurt Hindenburg
Browse files

Draw characters in exact positions

QT can't be made to draw monospaced text (if the font does not cooperate),
so avoid combining characters, using a QPainter::drawText() call for each
character.

For bidi text support this change requires konsole to reorder and reshape
the characters. This is done using the ICU library (which QT also uses).

This change allows for some improvements related to text rendering:

- More precise bidi reordering, which is no longer changed by characters'
  attributes and selection.
- underlines drawn separately from the text, allowing for differing
  underline modes (double, curly, dashed, dotted, colored).
- Overriding font for emoji characters.

This commit fixes a few bugs and addresses a lot more:

Feature requests: More standard conforming RTL and various underlines:
BUG: 403729
BUG: 387811

Using non-monospace font:
BUG: 416508
BUG: 452087
BUG: 425973
BUG: 430822
BUG: 442742
BUG: 441037
BUG: 430822



Emoji:
BUG: 440070
CCBUG: 450017
CCBUG: 445846
CCBUG: 453086

Regression: devanagari rendering
CCBUG: 381593
CCBUG: 451716
parent 4e875cdf
......@@ -102,6 +102,8 @@ set_package_properties(KF5DocTools PROPERTIES DESCRIPTION
TYPE OPTIONAL
)
find_package(ICU 61.0 COMPONENTS uc i18n REQUIRED)
if(NOT APPLE)
option(WITHOUT_X11 "Build without X11 integration (skips finding X11)" OFF)
if (NOT WITHOUT_X11)
......
......@@ -92,6 +92,7 @@ add_library(konsoleprivate_core STATIC ${konsoleprivate_core_SRCS})
# Needed to link this static lib to shared libs
set_target_properties(konsoleprivate_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(konsoleprivate_core ${konsole_LIBS})
target_link_libraries(konsoleprivate_core ICU::uc ICU::i18n)
set(konsolehelpers_SRCS
LabelsAligner.cpp
......
......@@ -17,45 +17,62 @@
using namespace Konsole;
FontDialog::FontDialog(QWidget *parent)
FontDialog::FontDialog(QWidget *parent, bool emoji, const QFont font)
: QDialog(parent)
, _fontChooser(nullptr)
, _showAllFonts(nullptr)
, _buttonBox(nullptr)
, _emoji(emoji)
{
setWindowTitle(i18nc("@title:window", "Select font"));
KFontChooser::DisplayFlag onlyFixed = _emoji ? KFontChooser::FixedFontsOnly : KFontChooser::FixedFontsOnly;
#if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 86, 0)
_fontChooser = new KFontChooser(KFontChooser::FixedFontsOnly, this);
_fontChooser = new KFontChooser(onlyFixed, this);
if (_emoji) {
QStringList list = KFontChooser::createFontList(0).filter(QStringLiteral("emoji"), Qt::CaseInsensitive);
_fontChooser->setFont(font);
_fontChooser->setFontListItems(KFontChooser::createFontList(0).filter(QStringLiteral("emoji"), Qt::CaseInsensitive));
_fontChooser->setFont(font);
}
#else
_fontChooser = new KFontChooser(this, KFontChooser::FixedFontsOnly);
_fontChooser = new KFontChooser(this, onlyFixed);
#endif
_showAllFonts = new QCheckBox(i18nc("@action:button", "Show all fonts"), this);
_showAllFontsWarningButton = new QToolButton(this);
_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
_fontChooser->setSampleText(
QStringLiteral("0OQ 1Il!| 5S 8B rnm :; ,. \"'` ~-= ({[<>]})\n"
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\n"
"abcdefghijklmnopqrstuvwxyz"));
_showAllFontsWarningButton->setIcon(QIcon::fromTheme(QStringLiteral("emblem-warning")));
_showAllFontsWarningButton->setAutoRaise(true);
if (_emoji) {
_fontChooser->setSampleText(
/* clang-format off */
QStringLiteral(" 🏴🤘🚬🌍🌎🌏🥆💣🗡🔫⚗️⚛️☢️☣️🌿🎱🏧💉💊🕴️📡🤻🦑🇦🇶👩‍🔬🪤🚱✊🏿🔬🧬🏴‍☠️🤽\n"
"0123456789\n"
"👆🏻 👆🏼 👆🏽 👆🏾 👆🏿 👨‍❤️‍👨 👨‍❤️‍💋‍👨 👩‍👩‍👧‍👧 👩🏻‍🤝‍👨🏿 👨‍👨‍👧‍👦\n"
"🇧🇲 🇨🇭 🇨🇿 🇪🇺 🇬🇱 🇲🇬 🇲🇹 🇸🇿 🇿🇲"));
/* clang-format on */
} else {
_fontChooser->setSampleText(
QStringLiteral("0OQ 1Il!| 5S 8B rnm :; ,. \"'` ~-= ({[<>]})\n"
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\n"
"abcdefghijklmnopqrstuvwxyz"));
_showAllFontsWarningButton->setIcon(QIcon::fromTheme(QStringLiteral("emblem-warning")));
_showAllFontsWarningButton->setAutoRaise(true);
connect(_fontChooser, &KFontChooser::fontSelected, this, &FontDialog::fontChanged);
connect(_showAllFonts, &QCheckBox::toggled, this, [this](bool enable) {
_fontChooser->setFont(_fontChooser->font(), !enable);
});
connect(_showAllFontsWarningButton, &QToolButton::clicked, this, [this](bool) {
const QString message = i18nc("@info:status",
"By its very nature, a terminal program requires font characters that are equal width (monospace). Any non monospaced "
"font may cause display issues. This should not be necessary except in rare cases.");
const QPoint pos = QPoint(_showAllFonts->width() / 2, _showAllFonts->height());
QWhatsThis::showText(_showAllFonts->mapToGlobal(pos), message, _showAllFonts);
});
connect(_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(_showAllFonts, &QCheckBox::toggled, this, [this](bool enable) {
_fontChooser->setFont(_fontChooser->font(), !enable);
});
connect(_showAllFontsWarningButton, &QToolButton::clicked, this, [this](bool) {
const QString message =
i18nc("@info:status",
"By its very nature, a terminal program requires font characters that are equal width (monospace). Any non monospaced "
"font may cause display issues. This should not be necessary except in rare cases.");
const QPoint pos = QPoint(_showAllFonts->width() / 2, _showAllFonts->height());
QWhatsThis::showText(_showAllFonts->mapToGlobal(pos), message, _showAllFonts);
});
}
auto *showAllFontsLayout = new QHBoxLayout();
showAllFontsLayout->addWidget(_showAllFonts);
......@@ -66,11 +83,16 @@ FontDialog::FontDialog(QWidget *parent)
auto *layout = new QVBoxLayout(this);
layout->addWidget(_fontChooser, 1);
layout->addLayout(showAllFontsLayout);
if (!_emoji) {
layout->addLayout(showAllFontsLayout);
}
layout->addWidget(_buttonBox);
connect(_fontChooser, &KFontChooser::fontSelected, this, &FontDialog::fontChanged);
connect(_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
void FontDialog::setFont(const QFont &font)
{
_fontChooser->setFont(font, !_showAllFonts->isChecked());
_fontChooser->setFont(font, !_showAllFonts->isChecked() && !_emoji);
}
......@@ -21,7 +21,7 @@ class FontDialog : public QDialog
Q_OBJECT
public:
explicit FontDialog(QWidget *parent = nullptr);
explicit FontDialog(QWidget *parent = nullptr, bool emoji = false, const QFont font = QFont());
QFont font() const
{
......@@ -37,6 +37,7 @@ private:
QCheckBox *_showAllFonts;
QToolButton *_showAllFontsWarningButton;
QDialogButtonBox *_buttonBox;
bool _emoji;
};
}
......
......@@ -70,7 +70,10 @@ Screen::Screen(int lines, int columns)
, _cuY(0)
, _currentForeground(CharacterColor())
, _currentBackground(CharacterColor())
, _currentRendition(DEFAULT_RENDITION)
, _currentRendition({DEFAULT_RENDITION})
, _ulColorQueueStart(0)
, _ulColorQueueEnd(0)
, _currentULColor(0)
, _topMargin(0)
, _bottomMargin(0)
, _replMode(REPL_None)
......@@ -83,7 +86,7 @@ Screen::Screen(int lines, int columns)
, _blockSelectionMode(false)
, _effectiveForeground(CharacterColor())
, _effectiveBackground(CharacterColor())
, _effectiveRendition(DEFAULT_RENDITION)
, _effectiveRendition({DEFAULT_RENDITION})
, _lastPos(-1)
, _lastDrawnChar(0)
, _escapeSequenceUrlExtractor(nullptr)
......@@ -286,7 +289,7 @@ void Screen::deleteChars(int n)
_screenLines[_cuY].remove(_cuX, n);
// Append space(s) with current attributes
Character spaceWithCurrentAttrs(' ', _effectiveForeground, _effectiveBackground, _effectiveRendition, 0);
Character spaceWithCurrentAttrs(' ', _effectiveForeground, _effectiveBackground, _effectiveRendition.all, 0);
for (int i = 0; i < n; ++i) {
_screenLines[_cuY].append(spaceWithCurrentAttrs);
......@@ -646,7 +649,7 @@ void Screen::reverseRendition(Character &p) const
void Screen::updateEffectiveRendition()
{
_effectiveRendition = _currentRendition;
if ((_currentRendition & RE_REVERSE) != 0) {
if ((_currentRendition.f.reverse) != 0) {
_effectiveForeground = _currentBackground;
_effectiveBackground = _currentForeground;
} else {
......@@ -654,12 +657,12 @@ void Screen::updateEffectiveRendition()
_effectiveBackground = _currentBackground;
}
if ((_currentRendition & RE_BOLD) != 0) {
if ((_currentRendition & RE_FAINT) == 0) {
if ((_currentRendition.f.bold) != 0) {
if ((_currentRendition.f.faint) == 0) {
_effectiveForeground.setIntensive();
}
} else {
if ((_currentRendition & RE_FAINT) != 0) {
if ((_currentRendition.f.faint) != 0) {
_effectiveForeground.setFaint();
}
}
......@@ -688,7 +691,7 @@ void Screen::copyFromHistory(Character *dest, int startLine, int count) const
if (_selBegin != -1) {
for (int column = 0; column < lastColumn; ++column) {
if (isSelected(column, line)) {
dest[destLineOffset + column].rendition |= RE_SELECTED;
dest[destLineOffset + column].rendition.f.selected = 1;
}
}
}
......@@ -720,7 +723,7 @@ void Screen::copyFromScreen(Character *dest, int startLine, int count) const
if (_selBegin != -1) {
for (int column = 0; column < lastColumn; ++column) {
if (isSelected(column, line + historyLines)) {
dest[destLineOffset + column].rendition |= RE_SELECTED;
dest[destLineOffset + column].rendition.f.selected = 1;
}
}
}
......@@ -761,7 +764,7 @@ void Screen::getImage(Character *dest, int size, int startLine, int endLine) con
// mark the character at the current cursor position
int cursorIndex = loc(visX, _cuY + linesInHistoryBuffer);
if (getMode(MODE_Cursor) && cursorIndex < _columns * mergedLines) {
dest[cursorIndex].rendition |= RE_CURSOR;
dest[cursorIndex].rendition.f.cursor = 1;
}
}
......@@ -947,13 +950,14 @@ void Screen::displayCharacter(uint c)
// putting the cursor one right to the last column of the screen.
int w = Character::width(c);
const QChar::Category category = QChar::category(c);
if (w < 0) {
// Non-printable character
return;
} else if (w == 0) {
const QChar::Category category = QChar::category(c);
if (category != QChar::Mark_NonSpacing && category != QChar::Letter_Other && category != QChar::Other_Format) {
} else if (category == QChar::Mark_SpacingCombining || w == 0 || Character::emoji(c) || c == 0x20E3) {
bool emoji = Character::emoji(c);
if (category != QChar::Mark_SpacingCombining && category != QChar::Mark_NonSpacing && category != QChar::Letter_Other && category != QChar::Other_Format
&& !emoji && c != 0x20E3) {
return;
}
// Find previous "real character" to try to combine with
......@@ -980,6 +984,9 @@ void Screen::displayCharacter(uint c)
} while (_screenLines.at(charToCombineWithY).at(charToCombineWithX).isRightHalfOfDoubleWide());
if (!previousChar) {
if (emoji) {
goto notcombine;
}
if (!Hangul::isHangul(c)) {
return;
} else {
......@@ -990,24 +997,88 @@ void Screen::displayCharacter(uint c)
Character &currentChar = _screenLines[charToCombineWithY][charToCombineWithX];
if (c == 0x20E3) {
// Combining Enclosing Keycap - only combines with presentation mode #,*,0-9
if ((currentChar.character != 0x23 && currentChar.character != 0x2A && (currentChar.character < '0' || currentChar.character > '9'))
|| (currentChar.flags & EF_EMOJI_REPRESENTATION) == 0) {
// Is this the right thing TODO?
return;
}
}
if (c == 0xFE0F) {
// Emoji presentation - should not be included
currentChar.flags |= EF_EMOJI_REPRESENTATION;
return;
}
if (c == 0x200D) {
// Zero width joiner
currentChar.flags |= EF_EMOJI_REPRESENTATION;
}
if (c >= 0xE0020 && c <= 0xE007F) {
// Tags - used for some flags
currentChar.flags |= EF_EMOJI_REPRESENTATION;
}
if (c >= 0x1f3fb && c <= 0x1f3ff) {
// Emoji modifier Fitzpatrick - changes skin color
uint currentUcs4 = currentChar.character;
if (currentChar.rendition.f.extended == 1) {
ushort extendedCharLength;
const uint *oldChars = ExtendedCharTable::instance.lookupExtendedChar(currentChar.character, extendedCharLength);
currentUcs4 = oldChars[extendedCharLength - 1];
}
if (currentUcs4 < 0x261d || (currentUcs4 > 0x270d && currentUcs4 < 0x1efff) || currentUcs4 > 0x1faff) {
goto notcombine;
}
currentChar.flags |= EF_EMOJI_REPRESENTATION;
} else if (c >= 0x1f1e6 && c <= 0x1f1ff) {
// Regional indicators - flag components
if (currentChar.rendition.f.extended == 1 || currentChar.character < 0x1f1e6 || currentChar.character > 0x1f1ff) {
goto notcombine;
}
currentChar.flags |= EF_EMOJI_REPRESENTATION;
} else if (emoji) {
if (currentChar.rendition.f.extended == 0) {
goto notcombine;
}
ushort extendedCharLength;
const uint *oldChars = ExtendedCharTable::instance.lookupExtendedChar(currentChar.character, extendedCharLength);
if (oldChars[extendedCharLength - 1] != 0x200d) {
goto notcombine;
}
}
if (Hangul::isHangul(c) && !Hangul::combinesWith(currentChar, c)) {
w = 2;
goto notcombine;
}
if ((currentChar.rendition & RE_EXTENDED_CHAR) == 0) {
if (currentChar.rendition.f.extended == 0) {
const uint chars[2] = {currentChar.character, c};
currentChar.rendition |= RE_EXTENDED_CHAR;
currentChar.rendition.f.extended = 1;
auto extChars = [this]() {
return usedExtendedChars();
};
currentChar.character = ExtendedCharTable::instance.createExtendedChar(chars, 2, extChars);
if (category == QChar::Mark_SpacingCombining) {
// ensure current line vector has enough elements
if (_screenLines[_cuY].size() < _cuX + w) {
_screenLines[_cuY].resize(_cuX + w);
}
Character &ch = _screenLines[_cuY][_cuX];
ch.setRightHalfOfDoubleWide();
ch.foregroundColor = _effectiveForeground;
ch.backgroundColor = _effectiveBackground;
ch.rendition = _effectiveRendition;
ch.flags = setRepl(EF_UNREAL, _replMode);
_cuX += 1;
}
} else {
ushort extendedCharLength;
const uint *oldChars = ExtendedCharTable::instance.lookupExtendedChar(currentChar.character, extendedCharLength);
Q_ASSERT(extendedCharLength > 1);
Q_ASSERT(oldChars);
if (((oldChars) != nullptr) && extendedCharLength < 8) {
Q_ASSERT(extendedCharLength > 1);
if (((oldChars) != nullptr) && extendedCharLength < 10) {
Q_ASSERT(extendedCharLength < 65535); // redundant due to above check
auto chars = std::make_unique<uint[]>(extendedCharLength + 1);
std::copy_n(oldChars, extendedCharLength, chars.get());
......@@ -1051,7 +1122,10 @@ notcombine:
currentChar.foregroundColor = _effectiveForeground;
currentChar.backgroundColor = _effectiveBackground;
currentChar.rendition = _effectiveRendition;
currentChar.flags = setRepl(EF_REAL, _replMode);
currentChar.flags = setRepl(EF_REAL, _replMode) | SetULColor(0, _currentULColor);
if (Character::emojiPresentation(c)) {
currentChar.flags |= EF_EMOJI_REPRESENTATION;
}
_lastDrawnChar = c;
......@@ -1416,13 +1490,19 @@ void Screen::clearEntireLine()
void Screen::setRendition(RenditionFlags rendition)
{
_currentRendition |= rendition;
_currentRendition.all |= rendition;
updateEffectiveRendition();
}
void Screen::setUnderlineType(int type)
{
_currentRendition.f.underline = type;
updateEffectiveRendition();
}
void Screen::resetRendition(RenditionFlags rendition)
{
_currentRendition &= ~rendition;
_currentRendition.all &= ~rendition;
updateEffectiveRendition();
}
......@@ -1430,7 +1510,7 @@ void Screen::setDefaultRendition()
{
setForeColor(COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR);
setBackColor(COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR);
_currentRendition = DEFAULT_RENDITION;
_currentRendition = {DEFAULT_RENDITION};
updateEffectiveRendition();
}
......@@ -1456,6 +1536,31 @@ void Screen::setBackColor(int space, int color)
}
}
void Screen::setULColor(int space, int color)
{
CharacterColor col(quint8(space), color);
if (col.isValid()) {
int end = _ulColorQueueEnd;
if (end < _ulColorQueueStart) {
end += 15;
}
for (int i = _ulColorQueueStart; i < end; i++) {
if (col == _ulColors[i % 15]) {
_currentULColor = i % 15 + 1;
return;
}
}
_ulColors[_ulColorQueueEnd] = col;
_currentULColor = _ulColorQueueEnd + 1;
_ulColorQueueEnd = (_ulColorQueueEnd + 1) % 15;
if (_ulColorQueueEnd == _ulColorQueueStart) {
_ulColorQueueStart = (_ulColorQueueStart + 1) % 15;
}
} else {
_currentULColor = 0;
}
}
void Screen::clearSelection()
{
_selBottomRight = -1;
......@@ -1920,7 +2025,6 @@ int Screen::copyLineToStream(int line,
int p = 0;
for (int i = 0; i < count; i++) {
Character c = characterBuffer[spacesCount + i];
// fprintf(stderr, "copy %i %i %i\n", i, c.character, c.flags);
if (((options & ExcludePrompt) != 0 && (c.flags & EF_REPL) == EF_REPL_PROMPT)
|| ((options & ExcludeInput) != 0 && (c.flags & EF_REPL) == EF_REPL_INPUT)
|| ((options & ExcludeOutput) != 0 && (c.flags & EF_REPL) == EF_REPL_OUTPUT)) {
......
......@@ -314,6 +314,7 @@ public:
* @see Character::rendition
*/
void setRendition(RenditionFlags rendition);
void setUnderlineType(int type);
/**
* Disables the given @p rendition flag. Rendition flags control the appearance
* of characters on the screen.
......@@ -346,6 +347,13 @@ public:
*/
void setDefaultRendition();
void setULColor(int space, int color);
CharacterColor const *ulColorTable() const
{
return _ulColors;
};
/** Returns the column which the cursor is positioned at. */
int getCursorX() const;
/** Returns the line which the cursor is positioned on. */
......@@ -642,7 +650,7 @@ public:
for (int i = 0; i < _lines; ++i) {
const ImageLine &il = _screenLines[i];
for (int j = 0; j < il.length(); ++j) {
if (il[j].rendition & RE_EXTENDED_CHAR) {
if (il[j].rendition.f.extended) {
result << il[j].character;
}
}
......@@ -800,7 +808,12 @@ private:
// cursor color and rendition info
CharacterColor _currentForeground;
CharacterColor _currentBackground;
RenditionFlags _currentRendition;
RenditionFlagsC _currentRendition;
CharacterColor _ulColors[15];
int _ulColorQueueStart;
int _ulColorQueueEnd;
int _currentULColor;
// margins ----------------
int _topMargin;
......@@ -829,7 +842,7 @@ private:
// effective colors and rendition ------------
CharacterColor _effectiveForeground; // These are derived from
CharacterColor _effectiveBackground; // the cu_* variables above
RenditionFlags _effectiveRendition; // to speed up operation
RenditionFlagsC _effectiveRendition; // to speed up operation
class SavedState
{
......@@ -838,7 +851,7 @@ private:
: cursorColumn(0)
, cursorLine(0)
, originMode(0)
, rendition(0)
, rendition({0})
, foreground(CharacterColor())
, background(CharacterColor())
{
......@@ -847,7 +860,7 @@ private:
int cursorColumn;
int cursorLine;
int originMode;
RenditionFlags rendition;
RenditionFlagsC rendition;
CharacterColor foreground;
CharacterColor background;
};
......
......@@ -511,7 +511,7 @@ void Vt102Emulation::csi_dispatch(const uint cc)
processToken(token_csi_pq(cc), 0, 0);
} else if (tokenBufferPos != 0 && tokenBuffer[0] == '>') {
processToken(token_csi_pg(cc), 0, 0);
} else if (cc == 'm' && !params.sub[i].count && params.count - i >= 4 && (params.value[i] == 38 || params.value[i] == 48)
} else if (cc == 'm' && !params.sub[i].count && params.count - i >= 4 && (params.value[i] == 38 || params.value[i] == 48 || params.value[i] == 58)
&& params.value[i + 1] == 2) {
// ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
i += 2;
......@@ -519,22 +519,27 @@ void Vt102Emulation::csi_dispatch(const uint cc)
COLOR_SPACE_RGB,
(params.value[i] << 16) | (params.value[i + 1] << 8) | params.value[i + 2]);
i += 2;
} else if (cc == 'm' && params.sub[i].count >= 5 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 2) {
} else if (cc == 'm' && params.sub[i].count >= 5 && (params.value[i] == 38 || params.value[i] == 48 || params.value[i] == 58)
&& params.sub[i].value[1] == 2) {
// ESC[ ... 48:2:<id>:<red>:<green>:<blue> ... m -or- ESC[ ... 38:2:<id>:<red>:<green>:<blue> ... m
processToken(token_csi_ps(cc, params.value[i]),
COLOR_SPACE_RGB,
(params.sub[i].value[3] << 16) | (params.sub[i].value[4] << 8) | params.sub[i].value[5]);
} else if (cc == 'm' && params.sub[i].count == 4 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 2) {
} else if (cc == 'm' && params.sub[i].count == 4 && (params.value[i] == 38 || params.value[i] == 48 || params.value[i] == 58)
&& params.sub[i].value[1] == 2) {
// ESC[ ... 48:2:<red>:<green>:<blue> ... m -or- ESC[ ... 38:2:<red>:<green>:<blue> ... m
processToken(token_csi_ps(cc, params.value[i]),
COLOR_SPACE_RGB,
(params.sub[i].value[2] << 16) | (params.sub[i].value[3] << 8) | params.sub[i].value[4]);
} else if (cc == 'm' && !params.sub[i].count && params.count - i >= 2 && (params.value[i] == 38 || params.value[i] == 48)
} else if (cc == 'm' && params.sub[i].count == 1 && params.value[i] == 4) {
processToken(token_csi_ps(cc, params.value[i]), params.sub[i].value[1], 1);
} else if (cc == 'm' && !params.sub[i].count && params.count - i >= 2 && (params.value[i] == 38 || params.value[i] == 48 || params.value[i] == 58)
&& params.value[i + 1] == 5) {
// ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
i += 2;
processToken(token_csi_ps(cc, params.value[i - 2]), COLOR_SPACE_256, params.value[i]);
} else if (cc == 'm' && params.sub[i].count >= 2 && (params.value[i] == 38 || params.value[i] == 48) && params.sub[i].value[1] == 5) {
} else if (cc == 'm' && params.sub[i].count >= 2 && (params.value[i] == 38 || params.value[i] == 48 || params.value[i] == 58)
&& params.sub[i].value[1] == 5) {
// ESC[ ... 48:5:<index> ... m -or- ESC[ ... 38:5:<index> ... m
processToken(token_csi_ps(cc, params.value[i]), COLOR_SPACE_256, params.sub[i].value[2]);
} else if (_nIntermediate == 0) {
......@@ -985,16 +990,16 @@ void Vt102Emulation::processChecksumRequest([[maybe_unused]] int crargc, int cra
// XXX: Apparently, VT520 uses 0x00 for uninitialized cells, konsole can't tell uninitialized cells from spaces
Character c = image[y * _currentScreen->getColumns() + x];
if (c.rendition & RE_CONCEAL) {
if (c.rendition.f.conceal) {
checksum += 0x20; // don't reveal secrets
} else {
checksum += c.character;
}
checksum += (c.rendition & RE_BOLD) / RE_BOLD * 0x80;
checksum += (c.rendition & RE_BLINK) / RE_BLINK * 0x40;
checksum += (c.rendition & RE_REVERSE) / RE_REVERSE * 0x20;
checksum += (c.rendition & RE_UNDERLINE) / RE_UNDERLINE * 0x10;
checksum += c.rendition.f.bold * 0x80;
checksum += c.rendition.f.blink * 0x40;
checksum += c.rendition.f.reverse * 0x20;
checksum += !!(c.rendition.all & RE_UNDERLINE_MASK) * 0x10;
}
}
......@@ -1353,7 +1358,13 @@ void Vt102Emulation::processToken(int token, int p, int q)
case token_csi_ps('m', 1) : _currentScreen-> setRendition (RE_BOLD ); break; //VT100
case token_csi_ps('m', 2) : _currentScreen-> setRendition (RE_FAINT ); break;
case token_csi_ps('m', 3) : _currentScreen-> setRendition (RE_ITALIC ); break; //VT100
case token_csi_ps('m', 4) : _currentScreen-> setRendition (RE_UNDERLINE); break; //VT100
case token_csi_ps('m', 4) :
if (q == 1) {
_currentScreen->setUnderlineType(p);
} else {
_currentScreen->setUnderlineType(RE_UNDERLINE);
}
break; //VT100
case token_csi_ps('m', 5) : _currentScreen-> setRendition (RE_BLINK ); break; //VT100
case token_csi_ps('m', 7) : _currentScreen-> setRendition (RE_REVERSE ); break;
case token_csi_ps('m', 8) : _currentScreen-> setRendition (RE_CONCEAL ); break;
......@@ -1362,11 +1373,11 @@ void Vt102Emulation::processToken(int token, int p, int q)
case token_csi_ps('m', 10) : /* IGNORED: mapping related */ break; //LINUX
case token_csi_ps('m', 11) : /* IGNORED: mapping related */ break; //LINUX
case token_csi_ps('m', 12) : /* IGNORED: mapping related */ break; //LINUX
case token_csi_ps('m', 21) : _currentScreen->resetRendition (RE_BOLD ); break;
case token_csi_ps('m', 21) : _currentScreen->setUnderlineType(RE_UNDERLINE_DOUBLE); break;
case token_csi_ps('m', 22) : _currentScreen->resetRendition (RE_BOLD );
_currentScreen->resetRendition (RE_FAINT ); break;
case token_csi_ps('m', 23) : _currentScreen->resetRendition (RE_ITALIC ); break; //VT100
case token_csi_ps('m', 24) : _currentScreen->resetRendition (RE_UNDERLINE); break;
case token_csi_ps('m', 24) : _currentScreen->resetRendition (RE_UNDERLINE_MASK); break;
case token_csi_ps('m', 25) : _currentScreen->resetRendition (RE_BLINK ); break;
case token_csi_ps('m', 27) : _currentScreen->resetRendition (RE_REVERSE ); break;
case token_csi_ps('m', 28) : _currentScreen->resetRendition (RE_CONCEAL ); break;
......@@ -1399,6 +1410,10 @@ void Vt102Emulation::processToken(int token, int p, int q)
case token_csi_ps('m', 49) : _currentScreen->setBackColor (COLOR_SPACE_DEFAULT, 1); break;
case token_csi_ps('m', 58) : _currentScreen->setULColor (p, q); break;
case token_csi_ps('m', 59) : _currentScreen->setULColor (COLOR_SPACE_UNDEFINED, 0); break;