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