File indexing completed on 2024-05-12 09:56:56
0001 /* 0002 SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own 0008 #include "HTMLDecoder.h" 0009 0010 // Konsole characters 0011 #include <ExtendedCharTable.h> 0012 0013 // Qt 0014 #include <QTextStream> 0015 0016 using namespace Konsole; 0017 0018 HTMLDecoder::HTMLDecoder(const QColor *colorTable, const QFont &profileFont) 0019 : _output(nullptr) 0020 , _profileFont(profileFont) 0021 , _innerSpanOpen(false) 0022 , _lastRendition(DEFAULT_RENDITION) 0023 , _lastForeColor(CharacterColor()) 0024 , _lastBackColor(CharacterColor()) 0025 , _validProfile(false) 0026 { 0027 Q_ASSERT(colorTable); 0028 std::copy_n(colorTable, TABLE_COLORS, _colorTable); 0029 } 0030 0031 void HTMLDecoder::begin(QTextStream *output) 0032 { 0033 _output = output; 0034 0035 if (_validProfile) { 0036 QString style; 0037 0038 style.append(QStringLiteral("font-family:'%1',monospace;").arg(_profileFont.family())); 0039 0040 // Prefer point size if set 0041 if (_profileFont.pointSizeF() > 0) { 0042 style.append(QStringLiteral("font-size:%1pt;").arg(_profileFont.pointSizeF())); 0043 } else { 0044 style.append(QStringLiteral("font-size:%1px;").arg(_profileFont.pixelSize())); 0045 } 0046 0047 style.append(QStringLiteral("color:%1;").arg(_colorTable[DEFAULT_FORE_COLOR].name())); 0048 style.append(QStringLiteral("background-color:%1;").arg(_colorTable[DEFAULT_BACK_COLOR].name())); 0049 0050 *output << QStringLiteral("<body style=\"%1\">").arg(style); 0051 } else { 0052 QString text; 0053 openSpan(text, QStringLiteral("font-family:monospace")); 0054 *output << text; 0055 } 0056 } 0057 0058 void HTMLDecoder::end() 0059 { 0060 Q_ASSERT(_output); 0061 0062 if (_validProfile) { 0063 *_output << QStringLiteral("</body>"); 0064 } else { 0065 QString text; 0066 closeSpan(text); 0067 *_output << text; 0068 } 0069 0070 _output = nullptr; 0071 } 0072 0073 // TODO: Support for LineProperty (mainly double width , double height) 0074 void HTMLDecoder::decodeLine(const Character *const characters, int count, LineProperty /*properties*/) 0075 { 0076 Q_ASSERT(_output); 0077 0078 QString text; 0079 0080 int spaceCount = 0; 0081 0082 for (int i = 0; i < count; i++) { 0083 // check if appearance of character is different from previous char 0084 if (characters[i].rendition.all != _lastRendition || characters[i].foregroundColor != _lastForeColor 0085 || characters[i].backgroundColor != _lastBackColor) { 0086 if (_innerSpanOpen) { 0087 closeSpan(text); 0088 _innerSpanOpen = false; 0089 } 0090 0091 _lastRendition = characters[i].rendition.all; 0092 _lastForeColor = characters[i].foregroundColor; 0093 _lastBackColor = characters[i].backgroundColor; 0094 0095 // build up style string 0096 QString style; 0097 0098 bool useBold = (_lastRendition & RE_BOLD) != 0; 0099 if (useBold) { 0100 style.append(QLatin1String("font-weight:bold;")); 0101 } 0102 0103 if ((_lastRendition & RE_UNDERLINE_MASK) != 0) { 0104 style.append(QLatin1String("font-decoration:underline;")); 0105 } 0106 0107 style.append(QStringLiteral("color:%1;").arg(_lastForeColor.color(_colorTable).name())); 0108 0109 style.append(QStringLiteral("background-color:%1;").arg(_lastBackColor.color(_colorTable).name())); 0110 0111 // open the span with the current style 0112 openSpan(text, style); 0113 _innerSpanOpen = true; 0114 } 0115 0116 // handle whitespace 0117 if (characters[i].isSpace()) { 0118 spaceCount++; 0119 } else { 0120 spaceCount = 0; 0121 } 0122 0123 // output current character 0124 if (spaceCount < 2) { 0125 if ((characters[i].rendition.all & RE_EXTENDED_CHAR) != 0) { 0126 ushort extendedCharLength = 0; 0127 const char32_t *chars = ExtendedCharTable::instance.lookupExtendedChar(characters[i].character, extendedCharLength); 0128 if (chars != nullptr) { 0129 text.append(QString::fromUcs4(chars, extendedCharLength)); 0130 } 0131 } else { 0132 // escape HTML tag characters and just display others as they are 0133 const QChar ch(characters[i].character); 0134 if (ch == QLatin1Char('<')) { 0135 text.append(QLatin1String("<")); 0136 } else if (ch == QLatin1Char('>')) { 0137 text.append(QLatin1String(">")); 0138 } else if (ch == QLatin1Char('&')) { 0139 text.append(QLatin1String("&")); 0140 } else { 0141 text.append(ch); 0142 } 0143 } 0144 } else { 0145 // HTML truncates multiple spaces, so use a space marker instead 0146 // Use   instead of   so xmllint will work. 0147 text.append(QLatin1String(" ")); 0148 } 0149 } 0150 0151 // close any remaining open inner spans 0152 if (_innerSpanOpen) { 0153 closeSpan(text); 0154 _innerSpanOpen = false; 0155 } 0156 0157 // start new line 0158 text.append(QLatin1String("<br>")); 0159 0160 *_output << text; 0161 } 0162 0163 void HTMLDecoder::openSpan(QString &text, const QString &style) 0164 { 0165 text.append(QStringLiteral("<span style=\"%1\">").arg(style)); 0166 } 0167 0168 void HTMLDecoder::closeSpan(QString &text) 0169 { 0170 text.append(QLatin1String("</span>")); 0171 }