1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "../ui_font.h"
4
5 #include <stdio.h>
6 #include <string.h> /* memset/strncasecmp */
7 #include <pobl/bl_debug.h>
8 #include <pobl/bl_str.h> /* bl_snprintf */
9 #include <pobl/bl_mem.h> /* alloca */
10 #include <pobl/bl_str.h> /* bl_str_sep/bl_str_to_int */
11 #include <pobl/bl_locale.h> /* bl_get_lang() */
12 #include <mef/ef_ucs4_map.h>
13 #include <vt_char_encoding.h>
14
15 #ifdef USE_OT_LAYOUT
16 #include "otl.h"
17 #endif
18
19 #define FOREACH_FONT_ENCODINGS(csinfo, font_encoding_p) \
20 for ((font_encoding_p) = &csinfo->encoding_names[0]; *(font_encoding_p); (font_encoding_p)++)
21
22 #if 0
23 #define __DEBUG
24 #endif
25
26 typedef struct wincs_info {
27 DWORD cs;
28 vt_char_encoding_t encoding;
29
30 } wincs_info_t;
31
32 typedef struct cs_info {
33 ef_charset_t cs;
34 DWORD wincs;
35
36 } cs_info_t;
37
38 /* --- static variables --- */
39
40 static wincs_info_t wincs_info_table[] = {
41 { DEFAULT_CHARSET, VT_UNKNOWN_ENCODING, },
42 { SYMBOL_CHARSET, VT_UNKNOWN_ENCODING, },
43 { OEM_CHARSET, VT_UNKNOWN_ENCODING, },
44 { ANSI_CHARSET, VT_CP1252, },
45 { RUSSIAN_CHARSET, VT_CP1251, },
46 { GREEK_CHARSET, VT_CP1253, },
47 { TURKISH_CHARSET, VT_CP1254, },
48 { BALTIC_CHARSET, VT_CP1257, },
49 { HEBREW_CHARSET, VT_CP1255, },
50 { ARABIC_CHARSET, VT_CP1256, },
51 { SHIFTJIS_CHARSET, VT_SJIS, },
52 { HANGEUL_CHARSET, VT_UHC, },
53 { GB2312_CHARSET, VT_GBK, },
54 { CHINESEBIG5_CHARSET, VT_BIG5},
55 { JOHAB_CHARSET, VT_JOHAB, },
56 { THAI_CHARSET, VT_TIS620, },
57 { EASTEUROPE_CHARSET, VT_ISO8859_3, },
58 { MAC_CHARSET, VT_UNKNOWN_ENCODING, },
59 };
60
61 static cs_info_t cs_info_table[] = {
62 { ISO10646_UCS4_1, DEFAULT_CHARSET, },
63 { ISO10646_UCS4_1_V, DEFAULT_CHARSET, },
64
65 { DEC_SPECIAL, SYMBOL_CHARSET, },
66 { ISO8859_1_R, ANSI_CHARSET, },
67 { ISO8859_2_R, DEFAULT_CHARSET, },
68 { ISO8859_3_R, EASTEUROPE_CHARSET, },
69 { ISO8859_4_R, DEFAULT_CHARSET, },
70 { ISO8859_5_R, RUSSIAN_CHARSET, },
71 { ISO8859_6_R, ARABIC_CHARSET, },
72 { ISO8859_7_R, GREEK_CHARSET, },
73 { ISO8859_8_R, HEBREW_CHARSET, },
74 { ISO8859_9_R, TURKISH_CHARSET, },
75 { ISO8859_10_R, DEFAULT_CHARSET, },
76 { TIS620_2533, THAI_CHARSET, },
77 { ISO8859_13_R, DEFAULT_CHARSET, },
78 { ISO8859_14_R, DEFAULT_CHARSET, },
79 { ISO8859_15_R, DEFAULT_CHARSET, },
80 { ISO8859_16_R, DEFAULT_CHARSET, },
81 { TCVN5712_3_1993, VIETNAMESE_CHARSET, },
82 { ISCII_ASSAMESE, DEFAULT_CHARSET, },
83 { ISCII_BENGALI, DEFAULT_CHARSET, },
84 { ISCII_GUJARATI, DEFAULT_CHARSET, },
85 { ISCII_HINDI, DEFAULT_CHARSET, },
86 { ISCII_KANNADA, DEFAULT_CHARSET, },
87 { ISCII_MALAYALAM, DEFAULT_CHARSET, },
88 { ISCII_ORIYA, DEFAULT_CHARSET, },
89 { ISCII_PUNJABI, DEFAULT_CHARSET, },
90 { ISCII_TAMIL, DEFAULT_CHARSET, },
91 { ISCII_TELUGU, DEFAULT_CHARSET, },
92 { VISCII, VIETNAMESE_CHARSET, },
93 { KOI8_R, RUSSIAN_CHARSET, },
94 { KOI8_U, RUSSIAN_CHARSET, },
95 { KOI8_T, RUSSIAN_CHARSET, },
96 { GEORGIAN_PS, DEFAULT_CHARSET, },
97 { CP1250, EASTEUROPE_CHARSET, },
98 { CP1251, RUSSIAN_CHARSET, },
99 { CP1252, ANSI_CHARSET, },
100 { CP1253, GREEK_CHARSET, },
101 { CP1254, TURKISH_CHARSET, },
102 { CP1255, HEBREW_CHARSET, },
103 { CP1256, ARABIC_CHARSET, },
104 { CP1257, BALTIC_CHARSET, },
105 { CP1258, VIETNAMESE_CHARSET, },
106
107 { JISX0201_KATA, SHIFTJIS_CHARSET, },
108 { JISX0201_ROMAN, SHIFTJIS_CHARSET, },
109 { JISC6226_1978, SHIFTJIS_CHARSET, },
110 { JISX0208_1983, SHIFTJIS_CHARSET, },
111 { JISX0208_1990, SHIFTJIS_CHARSET, },
112 { JISX0212_1990, SHIFTJIS_CHARSET, },
113 { JISX0213_2000_1, SHIFTJIS_CHARSET, },
114 { JISX0213_2000_2, SHIFTJIS_CHARSET, },
115
116 { KSC5601_1987, HANGEUL_CHARSET, },
117 { UHC, HANGEUL_CHARSET, },
118 { JOHAB, JOHAB_CHARSET, },
119
120 { GB2312_80, GB2312_CHARSET, },
121 { GBK, GB2312_CHARSET, },
122 { BIG5, CHINESEBIG5_CHARSET, },
123 { HKSCS, DEFAULT_CHARSET, },
124 { CNS11643_1992_1, GB2312_CHARSET, },
125 { CNS11643_1992_2, GB2312_CHARSET, },
126 { CNS11643_1992_3, GB2312_CHARSET, },
127 { CNS11643_1992_4, GB2312_CHARSET, },
128 { CNS11643_1992_5, GB2312_CHARSET, },
129 { CNS11643_1992_6, GB2312_CHARSET, },
130 { CNS11643_1992_7, GB2312_CHARSET, },
131 };
132
133 static GC display_gc;
134
135 static int use_point_size;
136
137 /* --- static functions --- */
138
get_wincs_info(ef_charset_t cs)139 static wincs_info_t *get_wincs_info(ef_charset_t cs) {
140 int count;
141
142 for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_t); count++) {
143 if (cs_info_table[count].cs == cs) {
144 DWORD wincs;
145
146 wincs = cs_info_table[count].wincs;
147
148 for (count = 0; count < sizeof(wincs_info_table) / sizeof(wincs_info_t); count++) {
149 if (wincs_info_table[count].cs == wincs) {
150 return &wincs_info_table[count];
151 }
152 }
153
154 break;
155 }
156 }
157
158 #ifdef DEBUG
159 bl_warn_printf(BL_DEBUG_TAG " not supported cs(%x).\n", cs);
160 #endif
161
162 return NULL;
163 }
164
parse_font_name(char ** font_family,int * font_weight,int * is_italic,double * font_size,u_int * percent,char * font_name)165 static int parse_font_name(
166 char **font_family, int *font_weight, /* if weight is not specified in
167 font_name , not changed. */
168 int *is_italic, /* if slant is not specified in font_name , not changed. */
169 double *font_size, /* if size is not specified in font_name , not changed. */
170 u_int *percent, /* if percent is not specified in font_name , not changed. */
171 char *font_name /* modified by this function. */
172 ) {
173 char *p;
174 size_t len;
175
176 /*
177 * Format.
178 * [Family]( [WEIGHT] [SLANT] [SIZE]:[Percentage])
179 */
180
181 *font_family = font_name;
182
183 if ((p = strrchr(font_name, ':'))) {
184 /* Parsing ":[Percentage]" */
185 if (bl_str_to_uint(percent, p + 1)) {
186 *p = '\0';
187 }
188 #ifdef DEBUG
189 else {
190 bl_warn_printf(BL_DEBUG_TAG " Percentage(%s) is illegal.\n", p + 1);
191 }
192 #endif
193 }
194
195 /*
196 * Parsing "[Family] [WEIGHT] [SLANT] [SIZE]".
197 * Following is the same as libtype/ui_font_ft.c and fb/ui_font.c.
198 * except FW_* and is_italic.
199 */
200
201 #if 0
202 bl_debug_printf("Parsing %s for [Family] [Weight] [Slant]\n", *font_family);
203 #endif
204
205 p = bl_str_chop_spaces(*font_family);
206 len = strlen(p);
207 while (len > 0) {
208 size_t step = 0;
209
210 if (*p == ' ') {
211 char *orig_p;
212
213 orig_p = p;
214 do {
215 p++;
216 len--;
217 } while (*p == ' ');
218
219 if (len == 0) {
220 *orig_p = '\0';
221
222 break;
223 } else {
224 int count;
225 struct {
226 char *style;
227 int weight;
228 int is_italic;
229
230 } styles[] = {
231 /*
232 * Portable styles.
233 */
234 /* slant */
235 { "italic", 0, 1, },
236 /* weight */
237 { "bold", FW_BOLD, 0, },
238
239 /*
240 * Hack for styles which can be returned by
241 * gtk_font_selection_dialog_get_font_name().
242 */
243 /* slant */
244 { "oblique", /* XXX This style is ignored. */ 0, 0, },
245 /* weight */
246 { "light", /* e.g. "Bookman Old Style Light" */ FW_LIGHT, 0, },
247 { "semi-bold", FW_SEMIBOLD, 0, },
248 { "heavy", /* e.g. "Arial Black Heavy" */ FW_HEAVY, 0, },
249 /* other */
250 { "semi-condensed", /* XXX This style is ignored. */ 0, 0, },
251 };
252
253 for (count = 0; count < sizeof(styles) / sizeof(styles[0]); count++) {
254 size_t len_v;
255
256 len_v = strlen(styles[count].style);
257
258 /* XXX strncasecmp is not portable? */
259 if (len >= len_v && strncasecmp(p, styles[count].style, len_v) == 0) {
260 *orig_p = '\0';
261 step = len_v;
262 if (styles[count].weight) {
263 *font_weight = styles[count].weight;
264 } else if (styles[count].is_italic) {
265 *is_italic = 1;
266 }
267
268 goto next_char;
269 }
270 }
271
272 if (*p != '0' || /* In case of "DevLys 010" font family. */
273 *(p + 1) == '\0') /* "MS Gothic 0" => "MS Gothic" + "0" */
274 {
275 char *end;
276 double size;
277
278 size = strtod(p, &end);
279 if (*end == '\0') {
280 /* p has no more parameters. */
281
282 *orig_p = '\0';
283 if (size > 0) {
284 *font_size = size;
285 }
286
287 break;
288 }
289 }
290
291 step = 1;
292 }
293 } else {
294 step = 1;
295 }
296
297 next_char:
298 p += step;
299 len -= step;
300 }
301
302 return 1;
303 }
304
calculate_char_width(ui_font_t * font,u_int32_t ch,ef_charset_t cs)305 static u_int calculate_char_width(ui_font_t *font, u_int32_t ch, ef_charset_t cs) {
306 SIZE sz;
307
308 if (!display_gc) {
309 /*
310 * Cached as far as ui_caculate_char_width is called.
311 * display_gc is destroyed in ui_font_new or ui_font_destroy.
312 */
313 display_gc = CreateIC("Display", NULL, NULL, NULL);
314 }
315
316 SelectObject(display_gc, font->xfont->fid);
317
318 if (cs != US_ASCII && !IS_ISCII(cs)) {
319 u_int32_t ucs4_code;
320 u_char utf16[4];
321 int len;
322 BOOL ret;
323
324 if (IS_ISO10646_UCS4(cs)) {
325 ucs4_code = ch;
326 } else {
327 ef_char_t non_ucs;
328 ef_char_t ucs4;
329
330 non_ucs.size = CS_SIZE(cs);
331 non_ucs.property = 0;
332 non_ucs.cs = cs;
333 ef_int_to_bytes(non_ucs.ch, non_ucs.size, ch);
334
335 if (vt_is_msb_set(cs)) {
336 u_int count;
337
338 for (count = 0; count < non_ucs.size; count++) {
339 non_ucs.ch[count] &= 0x7f;
340 }
341 }
342
343 if (ef_map_to_ucs4(&ucs4, &non_ucs)) {
344 ucs4_code = ef_bytes_to_int(ucs4.ch, 4);
345 } else {
346 return 0;
347 }
348 }
349
350 len = ui_convert_ucs4_to_utf16(utf16, ucs4_code) / 2;
351
352 #ifdef USE_OT_LAYOUT
353 if (font->use_ot_layout /* && font->ot_font */) {
354 #ifdef USE_WIN32API
355 /* GetTextExtentPointI doesn't exist on mingw-i686-pc-mingw */
356 static BOOL (*func)(HDC, LPWORD, int, LPSIZE);
357
358 if (!func) {
359 func = GetProcAddress(GetModuleHandleA("GDI32.DLL"), "GetTextExtentPointI");
360 }
361
362 ret = (*func)(display_gc, utf16, len, &sz);
363 #else
364 ret = GetTextExtentPointI(display_gc, utf16, len, &sz);
365 #endif
366 } else
367 #endif
368 {
369 ret = GetTextExtentPoint32W(display_gc, utf16, len, &sz);
370 }
371
372 if (!ret) {
373 return 0;
374 }
375 } else {
376 u_char c;
377
378 c = ch;
379 if (!GetTextExtentPoint32A(display_gc, &c, 1, &sz)) {
380 return 0;
381 }
382 }
383
384 if (sz.cx < 0) {
385 return 0;
386 } else {
387 return sz.cx;
388 }
389 }
390
391 /* --- global functions --- */
392
ui_compose_dec_special_font(void)393 void ui_compose_dec_special_font(void) {
394 /* Do nothing for now in win32. */
395 }
396
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)397 ui_font_t *ui_font_new(Display *display, vt_font_t id, int size_attr, ui_type_engine_t type_engine,
398 ui_font_present_t font_present, const char *fontname, u_int fontsize,
399 u_int col_width, int use_medium_for_bold, int letter_space) {
400 ui_font_t *font;
401 u_int cols;
402 wincs_info_t *wincsinfo;
403 char *font_family;
404 wchar_t *w_font_family;
405 int wlen;
406 int weight;
407 int is_italic;
408 int width;
409 int height;
410 double fontsize_d;
411 u_int percent;
412
413 if (type_engine != TYPE_XCORE ||
414 (font = calloc(1, sizeof(ui_font_t) + sizeof(XFontStruct))) == NULL) {
415 #ifdef DEBUG
416 bl_warn_printf(BL_DEBUG_TAG " malloc() failed.\n");
417 #endif
418
419 return NULL;
420 }
421
422 font->xfont = font + 1;
423
424 font->display = display;
425 font->id = id;
426
427 if (font->id & FONT_FULLWIDTH) {
428 cols = 2;
429 } else {
430 cols = 1;
431 }
432
433 if (IS_ISCII(FONT_CS(font->id)) || FONT_CS(font->id) == ISO10646_UCS4_1_V) {
434 /*
435 * For exampe, 'W' width and 'l' width of OR-TTSarala font for ISCII_ORIYA
436 * are the same by chance, though it is actually a proportional font.
437 */
438 font->is_var_col_width = font->is_proportional = 1;
439 } else if (font_present & FONT_VAR_WIDTH) {
440 font->is_var_col_width = 1;
441 }
442
443 if (font_present & FONT_VERTICAL) {
444 font->is_vertical = 1;
445 }
446
447 if ((wincsinfo = get_wincs_info(FONT_CS(font->id))) == NULL) {
448 #ifdef DEBUG
449 bl_warn_printf(BL_DEBUG_TAG " charset(0x%.2x) is not supported.\n", FONT_CS(font->id));
450 #endif
451
452 free(font);
453
454 return NULL;
455 }
456
457 if (font->id & FONT_BOLD) {
458 #if 0
459 weight = FW_BOLD;
460 #else
461 /*
462 * XXX
463 * Width of bold font is not necessarily the same as
464 * that of normal font in win32.
465 * So ignore weight and if font->id is bold use double-
466 * drawing method for now.
467 */
468 weight = FW_DONTCARE;
469 #endif
470 } else {
471 weight = FW_MEDIUM;
472 }
473
474 if (font->id & FONT_ITALIC) {
475 is_italic = TRUE;
476 } else {
477 is_italic = FALSE;
478 }
479
480 if (size_attr) {
481 if (size_attr >= DOUBLE_HEIGHT_TOP) {
482 fontsize *= 2;
483 }
484
485 col_width *= 2;
486 }
487
488 font_family = NULL;
489 percent = 0;
490 fontsize_d = (double)fontsize;
491
492 if (FONT_CS(font->id) == DEC_SPECIAL) {
493 font_family = "Tera Special";
494 } else if (fontname) {
495 char *p;
496
497 if ((p = alloca(strlen(fontname) + 1)) == NULL) {
498 free(font);
499
500 return NULL;
501 }
502 strcpy(p, fontname);
503
504 parse_font_name(&font_family, &weight, &is_italic, &fontsize_d, &percent, p);
505 } else {
506 /* Default font */
507 font_family = "Courier New";
508 }
509
510 wlen = MultiByteToWideChar(CP_UTF8, 0, font_family, -1, NULL, 0);
511 if ((w_font_family = alloca(wlen)) == NULL) {
512 free(font);
513
514 return NULL;
515 }
516 MultiByteToWideChar(CP_UTF8, 0, font_family, -1, w_font_family, wlen);
517
518 if (!display_gc) {
519 display_gc = CreateIC("Display", NULL, NULL, NULL);
520 }
521
522 height = fontsize_d;
523 #if 0
524 if (col_width > 0) {
525 if (size_attr == DOUBLE_WIDTH) {
526 width = fontsize_d;
527 } else {
528 width = (font->is_vertical ? col_width / 2 : col_width);
529 }
530 }
531 #else
532 if (size_attr == DOUBLE_WIDTH) {
533 width = fontsize_d;
534 }
535 #endif
536 else {
537 width = 0;
538 }
539 if (use_point_size) {
540 height = -MulDiv(height, GetDeviceCaps(display_gc, LOGPIXELSY), 72);
541 width = -MulDiv(width, GetDeviceCaps(display_gc, LOGPIXELSX), 72);
542 }
543
544 font->xfont->fid =
545 CreateFontW(height, /* Height */
546 width, /* Width (0=auto) */
547 0, /* text angle */
548 0, /* char angle */
549 weight, /* weight */
550 is_italic, /* italic */
551 FALSE, /* underline */
552 FALSE, /* eraseline */
553 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
554 (font_present & FONT_AA) ? ANTIALIASED_QUALITY :
555 DEFAULT_QUALITY /* PROOF_QUALITY */,
556 FIXED_PITCH | FF_DONTCARE, w_font_family);
557
558 if (!font->xfont->fid) {
559 #ifdef DEBUG
560 bl_warn_printf(BL_DEBUG_TAG " CreateFont failed.\n");
561 free(font);
562 #endif
563
564 return NULL;
565 } else {
566 TEXTMETRIC tm;
567 SIZE w_sz;
568 SIZE l_sz;
569
570 SelectObject(display_gc, font->xfont->fid);
571
572 GetTextMetrics(display_gc, &tm);
573
574 /*
575 * Note that fixed pitch font containing both Hankaku and Zenkaku characters
576 * like
577 * MS Gothic is regarded as VARIABLE_PITCH. (tm.tmPitchAndFamily)
578 * So "w" and "l" width is compared to check if font is proportional or not.
579 */
580 GetTextExtentPoint32A(display_gc, "w", 1, &w_sz);
581 GetTextExtentPoint32A(display_gc, "l", 1, &l_sz);
582
583 #ifdef DEBUG
584 bl_debug_printf(
585 "Family %s Size %d CS %x => AveCharWidth %d MaxCharWidth %d 'w' width "
586 "%d 'l' width %d Height %d Ascent %d ExLeading %d InLeading %d "
587 "Pitch&Family %d Weight %d\n",
588 font_family, fontsize, wincsinfo->cs, tm.tmAveCharWidth, tm.tmMaxCharWidth, w_sz.cx,
589 l_sz.cx, tm.tmHeight, tm.tmAscent, tm.tmExternalLeading, tm.tmInternalLeading,
590 tm.tmPitchAndFamily, tm.tmWeight);
591 #endif
592
593 if (w_sz.cx != l_sz.cx) {
594 font->is_proportional = 1;
595 font->width = tm.tmAveCharWidth * cols;
596 } else {
597 SIZE sp_sz;
598 WORD sp = 0x3000; /* wide space */
599
600 if (cols == 2 && GetTextExtentPoint32W(display_gc, &sp, 1, &sp_sz) &&
601 sp_sz.cx != l_sz.cx * 2) {
602 font->is_proportional = 1;
603 font->width = sp_sz.cx;
604 } else {
605 font->width = w_sz.cx * cols;
606 }
607 }
608
609 font->height = tm.tmHeight;
610 font->ascent = tm.tmAscent;
611
612 if ((font->id & FONT_BOLD) && tm.tmWeight <= FW_MEDIUM) {
613 font->double_draw_gap = 1;
614 }
615 }
616
617 font->xfont->size = fontsize;
618
619 /*
620 * Following processing is same as ui_font.c:set_xfont()
621 */
622
623 if (col_width == 0) {
624 /* standard(usascii) font */
625
626 if (!font->is_var_col_width) {
627 u_int ch_width;
628
629 if (percent > 0) {
630 if (font->is_vertical) {
631 /* The width of full and half character font is the same. */
632 letter_space *= 2;
633 ch_width = fontsize * percent / 100;
634 } else {
635 ch_width = fontsize * percent / 200;
636 }
637 } else {
638 ch_width = font->width;
639
640 if (font->is_vertical) {
641 /* The width of full and half character font is the same. */
642 letter_space *= 2;
643 ch_width *= 2;
644 }
645 }
646
647 if (use_point_size) {
648 ch_width = -MulDiv(ch_width, GetDeviceCaps(display_gc, LOGPIXELSX), 72);
649 }
650
651 if (letter_space > 0 || ch_width > -letter_space) {
652 ch_width += letter_space;
653 }
654
655 if (font->width != ch_width) {
656 font->is_proportional = 1;
657
658 if (font->width < ch_width) {
659 font->x_off = (ch_width - font->width) / 2;
660 }
661
662 font->width = ch_width;
663 }
664 }
665 } else {
666 /* not a standard(usascii) font */
667
668 /*
669 * XXX hack
670 * forcibly conforming non standard font width to standard font width.
671 */
672
673 if (font->is_vertical) {
674 /*
675 * The width of full and half character font is the same.
676 * is_var_col_width is always false if is_vertical is true.
677 */
678 if (font->width != col_width) {
679 bl_msg_printf("Font(id %x) width(%d) doesn't fit column width(%d).\n",
680 font->id, font->width, col_width);
681
682 font->is_proportional = 1;
683
684 if (font->width < col_width) {
685 font->x_off = (col_width - font->width) / 2;
686 }
687
688 font->width = col_width;
689 }
690 } else if (font->width != col_width * cols) {
691 bl_msg_printf("Font(id %x) width(%d) doesn't fit column width(%d).\n",
692 font->id, font->width, col_width * cols);
693
694 font->is_proportional = 1;
695
696 if (!font->is_var_col_width) {
697 if (font->width < col_width * cols) {
698 font->x_off = (col_width * cols - font->width) / 2;
699 }
700
701 font->width = col_width * cols;
702 }
703 }
704 }
705
706 font->size_attr = size_attr;
707
708 if (wincsinfo->cs != ANSI_CHARSET && wincsinfo->cs != SYMBOL_CHARSET &&
709 !IS_ISO10646_UCS4(FONT_CS(font->id))) {
710 if (!(font->xfont->conv = vt_char_encoding_conv_new(wincsinfo->encoding))) {
711 #ifdef DEBUG
712 bl_warn_printf(BL_DEBUG_TAG " vt_char_encoding_conv_new(font id %x) failed.\n", font->id);
713 #endif
714 }
715 }
716
717 if (font->is_proportional && !font->is_var_col_width) {
718 bl_msg_printf("Font(id %x): Draw one char at a time to fit column width.\n", font->id);
719 }
720
721 return font;
722 }
723
ui_font_destroy(ui_font_t * font)724 void ui_font_destroy(ui_font_t *font) {
725 #ifdef USE_OT_LAYOUT
726 if (font->ot_font) {
727 otl_close(font->ot_font);
728 }
729 #endif
730
731 if (font->xfont->fid) {
732 DeleteObject(font->xfont->fid);
733 }
734
735 if (font->xfont->conv) {
736 (*font->xfont->conv->destroy)(font->xfont->conv);
737 }
738
739 free(font);
740
741 if (display_gc) {
742 DeleteDC(display_gc);
743 display_gc = None;
744 }
745 }
746
747 #ifdef USE_OT_LAYOUT
ui_font_has_ot_layout_table(ui_font_t * font)748 int ui_font_has_ot_layout_table(ui_font_t *font) {
749 if (!font->ot_font) {
750 if (font->ot_font_not_found) {
751 return 0;
752 }
753
754 if (!display_gc) {
755 /*
756 * Cached as far as ui_caculate_char_width is called.
757 * display_gc is destroyed in ui_font_new or ui_font_destroy.
758 */
759 display_gc = CreateIC("Display", NULL, NULL, NULL);
760 }
761
762 SelectObject(display_gc, font->xfont->fid);
763
764 font->ot_font = otl_open(display_gc);
765
766 if (!font->ot_font) {
767 font->ot_font_not_found = 1;
768
769 return 0;
770 }
771 }
772
773 return 1;
774 }
775
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)776 u_int ui_convert_text_to_glyphs(ui_font_t *font, u_int32_t *shape_glyphs, u_int num_shape_glyphs,
777 int8_t *xoffsets, int8_t *yoffsets, u_int8_t *advances,
778 u_int32_t *noshape_glyphs, u_int32_t *src, u_int src_len,
779 const char *script, const char *features) {
780 u_int size;
781
782 if (use_point_size) {
783 if (!display_gc) {
784 display_gc = CreateIC("Display", NULL, NULL, NULL);
785 }
786
787 size = MulDiv((int)font->xfont->size, GetDeviceCaps(display_gc, LOGPIXELSY), 72);
788 } else {
789 size = font->xfont->size;
790 }
791
792 return otl_convert_text_to_glyphs(font->ot_font, shape_glyphs, num_shape_glyphs,
793 xoffsets, yoffsets, advances, noshape_glyphs,
794 src, src_len, script, features,
795 size * (font->size_attr >= DOUBLE_WIDTH ? 2 : 1));
796 }
797 #endif /* USE_OT_LAYOUT */
798
ui_calculate_char_width(ui_font_t * font,u_int32_t ch,ef_charset_t cs,int is_awidth,int * draw_alone)799 u_int ui_calculate_char_width(ui_font_t *font, u_int32_t ch, ef_charset_t cs, int is_awidth,
800 int *draw_alone) {
801 if (draw_alone) {
802 *draw_alone = 0;
803 }
804
805 if (font->is_proportional) {
806 if (font->is_var_col_width) {
807 return calculate_char_width(font, ch, cs);
808 }
809
810 if (draw_alone) {
811 *draw_alone = 1;
812 }
813 } else if (draw_alone &&
814 cs == ISO10646_UCS4_1 /* ISO10646_UCS4_1_V is always proportional */ &&
815 is_awidth) {
816 if (calculate_char_width(font, ch, cs) != font->width) {
817 *draw_alone = 1;
818 }
819 }
820
821 return font->width;
822 }
823
ui_font_use_point_size(int use)824 void ui_font_use_point_size(int use) { use_point_size = use; }
825
826 /* Return written size */
ui_convert_ucs4_to_utf16(u_char * dst,u_int32_t src)827 size_t ui_convert_ucs4_to_utf16(u_char *dst, /* 4 bytes. Little endian. 16bit aligned. */
828 u_int32_t src) {
829 u_int16_t *dst16 = (u_int16_t*)dst;
830
831 if (src < 0x10000) {
832 *dst16 = src;
833
834 return 2;
835 } else if (src < 0x110000) {
836 /* surrogate pair */
837
838 src -= 0x10000;
839
840 dst16[0] = ((src & 0xfffc0000) >> 10) + 0xd800 + ((src & 0x3fc00) >> 10);
841 dst16[1] = (src & 0x300) + 0xdc00 + (src & 0xff);
842
843 return 4;
844 }
845
846 return 0;
847 }
848
849 #ifdef DEBUG
850
ui_font_dump(ui_font_t * font)851 void ui_font_dump(ui_font_t *font) {
852 bl_msg_printf(" id %x: Font %p", font->id, font->xfont->fid);
853
854 if (font->is_proportional) {
855 bl_msg_printf(" (proportional)");
856 }
857 bl_msg_printf("\n");
858 }
859
860 #endif
861