1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "ui_font_config.h"
4
5 #include <string.h> /* memset */
6
7 #include <pobl/bl_mem.h> /* malloc */
8 #include <pobl/bl_str.h> /* strdup */
9 #include <pobl/bl_util.h> /* DIGIT_STR_LEN */
10 #include <pobl/bl_conf_io.h>
11 #include <pobl/bl_file.h>
12 #include <pobl/bl_debug.h>
13
14 #include <vt_char.h>
15 #include <vt_char_encoding.h> /* vt_parse_unicode_area */
16
17 #define DEFAULT_FONT 0x1ff /* MAX_CHARSET */
18
19 #if 0
20 #define __DEBUG
21 #endif
22
23 typedef struct cs_table {
24 char *name;
25 ef_charset_t cs;
26
27 } cs_table_t;
28
29 typedef struct custom_cache {
30 const char *file;
31 char *key;
32 char *value;
33
34 } custom_cache_t;
35
36 /* --- static variables --- */
37
38 #if defined(USE_FRAMEBUFFER) || defined(USE_CONSOLE) || defined(USE_WAYLAND) || defined(USE_SDL2)
39
40 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
41 static int use_aafont;
42 #define FONT_FILE (use_aafont ? aafont_file + 7 : "font")
43 #define VFONT_FILE (use_aafont ? vaafont_file + 7 : "vfont")
44 #define TFONT_FILE (use_aafont ? taafont_file + 7 : "tfont")
45 #else
46 #define FONT_FILE "font"
47 #define VFONT_FILE "vfont"
48 #define TFONT_FILE "tfont"
49 #endif
50
51 static char *font_file = "mlterm/font-fb";
52 static char *vfont_file = "mlterm/vfont-fb";
53 static char *tfont_file = "mlterm/tfont-fb";
54
55 #else
56
57 #define FONT_FILE (font_file + 7)
58 #define VFONT_FILE (vfont_file + 7)
59 #define TFONT_FILE (tfont_file + 7)
60 static char *font_file = "mlterm/font";
61 static char *vfont_file = "mlterm/vfont";
62 static char *tfont_file = "mlterm/tfont";
63
64 #endif
65
66 static char *aafont_file = "mlterm/aafont";
67 static char *vaafont_file = "mlterm/vaafont";
68 static char *taafont_file = "mlterm/taafont";
69
70 /*
71 * If this table is changed, ui_font.c:cs_info_table and mc_font.c:cs_info_table
72 * shoule be also changed.
73 */
74 static cs_table_t cs_table[] = {
75 {"ISO10646_UCS4_1", ISO10646_UCS4_1},
76
77 {"DEC_SPECIAL", DEC_SPECIAL},
78 {"ISO8859_1", ISO8859_1_R},
79 {"ISO8859_2", ISO8859_2_R},
80 {"ISO8859_3", ISO8859_3_R},
81 {"ISO8859_4", ISO8859_4_R},
82 {"ISO8859_5", ISO8859_5_R},
83 {"ISO8859_6", ISO8859_6_R},
84 {"ISO8859_7", ISO8859_7_R},
85 {"ISO8859_8", ISO8859_8_R},
86 {"ISO8859_9", ISO8859_9_R},
87 {"ISO8859_10", ISO8859_10_R},
88 {"TIS620", TIS620_2533},
89 {"ISO8859_13", ISO8859_13_R},
90 {"ISO8859_14", ISO8859_14_R},
91 {"ISO8859_15", ISO8859_15_R},
92 {"ISO8859_16", ISO8859_16_R},
93 {"TCVN5712", TCVN5712_3_1993},
94 {"ISCII_ASSAMESE", ISCII_ASSAMESE},
95 {"ISCII_BENGALI", ISCII_BENGALI},
96 {"ISCII_GUJARATI", ISCII_GUJARATI},
97 {"ISCII_HINDI", ISCII_HINDI},
98 {"ISCII_KANNADA", ISCII_KANNADA},
99 {"ISCII_MALAYALAM", ISCII_MALAYALAM},
100 {"ISCII_ORIYA", ISCII_ORIYA},
101 {"ISCII_PUNJABI", ISCII_PUNJABI},
102 {"ISCII_TAMIL", ISCII_TAMIL},
103 {"ISCII_TELUGU", ISCII_TELUGU},
104 {"VISCII", VISCII},
105 {"KOI8_R", KOI8_R},
106 {"KOI8_U", KOI8_U},
107 #if 0
108 /*
109 * Koi8_t and georgian_ps charsets can be shown by unicode font only.
110 */
111 {"KOI8_T", KOI8_T},
112 {"GEORGIAN_PS", GEORGIAN_PS},
113 #endif
114 #ifdef USE_WIN32GUI
115 {"CP1250", CP1250},
116 {"CP1251", CP1251},
117 {"CP1252", CP1252},
118 {"CP1253", CP1253},
119 {"CP1254", CP1254},
120 {"CP1255", CP1255},
121 {"CP1256", CP1256},
122 {"CP1257", CP1257},
123 {"CP1258", CP1258},
124 #endif
125 {"JISX0201_KATA", JISX0201_KATA},
126 {"JISX0201_ROMAN", JISX0201_ROMAN},
127 {"JISX0208_1978", JISC6226_1978},
128 {"JISC6226_1978", JISC6226_1978},
129 {"JISX0208_1983", JISX0208_1983},
130 {"JISX0208_1990", JISX0208_1990},
131 {"JISX0212_1990", JISX0212_1990},
132 {"JISX0213_2000_1", JISX0213_2000_1},
133 {"JISX0213_2000_2", JISX0213_2000_2},
134 {"KSC5601_1987", KSC5601_1987},
135 {"KSX1001_1997", KSC5601_1987},
136 #if 0
137 /*
138 * XXX
139 * UHC and JOHAB fonts are not used at the present time.
140 * see vt_vt100_parser.c:vt_parse_vt100_sequence().
141 */
142 {"UHC", UHC},
143 {"JOHAB", JOHAB},
144 #endif
145 {"GB2312_80", GB2312_80},
146 {"GBK", GBK},
147 {"BIG5", BIG5},
148 {"HKSCS", HKSCS},
149 {"CNS11643_1992_1", CNS11643_1992_1},
150 {"CNS11643_1992_2", CNS11643_1992_2},
151 {"CNS11643_1992_3", CNS11643_1992_3},
152 {"CNS11643_1992_4", CNS11643_1992_4},
153 {"CNS11643_1992_5", CNS11643_1992_5},
154 {"CNS11643_1992_6", CNS11643_1992_6},
155 {"CNS11643_1992_7", CNS11643_1992_7},
156
157 };
158
159 static ui_font_config_t **font_configs;
160 static u_int num_configs;
161
162 /*
163 * These will be leaked unless change_custom_cache( ... , "") deletes them.
164 * change_custom_cache( ... , "") is called only from save_conf, which means
165 * that they are deleted when all of them are saved to ~/.mlterm/(vt)(aa)font
166 * file.
167 */
168 static custom_cache_t *custom_cache;
169 static u_int num_customs;
170
171 /* --- static functions --- */
172
get_font_name_pair(BL_MAP (ui_font_name)table,vt_font_t font)173 static BL_PAIR(ui_font_name) get_font_name_pair(BL_MAP(ui_font_name) table, vt_font_t font) {
174 BL_PAIR(ui_font_name) pair;
175
176 bl_map_get(table, font, pair);
177
178 return pair;
179 }
180
BL_PAIR(ui_font_name)181 static BL_PAIR(ui_font_name) * get_font_name_pairs_array(u_int *size, BL_MAP(ui_font_name) table) {
182 BL_PAIR(ui_font_name) * array;
183
184 bl_map_get_pairs_array(table, array, *size);
185
186 return array;
187 }
188
set_font_name_to_table(BL_MAP (ui_font_name)table,vt_font_t font,char * fontname)189 static int set_font_name_to_table(BL_MAP(ui_font_name) table, vt_font_t font, char *fontname) {
190 int result;
191
192 bl_map_set(result, table, font, fontname);
193
194 return result;
195 }
196
parse_key(const char * key)197 static vt_font_t parse_key(const char *key) {
198 int count;
199 size_t key_len;
200 ef_charset_t cs;
201 vt_font_t font;
202
203 key_len = strlen(key);
204
205 if (key_len >= 7 && strncmp(key, "DEFAULT", 7) == 0) {
206 if (key_len >= 8) {
207 bl_warn_printf("Illegal charset for font: %s.\n", key);
208 return UNKNOWN_CS;
209 }
210
211 font = DEFAULT_FONT;
212
213 goto check_style;
214 }
215
216 if (key_len >= 3 && strncmp(key, "U+", 2) == 0) {
217 u_int min;
218 u_int max;
219
220 if (vt_parse_unicode_area(key, &min, &max) &&
221 (font = vt_get_unicode_area_font(min, max)) != UNKNOWN_CS) {
222 goto check_style;
223 } else {
224 return UNKNOWN_CS;
225 }
226 }
227
228 for (count = 0; count < sizeof(cs_table) / sizeof(cs_table[0]); count++) {
229 size_t nlen;
230
231 nlen = strlen(cs_table[count].name);
232
233 if (key_len >= nlen && strncmp(cs_table[count].name, key, nlen) == 0 &&
234 (key[nlen] == '\0' ||
235 /* "_BOLD" or "_FULLWIDTH" is trailing */ key[nlen] == '_')) {
236 cs = cs_table[count].cs;
237
238 break;
239 }
240 }
241
242 if (count == sizeof(cs_table) / sizeof(cs_table[0])) {
243 #ifdef DEBUG
244 bl_debug_printf(BL_DEBUG_TAG " %s is not valid charset.\n", key);
245 #endif
246
247 return UNKNOWN_CS;
248 }
249
250 font = NORMAL_FONT_OF(cs);
251
252 if (!(font & FONT_FULLWIDTH) && (strstr(key, "_BIWIDTH") || /* XXX compat with 3.2.2 or before. */
253 strstr(key, "_FULLWIDTH"))) {
254 font |= FONT_FULLWIDTH;
255 }
256
257 check_style:
258 if (strstr(key, "_BOLD")) {
259 font |= FONT_BOLD;
260 }
261
262 if (strstr(key, "_ITALIC")) {
263 font |= FONT_ITALIC;
264 }
265
266 return font;
267 }
268
parse_value(char ** font_name,char * value)269 static void parse_value(char **font_name, /* if value is "" or illegal format, not changed. */
270 char *value /* Don't specify NULL. */ ) {
271 #if 1 /* XXX Compat with old format (3.6.3 or before): [size],[font name] */
272 char *p;
273
274 if ('0' <= *value && *value <= '9' && (p = strchr(value, ','))) {
275 value = p + 1;
276 }
277 #endif
278
279 *font_name = value;
280 }
281
282 /*
283 * <Return value>
284 * 1: Valid "%d" or no '%' is found.
285 * 0: Invalid '%' is found.
286 */
is_valid_font_format(const char * format)287 static int is_valid_font_format(const char *format) {
288 char *p;
289
290 if ((p = strchr(format, '%'))) {
291 /* force to be '%d' */
292 if (p[1] != 'd') {
293 return 0;
294 }
295
296 /* '%' can happen only once at most */
297 if (p != strrchr(format, '%')) {
298 return 0;
299 }
300 }
301
302 return 1;
303 }
304
305 /*
306 * <Return value>
307 * 0: Not changed(including the case of failure).
308 * 1: Succeeded.
309 */
customize_font_name(ui_font_config_t * font_config,vt_font_t font,const char * fontname)310 static int customize_font_name(ui_font_config_t *font_config, vt_font_t font,
311 const char *fontname) {
312 BL_PAIR(ui_font_name) pair;
313
314 if (is_valid_font_format(fontname) == 0) {
315 bl_msg_printf("%s is invalid format for font name.\n");
316
317 return 0;
318 }
319
320 if ((pair = get_font_name_pair(font_config->font_name_table, font))) {
321 if (*fontname == '\0') {
322 int result;
323
324 /* Curent setting in font_config is removed. */
325 free(pair->value);
326 bl_map_erase_simple(result, font_config->font_name_table, font);
327 } else if (strcmp(pair->value, fontname) != 0) {
328 char *value;
329
330 if ((value = strdup(fontname)) == NULL) {
331 return 0;
332 }
333
334 free(pair->value);
335 pair->value = value;
336 } else {
337 /* If new fontname is the same as current one, nothing is done. */
338 return 0;
339 }
340 } else {
341 char *value;
342
343 if (*fontname == '\0' || (value = strdup(fontname)) == NULL) {
344 return 0;
345 }
346
347 set_font_name_to_table(font_config->font_name_table, font, value);
348 }
349
350 #ifdef DEBUG
351 bl_debug_printf(BL_DEBUG_TAG " Set %x font => fontname %s.\n", font, fontname);
352 #endif
353
354 return 1;
355 }
356
parse_conf(ui_font_config_t * font_config,const char * key,const char * value)357 static int parse_conf(ui_font_config_t *font_config, const char *key,
358 const char *value /* value = "" or ";" => Reset font name. */
359 ) {
360 vt_font_t font;
361 char *font_name;
362
363 if ((font = parse_key(key)) == UNKNOWN_CS ||
364 (font_name = alloca(strlen(value) + 1)) == NULL) {
365 return 0;
366 }
367 strcpy(font_name, value);
368
369 /*
370 * XXX
371 * Compat with old formats (3.6.3 or before): [default font name];[font size],[font name];...
372 */
373 #if 1
374 {
375 const char *p = value;
376 while ((p = strchr(p, ';'))) {
377 p++;
378 if (('0' <= *p && *p <= '9') || *p == '\0') {
379 font_name[p - value - 1] = '\0';
380
381 break;
382 }
383 }
384 }
385 #endif
386
387 parse_value(&font_name, font_name);
388 customize_font_name(font_config, font, font_name);
389
390 return 1;
391 }
392
apply_custom_cache(ui_font_config_t * font_config,const char * filename)393 static int apply_custom_cache(ui_font_config_t *font_config, const char *filename) {
394 u_int count;
395
396 for (count = 0; count < num_customs; count++) {
397 if (filename == custom_cache[count].file) {
398 #ifdef __DEBUG
399 bl_debug_printf("Appling customization %s=%s\n", custom_cache[count].key,
400 custom_cache[count].value);
401 #endif
402
403 parse_conf(font_config, custom_cache[count].key, custom_cache[count].value);
404 }
405 }
406
407 return 1;
408 }
409
read_conf(ui_font_config_t * font_config,const char * filename)410 static int read_conf(ui_font_config_t *font_config, const char *filename) {
411 bl_file_t *from;
412 char *key;
413 char *value;
414
415 #ifdef __DEBUG
416 bl_debug_printf(BL_DEBUG_TAG " read_conf( %s)\n", filename);
417 #endif
418
419 if (!(from = bl_file_open(filename, "r"))) {
420 #ifdef DEBUG
421 bl_warn_printf(BL_DEBUG_TAG " %s couldn't be opened.\n", filename);
422 #endif
423
424 return 0;
425 }
426
427 while (bl_conf_io_read(from, &key, &value)) {
428 #ifdef __DEBUG
429 bl_debug_printf(BL_DEBUG_TAG " Read line from %s => %s = %s\n", filename, key, value);
430 #endif
431
432 parse_conf(font_config, key, value);
433 }
434
435 bl_file_close(from);
436
437 return 1;
438 }
439
read_all_conf(ui_font_config_t * font_config,const char * changed_font_file)440 static int read_all_conf(ui_font_config_t *font_config,
441 const char *changed_font_file /* If this function is
442 * called after a font
443 * file is
444 * changed, specify it
445 * here to avoid re-read
446 * font files.
447 * Otherwise specify
448 * NULL. */
449 ) {
450 char *font_rcfile;
451 char *font_rcfile2; /* prior to font_rcfile */
452 char *rcpath;
453
454 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
455 if (use_aafont)
456 #else
457 /* '>= XFT' means XFT or Cairo */
458 if (font_config->type_engine >= TYPE_XFT)
459 #endif
460 {
461 font_rcfile = aafont_file;
462
463 switch (font_config->font_present & ~FONT_AA) {
464 default:
465 font_rcfile2 = NULL;
466 break;
467
468 case FONT_VAR_WIDTH:
469 font_rcfile2 = vaafont_file;
470 break;
471
472 case FONT_VERTICAL:
473 font_rcfile2 = taafont_file;
474 break;
475 }
476 } else {
477 font_rcfile = font_file;
478
479 switch (font_config->font_present & ~FONT_AA) {
480 default:
481 font_rcfile2 = NULL;
482 break;
483
484 case FONT_VAR_WIDTH:
485 font_rcfile2 = vfont_file;
486 break;
487
488 case FONT_VERTICAL:
489 font_rcfile2 = tfont_file;
490 break;
491 }
492 }
493
494 if (!changed_font_file) {
495 if ((rcpath = bl_get_sys_rc_path(font_rcfile))) {
496 read_conf(font_config, rcpath);
497 free(rcpath);
498 }
499 }
500
501 if (!changed_font_file || changed_font_file == font_rcfile) {
502 if ((rcpath = bl_get_user_rc_path(font_rcfile))) {
503 read_conf(font_config, rcpath);
504 free(rcpath);
505 }
506 }
507
508 apply_custom_cache(font_config, font_rcfile);
509
510 if (font_rcfile2) {
511 if (!changed_font_file) {
512 if ((rcpath = bl_get_sys_rc_path(font_rcfile2))) {
513 read_conf(font_config, rcpath);
514 free(rcpath);
515 }
516 }
517
518 if ((rcpath = bl_get_user_rc_path(font_rcfile2))) {
519 read_conf(font_config, rcpath);
520 free(rcpath);
521 }
522
523 apply_custom_cache(font_config, font_rcfile2);
524 }
525
526 return 1;
527 }
528
change_custom_cache(const char * file,const char * key,const char * value)529 static int change_custom_cache(const char *file, const char *key, const char *value) {
530 void *p;
531 u_int count;
532
533 for (count = 0; count < num_customs; count++) {
534 if (custom_cache[count].file == file && strcmp(custom_cache[count].key, key) == 0) {
535 if (*value) {
536 /* replace */
537 char *p;
538
539 if (strcmp(custom_cache[count].value, value) == 0) {
540 /* not changed */
541 return 0;
542 }
543
544 if ((p = strdup(value))) {
545 free(custom_cache[count].value);
546 custom_cache[count].value = p;
547 }
548 } else {
549 /* remove */
550
551 free(custom_cache[count].key);
552 free(custom_cache[count].value);
553 custom_cache[count] = custom_cache[--num_customs];
554 if (num_customs == 0) {
555 free(custom_cache);
556 custom_cache = NULL;
557
558 #ifdef __DEBUG
559 bl_debug_printf("Custom cache is completely freed.\n");
560 #endif
561 }
562 }
563
564 return 1;
565 }
566 }
567
568 /* #if 1 => Don't remove font settings read from *font files in ~/.mlterm */
569 #if 0
570 if (*value == '\0') {
571 return 0;
572 }
573 #endif
574
575 if ((p = realloc(custom_cache, sizeof(custom_cache_t) * (num_customs + 1))) == NULL) {
576 return 0;
577 }
578
579 custom_cache = p;
580
581 if ((custom_cache[num_customs].key = strdup(key)) == NULL) {
582 return 0;
583 }
584
585 if ((custom_cache[num_customs].value = strdup(value)) == NULL) {
586 free(custom_cache[num_customs].key);
587
588 return 0;
589 }
590
591 custom_cache[num_customs++].file = file;
592
593 #ifdef __DEBUG
594 bl_debug_printf("%s=%s is newly added to custom cache.\n", key, value);
595 #endif
596
597 return 1;
598 }
599
write_conf(char * path,const char * key,const char * value)600 static int write_conf(char *path, /* Can be destroyed in this function. */
601 const char *key, const char *value) {
602 bl_conf_write_t *conf;
603
604 if (!(conf = bl_conf_write_open(path))) {
605 return 0;
606 }
607
608 bl_conf_io_write(conf, key, value);
609
610 bl_conf_write_close(conf);
611
612 return 1;
613 }
614
save_conf(const char * file,const char * key,char * value)615 static int save_conf(const char *file, const char *key,
616 char *value /* Includes multiple entries. Destroyed in this function. */
617 ) {
618 char *path;
619 int ret;
620
621 if ((path = bl_get_user_rc_path(file)) == NULL) {
622 return 0;
623 }
624
625 if ((ret = write_conf(path, key, value))) {
626 /* Remove from custom_cache */
627 change_custom_cache(file, key, "");
628 }
629
630 free(path);
631
632 return ret;
633 }
634
find_font_config(ui_type_engine_t type_engine,ui_font_present_t font_present)635 static ui_font_config_t *find_font_config(ui_type_engine_t type_engine,
636 ui_font_present_t font_present) {
637 if (font_configs) {
638 u_int count;
639
640 for (count = 0; count < num_configs; count++) {
641 if (font_configs[count]->font_present == font_present &&
642 font_configs[count]->type_engine == type_engine) {
643 return font_configs[count];
644 }
645 }
646 }
647
648 return NULL;
649 }
650
match_font_configs(ui_font_config_t ** matched_configs,u_int max_size,int is_xcore,ui_font_present_t present_mask)651 static u_int match_font_configs(ui_font_config_t **matched_configs,
652 u_int max_size, /* must be over 0. */
653 int is_xcore, ui_font_present_t present_mask) {
654 u_int count;
655 u_int size;
656
657 size = 0;
658 for (count = 0; count < num_configs; count++) {
659 if (
660 #if !defined(USE_FREETYPE) || !defined(USE_FONTCONFIG)
661 (is_xcore ? font_configs[count]->type_engine == TYPE_XCORE :
662 /* '>= XFT' means XFT or Cairo */
663 font_configs[count]->type_engine >= TYPE_XFT) &&
664 #endif
665 (present_mask ? (font_configs[count]->font_present & present_mask) : 1)) {
666 matched_configs[size++] = font_configs[count];
667 if (size >= max_size) {
668 break;
669 }
670 }
671 }
672
673 return size;
674 }
675
create_shared_font_config(ui_type_engine_t type_engine,ui_font_present_t font_present)676 static ui_font_config_t *create_shared_font_config(ui_type_engine_t type_engine,
677 ui_font_present_t font_present) {
678 u_int count;
679
680 for (count = 0; count < num_configs; count++) {
681 if ((type_engine == TYPE_XCORE ? font_configs[count]->type_engine == TYPE_XCORE :
682 /* '>= XFT' means XFT or Cairo */
683 font_configs[count]->type_engine >= TYPE_XFT) &&
684 ((font_configs[count]->font_present & ~FONT_AA) == (font_present & ~FONT_AA))) {
685 #ifdef __DEBUG
686 bl_debug_printf(BL_DEBUG_TAG " Found sharable font_config.\n");
687 #endif
688
689 ui_font_config_t *font_config;
690
691 if ((font_config = malloc(sizeof(ui_font_config_t))) == NULL) {
692 return NULL;
693 }
694
695 font_config->type_engine = type_engine;
696 font_config->font_present = font_present;
697 font_config->font_name_table = font_configs[count]->font_name_table;
698 font_config->ref_count = 0;
699
700 return font_config;
701 }
702 }
703
704 return NULL;
705 }
706
new_table(ui_font_config_t * font_config)707 static void new_table(ui_font_config_t *font_config) {
708 bl_map_new_with_size(vt_font_t, char *, font_config->font_name_table, bl_map_hash_int,
709 bl_map_compare_int, 16);
710 }
711
destroy_table(ui_font_config_t * font_config)712 static void destroy_table(ui_font_config_t *font_config) {
713 u_int count;
714 u_int size;
715 BL_PAIR(ui_font_name) * fn_array;
716
717 fn_array = get_font_name_pairs_array(&size, font_config->font_name_table);
718
719 for (count = 0; count < size; count++) {
720 free(fn_array[count]->value);
721 }
722
723 bl_map_destroy(font_config->font_name_table);
724 }
725
726 /* --- global functions --- */
727
728 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
ui_use_aafont(void)729 int ui_use_aafont(void) {
730 if (num_configs > 0 || use_aafont) {
731 return 0;
732 }
733
734 use_aafont = 1;
735 ui_font_use_fontconfig();
736
737 return 1;
738 }
739
ui_is_using_aafont(void)740 int ui_is_using_aafont(void) { return use_aafont; }
741 #endif
742
ui_acquire_font_config(ui_type_engine_t type_engine,ui_font_present_t font_present)743 ui_font_config_t *ui_acquire_font_config(ui_type_engine_t type_engine,
744 ui_font_present_t font_present) {
745 ui_font_config_t *font_config;
746 void *p;
747
748 if ((font_config = find_font_config(type_engine, font_present))) {
749 font_config->ref_count++;
750
751 return font_config;
752 }
753
754 if ((p = realloc(font_configs, sizeof(ui_font_config_t *) * (num_configs + 1))) == NULL) {
755 return NULL;
756 }
757
758 font_configs = p;
759
760 if ((font_config = create_shared_font_config(type_engine, font_present)) == NULL) {
761 if ((font_config = ui_font_config_new(type_engine, font_present)) == NULL ||
762 !read_all_conf(font_config, NULL)) {
763 return NULL;
764 }
765 }
766
767 font_config->ref_count++;
768
769 return font_configs[num_configs++] = font_config;
770 }
771
ui_release_font_config(ui_font_config_t * font_config)772 void ui_release_font_config(ui_font_config_t *font_config) {
773 u_int count;
774 int has_share;
775 int found;
776
777 if (--font_config->ref_count > 0) {
778 return;
779 }
780
781 has_share = 0;
782 found = 0;
783 count = 0;
784 while (count < num_configs) {
785 if (font_configs[count] == font_config) {
786 font_configs[count] = font_configs[--num_configs];
787 found = 1;
788
789 continue;
790 } else if ((font_config->type_engine == TYPE_XCORE
791 ? font_configs[count]->type_engine == TYPE_XCORE
792 :
793 /* '>= XFT' means XFT or Cairo */
794 font_configs[count]->type_engine >= TYPE_XFT) &&
795 ((font_configs[count]->font_present & ~FONT_AA) ==
796 (font_config->font_present & ~FONT_AA))) {
797 has_share = 1;
798 }
799
800 count++;
801 }
802
803 if (!found) {
804 #ifdef DEBUG
805 bl_debug_printf(BL_DEBUG_TAG " font_config is not found in font_configs.\n");
806 #endif
807
808 return;
809 }
810
811 if (has_share /* && num_configs > 0 */) {
812 #ifdef __DEBUG
813 bl_debug_printf(BL_DEBUG_TAG " Sharable font_config exists.\n");
814 #endif
815
816 free(font_config);
817
818 return;
819 }
820
821 ui_font_config_destroy(font_config);
822
823 if (num_configs == 0) {
824 free(font_configs);
825 font_configs = NULL;
826 }
827 }
828
ui_font_config_new(ui_type_engine_t type_engine,ui_font_present_t font_present)829 ui_font_config_t *ui_font_config_new(ui_type_engine_t type_engine, ui_font_present_t font_present) {
830 ui_font_config_t *font_config;
831
832 if ((font_config = malloc(sizeof(ui_font_config_t))) == NULL) {
833 return NULL;
834 }
835
836 new_table(font_config);
837
838 font_config->type_engine = type_engine;
839 font_config->font_present = font_present;
840 font_config->ref_count = 0;
841
842 return font_config;
843 }
844
ui_font_config_destroy(ui_font_config_t * font_config)845 void ui_font_config_destroy(ui_font_config_t *font_config) {
846 destroy_table(font_config);
847 free(font_config);
848 }
849
850 /*
851 * 0 => customization is failed.
852 * -1 => customization is succeeded but saving is failed.
853 * 1 => succeeded.
854 */
ui_customize_font_file(const char * file,char * key,char * value,int save)855 int ui_customize_font_file(const char *file, /* if null, use "mlterm/font" file. */
856 char *key, /* charset name */
857 char *value, /* font list */
858 int save) {
859 /*
860 * Max number of target font_config is 6.
861 * [file == aafont_file]
862 * TYPE_XFT, TYPE_XFT & FONT_VAR_WIDTH , TYPE_XFT & FONT_VERTICAL , TYPE_XFT &
863 * FONT_AA ,
864 * TYPE_XFT & FONT_VAR_WIDTH & FONT_AA , TYPE_XFT & FONT_VERTICAL & FONT_AA
865 */
866 ui_font_config_t *targets[6];
867 u_int num_targets;
868 u_int count;
869 int ret;
870
871 if (file == NULL ||
872 #if defined(USE_FREETYPE) && defined(USE_FONTCONFIG)
873 strcmp(file, "font") == 0
874 #else
875 strcmp(file, FONT_FILE) == 0
876 #endif
877 ) {
878 file = font_file;
879 num_targets = match_font_configs(targets, 6, /* is xcore */ 1, 0);
880 } else if (strcmp(file, aafont_file + 7) == 0) {
881 file = aafont_file;
882 num_targets = match_font_configs(targets, 6, /* is not xcore */ 0, 0);
883 } else if (strcmp(file, VFONT_FILE) == 0) {
884 file = vfont_file;
885 num_targets = match_font_configs(targets, 6, /* is xcore */ 1, FONT_VAR_WIDTH);
886 } else if (strcmp(file, TFONT_FILE) == 0) {
887 file = tfont_file;
888 num_targets = match_font_configs(targets, 6, /* is xcore */ 1, FONT_VERTICAL);
889 } else if (strcmp(file, vaafont_file + 7) == 0) {
890 file = vaafont_file;
891 num_targets = match_font_configs(targets, 6, /* is not xcore */ 0, FONT_VAR_WIDTH);
892 } else if (strcmp(file, taafont_file + 7) == 0) {
893 file = taafont_file;
894 num_targets = match_font_configs(targets, 6, /* is not xcore */ 0, FONT_VERTICAL);
895 } else {
896 #ifdef DEBUG
897 bl_debug_printf(BL_DEBUG_TAG " font file %s is not found.\n", file);
898 #endif
899
900 return 0;
901 }
902
903 #ifdef __DEBUG
904 if (num_targets) {
905 bl_debug_printf("customize font file %s %s %s\n", file, key, value);
906 } else {
907 bl_debug_printf("customize font file %s %s %s(not changed in run time)\n", file, key, value);
908 }
909 #endif
910
911 if (change_custom_cache(file, key, value)) {
912 if (*value == '\0') {
913 /* remove */
914 for (count = 0; count < num_targets; count++) {
915 /*
916 * reset font_name_table
917 *
918 * ~/.mlterm/font: ISO10646_UCS4_1=a
919 * => mlcc font ISO10646_UCS4_1 b
920 * => mlcc font ISO10646_UCS4_1 "" (results in ISO10646_UCS4_1=a)
921 */
922 destroy_table(targets[count]);
923 new_table(targets[count]);
924
925 read_all_conf(targets[count], NULL);
926 }
927
928 return 1;
929 } else {
930 ret = 1;
931 for (count = 0; count < num_targets; count++) {
932 read_all_conf(targets[count], file);
933 }
934 }
935 } else {
936 ret = 0;
937 }
938
939 if (save && !save_conf(file, key, value)) {
940 return ret ? -1 : 0;
941 } else {
942 return ret;
943 }
944 }
945
ui_get_config_font_name(ui_font_config_t * font_config,u_int font_size,vt_font_t font)946 char *ui_get_config_font_name(ui_font_config_t *font_config, u_int font_size, vt_font_t font) {
947 vt_font_t cand_font;
948 BL_PAIR(ui_font_name) pair;
949 char *font_name;
950 char *encoding;
951 size_t encoding_len;
952 int has_percentd;
953 #ifdef USE_XLIB
954 static char *orig_style[] = {"-medium-", "-r-", "-medium-r-"};
955 static char *new_style[] = {"-bold-", "-i-", "-bold-i-"};
956 #endif
957
958 if (UNICODE_AREA(font)) {
959 font &= ~FONT_FULLWIDTH;
960 }
961
962 encoding = NULL;
963 cand_font = NO_SIZE_ATTR(font);
964
965 while (!(pair = get_font_name_pair(font_config->font_name_table, cand_font))) {
966 #ifdef USE_XLIB
967 int idx;
968
969 if (font_config->type_engine == TYPE_XCORE) {
970 if ((idx = FONT_STYLE_INDEX(font)) >= 0 &&
971 ((pair = get_font_name_pair(font_config->font_name_table, FONT_CS(cand_font))) &&
972 (font_name = bl_str_replace(pair->value, orig_style[idx], new_style[idx])))) {
973 #ifdef DEBUG
974 bl_debug_printf(BL_DEBUG_TAG " Set font %s for %x\n", font_name, font);
975 #endif
976
977 set_font_name_to_table(font_config->font_name_table, cand_font, font_name);
978
979 continue;
980 }
981 } else
982 #endif
983 {
984 if (cand_font & FONT_STYLES) {
985 cand_font &= ~FONT_STYLES;
986
987 continue;
988 }
989 }
990
991 if (cand_font & FONT_FULLWIDTH) {
992 cand_font &= ~FONT_FULLWIDTH;
993 } else if (FONT_CS(cand_font) != DEFAULT_FONT) {
994 cand_font = DEFAULT_FONT;
995 } else {
996 return NULL;
997 }
998 }
999
1000 #ifdef USE_XLIB
1001 if (font_config->type_engine == TYPE_XCORE && FONT_CS(cand_font) == DEFAULT_FONT &&
1002 /* encoding is appended if font_name is XLFD (not alias name). */
1003 (strchr(pair->value, '*') || strchr(pair->value, '-'))) {
1004 char **names;
1005
1006 if ((names = ui_font_get_encoding_names(FONT_CS(font))) && names[0]) {
1007 encoding = names[0];
1008 }
1009 }
1010 #endif
1011
1012 #if 1
1013 if (*(pair->value) == '&' &&
1014 /* XXX font variable is overwritten. */
1015 (font = parse_key(pair->value + 1)) != UNKNOWN_CS) {
1016 /*
1017 * XXX (Undocumented)
1018 *
1019 * JISX0213_2000_1 = &JISX0208_1983 in font configuration files.
1020 * => try to get a font name of JISX0208_1983 instead of
1021 * JISX0213_2000_1 recursively.
1022 */
1023 return ui_get_config_font_name(font_config, font_size, font);
1024 }
1025 #endif
1026
1027 /*
1028 * If pair->value is valid format or not is checked by is_valid_font_format()
1029 * in customize_font_name().
1030 * So all you have to do here is strchr( ... , '%') alone.
1031 */
1032 if (strchr(pair->value, '%')) {
1033 has_percentd = 1;
1034 } else if (encoding == NULL) {
1035 return strdup(pair->value);
1036 } else {
1037 has_percentd = 0;
1038 }
1039
1040 if (!(font_name = malloc(strlen(pair->value) +
1041 /* -2 is for "%d" */
1042 (has_percentd ? DIGIT_STR_LEN(font_size) - 2 : 0) +
1043 (encoding_len = encoding ? strlen(encoding) : 0) + 1))) {
1044 return NULL;
1045 }
1046
1047 if (has_percentd) {
1048 sprintf(font_name, pair->value, font_size);
1049 } else {
1050 strcpy(font_name, pair->value);
1051 }
1052
1053 if (encoding) {
1054 char *percent;
1055
1056 if ((percent = strchr(font_name, ':'))) {
1057 /* -*-:200 -> -*-iso8859-1:200 */
1058
1059 memmove(percent + encoding_len, percent, strlen(percent) + 1);
1060 memcpy(percent, encoding, encoding_len);
1061 } else {
1062 strcat(font_name, encoding);
1063 }
1064 }
1065
1066 return font_name;
1067 }
1068
ui_get_config_font_name2(const char * file,u_int font_size,char * font_cs)1069 char *ui_get_config_font_name2(const char *file, /* can be NULL */
1070 u_int font_size, char *font_cs) {
1071 vt_font_t font;
1072 ui_font_config_t *font_config;
1073 ui_type_engine_t engine;
1074 ui_font_present_t present;
1075 char *font_name;
1076
1077 if (file == NULL || strcmp(file, FONT_FILE) == 0) {
1078 engine = TYPE_XCORE;
1079 present = 0;
1080 }
1081 #if !defined(USE_FREETYPE) || !defined(USE_FONTCONFIG)
1082 else if (strcmp(file, aafont_file + 7) == 0) {
1083 engine = TYPE_XFT;
1084
1085 /*
1086 * font_config::font_name_table is shared with
1087 * font_configs whose difference is only FONT_AA.
1088 */
1089 present = 0;
1090 } else if (strcmp(file, vaafont_file + 7) == 0) {
1091 engine = TYPE_XFT;
1092 present = FONT_VAR_WIDTH;
1093 } else if (strcmp(file, taafont_file + 7) == 0) {
1094 engine = TYPE_XFT;
1095 present = FONT_VERTICAL;
1096 }
1097 #endif
1098 else if (strcmp(file, VFONT_FILE) == 0) {
1099 engine = TYPE_XCORE;
1100 present = FONT_VAR_WIDTH;
1101 } else if (strcmp(file, TFONT_FILE) == 0) {
1102 engine = TYPE_XCORE;
1103 present = FONT_VERTICAL;
1104 } else {
1105 #ifdef DEBUG
1106 bl_debug_printf(BL_DEBUG_TAG " font file %s is not found.\n", file);
1107 #endif
1108
1109 return NULL;
1110 }
1111
1112 if ((font_config = ui_acquire_font_config(engine, present)) == NULL) {
1113 #ifdef DEBUG
1114 bl_debug_printf(BL_DEBUG_TAG " ui_font_config_t is not found.\n");
1115 #endif
1116
1117 return NULL;
1118 }
1119
1120 if ((font = parse_key(font_cs)) == UNKNOWN_CS) {
1121 return NULL;
1122 }
1123
1124 font_name = ui_get_config_font_name(font_config, font_size, font);
1125
1126 ui_release_font_config(font_config);
1127
1128 return font_name;
1129 }
1130
ui_get_config_font_names_all(ui_font_config_t * font_config,u_int font_size)1131 char *ui_get_config_font_names_all(ui_font_config_t *font_config, u_int font_size) {
1132 BL_PAIR(ui_font_name) * array;
1133 u_int size;
1134 char *font_name_list;
1135 size_t list_len;
1136 char *p;
1137 u_int count;
1138
1139 array = get_font_name_pairs_array(&size, font_config->font_name_table);
1140
1141 if (size == 0) {
1142 return NULL;
1143 }
1144
1145 list_len = 0;
1146
1147 for (count = 0; count < size; count++) {
1148 list_len += (strlen(array[count]->value) - 2 + DIGIT_STR_LEN(font_size) + 1);
1149 }
1150
1151 if ((font_name_list = malloc(list_len)) == NULL) {
1152 return NULL;
1153 }
1154
1155 p = font_name_list;
1156
1157 for (count = 0; count < size; count++) {
1158 /*
1159 * XXX
1160 * Ignore DEFAULT_FONT setting because it doesn't have encoding name.
1161 */
1162 if (FONT_CS(array[count]->key) != DEFAULT_FONT) {
1163 sprintf(p, array[count]->value, font_size);
1164 p += strlen(p);
1165 *(p++) = ',';
1166 }
1167 }
1168
1169 if (p > font_name_list) {
1170 --p;
1171 }
1172 *p = '\0';
1173
1174 #ifdef DEBUG
1175 bl_debug_printf(BL_DEBUG_TAG " Font list is %s\n", font_name_list);
1176 #endif
1177
1178 return font_name_list;
1179 }
1180
ui_font_config_dump(ui_font_config_t * font_config)1181 char *ui_font_config_dump(ui_font_config_t *font_config) {
1182 BL_PAIR(ui_font_name) * array;
1183 u_int size;
1184 char *font_name_list;
1185 size_t list_len;
1186 char *p;
1187 u_int count;
1188
1189 array = get_font_name_pairs_array(&size, font_config->font_name_table);
1190
1191 if (size == 0) {
1192 return "No font settings";
1193 }
1194
1195 list_len = 0;
1196 for (count = 0; count < size; count++) {
1197 list_len += (4 /* CSI2J */ + 15 /* ISO10646_UCS4_1, U+10FFFF-10FFFF */ +
1198 12 /* _BOLD_ITALIC */ + 10 /* _FULLWIDTH */ + 1 /* = */ +
1199 strlen(array[count]->value) + 2 /* \r\n or \0 */);
1200 }
1201
1202 if ((font_name_list = malloc(list_len)) == NULL) {
1203 return "No font settings";
1204 }
1205
1206 strcpy(font_name_list, "\x1b[2J");
1207 p = font_name_list + 4;
1208
1209 for (count = 0; count < size; count++) {
1210 if (FONT_CS(array[count]->key) == DEFAULT_FONT) {
1211 strcpy(p, "DEFAULT");
1212 p += 7;
1213 } else {
1214 u_int count2;
1215
1216 for (count2 = 0; count2 < sizeof(cs_table) / sizeof(cs_table[0]); count2++) {
1217 if (FONT_CS(array[count]->key) == cs_table[count2].cs) {
1218 int min;
1219 int max;
1220
1221 if (vt_get_unicode_area(array[count]->key, &min, &max)) {
1222 sprintf(p, "U+%x-%x", min, max);
1223 } else {
1224 strcpy(p, cs_table[count2].name);
1225 }
1226 p += strlen(p);
1227
1228 goto next_step;
1229 }
1230 }
1231
1232 continue;
1233 }
1234
1235 next_step:
1236 if (array[count]->key & FONT_BOLD) {
1237 strcpy(p, "_BOLD");
1238 p += 5;
1239 }
1240
1241 if (array[count]->key & FONT_ITALIC) {
1242 strcpy(p, "_ITALIC");
1243 p += 7;
1244 }
1245
1246 if (array[count]->key & FONT_FULLWIDTH) {
1247 strcpy(p, "_FULLWIDTH");
1248 p += 10;
1249 }
1250
1251 sprintf(p, "=%s", array[count]->value);
1252 p += strlen(p);
1253
1254 *(p++) = '\r';
1255 *(p++) = '\n';
1256 }
1257
1258 *(p - 2) = '\0';
1259
1260 return font_name_list;
1261 }
1262
ui_get_charset_name(ef_charset_t cs)1263 char *ui_get_charset_name(ef_charset_t cs) {
1264 int count;
1265
1266 for (count = 0; count < sizeof(cs_table) / sizeof(cs_table[0]); count++) {
1267 if (cs_table[count].cs == cs) {
1268 return cs_table[count].name;
1269 }
1270 }
1271
1272 return NULL;
1273 }
1274
1275 #ifdef BL_DEBUG
1276
1277 #include <assert.h>
1278
TEST_ui_font_config(void)1279 void TEST_ui_font_config(void) {
1280 #ifdef USE_XLIB
1281 ui_font_config_t *font_config;
1282 char *value;
1283
1284 font_config = ui_font_config_new(TYPE_XCORE, 0);
1285 customize_font_name(font_config, ISO8859_1_R, "-hoge-medium-r-fuga-");
1286
1287 value = ui_get_config_font_name(font_config, 12, ISO8859_1_R | FONT_BOLD);
1288 assert(strcmp("-hoge-bold-r-fuga-", value) == 0);
1289 free(value);
1290
1291 value = ui_get_config_font_name(font_config, 12, ISO8859_1_R | FONT_ITALIC);
1292 assert(strcmp("-hoge-medium-i-fuga-", value) == 0);
1293 free(value);
1294
1295 value = ui_get_config_font_name(font_config, 12, ISO8859_1_R | FONT_BOLD | FONT_ITALIC);
1296 assert(strcmp("-hoge-bold-i-fuga-", value) == 0);
1297 free(value);
1298
1299 ui_font_config_destroy(font_config);
1300
1301 bl_msg_printf("PASS ui_font_config test.\n");
1302 #endif
1303 }
1304
1305 #endif
1306