1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_color.h"
4
5 #include <stdio.h> /* sscanf */
6 #include <string.h> /* strcmp */
7 #include <pobl/bl_debug.h>
8 #include <pobl/bl_map.h>
9 #include <pobl/bl_mem.h>
10 #include <pobl/bl_file.h>
11 #include <pobl/bl_conf_io.h>
12 #include <pobl/bl_str.h> /* strdup */
13
14 typedef struct rgb {
15 u_int8_t red;
16 u_int8_t green;
17 u_int8_t blue;
18 u_int8_t alpha;
19
20 } rgb_t;
21
22 BL_MAP_TYPEDEF(color_rgb, vt_color_t, rgb_t);
23
24 /* --- static variables --- */
25
26 static char *color_name_table[] = {
27 "hl_black", "hl_red", "hl_green", "hl_yellow", "hl_blue", "hl_magenta", "hl_cyan", "hl_white",
28 };
29
30 static u_int8_t vtsys_color_rgb_table[][3] = {
31 {0x00, 0x00, 0x00},
32 {0xcd, 0x00, 0x00},
33 {0x00, 0xcd, 0x00},
34 {0xcd, 0xcd, 0x00},
35 {0x00, 0x00, 0xee},
36 {0xcd, 0x00, 0xcd},
37 {0x00, 0xcd, 0xcd},
38 {0xe5, 0xe5, 0xe5},
39
40 {0x7f, 0x7f, 0x7f},
41 {0xff, 0x00, 0x00},
42 {0x00, 0xff, 0x00},
43 {0xff, 0xff, 0x00},
44 {0x5c, 0x5c, 0xff},
45 {0xff, 0x00, 0xff},
46 {0x00, 0xff, 0xff},
47 {0xff, 0xff, 0xff},
48 };
49
50 #if 0
51 static u_int8_t color256_rgb_table[][3] = {
52 /* CUBE COLOR(0x10-0xe7) */
53 {0x00, 0x00, 0x00},
54 {0x00, 0x00, 0x5f},
55 {0x00, 0x00, 0x87},
56 {0x00, 0x00, 0xaf},
57 {0x00, 0x00, 0xd7},
58 {0x00, 0x00, 0xff},
59 {0x00, 0x5f, 0x00},
60 {0x00, 0x5f, 0x5f},
61 {0x00, 0x5f, 0x87},
62 {0x00, 0x5f, 0xaf},
63 {0x00, 0x5f, 0xd7},
64 {0x00, 0x5f, 0xff},
65 {0x00, 0x87, 0x00},
66 {0x00, 0x87, 0x5f},
67 {0x00, 0x87, 0x87},
68 {0x00, 0x87, 0xaf},
69 {0x00, 0x87, 0xd7},
70 {0x00, 0x87, 0xff},
71 {0x00, 0xaf, 0x00},
72 {0x00, 0xaf, 0x5f},
73 {0x00, 0xaf, 0x87},
74 {0x00, 0xaf, 0xaf},
75 {0x00, 0xaf, 0xd7},
76 {0x00, 0xaf, 0xff},
77 {0x00, 0xd7, 0x00},
78 {0x00, 0xd7, 0x5f},
79 {0x00, 0xd7, 0x87},
80 {0x00, 0xd7, 0xaf},
81 {0x00, 0xd7, 0xd7},
82 {0x00, 0xd7, 0xff},
83 {0x00, 0xff, 0x00},
84 {0x00, 0xff, 0x5f},
85 {0x00, 0xff, 0x87},
86 {0x00, 0xff, 0xaf},
87 {0x00, 0xff, 0xd7},
88 {0x00, 0xff, 0xff},
89 {0x5f, 0x00, 0x00},
90 {0x5f, 0x00, 0x5f},
91 {0x5f, 0x00, 0x87},
92 {0x5f, 0x00, 0xaf},
93 {0x5f, 0x00, 0xd7},
94 {0x5f, 0x00, 0xff},
95 {0x5f, 0x5f, 0x00},
96 {0x5f, 0x5f, 0x5f},
97 {0x5f, 0x5f, 0x87},
98 {0x5f, 0x5f, 0xaf},
99 {0x5f, 0x5f, 0xd7},
100 {0x5f, 0x5f, 0xff},
101 {0x5f, 0x87, 0x00},
102 {0x5f, 0x87, 0x5f},
103 {0x5f, 0x87, 0x87},
104 {0x5f, 0x87, 0xaf},
105 {0x5f, 0x87, 0xd7},
106 {0x5f, 0x87, 0xff},
107 {0x5f, 0xaf, 0x00},
108 {0x5f, 0xaf, 0x5f},
109 {0x5f, 0xaf, 0x87},
110 {0x5f, 0xaf, 0xaf},
111 {0x5f, 0xaf, 0xd7},
112 {0x5f, 0xaf, 0xff},
113 {0x5f, 0xd7, 0x00},
114 {0x5f, 0xd7, 0x5f},
115 {0x5f, 0xd7, 0x87},
116 {0x5f, 0xd7, 0xaf},
117 {0x5f, 0xd7, 0xd7},
118 {0x5f, 0xd7, 0xff},
119 {0x5f, 0xff, 0x00},
120 {0x5f, 0xff, 0x5f},
121 {0x5f, 0xff, 0x87},
122 {0x5f, 0xff, 0xaf},
123 {0x5f, 0xff, 0xd7},
124 {0x5f, 0xff, 0xff},
125 {0x87, 0x00, 0x00},
126 {0x87, 0x00, 0x5f},
127 {0x87, 0x00, 0x87},
128 {0x87, 0x00, 0xaf},
129 {0x87, 0x00, 0xd7},
130 {0x87, 0x00, 0xff},
131 {0x87, 0x5f, 0x00},
132 {0x87, 0x5f, 0x5f},
133 {0x87, 0x5f, 0x87},
134 {0x87, 0x5f, 0xaf},
135 {0x87, 0x5f, 0xd7},
136 {0x87, 0x5f, 0xff},
137 {0x87, 0x87, 0x00},
138 {0x87, 0x87, 0x5f},
139 {0x87, 0x87, 0x87},
140 {0x87, 0x87, 0xaf},
141 {0x87, 0x87, 0xd7},
142 {0x87, 0x87, 0xff},
143 {0x87, 0xaf, 0x00},
144 {0x87, 0xaf, 0x5f},
145 {0x87, 0xaf, 0x87},
146 {0x87, 0xaf, 0xaf},
147 {0x87, 0xaf, 0xd7},
148 {0x87, 0xaf, 0xff},
149 {0x87, 0xd7, 0x00},
150 {0x87, 0xd7, 0x5f},
151 {0x87, 0xd7, 0x87},
152 {0x87, 0xd7, 0xaf},
153 {0x87, 0xd7, 0xd7},
154 {0x87, 0xd7, 0xff},
155 {0x87, 0xff, 0x00},
156 {0x87, 0xff, 0x5f},
157 {0x87, 0xff, 0x87},
158 {0x87, 0xff, 0xaf},
159 {0x87, 0xff, 0xd7},
160 {0x87, 0xff, 0xff},
161 {0xaf, 0x00, 0x00},
162 {0xaf, 0x00, 0x5f},
163 {0xaf, 0x00, 0x87},
164 {0xaf, 0x00, 0xaf},
165 {0xaf, 0x00, 0xd7},
166 {0xaf, 0x00, 0xff},
167 {0xaf, 0x5f, 0x00},
168 {0xaf, 0x5f, 0x5f},
169 {0xaf, 0x5f, 0x87},
170 {0xaf, 0x5f, 0xaf},
171 {0xaf, 0x5f, 0xd7},
172 {0xaf, 0x5f, 0xff},
173 {0xaf, 0x87, 0x00},
174 {0xaf, 0x87, 0x5f},
175 {0xaf, 0x87, 0x87},
176 {0xaf, 0x87, 0xaf},
177 {0xaf, 0x87, 0xd7},
178 {0xaf, 0x87, 0xff},
179 {0xaf, 0xaf, 0x00},
180 {0xaf, 0xaf, 0x5f},
181 {0xaf, 0xaf, 0x87},
182 {0xaf, 0xaf, 0xaf},
183 {0xaf, 0xaf, 0xd7},
184 {0xaf, 0xaf, 0xff},
185 {0xaf, 0xd7, 0x00},
186 {0xaf, 0xd7, 0x5f},
187 {0xaf, 0xd7, 0x87},
188 {0xaf, 0xd7, 0xaf},
189 {0xaf, 0xd7, 0xd7},
190 {0xaf, 0xd7, 0xff},
191 {0xaf, 0xff, 0x00},
192 {0xaf, 0xff, 0x5f},
193 {0xaf, 0xff, 0x87},
194 {0xaf, 0xff, 0xaf},
195 {0xaf, 0xff, 0xd7},
196 {0xaf, 0xff, 0xff},
197 {0xd7, 0x00, 0x00},
198 {0xd7, 0x00, 0x5f},
199 {0xd7, 0x00, 0x87},
200 {0xd7, 0x00, 0xaf},
201 {0xd7, 0x00, 0xd7},
202 {0xd7, 0x00, 0xff},
203 {0xd7, 0x5f, 0x00},
204 {0xd7, 0x5f, 0x5f},
205 {0xd7, 0x5f, 0x87},
206 {0xd7, 0x5f, 0xaf},
207 {0xd7, 0x5f, 0xd7},
208 {0xd7, 0x5f, 0xff},
209 {0xd7, 0x87, 0x00},
210 {0xd7, 0x87, 0x5f},
211 {0xd7, 0x87, 0x87},
212 {0xd7, 0x87, 0xaf},
213 {0xd7, 0x87, 0xd7},
214 {0xd7, 0x87, 0xff},
215 {0xd7, 0xaf, 0x00},
216 {0xd7, 0xaf, 0x5f},
217 {0xd7, 0xaf, 0x87},
218 {0xd7, 0xaf, 0xaf},
219 {0xd7, 0xaf, 0xd7},
220 {0xd7, 0xaf, 0xff},
221 {0xd7, 0xd7, 0x00},
222 {0xd7, 0xd7, 0x5f},
223 {0xd7, 0xd7, 0x87},
224 {0xd7, 0xd7, 0xaf},
225 {0xd7, 0xd7, 0xd7},
226 {0xd7, 0xd7, 0xff},
227 {0xd7, 0xff, 0x00},
228 {0xd7, 0xff, 0x5f},
229 {0xd7, 0xff, 0x87},
230 {0xd7, 0xff, 0xaf},
231 {0xd7, 0xff, 0xd7},
232 {0xd7, 0xff, 0xff},
233 {0xff, 0x00, 0x00},
234 {0xff, 0x00, 0x5f},
235 {0xff, 0x00, 0x87},
236 {0xff, 0x00, 0xaf},
237 {0xff, 0x00, 0xd7},
238 {0xff, 0x00, 0xff},
239 {0xff, 0x5f, 0x00},
240 {0xff, 0x5f, 0x5f},
241 {0xff, 0x5f, 0x87},
242 {0xff, 0x5f, 0xaf},
243 {0xff, 0x5f, 0xd7},
244 {0xff, 0x5f, 0xff},
245 {0xff, 0x87, 0x00},
246 {0xff, 0x87, 0x5f},
247 {0xff, 0x87, 0x87},
248 {0xff, 0x87, 0xaf},
249 {0xff, 0x87, 0xd7},
250 {0xff, 0x87, 0xff},
251 {0xff, 0xaf, 0x00},
252 {0xff, 0xaf, 0x5f},
253 {0xff, 0xaf, 0x87},
254 {0xff, 0xaf, 0xaf},
255 {0xff, 0xaf, 0xd7},
256 {0xff, 0xaf, 0xff},
257 {0xff, 0xd7, 0x00},
258 {0xff, 0xd7, 0x5f},
259 {0xff, 0xd7, 0x87},
260 {0xff, 0xd7, 0xaf},
261 {0xff, 0xd7, 0xd7},
262 {0xff, 0xd7, 0xff},
263 {0xff, 0xff, 0x00},
264 {0xff, 0xff, 0x5f},
265 {0xff, 0xff, 0x87},
266 {0xff, 0xff, 0xaf},
267 {0xff, 0xff, 0xd7},
268 {0xff, 0xff, 0xff},
269
270 /* GRAY SCALE COLOR(0xe8-0xff) */
271 {0x08, 0x08, 0x08},
272 {0x12, 0x12, 0x12},
273 {0x1c, 0x1c, 0x1c},
274 {0x26, 0x26, 0x26},
275 {0x30, 0x30, 0x30},
276 {0x3a, 0x3a, 0x3a},
277 {0x44, 0x44, 0x44},
278 {0x4e, 0x4e, 0x4e},
279 {0x58, 0x58, 0x58},
280 {0x62, 0x62, 0x62},
281 {0x6c, 0x6c, 0x6c},
282 {0x76, 0x76, 0x76},
283 {0x80, 0x80, 0x80},
284 {0x8a, 0x8a, 0x8a},
285 {0x94, 0x94, 0x94},
286 {0x9e, 0x9e, 0x9e},
287 {0xa8, 0xa8, 0xa8},
288 {0xb2, 0xb2, 0xb2},
289 {0xbc, 0xbc, 0xbc},
290 {0xc6, 0xc6, 0xc6},
291 {0xd0, 0xd0, 0xd0},
292 {0xda, 0xda, 0xda},
293 {0xe4, 0xe4, 0xe4},
294 {0xee, 0xee, 0xee},
295 };
296 #endif
297
298 static char *color_file = "mlterm/color";
299 static BL_MAP(color_rgb) color_config;
300 static u_int num_changed_256_colors;
301
302 static struct {
303 u_int is_changed : 1;
304 u_int mark : 7;
305 u_int8_t red;
306 u_int8_t green;
307 u_int8_t blue;
308
309 } * ext_color_table;
310 static u_int ext_color_mark = 1;
311
312 static int color_distance_threshold = COLOR_DISTANCE_THRESHOLD;
313 static int use_pseudo_color = 0;
314
315 /* --- static functions --- */
316
get_default_rgb(vt_color_t color,u_int8_t * red,u_int8_t * green,u_int8_t * blue)317 static void get_default_rgb(vt_color_t color, /* is 255 or less */
318 u_int8_t *red, u_int8_t *green, u_int8_t *blue) {
319 if (IS_VTSYS_COLOR(color)) {
320 *red = vtsys_color_rgb_table[color][0];
321 *green = vtsys_color_rgb_table[color][1];
322 *blue = vtsys_color_rgb_table[color][2];
323 } else if (color <= 0xe7) {
324 u_int8_t tmp;
325
326 tmp = (color - 0x10) % 6;
327 *blue = tmp ? (tmp * 40 + 55) & 0xff : 0;
328
329 tmp = ((color - 0x10) / 6) % 6;
330 *green = tmp ? (tmp * 40 + 55) & 0xff : 0;
331
332 tmp = ((color - 0x10) / 36) % 6;
333 *red = tmp ? (tmp * 40 + 55) & 0xff : 0;
334 } else /* if( color >= 0xe8) */
335 {
336 u_int8_t tmp;
337
338 tmp = (color - 0xe8) * 10 + 8;
339
340 *blue = tmp;
341 *green = tmp;
342 *red = tmp;
343 }
344 }
345
get_color_rgb_pair(vt_color_t color)346 static BL_PAIR(color_rgb) get_color_rgb_pair(vt_color_t color) {
347 BL_PAIR(color_rgb) pair;
348
349 bl_map_get(color_config, color, pair);
350
351 return pair;
352 }
353
color_config_set_rgb(vt_color_t color,u_int8_t red,u_int8_t green,u_int8_t blue,u_int8_t alpha)354 static int color_config_set_rgb(vt_color_t color, /* is 255 or less */
355 u_int8_t red, u_int8_t green, u_int8_t blue, u_int8_t alpha) {
356 BL_PAIR(color_rgb) pair;
357 int result;
358 rgb_t rgb;
359
360 rgb.red = red;
361 rgb.green = green;
362 rgb.blue = blue;
363 rgb.alpha = alpha;
364
365 if ((pair = get_color_rgb_pair(color))) {
366 u_int8_t r;
367 u_int8_t g;
368 u_int8_t b;
369
370 if (pair->value.red == red && pair->value.green == green && pair->value.blue == blue &&
371 pair->value.alpha == alpha) {
372 /* Not changed */
373
374 #ifdef DEBUG
375 bl_debug_printf(BL_DEBUG_TAG " color %d rgb(%02x%02x%02x%02x) not changed.\n", color, red,
376 green, blue, alpha);
377 #endif
378
379 return 0;
380 }
381
382 get_default_rgb(color, &r, &g, &b);
383
384 if (r == red && g == green && b == blue && alpha == 0xff) {
385 if (IS_256_COLOR(color)) {
386 num_changed_256_colors--;
387 }
388
389 bl_map_erase_simple(result, color_config, color);
390 } else {
391 pair->value = rgb;
392 }
393
394 return 1;
395 } else {
396 u_int8_t r;
397 u_int8_t g;
398 u_int8_t b;
399
400 /*
401 * The same rgb as the default is rejected in 256 color.
402 * The same rgb as the default is not rejected in sys color
403 * for backward compatibility with 3.1.5 or before. (If rejected,
404 * mlterm -fg hl_white doesn't work even if hl_white is defined
405 * in ~/.mlterm/color.)
406 */
407
408 if (IS_256_COLOR(color)) {
409 if (!vt_get_color_rgba(color, &r, &g, &b, NULL)) {
410 return 0;
411 }
412
413 if (red == r && green == g && blue == b && alpha == 0xff) {
414 /* Not changed */
415
416 #ifdef DEBUG
417 bl_debug_printf(BL_DEBUG_TAG " color %d rgb(%02x%02x%02x%02x) not changed.\n", color, red,
418 green, blue, alpha);
419 #endif
420
421 return 0;
422 }
423 #ifdef DEBUG
424 else {
425 bl_debug_printf(BL_DEBUG_TAG " color %d rgb(%02x%02x%02x) changed => %02x%02x%02x.\n",
426 color, r, g, b, red, green, blue);
427 }
428 #endif
429
430 num_changed_256_colors++;
431 }
432
433 bl_map_set(result, color_config, color, rgb);
434
435 return result;
436 }
437 }
438
color_config_get_rgb(vt_color_t color,u_int8_t * red,u_int8_t * green,u_int8_t * blue,u_int8_t * alpha)439 static int color_config_get_rgb(vt_color_t color, u_int8_t *red, u_int8_t *green, u_int8_t *blue,
440 u_int8_t *alpha /* can be NULL */
441 ) {
442 BL_PAIR(color_rgb) pair;
443
444 if ((pair = get_color_rgb_pair(color)) == NULL) {
445 return 0;
446 }
447
448 *red = pair->value.red;
449 *blue = pair->value.blue;
450 *green = pair->value.green;
451 if (alpha) {
452 *alpha = pair->value.alpha;
453 }
454
455 #ifdef __DEBUG
456 bl_debug_printf(BL_DEBUG_TAG " %d's rgb => %d %d %d\n", color, *red, *blue, *green);
457 #endif
458
459 return 1;
460 }
461
parse_conf(char * color_name,char * rgb)462 static int parse_conf(char *color_name, char *rgb) {
463 u_int8_t red;
464 u_int8_t green;
465 u_int8_t blue;
466 u_int8_t alpha;
467 vt_color_t color;
468
469 /*
470 * Illegal color name is rejected.
471 */
472 if ((color = vt_get_color(color_name)) == VT_UNKNOWN_COLOR) {
473 return 0;
474 }
475
476 if (*rgb == '\0') {
477 if (!get_color_rgb_pair(color)) {
478 return 0;
479 } else {
480 int result;
481
482 if (IS_256_COLOR(color)) {
483 num_changed_256_colors--;
484 }
485
486 bl_map_erase_simple(result, color_config, color);
487
488 return 1;
489 }
490 } else {
491 /* XXX "red", "green", "blue" and so on are available for rgb */
492 vt_color_t rgb_color = vt_get_color(rgb);
493
494 if ((rgb_color != VT_UNKNOWN_COLOR) ?
495 !vt_get_color_rgba(color, &red, &green, &blue, &alpha) :
496 !vt_color_parse_rgb_name(&red, &green, &blue, &alpha, rgb)) {
497 #ifdef DEBUG
498 bl_warn_printf(BL_DEBUG_TAG " illegal rgblist format (%s,%s)\n", color_name, rgb);
499 #endif
500
501 return 0;
502 }
503 }
504
505 #ifdef __DEBUG
506 bl_debug_printf("%s(%d) = red %x green %x blue %x\n", color_name, color, red, green, blue);
507 #endif
508
509 return color_config_set_rgb(color, red, green, blue, alpha);
510 }
511
read_conf(const char * filename)512 static void read_conf(const char *filename) {
513 bl_file_t *from;
514 char *color_name;
515 char *rgb;
516
517 if (!(from = bl_file_open(filename, "r"))) {
518 #ifdef DEBUG
519 bl_warn_printf(BL_DEBUG_TAG " %s couldn't be opened.\n", filename);
520 #endif
521
522 return;
523 }
524
525 while (bl_conf_io_read(from, &color_name, &rgb)) {
526 parse_conf(color_name, rgb);
527 }
528
529 bl_file_close(from);
530 }
531
532 /* --- global functions --- */
533
vt_set_color_mode(const char * mode)534 void vt_set_color_mode(const char *mode) {
535 if (strcmp(mode, "256") == 0) {
536 color_distance_threshold = COLOR_DISTANCE_THRESHOLD;
537 use_pseudo_color = 1;
538 } else {
539 if (strcmp(mode, "true") == 0) {
540 color_distance_threshold = 40; /* 9 + 30 + 1 */
541 } else /* if( strcmp( mode , "high") == 0 */
542 {
543 color_distance_threshold = COLOR_DISTANCE_THRESHOLD;
544 }
545 use_pseudo_color = 0;
546 }
547 }
548
vt_get_color_mode(void)549 char *vt_get_color_mode(void) {
550 if (use_pseudo_color) {
551 return "256";
552 } else if (color_distance_threshold == 40) {
553 return "true";
554 } else {
555 return "high";
556 }
557 }
558
vt_color_config_init(void)559 void vt_color_config_init(void) {
560 char *rcpath;
561
562 bl_map_new_with_size(vt_color_t, rgb_t, color_config, bl_map_hash_int, bl_map_compare_int, 16);
563
564 if ((rcpath = bl_get_sys_rc_path(color_file))) {
565 read_conf(rcpath);
566 free(rcpath);
567 }
568
569 if ((rcpath = bl_get_user_rc_path(color_file))) {
570 read_conf(rcpath);
571 free(rcpath);
572 }
573 }
574
vt_color_config_final(void)575 void vt_color_config_final(void) {
576 bl_map_destroy(color_config);
577 color_config = NULL;
578 }
579
580 /*
581 * Return value 0 means customization failed or not changed.
582 * Return value -1 means saving failed.
583 */
vt_customize_color_file(char * color,char * rgb,int save)584 int vt_customize_color_file(char *color, char *rgb, int save) {
585 if (!color_config || !parse_conf(color, rgb)) {
586 return 0;
587 }
588
589 if (save) {
590 char *path;
591 bl_conf_write_t *conf;
592
593 if ((path = bl_get_user_rc_path(color_file)) == NULL) {
594 return -1;
595 }
596
597 conf = bl_conf_write_open(path);
598 free(path);
599 if (conf == NULL) {
600 return -1;
601 }
602
603 bl_conf_io_write(conf, color, rgb);
604
605 bl_conf_write_close(conf);
606 }
607
608 return 1;
609 }
610
vt_get_color_name(vt_color_t color)611 char *vt_get_color_name(vt_color_t color) {
612 if (IS_VTSYS_COLOR(color)) {
613 if (color & VT_BOLD_COLOR_MASK) {
614 return color_name_table[color & ~VT_BOLD_COLOR_MASK];
615 } else {
616 return color_name_table[color] + 3;
617 }
618 } else if (IS_256_COLOR(color)) {
619 /* XXX Not reentrant */
620 static char color_name_256[4];
621
622 snprintf(color_name_256, sizeof(color_name_256), "%d", color);
623
624 return color_name_256;
625 } else {
626 return NULL;
627 }
628 }
629
vt_get_color(const char * name)630 vt_color_t vt_get_color(const char *name) {
631 vt_color_t color;
632
633 if (sscanf(name, "%d", (int*)&color) == 1) {
634 if (IS_VTSYS256_COLOR(color)) {
635 return color;
636 }
637 }
638
639 for (color = VT_BLACK; color <= VT_WHITE; color++) {
640 if (strcmp(name, color_name_table[color] + 3) == 0) {
641 return color;
642 } else if (strcmp(name, color_name_table[color]) == 0) {
643 return color | VT_BOLD_COLOR_MASK;
644 }
645 }
646
647 return VT_UNKNOWN_COLOR;
648 }
649
vt_get_color_rgba(vt_color_t color,u_int8_t * red,u_int8_t * green,u_int8_t * blue,u_int8_t * alpha)650 int vt_get_color_rgba(vt_color_t color, u_int8_t *red, u_int8_t *green, u_int8_t *blue,
651 u_int8_t *alpha /* can be NULL */
652 ) {
653 if (!IS_VALID_COLOR_EXCEPT_SPECIAL_COLORS(color)) {
654 return 0;
655 }
656
657 if (IS_EXT_COLOR(color)) {
658 if (!ext_color_table || ext_color_table[EXT_COLOR_TO_INDEX(color)].mark == 0) {
659 return 0;
660 }
661
662 *red = ext_color_table[EXT_COLOR_TO_INDEX(color)].red;
663 *green = ext_color_table[EXT_COLOR_TO_INDEX(color)].green;
664 *blue = ext_color_table[EXT_COLOR_TO_INDEX(color)].blue;
665 } else if (color_config && color_config_get_rgb(color, red, green, blue, alpha)) {
666 return 1;
667 } else {
668 get_default_rgb(color, red, green, blue);
669 }
670
671 if (alpha) {
672 *alpha = 0xff;
673 }
674
675 return 1;
676 }
677
vt_color_parse_rgb_name(u_int8_t * red,u_int8_t * green,u_int8_t * blue,u_int8_t * alpha,const char * name)678 int vt_color_parse_rgb_name(u_int8_t *red, u_int8_t *green, u_int8_t *blue, u_int8_t *alpha,
679 const char *name) {
680 int r;
681 int g;
682 int b;
683 int a;
684 size_t name_len;
685 char *format;
686 int has_alpha;
687 int long_color;
688
689 a = 0xffff;
690 has_alpha = 0;
691 long_color = 0;
692
693 name_len = strlen(name);
694
695 if (name_len >= 14) {
696 /*
697 * XXX
698 * "RRRR-GGGG-BBBB" length is 14, but 2.4.0 or before accepts
699 * "RRRR-GGGG-BBBB....."(trailing any characters) format and
700 * what is worse "RRRR-GGGG-BBBB;" appears in etc/color sample file.
701 * So, more than 14 length is also accepted for backward compatiblity.
702 */
703 if (sscanf(name, "%4x-%4x-%4x", &r, &g, &b) == 3) {
704 goto end;
705 } else if (name_len == 16) {
706 format = "rgba:%2x/%2x/%2x/%2x";
707 has_alpha = 1;
708 } else if (name_len == 17) {
709 format = "#%4x%4x%4x%4x";
710 has_alpha = 1;
711 long_color = 1;
712 } else if (name_len == 18) {
713 format = "rgb:%4x/%4x/%4x";
714 long_color = 1;
715 } else if (name_len == 24) {
716 format = "rgba:%4x/%4x/%4x/%4x";
717 long_color = 1;
718 has_alpha = 1;
719 } else {
720 goto fail;
721 }
722 } else {
723 if (name_len == 7) {
724 format = "#%2x%2x%2x";
725 } else if (name_len == 9) {
726 format = "#%2x%2x%2x%2x";
727 has_alpha = 1;
728 } else if (name_len == 12) {
729 format = "rgb:%2x/%2x/%2x";
730 } else if (name_len == 13) {
731 format = "#%4x%4x%4x";
732 long_color = 1;
733 } else {
734 goto fail;
735 }
736 }
737
738 if (sscanf(name, format, &r, &g, &b, &a) != (3 + has_alpha)) {
739 goto fail;
740 }
741
742 end:
743 if (long_color) {
744 *red = (r >> 8) & 0xff;
745 *green = (g >> 8) & 0xff;
746 *blue = (b >> 8) & 0xff;
747 *alpha = (a >> 8) & 0xff;
748 } else {
749 *red = r;
750 *green = g;
751 *blue = b;
752 *alpha = a & 0xff;
753 }
754
755 #ifdef __DEBUG
756 bl_debug_printf(BL_DEBUG_TAG " %s => %x %x %x %x\n", name, *red, *green, *blue, *alpha);
757 #endif
758
759 return 1;
760
761 fail:
762 #if 1
763 /* Backward compatibility with mlterm-3.1.5 or before. */
764 if (color_config) {
765 /*
766 * If 'name' is a color name defined in ~/.mlterm/color, its rgb is returned.
767 * (for ui_load_named_xcolor())
768 */
769 vt_color_t color;
770
771 if ((color = vt_get_color(name)) != VT_UNKNOWN_COLOR &&
772 color_config_get_rgb(color, red, green, blue, alpha)) {
773 return 1;
774 }
775 }
776 #endif
777
778 return 0;
779 }
780
vt_color_force_linear_search(int flag)781 void vt_color_force_linear_search(int flag) {
782 if (flag) {
783 num_changed_256_colors++;
784 } else {
785 num_changed_256_colors--;
786 }
787 }
788
789 /*
790 * Return the number of colors which should be searched after this function.
791 */
vt_get_closest_256_color(vt_color_t * closest,u_int * min_diff,u_int8_t red,u_int8_t green,u_int8_t blue,int threshold)792 u_int vt_get_closest_256_color(vt_color_t *closest, u_int *min_diff, u_int8_t red, u_int8_t green,
793 u_int8_t blue, int threshold) {
794 int r, g, b;
795 int tmp;
796 vt_color_t color;
797 u_int8_t rgb[3];
798 u_int diff;
799 int diff_r, diff_g, diff_b;
800 int count;
801 int num;
802
803 if (num_changed_256_colors > 0) {
804 return 256;
805 }
806
807 /*
808 * 0 - 47 => 0
809 * 48 - 114 => 1
810 * 115 - 154 => 2
811 * ...
812 */
813 tmp = (red <= 114 ? (red >= 48) : ((red - 55) + 20) / 40);
814 r = tmp ? (tmp * 40 + 55) & 0xff : 0;
815 color = tmp * 36;
816 tmp = (green <= 114 ? (green >= 48) : ((green - 55) + 20) / 40);
817 g = tmp ? (tmp * 40 + 55) & 0xff : 0;
818 color += tmp * 6;
819 tmp = (blue <= 114 ? (blue >= 48) : ((blue - 55) + 20) / 40);
820 b = tmp ? (tmp * 40 + 55) & 0xff : 0;
821 color += tmp;
822 /* lazy color-space conversion */
823 diff_r = red - r;
824 diff_g = green - g;
825 diff_b = blue - b;
826 diff = COLOR_DISTANCE(diff_r, diff_g, diff_b);
827 if (diff < *min_diff) {
828 *min_diff = diff;
829 *closest = color + 0x10;
830 if (diff < threshold) {
831 return 0;
832 }
833 }
834
835 num = 1;
836 rgb[0] = red;
837
838 if (red != green) {
839 rgb[num++] = green;
840 }
841
842 if (red != blue && green != blue) {
843 rgb[num++] = blue;
844 }
845
846 for (count = 0; count < num; count++) {
847 tmp = (rgb[count] >= 233 ? 23 : (rgb[count] <= 12 ? 0 : ((rgb[count] - 8) + 5) / 10));
848 r = g = b = tmp * 10 + 8;
849 /* lazy color-space conversion */
850 diff_r = red - r;
851 diff_g = green - g;
852 diff_b = blue - b;
853 diff = COLOR_DISTANCE(diff_r, diff_g, diff_b);
854 if (diff < *min_diff) {
855 *min_diff = diff;
856 *closest = tmp + 0xe8;
857 if (diff < threshold) {
858 return 0;
859 }
860 }
861 }
862
863 return 16;
864 }
865
vt_get_closest_color(u_int8_t red,u_int8_t green,u_int8_t blue)866 vt_color_t vt_get_closest_color(u_int8_t red, u_int8_t green, u_int8_t blue) {
867 vt_color_t closest = VT_UNKNOWN_COLOR;
868 vt_color_t color;
869 u_int linear_search_max;
870 u_int min = 0xffffff;
871 vt_color_t oldest_color;
872 u_int oldest_mark;
873 u_int max = 0;
874
875 #ifdef __DEBUG
876 vt_color_t hit_closest = VT_UNKNOWN_COLOR;
877 vt_get_closest_256_color(&hit_closest, &min, red, green, blue);
878 min = 0xffffff;
879
880 for (color = 16; color < 256; color++)
881 #else
882 if ((linear_search_max = vt_get_closest_256_color(&closest, &min, red, green, blue,
883 color_distance_threshold)) == 0) {
884 return closest;
885 }
886
887 for (color = 0; color < linear_search_max; color++)
888 #endif
889 {
890 u_int8_t r;
891 u_int8_t g;
892 u_int8_t b;
893 u_int8_t a;
894
895 if (vt_get_color_rgba(color, &r, &g, &b, &a) && a == 0xff) {
896 u_int diff;
897 int diff_r, diff_g, diff_b;
898
899 /* lazy color-space conversion */
900 diff_r = red - r;
901 diff_g = green - g;
902 diff_b = blue - b;
903 diff = COLOR_DISTANCE(diff_r, diff_g, diff_b);
904 if (diff < min) {
905 min = diff;
906 closest = color;
907 if (diff < color_distance_threshold) {
908 #ifdef __DEBUG
909 /*
910 * XXX
911 * The result of linear search of boundary values
912 * (115, 195 etc) is different from that of
913 * vt_get_closest_256_color() of it.
914 */
915 if (closest != hit_closest) {
916 bl_debug_printf("ERROR %x %x %x -> %x<=>%x\n", red, green, blue, closest, hit_closest);
917 }
918 #endif
919
920 return closest;
921 }
922 }
923 }
924 }
925
926 #ifdef __DEBUG
927 /*
928 * XXX
929 * The result of linear search of boundary values (115, 195 etc) is
930 * different from that of vt_get_closest_256_color() of it.
931 */
932 if (closest != hit_closest) {
933 bl_debug_printf("ERROR %x %x %x -> %x<=>%x\n", red, green, blue, closest, hit_closest);
934 }
935 #endif
936
937 if (use_pseudo_color ||
938 (!ext_color_table && !(ext_color_table = calloc(MAX_EXT_COLORS, sizeof(*ext_color_table))))) {
939 return closest;
940 }
941
942 if ((oldest_mark = ext_color_mark / 2) == MAX_EXT_COLORS / 2) {
943 oldest_mark = 1;
944 } else {
945 oldest_mark++;
946 }
947
948 if (ext_color_mark == MAX_EXT_COLORS) {
949 ext_color_mark = 2;
950 } else {
951 ext_color_mark++;
952 }
953
954 color = 0;
955 while (ext_color_table[color].mark) {
956 u_int diff;
957 int diff_r, diff_g, diff_b;
958
959 /* lazy color-space conversion */
960 diff_r = red - ext_color_table[color].red;
961 diff_g = green - ext_color_table[color].green;
962 diff_b = blue - ext_color_table[color].blue;
963 diff = COLOR_DISTANCE(diff_r, diff_g, diff_b);
964 if (diff < min) {
965 min = diff;
966 if (diff < color_distance_threshold) {
967 /* Set new mark */
968 ext_color_table[color].mark = ext_color_mark / 2;
969
970 #ifdef __DEBUG
971 bl_debug_printf(BL_DEBUG_TAG " Use cached ext color %x\n", INDEX_TO_EXT_COLOR(color));
972 #endif
973
974 return INDEX_TO_EXT_COLOR(color);
975 }
976 }
977
978 if (max == MAX_EXT_COLORS / 2) {
979 /* do nothing */
980 } else if (ext_color_table[color].mark == oldest_mark) {
981 max = MAX_EXT_COLORS / 2;
982 oldest_color = color;
983 } else {
984 if (ext_color_table[color].mark < oldest_mark) {
985 diff = oldest_mark - ext_color_table[color].mark;
986 } else /* if( ext_color_table[color].mark > oldest_mark) */
987 {
988 diff = oldest_mark + (MAX_EXT_COLORS / 2) - ext_color_table[color].mark;
989 }
990
991 if (diff > max) {
992 max = diff;
993 oldest_color = color;
994 }
995 }
996
997 if (++color == MAX_EXT_COLORS) {
998 color = oldest_color;
999 ext_color_table[color].is_changed = 1;
1000
1001 #ifdef DEBUG
1002 bl_debug_printf(BL_DEBUG_TAG " Destroy ext color %x mark %x\n", INDEX_TO_EXT_COLOR(color),
1003 ext_color_table[color].mark);
1004 #endif
1005
1006 break;
1007 }
1008 }
1009
1010 ext_color_table[color].mark = ext_color_mark / 2;
1011 ext_color_table[color].red = red;
1012 ext_color_table[color].green = green;
1013 ext_color_table[color].blue = blue;
1014
1015 #ifdef DEBUG
1016 bl_debug_printf(BL_DEBUG_TAG "New ext color %.2x: r%.2x g%x b%.2x mark %x\n",
1017 INDEX_TO_EXT_COLOR(color), red, green, blue, ext_color_table[color].mark);
1018 #endif
1019
1020 return INDEX_TO_EXT_COLOR(color);
1021 }
1022
vt_ext_color_is_changed(vt_color_t color)1023 int vt_ext_color_is_changed(vt_color_t color) {
1024 if (ext_color_table[EXT_COLOR_TO_INDEX(color)].is_changed) {
1025 ext_color_table[EXT_COLOR_TO_INDEX(color)].is_changed = 0;
1026
1027 return 1;
1028 } else {
1029 return 0;
1030 }
1031 }
1032