Branch data Line data Source code
1 : : #ifdef RUN_TESTS
2 : : # include <gtest/gtest.h>
3 : : #endif
4 : : /** @file rendering/color.cc
5 : : * @brief Defines conversions between different color formats and parsing colors defined in strings.
6 : : */
7 : :
8 : : #include <array>
9 : : #include <string>
10 : : #include <cstdlib>
11 : : #include <cstring>
12 : : #include <utility>
13 : : #include <vector>
14 : : #include <algorithm>
15 : :
16 : : #include "ctype.hh"
17 : : #include "color.hh"
18 : :
19 : 17 : unsigned ParseColorName(std::u32string_view s)
20 : : {
21 : 17 : return ParseColorName(ToUTF8(s));
22 : : }
23 : :
24 : : /*
25 : : A simple version of the colors array can be generated with:
26 : :
27 : : grep -v '!' /usr/share/X11/rgb.txt \
28 : : | perl -pe "s/(\d+)\s+(\d+)\s+(\d+)\s+(.*)/ {\"\\4\", Repack({\\1,\\2,\\3}) },/" \
29 : : | tr A-Z a-z
30 : :
31 : : The current version is auto-generated code.
32 : : It uses fast hashing that is guaranteed to return correct value
33 : : for all known colors, but undefined value for other strings.
34 : : The hashing is optimized such that the range of different hashes is as short as possible.
35 : : */
36 : :
37 : : static constexpr unsigned mod = 3832u, mul = 380u;
38 : : // Note: Not using std::string_view, because clang falsely reports it's not a built-in-constant when it is.
39 : 771 : static constexpr unsigned hash(const char* s, std::size_t length)
40 : : {
41 : 771 : constexpr std::uint_least64_t lett = 0x927B029ACC77F; // maps a..z into 0..3
42 : 771 : constexpr std::uint_least64_t map = 0x928CFB571EE207; // maps everything into hex digits
43 : 771 : std::uint_least64_t result = 0x7923C1BDEEE579CE;
44 [ + + ]: 7474 : for(std::size_t p=0; p<length; ++p)
45 : : {
46 : 6703 : unsigned z = s[p], t;
47 : :
48 : 6703 : std::uint_least64_t space = -std::uint_least64_t(z != ' ');
49 : : /* code_lett gets same result for both uppercase and lowercase. */
50 : 6703 : unsigned ch = (2*z - 2*'a');
51 : 6703 : unsigned code_lett = (4*lett) >> (ch&63) /* 0..3 */;
52 : 6703 : unsigned code_dig = (4*z + 4*4 - 4*'0') /* 4..13 */;
53 : :
54 : : // z = (z&64) ? code_lett : code_dig; // Branchful version commented out
55 : : // Branchless version of the same:
56 : : // Bit 6 is set for lowercase and uppercase, but not digits
57 : : // Bit 5 is set for lowercase and digits, but not uppercase
58 : : // Bit 4 is set for digits and half of letters
59 : : #ifdef __clang__
60 : : code_lett &= 3*4;
61 : : // Clang optimizes this into a cmov
62 : : t = (z & 64) ? code_lett : code_dig;
63 : : #else
64 : : // For GCC, this produces better code, still not very good though.
65 : 6703 : t = (z >> 6) & 1; // Test bit 6 to detect alphabet
66 : 6703 : t = (code_lett & t*3*4) // True: want 3*4, false: want 0
67 : 6703 : + (code_dig & ~-t); // True: want 0, false: want 15*4
68 : : #endif
69 : :
70 : : // If the symbol was space, don't update result (skip spaces)
71 : : // Clang generates branchless cmov from this.
72 : : // GCC is not quite that smart...
73 : 6703 : result = ((result*mul + ((map >> (t&63)) & 15)) & space) + (result & ~space);
74 : : }
75 : 771 : return result % mod;
76 : : }
77 : :
78 : : /* Autogenerated code. This macro defines all the colors and their hashes. */
79 : : #define docolors(o) \
80 : : o( 1, 0xFFB5C5, "pink1")\
81 : : o( 5, 0xCD919E, "pink3")\
82 : : o( 7, 0xEEA9B8, "pink2")\
83 : : o( 11, 0x8B636C, "pink4")\
84 : : o( 30, 0x6495ED, "cornflower blue", "CornflowerBlue")\
85 : : o( 42, 0xFFFAFA, "snow")\
86 : : o( 65, 0xFFFAFA, "snow1")\
87 : : o( 66, 0xB03060, "maroon")\
88 : : o( 69, 0xCDC9C9, "snow3")\
89 : : o( 70, 0xFFE4B5, "moccasin")\
90 : : o( 71, 0xEEE9E9, "snow2")\
91 : : o( 72, 0x000080, "navy")\
92 : : o( 75, 0x8B8989, "snow4")\
93 : : o( 78, 0x7B68EE, "medium slate blue", "MediumSlateBlue")\
94 : : o( 80, 0x2F4F4F, "dark slate gray", "DarkSlateGray", "dark slate grey", "DarkSlateGrey")\
95 : : o( 94, 0xFDF5E6, "old lace", "OldLace")\
96 : : o( 104, 0xEEE8AA, "pale goldenrod", "PaleGoldenrod")\
97 : : o( 120, 0xF5FFFA, "mint cream", "MintCream")\
98 : : o( 134, 0x0000CD, "medium blue", "MediumBlue")\
99 : : o( 138, 0xEE82EE, "violet")\
100 : : o( 176, 0xC71585, "medium violet red", "MediumVioletRed")\
101 : : o( 189, 0xFFF68F, "khaki1")\
102 : : o( 193, 0xCDC673, "khaki3")\
103 : : o( 195, 0xEEE685, "khaki2")\
104 : : o( 199, 0x8B864E, "khaki4")\
105 : : o( 209, 0xFF8C69, "salmon1")\
106 : : o( 213, 0xCD7054, "salmon3")\
107 : : o( 215, 0xEE8262, "salmon2")\
108 : : o( 219, 0x8B4C39, "salmon4")\
109 : : o( 221, 0x696969, "gray41", "grey41")\
110 : : o( 222, 0x7A7A7A, "gray48", "grey48")\
111 : : o( 225, 0x6E6E6E, "gray43", "grey43")\
112 : : o( 227, 0x6B6B6B, "gray42", "grey42")\
113 : : o( 228, 0x787878, "gray47", "grey47")\
114 : : o( 229, 0x7D7D7D, "gray49", "grey49")\
115 : : o( 231, 0x707070, "gray44", "grey44")\
116 : : o( 232, 0x757575, "gray46", "grey46")\
117 : : o( 234, 0x666666, "gray40", "grey40")\
118 : : o( 235, 0x737373, "gray45", "grey45")\
119 : : o( 240, 0xD70751, "DebianRed")\
120 : : o( 253, 0x1C1C1C, "gray11", "grey11")\
121 : : o( 254, 0x2E2E2E, "gray18", "grey18")\
122 : : o( 257, 0x212121, "gray13", "grey13")\
123 : : o( 259, 0x1F1F1F, "gray12", "grey12")\
124 : : o( 260, 0x2B2B2B, "gray17", "grey17")\
125 : : o( 261, 0x303030, "gray19", "grey19")\
126 : : o( 263, 0x242424, "gray14", "grey14")\
127 : : o( 264, 0x292929, "gray16", "grey16")\
128 : : o( 266, 0x1A1A1A, "gray10", "grey10")\
129 : : o( 267, 0x262626, "gray15", "grey15")\
130 : : o( 274, 0x8B4513, "saddle brown", "SaddleBrown")\
131 : : o( 329, 0xFFEFDB, "AntiqueWhite1")\
132 : : o( 333, 0xCDC0B0, "AntiqueWhite3")\
133 : : o( 335, 0xEEDFCC, "AntiqueWhite2")\
134 : : o( 338, 0x2E8B57, "sea green", "SeaGreen")\
135 : : o( 339, 0x8B8378, "AntiqueWhite4")\
136 : : o( 353, 0xFFE4C4, "bisque1")\
137 : : o( 357, 0xCDB79E, "bisque3")\
138 : : o( 359, 0xEED5B7, "bisque2")\
139 : : o( 361, 0x7FFF00, "chartreuse1")\
140 : : o( 362, 0xA52A2A, "brown")\
141 : : o( 363, 0x8B7D6B, "bisque4")\
142 : : o( 365, 0x66CD00, "chartreuse3")\
143 : : o( 367, 0x76EE00, "chartreuse2")\
144 : : o( 369, 0xFF0000, "red1")\
145 : : o( 371, 0x458B00, "chartreuse4")\
146 : : o( 373, 0xCD0000, "red3")\
147 : : o( 375, 0xEE0000, "red2")\
148 : : o( 377, 0xFF83FA, "orchid1")\
149 : : o( 379, 0x8B0000, "red4")\
150 : : o( 381, 0xCD69C9, "orchid3")\
151 : : o( 383, 0xEE7AE9, "orchid2")\
152 : : o( 387, 0x8B4789, "orchid4")\
153 : : o( 392, 0xFFD700, "gold")\
154 : : o( 393, 0x63B8FF, "SteelBlue1")\
155 : : o( 397, 0x4F94CD, "SteelBlue3")\
156 : : o( 399, 0x5CACEE, "SteelBlue2")\
157 : : o( 403, 0x36648B, "SteelBlue4")\
158 : : o( 426, 0xF08080, "light coral", "LightCoral")\
159 : : o( 430, 0x00008B, "dark blue", "DarkBlue")\
160 : : o( 433, 0xFFFACD, "LemonChiffon1")\
161 : : o( 437, 0xCDC9A5, "LemonChiffon3")\
162 : : o( 439, 0xEEE9BF, "LemonChiffon2")\
163 : : o( 443, 0x8B8970, "LemonChiffon4")\
164 : : o( 490, 0xD2B48C, "tan")\
165 : : o( 505, 0x00BFFF, "DeepSkyBlue1")\
166 : : o( 509, 0x009ACD, "DeepSkyBlue3")\
167 : : o( 510, 0xA020F0, "purple")\
168 : : o( 511, 0x00B2EE, "DeepSkyBlue2")\
169 : : o( 515, 0x00688B, "DeepSkyBlue4")\
170 : : o( 526, 0x40E0D0, "turquoise")\
171 : : o( 529, 0x836FFF, "SlateBlue1")\
172 : : o( 533, 0x6959CD, "SlateBlue3")\
173 : : o( 535, 0x7A67EE, "SlateBlue2")\
174 : : o( 539, 0x473C8B, "SlateBlue4")\
175 : : o( 564, 0xDA70D6, "orchid")\
176 : : o( 569, 0xFFD39B, "burlywood1")\
177 : : o( 573, 0xCDAA7D, "burlywood3")\
178 : : o( 574, 0x6A5ACD, "slate blue", "SlateBlue")\
179 : : o( 575, 0xEEC591, "burlywood2")\
180 : : o( 579, 0x8B7355, "burlywood4")\
181 : : o( 601, 0x9C9C9C, "gray61", "grey61")\
182 : : o( 602, 0xADADAD, "gray68", "grey68")\
183 : : o( 605, 0xA1A1A1, "gray63", "grey63")\
184 : : o( 606, 0xF0F8FF, "alice blue", "AliceBlue")\
185 : : o( 607, 0x9E9E9E, "gray62", "grey62")\
186 : : o( 608, 0xABABAB, "gray67", "grey67")\
187 : : o( 609, 0xB0B0B0, "gray69", "grey69")\
188 : : o( 611, 0xA3A3A3, "gray64", "grey64")\
189 : : o( 612, 0xA8A8A8, "gray66", "grey66")\
190 : : o( 614, 0x999999, "gray60", "grey60")\
191 : : o( 615, 0xA6A6A6, "gray65", "grey65")\
192 : : o( 617, 0xFF7256, "coral1")\
193 : : o( 621, 0xCD5B45, "coral3")\
194 : : o( 623, 0xEE6A50, "coral2")\
195 : : o( 627, 0x8B3E2F, "coral4")\
196 : : o( 633, 0xCFCFCF, "gray81", "grey81")\
197 : : o( 634, 0xE0E0E0, "gray88", "grey88")\
198 : : o( 637, 0xD4D4D4, "gray83", "grey83")\
199 : : o( 639, 0xD1D1D1, "gray82", "grey82")\
200 : : o( 640, 0xDEDEDE, "gray87", "grey87")\
201 : : o( 641, 0xE3E3E3, "gray89", "grey89")\
202 : : o( 643, 0xD6D6D6, "gray84", "grey84")\
203 : : o( 644, 0xDBDBDB, "gray86", "grey86")\
204 : : o( 646, 0xCCCCCC, "gray80", "grey80")\
205 : : o( 647, 0xD9D9D9, "gray85", "grey85")\
206 : : o( 672, 0xD02090, "violet red", "VioletRed")\
207 : : o( 689, 0xF0FFF0, "honeydew1")\
208 : : o( 693, 0xC1CDC1, "honeydew3")\
209 : : o( 695, 0xE0EEE0, "honeydew2")\
210 : : o( 697, 0xFFB90F, "DarkGoldenrod1")\
211 : : o( 699, 0x838B83, "honeydew4")\
212 : : o( 701, 0xCD950C, "DarkGoldenrod3")\
213 : : o( 703, 0xEEAD0E, "DarkGoldenrod2")\
214 : : o( 707, 0x8B6508, "DarkGoldenrod4")\
215 : : o( 722, 0x8A2BE2, "blue violet", "BlueViolet")\
216 : : o( 737, 0x1E90FF, "DodgerBlue1")\
217 : : o( 738, 0xFFB6C1, "light pink", "LightPink")\
218 : : o( 741, 0x1874CD, "DodgerBlue3")\
219 : : o( 743, 0x1C86EE, "DodgerBlue2")\
220 : : o( 747, 0x104E8B, "DodgerBlue4")\
221 : : o( 761, 0xFF7F24, "chocolate1")\
222 : : o( 765, 0xCD661D, "chocolate3")\
223 : : o( 767, 0xEE7621, "chocolate2")\
224 : : o( 769, 0xFF6EB4, "HotPink1")\
225 : : o( 771, 0x8B4513, "chocolate4")\
226 : : o( 773, 0xCD6090, "HotPink3")\
227 : : o( 775, 0xEE6AA7, "HotPink2")\
228 : : o( 779, 0x8B3A62, "HotPink4")\
229 : : o( 782, 0x0000FF, "blue")\
230 : : o( 810, 0xF0FFF0, "honeydew")\
231 : : o( 824, 0xB8860B, "dark goldenrod", "DarkGoldenrod")\
232 : : o( 830, 0x191970, "midnight blue", "MidnightBlue")\
233 : : o( 833, 0xFFA54F, "tan1")\
234 : : o( 837, 0xCD853F, "tan3")\
235 : : o( 839, 0xEE9A49, "tan2")\
236 : : o( 843, 0x8B5A2B, "tan4")\
237 : : o( 894, 0xA0522D, "sienna")\
238 : : o( 905, 0xFFFFE0, "LightYellow1")\
239 : : o( 909, 0xCDCDB4, "LightYellow3")\
240 : : o( 911, 0xEEEED1, "LightYellow2")\
241 : : o( 913, 0xBF3EFF, "DarkOrchid1")\
242 : : o( 915, 0x8B8B7A, "LightYellow4")\
243 : : o( 917, 0x9A32CD, "DarkOrchid3")\
244 : : o( 919, 0xB23AEE, "DarkOrchid2")\
245 : : o( 922, 0xFFF8DC, "cornsilk")\
246 : : o( 923, 0x68228B, "DarkOrchid4")\
247 : : o( 934, 0xB0E0E6, "powder blue", "PowderBlue")\
248 : : o( 937, 0xFF4040, "brown1")\
249 : : o( 938, 0xBC8F8F, "rosy brown", "RosyBrown")\
250 : : o( 941, 0xCD3333, "brown3")\
251 : : o( 943, 0xEE3B3B, "brown2")\
252 : : o( 946, 0x00FA9A, "medium spring green", "MediumSpringGreen")\
253 : : o( 947, 0x8B2323, "brown4")\
254 : : o( 970, 0xFF8C00, "dark orange", "DarkOrange")\
255 : : o( 990, 0x8470FF, "light slate blue", "LightSlateBlue")\
256 : : o( 1009, 0xC1FFC1, "DarkSeaGreen1")\
257 : : o( 1013, 0x9BCD9B, "DarkSeaGreen3")\
258 : : o( 1015, 0xB4EEB4, "DarkSeaGreen2")\
259 : : o( 1019, 0x698B69, "DarkSeaGreen4")\
260 : : o( 1025, 0xFFEC8B, "LightGoldenrod1")\
261 : : o( 1026, 0xE9967A, "dark salmon", "DarkSalmon")\
262 : : o( 1029, 0xCDBE70, "LightGoldenrod3")\
263 : : o( 1031, 0xEEDC82, "LightGoldenrod2")\
264 : : o( 1035, 0x8B814C, "LightGoldenrod4")\
265 : : o( 1086, 0xDCDCDC, "gainsboro")\
266 : : o( 1090, 0xFAFAD2, "light goldenrod yellow", "LightGoldenrodYellow")\
267 : : o( 1097, 0xFFF8DC, "cornsilk1")\
268 : : o( 1101, 0xCDC8B1, "cornsilk3")\
269 : : o( 1103, 0xEEE8CD, "cornsilk2")\
270 : : o( 1107, 0x8B8878, "cornsilk4")\
271 : : o( 1120, 0xDDA0DD, "plum")\
272 : : o( 1137, 0xFFDAB9, "PeachPuff1")\
273 : : o( 1141, 0xCDAF95, "PeachPuff3")\
274 : : o( 1143, 0xEECBAD, "PeachPuff2")\
275 : : o( 1147, 0x8B7765, "PeachPuff4")\
276 : : o( 1161, 0xE066FF, "MediumOrchid1")\
277 : : o( 1165, 0xB452CD, "MediumOrchid3")\
278 : : o( 1167, 0xD15FEE, "MediumOrchid2")\
279 : : o( 1171, 0x7A378B, "MediumOrchid4")\
280 : : o( 1216, 0x8B0000, "dark red", "DarkRed")\
281 : : o( 1222, 0xAFEEEE, "pale turquoise", "PaleTurquoise")\
282 : : o( 1258, 0xFFFFE0, "light yellow", "LightYellow")\
283 : : o( 1266, 0x9400D3, "dark violet", "DarkViolet")\
284 : : o( 1345, 0xFFDEAD, "NavajoWhite1")\
285 : : o( 1349, 0xCDB38B, "NavajoWhite3")\
286 : : o( 1351, 0xEECFA1, "NavajoWhite2")\
287 : : o( 1355, 0x8B795E, "NavajoWhite4")\
288 : : o( 1368, 0xDB7093, "pale violet red", "PaleVioletRed")\
289 : : o( 1375, 0xBDB76B, "dark khaki", "DarkKhaki")\
290 : : o( 1385, 0xFFFF00, "yellow1")\
291 : : o( 1386, 0xFFA07A, "light salmon", "LightSalmon")\
292 : : o( 1389, 0xCDCD00, "yellow3")\
293 : : o( 1391, 0xEEEE00, "yellow2")\
294 : : o( 1395, 0x8B8B00, "yellow4")\
295 : : o( 1409, 0xFF3030, "firebrick1")\
296 : : o( 1413, 0xCD2626, "firebrick3")\
297 : : o( 1415, 0xEE2C2C, "firebrick2")\
298 : : o( 1419, 0x8B1A1A, "firebrick4")\
299 : : o( 1449, 0x00FFFF, "cyan1")\
300 : : o( 1453, 0x00CDCD, "cyan3")\
301 : : o( 1455, 0x00EEEE, "cyan2")\
302 : : o( 1459, 0x008B8B, "cyan4")\
303 : : o( 1463, 0xE6E6FA, "lavender")\
304 : : o( 1464, 0xD3D3D3, "light grey", "LightGrey", "light gray", "LightGray")\
305 : : o( 1466, 0x00FF00, "green")\
306 : : o( 1478, 0xF8F8FF, "ghost white", "GhostWhite")\
307 : : o( 1482, 0x8FBC8F, "dark sea green", "DarkSeaGreen")\
308 : : o( 1494, 0xFFE4E1, "misty rose", "MistyRose")\
309 : : o( 1506, 0x3CB371, "medium sea green", "MediumSeaGreen")\
310 : : o( 1513, 0xFF3E96, "VioletRed1")\
311 : : o( 1514, 0xF4A460, "sandy brown", "SandyBrown")\
312 : : o( 1517, 0xCD3278, "VioletRed3")\
313 : : o( 1519, 0xEE3A8C, "VioletRed2")\
314 : : o( 1523, 0x8B2252, "VioletRed4")\
315 : : o( 1529, 0x0000FF, "blue1")\
316 : : o( 1530, 0x000000, "black")\
317 : : o( 1533, 0x0000CD, "blue3")\
318 : : o( 1535, 0x0000EE, "blue2")\
319 : : o( 1539, 0x00008B, "blue4")\
320 : : o( 1552, 0xFFDAB9, "peach puff", "PeachPuff")\
321 : : o( 1609, 0x4876FF, "RoyalBlue1")\
322 : : o( 1613, 0x3A5FCD, "RoyalBlue3")\
323 : : o( 1615, 0x436EEE, "RoyalBlue2")\
324 : : o( 1619, 0x27408B, "RoyalBlue4")\
325 : : o( 1630, 0xFAEBD7, "antique white", "AntiqueWhite")\
326 : : o( 1638, 0x87CEFA, "light sky blue", "LightSkyBlue")\
327 : : o( 1692, 0x9932CC, "dark orchid", "DarkOrchid")\
328 : : o( 1697, 0xFF1493, "DeepPink1")\
329 : : o( 1701, 0xCD1076, "DeepPink3")\
330 : : o( 1703, 0xEE1289, "DeepPink2")\
331 : : o( 1705, 0xFFE1FF, "thistle1")\
332 : : o( 1707, 0x8B0A50, "DeepPink4")\
333 : : o( 1709, 0xCDB5CD, "thistle3")\
334 : : o( 1711, 0xEED2EE, "thistle2")\
335 : : o( 1715, 0x8B7B8B, "thistle4")\
336 : : o( 1741, 0x828282, "gray51", "grey51")\
337 : : o( 1742, 0x949494, "gray58", "grey58")\
338 : : o( 1745, 0x878787, "gray53", "grey53")\
339 : : o( 1747, 0x858585, "gray52", "grey52")\
340 : : o( 1748, 0x919191, "gray57", "grey57")\
341 : : o( 1749, 0x969696, "gray59", "grey59")\
342 : : o( 1751, 0x8A8A8A, "gray54", "grey54")\
343 : : o( 1752, 0x8F8F8F, "gray56", "grey56")\
344 : : o( 1754, 0x7F7F7F, "gray50", "grey50")\
345 : : o( 1755, 0x8C8C8C, "gray55", "grey55")\
346 : : o( 1773, 0x4F4F4F, "gray31", "grey31")\
347 : : o( 1774, 0x616161, "gray38", "grey38")\
348 : : o( 1777, 0x545454, "gray33", "grey33")\
349 : : o( 1779, 0x525252, "gray32", "grey32")\
350 : : o( 1780, 0x5E5E5E, "gray37", "grey37")\
351 : : o( 1781, 0x636363, "gray39", "grey39")\
352 : : o( 1783, 0x575757, "gray34", "grey34")\
353 : : o( 1784, 0x5C5C5C, "gray36", "grey36")\
354 : : o( 1786, 0x4D4D4D, "gray30", "grey30")\
355 : : o( 1787, 0x595959, "gray35", "grey35")\
356 : : o( 1814, 0x4682B4, "steel blue", "SteelBlue")\
357 : : o( 1825, 0xFF4500, "OrangeRed1")\
358 : : o( 1826, 0xFF1493, "deep pink", "DeepPink")\
359 : : o( 1829, 0xCD3700, "OrangeRed3")\
360 : : o( 1831, 0xEE4000, "OrangeRed2")\
361 : : o( 1835, 0x8B2500, "OrangeRed4")\
362 : : o( 1841, 0xF0FFFF, "azure1")\
363 : : o( 1845, 0xC1CDCD, "azure3")\
364 : : o( 1847, 0xE0EEEE, "azure2")\
365 : : o( 1850, 0xFF6347, "tomato")\
366 : : o( 1851, 0x838B8B, "azure4")\
367 : : o( 1870, 0x48D1CC, "medium turquoise", "MediumTurquoise")\
368 : : o( 1881, 0xFFAEB9, "LightPink1")\
369 : : o( 1885, 0xCD8C95, "LightPink3")\
370 : : o( 1886, 0xD8BFD8, "thistle")\
371 : : o( 1887, 0xEEA2AD, "LightPink2")\
372 : : o( 1891, 0x8B5F65, "LightPink4")\
373 : : o( 1897, 0xFFF5EE, "seashell1")\
374 : : o( 1901, 0xCDC5BF, "seashell3")\
375 : : o( 1903, 0xEEE5DE, "seashell2")\
376 : : o( 1907, 0x8B8682, "seashell4")\
377 : : o( 1921, 0xFFA500, "orange1")\
378 : : o( 1925, 0xCD8500, "orange3")\
379 : : o( 1927, 0xEE9A00, "orange2")\
380 : : o( 1931, 0x8B5A00, "orange4")\
381 : : o( 1942, 0x00CED1, "dark turquoise", "DarkTurquoise")\
382 : : o( 1958, 0xFFDEAD, "navajo white", "NavajoWhite")\
383 : : o( 1962, 0xE0FFFF, "light cyan", "LightCyan")\
384 : : o( 1978, 0xFFC0CB, "pink")\
385 : : o( 1990, 0x483D8B, "dark slate blue", "DarkSlateBlue")\
386 : : o( 1998, 0x66CDAA, "medium aquamarine", "MediumAquamarine")\
387 : : o( 2006, 0xD2691E, "chocolate")\
388 : : o( 2022, 0xFFFAF0, "floral white", "FloralWhite")\
389 : : o( 2042, 0xFFFACD, "lemon chiffon", "LemonChiffon")\
390 : : o( 2072, 0xFF0000, "red")\
391 : : o( 2081, 0xFFF0F5, "LavenderBlush1")\
392 : : o( 2085, 0xCDC1C5, "LavenderBlush3")\
393 : : o( 2087, 0xEEE0E5, "LavenderBlush2")\
394 : : o( 2091, 0x8B8386, "LavenderBlush4")\
395 : : o( 2094, 0x000080, "navy blue", "NavyBlue")\
396 : : o( 2110, 0xFFFFFF, "gray100", "grey100")\
397 : : o( 2118, 0x87CEEB, "sky blue", "SkyBlue")\
398 : : o( 2126, 0x00BFFF, "deep sky blue", "DeepSkyBlue")\
399 : : o( 2185, 0xFF00FF, "magenta1")\
400 : : o( 2189, 0xCD00CD, "magenta3")\
401 : : o( 2191, 0xEE00EE, "magenta2")\
402 : : o( 2195, 0x8B008B, "magenta4")\
403 : : o( 2230, 0xB0C4DE, "light steel blue", "LightSteelBlue")\
404 : : o( 2241, 0x9AFF9A, "PaleGreen1")\
405 : : o( 2245, 0x7CCD7C, "PaleGreen3")\
406 : : o( 2247, 0x90EE90, "PaleGreen2")\
407 : : o( 2251, 0x548B54, "PaleGreen4")\
408 : : o( 2252, 0xFFFFF0, "ivory")\
409 : : o( 2265, 0xFFC125, "goldenrod1")\
410 : : o( 2269, 0xCD9B1D, "goldenrod3")\
411 : : o( 2271, 0xEEB422, "goldenrod2")\
412 : : o( 2275, 0x8B6914, "goldenrod4")\
413 : : o( 2278, 0x9370DB, "medium purple", "MediumPurple")\
414 : : o( 2304, 0x696969, "dim gray", "DimGray", "dim grey", "DimGrey")\
415 : : o( 2322, 0xFF69B4, "hot pink", "HotPink")\
416 : : o( 2332, 0xBA55D3, "medium orchid", "MediumOrchid")\
417 : : o( 2342, 0x1E90FF, "dodger blue", "DodgerBlue")\
418 : : o( 2352, 0xA9A9A9, "dark grey", "DarkGrey", "dark gray", "DarkGray")\
419 : : o( 2378, 0xFF7F50, "coral")\
420 : : o( 2393, 0xFF6347, "tomato1")\
421 : : o( 2397, 0xCD4F39, "tomato3")\
422 : : o( 2399, 0xEE5C42, "tomato2")\
423 : : o( 2403, 0x8B3626, "tomato4")\
424 : : o( 2409, 0xFF82AB, "PaleVioletRed1")\
425 : : o( 2413, 0xCD6889, "PaleVioletRed3")\
426 : : o( 2415, 0xEE799F, "PaleVioletRed2")\
427 : : o( 2419, 0x8B475D, "PaleVioletRed4")\
428 : : o( 2425, 0xB0E2FF, "LightSkyBlue1")\
429 : : o( 2429, 0x8DB6CD, "LightSkyBlue3")\
430 : : o( 2431, 0xA4D3EE, "LightSkyBlue2")\
431 : : o( 2432, 0xFF4500, "orange red", "OrangeRed")\
432 : : o( 2435, 0x607B8B, "LightSkyBlue4")\
433 : : o( 2457, 0xFF7F00, "DarkOrange1")\
434 : : o( 2461, 0xCD6600, "DarkOrange3")\
435 : : o( 2463, 0xEE7600, "DarkOrange2")\
436 : : o( 2467, 0x8B4500, "DarkOrange4")\
437 : : o( 2496, 0x708090, "slate gray", "SlateGray", "slate grey", "SlateGrey")\
438 : : o( 2533, 0x363636, "gray21", "grey21")\
439 : : o( 2534, 0x474747, "gray28", "grey28")\
440 : : o( 2537, 0x3B3B3B, "gray23", "grey23")\
441 : : o( 2539, 0x383838, "gray22", "grey22")\
442 : : o( 2540, 0x454545, "gray27", "grey27")\
443 : : o( 2541, 0x4A4A4A, "gray29", "grey29")\
444 : : o( 2543, 0x3D3D3D, "gray24", "grey24")\
445 : : o( 2544, 0x424242, "gray26", "grey26")\
446 : : o( 2546, 0x333333, "gray20", "grey20")\
447 : : o( 2547, 0x404040, "gray25", "grey25")\
448 : : o( 2553, 0xFFFFF0, "ivory1")\
449 : : o( 2557, 0xCDCDC1, "ivory3")\
450 : : o( 2559, 0xEEEEE0, "ivory2")\
451 : : o( 2563, 0x8B8B83, "ivory4")\
452 : : o( 2569, 0xFF6A6A, "IndianRed1")\
453 : : o( 2573, 0xCD5555, "IndianRed3")\
454 : : o( 2575, 0xEE6363, "IndianRed2")\
455 : : o( 2577, 0xCAFF70, "DarkOliveGreen1")\
456 : : o( 2579, 0x8B3A3A, "IndianRed4")\
457 : : o( 2581, 0xA2CD5A, "DarkOliveGreen3")\
458 : : o( 2583, 0xBCEE68, "DarkOliveGreen2")\
459 : : o( 2587, 0x6E8B3D, "DarkOliveGreen4")\
460 : : o( 2617, 0xC0FF3E, "OliveDrab1")\
461 : : o( 2621, 0x9ACD32, "OliveDrab3")\
462 : : o( 2623, 0xB3EE3A, "OliveDrab2")\
463 : : o( 2627, 0x698B22, "OliveDrab4")\
464 : : o( 2675, 0xFFEFD5, "papaya whip", "PapayaWhip")\
465 : : o( 2694, 0xFF00FF, "magenta")\
466 : : o( 2697, 0x00F5FF, "turquoise1")\
467 : : o( 2701, 0x00C5CD, "turquoise3")\
468 : : o( 2703, 0x00E5EE, "turquoise2")\
469 : : o( 2704, 0xBEBEBE, "gray", "grey")\
470 : : o( 2707, 0x00868B, "turquoise4")\
471 : : o( 2714, 0xF0FFFF, "azure")\
472 : : o( 2737, 0xFF34B3, "maroon1")\
473 : : o( 2741, 0xCD2990, "maroon3")\
474 : : o( 2743, 0xEE30A7, "maroon2")\
475 : : o( 2747, 0x8B1C62, "maroon4")\
476 : : o( 2750, 0x5F9EA0, "cadet blue", "CadetBlue")\
477 : : o( 2769, 0x00FF00, "green1")\
478 : : o( 2773, 0x00CD00, "green3")\
479 : : o( 2775, 0x00EE00, "green2")\
480 : : o( 2777, 0xFFD700, "gold1")\
481 : : o( 2779, 0x008B00, "green4")\
482 : : o( 2781, 0xCDAD00, "gold3")\
483 : : o( 2783, 0xEEC900, "gold2")\
484 : : o( 2787, 0x8B7500, "gold4")\
485 : : o( 2809, 0xC6E2FF, "SlateGray1")\
486 : : o( 2813, 0x9FB6CD, "SlateGray3")\
487 : : o( 2815, 0xB9D3EE, "SlateGray2")\
488 : : o( 2819, 0x6C7B8B, "SlateGray4")\
489 : : o( 2849, 0x9B30FF, "purple1")\
490 : : o( 2850, 0x008B8B, "dark cyan", "DarkCyan")\
491 : : o( 2853, 0x7D26CD, "purple3")\
492 : : o( 2855, 0x912CEE, "purple2")\
493 : : o( 2857, 0xFFE7BA, "wheat1")\
494 : : o( 2859, 0x551A8B, "purple4")\
495 : : o( 2861, 0xCDBA96, "wheat3")\
496 : : o( 2863, 0xEED8AE, "wheat2")\
497 : : o( 2867, 0x8B7E66, "wheat4")\
498 : : o( 2871, 0xF0E68C, "khaki")\
499 : : o( 2874, 0x20B2AA, "light sea green", "LightSeaGreen")\
500 : : o( 2881, 0x00FF7F, "SpringGreen1")\
501 : : o( 2882, 0x32CD32, "lime green", "LimeGreen")\
502 : : o( 2885, 0x00CD66, "SpringGreen3")\
503 : : o( 2886, 0x7FFF00, "chartreuse")\
504 : : o( 2887, 0x00EE76, "SpringGreen2")\
505 : : o( 2891, 0x008B45, "SpringGreen4")\
506 : : o( 2912, 0x778899, "light slate gray", "LightSlateGray", "light slate grey", "LightSlateGrey")\
507 : : o( 2913, 0xB5B5B5, "gray71", "grey71")\
508 : : o( 2914, 0xC7C7C7, "gray78", "grey78")\
509 : : o( 2917, 0xBABABA, "gray73", "grey73")\
510 : : o( 2919, 0xB8B8B8, "gray72", "grey72")\
511 : : o( 2920, 0xC4C4C4, "gray77", "grey77")\
512 : : o( 2921, 0xC9C9C9, "gray79", "grey79")\
513 : : o( 2923, 0xBDBDBD, "gray74", "grey74")\
514 : : o( 2924, 0xC2C2C2, "gray76", "grey76")\
515 : : o( 2926, 0xB3B3B3, "gray70", "grey70")\
516 : : o( 2927, 0xBFBFBF, "gray75", "grey75")\
517 : : o( 2966, 0x4169E1, "royal blue", "RoyalBlue")\
518 : : o( 2985, 0xCAE1FF, "LightSteelBlue1")\
519 : : o( 2989, 0xA2B5CD, "LightSteelBlue3")\
520 : : o( 2991, 0xBCD2EE, "LightSteelBlue2")\
521 : : o( 2995, 0x6E7B8B, "LightSteelBlue4")\
522 : : o( 3024, 0xDEB887, "burlywood")\
523 : : o( 3042, 0xCD853F, "peru")\
524 : : o( 3048, 0xFFEBCD, "blanched almond", "BlanchedAlmond")\
525 : : o( 3081, 0x97FFFF, "DarkSlateGray1")\
526 : : o( 3085, 0x79CDCD, "DarkSlateGray3")\
527 : : o( 3087, 0x8DEEEE, "DarkSlateGray2")\
528 : : o( 3091, 0x528B8B, "DarkSlateGray4")\
529 : : o( 3153, 0xFF8247, "sienna1")\
530 : : o( 3157, 0xCD6839, "sienna3")\
531 : : o( 3159, 0xEE7942, "sienna2")\
532 : : o( 3163, 0x8B4726, "sienna4")\
533 : : o( 3193, 0xFFC1C1, "RosyBrown1")\
534 : : o( 3197, 0xCD9B9B, "RosyBrown3")\
535 : : o( 3199, 0xEEB4B4, "RosyBrown2")\
536 : : o( 3202, 0x00FFFF, "cyan")\
537 : : o( 3203, 0x8B6969, "RosyBrown4")\
538 : : o( 3206, 0xFFE4C4, "bisque")\
539 : : o( 3210, 0xFAF0E6, "linen")\
540 : : o( 3214, 0x6B8E23, "olive drab", "OliveDrab")\
541 : : o( 3226, 0x228B22, "forest green", "ForestGreen")\
542 : : o( 3230, 0x8B008B, "dark magenta", "DarkMagenta")\
543 : : o( 3240, 0xDAA520, "goldenrod")\
544 : : o( 3250, 0x556B2F, "dark olive green", "DarkOliveGreen")\
545 : : o( 3265, 0x7FFFD4, "aquamarine1")\
546 : : o( 3266, 0x7CFC00, "lawn green", "LawnGreen")\
547 : : o( 3269, 0x66CDAA, "aquamarine3")\
548 : : o( 3271, 0x76EEC6, "aquamarine2")\
549 : : o( 3275, 0x458B74, "aquamarine4")\
550 : : o( 3293, 0xE8E8E8, "gray91", "grey91")\
551 : : o( 3294, 0xFAFAFA, "gray98", "grey98")\
552 : : o( 3297, 0xEDEDED, "gray93", "grey93")\
553 : : o( 3299, 0xEBEBEB, "gray92", "grey92")\
554 : : o( 3300, 0xF7F7F7, "gray97", "grey97")\
555 : : o( 3301, 0xFCFCFC, "gray99", "grey99")\
556 : : o( 3303, 0xF0F0F0, "gray94", "grey94")\
557 : : o( 3304, 0xF5F5F5, "gray96", "grey96")\
558 : : o( 3306, 0xE5E5E5, "gray90", "grey90")\
559 : : o( 3307, 0xF2F2F2, "gray95", "grey95")\
560 : : o( 3326, 0xFFF0F5, "lavender blush", "LavenderBlush")\
561 : : o( 3329, 0xE0FFFF, "LightCyan1")\
562 : : o( 3333, 0xB4CDCD, "LightCyan3")\
563 : : o( 3335, 0xD1EEEE, "LightCyan2")\
564 : : o( 3339, 0x7A8B8B, "LightCyan4")\
565 : : o( 3346, 0x90EE90, "light green", "LightGreen")\
566 : : o( 3362, 0x00FF7F, "spring green", "SpringGreen")\
567 : : o( 3374, 0xADD8E6, "light blue", "LightBlue")\
568 : : o( 3409, 0xBFEFFF, "LightBlue1")\
569 : : o( 3413, 0x9AC0CD, "LightBlue3")\
570 : : o( 3414, 0xF5F5F5, "white smoke", "WhiteSmoke")\
571 : : o( 3415, 0xB2DFEE, "LightBlue2")\
572 : : o( 3419, 0x68838B, "LightBlue4")\
573 : : o( 3425, 0x54FF9F, "SeaGreen1")\
574 : : o( 3429, 0x43CD80, "SeaGreen3")\
575 : : o( 3431, 0x4EEE94, "SeaGreen2")\
576 : : o( 3434, 0xADFF2F, "green yellow", "GreenYellow")\
577 : : o( 3435, 0x2E8B57, "SeaGreen4")\
578 : : o( 3450, 0xFFF5EE, "seashell")\
579 : : o( 3481, 0xFFE4E1, "MistyRose1")\
580 : : o( 3485, 0xCDB7B5, "MistyRose3")\
581 : : o( 3487, 0xEED5D2, "MistyRose2")\
582 : : o( 3491, 0x8B7D7B, "MistyRose4")\
583 : : o( 3506, 0xF5F5DC, "beige")\
584 : : o( 3513, 0xFFBBFF, "plum1")\
585 : : o( 3517, 0xCD96CD, "plum3")\
586 : : o( 3519, 0xEEAEEE, "plum2")\
587 : : o( 3523, 0x8B668B, "plum4")\
588 : : o( 3558, 0x7FFFD4, "aquamarine")\
589 : : o( 3561, 0xFFA07A, "LightSalmon1")\
590 : : o( 3565, 0xCD8162, "LightSalmon3")\
591 : : o( 3567, 0xEE9572, "LightSalmon2")\
592 : : o( 3571, 0x8B5742, "LightSalmon4")\
593 : : o( 3593, 0xBBFFFF, "PaleTurquoise1")\
594 : : o( 3594, 0xF5DEB3, "wheat")\
595 : : o( 3597, 0x96CDCD, "PaleTurquoise3")\
596 : : o( 3599, 0xAEEEEE, "PaleTurquoise2")\
597 : : o( 3602, 0xFFFF00, "yellow")\
598 : : o( 3603, 0x668B8B, "PaleTurquoise4")\
599 : : o( 3624, 0xCD5C5C, "indian red", "IndianRed")\
600 : : o( 3633, 0xAB82FF, "MediumPurple1")\
601 : : o( 3637, 0x8968CD, "MediumPurple3")\
602 : : o( 3639, 0x9F79EE, "MediumPurple2")\
603 : : o( 3643, 0x5D478B, "MediumPurple4")\
604 : : o( 3656, 0xEEDD82, "light goldenrod", "LightGoldenrod")\
605 : : o( 3674, 0xFFA500, "orange")\
606 : : o( 3698, 0x98FB98, "pale green", "PaleGreen")\
607 : : o( 3721, 0x87CEFF, "SkyBlue1")\
608 : : o( 3725, 0x6CA6CD, "SkyBlue3")\
609 : : o( 3726, 0xFFFFFF, "white")\
610 : : o( 3727, 0x7EC0EE, "SkyBlue2")\
611 : : o( 3730, 0xFA8072, "salmon")\
612 : : o( 3731, 0x4A708B, "SkyBlue4")\
613 : : o( 3745, 0x98F5FF, "CadetBlue1")\
614 : : o( 3749, 0x7AC5CD, "CadetBlue3")\
615 : : o( 3751, 0x8EE5EE, "CadetBlue2")\
616 : : o( 3755, 0x53868B, "CadetBlue4")\
617 : : o( 3794, 0x9ACD32, "yellow green", "YellowGreen")\
618 : : o( 3802, 0x006400, "dark green", "DarkGreen")\
619 : : o( 3809, 0x030303, "gray1", "grey1")\
620 : : o( 3810, 0x141414, "gray8", "grey8")\
621 : : o( 3813, 0x080808, "gray3", "grey3")\
622 : : o( 3815, 0x050505, "gray2", "grey2")\
623 : : o( 3816, 0x121212, "gray7", "grey7")\
624 : : o( 3817, 0x171717, "gray9", "grey9")\
625 : : o( 3818, 0xB22222, "firebrick")\
626 : : o( 3819, 0x0A0A0A, "gray4", "grey4")\
627 : : o( 3820, 0x0F0F0F, "gray6", "grey6")\
628 : : o( 3822, 0x000000, "gray0", "grey0")\
629 : : o( 3823, 0x0D0D0D, "gray5", "grey5")\
630 : :
631 : : /** ParseHex: Attempts to read a hexadecimal number from the input.
632 : : * @returns Pair (result, length). Modifies the input pointer.
633 : : */
634 : 10 : static std::pair<unsigned long long, unsigned> ParseHex(const char*& s)
635 : : {
636 : 10 : unsigned long long result = 0;
637 : 10 : unsigned length = 0;
638 [ + + + + ]: 34 : while(*s != '\0' && *s != '/')
639 : : {
640 : 24 : result <<= 4;
641 [ - + ]: 24 : if(*s >= 'A' && *s <= 'F') result += *s - 'A' + 10;
642 [ - + ]: 24 : else if(*s >= 'a' && *s <= 'f') result += *s - 'a' + 10;
643 [ + - ]: 24 : else if(*s >= '0' && *s <= '9') result += *s - '0' + 0;
644 : : /* Non-hex digits are treated as '0'. */
645 : : /* This matches the HTML color parsing algorithm. */
646 : 24 : ++s; ++length;
647 : : }
648 : 10 : return {result, length};
649 : : }
650 : : /** ParseDbl: Attempts to read a floating point value from the input.
651 : : * @returns The read number, multiplied by 255.9999 and clamped into 0,255 range.
652 : : * Modifies the input pointer.
653 : : */
654 : 6 : static unsigned ParseDbl(const char*& s)
655 : : {
656 : 6 : char* endptr = nullptr;
657 : 6 : double result = std::strtod(s, &endptr);
658 : 6 : s = endptr;
659 [ - + - + ]: 6 : return unsigned(255.9999 * std::max(std::min(result, 1.), 0.));
660 : : }
661 : :
662 : : enum { use_separator=1, lsb_first=2, use_dbl=4 };
663 : : /** Attempts to reads a color number from the source using one of the different formats.
664 : : * @param source String to read. Forward-slashes are ignored.
665 : : * @param specs Specifications:
666 : : * &use_dbl = Reads floating point values.
667 : : * &use_separator = Reads three values.
668 : : * &lsb_first = Places first index to lsb and third index to msb.
669 : : * If unset, the opposite behavior is done.
670 : : * @returns The read color, as 24-bit integer.
671 : : */
672 : 8 : static unsigned ParseColorNumber(const char* source, unsigned specs)
673 : : {
674 : 8 : unsigned result = 0;
675 : 8 : unsigned long long val = 0;
676 : 8 : unsigned length = 0;
677 : 8 : unsigned bits = 0;
678 : :
679 [ + + ]: 32 : for(unsigned n=0; n<3; ++n)
680 : : {
681 [ + + ]: 32 : while(*source == '/') ++source;
682 : :
683 [ + + ]: 24 : if(specs & use_dbl)
684 : : {
685 : 6 : val = ParseDbl(source);
686 : 6 : bits = 8;
687 : : }
688 [ + + + + ]: 18 : else if((specs & use_separator) || n==0)
689 : : {
690 [ + + ]: 10 : std::tie(val, length) = ParseHex(source);
691 : 10 : bits = length*4;
692 [ + + ]: 10 : if(!(specs & use_separator)) bits /= 3;
693 : : }
694 : :
695 : 24 : unsigned mask = ((0x1u << bits)-1);
696 : 24 : unsigned temp = val & mask; val >>= bits;
697 : : // Scale to 0xFF.
698 : 24 : temp = temp * 0xFF / mask;
699 [ + + ]: 24 : if(specs & lsb_first)
700 : : {
701 : 12 : result += temp << (8*n);
702 : : // Place n=0 to LSB and n=2 to MSB.
703 : : }
704 : : else
705 : : {
706 : 12 : result <<= 8;
707 : 12 : result += temp;
708 : : // Place n=0 to MSB and n=0 to MSB. Reverse of above.
709 : : }
710 : : }
711 : 8 : return result;
712 : : }
713 : : /** Attempts reading a color in one of the numberic formats. */
714 : 779 : static std::pair<unsigned,bool> TryParseColorNumber(std::string_view lc)
715 : : {
716 : 779 : const char* source = nullptr;
717 : 779 : unsigned specs = 0;
718 : :
719 [ + + ]: 779 : if(lc.size() >= 4)
720 : : {
721 : 777 : static constexpr const char hextext[] = {'#'};
722 : 777 : static constexpr const char rgbtext[] = {'r','g','b',':'};
723 : 777 : static constexpr const char rgbitext[] = {'r','g','b','i',':'};
724 : : /* Note that these strings are case-sensitive. */
725 [ + + ]: 777 : if(std::memcmp(lc.data(), hextext, sizeof hextext) == 0) // shortest: "#FFF" = 4 characters
726 : : {
727 : 4 : source = lc.data()+1;
728 : 4 : specs = lsb_first;
729 : : }
730 [ + + ]: 773 : else if(std::memcmp(lc.data(), rgbtext, sizeof rgbtext) == 0) // shortest: "rgb:F/F/F" = 9
731 : : {
732 : 2 : source = lc.data()+4;
733 : 2 : specs = use_separator;
734 : : }
735 [ + + ]: 771 : else if(std::memcmp(lc.data(), rgbitext, sizeof rgbitext) == 0) // shortest: "rgbi:1/1/1" = 10
736 : : {
737 : : // Note: compares 5 letters while we only checked size >= 4.
738 : : // If size == 4, there will be a nul, so this comparison is still safe,
739 : : // assuming that the string view is nul terminated.
740 : 2 : source = lc.data()+5;
741 : 2 : specs = use_separator | use_dbl;
742 : : }
743 : : }
744 : 8 : return source
745 : 8 : ? std::pair{ ParseColorNumber(source, specs), true }
746 [ + - ]: 787 : : std::pair{ 0u, false };
747 : : }
748 : :
749 : : /** FindColor identifies the hash and returns a color matching it. */
750 : 771 : static constexpr unsigned FindColor(unsigned h)
751 : : {
752 : : #define o(a,b,...) case a: return b; break;
753 [ + + + + : 771 : switch(h) { docolors(o) }
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
754 : : #undef o
755 : 8 : return 0;
756 : : }
757 : : /** Generates an std::array containing colors in an index matching its hash. */
758 : : template <std::size_t... N>
759 : : static consteval auto GetColors(std::index_sequence<N...>)
760 : : {
761 : : return std::array<unsigned, sizeof...(N)>
762 : : {
763 : : // Using a separate function for this rather than
764 : : // inlining a long ?: chain makes compilation on GCC fast.
765 : : // While Clang has no trouble with a long ?: chain, GCC would take ages to compile it.
766 : : FindColor(N) ...
767 : : };
768 : : }
769 : :
770 : :
771 : : /** See explanation in VerifyHash() */
772 : : template<std::size_t N>
773 : : struct fixed_string
774 : : {
775 : : /** Initializes the string with the given @param s string constant */
776 : : constexpr fixed_string(const char (&s)[N]) { std::copy_n(s, N, str); }
777 : : /** @returns a pointer to the string */
778 : : consteval const char* data() const { return str; }
779 : : /** @returns the string length */
780 : : consteval std::size_t size() const { return N-1; }
781 : : /** Stores the string */
782 : : char str[N];
783 : : };
784 : :
785 : : /** VerifyHash()
786 : : * Purpose:
787 : : *
788 : : * Uses static_assert(hash()) to verify that all of the given strings
789 : : * match to the given hash value.
790 : : *
791 : : * Note: fixed_string as a template parameter is
792 : : * a c++20 feature (class-type in non-type template parameter)
793 : : * Minimum supported compiler version: GCC 9, Clang 12, MSVC 19.28
794 : : * Not supported by Apple Clang yet.
795 : : *
796 : : * For concepts, you need GCC 10 or Clang 10.
797 : : *
798 : : * A fixed_string wrapper must be used, because a character array
799 : : * is not a valid template parameter. Attempts to use "const char*"
800 : : * or "char[]" will result in compilation errors.
801 : : *
802 : : * Similarly, attempts to pass the strings as parameters will fail,
803 : : * such as this:
804 : : * template<unsigned expected_hash, std::size_t... N>
805 : : * static consteval void VerifyHash(const char (&...s)[N])
806 : : * because the compiler says they are not constant expressions.
807 : : *
808 : : * The expected hash number must also be a template parameter.
809 : : * Otherwise static_assert will fail saying that the number
810 : : * is not a constant expression.
811 : : * Even though the function is consteval, passing any of the
812 : : * function parameters to static_assert() will fail the compilation.
813 : : *
814 : : * Then, static_assert is not an expression. It is a statement.
815 : : * This would not compile:
816 : : * (static_assert(hash(s.data(), s.size()) == expected_hash), ...);
817 : : * We could wrap the static_assert in a lambda, turning it into
818 : : * an expression, but due to *two* bugs in GCC (PR99893 and PR99895),
819 : : * it does not compile. Both would work on Clang though.
820 : : */
821 : : template<unsigned expected_hash, fixed_string... s>
822 : : static constexpr inline void VerifyHash()
823 : : {
824 : : // Make sure all the hashes are equal and match expected_hash
825 : : static_assert( ((hash(s.data(), s.size()) == expected_hash) and ...), "Incorrect hash" );
826 : : }
827 : :
828 : 779 : unsigned ParseColorName(std::string_view s)
829 : : {
830 : : /* First check if it's #ABC, #AABBCC, rgb:aa/bb/cc or rgbi:0.2/0.6/0.8 */
831 [ + + ]: 779 : auto [result,success] = TryParseColorNumber(s);
832 [ + + ]: 779 : if(success) return result;
833 : :
834 : : /* Nope? Then look it up in the hardcoded version of Xorg colors database. */
835 : :
836 : : /* Verify that all of the hashes in docolors() match the implementation in hash() */
837 : : #define v(a,b,...) VerifyHash<a, __VA_ARGS__>();
838 : 771 : docolors(v);
839 : : #undef v
840 : :
841 : : /* Begin by reducing the provided color into a small hash that is unique
842 : : * for all colors in the database.
843 : : */
844 : 771 : unsigned short h = hash(s.data(), s.size());
845 : :
846 : : #if defined(__GNUC__) && !defined(__clang__)
847 : : /* GCC generates pretty optimal code for this. */
848 : : /* This produces an extra range check compared to what's below, but needs less data. */
849 : : /* Amount of data: same as below, minus ~100 bytes by average */
850 : 771 : return FindColor(h);
851 : : #elif defined(__clang__) || defined(__GNUC__)
852 : : /* Clang and GCC compile this well. No comparisons, just a singular data access. */
853 : : /* Amount of data: mod*4 = ~15 kB */
854 : : static constinit const auto colorvalues = GetColors(std::make_index_sequence<mod>());
855 : : return colorvalues[h];
856 : : #else
857 : : #define o(a,b,...) a,
858 : : #define q(a,b,...) b,
859 : : static constinit const unsigned short colorkeys[] { docolors(o) };
860 : : static constinit const unsigned int colorvalues[] { docolors(q) };
861 : : #undef q
862 : : #undef o
863 : : /* This uses least data, but performs about log2(753) = 10 comparisons. */
864 : : /* Amount of data: 753*2 + 753*4 = ~4.5 kB */
865 : : auto i = std::lower_bound(std::begin(colorkeys), std::end(colorkeys), h);
866 : : if(i != std::end(colorkeys) && *i == h)
867 : : return colorvalues[ i-std::begin(colorkeys) ];
868 : : return 0;
869 : : #endif
870 : : }
871 : :
872 : : #ifdef RUN_TESTS
873 : : /* The word "volatile" is used to ensure that inlining does not foil branch statistics in lcov */
874 : 3 : TEST(color, unpack_ok)
875 : : {
876 : 1 : volatile unsigned r = 0x123456;
877 : 1 : EXPECT_EQ(Unpack(r), (std::array{0x12u, 0x34u, 0x56u}));
878 : 1 : }
879 : 3 : TEST(color, repack_ok)
880 : : {
881 : : // Basic behavior
882 : 1 : volatile unsigned r = 0x56;
883 : 1 : EXPECT_EQ(Repack({0x12,0x34,r}), 0x123456u);
884 : : // Clamping
885 : 1 : volatile unsigned q = 256u;
886 : 1 : EXPECT_EQ(Repack({q,q,q}), 0xFFFFFFu);
887 : : // Desaturating
888 : 1 : volatile unsigned m = 512u;
889 : 1 : EXPECT_EQ(Repack({m,0,0}), 0xFF6E6Eu);
890 : 1 : }
891 : 3 : TEST(color, mix)
892 : : {
893 : 1 : volatile unsigned a=10;
894 : 1 : EXPECT_EQ(Mix(0x000000, 0xFFFFFF, a,30,40), 0xBFBFBFu);
895 : 1 : EXPECT_EQ(Mix(0x111111, 0xFF0000, a,30,40), 0xC30404u);
896 : 1 : EXPECT_EQ(Mix(0x111111, 0x00FF00, a,30,40), 0x04C304u);
897 : 1 : EXPECT_EQ(Mix(0x111111, 0x0000FF, a,30,40), 0x0404C3u);
898 : 1 : }
899 : 3 : TEST(color, cmyk)
900 : : {
901 : 1 : volatile unsigned r = 0x123456;
902 : 1 : EXPECT_EQ(cmy2rgb(r), (0xFFFFFFu - 0x123456u));
903 : 1 : EXPECT_EQ(cmyk2rgb((r<<8)|0x78), 0x7D6B59u);
904 : 1 : }
905 : 3 : TEST(color, parsecolorname_utf8)
906 : : {
907 : 1 : EXPECT_EQ(ParseColorName("#123456"), 0x123456u);
908 : 1 : EXPECT_EQ(ParseColorName("#123"), 0x112233u);
909 : 1 : EXPECT_EQ(ParseColorName("rgb:1/2/3"), 0x112233u);
910 : 1 : EXPECT_EQ(ParseColorName("rgbi:0.5/0/1"), 0x7F00FFu);
911 : 1 : EXPECT_EQ(ParseColorName("black"), 0x000000u);
912 : 1 : EXPECT_EQ(ParseColorName("white"), 0xFFFFFFu);
913 : 1 : EXPECT_EQ(ParseColorName("blue"), 0x0000FFu);
914 : 1 : EXPECT_EQ(ParseColorName("light coral"), 0xF08080u);
915 : 1 : EXPECT_EQ(ParseColorName("LightCoral"), 0xF08080u);
916 : :
917 : : // For coverage, do all colors
918 : : #define o(hash,color,...) {for(auto s: {__VA_ARGS__})ParseColorName(s); FindColor(hash);}
919 [ + + + + : 754 : docolors(o)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ ]
920 : : #undef o
921 : 1 : }
922 : 3 : TEST(color, parsecolorname_char32)
923 : : {
924 : 2 : EXPECT_EQ(ParseColorName(U"#123456"), 0x123456u);
925 : 2 : EXPECT_EQ(ParseColorName(U"#123"), 0x112233u);
926 : 2 : EXPECT_EQ(ParseColorName(U"rgb:1/2/3"), 0x112233u);
927 : 2 : EXPECT_EQ(ParseColorName(U"rgbi:0.5/0/1"), 0x7F00FFu);
928 : 2 : EXPECT_EQ(ParseColorName(U"black"), 0x000000u);
929 : 2 : EXPECT_EQ(ParseColorName(U"white"), 0xFFFFFFu);
930 : 2 : EXPECT_EQ(ParseColorName(U"blue"), 0x0000FFu);
931 : 2 : EXPECT_EQ(ParseColorName(U"light coral"), 0xF08080u);
932 : 2 : EXPECT_EQ(ParseColorName(U"LightCoral"), 0xF08080u);
933 : 1 : }
934 : : #endif
|