File indexing completed on 2024-05-12 04:02:17
0001 /* 0002 SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "ansihighlighter.h" 0008 #include "abstracthighlighter_p.h" 0009 #include "context_p.h" 0010 #include "definition.h" 0011 #include "definition_p.h" 0012 #include "format.h" 0013 #include "ksyntaxhighlighting_logging.h" 0014 #include "state.h" 0015 #include "state_p.h" 0016 #include "theme.h" 0017 0018 #include <QColor> 0019 #include <QFile> 0020 #include <QFileInfo> 0021 #include <QHash> 0022 #include <QIODevice> 0023 #include <QTextStream> 0024 0025 #include <cmath> 0026 #include <vector> 0027 0028 using namespace KSyntaxHighlighting; 0029 0030 namespace 0031 { 0032 struct Lab { 0033 double L; 0034 double a; 0035 double b; 0036 }; 0037 0038 // clang-format off 0039 // xterm color reference 0040 // constexpr Rgb888 xterm256Colors[] { 0041 // {0x00, 0x00, 0x00}, {0x80, 0x00, 0x00}, {0x00, 0x80, 0x00}, {0x80, 0x80, 0x00}, 0042 // {0x00, 0x00, 0x80}, {0x80, 0x00, 0x80}, {0x00, 0x80, 0x80}, {0xc0, 0xc0, 0xc0}, 0043 // {0x80, 0x80, 0x80}, {0xff, 0x00, 0x00}, {0x00, 0xff, 0x00}, {0xff, 0xff, 0x00}, 0044 // {0x00, 0x00, 0xff}, {0xff, 0x00, 0xff}, {0x00, 0xff, 0xff}, {0xff, 0xff, 0xff}, 0045 // {0x00, 0x00, 0x00}, {0x00, 0x00, 0x5f}, {0x00, 0x00, 0x87}, {0x00, 0x00, 0xaf}, 0046 // {0x00, 0x00, 0xd7}, {0x00, 0x00, 0xff}, {0x00, 0x5f, 0x00}, {0x00, 0x5f, 0x5f}, 0047 // {0x00, 0x5f, 0x87}, {0x00, 0x5f, 0xaf}, {0x00, 0x5f, 0xd7}, {0x00, 0x5f, 0xff}, 0048 // {0x00, 0x87, 0x00}, {0x00, 0x87, 0x5f}, {0x00, 0x87, 0x87}, {0x00, 0x87, 0xaf}, 0049 // {0x00, 0x87, 0xd7}, {0x00, 0x87, 0xff}, {0x00, 0xaf, 0x00}, {0x00, 0xaf, 0x5f}, 0050 // {0x00, 0xaf, 0x87}, {0x00, 0xaf, 0xaf}, {0x00, 0xaf, 0xd7}, {0x00, 0xaf, 0xff}, 0051 // {0x00, 0xd7, 0x00}, {0x00, 0xd7, 0x5f}, {0x00, 0xd7, 0x87}, {0x00, 0xd7, 0xaf}, 0052 // {0x00, 0xd7, 0xd7}, {0x00, 0xd7, 0xff}, {0x00, 0xff, 0x00}, {0x00, 0xff, 0x5f}, 0053 // {0x00, 0xff, 0x87}, {0x00, 0xff, 0xaf}, {0x00, 0xff, 0xd7}, {0x00, 0xff, 0xff}, 0054 // {0x5f, 0x00, 0x00}, {0x5f, 0x00, 0x5f}, {0x5f, 0x00, 0x87}, {0x5f, 0x00, 0xaf}, 0055 // {0x5f, 0x00, 0xd7}, {0x5f, 0x00, 0xff}, {0x5f, 0x5f, 0x00}, {0x5f, 0x5f, 0x5f}, 0056 // {0x5f, 0x5f, 0x87}, {0x5f, 0x5f, 0xaf}, {0x5f, 0x5f, 0xd7}, {0x5f, 0x5f, 0xff}, 0057 // {0x5f, 0x87, 0x00}, {0x5f, 0x87, 0x5f}, {0x5f, 0x87, 0x87}, {0x5f, 0x87, 0xaf}, 0058 // {0x5f, 0x87, 0xd7}, {0x5f, 0x87, 0xff}, {0x5f, 0xaf, 0x00}, {0x5f, 0xaf, 0x5f}, 0059 // {0x5f, 0xaf, 0x87}, {0x5f, 0xaf, 0xaf}, {0x5f, 0xaf, 0xd7}, {0x5f, 0xaf, 0xff}, 0060 // {0x5f, 0xd7, 0x00}, {0x5f, 0xd7, 0x5f}, {0x5f, 0xd7, 0x87}, {0x5f, 0xd7, 0xaf}, 0061 // {0x5f, 0xd7, 0xd7}, {0x5f, 0xd7, 0xff}, {0x5f, 0xff, 0x00}, {0x5f, 0xff, 0x5f}, 0062 // {0x5f, 0xff, 0x87}, {0x5f, 0xff, 0xaf}, {0x5f, 0xff, 0xd7}, {0x5f, 0xff, 0xff}, 0063 // {0x87, 0x00, 0x00}, {0x87, 0x00, 0x5f}, {0x87, 0x00, 0x87}, {0x87, 0x00, 0xaf}, 0064 // {0x87, 0x00, 0xd7}, {0x87, 0x00, 0xff}, {0x87, 0x5f, 0x00}, {0x87, 0x5f, 0x5f}, 0065 // {0x87, 0x5f, 0x87}, {0x87, 0x5f, 0xaf}, {0x87, 0x5f, 0xd7}, {0x87, 0x5f, 0xff}, 0066 // {0x87, 0x87, 0x00}, {0x87, 0x87, 0x5f}, {0x87, 0x87, 0x87}, {0x87, 0x87, 0xaf}, 0067 // {0x87, 0x87, 0xd7}, {0x87, 0x87, 0xff}, {0x87, 0xaf, 0x00}, {0x87, 0xaf, 0x5f}, 0068 // {0x87, 0xaf, 0x87}, {0x87, 0xaf, 0xaf}, {0x87, 0xaf, 0xd7}, {0x87, 0xaf, 0xff}, 0069 // {0x87, 0xd7, 0x00}, {0x87, 0xd7, 0x5f}, {0x87, 0xd7, 0x87}, {0x87, 0xd7, 0xaf}, 0070 // {0x87, 0xd7, 0xd7}, {0x87, 0xd7, 0xff}, {0x87, 0xff, 0x00}, {0x87, 0xff, 0x5f}, 0071 // {0x87, 0xff, 0x87}, {0x87, 0xff, 0xaf}, {0x87, 0xff, 0xd7}, {0x87, 0xff, 0xff}, 0072 // {0xaf, 0x00, 0x00}, {0xaf, 0x00, 0x5f}, {0xaf, 0x00, 0x87}, {0xaf, 0x00, 0xaf}, 0073 // {0xaf, 0x00, 0xd7}, {0xaf, 0x00, 0xff}, {0xaf, 0x5f, 0x00}, {0xaf, 0x5f, 0x5f}, 0074 // {0xaf, 0x5f, 0x87}, {0xaf, 0x5f, 0xaf}, {0xaf, 0x5f, 0xd7}, {0xaf, 0x5f, 0xff}, 0075 // {0xaf, 0x87, 0x00}, {0xaf, 0x87, 0x5f}, {0xaf, 0x87, 0x87}, {0xaf, 0x87, 0xaf}, 0076 // {0xaf, 0x87, 0xd7}, {0xaf, 0x87, 0xff}, {0xaf, 0xaf, 0x00}, {0xaf, 0xaf, 0x5f}, 0077 // {0xaf, 0xaf, 0x87}, {0xaf, 0xaf, 0xaf}, {0xaf, 0xaf, 0xd7}, {0xaf, 0xaf, 0xff}, 0078 // {0xaf, 0xd7, 0x00}, {0xaf, 0xd7, 0x5f}, {0xaf, 0xd7, 0x87}, {0xaf, 0xd7, 0xaf}, 0079 // {0xaf, 0xd7, 0xd7}, {0xaf, 0xd7, 0xff}, {0xaf, 0xff, 0x00}, {0xaf, 0xff, 0x5f}, 0080 // {0xaf, 0xff, 0x87}, {0xaf, 0xff, 0xaf}, {0xaf, 0xff, 0xd7}, {0xaf, 0xff, 0xff}, 0081 // {0xd7, 0x00, 0x00}, {0xd7, 0x00, 0x5f}, {0xd7, 0x00, 0x87}, {0xd7, 0x00, 0xaf}, 0082 // {0xd7, 0x00, 0xd7}, {0xd7, 0x00, 0xff}, {0xd7, 0x5f, 0x00}, {0xd7, 0x5f, 0x5f}, 0083 // {0xd7, 0x5f, 0x87}, {0xd7, 0x5f, 0xaf}, {0xd7, 0x5f, 0xd7}, {0xd7, 0x5f, 0xff}, 0084 // {0xd7, 0x87, 0x00}, {0xd7, 0x87, 0x5f}, {0xd7, 0x87, 0x87}, {0xd7, 0x87, 0xaf}, 0085 // {0xd7, 0x87, 0xd7}, {0xd7, 0x87, 0xff}, {0xd7, 0xaf, 0x00}, {0xd7, 0xaf, 0x5f}, 0086 // {0xd7, 0xaf, 0x87}, {0xd7, 0xaf, 0xaf}, {0xd7, 0xaf, 0xd7}, {0xd7, 0xaf, 0xff}, 0087 // {0xd7, 0xd7, 0x00}, {0xd7, 0xd7, 0x5f}, {0xd7, 0xd7, 0x87}, {0xd7, 0xd7, 0xaf}, 0088 // {0xd7, 0xd7, 0xd7}, {0xd7, 0xd7, 0xff}, {0xd7, 0xff, 0x00}, {0xd7, 0xff, 0x5f}, 0089 // {0xd7, 0xff, 0x87}, {0xd7, 0xff, 0xaf}, {0xd7, 0xff, 0xd7}, {0xd7, 0xff, 0xff}, 0090 // {0xff, 0x00, 0x00}, {0xff, 0x00, 0x5f}, {0xff, 0x00, 0x87}, {0xff, 0x00, 0xaf}, 0091 // {0xff, 0x00, 0xd7}, {0xff, 0x00, 0xff}, {0xff, 0x5f, 0x00}, {0xff, 0x5f, 0x5f}, 0092 // {0xff, 0x5f, 0x87}, {0xff, 0x5f, 0xaf}, {0xff, 0x5f, 0xd7}, {0xff, 0x5f, 0xff}, 0093 // {0xff, 0x87, 0x00}, {0xff, 0x87, 0x5f}, {0xff, 0x87, 0x87}, {0xff, 0x87, 0xaf}, 0094 // {0xff, 0x87, 0xd7}, {0xff, 0x87, 0xff}, {0xff, 0xaf, 0x00}, {0xff, 0xaf, 0x5f}, 0095 // {0xff, 0xaf, 0x87}, {0xff, 0xaf, 0xaf}, {0xff, 0xaf, 0xd7}, {0xff, 0xaf, 0xff}, 0096 // {0xff, 0xd7, 0x00}, {0xff, 0xd7, 0x5f}, {0xff, 0xd7, 0x87}, {0xff, 0xd7, 0xaf}, 0097 // {0xff, 0xd7, 0xd7}, {0xff, 0xd7, 0xff}, {0xff, 0xff, 0x00}, {0xff, 0xff, 0x5f}, 0098 // {0xff, 0xff, 0x87}, {0xff, 0xff, 0xaf}, {0xff, 0xff, 0xd7}, {0xff, 0xff, 0xff}, 0099 // {0x08, 0x08, 0x08}, {0x12, 0x12, 0x12}, {0x1c, 0x1c, 0x1c}, {0x26, 0x26, 0x26}, 0100 // {0x30, 0x30, 0x30}, {0x3a, 0x3a, 0x3a}, {0x44, 0x44, 0x44}, {0x4e, 0x4e, 0x4e}, 0101 // {0x58, 0x58, 0x58}, {0x62, 0x62, 0x62}, {0x6c, 0x6c, 0x6c}, {0x76, 0x76, 0x76}, 0102 // {0x80, 0x80, 0x80}, {0x8a, 0x8a, 0x8a}, {0x94, 0x94, 0x94}, {0x9e, 0x9e, 0x9e}, 0103 // {0xa8, 0xa8, 0xa8}, {0xb2, 0xb2, 0xb2}, {0xbc, 0xbc, 0xbc}, {0xc6, 0xc6, 0xc6}, 0104 // {0xd0, 0xd0, 0xd0}, {0xda, 0xda, 0xda}, {0xe4, 0xe4, 0xe4}, {0xee, 0xee, 0xee}, 0105 // }; 0106 0107 // xterm color represented in Oklab 0108 // see rgbToOklab() 0109 constexpr Lab xterm240_Oklabs[] { 0110 // ignore the first 16 colors as they are unpredictable (user configurable) 0111 // {0x0p+0, 0x0p+0, 0x0p+0}, 0112 // {0x1.2d5e6bee2c4f6p+5, 0x1.af99c042ea40cp+3, 0x1.e2f6ba84d2d25p+2}, 0113 // {0x1.9fcc4f3622914p+5, -0x1.c105bf1d2d218p+3, 0x1.586870aec30a4p+3}, 0114 // {0x1.d089126c75579p+5, -0x1.12107f2e3119p+2, 0x1.7d020b82d4b9cp+3}, 0115 // {0x1.b1ce15c4fcb51p+4, -0x1.f203762eb1242p+0, -0x1.2b150ae3c14bep+4}, 0116 // {0x1.50bc446f31833p+5, 0x1.078a1150b431ap+4, -0x1.44d35b3de7eafp+3}, 0117 // {0x1.b27d96eb8f471p+5, -0x1.1ee8867b0e065p+3, -0x1.2f2f18261c69ap+1}, 0118 // {0x1.431e523cc2f4dp+6, -0x1.ad694c777b8p-11, -0x1.c7c3ea0c32ep-8}, 0119 // {0x1.dfe5855ae1528p+5, -0x1.3ee1ad40618p-11, -0x1.5273b9784a3p-8}, 0120 // {0x1.f663baac570efp+5, 0x1.67be9f690c994p+4, 0x1.928e76c3750aep+3}, 0121 // {0x1.5a92b1ff8af32p+6, -0x1.76441609cfb3ap+4, 0x1.1f1186319beaap+4}, 0122 // {0x1.83323c984ee7ap+6, -0x1.c8df58716d4cbp+2, 0x1.3d9335b5d20f9p+4}, 0123 // {0x1.69950098864afp+5, -0x1.9f19c42a8c674p+1, -0x1.f293e325bec2ep+4}, 0124 // {0x1.18ac5c68852cdp+6, 0x1.b753a9bd5dbeep+4, -0x1.0ebf0dff35bfbp+4}, 0125 // {0x1.6a27499e4d3d6p+6, -0x1.de4892c062f8p+3, -0x1.f96a59bc9de4cp+1}, 0126 // {0x1.8ffffbb77c76ap+6, -0x1.09cab717214p-10, -0x1.1a1aa7765a7p-7}, 0127 // 240 colors mode 0128 {0x0p+0, 0x0p+0, 0x0p+0}, 0129 {0x1.5f181b2779cap+4, -0x1.930f78e22f09ap+0, -0x1.e41dbddfca08ap+3}, 0130 {0x1.c2d3be821f882p+4, -0x1.02c70dd8af008p+1, -0x1.36d1623919ffp+4}, 0131 {0x1.10a39beeb2926p+5, -0x1.38fe38b7dab01p+1, -0x1.77efa95d520b4p+4}, 0132 {0x1.3de43fe8d92efp+5, -0x1.6cf188320fff2p+1, -0x1.b655790a27192p+4}, 0133 {0x1.69950098864afp+5, -0x1.9f19c42a8c674p+1, -0x1.f293e325bec2ep+4}, 0134 {0x1.50853f46a9f9ep+5, -0x1.6b6901a80404fp+3, 0x1.16bdec11e60d8p+3}, 0135 {0x1.5fa625f2c3fbcp+5, -0x1.d0691ed5aa7ap+2, -0x1.eac16e8cb9241p+0}, 0136 {0x1.6f4222fc3f0dbp+5, -0x1.61b0e7ffa5e8ap+2, -0x1.05e8906ee23d7p+3}, 0137 {0x1.83e99e6187f46p+5, -0x1.1a61c98b895p+2, -0x1.c3da094bbcf2fp+3}, 0138 {0x1.9ca47689a503dp+5, -0x1.e9259e3439104p+1, -0x1.396812c634de3p+4}, 0139 {0x1.b872b55db6144p+5, -0x1.ccd50a2fd6662p+1, -0x1.89dec898ec996p+4}, 0140 {0x1.b01d15d276ef1p+5, -0x1.d2a4448f6ccacp+3, 0x1.65ec167dcb488p+3}, 0141 {0x1.b9760adf5c444p+5, -0x1.6a3760af4b6c4p+3, 0x1.a26bb322495e2p+1}, 0142 {0x1.c38a22a31944p+5, -0x1.2a2a93c4b741p+3, -0x1.3b14a376ffbecp+1}, 0143 {0x1.d185a36cfcd6ep+5, -0x1.e760f29e8fcb4p+2, -0x1.0bf936f2a6743p+3}, 0144 {0x1.e321d754f2b44p+5, -0x1.95a749a95debp+2, -0x1.c3928e31b9cf8p+3}, 0145 {0x1.f7eb8d9ad84b9p+5, -0x1.5e28b7cc193ddp+2, -0x1.38bda7259441ep+4}, 0146 {0x1.0552717cdb82p+6, -0x1.1a33f75f67b0fp+4, 0x1.b0e8bd24c3fdep+3}, 0147 {0x1.08898a5b7805dp+6, -0x1.e29bd3071d97ap+3, 0x1.e0b5994e0238ep+2}, 0148 {0x1.0c10ad1b87866p+6, -0x1.a54f2215371a5p+3, 0x1.45758e5457898p+1}, 0149 {0x1.1111e924447e9p+6, -0x1.68a24e1d5efe1p+3, -0x1.7d178a838ea32p+1}, 0150 {0x1.178bb94d30a5cp+6, -0x1.335d7d75dd017p+3, -0x1.13f78c003ba13p+3}, 0151 {0x1.1f6aa49fcff2p+6, -0x1.0830d167759a4p+3, -0x1.c578e33f21d88p+3}, 0152 {0x1.30b236b57ac86p+6, -0x1.490afbe3d8e11p+4, 0x1.f8c35fbb689dap+3}, 0153 {0x1.331144aae0ad4p+6, -0x1.289bac3eeb83p+4, 0x1.626ea3a63748p+3}, 0154 {0x1.35b09f5c62a7ap+6, -0x1.0d33e3db59803p+4, 0x1.b66836d6f7ff6p+2}, 0155 {0x1.3973d5b39baa4p+6, -0x1.de87e61f0c86ap+3, 0x1.de8cf8346969cp+0}, 0156 {0x1.3e64dbeab2c38p+6, -0x1.a47dea5d85dbbp+3, -0x1.bc586cdcba45p+1}, 0157 {0x1.44815d7f73a41p+6, -0x1.706c35b4850ecp+3, -0x1.1d13e731dfc5bp+3}, 0158 {0x1.5a92b1ff8af32p+6, -0x1.76441609cfb3ap+4, 0x1.1f1186319beaap+4}, 0159 {0x1.5c6885a0ab4cap+6, -0x1.5c0bf4148d03dp+4, 0x1.c5b4a75d0a01ep+3}, 0160 {0x1.5e72281eb918cp+6, -0x1.4422b7d2ad44bp+4, 0x1.5305a49da3492p+3}, 0161 {0x1.61631d5752788p+6, -0x1.282b31110d79dp+4, 0x1.8b1a60b561753p+2}, 0162 {0x1.65488920f4795p+6, -0x1.0b1a0cfacacfbp+4, 0x1.3d72a3bb176fp+0}, 0163 {0x1.6a27499e4d3d6p+6, -0x1.de4892c062f8p+3, -0x1.f96a59bc9de4cp+1}, 0164 {0x1.e7d1475ebe201p+4, 0x1.5d4f5ebb6cf8ep+3, 0x1.86e150bac0e61p+2}, 0165 {0x1.10883ee613f6bp+5, 0x1.aa957aceb4328p+3, -0x1.06e4a6bcf37ep+3}, 0166 {0x1.2a507c82ee1e7p+5, 0x1.880d450b132c9p+3, -0x1.c81b5ba73664ap+3}, 0167 {0x1.4902475f20191p+5, 0x1.4f4dfeda4e013p+3, -0x1.38d6c960a7255p+4}, 0168 {0x1.6aa42ff68fb65p+5, 0x1.1116140836dp+3, -0x1.84f2dbb4bf7b2p+4}, 0169 {0x1.8def7d6adc3d5p+5, 0x1.ab6406f65a5b9p+2, -0x1.caee116cbc66ep+4}, 0170 {0x1.77f724f99d0c9p+5, -0x1.bb9ee0e906bf2p+1, 0x1.345d15707c9e4p+3}, 0171 {0x1.8465d178eda3bp+5, -0x1.021519c6d64p-11, -0x1.11ebea130b3p-8}, 0172 {0x1.917d476fba08dp+5, 0x1.84e9b4b9a4816p+0, -0x1.89910d2df7414p+2}, 0173 {0x1.a32d016052029p+5, 0x1.352fbc1045df3p+1, -0x1.847eed4ab1e03p+3}, 0174 {0x1.b8cfd7baeb72ap+5, 0x1.5d6575ced028ep+1, -0x1.1bff70d82f589p+4}, 0175 {0x1.d1a20bfd91dbap+5, 0x1.4de285fe39a4dp+1, -0x1.6f381fca63bcep+4}, 0176 {0x1.c99e943a2d79fp+5, -0x1.219ec15c5de22p+3, 0x1.78f2db7cd8205p+3}, 0177 {0x1.d20af5c832c06p+5, -0x1.86c31353f2968p+2, 0x1.15f4d958ffb6ep+2}, 0178 {0x1.db2d2b76b7db4p+5, -0x1.107aa185fa178p+2, -0x1.3a545f6bb32fep+0}, 0179 {0x1.e7ef429658179p+5, -0x1.58a57459e2113p+1, -0x1.c50012145074dp+2}, 0180 {0x1.f821bad822a9ep+5, -0x1.8ea06e2a9e1f6p+0, -0x1.9a5cf82ebb612p+3}, 0181 {0x1.05b4f2f9696abp+6, -0x1.b3645fe7f9294p-1, -0x1.24f471b4e8b62p+4}, 0182 {0x1.0e4a1f1b1ddcep+6, -0x1.b32bbdf7204c1p+3, 0x1.be3e8e0b04a1fp+3}, 0183 {0x1.114fcf04f35b3p+6, -0x1.6696d5115c7e4p+3, 0x1.058704ea2708p+3}, 0184 {0x1.14a2558b5b6c7p+6, -0x1.2c7e211429d81p+3, 0x1.a9f809f8ee4dfp+1}, 0185 {0x1.195c00cf22a51p+6, -0x1.e58de99c40fb6p+2, -0x1.0e4f6479339a5p+1}, 0186 {0x1.1f7e4eea78cb7p+6, -0x1.809e6530a25d5p+2, -0x1.ee2cfac349d5ep+2}, 0187 {0x1.26f9f5da0f33bp+6, -0x1.2ffe0404fe1e4p+2, -0x1.a87af760f19c2p+3}, 0188 {0x1.37635555b270cp+6, -0x1.17deced6d377ep+4, 0x1.0159387931185p+4}, 0189 {0x1.39aa8b444a1c7p+6, -0x1.f1b4258b74e35p+3, 0x1.70a1d9ed49333p+3}, 0190 {0x1.3c30003dc4bdap+6, -0x1.bcf061cd62971p+3, 0x1.d845b8f464806p+2}, 0191 {0x1.3fcf0a7e4fdb8p+6, -0x1.8316f8fb04f1cp+3, 0x1.3be7d797ab219p+1}, 0192 {0x1.4492530767fa4p+6, -0x1.4af657f86bc35p+3, -0x1.69ccecfbead6p+1}, 0193 {0x1.4a78e7a0304fbp+6, -0x1.18be182ded159p+3, -0x1.07ac09ccdfff4p+3}, 0194 {0x1.5fc9ac083946p+6, -0x1.4f840d59cd9aep+4, 0x1.22ef620ec7775p+4}, 0195 {0x1.6192b2ae205fp+6, -0x1.361d4509435d5p+4, 0x1.cfe893676e62ep+3}, 0196 {0x1.638e487d443e1p+6, -0x1.1edcf418396fcp+4, 0x1.5f105a3f7b33p+3}, 0197 {0x1.666b5164f3799p+6, -0x1.03988ade0159ep+4, 0x1.a6a2e5baac692p+2}, 0198 {0x1.6a3706fa48d42p+6, -0x1.ce6b98f424c54p+3, 0x1.b67fa4fafc2e8p+0}, 0199 {0x1.6ef6b7860b53fp+6, -0x1.97ce09961f218p+3, -0x1.b926ed0fbe897p+1}, 0200 {0x1.3931bb83cb32dp+5, 0x1.c0894426a198dp+3, 0x1.f5ea328bf4058p+2}, 0201 {0x1.4b9e77eb58ebfp+5, 0x1.108cfd41d7919p+4, -0x1.0eaf04c8d3b35p+2}, 0202 {0x1.5df2d7bacd40ap+5, 0x1.11e15f9b225acp+4, -0x1.51924b9c514f3p+3}, 0203 {0x1.756bc7d79519bp+5, 0x1.03a63c750b36bp+4, -0x1.052fc194cf52p+4}, 0204 {0x1.90b3e1d276c5dp+5, 0x1.d79fd75fb3811p+3, -0x1.58e6a7a1da1fcp+4}, 0205 {0x1.aea5654d2d631p+5, 0x1.9f14550c88c57p+3, -0x1.a57e86563dbcap+4}, 0206 {0x1.9b6948efcb1e8p+5, 0x1.dddaa142e7b3ap+0, 0x1.4f83ba256abcfp+3}, 0207 {0x1.a5f9bfdb796c8p+5, 0x1.3de3647070a5bp+2, 0x1.b416b1e2a3817p+0}, 0208 {0x1.b1407c7a80b46p+5, 0x1.9d8674f672f17p+2, -0x1.112d7835e0443p+2}, 0209 {0x1.c0b6552db89b1p+5, 0x1.d8c2a5262b398p+2, -0x1.480f10f6d0b5fp+3}, 0210 {0x1.d3edc2b5ca1f7p+5, 0x1.edbf49a0778e4p+2, -0x1.fe5ca96caae15p+3}, 0211 {0x1.ea519f7b4bf8cp+5, 0x1.e35c8bfe38bf9p+2, -0x1.5483ed4b7e5ebp+4}, 0212 {0x1.e2c36ca30962cp+5, -0x1.1cd1878e91233p+2, 0x1.8bf558e4fbde3p+3}, 0213 {0x1.ea67769abd5c1p+5, -0x1.c053e5b6c3b66p+0, 0x1.59302161a2865p+2}, 0214 {0x1.f2ba2dd022991p+5, -0x1.4b64e809e68p-11, -0x1.5fbb8b338b8p-8}, 0215 {0x1.fe6b844bbf20fp+5, 0x1.8040f07e39554p+0, -0x1.7196ffd7de002p+2}, 0216 {0x1.06aeef460087dp+6, 0x1.4afa79e390244p+1, -0x1.705a7c8493135p+3}, 0217 {0x1.0fa5554a5c955p+6, 0x1.9dea7336ee828p+1, -0x1.1089bb9ca046ep+4}, 0218 {0x1.178e9051b853ep+6, -0x1.3b3b8e6c52f1cp+3, 0x1.cc268b9a4e157p+3}, 0219 {0x1.1a65db5c4c0d1p+6, -0x1.e697a167b2b86p+2, 0x1.1b4d0d1ca381dp+3}, 0220 {0x1.1d86bd983524p+6, -0x1.77ccb1bcef226p+2, 0x1.08e1384d16e75p+2}, 0221 {0x1.21fc7ad985402p+6, -0x1.08e3f099fb00fp+2, -0x1.363e6fbac8902p+0}, 0222 {0x1.27cb1d6dd9434p+6, -0x1.4f7ef424b1025p+1, -0x1.b1af4c945ce98p+2}, 0223 {0x1.2ee710ec206cfp+6, -0x1.6ac7f2787bda1p+0, -0x1.89e8c18db3849p+3}, 0224 {0x1.3e7c86695f695p+6, -0x1.ceac064fd3a97p+3, 0x1.06a67a74ff4cp+4}, 0225 {0x1.40ac0504d65f2p+6, -0x1.935bda5136fdbp+3, 0x1.7fa8ea5683dffp+3}, 0226 {0x1.4317a9d652f14p+6, -0x1.608608dcc2607p+3, 0x1.fc21edd271f8bp+2}, 0227 {0x1.46928cf49114ap+6, -0x1.2883a0410f74bp+3, 0x1.8d4b911a8102bp+1}, 0228 {0x1.4b27f53f2d1c8p+6, -0x1.e40f8922e26b2p+2, -0x1.11ca0bf0acee9p+1}, 0229 {0x1.50d83b6f7788bp+6, -0x1.82a0417f98419p+2, -0x1.e18432a6676edp+2}, 0230 {0x1.6567db05a012cp+6, -0x1.27d55f8b64f16p+4, 0x1.271e9400a42e4p+4}, 0231 {0x1.6723b3feab73ap+6, -0x1.0f412c5a09d1ap+4, 0x1.dae43f7f7eb6ep+3}, 0232 {0x1.6910cf423acf1p+6, -0x1.f152d3d18c3b3p+3, 0x1.6c04c44876eb2p+3}, 0233 {0x1.6bd948eca017fp+6, -0x1.bc29d2c53f57ap+3, 0x1.c44a28d107a62p+2}, 0234 {0x1.6f8a69cf10b1p+6, -0x1.84b224c6d040cp+3, 0x1.1c910c629db67p+1}, 0235 {0x1.7429ebc4e406dp+6, -0x1.4f4a0b735c531p+3, -0x1.73a39097eadefp+1}, 0236 {0x1.7acf7694f8c6p+5, 0x1.0f40ef4bed7e8p+4, 0x1.2f88d81b23f2ep+3}, 0237 {0x1.87b52573912c8p+5, 0x1.3e9cadbae2c71p+4, -0x1.21c127942ffc2p-1}, 0238 {0x1.95308092c646cp+5, 0x1.4bd8ec93cbe28p+4, -0x1.b1ad2fc6cd5ccp+2}, 0239 {0x1.a743d71712a69p+5, 0x1.4b428f09e4704p+4, -0x1.984b766ca527bp+3}, 0240 {0x1.bd35da1ada54ap+5, 0x1.3ee7b023f1a36p+4, -0x1.252f399063a3p+4}, 0241 {0x1.d638af110e2bfp+5, 0x1.2a6369728426p+4, -0x1.777a4238ecc9cp+4}, 0242 {0x1.c5db1e678f93bp+5, 0x1.be23ef0d11b9fp+2, 0x1.706e52e6555aep+3}, 0243 {0x1.ceab15b1e5e2cp+5, 0x1.376364145a451p+3, 0x1.d7fd2a954eedcp+1}, 0244 {0x1.d8302a174d63dp+5, 0x1.67a05469bf7c1p+3, -0x1.0236bbe6ffddap+1}, 0245 {0x1.e56c6a282c6fep+5, 0x1.8915eed9a5994p+3, -0x1.fb2d49a257381p+2}, 0246 {0x1.f622a3ef65e7fp+5, 0x1.98638aed6156bp+3, -0x1.b57e66e36241ap+3}, 0247 {0x1.04f5c4d9c25cfp+6, 0x1.9710ff57a7b7ap+3, -0x1.32004fe7bd5b5p+4}, 0248 {0x1.018127d59826cp+6, 0x1.1e619caaa3a8fp-1, 0x1.a49bd0215a96dp+3}, 0249 {0x1.04e57659b4cf6p+6, 0x1.8024718692a3cp+1, 0x1.addd1b874609p+2}, 0250 {0x1.089bd543a0e63p+6, 0x1.2a7652607e02cp+2, 0x1.8d85013677bap+0}, 0251 {0x1.0ddb424d04fadp+6, 0x1.889c9b8223651p+2, -0x1.05aa1bc86a9d4p+2}, 0252 {0x1.149da8fbd8909p+6, 0x1.ce4542c130c31p+2, -0x1.3934aac98d184p+3}, 0253 {0x1.1cca409e32c6dp+6, 0x1.f855300b25ba5p+2, -0x1.eac45e49f86bap+3}, 0254 {0x1.23f3e081f0e6fp+6, -0x1.587d5d644e818p+2, 0x1.deea03a7e9e2p+3}, 0255 {0x1.26935d2d5bb58p+6, -0x1.a6ab45ebb79ddp+1, 0x1.38265c4c6d156p+3}, 0256 {0x1.29783d4927cb6p+6, -0x1.aa081e388f0b6p+0, 0x1.4de28afb99798p+2}, 0257 {0x1.2d9b5abdd0df6p+6, -0x1.90d2c34c4c8p-11, -0x1.a96c3913736p-8}, 0258 {0x1.3303704c60227p+6, 0x1.7842d686da2p+0, -0x1.6001098473213p+2}, 0259 {0x1.39a911d79bf6cp+6, 0x1.51ae39272f6fp+1, -0x1.604eff9e13224p+3}, 0260 {0x1.483b66bb75f41p+6, -0x1.53e4a65e5bd0ep+3, 0x1.0dfa4f4feec89p+4}, 0261 {0x1.4a4cab5bdb777p+6, -0x1.1bf0c7950b46ap+3, 0x1.9433415e2e559p+3}, 0262 {0x1.4c9756fc325a6p+6, -0x1.d6e499fe26166p+2, 0x1.1693b52228314p+3}, 0263 {0x1.4fe3e8502420ap+6, -0x1.6b29463056a7ep+2, 0x1.fcea504279e1bp+1}, 0264 {0x1.543e4f84c51c9p+6, -0x1.01c201c3fcfbep+2, -0x1.311b349896504p+0}, 0265 {0x1.59a86b698fe17p+6, -0x1.4697ac30fd276p+1, -0x1.a218614573a54p+2}, 0266 {0x1.6d3f94c53849cp+6, -0x1.e750c3b6abf94p+3, 0x1.2cfd8e3a3298cp+4}, 0267 {0x1.6ee9ffc7c561bp+6, -0x1.b847cb4caca9ap+3, 0x1.ea32a397a5ea3p+3}, 0268 {0x1.70c3ef56a2364p+6, -0x1.8cc812a446223p+3, 0x1.7e0dc7e1aa4eep+3}, 0269 {0x1.737125604c02dp+6, -0x1.5959ff3792892p+3, 0x1.ed9e6884d6db8p+2}, 0270 {0x1.76fef3ccb11e4p+6, -0x1.2379a952d29eap+3, 0x1.77d044e094287p+1}, 0271 {0x1.7b739668b58adp+6, -0x1.def62d62ac5d3p+2, -0x1.1242c0559f9b9p+1}, 0272 {0x1.b9af6705b3e1ap+5, 0x1.3c46b4e4aa724p+4, 0x1.61ea416f62116p+3}, 0273 {0x1.c34652a386648p+5, 0x1.673d5400dac6ap+4, 0x1.575529f864e4ap+1}, 0274 {0x1.cd90a5a7155efp+5, 0x1.7aac661c86347p+4, -0x1.97f5d2781d1d2p+1}, 0275 {0x1.dbc2183aadc6dp+5, 0x1.83f34257f81ecp+4, -0x1.24c7f27451716p+3}, 0276 {0x1.ed84b050fd5fep+5, 0x1.823e0b9a9286fp+4, -0x1.dc10370a896a1p+3}, 0277 {0x1.012d3f7585d8bp+6, 0x1.772916c92c8cp+4, -0x1.444d46ad4a3f5p+4}, 0278 {0x1.f498a57d50c8dp+5, 0x1.72c50647a1b01p+3, 0x1.9501b7bc92a26p+3}, 0279 {0x1.fbec5add8799fp+5, 0x1.c10937ac1ff0cp+3, 0x1.71506b03a0cfcp+2}, 0280 {0x1.01f4d75996fc6p+6, 0x1.f168c838b27a5p+3, 0x1.a2871b4170f08p-2}, 0281 {0x1.07934868d42f1p+6, 0x1.0ba82dcee8d5fp+4, -0x1.55f50c12fdb69p+2}, 0282 {0x1.0ec4c024626fep+6, 0x1.16b4701bb2cep+4, -0x1.627c9a1b01177p+3}, 0283 {0x1.1768d8b0aa031p+6, 0x1.199f4e2e9e65fp+4, -0x1.09c1c4e924702p+4}, 0284 {0x1.14522a4a9a7e2p+6, 0x1.6020b0a7ecac7p+2, 0x1.c1a8f99df62d9p+3}, 0285 {0x1.174b930ef061ap+6, 0x1.ec83068a9839fp+2, 0x1.06f134f7cc07ep+3}, 0286 {0x1.1a90921a38fe7p+6, 0x1.28d89eb448a2cp+3, 0x1.ab5fe99a94265p+1}, 0287 {0x1.1f36b9520ad75p+6, 0x1.57ace8397fb96p+3, -0x1.0feb2da7758d4p+1}, 0288 {0x1.253f2b741784fp+6, 0x1.7c087d08384b1p+3, -0x1.efdb49212f992p+2}, 0289 {0x1.2c9a998952cf1p+6, 0x1.9366b5a4edd8ap+3, -0x1.a9848b6099745p+3}, 0290 {0x1.330541ae3e385p+6, -0x1.39e238ea7801p-1, 0x1.f5ec9f058d778p+3}, 0291 {0x1.3568ff8940412p+6, 0x1.4b2aea6a2b17bp+0, 0x1.5aadb9534e15p+3}, 0292 {0x1.380d495b09ffp+6, 0x1.6b2260c162acep+1, 0x1.a0b3e40fdedfp+2}, 0293 {0x1.3bd6db55a86abp+6, 0x1.1c0894632c07ep+2, 0x1.73acfbc73a52cp+0}, 0294 {0x1.40ced5740b6ecp+6, 0x1.784d8d5bd59bap+2, -0x1.f87f29ae0432ap+1}, 0295 {0x1.46f1d56d6a627p+6, 0x1.c2acec311d85p+2, -0x1.2d078d1d0ec93p+3}, 0296 {0x1.54692a261ff77p+6, -0x1.91aafde5841e2p+2, 0x1.1733b7c5acf09p+4}, 0297 {0x1.5657fb0185f53p+6, -0x1.292fef1c6094ap+2, 0x1.adacb9827ba1ep+3}, 0298 {0x1.587cf8c168362p+6, -0x1.9aa045411de21p+1, 0x1.34f47fa15abacp+3}, 0299 {0x1.5b946ca219efdp+6, -0x1.98465c0dc7b2ap+0, 0x1.43ded9d06d2f2p+2}, 0300 {0x1.5faadb5249c01p+6, -0x1.d35a0bdd6ap-11, -0x1.f008c176226p-8}, 0301 {0x1.64c3b31613c93p+6, 0x1.6ffd305ac700dp+0, -0x1.52580b551209ep+2}, 0302 {0x1.773c645e32d2dp+6, -0x1.6c001f7fba478p+3, 0x1.3482f283026fp+4}, 0303 {0x1.78d215b19332bp+6, -0x1.3f6c1cce8d703p+3, 0x1.fda06ae8dbf53p+3}, 0304 {0x1.7a9531dc8addap+6, -0x1.15dd42d16c7e4p+3, 0x1.94e8098e96fccp+3}, 0305 {0x1.7d21e2193d5bcp+6, -0x1.c8c718caa9f8ep+2, 0x1.1105d830d79dp+3}, 0306 {0x1.808572bc9578ap+6, -0x1.607bf910c57eep+2, 0x1.ebe2b93545493p+1}, 0307 {0x1.84c6a7914070fp+6, -0x1.f6c2ba3dfc25ap+1, -0x1.2beab2de5e36ep+0}, 0308 {0x1.f663baac570efp+5, 0x1.67be9f690c994p+4, 0x1.928e76c3750aep+3}, 0309 {0x1.fdd78bfa0c16bp+5, 0x1.8da11d29326eap+4, 0x1.63128e5e5d16fp+2}, 0310 {0x1.02fa8211ca545p+6, 0x1.a3a4c44447321p+4, 0x1.04d0a318f0ebp-3}, 0311 {0x1.08ace6a6b1bbcp+6, 0x1.b32f97fdc6c72p+4, -0x1.69ea7f28a916ap+2}, 0312 {0x1.0ff3cb8943e81p+6, 0x1.b9bf03db71bbbp+4, -0x1.6cb54bc7e9c6p+3}, 0313 {0x1.18ac5c68852cdp+6, 0x1.b753a9bd5dbeep+4, -0x1.0ebf0dff35bfbp+4}, 0314 {0x1.12e57190e4906p+6, 0x1.f7243f8456bc9p+3, 0x1.bbbf019d6f15fp+3}, 0315 {0x1.15f567ae01685p+6, 0x1.1e238872ebfe1p+4, 0x1.f5db81101607bp+2}, 0316 {0x1.1952176f81196p+6, 0x1.35eb43e1b3454p+4, 0x1.6f044118da651p+1}, 0317 {0x1.1e17b3f5be1e9p+6, 0x1.4aa233635e996p+4, -0x1.54536023af51fp+1}, 0318 {0x1.244540fde90c8p+6, 0x1.590428a4cd957p+4, -0x1.09fd595c81312p+3}, 0319 {0x1.2bc8d270727cdp+6, 0x1.6002d76c0fae1p+4, -0x1.bbbb8dd0769e1p+3}, 0320 {0x1.2910051d7f4b8p+6, 0x1.4505f3d8c93bep+3, 0x1.e1f0441f64aep+3}, 0321 {0x1.2ba848891bba1p+6, 0x1.83d80a13be75dp+3, 0x1.39f759ee811ebp+3}, 0322 {0x1.2e852380cafc2p+6, 0x1.b3d439de20201p+3, 0x1.5018eb1694a48p+2}, 0323 {0x1.329c951f395aap+6, 0x1.e28db45c54996p+3, 0x1.689e197414bp-7}, 0324 {0x1.37f5013da44b7p+6, 0x1.04846845ce376p+4, -0x1.5f9623aa14c25p+2}, 0325 {0x1.3e86c9cea44c3p+6, 0x1.11f59319394fdp+4, -0x1.6049926fe33dap+3}, 0326 {0x1.443efb939f1d1p+6, 0x1.0a131d35fab88p+2, 0x1.0838884c6c35ap+4}, 0327 {0x1.4667729b66dbap+6, 0x1.793a281884d1p+2, 0x1.8155ad5254ba1p+3}, 0328 {0x1.48cb51f255527p+6, 0x1.d609d14c020d1p+2, 0x1.fd82e0735fdcep+2}, 0329 {0x1.4c3af36c4bb13p+6, 0x1.1c709781a9fb2p+3, 0x1.8ca66dc4e33fdp+1}, 0330 {0x1.50c14ed0ba88bp+6, 0x1.4a1d653379591p+3, -0x1.14ee52d3fd0e1p+1}, 0331 {0x1.565e87fd89a8p+6, 0x1.6fe5c4c37980fp+3, -0x1.e3e3e3d81f648p+2}, 0332 {0x1.62b687ada6a2dp+6, -0x1.b1a7c98c53b9bp+0, 0x1.221d2fc2be6cp+4}, 0333 {0x1.6480f342fedfap+6, -0x1.728e49c5a9ba8p-3, 0x1.cb44060a17de8p+3}, 0334 {0x1.667e081a8e931p+6, 0x1.2c204353d8acp+0, 0x1.582d07a1ac706p+3}, 0335 {0x1.695d03a4b4ea6p+6, 0x1.5b9dd1e5192c9p+1, 0x1.949cc8da7db3dp+2}, 0336 {0x1.6d2ad25b49139p+6, 0x1.10c661536b1e3p+2, 0x1.60b9aee667ea2p+0}, 0337 {0x1.71ec510363cccp+6, 0x1.6b2af260ca3f1p+2, -0x1.e8e3d6769ed61p+1}, 0338 {0x1.83323c984ee7ap+6, -0x1.c8df58716d4cbp+2, 0x1.3d9335b5d20f9p+4}, 0339 {0x1.84b109344c92cp+6, -0x1.750134f94569cp+2, 0x1.0a63166d3ca32p+4}, 0340 {0x1.865ae5967696dp+6, -0x1.260f129da839ep+2, 0x1.b00f6d0ac1f93p+3}, 0341 {0x1.88c3891dbffdp+6, -0x1.8e7bf5d542ea4p+1, 0x1.30323669c3d67p+3}, 0342 {0x1.8bf825267af8ep+6, -0x1.89d8c0f2ba1ffp+0, 0x1.3b2af0c9eed76p+2}, 0343 {0x1.8ffffbb77c76ap+6, -0x1.09cab717214p-10, -0x1.1a1aa7765a7p-7}, 0344 {0x1.ae1c063cf8075p+3, -0x1.1dcc8d6b21p-13, -0x1.2f56d49352fp-10}, 0345 {0x1.23869fde6955fp+4, -0x1.836d13c82dp-13, -0x1.9b340cb2926p-10}, 0346 {0x1.6a51d9755cb1ep+4, -0x1.e1821bf6d08p-13, -0x1.ff0f3c5806ap-10}, 0347 {0x1.adca073d0c9a1p+4, -0x1.1d961152df8p-12, -0x1.2f1d00745cap-9}, 0348 {0x1.eeb26a3638306p+4, -0x1.48b751f0a58p-12, -0x1.5ce3e1a3db8p-9}, 0349 {0x1.16c4868a9dbc4p+5, -0x1.7278906708p-12, -0x1.89352628678p-9}, 0350 {0x1.3552cb4726ed2p+5, -0x1.9b140ac6fbp-12, -0x1.b44e9f2325p-9}, 0351 {0x1.53242132979b2p+5, -0x1.c2b46f9c328p-12, -0x1.de5d99b6f9p-9}, 0352 {0x1.7051013cf5a69p+5, -0x1.e97a44c10a8p-12, -0x1.03c24d5b897p-8}, 0353 {0x1.8ceca3a0569fdp+5, -0x1.07bf8a7e0fcp-11, -0x1.17ef5f1c441p-8}, 0354 {0x1.a9067ed63306p+5, -0x1.1a6bb67a6bp-11, -0x1.2bc0e9df0a8p-8}, 0355 {0x1.c4ab42f91535bp+5, -0x1.2cca14a233p-11, -0x1.3f3fe0662d2p-8}, 0356 {0x1.dfe5855ae1528p+5, -0x1.3ee1ad40618p-11, -0x1.5273b9784a3p-8}, 0357 {0x1.fabe397d15c9dp+5, -0x1.50b872fc158p-11, -0x1.6562c531248p-8}, 0358 {0x1.0a9e8459f8d9ap+6, -0x1.62537d1958p-11, -0x1.78126ad030ep-8}, 0359 {0x1.17b44990f13f5p+6, -0x1.73b732a42fp-11, -0x1.8a87568ccdp-8}, 0360 {0x1.24a350705ddf4p+6, -0x1.84e76b1c308p-11, -0x1.9cc59c424aap-8}, 0361 {0x1.316e23ed9d96ap+6, -0x1.95e7879947p-11, -0x1.aed0d2216dp-8}, 0362 {0x1.3e1704b29c069p+6, -0x1.a6ba8679e08p-11, -0x1.c0ac258f992p-8}, 0363 {0x1.4a9ff4d8984e6p+6, -0x1.b76312f3808p-11, -0x1.d25a6bb27acp-8}, 0364 {0x1.570ac151c1615p+6, -0x1.c7e3919c138p-11, -0x1.e3de2eb684p-8}, 0365 {0x1.6359098c40c61p+6, -0x1.d83e2a89bbp-11, -0x1.f539b894d66p-8}, 0366 {0x1.6f8c45b456692p+6, -0x1.e874d1a7f5p-11, -0x1.03378df3804p-7}, 0367 {0x1.7ba5cbe12c3fcp+6, -0x1.f8894d9602p-11, -0x1.0bc01d99c93p-7}, 0368 }; 0369 0370 // Perform the inverse gamma companding for a sRGB color 0371 // http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html 0372 // double inverseGammaCompanding(int c) { 0373 // // [0, 255] to [0, 1] 0374 // double v = c / 255.0; 0375 // if (v <= 0.04045) { 0376 // return v / 12.92; 0377 // } 0378 // return std::pow((v + 0.055) / 1.055, 2.4); 0379 // }; 0380 constexpr double RGB888_to_sRGB_table[] { 0381 0x0p+0, 0x1.3e45677c176f7p-12, 0x1.3e45677c176f7p-11, 0x1.dd681b3a23272p-11, 0382 0x1.3e45677c176f7p-10, 0x1.8dd6c15b1d4b4p-10, 0x1.dd681b3a23272p-10, 0x1.167cba8c94818p-9, 0383 0x1.3e45677c176f7p-9, 0x1.660e146b9a5d6p-9, 0x1.8dd6c15b1d4b4p-9, 0x1.b6a31b5259c99p-9, 0384 0x1.e1e31d70c99ddp-9, 0x1.07c38bf8583a9p-8, 0x1.1fcc2beed6421p-8, 0x1.390ffaf95e279p-8, 0385 0x1.53936cc7bc928p-8, 0x1.6f5addb50c915p-8, 0x1.8c6a94031b561p-8, 0x1.aac6c0fb97351p-8, 0386 0x1.ca7381f9f602bp-8, 0x1.eb74e160978dp-8, 0x1.06e76bbda92b8p-7, 0x1.18c2a5a8a8044p-7, 0387 0x1.2b4e09b3f0ae3p-7, 0x1.3e8b7b3bde965p-7, 0x1.527cd60af8b85p-7, 0x1.6723eea8d3709p-7, 0388 0x1.7c8292a3db6b3p-7, 0x1.929a88d67b521p-7, 0x1.a96d91a8016bdp-7, 0x1.c0fd67499fab6p-7, 0389 0x1.d94bbdefd740ep-7, 0x1.f25a44089883fp-7, 0x1.061551372c694p-6, 0x1.135f3e4c2cce2p-6, 0390 0x1.210bb8642b172p-6, 0x1.2f1b8c1ae46bdp-6, 0x1.3d8f839b79c0bp-6, 0x1.4c6866b3e9fa4p-6, 0391 0x1.5ba6fae794313p-6, 0x1.6b4c0380d2deep-6, 0x1.7b5841a1bf3acp-6, 0x1.8bcc74542addbp-6, 0392 0x1.9ca95898dc8b5p-6, 0x1.adefa9761c02p-6, 0x1.bfa0200597bd9p-6, 0x1.d1bb7381aec1fp-6, 0393 0x1.e442595227bcap-6, 0x1.f73585185e1b5p-6, 0x1.054ad45d76878p-5, 0x1.0f31ba386ff26p-5, 0394 0x1.194fcb663747bp-5, 0x1.23a55e62a662ap-5, 0x1.2e32c8e148d11p-5, 0x1.38f85fd21eacfp-5, 0395 0x1.43f67766310ffp-5, 0x1.4f2d6313fa8dp-5, 0x1.5a9d759ba5edp-5, 0x1.6647010b254eep-5, 0396 0x1.722a56c2239eep-5, 0x1.7e47c775d2427p-5, 0x1.8a9fa33494b07p-5, 0x1.973239698b9ccp-5, 0397 0x1.a3ffd8e001389p-5, 0x1.b108cfc6b7fbcp-5, 0x1.be4d6bb31d522p-5, 0x1.cbcdf9a4616f2p-5, 0398 0x1.d98ac60675833p-5, 0x1.e7841cb4f16dfp-5, 0x1.f5ba48fde2048p-5, 0x1.0216cad240765p-4, 0399 0x1.096f2671eb815p-4, 0x1.10e65c38a5192p-4, 0x1.187c90bf8bce2p-4, 0x1.2031e85f5d6dap-4, 0400 0x1.28068731a1952p-4, 0x1.2ffa9111cb94bp-4, 0x1.380e299e53f92p-4, 0x1.40417439ca10fp-4, 0401 0x1.4894940bddbfbp-4, 0x1.5107ac0261e59p-4, 0x1.599aded247aacp-4, 0x1.624e4ef892ed4p-4, 0402 0x1.6b221ebb4817ep-4, 0x1.7416702a539d1p-4, 0x1.7d2b65206b527p-4, 0x1.86611f43e9e6ap-4, 0403 0x1.8fb7c007a4a7p-4, 0x1.992f68abbbc89p-4, 0x1.a2c83a3e6566dp-4, 0x1.ac82559cb3644p-4, 0404 0x1.b65ddb7354604p-4, 0x1.c05aec3f4fe5ep-4, 0x1.ca79a84ebe03p-4, 0x1.d4ba2fc17a6a5p-4, 0405 0x1.df1ca289d34b8p-4, 0x1.e9a1206d34003p-4, 0x1.f447c904cbb4ep-4, 0x1.ff10bbbe302c2p-4, 0406 0x1.04fe0bedfe5f1p-3, 0x1.0a84fe3b36d8fp-3, 0x1.101d443dfc06fp-3, 0x1.15c6ed58eefdfp-3, 0407 0x1.1b8208da5fefp-3, 0x1.214ea5fc9514ap-3, 0x1.272cd3e610123p-3, 0x1.2d1ca1a9d1cfbp-3, 0408 0x1.331e1e479cdf5p-3, 0x1.393158ac3674ep-3, 0x1.3f565fb1a5fd5p-3, 0x1.458d421f735dfp-3, 0409 0x1.4bd60eaae3e73p-3, 0x1.5230d3f736034p-3, 0x1.589da095dbaa1p-3, 0x1.5f1c8306b3a3cp-3, 0410 0x1.65ad89b841a2bp-3, 0x1.6c50c307e53bfp-3, 0x1.73063d420fc8p-3, 0x1.79ce06a279303p-3, 0411 0x1.80a82d5453b5dp-3, 0x1.8794bf727eb3fp-3, 0x1.8e93cb07b8679p-3, 0x1.95a55e0ecec0bp-3, 0412 0x1.9cc98672cf47ep-3, 0x1.a400520f3619cp-3, 0x1.ab49ceb01c003p-3, 0x1.b2a60a1263b0ap-3, 0413 0x1.ba1511e3e632dp-3, 0x1.c196f3c39e76fp-3, 0x1.c92bbd41d41fep-3, 0x1.d0d37be045851p-3, 0414 0x1.d88e3d1250f68p-3, 0x1.e05c0e3d1d3ep-3, 0x1.e83cfcb7c16fp-3, 0x1.f03115cb6bfd3p-3, 0415 0x1.f83866b38924dp-3, 0x1.00297e4ef4553p-2, 0x1.044072557177ap-2, 0x1.086115f6beb3ap-2, 0416 0x1.0c8b6fb5c735ep-2, 0x1.10bf860ef039ap-2, 0x1.14fd5f782a5a6p-2, 0x1.1945026102997p-2, 0417 0x1.1d967532b31b1p-2, 0x1.21f1be50339e7p-2, 0x1.2656e41649ae3p-2, 0x1.2ac5ecdb988f8p-2, 0418 0x1.2f3edef0b0ed8p-2, 0x1.33c1c0a020438p-2, 0x1.384e982e800b1p-2, 0x1.3ce56bda84a81p-2, 0419 0x1.418641dd0c1bcp-2, 0x1.463120692c7afp-2, 0x1.4ae60dac4229dp-2, 0x1.4fa50fcdfde15p-2, 0420 0x1.546e2cf0727a9p-2, 0x1.59416b3022858p-2, 0x1.5e1ed0a40daabp-2, 0x1.6306635dbdd7bp-2, 0421 0x1.67f82969543a2p-2, 0x1.6cf428cd96079p-2, 0x1.71fa678bf915dp-2, 0x1.770aeba0b042ap-2, 0422 0x1.7c25bb02b7ac5p-2, 0x1.814adba3e0bd9p-2, 0x1.867a5370de0b1p-2, 0x1.8bb428514f067p-2, 0423 0x1.90f86027cb84ep-2, 0x1.964700d1ef1b1p-2, 0x1.9ba0102864521p-2, 0x1.a10393feefafdp-2, 0424 0x1.a67192247a9bep-2, 0x1.abea10631e195p-2, 0x1.b16d14802d5cap-2, 0x1.b6faa43c403bbp-2, 0425 0x1.bc92c5533d785p-2, 0x1.c2357d7c64e5dp-2, 0x1.c7e2d26a596dep-2, 0x1.cd9ac9cb2aef2p-2, 0426 0x1.d35d69485ffc5p-2, 0x1.d92ab686ff782p-2, 0x1.df02b7279a10dp-2, 0x1.e4e570c6539c5p-2, 0427 0x1.ead2e8faec526p-2, 0x1.f0cb2558c9ea4p-2, 0x1.f6ce2b6f00983p-2, 0x1.fcdc00c85bec2p-2, 0428 0x1.017a5575b3cb2p-1, 0x1.048c17ad3c04bp-1, 0x1.07a349c9d9837p-1, 0x1.0abfee888c05p-1, 0429 0x1.0de208a4444c8p-1, 0x1.11099ad5e83ebp-1, 0x1.1436a7d456eefp-1, 0x1.176932546ca12p-1, 0430 0x1.1aa13d0906bdap-1, 0x1.1ddecaa307b85p-1, 0x1.2121ddd15aecep-1, 0x1.246a7940f86d1p-1, 0431 0x1.27b89f9ce8c4bp-1, 0x1.2b0c538e48b07p-1, 0x1.2e6597bc4ccap-1, 0x1.31c46ecc4528dp-1, 0432 0x1.3528db61a0f73p-1, 0x1.3892e01df1fccp-1, 0x1.3c027fa0f01ebp-1, 0x1.3f77bc887cd3bp-1, 0433 0x1.42f29970a68f8p-1, 0x1.467318f3ac22dp-1, 0x1.49f93daa00113p-1, 0x1.4d850a2a4bde1p-1, 0434 0x1.51168109734e5p-1, 0x1.54ada4da97a1bp-1, 0x1.584a782f1ac23p-1, 0x1.5becfd96a2698p-1, 0435 0x1.5f95379f1b3edp-1, 0x1.634328d4bbe97p-1, 0x1.66f6d3c2081cfp-1, 0x1.6ab03aefd39aap-1, 0436 0x1.6e6f60e5452b1p-1, 0x1.72344827d98f6p-1, 0x1.75fef33b6669bp-1, 0x1.79cf64a21d1e2p-1, 0437 0x1.7da59edc8dabp-1, 0x1.8181a469a9787p-1, 0x1.856377c6c6224p-1, 0x1.894b1b6fa0377p-1, 0438 0x1.8d3891de5df49p-1, 0x1.912bdd8b91f45p-1, 0x1.952500ee3dda5p-1, 0x1.9923fe7bd4f67p-1, 0439 0x1.9d28d8a83edfcp-1, 0x1.a13391e5da09fp-1, 0x1.a5442ca57e52ep-1, 0x1.a95aab567f88fp-1, 0440 0x1.ad771066afec2p-1, 0x1.b1995e4262a69p-1, 0x1.b5c197546e3f8p-1, 0x1.b9efbe062f086p-1, 0441 0x1.be23d4bf8981bp-1, 0x1.c25ddde6ecbbbp-1, 0x1.c69ddbe154af1p-1, 0x1.cae3d1124c90bp-1, 0442 0x1.cf2fbfdbf11f1p-1, 0x1.d381aa9ef2e82p-1, 0x1.d7d993ba988d4p-1, 0x1.dc377d8cc0fd5p-1, 0443 0x1.e09b6a71e5aa6p-1, 0x1.e5055cc51cbb4p-1, 0x1.e97556e01b351p-1, 0x1.edeb5b1b37216p-1, 0444 0x1.f2676bcd69adep-1, 0x1.f6e98b4c51466p-1, 0x1.fb71bbec33ab2p-1, 0x1p+0, 0445 }; 0446 // clang-format on 0447 0448 // convert a RGB color to Oklab (https://bottosson.github.io/posts/oklab/) 0449 Lab rgbToOklab(QRgb rgb) 0450 { 0451 const double r = RGB888_to_sRGB_table[qRed(rgb)]; 0452 const double g = RGB888_to_sRGB_table[qGreen(rgb)]; 0453 const double b = RGB888_to_sRGB_table[qBlue(rgb)]; 0454 0455 const double l = std::cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b); 0456 const double m = std::cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b); 0457 const double s = std::cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b); 0458 0459 // M2 * 100 * {l', m', s'} 0460 return Lab{ 0461 (021.04542553 * l + 079.36177850 * m - 000.40720468 * s), 0462 (197.79984951 * l - 242.85922050 * m + 045.05937099 * s), 0463 (002.59040371 * l + 078.27717662 * m - 080.86757660 * s), 0464 }; 0465 } 0466 0467 constexpr double epsilon = 1e-15; 0468 0469 inline double sinDegree(double x) 0470 { 0471 return std::sin(x * M_PI / 180.0); 0472 } 0473 0474 inline double cosDegree(double x) 0475 { 0476 return std::cos(x * M_PI / 180.0); 0477 } 0478 0479 inline double pow2(double x) 0480 { 0481 return x * x; 0482 } 0483 0484 inline double computeHPrime(double a_prime, double b) 0485 { 0486 if (std::abs(a_prime) < epsilon && std::abs(b) < epsilon) { 0487 return 0.0; 0488 } 0489 0490 const double value = std::atan2(b, a_prime) * 180.0 / M_PI; 0491 return (value < 0.0) ? value + 360.0 : value; 0492 } 0493 0494 inline double computeDeltaHPrime(double C1_prime, double C2_prime, double h1_prime, double h2_prime) 0495 { 0496 if (C1_prime * C2_prime < epsilon) { 0497 return 0.0; 0498 } 0499 0500 const double diff = h2_prime - h1_prime; 0501 0502 if (std::abs(diff) <= 180.0) { 0503 return diff; 0504 } else if (diff > 180.0) { 0505 return diff - 360.0; 0506 } else { 0507 return diff + 360.0; 0508 } 0509 } 0510 0511 inline double computeHPrimeBar(double C1_prime, double C2_prime, double h1_prime, double h2_prime) 0512 { 0513 const double sum = h1_prime + h2_prime; 0514 0515 if (C1_prime * C2_prime < epsilon) { 0516 return sum; 0517 } 0518 0519 const double dist = std::abs(h1_prime - h2_prime); 0520 0521 if (dist <= 180.0) { 0522 return 0.5 * sum; 0523 } else if (sum < 360.0) { 0524 return 0.5 * (sum + 360.0); 0525 } else { 0526 return 0.5 * (sum - 360.0); 0527 } 0528 } 0529 0530 /// Calculate the perceptual color difference based on CIEDE2000. 0531 /// https://en.wikipedia.org/wiki/Color_difference#CIEDE2000 0532 /// \return The color difference of the two colors. 0533 double calculate_CIEDE2000(const Lab &color1, const Lab &color2) 0534 { 0535 const double L1 = color1.L; 0536 const double a1 = color1.a; 0537 const double b1 = color1.b; 0538 const double L2 = color2.L; 0539 const double a2 = color2.a; 0540 const double b2 = color2.b; 0541 0542 const double _25_pow_7 = /*std::pow(25.0, 7.0) = */ 6103515625.0; 0543 0544 const double C1_ab = std::sqrt(a1 * a1 + b1 * b1); 0545 const double C2_ab = std::sqrt(a2 * a2 + b2 * b2); 0546 const double C_ab_bar = 0.5 * (C1_ab + C2_ab); 0547 const double c_ab_bar_pow_7 = std::pow(C_ab_bar, 7.0); 0548 const double G = 0.5 * (1.0 - std::sqrt(c_ab_bar_pow_7 / (c_ab_bar_pow_7 + _25_pow_7))); 0549 const double a1_prime = (1.0 + G) * a1; 0550 const double a2_prime = (1.0 + G) * a2; 0551 const double C1_prime = std::sqrt(a1_prime * a1_prime + b1 * b1); 0552 const double C2_prime = std::sqrt(a2_prime * a2_prime + b2 * b2); 0553 const double h1_prime = computeHPrime(a1_prime, b1); 0554 const double h2_prime = computeHPrime(a2_prime, b2); 0555 0556 const double deltaL_prime = L2 - L1; 0557 const double deltaC_prime = C2_prime - C1_prime; 0558 const double deltah_prime = computeDeltaHPrime(C1_prime, C2_prime, h1_prime, h2_prime); 0559 const double deltaH_prime = 2.0 * std::sqrt(C1_prime * C2_prime) * sinDegree(0.5 * deltah_prime); 0560 0561 const double L_primeBar = 0.5 * (L1 + L2); 0562 const double C_primeBar = 0.5 * (C1_prime + C2_prime); 0563 const double h_primeBar = computeHPrimeBar(C1_prime, C2_prime, h1_prime, h2_prime); 0564 0565 const double T = 1.0 - 0.17 * cosDegree(h_primeBar - 30.0) + 0.24 * cosDegree(2.0 * h_primeBar) + 0.32 * cosDegree(3.0 * h_primeBar + 6.0) 0566 - 0.20 * cosDegree(4.0 * h_primeBar - 63.0); 0567 0568 const double C_primeBar_pow7 = std::pow(C_primeBar, 7.0); 0569 const double R_C = 2.0 * std::sqrt(C_primeBar_pow7 / (C_primeBar_pow7 + _25_pow_7)); 0570 const double S_L = 1.0 + (0.015 * pow2(L_primeBar - 50.0)) / std::sqrt(20.0 + pow2(L_primeBar - 50.0)); 0571 const double S_C = 1.0 + 0.045 * C_primeBar; 0572 const double S_H = 1.0 + 0.015 * C_primeBar * T; 0573 const double R_T = -R_C * sinDegree(60.0 * std::exp(-pow2((h_primeBar - 275) / 25.0))); 0574 0575 constexpr double kL = 1.0; 0576 constexpr double kC = 1.0; 0577 constexpr double kH = 1.0; 0578 0579 const double deltaL = deltaL_prime / (kL * S_L); 0580 const double deltaC = deltaC_prime / (kC * S_C); 0581 const double deltaH = deltaH_prime / (kH * S_H); 0582 0583 return /*std::sqrt*/ (deltaL * deltaL + deltaC * deltaC + deltaH * deltaH + R_T * deltaC * deltaH); 0584 } 0585 0586 struct AnsiBuffer { 0587 using ColorCache = QHash<QRgb, int>; 0588 0589 void append(char c) 0590 { 0591 Q_ASSERT(remaining() >= 1); 0592 m_data[m_size] = c; 0593 ++m_size; 0594 } 0595 0596 void append(QLatin1String str) 0597 { 0598 Q_ASSERT(remaining() >= str.size()); 0599 memcpy(m_data + m_size, str.data(), str.size()); 0600 m_size += str.size(); 0601 } 0602 0603 void appendForeground(QRgb rgb, bool is256Colors, ColorCache &colorCache) 0604 { 0605 append(QLatin1String("38;")); 0606 append(rgb, is256Colors, colorCache); 0607 } 0608 0609 void appendBackground(QRgb rgb, bool is256Colors, ColorCache &colorCache) 0610 { 0611 append(QLatin1String("48;")); 0612 append(rgb, is256Colors, colorCache); 0613 } 0614 0615 void append(QRgb rgb, bool is256Colors, ColorCache &colorCache) 0616 { 0617 auto appendUInt8 = [&](int x) { 0618 Q_ASSERT(x <= 255 && x >= 0); 0619 if (x > 99) { 0620 if (x >= 200) { 0621 append('2'); 0622 x -= 200; 0623 } else { 0624 append('1'); 0625 x -= 100; 0626 } 0627 } else if (x < 10) { 0628 append(char('0' + x)); 0629 return; 0630 } 0631 0632 // clang-format off 0633 constexpr char const* tb2digits = 0634 "00" "01" "02" "03" "04" "05" "06" "07" "08" "09" 0635 "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" 0636 "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" 0637 "30" "31" "32" "33" "34" "35" "36" "37" "38" "39" 0638 "40" "41" "42" "43" "44" "45" "46" "47" "48" "49" 0639 "50" "51" "52" "53" "54" "55" "56" "57" "58" "59" 0640 "60" "61" "62" "63" "64" "65" "66" "67" "68" "69" 0641 "70" "71" "72" "73" "74" "75" "76" "77" "78" "79" 0642 "80" "81" "82" "83" "84" "85" "86" "87" "88" "89" 0643 "90" "91" "92" "93" "94" "95" "96" "97" "98" "99"; 0644 // clang-format on 0645 0646 auto *p = tb2digits + x * 2; 0647 append(p[0]); 0648 append(p[1]); 0649 }; 0650 0651 if (is256Colors) { 0652 double dist = 1e24; 0653 int idx = 0; 0654 auto it = colorCache.find(rgb); 0655 if (it == colorCache.end()) { 0656 const auto lab = rgbToOklab(rgb); 0657 // find the nearest xterm color 0658 for (Lab const &xtermLab : xterm240_Oklabs) { 0659 auto dist2 = calculate_CIEDE2000(lab, xtermLab); 0660 if (dist2 < dist) { 0661 dist = dist2; 0662 idx = &xtermLab - xterm240_Oklabs; 0663 } 0664 } 0665 // add 16 to convert 240 colors mode to 256 colors mode 0666 idx += 16; 0667 colorCache.insert(rgb, idx); 0668 } else { 0669 idx = it.value(); 0670 } 0671 0672 append('5'); 0673 append(';'); 0674 appendUInt8(idx); 0675 } else { 0676 append('2'); 0677 append(';'); 0678 appendUInt8(qRed(rgb)); 0679 append(';'); 0680 appendUInt8(qGreen(rgb)); 0681 append(';'); 0682 appendUInt8(qBlue(rgb)); 0683 } 0684 append(';'); 0685 } 0686 0687 // Replace last character with 'm'. Last character must be ';' 0688 void setFinalStyle() 0689 { 0690 Q_ASSERT(m_data[m_size - 1] == ';'); 0691 m_data[m_size - 1] = 'm'; 0692 } 0693 0694 void clear() 0695 { 0696 m_size = 0; 0697 } 0698 0699 QLatin1String latin1() const 0700 { 0701 return QLatin1String(m_data, m_size); 0702 } 0703 0704 private: 0705 char m_data[128]; 0706 int m_size = 0; 0707 0708 int remaining() const noexcept 0709 { 0710 return 128 - m_size; 0711 } 0712 }; 0713 0714 void fillString(QString &s, int n, QStringView fill) 0715 { 0716 if (n > 0) { 0717 for (; n > fill.size(); n -= fill.size()) { 0718 s += fill; 0719 } 0720 s += fill.left(n); 0721 } 0722 } 0723 0724 struct GraphLine { 0725 QString graphLine; 0726 QString labelLine; 0727 int graphLineLength = 0; 0728 int labelLineLength = 0; 0729 int nextLabelOffset = 0; 0730 0731 template<class String> 0732 void pushLabel(int offset, String const &s, int numberDisplayableChar) 0733 { 0734 Q_ASSERT(offset >= labelLineLength); 0735 const int n = offset - labelLineLength; 0736 labelLineLength += numberDisplayableChar + n; 0737 fillLine(labelLine, n); 0738 labelLine += s; 0739 nextLabelOffset = labelLineLength; 0740 } 0741 0742 template<class String> 0743 void pushGraph(int offset, String const &s, int numberDisplayableChar) 0744 { 0745 Q_ASSERT(offset >= graphLineLength); 0746 const int n = offset - graphLineLength; 0747 graphLineLength += numberDisplayableChar + n; 0748 fillLine(graphLine, n); 0749 const int ps1 = graphLine.size(); 0750 graphLine += s; 0751 if (offset >= labelLineLength) { 0752 const int n2 = offset - labelLineLength; 0753 labelLineLength += n2 + 1; 0754 fillLine(labelLine, n2); 0755 labelLine += QStringView(graphLine).right(graphLine.size() - ps1); 0756 } 0757 } 0758 0759 private: 0760 static void fillLine(QString &s, int n) 0761 { 0762 Q_ASSERT(n >= 0); 0763 fillString(s, 0764 n, 0765 QStringLiteral(" " 0766 " " 0767 " ")); 0768 } 0769 }; 0770 0771 /** 0772 * Returns the first free line at a given position or create a new one 0773 */ 0774 GraphLine &lineAtOffset(std::vector<GraphLine> &graphLines, int offset) 0775 { 0776 const auto last = graphLines.end(); 0777 auto p = std::find_if(graphLines.begin(), last, [=](GraphLine const &line) { 0778 return line.nextLabelOffset < offset; 0779 }); 0780 if (p == last) { 0781 graphLines.emplace_back(); 0782 return graphLines.back(); 0783 } 0784 return *p; 0785 } 0786 0787 // disable bold, italic and underline on | 0788 const QLatin1String graphSymbol("\x1b[22;23;24m|"); 0789 // reverse video 0790 const QLatin1String nameStyle("\x1b[7m"); 0791 0792 /** 0793 * ANSI Highlighter dedicated to traces 0794 */ 0795 class DebugSyntaxHighlighter : public KSyntaxHighlighting::AbstractHighlighter 0796 { 0797 public: 0798 using Option = KSyntaxHighlighting::AnsiHighlighter::Option; 0799 using Options = KSyntaxHighlighting::AnsiHighlighter::Options; 0800 0801 void setDefinition(const KSyntaxHighlighting::Definition &def) override 0802 { 0803 AbstractHighlighter::setDefinition(def); 0804 m_contextCapture.setDefinition(def); 0805 0806 const auto &definitions = def.includedDefinitions(); 0807 for (const auto &definition : definitions) { 0808 const auto *defData = DefinitionData::get(definition); 0809 for (const auto &context : defData->contexts) { 0810 m_defDataBycontexts.insert(&context, defData); 0811 } 0812 } 0813 } 0814 0815 void highlightData(QTextStream &in, 0816 QTextStream &out, 0817 QLatin1String infoStyle, 0818 QLatin1String editorBackground, 0819 const std::vector<QPair<QString, QString>> &ansiStyles, 0820 Options options) 0821 { 0822 initRegionStyles(ansiStyles); 0823 0824 m_hasFormatTrace = options.testFlag(Option::TraceFormat); 0825 m_hasRegionTrace = options.testFlag(Option::TraceRegion); 0826 m_hasStackSizeTrace = options.testFlag(Option::TraceStackSize); 0827 m_hasContextTrace = options.testFlag(Option::TraceContext); 0828 const bool hasFormatOrContextTrace = m_hasFormatTrace || m_hasContextTrace || m_hasStackSizeTrace; 0829 0830 const bool hasSeparator = hasFormatOrContextTrace && m_hasRegionTrace; 0831 const QString resetBgColor = (editorBackground.isEmpty() ? QStringLiteral("\x1b[0m") : editorBackground); 0832 0833 bool firstLine = true; 0834 State state; 0835 QString currentLine; 0836 const bool isUnbuffered = options.testFlag(Option::Unbuffered); 0837 while (in.readLineInto(¤tLine)) { 0838 auto oldState = state; 0839 state = highlightLine(currentLine, state); 0840 0841 if (hasSeparator) { 0842 if (!firstLine) { 0843 out << QStringLiteral("\x1b[0m────────────────────────────────────────────────────\x1b[K\n"); 0844 } 0845 firstLine = false; 0846 } 0847 0848 if (!m_regions.empty()) { 0849 printRegions(out, infoStyle, currentLine.size()); 0850 out << resetBgColor; 0851 } 0852 0853 for (const auto &fragment : m_highlightedFragments) { 0854 auto const &ansiStyle = ansiStyles[fragment.formatId]; 0855 out << ansiStyle.first << QStringView(currentLine).mid(fragment.offset, fragment.length) << ansiStyle.second; 0856 } 0857 0858 out << QStringLiteral("\x1b[K\n"); 0859 0860 if (hasFormatOrContextTrace && !m_highlightedFragments.empty()) { 0861 if (m_hasContextTrace || m_hasStackSizeTrace) { 0862 appendContextNames(oldState, currentLine); 0863 } 0864 0865 printFormats(out, infoStyle, ansiStyles); 0866 out << resetBgColor; 0867 } 0868 0869 m_highlightedFragments.clear(); 0870 0871 if (isUnbuffered) { 0872 out.flush(); 0873 } 0874 } 0875 } 0876 0877 void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override 0878 { 0879 m_highlightedFragments.push_back({m_hasFormatTrace ? format.name() : QString(), offset, length, format.id()}); 0880 } 0881 0882 void applyFolding(int offset, int /*length*/, FoldingRegion region) override 0883 { 0884 if (!m_hasRegionTrace) { 0885 return; 0886 } 0887 0888 const auto id = region.id(); 0889 0890 if (region.type() == FoldingRegion::Begin) { 0891 m_regions.push_back(Region{m_regionDepth, offset, -1, id, Region::State::Open}); 0892 // swap with previous region if this is a closing region with same offset in order to superimpose labels 0893 if (m_regions.size() >= 2) { 0894 auto &previousRegion = m_regions[m_regions.size() - 2]; 0895 if (previousRegion.state == Region::State::Close && previousRegion.offset == offset) { 0896 std::swap(previousRegion, m_regions.back()); 0897 if (previousRegion.bindIndex != -1) { 0898 m_regions[previousRegion.bindIndex].bindIndex = m_regions.size() - 1; 0899 } 0900 } 0901 } 0902 ++m_regionDepth; 0903 } else { 0904 // find open region 0905 auto it = m_regions.rbegin(); 0906 auto eit = m_regions.rend(); 0907 for (int depth = 0; it != eit; ++it) { 0908 if (it->regionId == id && it->bindIndex < 0) { 0909 if (it->state == Region::State::Close) { 0910 ++depth; 0911 } else if (--depth < 0) { 0912 break; 0913 } 0914 } 0915 } 0916 0917 if (it != eit) { 0918 it->bindIndex = int(m_regions.size()); 0919 int bindIndex = int(&*it - m_regions.data()); 0920 m_regions.push_back(Region{it->depth, offset, bindIndex, id, Region::State::Close}); 0921 } else { 0922 m_regions.push_back(Region{-1, offset, -1, id, Region::State::Close}); 0923 } 0924 0925 m_regionDepth = std::max(m_regionDepth - 1, 0); 0926 } 0927 } 0928 0929 using KSyntaxHighlighting::AbstractHighlighter::highlightLine; 0930 0931 private: 0932 /** 0933 * Initializes with colors of \p ansiStyle without duplicate. 0934 */ 0935 void initRegionStyles(const std::vector<QPair<QString, QString>> &ansiStyles) 0936 { 0937 m_regionStyles.resize(ansiStyles.size()); 0938 for (std::size_t i = 0; i < m_regionStyles.size(); ++i) { 0939 m_regionStyles[i] = ansiStyles[i].first; 0940 } 0941 0942 std::sort(m_regionStyles.begin(), m_regionStyles.end()); 0943 m_regionStyles.erase(std::unique(m_regionStyles.begin(), m_regionStyles.end()), m_regionStyles.end()); 0944 } 0945 0946 /** 0947 * Append the context name in front of the format name. 0948 */ 0949 void appendContextNames(State &state, QStringView currentLine) 0950 { 0951 auto newState = state; 0952 for (auto &fragment : m_highlightedFragments) { 0953 QString contextName = extractContextName(StateData::get(newState)); 0954 0955 m_contextCapture.offsetNext = 0; 0956 m_contextCapture.lengthNext = 0; 0957 // truncate the line to deduce the context from the format 0958 const auto lineFragment = currentLine.mid(0, fragment.offset + fragment.length + 1); 0959 newState = m_contextCapture.highlightLine(lineFragment, state); 0960 0961 // Deduced context does not start at the position of the format. 0962 // This can happen because of lookAhead/fallthrought attribute, 0963 // assertion in regex, etc. 0964 if (m_contextCapture.offset != fragment.offset && m_contextCapture.length != fragment.length) { 0965 contextName.insert(0, QLatin1Char('~')); 0966 } 0967 fragment.name.insert(0, contextName); 0968 } 0969 } 0970 0971 /** 0972 * \return Current context name with definition name if different 0973 * from the current definition name 0974 */ 0975 QString extractContextName(StateData *stateData) const 0976 { 0977 QString label; 0978 0979 if (m_hasStackSizeTrace) { 0980 // first state is empty 0981 int stateSize = stateData ? stateData->size() : 0; 0982 label = QLatin1Char('(') % QString::number(stateSize) % QLatin1Char(')'); 0983 } 0984 0985 if (m_hasContextTrace) { 0986 // first state is empty 0987 if (!stateData) { 0988 return label + QStringLiteral("[???]"); 0989 } 0990 0991 const auto context = stateData->topContext(); 0992 const auto defDataIt = m_defDataBycontexts.find(context); 0993 const auto contextName = (defDataIt != m_defDataBycontexts.end()) ? QString(QLatin1Char('<') % (*defDataIt)->name % QLatin1Char('>')) : QString(); 0994 return QString(label % contextName % QLatin1Char('[') % context->name() % QLatin1Char(']')); 0995 } 0996 0997 return label; 0998 } 0999 1000 void printFormats(QTextStream &out, QLatin1String regionStyle, const std::vector<QPair<QString, QString>> &ansiStyles) 1001 { 1002 // init graph 1003 m_formatGraph.clear(); 1004 for (auto const &fragment : m_highlightedFragments) { 1005 GraphLine &line = lineAtOffset(m_formatGraph, fragment.offset); 1006 auto const &style = ansiStyles[fragment.formatId].first; 1007 line.pushLabel(fragment.offset, style % nameStyle % fragment.name % regionStyle, fragment.name.size()); 1008 1009 for (GraphLine *pline = m_formatGraph.data(); pline <= &line; ++pline) { 1010 pline->pushGraph(fragment.offset, style % graphSymbol % regionStyle, 1); 1011 } 1012 } 1013 1014 // display graph 1015 out << regionStyle; 1016 auto first = m_formatGraph.begin(); 1017 auto last = m_formatGraph.end(); 1018 --last; 1019 for (; first != last; ++first) { 1020 out << first->graphLine << "\x1b[K\n" << first->labelLine << "\x1b[K\n"; 1021 } 1022 out << first->graphLine << "\x1b[K\n" << first->labelLine << "\x1b[K\x1b[0m\n"; 1023 } 1024 1025 void printRegions(QTextStream &out, QLatin1String regionStyle, int lineLength) 1026 { 1027 const QString continuationLine = QStringLiteral( 1028 "------------------------------" 1029 "------------------------------" 1030 "------------------------------"); 1031 1032 bool hasContinuation = false; 1033 1034 m_regionGraph.clear(); 1035 QString label; 1036 QString numStr; 1037 1038 // init graph 1039 for (Region ®ion : m_regions) { 1040 if (region.state == Region::State::Continuation) { 1041 hasContinuation = true; 1042 continue; 1043 } 1044 1045 auto pushGraphs = [&](int offset, const GraphLine *endline, QStringView style) { 1046 for (GraphLine *pline = m_regionGraph.data(); pline <= endline; ++pline) { 1047 // a label can hide a graph 1048 if (pline->graphLineLength <= offset) { 1049 pline->pushGraph(offset, style % graphSymbol % regionStyle, 1); 1050 } 1051 } 1052 }; 1053 1054 QChar openChar; 1055 QChar closeChar; 1056 int lpad = 0; 1057 int rpad = 0; 1058 1059 int offsetLabel = region.offset; 1060 1061 numStr.setNum(region.regionId); 1062 1063 if (region.state == Region::State::Open) { 1064 openChar = QLatin1Char('('); 1065 if (region.bindIndex == -1) { 1066 rpad = lineLength - region.offset - numStr.size(); 1067 } else { 1068 rpad = m_regions[region.bindIndex].offset - region.offset - 2; 1069 closeChar = QLatin1Char(')'); 1070 } 1071 // close without open 1072 } else if (region.bindIndex == -1) { 1073 closeChar = QLatin1Char('>'); 1074 // label already present, we only display the graph 1075 } else if (m_regions[region.bindIndex].state == Region::State::Open) { 1076 const auto &openRegion = m_regions[region.bindIndex]; 1077 // here offset is a graph index 1078 const GraphLine &line = m_regionGraph[openRegion.offset]; 1079 const auto &style = m_regionStyles[openRegion.depth % m_regionStyles.size()]; 1080 pushGraphs(region.offset, &line, style); 1081 continue; 1082 } else { 1083 closeChar = QLatin1Char(')'); 1084 lpad = region.offset - numStr.size(); 1085 offsetLabel = 0; 1086 } 1087 1088 const QStringView openS(&openChar, openChar.unicode() ? 1 : 0); 1089 const QStringView closeS(&closeChar, closeChar.unicode() ? 1 : 0); 1090 1091 label.clear(); 1092 fillString(label, lpad, continuationLine); 1093 label += numStr; 1094 fillString(label, rpad, continuationLine); 1095 1096 GraphLine &line = lineAtOffset(m_regionGraph, offsetLabel); 1097 const auto &style = m_regionStyles[region.depth % m_regionStyles.size()]; 1098 line.pushLabel(offsetLabel, style % nameStyle % openS % label % closeS % regionStyle, label.size() + openS.size() + closeS.size()); 1099 pushGraphs(region.offset, &line, style); 1100 1101 // transforms offset into graph index when region is on 1 line 1102 if (region.state == Region::State::Open && region.bindIndex != -1) { 1103 region.offset = &line - m_regionGraph.data(); 1104 } 1105 } 1106 1107 out << regionStyle; 1108 1109 // display regions which are neither closed nor open 1110 if (hasContinuation) { 1111 label.clear(); 1112 fillString(label, lineLength ? lineLength : 5, continuationLine); 1113 for (const auto ®ion : m_regions) { 1114 if (region.state == Region::State::Continuation && region.bindIndex == -1) { 1115 const auto &style = m_regionStyles[region.depth % m_regionStyles.size()]; 1116 out << style << nameStyle << label << regionStyle << "\x1b[K\n"; 1117 } 1118 } 1119 } 1120 1121 // display graph 1122 if (!m_regionGraph.empty()) { 1123 auto first = m_regionGraph.rbegin(); 1124 auto last = m_regionGraph.rend(); 1125 --last; 1126 for (; first != last; ++first) { 1127 out << first->labelLine << "\x1b[K\n" << first->graphLine << "\x1b[K\n"; 1128 } 1129 out << first->labelLine << "\x1b[K\n" << first->graphLine << "\x1b[K\x1b[0m\n"; 1130 } 1131 1132 // keep regions that are not closed 1133 m_regions.erase(std::remove_if(m_regions.begin(), 1134 m_regions.end(), 1135 [](Region const ®ion) { 1136 return region.bindIndex != -1 || region.state == Region::State::Close; 1137 }), 1138 m_regions.end()); 1139 // all remaining regions become Continuation 1140 for (auto ®ion : m_regions) { 1141 region.offset = 0; 1142 region.state = Region::State::Continuation; 1143 } 1144 } 1145 1146 struct HighlightFragment { 1147 QString name; 1148 int offset; 1149 int length; 1150 int formatId; 1151 }; 1152 1153 struct ContextCaptureHighlighter : KSyntaxHighlighting::AbstractHighlighter { 1154 int offset; 1155 int length; 1156 int offsetNext; 1157 int lengthNext; 1158 1159 void applyFormat(int offset, int length, const KSyntaxHighlighting::Format & /*format*/) override 1160 { 1161 offset = offsetNext; 1162 length = lengthNext; 1163 offsetNext = offset; 1164 lengthNext = length; 1165 } 1166 1167 using KSyntaxHighlighting::AbstractHighlighter::highlightLine; 1168 }; 1169 1170 struct Region { 1171 enum class State : int8_t { 1172 Open, 1173 Close, 1174 Continuation, 1175 }; 1176 1177 int depth; 1178 int offset; 1179 int bindIndex; 1180 int regionId; 1181 State state; 1182 }; 1183 1184 bool m_hasFormatTrace; 1185 bool m_hasRegionTrace; 1186 bool m_hasStackSizeTrace; 1187 bool m_hasContextTrace; 1188 1189 std::vector<HighlightFragment> m_highlightedFragments; 1190 std::vector<GraphLine> m_formatGraph; 1191 ContextCaptureHighlighter m_contextCapture; 1192 1193 int m_regionDepth = 0; 1194 std::vector<Region> m_regions; 1195 std::vector<GraphLine> m_regionGraph; 1196 std::vector<QStringView> m_regionStyles; 1197 1198 QHash<const Context *, const DefinitionData *> m_defDataBycontexts; 1199 }; 1200 } // anonymous namespace 1201 1202 class KSyntaxHighlighting::AnsiHighlighterPrivate : public AbstractHighlighterPrivate 1203 { 1204 public: 1205 QTextStream out; 1206 QFile file; 1207 QStringView currentLine; 1208 // pairs of startColor / resetColor 1209 std::vector<QPair<QString, QString>> ansiStyles; 1210 }; 1211 1212 AnsiHighlighter::AnsiHighlighter() 1213 : AbstractHighlighter(new AnsiHighlighterPrivate()) 1214 { 1215 } 1216 1217 AnsiHighlighter::~AnsiHighlighter() = default; 1218 1219 void AnsiHighlighter::setOutputFile(const QString &fileName) 1220 { 1221 Q_D(AnsiHighlighter); 1222 if (d->file.isOpen()) { 1223 d->file.close(); 1224 } 1225 d->file.setFileName(fileName); 1226 if (!d->file.open(QFile::WriteOnly | QFile::Truncate)) { 1227 qCWarning(Log) << "Failed to open output file" << fileName << ":" << d->file.errorString(); 1228 return; 1229 } 1230 d->out.setDevice(&d->file); 1231 } 1232 1233 void AnsiHighlighter::setOutputFile(FILE *fileHandle) 1234 { 1235 Q_D(AnsiHighlighter); 1236 d->file.open(fileHandle, QIODevice::WriteOnly); 1237 d->out.setDevice(&d->file); 1238 } 1239 1240 void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, Options options) 1241 { 1242 QFileInfo fi(fileName); 1243 QFile f(fileName); 1244 if (!f.open(QFile::ReadOnly)) { 1245 qCWarning(Log) << "Failed to open input file" << fileName << ":" << f.errorString(); 1246 return; 1247 } 1248 1249 highlightData(&f, format, options); 1250 } 1251 1252 void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, Options options) 1253 { 1254 Q_D(AnsiHighlighter); 1255 1256 if (!d->out.device()) { 1257 qCWarning(Log) << "No output stream defined!"; 1258 return; 1259 } 1260 1261 const auto is256Colors = (format == AnsiFormat::XTerm256Color); 1262 const auto &theme = d->m_theme; 1263 const auto &definition = d->m_definition; 1264 1265 auto definitions = definition.includedDefinitions(); 1266 definitions.append(definition); 1267 1268 AnsiBuffer::ColorCache colorCache; 1269 1270 AnsiBuffer foregroundColorBuffer; 1271 AnsiBuffer backgroundColorBuffer; 1272 QLatin1String foregroundDefaultColor; 1273 QLatin1String backgroundDefaultColor; 1274 1275 const bool useEditorBackground = options.testFlag(Option::UseEditorBackground); 1276 1277 // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters 1278 1279 if (useEditorBackground) { 1280 const QRgb foregroundColor = theme.textColor(Theme::Normal); 1281 const QRgb backgroundColor = theme.editorColor(Theme::BackgroundColor); 1282 foregroundColorBuffer.appendForeground(foregroundColor, is256Colors, colorCache); 1283 backgroundColorBuffer.append(QLatin1String("\x1b[")); 1284 backgroundColorBuffer.appendBackground(backgroundColor, is256Colors, colorCache); 1285 foregroundDefaultColor = foregroundColorBuffer.latin1(); 1286 backgroundDefaultColor = backgroundColorBuffer.latin1().mid(2); 1287 } 1288 1289 int maxId = 0; 1290 for (const auto &definition : std::as_const(definitions)) { 1291 for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { 1292 maxId = qMax(maxId, format.id()); 1293 } 1294 } 1295 d->ansiStyles.clear(); 1296 // ansiStyles must not be empty for applyFormat to work even with a definition without any context 1297 d->ansiStyles.resize(maxId + 1); 1298 1299 // initialize ansiStyles 1300 for (const auto &definition : std::as_const(definitions)) { 1301 for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { 1302 AnsiBuffer buffer; 1303 1304 buffer.append(QLatin1String("\x1b[")); 1305 1306 const bool hasFg = format.hasTextColor(theme); 1307 const bool hasBg = format.hasBackgroundColor(theme); 1308 const bool hasBold = format.isBold(theme); 1309 const bool hasItalic = format.isItalic(theme); 1310 const bool hasUnderline = format.isUnderline(theme); 1311 const bool hasStrikeThrough = format.isStrikeThrough(theme); 1312 1313 if (hasFg) { 1314 buffer.appendForeground(format.textColor(theme).rgb(), is256Colors, colorCache); 1315 } else { 1316 buffer.append(foregroundDefaultColor); 1317 } 1318 if (hasBg) { 1319 buffer.appendBackground(format.backgroundColor(theme).rgb(), is256Colors, colorCache); 1320 } 1321 if (hasBold) { 1322 buffer.append(QLatin1String("1;")); 1323 } 1324 if (hasItalic) { 1325 buffer.append(QLatin1String("3;")); 1326 } 1327 if (hasUnderline) { 1328 buffer.append(QLatin1String("4;")); 1329 } 1330 if (hasStrikeThrough) { 1331 buffer.append(QLatin1String("9;")); 1332 } 1333 1334 // if there is ANSI style 1335 if (buffer.latin1().size() > 2) { 1336 buffer.setFinalStyle(); 1337 auto &style = d->ansiStyles[format.id()]; 1338 style.first = buffer.latin1(); 1339 1340 if (useEditorBackground) { 1341 buffer.clear(); 1342 const bool hasEffect = hasBold || hasItalic || hasUnderline || hasStrikeThrough; 1343 if (hasBg) { 1344 buffer.append(hasEffect ? QLatin1String("\x1b[0;") : QLatin1String("\x1b[")); 1345 buffer.append(backgroundDefaultColor); 1346 buffer.setFinalStyle(); 1347 style.second = buffer.latin1(); 1348 } else if (hasEffect) { 1349 buffer.append(QLatin1String("\x1b[")); 1350 if (hasBold) { 1351 buffer.append(QLatin1String("22;")); 1352 } 1353 if (hasItalic) { 1354 buffer.append(QLatin1String("23;")); 1355 } 1356 if (hasUnderline) { 1357 buffer.append(QLatin1String("24;")); 1358 } 1359 if (hasStrikeThrough) { 1360 buffer.append(QLatin1String("29;")); 1361 } 1362 buffer.setFinalStyle(); 1363 style.second = buffer.latin1(); 1364 } 1365 } else { 1366 style.second = QStringLiteral("\x1b[0m"); 1367 } 1368 } 1369 } 1370 } 1371 1372 if (useEditorBackground) { 1373 backgroundColorBuffer.setFinalStyle(); 1374 backgroundDefaultColor = backgroundColorBuffer.latin1(); 1375 d->out << backgroundDefaultColor; 1376 } 1377 1378 QTextStream in(dev); 1379 1380 if (!options.testAnyFlag(Option::TraceAll)) { 1381 State state; 1382 QString currentLine; 1383 const bool isUnbuffered = options.testFlag(Option::Unbuffered); 1384 while (in.readLineInto(¤tLine)) { 1385 d->currentLine = currentLine; 1386 state = highlightLine(d->currentLine, state); 1387 1388 if (useEditorBackground) { 1389 d->out << QStringLiteral("\x1b[K\n"); 1390 } else { 1391 d->out << QLatin1Char('\n'); 1392 } 1393 1394 if (isUnbuffered) { 1395 d->out.flush(); 1396 } 1397 } 1398 } else { 1399 AnsiBuffer buffer; 1400 buffer.append(QLatin1String("\x1b[0;")); 1401 buffer.appendBackground(theme.editorColor(useEditorBackground ? Theme::TemplateBackground : Theme::BackgroundColor), is256Colors, colorCache); 1402 buffer.setFinalStyle(); 1403 DebugSyntaxHighlighter debugHighlighter; 1404 debugHighlighter.setDefinition(definition); 1405 debugHighlighter.highlightData(in, d->out, buffer.latin1(), backgroundDefaultColor, d->ansiStyles, options); 1406 } 1407 1408 if (useEditorBackground) { 1409 d->out << QStringLiteral("\x1b[0m"); 1410 } 1411 1412 d->out.setDevice(nullptr); 1413 d->file.close(); 1414 d->ansiStyles.clear(); 1415 } 1416 1417 void AnsiHighlighter::applyFormat(int offset, int length, const Format &format) 1418 { 1419 Q_D(AnsiHighlighter); 1420 auto const &ansiStyle = d->ansiStyles[format.id()]; 1421 d->out << ansiStyle.first << d->currentLine.mid(offset, length) << ansiStyle.second; 1422 }