1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "../ui_font.h"
4
5 #include <pobl/bl_debug.h>
6 #include <pobl/bl_str.h> /* bl_snprintf */
7 #include <pobl/bl_mem.h> /* alloca */
8 #include <pobl/bl_str.h> /* bl_str_sep/bl_str_to_int/memset/strncasecmp */
9 #include <pobl/bl_util.h> /* DIGIT_STR_LEN */
10 #include <pobl/bl_locale.h> /* bl_get_lang() */
11 #include <mef/ef_ucs4_map.h>
12 #include <vt_char_encoding.h> /* vt_is_msb_set */
13
14 #include "ui_type_loader.h"
15 #include "ui_decsp_font.h"
16
17 #define FOREACH_FONT_ENCODINGS(csinfo, font_encoding_p) \
18 for ((font_encoding_p) = (csinfo)->encoding_names; \
19 (font_encoding_p) < \
20 (csinfo)->encoding_names + \
21 sizeof((csinfo)->encoding_names) / sizeof((csinfo)->encoding_names[0]) && \
22 *(font_encoding_p); \
23 (font_encoding_p)++)
24
25 #define DIVIDE_ROUNDING(a, b) (((int)((a)*10 + (b)*5)) / ((int)((b)*10)))
26 #define DIVIDE_ROUNDINGUP(a, b) (((int)((a)*10 + (b)*10 - 1)) / ((int)((b)*10)))
27
28 #if 0
29 #define __DEBUG
30 #endif
31
32 typedef struct cs_info {
33 ef_charset_t cs;
34
35 /* default encodings. */
36 char *encoding_names[2];
37
38 } cs_info_t;
39
40 /* --- static variables --- */
41
42 /*
43 * If this table is changed, ui_font_config.c:cs_table and
44 * mc_font.c:cs_info_table
45 * shoule be also changed.
46 */
47 static cs_info_t cs_info_table[] = {
48 { ISO10646_UCS4_1, { "iso10646-1", NULL, }, },
49 { DEC_SPECIAL, { "iso8859-1", NULL, }, },
50 { ISO8859_1_R, { "iso8859-1", NULL, }, },
51 { ISO8859_2_R, { "iso8859-2", NULL, }, },
52 { ISO8859_3_R, { "iso8859-3", NULL, }, },
53 { ISO8859_4_R, { "iso8859-4", NULL, }, },
54 { ISO8859_5_R, { "iso8859-5", NULL, }, },
55 { ISO8859_6_R, { "iso8859-6", NULL, }, },
56 { ISO8859_7_R, { "iso8859-7", NULL, }, },
57 { ISO8859_8_R, { "iso8859-8", NULL, }, },
58 { ISO8859_9_R, { "iso8859-9", NULL, }, },
59 { ISO8859_10_R, { "iso8859-10", NULL, }, },
60 { TIS620_2533, { "tis620.2533-1", "tis620.2529-1", }, },
61 { ISO8859_13_R, { "iso8859-13", NULL, }, },
62 { ISO8859_14_R, { "iso8859-14", NULL, }, },
63 { ISO8859_15_R, { "iso8859-15", NULL, }, },
64 { ISO8859_16_R, { "iso8859-16", NULL, }, },
65
66 /*
67 * XXX
68 * The encoding of TCVN font is iso8859-1, and its font family is .VnTime or
69 * .VnTimeH... How to deal with it ?
70 */
71 { TCVN5712_3_1993, { NULL, NULL, }, },
72
73 { ISCII_ASSAMESE, { NULL, NULL, }, },
74 { ISCII_BENGALI, { NULL, NULL, }, },
75 { ISCII_GUJARATI, { NULL, NULL, }, },
76 { ISCII_HINDI, { NULL, NULL, }, },
77 { ISCII_KANNADA, { NULL, NULL, }, },
78 { ISCII_MALAYALAM, { NULL, NULL, }, },
79 { ISCII_ORIYA, { NULL, NULL, }, },
80 { ISCII_PUNJABI, { NULL, NULL, }, },
81 { ISCII_TAMIL, { NULL, NULL, }, },
82 { ISCII_TELUGU, { NULL, NULL, }, },
83 { VISCII, { "viscii-1", NULL, }, },
84 { KOI8_R, { "koi8-r", NULL, }, },
85 { KOI8_U, { "koi8-u", NULL, }, },
86
87 #if 0
88 /*
89 * XXX
90 * KOI8_T, GEORGIAN_PS and CP125X charset can be shown by unicode font only.
91 */
92 { KOI8_T, { NULL, NULL, }, },
93 { GEORGIAN_PS, { NULL, NULL, }, },
94 { CP1250, { NULL, NULL, }, },
95 { CP1251, { NULL, NULL, }, },
96 { CP1252, { NULL, NULL, }, },
97 { CP1253, { NULL, NULL, }, },
98 { CP1254, { NULL, NULL, }, },
99 { CP1255, { NULL, NULL, }, },
100 { CP1256, { NULL, NULL, }, },
101 { CP1257, { NULL, NULL, }, },
102 { CP1258, { NULL, NULL, }, },
103 { CP874, { NULL, NULL, }, },
104 #endif
105
106 { JISX0201_KATA, { "jisx0201.1976-0", NULL, }, },
107 { JISX0201_ROMAN, { "jisx0201.1976-0", NULL, }, },
108 { JISC6226_1978, { "jisx0208.1978-0", "jisx0208.1983-0", }, },
109 { JISX0208_1983, { "jisx0208.1983-0", "jisx0208.1990-0", }, },
110 { JISX0208_1990, { "jisx0208.1990-0", "jisx0208.1983-0", }, },
111 { JISX0212_1990, { "jisx0212.1990-0", NULL, }, },
112 { JISX0213_2000_1, { "jisx0213.2000-1", "jisx0208.1983-0", }, },
113 { JISX0213_2000_2, { "jisx0213.2000-2", NULL, }, },
114 { KSC5601_1987, { "ksc5601.1987-0", "ksx1001.1997-0", }, },
115
116 #if 0
117 /*
118 * XXX
119 * UHC and JOHAB fonts are not used at the present time.
120 * see vt_vt100_parser.c:vt_parse_vt100_sequence().
121 */
122 { UHC, { NULL, NULL, }, },
123 { JOHAB, { "johabsh-1", /* "johabs-1" , */ "johab-1", }, },
124 #endif
125
126 { GB2312_80, { "gb2312.1980-0", NULL, }, },
127 { GBK, { "gbk-0", NULL, }, },
128 { BIG5, { "big5.eten-0", "big5.hku-0", }, },
129 { HKSCS, { "big5hkscs-0", "big5-0", }, },
130 { CNS11643_1992_1, { "cns11643.1992-1", "cns11643.1992.1-0", }, },
131 { CNS11643_1992_2, { "cns11643.1992-2", "cns11643.1992.2-0", }, },
132 { CNS11643_1992_3, { "cns11643.1992-3", "cns11643.1992.3-0", }, },
133 { CNS11643_1992_4, { "cns11643.1992-4", "cns11643.1992.4-0", }, },
134 { CNS11643_1992_5, { "cns11643.1992-5", "cns11643.1992.5-0", }, },
135 { CNS11643_1992_6, { "cns11643.1992-6", "cns11643.1992.6-0", }, },
136 { CNS11643_1992_7, { "cns11643.1992-7", "cns11643.1992.7-0", }, },
137 };
138
139 static int compose_dec_special_font;
140 static int use_point_size_for_fc;
141 static double dpi_for_fc;
142
143 /* --- static functions --- */
144
get_cs_info(ef_charset_t cs)145 static cs_info_t *get_cs_info(ef_charset_t cs) {
146 int count;
147
148 for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_t); count++) {
149 if (cs_info_table[count].cs == cs) {
150 return &cs_info_table[count];
151 }
152 }
153
154 #ifdef DEBUG
155 bl_warn_printf(BL_DEBUG_TAG " not supported cs(%x).\n", cs);
156 #endif
157
158 return NULL;
159 }
160
161 #if !defined(NO_DYNAMIC_LOAD_TYPE)
xft_unset_font(ui_font_t * font)162 static void xft_unset_font(ui_font_t *font) {
163 void (*func)(ui_font_t *);
164
165 if (!(func = ui_load_type_xft_func(UI_UNSET_FONT))) {
166 return;
167 }
168
169 (*func)(font);
170 }
171 #elif defined(USE_TYPE_XFT)
172 void xft_unset_font(ui_font_t *font);
173 #endif
174
175 #if !defined(NO_DYNAMIC_LOAD_TYPE)
cairo_unset_font(ui_font_t * font)176 static void cairo_unset_font(ui_font_t *font) {
177 void (*func)(ui_font_t *);
178
179 if (!(func = ui_load_type_cairo_func(UI_UNSET_FONT))) {
180 return;
181 }
182
183 (*func)(font);
184 }
185 #elif defined(USE_TYPE_CAIRO)
186 void cairo_unset_font(ui_font_t *font);
187 #endif
188
set_decsp_font(ui_font_t * font)189 static int set_decsp_font(ui_font_t *font) {
190 /*
191 * freeing font->xfont or font->xft_font
192 */
193 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
194 if (font->xft_font) {
195 xft_unset_font(font);
196 }
197 #endif
198
199 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
200 if (font->cairo_font) {
201 cairo_unset_font(font);
202 }
203 #endif
204
205 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
206 if (font->xfont) {
207 XFreeFont(font->display, font->xfont);
208 font->xfont = NULL;
209 }
210 #endif
211
212 if ((font->decsp_font =
213 ui_decsp_font_new(font->display, font->width, font->height, font->ascent)) == NULL) {
214 return 0;
215 }
216
217 /* decsp_font is impossible to draw double with. */
218 font->double_draw_gap = 0;
219
220 /* decsp_font is always fixed pitch. */
221 font->is_proportional = 0;
222
223 return 1;
224 }
225
226 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
227
xcore_calculate_char_width(Display * display,XFontStruct * xfont,u_int32_t ch)228 static u_int xcore_calculate_char_width(Display *display, XFontStruct *xfont, u_int32_t ch) {
229 int width;
230
231 if (ch < 0x100) {
232 u_char c;
233
234 c = ch;
235
236 width = XTextWidth(xfont, &c, 1);
237 } else {
238 XChar2b c[2];
239
240 width = XTextWidth16(xfont, c, ui_convert_ucs4_to_utf16(c, ch) / 2);
241 }
242
243 if (width < 0) {
244 /* Some (indic) fonts could return minus value as text width. */
245 return 0;
246 } else {
247 return width;
248 }
249 }
250
parse_xfont_name(char ** font_xlfd,char ** percent,char * font_name)251 static int parse_xfont_name(char **font_xlfd, char **percent, /* NULL can be returned. */
252 char *font_name /* Don't specify NULL. Broken in this function */
253 ) {
254 /*
255 * XFont format.
256 * [Font XLFD](:[Percentage])
257 */
258
259 /* bl_str_sep() never returns NULL because font_name isn't NULL. */
260 *font_xlfd = bl_str_sep(&font_name, ":");
261
262 /* may be NULL */
263 *percent = font_name;
264
265 return 1;
266 }
267
load_xfont_intern(Display * display,char * fontname,size_t max_len,const char * family,const char * weight,const char * slant,const char * width,const char * additional,u_int fontsize,const char * spacing,const char * encoding)268 static XFontStruct *load_xfont_intern(Display *display, char *fontname, size_t max_len,
269 const char *family, const char *weight,
270 const char *slant, const char *width, const char *additional,
271 u_int fontsize, const char *spacing, const char *encoding) {
272 bl_snprintf(fontname, max_len, "-*-%s-%s-%s-%s-%s-%d-*-*-*-%s-*-%s", family, weight, slant,
273 width, additional, fontsize, spacing, encoding);
274
275 #ifdef DEBUG
276 bl_debug_printf(BL_DEBUG_TAG " loading %s.\n", fontname);
277 #endif
278
279 return XLoadQueryFont(display, fontname);
280 }
281
load_xfont(Display * display,const char * family,const char * weight,const char * slant,const char * width,u_int fontsize,const char * spacing,const char * encoding)282 static XFontStruct *load_xfont(Display *display, const char *family, const char *weight,
283 const char *slant, const char *width, u_int fontsize,
284 const char *spacing, const char *encoding) {
285 XFontStruct *xfont;
286 char *fontname;
287 size_t max_len;
288
289 /* "+ 19" means the num of '-' , '*'(18byte) and null chars. */
290 max_len = strlen(family) + 7 /* unifont */ + strlen(weight) + strlen(slant) +
291 strlen(width) + 2 /* lang */ + DIGIT_STR_LEN(fontsize) + strlen(spacing) +
292 strlen(encoding) + 19;
293
294 if ((fontname = alloca(max_len)) == NULL) {
295 return NULL;
296 }
297
298 if ((xfont = load_xfont_intern(display, fontname, max_len, family, weight, slant, width, "*",
299 fontsize, spacing, encoding))) {
300 return xfont;
301 }
302
303 if (strcmp(encoding, "iso10646-1") == 0 && strcmp(family, "biwidth") == 0) {
304 /* XFree86 Unicode font */
305
306 if ((xfont = load_xfont_intern(display, fontname, max_len, "*", weight, slant, width,
307 bl_get_lang(), fontsize, spacing, encoding))) {
308 return xfont;
309 }
310
311 if (strcmp(bl_get_lang(), "ja") != 0 &&
312 (xfont = load_xfont_intern(display, fontname, max_len, "*", weight, slant, width,
313 "ja", fontsize, spacing, encoding))) {
314 return xfont;
315 }
316
317 /* GNU Unifont (-gnu-unifont) */
318
319 return load_xfont_intern(display, fontname, max_len, "unifont", weight, slant,
320 width, "*", fontsize, spacing, encoding);
321 }
322
323 return NULL;
324 }
325
xcore_set_font(ui_font_t * font,const char * fontname,u_int fontsize,u_int col_width,int use_medium_for_bold,int letter_space)326 static int xcore_set_font(ui_font_t *font, const char *fontname, u_int fontsize,
327 u_int col_width, /* if usascii font wants to be set , 0 will be set */
328 int use_medium_for_bold, int letter_space) {
329 XFontStruct *xfont;
330 u_int cols;
331 char *weight;
332 char *slant;
333 char *width;
334 char *family;
335 cs_info_t *csinfo;
336 char **font_encoding_p;
337 u_int percent;
338 int count;
339 int num_spacings;
340 char *spacings[] = {"c", "m", "p"};
341
342 if ((csinfo = get_cs_info(FONT_CS(font->id))) == NULL) {
343 #ifdef DEBUG
344 bl_warn_printf(BL_DEBUG_TAG " get_cs_info(cs %x(id %x)) failed.\n", FONT_CS(font->id),
345 font->id);
346 #endif
347
348 return 0;
349 }
350
351 if (fontname) {
352 char *p;
353 char *font_xlfd;
354 char *percent_str;
355
356 if ((p = alloca(strlen(fontname) + 1)) == NULL) {
357 return 0;
358 }
359 strcpy(p, fontname);
360
361 if (parse_xfont_name(&font_xlfd, &percent_str, p)) {
362 #ifdef DEBUG
363 bl_debug_printf(BL_DEBUG_TAG " loading %s font (%s percent).\n", font_xlfd, percent_str);
364 #endif
365
366 while (1) {
367 if (!(xfont = XLoadQueryFont(font->display, font_xlfd))) {
368 char *xlfd;
369
370 if ((xlfd = bl_str_replace(font_xlfd, "-bold-", "-medium-"))) {
371 xfont = XLoadQueryFont(font->display, xlfd);
372 free(xlfd);
373 }
374
375 if (!xfont) {
376 bl_msg_printf("Font %s couldn't be loaded.\n", font_xlfd);
377
378 break;
379 }
380
381 font->double_draw_gap = 1;
382 } else {
383 font->double_draw_gap = use_medium_for_bold;
384 }
385
386 if (percent_str == NULL || !bl_str_to_uint(&percent, percent_str)) {
387 percent = 0;
388 }
389
390 goto font_found;
391 }
392 }
393 }
394
395 /*
396 * searching apropriate font by using font info.
397 */
398
399 #ifdef __DEBUG
400 bl_debug_printf("font for id %x will be loaded.\n", font->id);
401 #endif
402
403 font->double_draw_gap = 0;
404
405 percent = 0;
406
407 if (font->id & FONT_BOLD) {
408 weight = "bold";
409 } else {
410 weight = "medium";
411 }
412
413 if (font->id & FONT_ITALIC) {
414 slant = "i";
415 } else {
416 slant = "r";
417 }
418
419 width = "normal";
420
421 if ((font->id & FONT_FULLWIDTH) && (FONT_CS(font->id) == ISO10646_UCS4_1)) {
422 family = "biwidth";
423 num_spacings = sizeof(spacings) / sizeof(spacings[0]);
424 } else {
425 family = "fixed";
426 num_spacings = 1;
427 }
428
429 for (count = 0; ; count++) {
430 FOREACH_FONT_ENCODINGS(csinfo, font_encoding_p) {
431 int idx;
432
433 for (idx = 0; idx < num_spacings; idx++) {
434 if ((xfont = load_xfont(font->display, family, weight, slant, width, fontsize,
435 spacings[idx], *font_encoding_p))) {
436 goto font_found;
437 }
438 }
439 }
440
441 if (count == 0) {
442 width = "*";
443 family = "*";
444 num_spacings = sizeof(spacings) / sizeof(spacings[0]);
445 } else if (count == 1) {
446 slant = "*";
447 } else if (count == 2) {
448 weight = "*";
449
450 if (font->id & FONT_BOLD) {
451 /* no bold font is found. */
452 font->double_draw_gap = 1;
453 }
454 } else {
455 break;
456 }
457 }
458
459 return 0;
460
461 font_found:
462
463 font->xfont = xfont;
464
465 font->height = xfont->ascent + xfont->descent;
466 font->ascent = xfont->ascent;
467
468 /*
469 * calculating actual font glyph width.
470 */
471 font->is_proportional = 0;
472 font->width = xfont->max_bounds.width;
473
474 if (xfont->max_bounds.width != xfont->min_bounds.width) {
475 if (FONT_CS(font->id) == ISO10646_UCS4_1 || FONT_CS(font->id) == TIS620_2533) {
476 if (font->id & FONT_FULLWIDTH) {
477 /*
478 * XXX
479 * At the present time , all full width unicode fonts
480 * (which may include both half width and full width
481 * glyphs) are regarded as fixed.
482 * Since I don't know what chars to be compared to
483 * determine font proportion and width.
484 */
485 } else {
486 /*
487 * XXX
488 * A font including combining (0-width) glyphs or both half and
489 * full width glyphs.
490 * In this case , whether the font is proportional or not
491 * cannot be determined by comparing min_bounds and max_bounds,
492 * so if `i' and `W' chars have different width , the font is
493 * regarded as proportional (and `W' width is used as font->width).
494 */
495
496 u_int w_width;
497 u_int i_width;
498
499 if ((w_width = xcore_calculate_char_width(font->display, font->xfont, 'W')) == 0) {
500 font->is_proportional = 1;
501 } else if ((i_width = xcore_calculate_char_width(font->display, font->xfont, 'i')) == 0 ||
502 w_width != i_width) {
503 font->is_proportional = 1;
504 font->width = w_width;
505 } else {
506 font->width = w_width;
507 }
508 }
509 } else {
510 #ifdef DEBUG
511 bl_warn_printf(BL_DEBUG_TAG " max font width(%d) and min one(%d) are mismatched.\n",
512 xfont->max_bounds.width, xfont->min_bounds.width);
513 #endif
514
515 font->is_proportional = 1;
516 }
517 }
518
519 font->x_off = 0;
520
521 if (font->id & FONT_FULLWIDTH) {
522 cols = 2;
523 } else {
524 cols = 1;
525 }
526
527 if (col_width == 0) {
528 /* standard(usascii) font */
529
530 if (!font->is_var_col_width) {
531 u_int ch_width;
532
533 if (percent > 0) {
534 if (font->is_vertical) {
535 /* The width of full and half character font is the same. */
536 letter_space *= 2;
537 ch_width = DIVIDE_ROUNDING(fontsize * percent, 100);
538 } else {
539 ch_width = DIVIDE_ROUNDING(fontsize * percent, 200);
540 }
541 } else {
542 ch_width = font->width;
543
544 if (font->is_vertical) {
545 /* The width of full and half character font is the same. */
546 letter_space *= 2;
547 ch_width *= 2;
548 }
549 }
550
551 if (letter_space > 0 || ch_width > -letter_space) {
552 ch_width += letter_space;
553 }
554
555 if (font->width != ch_width) {
556 font->is_proportional = 1;
557
558 if (font->width < ch_width) {
559 /*
560 * If width(2) of '1' doesn't match ch_width(4)
561 * x_off = (4-2)/2 = 1.
562 * It means that starting position of drawing '1' is 1
563 * as follows.
564 *
565 * 0123
566 * +----+
567 * | ** |
568 * | * |
569 * | * |
570 * +----+
571 */
572 font->x_off = (ch_width - font->width) / 2;
573 }
574
575 font->width = ch_width;
576 }
577 }
578 } else {
579 /* not a standard(usascii) font */
580
581 /*
582 * XXX hack
583 * forcibly conforming non standard font width to standard font width.
584 */
585
586 if (font->is_vertical) {
587 /*
588 * The width of full and half character font is the same.
589 * is_var_col_width is always false if is_vertical is true.
590 */
591 if (font->width != col_width) {
592 bl_msg_printf("Font(id %x) width(%d) doesn't fit column width(%d).\n",
593 font->id, font->width, col_width);
594
595 font->is_proportional = 1;
596
597 if (font->width < col_width) {
598 font->x_off = (col_width - font->width) / 2;
599 }
600
601 font->width = col_width;
602 }
603 } else if (font->width != col_width * cols) {
604 bl_msg_printf("Font(id %x) width(%d) doesn't fit column width(%d).\n",
605 font->id, font->width, col_width * cols);
606
607 font->is_proportional = 1;
608
609 if (!font->is_var_col_width) {
610 if (font->width < col_width * cols) {
611 font->x_off = (col_width * cols - font->width) / 2;
612 }
613
614 font->width = col_width * cols;
615 }
616 }
617 }
618
619 /*
620 * checking if font width/height/ascent member is sane.
621 */
622
623 if (font->width == 0) {
624 #ifdef DEBUG
625 bl_warn_printf(BL_DEBUG_TAG " font width is 0.\n");
626 #endif
627
628 font->is_proportional = 1;
629
630 /* XXX this may be inaccurate. */
631 font->width = DIVIDE_ROUNDINGUP(fontsize * cols, 2);
632 }
633
634 if (font->height == 0) {
635 /* XXX this may be inaccurate. */
636 font->height = fontsize;
637 }
638
639 if (font->ascent == 0) {
640 /* XXX this may be inaccurate. */
641 font->ascent = fontsize;
642 }
643
644 /*
645 * set_decsp_font() is called after dummy font is loaded to get font metrics.
646 * Since dummy font encoding is "iso8859-1", loading rarely fails.
647 */
648 if (compose_dec_special_font && FONT_CS(font->id) == DEC_SPECIAL) {
649 return set_decsp_font(font);
650 }
651
652 return 1;
653 }
654
655 #endif
656
657 #if !defined(NO_DYNAMIC_LOAD_TYPE)
658
xft_calculate_char_width(ui_font_t * font,u_int32_t ch)659 static u_int xft_calculate_char_width(ui_font_t *font, u_int32_t ch /* US-ASCII or Unicode */
660 ) {
661 int (*func)(ui_font_t *, u_int32_t);
662
663 if (!(func = ui_load_type_xft_func(UI_CALCULATE_CHAR_WIDTH))) {
664 return 0;
665 }
666
667 return (*func)(font, ch);
668 }
669
xft_set_font(ui_font_t * font,const char * fontname,u_int fontsize,u_int col_width,int letter_space,int aa_opt,int use_point_size,double dpi)670 static int xft_set_font(ui_font_t *font, const char *fontname, u_int fontsize,
671 u_int col_width, /* if usascii font wants to be set , 0 will be set. */
672 int letter_space,
673 int aa_opt, /* 0 = default , 1 = enable , -1 = disable */
674 int use_point_size, double dpi) {
675 int (*func)(ui_font_t *, const char *, u_int, u_int, u_int, int, int, double);
676
677 if (!(func = ui_load_type_xft_func(UI_SET_FONT))) {
678 return 0;
679 }
680
681 return (*func)(font, fontname, fontsize, col_width, letter_space, aa_opt, use_point_size,
682 dpi);
683 }
684
xft_set_ot_font(ui_font_t * font)685 static int xft_set_ot_font(ui_font_t *font) {
686 int (*func)(ui_font_t *);
687
688 if (!(func = ui_load_type_xft_func(UI_SET_OT_FONT))) {
689 return 0;
690 }
691
692 return (*func)(font);
693 }
694
xft_convert_text_to_glyphs(ui_font_t * font,u_int32_t * shape_glyphs,u_int num_shape_glyphs,int8_t * xoffsets,int8_t * yoffsets,u_int8_t * advances,u_int32_t * noshape_glyphs,u_int32_t * src,u_int src_len,const char * script,const char * features)695 static u_int xft_convert_text_to_glyphs(ui_font_t *font, u_int32_t *shape_glyphs,
696 u_int num_shape_glyphs, int8_t *xoffsets,
697 int8_t *yoffsets, u_int8_t *advances,
698 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
699 const char *script, const char *features) {
700 int (*func)(ui_font_t *, u_int32_t *, u_int, int8_t *, int8_t *, u_int8_t *, u_int32_t *,
701 u_int32_t *, u_int, const char *, const char *);
702
703 if (!(func = ui_load_type_xft_func(UI_CONVERT_TEXT_TO_GLYPHS))) {
704 return 0;
705 }
706
707 return (*func)(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, advances,
708 noshape_glyphs, src, src_len, script, features);
709 }
710
711 #elif defined(USE_TYPE_XFT)
712 u_int xft_calculate_char_width(ui_font_t *font, u_int32_t ch);
713 int xft_set_font(ui_font_t *font, const char *fontname, u_int fontsize, u_int col_width,
714 int letter_space, int aa_opt, int use_point_size, double dpi);
715 int xft_set_ot_font(ui_font_t *font);
716 #define xft_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, \
717 advances, noshape_glyphs, src, src_len, script, features) \
718 ft_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, advances, \
719 noshape_glyphs, src, src_len, script, features)
720 u_int ft_convert_text_to_glyphs(ui_font_t *font, u_int32_t *shape_glyphs, int8_t *xoffsets,
721 int8_t *yoffsets, u_int8_t *advances, u_int num_shape_glyphs,
722 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
723 const char *script, const char *features);
724 #endif
725
726 #if !defined(NO_DYNAMIC_LOAD_TYPE)
727
cairo_calculate_char_width(ui_font_t * font,u_int32_t ch)728 static u_int cairo_calculate_char_width(ui_font_t *font, u_int32_t ch /* US-ASCII or Unicode */
729 ) {
730 int (*func)(ui_font_t *, u_int32_t);
731
732 if (!(func = ui_load_type_cairo_func(UI_CALCULATE_CHAR_WIDTH))) {
733 return 0;
734 }
735
736 return (*func)(font, ch);
737 }
738
cairo_set_font(ui_font_t * font,const char * fontname,u_int fontsize,u_int col_width,int letter_space,int aa_opt,int use_point_size,double dpi)739 static int cairo_set_font(ui_font_t *font, const char *fontname, u_int fontsize,
740 u_int col_width, /* if usascii font wants to be set , 0 will be set. */
741 int letter_space,
742 int aa_opt, /* 0 = default , 1 = enable , -1 = disable */
743 int use_point_size, double dpi) {
744 int (*func)(ui_font_t *, const char *, u_int, u_int, u_int, int, int, double);
745
746 if (!(func = ui_load_type_cairo_func(UI_SET_FONT))) {
747 return 0;
748 }
749
750 return (*func)(font, fontname, fontsize, col_width, letter_space, aa_opt, use_point_size, dpi);
751 }
752
cairo_set_ot_font(ui_font_t * font)753 static int cairo_set_ot_font(ui_font_t *font) {
754 int (*func)(ui_font_t *);
755
756 if (!(func = ui_load_type_cairo_func(UI_SET_OT_FONT))) {
757 return 0;
758 }
759
760 return (*func)(font);
761 }
762
cairo_convert_text_to_glyphs(ui_font_t * font,u_int32_t * shape_glyphs,u_int num_shape_glyphs,int8_t * xoffsets,int8_t * yoffsets,u_int8_t * advances,u_int32_t * noshape_glyphs,u_int32_t * src,u_int src_len,const char * script,const char * features)763 static u_int cairo_convert_text_to_glyphs(ui_font_t *font, u_int32_t *shape_glyphs,
764 u_int num_shape_glyphs, int8_t *xoffsets,
765 int8_t *yoffsets, u_int8_t *advances,
766 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
767 const char *script, const char *features) {
768 int (*func)(ui_font_t *, u_int32_t *, u_int, int8_t *, int8_t *, u_int8_t *, u_int32_t *,
769 u_int32_t *, u_int, const char *, const char *);
770
771 if (!(func = ui_load_type_cairo_func(UI_CONVERT_TEXT_TO_GLYPHS))) {
772 return 0;
773 }
774
775 return (*func)(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, advances,
776 noshape_glyphs, src, src_len, script, features);
777 }
778
779 #elif defined(USE_TYPE_CAIRO)
780 u_int cairo_calculate_char_width(ui_font_t *font, u_int32_t ch);
781 int cairo_set_font(ui_font_t *font, const char *fontname, u_int fontsize, u_int col_width,
782 int letter_space, int aa_opt, int use_point_size, double dpi);
783 int cairo_set_ot_font(ui_font_t *font);
784 #define cairo_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, \
785 advances, noshape_glyphs, src, src_len, script, features) \
786 ft_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets, advances, \
787 noshape_glyphs, src, src_len, script, features)
788 #ifndef USE_TYPE_XFT
789 u_int ft_convert_text_to_glyphs(ui_font_t *font, u_int32_t *shape_glyphs, int8_t *xoffsets,
790 int8_t *yoffsets, u_int8_t *advances, u_int num_shape_glyphs,
791 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
792 const char *script, const char *features);
793 #endif
794 #endif
795
calculate_char_width(ui_font_t * font,u_int32_t ch,ef_charset_t cs)796 static u_int calculate_char_width(ui_font_t *font, u_int32_t ch, ef_charset_t cs) {
797 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
798 if (font->xft_font) {
799 if (cs != US_ASCII && cs != ISO8859_1_R && !IS_ISCII(cs)) {
800 if (!(ch = ui_convert_to_xft_ucs4(ch, cs))) {
801 return 0;
802 }
803 }
804
805 return xft_calculate_char_width(font, ch);
806 }
807 #endif
808
809 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
810 if (font->cairo_font) {
811 if (cs != US_ASCII && cs != ISO8859_1_R && !IS_ISCII(cs)) {
812 if (!(ch = ui_convert_to_xft_ucs4(ch, cs))) {
813 return 0;
814 }
815 }
816
817 return cairo_calculate_char_width(font, ch);
818 }
819 #endif
820
821 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
822 if (font->xfont) {
823 return xcore_calculate_char_width(font->display, font->xfont, ch);
824 }
825 #endif
826
827 #ifdef DEBUG
828 bl_debug_printf(BL_DEBUG_TAG " couldn't calculate correct font width.\n");
829 #endif
830
831 return 0;
832 }
833
834 /* --- global functions --- */
835
ui_compose_dec_special_font(void)836 void ui_compose_dec_special_font(void) {
837 compose_dec_special_font = 1;
838 }
839
ui_font_new(Display * display,vt_font_t id,int size_attr,ui_type_engine_t type_engine,ui_font_present_t font_present,const char * fontname,u_int fontsize,u_int col_width,int use_medium_for_bold,int letter_space)840 ui_font_t *ui_font_new(Display *display, vt_font_t id, int size_attr, ui_type_engine_t type_engine,
841 /* FONT_VAR_WIDTH is never set if FONT_VERTICAL is set. */
842 ui_font_present_t font_present,
843 const char *fontname, u_int fontsize, u_int col_width,
844 int use_medium_for_bold,
845 int letter_space /* ignored in variable column width mode. */) {
846 ui_font_t *font;
847
848 if ((font = calloc(1, sizeof(ui_font_t))) == NULL) {
849 #ifdef DEBUG
850 bl_warn_printf(BL_DEBUG_TAG " malloc() failed.\n");
851 #endif
852
853 return NULL;
854 }
855
856 font->display = display;
857 font->id = id;
858
859 if (font_present & FONT_VAR_WIDTH) {
860 font->is_var_col_width = 1;
861 } else if (IS_ISCII(FONT_CS(font->id))) {
862 /*
863 * For exampe, 'W' width and 'l' width of OR-TTSarala font for ISCII_ORIYA
864 * are the same by chance, though it is actually a proportional font.
865 */
866 font->is_var_col_width = font->is_proportional = 1;
867 }
868
869 if (font_present & FONT_VERTICAL) {
870 font->is_vertical = 1;
871 }
872
873 if (size_attr >= DOUBLE_HEIGHT_TOP) {
874 fontsize *= 2;
875 col_width *= 2;
876 }
877
878 switch (type_engine) {
879 default:
880 return NULL;
881
882 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
883 case TYPE_XFT:
884 if (!xft_set_font(font, fontname, fontsize, col_width, letter_space,
885 (font_present & FONT_AA) == FONT_AA
886 ? 1
887 : ((font_present & FONT_NOAA) == FONT_NOAA ? -1 : 0),
888 use_point_size_for_fc, dpi_for_fc)) {
889 free(font);
890
891 return NULL;
892 }
893
894 break;
895 #endif
896
897 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
898 case TYPE_CAIRO:
899 if (!cairo_set_font(font, fontname, fontsize, col_width, letter_space,
900 (font_present & FONT_AA) == FONT_AA
901 ? 1
902 : ((font_present & FONT_NOAA) == FONT_NOAA ? -1 : 0),
903 use_point_size_for_fc, dpi_for_fc)) {
904 free(font);
905
906 return NULL;
907 }
908
909 break;
910 #endif
911
912 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
913 case TYPE_XCORE:
914 if (font_present & FONT_AA) {
915 return NULL;
916 } else if (!xcore_set_font(font, fontname, fontsize, col_width, use_medium_for_bold,
917 letter_space)) {
918 if (size_attr >= DOUBLE_HEIGHT_TOP &&
919 xcore_set_font(font, fontname, fontsize / 2, col_width, use_medium_for_bold,
920 letter_space)) {
921 goto end;
922 }
923
924 free(font);
925
926 return NULL;
927 }
928
929 goto end;
930 #endif
931 }
932
933 /*
934 * set_decsp_font() is called after dummy xft/cairo font is loaded to get font
935 * metrics.
936 * Since dummy font encoding is "iso8859-1", loading rarely fails.
937 */
938 /* XXX dec specials must always be composed for now */
939 if (/* compose_dec_special_font && */ FONT_CS(font->id) == DEC_SPECIAL) {
940 set_decsp_font(font);
941 }
942
943 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
944 end:
945 #endif
946 if (size_attr == DOUBLE_WIDTH) {
947 if (type_engine == TYPE_CAIRO) {
948 font->x_off *= 2;
949 } else {
950 font->x_off += (font->width / 2);
951 font->is_proportional = 1;
952 font->is_var_col_width = 0;
953 }
954 font->width *= 2;
955 }
956
957 font->size_attr = size_attr;
958
959 if (font->is_proportional && !font->is_var_col_width) {
960 bl_msg_printf("Font(id %x): Draw one char at a time to fit column width.\n", font->id);
961 }
962
963 #ifdef DEBUG
964 ui_font_dump(font);
965 #endif
966
967 return font;
968 }
969
ui_font_destroy(ui_font_t * font)970 void ui_font_destroy(ui_font_t *font) {
971 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
972 if (font->xft_font) {
973 xft_unset_font(font);
974 }
975 #endif
976
977 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
978 if (font->cairo_font) {
979 cairo_unset_font(font);
980 }
981 #endif
982
983 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
984 if (font->xfont) {
985 XFreeFont(font->display, font->xfont);
986 font->xfont = NULL;
987 }
988 #endif
989
990 if (font->decsp_font) {
991 ui_decsp_font_destroy(font->decsp_font, font->display);
992 font->decsp_font = NULL;
993 }
994
995 free(font);
996 }
997
ui_calculate_char_width(ui_font_t * font,u_int32_t ch,ef_charset_t cs,int is_awidth,int * draw_alone)998 u_int ui_calculate_char_width(ui_font_t *font, u_int32_t ch, ef_charset_t cs, int is_awidth,
999 int *draw_alone) {
1000 if (draw_alone) {
1001 *draw_alone = 0;
1002 }
1003
1004 if (font->is_proportional) {
1005 if (font->is_var_col_width) {
1006 /* Returned value can be 0 if iscii font is used. */
1007 return calculate_char_width(font, ch, cs);
1008 }
1009
1010 if (draw_alone) {
1011 *draw_alone = 1;
1012 }
1013 } else if (draw_alone &&
1014 cs == ISO10646_UCS4_1 /* ISO10646_UCS4_1_V is always proportional */) {
1015 if (is_awidth ||
1016 /*
1017 * The width of U+2590 and U+2591 is narrow in EastAsianWidth-6.3.0
1018 * but the glyphs in GNU Unifont are full-width unexpectedly.
1019 */
1020 ch == 0x2590 || ch == 0x2591) {
1021 if (calculate_char_width(font, ch, cs) != font->width) {
1022 *draw_alone = 1;
1023 }
1024 }
1025 }
1026
1027 return font->width;
1028 }
1029
ui_font_get_encoding_names(ef_charset_t cs)1030 char **ui_font_get_encoding_names(ef_charset_t cs) {
1031 cs_info_t *info;
1032
1033 if ((info = get_cs_info(cs))) {
1034 return info->encoding_names;
1035 } else {
1036 return NULL;
1037 }
1038 }
1039
ui_font_use_point_size(int use)1040 void ui_font_use_point_size(int use) { use_point_size_for_fc = use; }
1041
ui_font_has_ot_layout_table(ui_font_t * font)1042 int ui_font_has_ot_layout_table(ui_font_t *font) {
1043 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
1044 if (font->cairo_font) {
1045 #ifdef USE_OT_LAYOUT
1046 if (!font->ot_font) {
1047 if (font->ot_font_not_found) {
1048 return 0;
1049 }
1050
1051 if (!cairo_set_ot_font(font)) {
1052 font->ot_font_not_found = 1;
1053
1054 return 0;
1055 }
1056 }
1057 #endif
1058
1059 return 1;
1060 }
1061 #endif
1062 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
1063 if (font->xft_font) {
1064 #ifdef USE_OT_LAYOUT
1065 if (!font->ot_font) {
1066 if (font->ot_font_not_found) {
1067 return 0;
1068 }
1069
1070 if (!xft_set_ot_font(font)) {
1071 font->ot_font_not_found = 1;
1072
1073 return 0;
1074 }
1075 }
1076 #endif
1077
1078 return 1;
1079 }
1080 #endif
1081
1082 return 0;
1083 }
1084
ui_convert_text_to_glyphs(ui_font_t * font,u_int32_t * shape_glyphs,u_int num_shape_glyphs,int8_t * xoffsets,int8_t * yoffsets,u_int8_t * advances,u_int32_t * noshape_glyphs,u_int32_t * src,u_int src_len,const char * script,const char * features)1085 u_int ui_convert_text_to_glyphs(ui_font_t *font, /* always has ot_font */
1086 u_int32_t *shape_glyphs, u_int num_shape_glyphs, int8_t *xoffsets,
1087 int8_t *yoffsets, u_int8_t *advances, u_int32_t *noshape_glyphs,
1088 u_int32_t *src, u_int src_len,
1089 const char *script, const char *features) {
1090 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
1091 if (font->cairo_font) {
1092 return cairo_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets,
1093 advances, noshape_glyphs, src, src_len, script, features);
1094 }
1095 #endif
1096 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
1097 if (font->xft_font) {
1098 return xft_convert_text_to_glyphs(font, shape_glyphs, num_shape_glyphs, xoffsets, yoffsets,
1099 advances, noshape_glyphs, src, src_len, script, features);
1100 }
1101 #endif
1102
1103 return 0;
1104 }
1105
1106 /* For mlterm-libvte */
ui_font_set_dpi_for_fc(double dpi)1107 void ui_font_set_dpi_for_fc(double dpi) { dpi_for_fc = dpi; }
1108
1109 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
1110
1111 static int use_cp932_ucs_for_xft = 0;
1112
ui_use_cp932_ucs_for_xft(void)1113 void ui_use_cp932_ucs_for_xft(void) {
1114 use_cp932_ucs_for_xft = 1;
1115 }
1116
1117 /*
1118 * used only for xft or cairo.
1119 * Don't call this function for US_ASCII, ISO8859_1_R and ISCII.
1120 */
ui_convert_to_xft_ucs4(u_int32_t ch,ef_charset_t cs)1121 u_int32_t ui_convert_to_xft_ucs4(u_int32_t ch, ef_charset_t cs) {
1122 ef_char_t non_ucs;
1123 ef_char_t ucs4;
1124
1125 if (IS_ISO10646_UCS4(cs) /* || cs == ISO10646_UCS2_1 */) {
1126 return ch;
1127 } else if (use_cp932_ucs_for_xft && cs == JISX0208_1983) {
1128 if (ch == 0x2140) {
1129 return 0xff3c;
1130 } else if (ch == 0x2141) {
1131 return 0xff5e;
1132 } else if (ch == 0x2142) {
1133 return 0x2225;
1134 } else if (ch == 0x215d) {
1135 return 0xff0d;
1136 } else if (ch == 0x2171) {
1137 return 0xffe0;
1138 } else if (ch == 0x2172) {
1139 return 0xffe1;
1140 } else if (ch == 0x224c) {
1141 return 0xffe2;
1142 }
1143 }
1144
1145 non_ucs.size = CS_SIZE(cs);
1146 non_ucs.property = 0;
1147 non_ucs.cs = cs;
1148 ef_int_to_bytes(non_ucs.ch, non_ucs.size, ch);
1149
1150 if (vt_is_msb_set(cs)) {
1151 u_int count;
1152
1153 for (count = 0; count < non_ucs.size; count++) {
1154 non_ucs.ch[count] &= 0x7f;
1155 }
1156 }
1157
1158 if (ef_map_to_ucs4(&ucs4, &non_ucs)) {
1159 return ef_char_to_int(&ucs4);
1160 } else {
1161 return 0;
1162 }
1163 }
1164
1165 #endif
1166
1167 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
1168
1169 /* Return written size */
ui_convert_ucs4_to_utf16(u_char * dst,u_int32_t src)1170 size_t ui_convert_ucs4_to_utf16(u_char *dst, /* 4 bytes. Big endian. */
1171 u_int32_t src) {
1172 #if 0
1173 bl_debug_printf(BL_DEBUG_TAG "%.8x => ", src);
1174 #endif
1175
1176 if (src < 0x10000) {
1177 dst[0] = (src >> 8) & 0xff;
1178 dst[1] = src & 0xff;
1179
1180 return 2;
1181 } else if (src < 0x110000) {
1182 /* surrogate pair */
1183
1184 u_char c;
1185
1186 src -= 0x10000;
1187 c = (u_char)(src / (0x100 * 0x400));
1188 src -= (c * 0x100 * 0x400);
1189 dst[0] = c + 0xd8;
1190
1191 c = (u_char)(src / 0x400);
1192 src -= (c * 0x400);
1193 dst[1] = c;
1194
1195 c = (u_char)(src / 0x100);
1196 src -= (c * 0x100);
1197 dst[2] = c + 0xdc;
1198 dst[3] = (u_char)src;
1199
1200 #if 0
1201 bl_msg_printf("%.2x%.2x%.2x%.2x\n", dst[0], dst[1], dst[2], dst[3]);
1202 #endif
1203
1204 return 4;
1205 }
1206
1207 return 0;
1208 }
1209
1210 #endif
1211
1212 #ifdef DEBUG
1213
ui_font_dump(ui_font_t * font)1214 void ui_font_dump(ui_font_t *font) {
1215 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
1216 bl_msg_printf("Font id %x: XFont %p ", font->id, font->xfont);
1217 #endif
1218 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT)
1219 bl_msg_printf("Font id %x: XftFont %p ", font->id, font->xft_font);
1220 #endif
1221 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_CAIRO)
1222 bl_msg_printf("Font id %x: CairoFont %p ", font->id, font->cairo_font);
1223 #endif
1224
1225 bl_msg_printf("(width %d, height %d, ascent %d, x_off %d, gap %d)", font->width, font->height,
1226 font->ascent, font->x_off, font->double_draw_gap);
1227
1228 if (font->is_proportional) {
1229 bl_msg_printf(" (proportional)");
1230 }
1231
1232 if (font->is_var_col_width) {
1233 bl_msg_printf(" (var col width)");
1234 }
1235
1236 if (font->is_vertical) {
1237 bl_msg_printf(" (vertical)");
1238 }
1239
1240 if (font->double_draw_gap) {
1241 bl_msg_printf(" (double drawing)");
1242 }
1243
1244 bl_msg_printf("\n");
1245 }
1246
1247 #endif
1248