File indexing completed on 2024-05-05 05:53:43
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0003 SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef CHARACTER_H 0009 #define CHARACTER_H 0010 0011 // Konsole 0012 #include "CharacterColor.h" 0013 #include "CharacterWidth.h" 0014 #include "ExtendedCharTable.h" 0015 #include "Hangul.h" 0016 #include "LineBlockCharacters.h" 0017 0018 // Qt 0019 #include <QVector> 0020 0021 /* clang-format off */ 0022 const int LINE_WRAPPED = (1 << 0); 0023 const int LINE_DOUBLEWIDTH = (1 << 1); 0024 const int LINE_DOUBLEHEIGHT_TOP = (1 << 2); 0025 const int LINE_DOUBLEHEIGHT_BOTTOM = (1 << 3); 0026 const int LINE_PROMPT_START = (1 << 4); 0027 const int LINE_INPUT_START = (1 << 5); 0028 const int LINE_OUTPUT_START = (1 << 6); 0029 /* clang-format on */ 0030 0031 namespace Konsole 0032 { 0033 #pragma pack(1) 0034 class LineProperty 0035 { 0036 public: 0037 explicit constexpr LineProperty(quint16 f = 0, uint l = 0, uint c = 0) 0038 : flags({f}) 0039 , length(l) 0040 , counter(c) 0041 { 0042 } 0043 union { 0044 quint16 all; 0045 struct { 0046 uint wrapped : 1; 0047 uint doublewidth : 1; 0048 uint doubleheight_top : 1; 0049 uint doubleheight_bottom : 1; 0050 uint prompt_start : 1; 0051 uint output_start : 1; 0052 uint input_start : 1; 0053 uint output : 1; 0054 uint error : 1; 0055 } f; 0056 } flags; 0057 qint16 length; 0058 quint16 counter; 0059 bool operator!=(const LineProperty &rhs) const 0060 { 0061 return (flags.all != rhs.flags.all); 0062 } 0063 void resetStarts() 0064 { 0065 flags.all &= ~(LINE_PROMPT_START | LINE_INPUT_START | LINE_OUTPUT_START); 0066 } 0067 quint16 getStarts() const 0068 { 0069 return flags.all & (LINE_PROMPT_START | LINE_INPUT_START | LINE_OUTPUT_START); 0070 } 0071 void setStarts(quint16 starts) 0072 { 0073 flags.all = (flags.all & ~(LINE_PROMPT_START | LINE_INPUT_START | LINE_OUTPUT_START)) | starts; 0074 } 0075 }; 0076 0077 typedef union { 0078 quint16 all; 0079 struct { 0080 uint bold : 1; 0081 uint blink : 1; 0082 uint transparent : 1; 0083 uint reverse : 1; 0084 uint italic : 1; 0085 uint cursor : 1; 0086 uint extended : 1; 0087 uint faint : 1; 0088 uint strikeout : 1; 0089 uint conceal : 1; 0090 uint overline : 1; 0091 uint selected : 1; 0092 uint underline : 4; 0093 } f; 0094 } RenditionFlagsC; 0095 typedef quint16 RenditionFlags; 0096 #pragma pack() 0097 0098 typedef quint16 ExtraFlags; 0099 0100 /* clang-format off */ 0101 const RenditionFlags DEFAULT_RENDITION = 0; 0102 const RenditionFlags RE_BOLD = (1 << 0); 0103 const RenditionFlags RE_BLINK = (1 << 1); 0104 const RenditionFlags RE_TRANSPARENT = (1 << 2); 0105 const RenditionFlags RE_REVERSE = (1 << 3); // Screen only 0106 const RenditionFlags RE_ITALIC = (1 << 4); 0107 const RenditionFlags RE_CURSOR = (1 << 5); 0108 const RenditionFlags RE_EXTENDED_CHAR = (1 << 6); 0109 const RenditionFlags RE_FAINT = (1 << 7); 0110 const RenditionFlags RE_STRIKEOUT = (1 << 8); 0111 const RenditionFlags RE_CONCEAL = (1 << 9); 0112 const RenditionFlags RE_OVERLINE = (1 << 10); 0113 const RenditionFlags RE_SELECTED = (1 << 11); 0114 const RenditionFlags RE_UNDERLINE_MASK = (15 << 12); 0115 const RenditionFlags RE_UNDERLINE_NONE = 0; 0116 const RenditionFlags RE_UNDERLINE = 1; 0117 const RenditionFlags RE_UNDERLINE_DOUBLE= 2; 0118 const RenditionFlags RE_UNDERLINE_CURL = 3; 0119 const RenditionFlags RE_UNDERLINE_DOT = 4; 0120 const RenditionFlags RE_UNDERLINE_DASH = 5; 0121 const RenditionFlags RE_UNDERLINE_BIT = (1 << 12); 0122 // Masks of flags that matter for drawing what is below/above the text 0123 const RenditionFlags RE_MASK_UNDER = RE_TRANSPARENT | RE_REVERSE | RE_CURSOR | RE_SELECTED; 0124 const RenditionFlags RE_MASK_ABOVE = RE_TRANSPARENT | RE_REVERSE | RE_CURSOR | RE_SELECTED | RE_STRIKEOUT | RE_CONCEAL | RE_OVERLINE | RE_UNDERLINE_MASK; 0125 0126 // flags that affect how the text is drawn 0127 // without RE_REVERSE, since the foreground color is calculated 0128 const RenditionFlags RE_TEXTDRAWING = RE_BOLD | RE_BLINK | RE_TRANSPARENT | RE_ITALIC | RE_CURSOR | RE_FAINT | RE_SELECTED; 0129 0130 0131 const ExtraFlags EF_UNREAL = 0; 0132 const ExtraFlags EF_REAL = (1 << 0); 0133 const ExtraFlags EF_REPL = (3 << 1); 0134 const ExtraFlags EF_REPL_NONE = (0 << 1); 0135 const ExtraFlags EF_REPL_PROMPT = (1 << 1); 0136 const ExtraFlags EF_REPL_INPUT = (2 << 1); 0137 const ExtraFlags EF_REPL_OUTPUT = (3 << 1); 0138 const ExtraFlags EF_UNDERLINE_COLOR = (15 << 3); 0139 const ExtraFlags EF_UNDERLINE_COLOR_1 = (1 << 3); 0140 const ExtraFlags EF_EMOJI_REPRESENTATION = (1 << 7); 0141 const ExtraFlags EF_ASCII_WORD = (1 << 8); 0142 const ExtraFlags EF_BRAHMIC_WORD = (1 << 9); 0143 0144 #define SetULColor(f, m) (((f) & ~EF_UNDERLINE_COLOR) | ((m) * EF_UNDERLINE_COLOR_1)) 0145 #define setRepl(f, m) (((f) & ~EF_REPL) | ((m) * EF_REPL_PROMPT)) 0146 /* clang-format on */ 0147 0148 /** 0149 * A single character in the terminal which consists of a unicode character 0150 * value, foreground and background colors and a set of rendition attributes 0151 * which specify how it should be drawn. 0152 */ 0153 class Character 0154 { 0155 public: 0156 /** 0157 * Constructs a new character. 0158 * 0159 * @param _c The unicode character value of this character. 0160 * @param _f The foreground color used to draw the character. 0161 * @param _b The color used to draw the character's background. 0162 * @param _r A set of rendition flags which specify how this character 0163 * is to be drawn. 0164 * @param _flags Extra flags describing the character. not directly related to its rendition 0165 */ 0166 explicit constexpr Character(uint _c = ' ', 0167 CharacterColor _f = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR), 0168 CharacterColor _b = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR), 0169 RenditionFlags _r = DEFAULT_RENDITION, 0170 ExtraFlags _flags = EF_REAL) 0171 : character(_c) 0172 , rendition({_r}) 0173 , foregroundColor(_f) 0174 , backgroundColor(_b) 0175 , flags(_flags) 0176 { 0177 } 0178 0179 /** The unicode character value for this character. 0180 * 0181 * if RE_EXTENDED_CHAR is set, character is a hash code which can be used to 0182 * look up the unicode character sequence in the ExtendedCharTable used to 0183 * create the sequence. 0184 */ 0185 char32_t character; 0186 0187 /** A combination of RENDITION flags which specify options for drawing the character. */ 0188 RenditionFlagsC rendition; 0189 0190 /** The foreground color used to draw this character. */ 0191 CharacterColor foregroundColor; 0192 0193 /** The color used to draw this character's background. */ 0194 CharacterColor backgroundColor; 0195 0196 /** Flags which are not specific to rendition 0197 * Indicate whether this character really exists, or exists simply as place holder. 0198 * REPL mode 0199 * Character type (script, etc.) 0200 */ 0201 ExtraFlags flags; 0202 0203 /** 0204 * returns true if the format (color, rendition flag) of the compared characters is equal 0205 */ 0206 constexpr bool equalsFormat(const Character &other) const; 0207 0208 /** 0209 * Compares two characters and returns true if they have the same unicode character value, 0210 * rendition and colors. 0211 */ 0212 friend constexpr bool operator==(const Character &a, const Character &b); 0213 0214 /** 0215 * Compares two characters and returns true if they have different unicode character values, 0216 * renditions or colors. 0217 */ 0218 friend constexpr bool operator!=(const Character &a, const Character &b); 0219 0220 constexpr bool isSpace() const 0221 { 0222 if (rendition.f.extended) { 0223 return false; 0224 } else { 0225 return QChar::isSpace(character); 0226 } 0227 } 0228 0229 int width() const 0230 { 0231 return width(character); 0232 } 0233 0234 int repl() const 0235 { 0236 return flags & EF_REPL; 0237 } 0238 0239 static constexpr int emojiPresentation1Start = 8986; 0240 static constexpr int emojiPresentation1End = 11093; 0241 static constexpr int emojiPresentation2Start = 126980; 0242 static constexpr int emojiPresentation2End = 129782; 0243 /* clang-format off */ 0244 static constexpr uint64_t emojiPresentation1Bits[] = { 0245 0x3, 0x0, 0x0, 0x2478000, 0x0, 0x0, 0x0, 0x0, 0246 0x0, 0x0, 0x0, 0xc00001800000000, 0x3ffc00000000000, 0x200002000000000, 0x4100c1800030080, 0x308090b010000, 0247 0x2e14000000004000, 0x3800000000000000, 0x2000400000, 0x0, 0x0, 0x0, 0x0, 0x0, 0248 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0249 0x840000000000006 0250 }; 0251 static constexpr uint64_t emojiPresentation2Bits[] = { 0252 0x1, 0x0, 0x0, 0x800, 0x0, 0x0, 0x7fe400, 0x2ffffffc00000000, 0253 0x77c80000400000, 0x3000, 0x0, 0xf000000000000000, 0254 0xfffbfe001fffffff, 0xfdffffffffffffff, 0xfffffffff000ffff, 0xfff11ffff000f87f, 0255 0xd7ffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xf9ffffffffffffff, 0256 0x3ffffffffffffff, 0x40000ffffff780, 0x100060000, 0xff80000000000000, 0257 0xffffffffffffffff, 0xf000000000000fff, 0xffffffffffffffff, 0x1ff01800e0e7103, 0x0, 0x0, 0x0, 0x10fff0000000, 0258 0x0, 0x0, 0x0, 0x0, 0xff7fffffffffff00, 0xfffffffffffffffb, 0xffffffffffffffff, 0xfffffffffffffff, 0259 0x0, 0xf1f1f00000000000, 0xf07ff1fffffff007, 0x7f00ff03ff003 0260 }; 0261 /* clang-format on */ 0262 0263 static bool emojiPresentation(uint ucs4) 0264 { 0265 if (ucs4 >= emojiPresentation1Start && ucs4 <= emojiPresentation1End) { 0266 return (emojiPresentation1Bits[(ucs4 - emojiPresentation1Start) / 64] & (uint64_t(1) << ((ucs4 - emojiPresentation1Start) % 64))) != 0; 0267 } else if (ucs4 >= emojiPresentation2Start && ucs4 <= emojiPresentation2End) { 0268 return (emojiPresentation2Bits[(ucs4 - emojiPresentation2Start) / 64] & (uint64_t(1) << ((ucs4 - emojiPresentation2Start) % 64))) != 0; 0269 } 0270 return false; 0271 } 0272 0273 static constexpr int emoji1Start = 8252; 0274 static constexpr int emoji1End = 12953; 0275 static constexpr int emoji2Start = 126980; 0276 static constexpr int emoji2End = 129782; 0277 /* clang-format off */ 0278 static constexpr uint64_t emoji1Bits[] = { 0279 0x2001, 0x0, 0x0, 0x2000004000000000, 0x0, 0x60003f000000, 0x0, 0x0, 0280 0x0, 0x0, 0x0, 0x1000c0000000, 0x0, 0x0, 0x70ffe00000080000, 0x0, 0281 0x0, 0x0, 0x40, 0x0, 0x0, 0x400c00000000000, 0x8000000000000010, 0x700c44d2132401f7, 0282 0x8000169800fff050, 0x30c831afc0000c, 0x7bf0600001ac1306, 0x1801022054bf242, 0x1800b850900, 0x1000200e000000, 0x8, 0x0, 0283 0x0, 0x0, 0x0, 0x300000000000000, 0x0, 0x0, 0x0, 0x0, 0284 0x0, 0x0, 0x0, 0x180000e00, 0x2100000, 0x0, 0x0, 0x0, 0285 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0286 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000000, 0287 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0288 0x0, 0x28000000 0289 }; 0290 static constexpr uint64_t emoji2Bits[] = { 0291 0x1, 0x0, 0x0, 0x800, 0x0, 0xc00300000000000, 0x7fe400, 0x6ffffffc00000000, 0292 0x7fc80000400000, 0x3000, 0x0, 0xf000000000000000, 0293 0xffffffff3fffffff, 0xffffffffffffffff, 0xfffffffffcecffff, 0xfffb9fffffffffff, 0294 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfbffffffffffffff, 0295 0x3ffffffffffffff, 0x7f980ffffff7e0, 0xc1006013000613c8, 0xffc08810a700e001, 0296 0xffffffffffffffff, 0xf000000000000fff, 0xffffffffffffffff, 0x1ff91a3fe0e7f83, 0x0, 0x0, 0x0, 0x10fff0000000, 0297 0x0, 0x0, 0x0, 0x0, 0xff7fffffffffff00, 0xfffffffffffffffb, 0xffffffffffffffff, 0xfffffffffffffff, 0298 0x0, 0xf1f1f00000000000, 0xf07ff1fffffff007, 0x7f00ff03ff003 0299 }; 0300 /* clang-format on */ 0301 0302 static bool emoji(uint ucs4) 0303 { 0304 if (ucs4 >= emoji1Start && ucs4 <= emoji1End) { 0305 return (emoji1Bits[(ucs4 - emoji1Start) / 64] & (uint64_t(1) << ((ucs4 - emoji1Start) % 64))) != 0; 0306 } else if (ucs4 >= emoji2Start && ucs4 <= emoji2End) { 0307 return (emoji2Bits[(ucs4 - emoji2Start) / 64] & (uint64_t(1) << ((ucs4 - emoji2Start) % 64))) != 0; 0308 } 0309 return false; 0310 } 0311 0312 static int width(uint ucs4) 0313 { 0314 // ASCII 0315 if (ucs4 >= 0x20 && ucs4 < 0x7f) 0316 return 1; 0317 0318 if (ucs4 >= 0xA0 && ucs4 <= 0xFF) 0319 return 1; 0320 0321 // NULL 0322 if (ucs4 == 0) 0323 return 0; 0324 0325 // Control chars 0326 if ((ucs4 > 0x0 && ucs4 < 0x20) || (ucs4 >= 0x7F && ucs4 < 0xA0)) 0327 return -1; 0328 0329 return characterWidth(ucs4); 0330 } 0331 0332 static int stringWidth(const char32_t *ucs4Str, int len) 0333 { 0334 int w = 0; 0335 Hangul::SyllablePos hangulSyllablePos = Hangul::NotInSyllable; 0336 0337 for (int i = 0; i < len; ++i) { 0338 const uint c = ucs4Str[i]; 0339 0340 if (!Hangul::isHangul(c)) { 0341 w += width(c); 0342 hangulSyllablePos = Hangul::NotInSyllable; 0343 } else { 0344 w += Hangul::width(c, width(c), hangulSyllablePos); 0345 } 0346 } 0347 return w; 0348 } 0349 0350 inline static int stringWidth(const QString &str) 0351 { 0352 const auto ucs4Str = str.toStdU32String(); 0353 return stringWidth(ucs4Str.data(), ucs4Str.size()); 0354 } 0355 0356 inline uint baseCodePoint() const 0357 { 0358 if (rendition.f.extended) { 0359 ushort extendedCharLength = 0; 0360 const char32_t *chars = ExtendedCharTable::instance.lookupExtendedChar(character, extendedCharLength); 0361 // FIXME: Coverity-Dereferencing chars, which is known to be nullptr 0362 return chars[0]; 0363 } 0364 return character; 0365 } 0366 0367 inline bool isSameScript(Character lhs) const 0368 { 0369 const QChar::Script script = QChar::script(lhs.baseCodePoint()); 0370 const QChar::Script currentScript = QChar::script(baseCodePoint()); 0371 if (currentScript == QChar::Script_Common || script == QChar::Script_Common || currentScript == QChar::Script_Inherited 0372 || script == QChar::Script_Inherited) { 0373 return true; 0374 } 0375 return currentScript == script; 0376 } 0377 0378 inline bool hasSameColors(Character lhs) const 0379 { 0380 return lhs.foregroundColor == foregroundColor && lhs.backgroundColor == backgroundColor; 0381 } 0382 0383 inline bool hasSameRendition(Character lhs) const 0384 { 0385 return (lhs.rendition.all & ~RE_EXTENDED_CHAR) == (rendition.all & ~RE_EXTENDED_CHAR) && lhs.flags == flags; 0386 } 0387 0388 inline bool hasSameLineDrawStatus(Character lhs) const 0389 { 0390 const bool lineDraw = LineBlockCharacters::canDraw(character); 0391 return LineBlockCharacters::canDraw(lhs.character) == lineDraw; 0392 } 0393 0394 inline bool hasSameAttributes(Character lhs) const 0395 { 0396 return hasSameColors(lhs) && hasSameRendition(lhs) && hasSameLineDrawStatus(lhs) && isSameScript(lhs); 0397 } 0398 0399 inline bool notSameAttributesText(Character lhs) const 0400 { 0401 // Only compare attributes used for drawing text 0402 return (lhs.rendition.all & RE_TEXTDRAWING) != (rendition.all & RE_TEXTDRAWING) || lhs.foregroundColor != foregroundColor; 0403 } 0404 0405 inline bool isRightHalfOfDoubleWide() const 0406 { 0407 return character == 0; 0408 } 0409 0410 inline void setRightHalfOfDoubleWide() 0411 { 0412 character = 0; 0413 } 0414 }; 0415 0416 constexpr bool operator==(const Character &a, const Character &b) 0417 { 0418 return a.character == b.character && a.equalsFormat(b); 0419 } 0420 0421 constexpr bool operator!=(const Character &a, const Character &b) 0422 { 0423 return !operator==(a, b); 0424 } 0425 0426 constexpr bool Character::equalsFormat(const Character &other) const 0427 { 0428 return backgroundColor == other.backgroundColor && foregroundColor == other.foregroundColor && rendition.all == other.rendition.all; 0429 } 0430 } 0431 Q_DECLARE_TYPEINFO(Konsole::Character, Q_MOVABLE_TYPE); 0432 0433 #endif // CHARACTER_H