1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
5
6 This file is part of the m17n library.
7
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
12
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301 USA. */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <ctype.h>
33
34 #include "m17n-gui.h"
35 #include "m17n-misc.h"
36 #include "internal.h"
37 #include "plist.h"
38 #include "symbol.h"
39 #include "language.h"
40 #include "internal-flt.h"
41 #include "internal-gui.h"
42 #include "font.h"
43 #include "face.h"
44
45 #ifdef HAVE_FREETYPE
46
47 #ifdef HAVE_FTBDF_H
48 #include FT_BDF_H
49 #endif
50
51 static int mdebug_flag = MDEBUG_FONT;
52
53 #ifdef HAVE_FONTCONFIG
54 #include <fontconfig/fcfreetype.h>
55
56 static FcConfig *fc_config;
57 static MSymbol Mgeneric_family;
58 #endif /* HAVE_FONTCONFIG */
59
60 /* Font properties; Mnormal is already defined in face.c. */
61 static MSymbol Mmedium, Mr, Mnull;
62
63 static MSymbol M0[5], M3_1, M1_0;
64
65 static FT_Library ft_library;
66
67 #ifdef HAVE_OTF
68 static OTF *invalid_otf = (OTF *) "";
69 static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
70 #endif /* HAVE_OTF */
71
72 typedef struct
73 {
74 MFont font;
75 #ifdef HAVE_OTF
76 /* NULL if not yet opened. invalid_otf if not OTF. */
77 OTF *otf;
78 #endif /* HAVE_OTF */
79 #ifdef HAVE_FONTCONFIG
80 FcLangSet *langset;
81 FcCharSet *charset;
82 #endif /* HAVE_FONTCONFIG */
83 } MFontFT;
84
85 typedef struct
86 {
87 M17NObject control;
88 FT_Face ft_face; /* This must be the 2nd member. */
89 MPlist *charmap_list;
90 int face_encapsulated;
91 } MRealizedFontFT;
92
93 typedef struct
94 {
95 char *ft_style;
96 int len;
97 enum MFontProperty prop;
98 char *val;
99 } MFTtoProp;
100
101 static MFTtoProp ft_to_prop[] =
102 { { "italic", 0, MFONT_STYLE, "i" },
103 { "roman", 0, MFONT_STYLE, "r" },
104 { "oblique", 0, MFONT_STYLE, "o" },
105 { "regular", 0, MFONT_WEIGHT, "normal" },
106 { "normal", 0, MFONT_WEIGHT, "normal" },
107 /* We need this entry even if "bold" is in commone_weight[] to
108 handle such style names as "bolditalic" and "boldoblique". */
109 { "bold", 0, MFONT_WEIGHT, "bold" },
110 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
111 { "demi", 0, MFONT_WEIGHT, "demibold" } };
112 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
113
114 /** List of FreeType fonts. Keys are family names, values are plists
115 containing fonts of the corresponding family. In the deeper
116 plist, keys are file names, values are (MFontFT *). */
117 static MPlist *ft_font_list;
118
119 /** List of FreeType fonts. Keys are script names, values are plists
120 containing fonts supporting the corresponding script. In the
121 deeper plist, keys are family names, values are (MFontFT *). */
122 static MPlist *ft_script_list;
123
124 /** List of FreeType fonts. Keys are language names, values are
125 plists containing fonts supporting the corresponding language. In
126 the deeper plist, keys are family names, values are (MFontFT *). */
127 static MPlist *ft_language_list;
128
129 static MPlist *ft_file_list;
130
131 static int all_fonts_scaned;
132
133 #define STRDUP_LOWER(s1, size, s2) \
134 do { \
135 int len = strlen (s2) + 1; \
136 char *p1, *p2; \
137 \
138 if ((size) < len) \
139 (s1) = alloca (len), (size) = len; \
140 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
141 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
142 *p1 = '\0'; \
143 } while (0)
144
145
146 static MPlist *ft_list_family (MSymbol, int, int);
147
148 static void
free_ft_rfont(void * object)149 free_ft_rfont (void *object)
150 {
151 MRealizedFontFT *ft_rfont = object;
152
153 if (! ft_rfont->face_encapsulated)
154 {
155 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
156 FT_Done_Face (ft_rfont->ft_face);
157 }
158 free (ft_rfont);
159 }
160
161 static void
free_ft_info(MFontFT * ft_info)162 free_ft_info (MFontFT *ft_info)
163 {
164 #ifdef HAVE_OTF
165 if (ft_info->otf && ft_info->otf != invalid_otf)
166 OTF_close (ft_info->otf);
167 #endif /* HAVE_OTF */
168 #ifdef HAVE_FONTCONFIG
169 if (ft_info->langset)
170 FcLangSetDestroy (ft_info->langset);
171 if (ft_info->charset)
172 FcCharSetDestroy (ft_info->charset);
173 #endif /* HAVE_FONTCONFIG */
174 free (ft_info);
175 }
176
177 static MPlist *
ft_get_charmaps(FT_Face ft_face)178 ft_get_charmaps (FT_Face ft_face)
179 {
180 MPlist *plist = mplist ();
181 int unicode_bmp = -1, unicode_full = -1;
182 int i;
183
184 mplist_add (plist, Mt, (void *) -1);
185 for (i = 0; i < ft_face->num_charmaps; i++)
186 {
187 MSymbol registry = Mnil;
188
189 if (ft_face->charmaps[i]->platform_id == 0)
190 {
191 if (ft_face->charmaps[i]->encoding_id <= 4)
192 registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
193 if (ft_face->charmaps[i]->encoding_id == 4)
194 unicode_bmp = unicode_full = i;
195 }
196 else if (ft_face->charmaps[i]->platform_id == 3)
197 {
198 if (ft_face->charmaps[i]->encoding_id == 1)
199 registry = M3_1, unicode_bmp = i;
200 else if (ft_face->charmaps[i]->encoding_id == 10)
201 unicode_bmp = unicode_full = i;
202 }
203 else if (ft_face->charmaps[i]->platform_id == 1
204 && ft_face->charmaps[i]->encoding_id == 0)
205 {
206 registry = M1_0;
207 mplist_add (plist, Mapple_roman, (void *) i);
208 }
209 if (registry == Mnil)
210 {
211 char registry_buf[16];
212
213 sprintf (registry_buf, "%d-%d",
214 ft_face->charmaps[i]->platform_id,
215 ft_face->charmaps[i]->encoding_id);
216 registry = msymbol (registry_buf);
217 }
218 mplist_add (plist, registry, (void *) i);
219 }
220 if (unicode_full >= 0)
221 mplist_add (plist, Municode_full, (void *) unicode_full);
222 if (unicode_bmp >= 0)
223 {
224 int i;
225
226 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
227 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
228 for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
229 if (i == 0x7F)
230 {
231 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
232 if (i == 0x100)
233 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
234 }
235 }
236
237 return plist;
238 }
239
240 static MFontFT *
ft_gen_font(FT_Face ft_face)241 ft_gen_font (FT_Face ft_face)
242 {
243 MFontFT *ft_info;
244 MFont *font;
245 char *buf;
246 int bufsize = 0;
247 char *stylename;
248 MSymbol family;
249 int size;
250
251 if (FT_IS_SCALABLE (ft_face))
252 size = ft_face->size->metrics.y_ppem;
253 else if (ft_face->num_fixed_sizes == 0)
254 return NULL;
255 else
256 size = ft_face->available_sizes[0].height;
257
258 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
259 font = &ft_info->font;
260 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
261 family = msymbol (buf);
262 mfont__set_property (font, MFONT_FAMILY, family);
263 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
264 mfont__set_property (font, MFONT_STYLE, Mr);
265 mfont__set_property (font, MFONT_STRETCH, Mnormal);
266 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
267 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
268 font->size = size * 10;
269 font->type = MFONT_TYPE_OBJECT;
270 font->source = MFONT_SOURCE_FT;
271 font->file = NULL;
272
273 stylename = ft_face->style_name;
274 while (*stylename)
275 {
276 int i;
277
278 for (i = 0; i < ft_to_prop_size; i++)
279 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
280 ft_to_prop[i].len))
281 {
282 mfont__set_property (font, ft_to_prop[i].prop,
283 msymbol (ft_to_prop[i].val));
284 stylename += ft_to_prop[i].len;
285 break;
286 }
287 if (i == ft_to_prop_size)
288 {
289 char *p1 = stylename + 1;
290 MSymbol sym;
291
292 while (*p1 >= 'a' && *p1 <= 'z') p1++;
293 sym = msymbol__with_len (stylename, p1 - stylename);
294 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
295 if (msymbol_get (sym, mfont__property_table[i].property))
296 {
297 mfont__set_property (font, i, sym);
298 break;
299 }
300 stylename = p1;
301 }
302 while (*stylename && ! isalpha (*stylename))
303 stylename++;
304 }
305 return ft_info;
306 }
307
308 #ifdef HAVE_FONTCONFIG
309
310 typedef struct
311 {
312 int fc_value;
313 char *m17n_value;
314 MSymbol sym;
315 } FC_vs_M17N_font_prop;
316
317 static FC_vs_M17N_font_prop fc_weight_table[] =
318 { { FC_WEIGHT_THIN, "thin" },
319 { FC_WEIGHT_ULTRALIGHT, "extralight" },
320 { FC_WEIGHT_LIGHT, "light" },
321 #ifdef FC_WEIGHT_BOOK
322 { FC_WEIGHT_BOOK, "book" },
323 #endif /* FC_WEIGHT_BOOK */
324 { FC_WEIGHT_REGULAR, "normal" },
325 { FC_WEIGHT_NORMAL, "normal" },
326 { FC_WEIGHT_MEDIUM, "medium" },
327 { FC_WEIGHT_DEMIBOLD, "demibold" },
328 { FC_WEIGHT_BOLD, "bold" },
329 { FC_WEIGHT_EXTRABOLD, "extrabold" },
330 { FC_WEIGHT_BLACK, "black" },
331 { FC_WEIGHT_HEAVY, "heavy" },
332 { FC_WEIGHT_MEDIUM, NULL } };
333 int fc_weight_table_size =
334 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
335
336 static FC_vs_M17N_font_prop fc_slant_table[] =
337 { { FC_SLANT_ROMAN, "r" },
338 { FC_SLANT_ITALIC, "i" },
339 { FC_SLANT_OBLIQUE, "o" },
340 { FC_SLANT_ROMAN, NULL } };
341 int fc_slant_table_size =
342 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
343
344 static FC_vs_M17N_font_prop fc_width_table[] =
345 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
346 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
347 { FC_WIDTH_CONDENSED, "condensed" },
348 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
349 { FC_WIDTH_NORMAL, "normal" },
350 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
351 { FC_WIDTH_EXPANDED, "expanded" },
352 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
353 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
354 { FC_WIDTH_NORMAL, NULL } };
355 int fc_width_table_size =
356 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
357
358
359 static FC_vs_M17N_font_prop *fc_all_table[] =
360 { fc_weight_table, fc_slant_table, fc_width_table };
361
362 static MSymbol
fc_decode_prop(int val,FC_vs_M17N_font_prop * table,int size)363 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
364 {
365 int i = size / 2;
366
367 if (val < table[i].fc_value)
368 {
369 for (i--; i >= 0; i--)
370 if (val > table[i].fc_value)
371 break;
372 i++;
373 }
374 else if (val > table[i].fc_value)
375 {
376 for (i++; i < size; i++)
377 if (val < table[i].fc_value)
378 break;
379 i--;
380 }
381 return table[i].sym;
382 }
383
384 static int
fc_encode_prop(MSymbol sym,FC_vs_M17N_font_prop * table)385 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
386 {
387 int i;
388
389 for (i = 0; table[i].m17n_value; i++)
390 if (table[i].sym == sym)
391 break;
392 return table[i].fc_value;
393 }
394
395 FcPattern *
fc_get_pattern(MFont * font)396 fc_get_pattern (MFont *font)
397 {
398 FcPattern *pat = FcPatternCreate ();
399 MSymbol sym, weight, style, stretch;
400
401
402 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
403 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
404 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
405 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
406 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
407 FcPatternAddInteger (pat, FC_WEIGHT,
408 fc_encode_prop (weight, fc_weight_table));
409 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
410 FcPatternAddInteger (pat, FC_SLANT,
411 fc_encode_prop (style, fc_slant_table));
412 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
413 FcPatternAddInteger (pat, FC_WIDTH,
414 fc_encode_prop (stretch, fc_width_table));
415 if (font->size > 0)
416 {
417 double size = font->size;
418 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
419 }
420 else if (font->size < 0)
421 {
422 double size = - font->size;
423 FcPatternAddDouble (pat, FC_SIZE, size / 10);
424 }
425 return pat;
426 }
427
428 static void
fc_parse_pattern(FcPattern * pat,char * family,MFontFT * ft_info)429 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
430 {
431 FcChar8 *str;
432 int val;
433 double size;
434 char *buf;
435 int bufsize = 0;
436 MSymbol sym;
437 FcLangSet *ls;
438 FcCharSet *cs;
439 MFont *font = &ft_info->font;
440
441 MFONT_INIT (font);
442 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
443 {
444 STRDUP_LOWER (buf, bufsize, (char *) str);
445 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
446 }
447 if (family)
448 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
449 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
450 {
451 STRDUP_LOWER (buf, bufsize, (char *) str);
452 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
453 }
454 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
455 {
456 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
457 mfont__set_property (font, MFONT_WEIGHT, sym);
458 }
459 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
460 {
461 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
462 mfont__set_property (font, MFONT_STYLE, sym);
463 }
464 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
465 {
466 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
467 mfont__set_property (font, MFONT_STRETCH, sym);
468 }
469 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
470 {
471 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
472 || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
473 || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
474 font->for_full_width = 1;
475 ft_info->langset = FcLangSetCopy (ls);
476 }
477 if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
478 ft_info->charset = FcCharSetCopy (cs);
479
480 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
481 font->type = MFONT_TYPE_SPEC;
482 font->source = MFONT_SOURCE_FT;
483 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
484 font->size = size * 10;
485 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
486 font->file = msymbol ((char *) str);
487 }
488
489
490 static MFontFT *
fc_gen_font(FcPattern * pat,char * family)491 fc_gen_font (FcPattern *pat, char *family)
492 {
493 MFontFT *ft_info;
494
495 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
496 fc_parse_pattern (pat, family, ft_info);
497 ft_info->font.type = MFONT_TYPE_OBJECT;
498 return ft_info;
499 }
500
501 static void
fc_init_font_list(void)502 fc_init_font_list (void)
503 {
504 FcPattern *pattern = FcPatternCreate ();
505 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
506 FcFontSet *fs = FcFontList (fc_config, pattern, os);
507 MPlist *plist = mplist ();
508 char *buf;
509 int bufsize = 0;
510 int i;
511
512 ft_font_list = plist;
513 for (i = 0; i < fs->nfont; i++)
514 {
515 char *fam;
516
517 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
518 (FcChar8 **) &fam) != FcResultMatch)
519 continue;
520 STRDUP_LOWER (buf, bufsize, fam);
521 plist = mplist_add (plist, msymbol (buf), NULL);
522 }
523 FcFontSetDestroy (fs);
524 FcObjectSetDestroy (os);
525 FcPatternDestroy (pattern);
526 }
527
528 static MPlist *
fc_list_pattern(FcPattern * pattern)529 fc_list_pattern (FcPattern *pattern)
530 {
531 FcObjectSet *os = NULL;
532 FcFontSet *fs = NULL;
533 MSymbol last_family = Mnil;
534 MPlist *plist = NULL, *pl = NULL;
535 char *buf;
536 int bufsize = 0;
537 int i;
538
539 if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
540 goto err;
541 if (! (fs = FcFontList (fc_config, pattern, os)))
542 goto err;
543
544 for (i = 0; i < fs->nfont; i++)
545 {
546 MSymbol family, file;
547 char *fam, *filename;
548 MFontFT *ft_info;
549
550 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
551 (FcChar8 **) &fam) != FcResultMatch)
552 continue;
553 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
554 (FcChar8 **) &filename) != FcResultMatch)
555 continue;
556 STRDUP_LOWER (buf, bufsize, fam);
557 family = msymbol (buf);
558 file = msymbol (filename);
559 if (family != last_family)
560 {
561 pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
562 last_family = family;
563 }
564 ft_info = mplist_get (pl, file);
565 if (ft_info)
566 {
567 if (! plist)
568 plist = mplist ();
569 mplist_add (plist, family, ft_info);
570 }
571 }
572
573 err:
574 if (fs) FcFontSetDestroy (fs);
575 if (os) FcObjectSetDestroy (os);
576 return plist;
577 }
578
579 /* Return FcCharSet object built from CHAR_LIST or MT. In the latter
580 case, it is assured that the M-text contains at least one
581 character. */
582
583 static FcCharSet *
fc_build_charset(MPlist * char_list,MText * mt)584 fc_build_charset (MPlist *char_list, MText *mt)
585 {
586 FcCharSet *cs = FcCharSetCreate ();
587
588 if (! cs)
589 return NULL;
590 if (char_list)
591 {
592 for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
593 if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
594 {
595 FcCharSetDestroy (cs);
596 return NULL;
597 }
598 }
599 else
600 {
601 int i;
602
603 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
604 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
605 {
606 FcCharSetDestroy (cs);
607 return NULL;
608 }
609 if (mtext_nchars (mt) > 0
610 && (mt = mtext_get_prop (mt, 0, Mtext)))
611 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
612 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
613 {
614 FcCharSetDestroy (cs);
615 return NULL;
616 }
617 }
618 return cs;
619 }
620
621 #else /* not HAVE_FONTCONFIG */
622
623 static MPlist *
ft_add_font(char * filename)624 ft_add_font (char *filename)
625 {
626 FT_Face ft_face;
627 char *stylename;
628 int size = 0;
629 MSymbol family;
630 MFontFT *ft_info;
631 MFont *font;
632 MPlist *plist;
633 int i;
634 char *buf;
635 int bufsize = 0;
636
637 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
638 return NULL;
639 ft_info = ft_gen_font (ft_face);
640 FT_Done_Face (ft_face);
641 if (! ft_info)
642 return NULL;
643
644 font = &ft_info->font;
645 font->file = msymbol (filename);
646
647 plist = mplist_find_by_key (ft_font_list, family);
648 if (plist)
649 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
650 else
651 {
652 plist = mplist ();
653 mplist_add (plist, font->file, ft_info);
654 plist = mplist_push (ft_font_list, family, plist);
655 }
656 return plist;
657 }
658
659 static void
ft_init_font_list(void)660 ft_init_font_list (void)
661 {
662 MPlist *plist;
663 struct stat buf;
664 char *pathname;
665 char *path;
666 USE_SAFE_ALLOCA;
667
668 ft_font_list = mplist ();
669 MPLIST_DO (plist, mfont_freetype_path)
670 if (MPLIST_STRING_P (plist)
671 && (pathname = MPLIST_STRING (plist))
672 && stat (pathname, &buf) == 0)
673 {
674 if (S_ISREG (buf.st_mode))
675 ft_add_font (pathname);
676 else if (S_ISDIR (buf.st_mode))
677 {
678 DIR *dir = opendir (pathname);
679
680 if (dir)
681 {
682 int len = strlen (pathname);
683 struct dirent *dp;
684
685 while ((dp = readdir (dir)) != NULL)
686 {
687 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
688 strcpy (path, pathname);
689 path[len] = '/';
690 strcpy (path + len + 1, dp->d_name);
691 ft_add_font (path);
692 }
693 closedir (dir);
694 }
695 }
696 }
697 SAFE_FREE (path);
698 }
699
700 /* Return 1 iff the font pointed by FT_INFO has all characters in
701 CHAR_LIST. */
702
703 static int
ft_has_char_list_p(MFontFT * ft_info,MPlist * char_list)704 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
705 {
706 FT_Face ft_face;
707 MPlist *cl;
708
709 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
710 return 0;
711 MPLIST_DO (cl, char_list)
712 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
713 break;
714 FT_Done_Face (ft_face);
715 return MPLIST_TAIL_P (cl);
716 }
717
718 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
719 that supports characters in CHAR_LIST or MT. One of CHAR_LIST or
720 MT must be NULL. */
721
722 static MPlist *
ft_list_char_list(MPlist * char_list,MText * mt)723 ft_list_char_list (MPlist *char_list, MText *mt)
724 {
725 MPlist *plist = NULL, *pl, *p;
726
727 if (! ft_font_list)
728 ft_list_family (Mnil, 0, 1);
729
730 if (mt)
731 {
732 int len = mtext_nchars (mt);
733 MText *extra = mtext_get_prop (mt, 0, Mtext);
734 int total_len = len + (extra ? mtext_nchars (extra) : 0);
735 int i;
736
737 char_list = mplist ();
738 for (i = 0; i < total_len; i++)
739 {
740 int c = (i < len ? mtext_ref_char (mt, i)
741 : mtext_ref_char (extra, i - len));
742
743 if (! mplist_find_by_value (char_list, (void *) c))
744 mplist_push (char_list, Minteger, (void *) c);
745 }
746 }
747
748 MPLIST_DO (pl, ft_font_list)
749 {
750 MPLIST_DO (p, MPLIST_PLIST (pl))
751 {
752 MFontFT *ft_info = MPLIST_VAL (p);
753
754 if (ft_has_char_list_p (ft_info, char_list))
755 {
756 MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
757
758 if (! plist)
759 plist = mplist ();
760 mplist_push (plist, family, ft_info);
761 }
762 }
763 }
764 if (mt)
765 M17N_OBJECT_UNREF (char_list);
766 return plist;
767 }
768 #endif /* not HAVE_FONTCONFIG */
769
770
771 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
772 scan all fonts and return ft_font_list. */
773
774 static MPlist *
ft_list_family(MSymbol family,int check_generic,int check_alias)775 ft_list_family (MSymbol family, int check_generic, int check_alias)
776 {
777 MPlist *plist;
778 #ifdef HAVE_FONTCONFIG
779 char *fam;
780 MPlist *pl, *p;
781 FcPattern *pattern;
782 FcObjectSet *os;
783 FcFontSet *fs;
784 int i;
785 char *buf;
786 int bufsize = 0;
787 MSymbol generic;
788
789 if (! ft_font_list)
790 {
791 MSymbol sym;
792
793 plist = ft_font_list = mplist ();
794 pattern = FcPatternCreate ();
795 os = FcObjectSetBuild (FC_FAMILY, NULL);
796 fs = FcFontList (fc_config, pattern, os);
797 for (i = 0; i < fs->nfont; i++)
798 {
799 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
800 (FcChar8 **) &fam) != FcResultMatch)
801 continue;
802 STRDUP_LOWER (buf, bufsize, fam);
803 sym = msymbol (buf);
804 if (! mplist_find_by_key (ft_font_list, sym))
805 plist = mplist_add (plist, sym, NULL);
806 }
807 FcFontSetDestroy (fs);
808 FcObjectSetDestroy (os);
809 FcPatternDestroy (pattern);
810 }
811
812 if (family == Mnil)
813 {
814 if (! all_fonts_scaned)
815 {
816 MPLIST_DO (plist, ft_font_list)
817 {
818 if (! MPLIST_VAL (plist))
819 ft_list_family (MPLIST_KEY (plist), 0, 1);
820 }
821 all_fonts_scaned = 1;
822 }
823 return ft_font_list;
824 }
825
826 plist = mplist_find_by_key (ft_font_list, family);
827 if (plist)
828 {
829 if (! MPLIST_VAL (plist))
830 {
831 fam = MSYMBOL_NAME (family);
832 pattern = FcPatternCreate ();
833 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
834 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
835 FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
836 NULL);
837 fs = FcFontList (fc_config, pattern, os);
838 p = pl = mplist ();
839 for (i = 0; i < fs->nfont; i++)
840 {
841 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
842 p = mplist_add (p, ft_info->font.file, ft_info);
843 }
844 MPLIST_VAL (plist) = pl;
845 FcFontSetDestroy (fs);
846 FcObjectSetDestroy (os);
847 FcPatternDestroy (pattern);
848 }
849 }
850 else if (check_generic
851 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
852 {
853 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
854 FcChar8 *fam8;
855
856 if (family != generic)
857 plist = ft_list_family (generic, 1, 1);
858 else
859 {
860 fam = MSYMBOL_NAME (family);
861 plist = mplist ();
862 mplist_push (ft_font_list, family, plist);
863 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
864 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
865 for (i = 0; 1; i++)
866 {
867 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
868 != FcResultMatch)
869 break;
870 STRDUP_LOWER (buf, bufsize, (char *) fam8);
871 family = msymbol (buf);
872 if (msymbol_get (family, Mgeneric_family))
873 break;
874 pl = ft_list_family (family, 0, 1);
875 if (! pl)
876 continue;
877 MPLIST_DO (pl, MPLIST_PLIST (pl))
878 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
879 }
880 plist = ft_font_list;
881 }
882 }
883 else if (check_alias)
884 {
885 /* Check if there exist an alias. */
886 pl = mplist ();
887 plist = mplist_add (ft_font_list, family, pl);
888
889 pattern = FcPatternBuild (NULL,
890 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
891 NULL);
892 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
893
894 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
895 (FcChar8 **) &fam) == FcResultMatch;
896 i++);
897 if (i > 0)
898 {
899 /* The last one is a generic family. */
900 MSymbol sym;
901 int j;
902 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
903 NULL);
904
905 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
906 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
907 (FcChar8 **) &fam) == FcResultMatch;
908 j++);
909
910 /* Now we know that the last J fonts in PATTERN are from
911 generic font, and the first one is not available. So,
912 the remaining ones are aliases. */
913 j = i - j;
914 for (i = 1; i < j; i++)
915 {
916 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
917 STRDUP_LOWER (buf, bufsize, fam);
918 sym = msymbol (buf);
919 p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
920 if (! MPLIST_TAIL_P (p))
921 MPLIST_DO (p, p)
922 mplist_push (pl, Mt, MPLIST_VAL (p));
923 }
924 }
925 }
926 else
927 {
928 pl = mplist ();
929 plist = mplist_add (ft_font_list, family, pl);
930 }
931
932 #else /* not HAVE_FONTCONFIG */
933
934 if (! all_fonts_scaned)
935 {
936 ft_init_font_list ();
937 all_fonts_scaned = 1;
938 }
939 if (family == Mnil)
940 plist = ft_font_list;
941 else
942 {
943 plist = mplist_find_by_key (ft_font_list, family);
944 if (! plist)
945 plist = mplist_push (ft_font_list, family, mplist ());
946 }
947 #endif /* not HAVE_FONTCONFIG */
948
949 return plist;
950 }
951
952 static MPlist *
ft_list_language(MSymbol language)953 ft_list_language (MSymbol language)
954 {
955 MPlist *plist = NULL;
956 MText *mt;
957
958 if (! ft_language_list)
959 ft_language_list = mplist ();
960 else if ((plist = mplist_find_by_key (ft_language_list, language)))
961 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
962
963 mt = mlanguage_text (language);
964
965 #ifdef HAVE_FONTCONFIG
966 {
967 FcPattern *pattern = NULL;
968 FcCharSet *cs = NULL;
969 FcLangSet *ls = NULL;
970
971 if (! (pattern = FcPatternCreate ()))
972 goto err;
973
974 if (mt && mtext_nchars (mt) > 0)
975 {
976 cs = fc_build_charset (NULL, mt);
977 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
978 goto err;
979 }
980 else
981 {
982 if (! (ls = FcLangSetCreate ()))
983 goto err;
984 if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
985 || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
986 goto err;
987 }
988
989 plist = fc_list_pattern (pattern);
990 err:
991 if (cs) FcCharSetDestroy (cs);
992 if (ls) FcLangSetDestroy (ls);
993 if (pattern) FcPatternDestroy (pattern);
994 }
995 #else /* not HAVE_FONTCONFIG */
996 if (mt && mtext_nchars (mt) > 0)
997 plist = ft_list_char_list (NULL, mt);
998 #endif /* not HAVE_FONTCONFIG */
999
1000 mplist_push (ft_language_list, language, plist);
1001 return plist;
1002 }
1003
1004 static MPlist *
ft_list_script(MSymbol script)1005 ft_list_script (MSymbol script)
1006 {
1007 MPlist *plist = NULL;
1008 MPlist *char_list;
1009
1010 if (! ft_script_list)
1011 ft_script_list = mplist ();
1012 else if ((plist = mplist_find_by_key (ft_script_list, script)))
1013 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1014
1015 char_list = mscript__char_list (script);
1016
1017 #ifdef HAVE_FONTCONFIG
1018 if (char_list)
1019 {
1020 FcPattern *pattern = NULL;
1021 FcCharSet *cs;
1022
1023 if (! (pattern = FcPatternCreate ()))
1024 goto err;
1025 cs = fc_build_charset (char_list, NULL);
1026 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1027 goto err;
1028 plist = fc_list_pattern (pattern);
1029 err:
1030 if (cs) FcCharSetDestroy (cs);
1031 if (pattern) FcPatternDestroy (pattern);
1032 }
1033 #else /* not HAVE_FONTCONFIG */
1034 if (char_list)
1035 plist = ft_list_char_list (char_list, NULL);
1036 #endif /* not HAVE_FONTCONFIG */
1037
1038 mplist_push (ft_script_list, script, plist);
1039 return (plist);
1040 }
1041
1042 static int
ft_check_cap_otf(MFontFT * ft_info,MFontCapability * cap,FT_Face ft_face)1043 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1044 {
1045 #ifdef HAVE_OTF
1046 if (ft_info->otf == invalid_otf)
1047 return -1;
1048 if (! ft_info->otf)
1049 {
1050 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1051 if (ft_face)
1052 ft_info->otf = OTF_open_ft_face (ft_face);
1053 else
1054 #endif
1055 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1056 if (! ft_info->otf)
1057 {
1058 ft_info->otf = invalid_otf;
1059 return -1;
1060 }
1061 }
1062 if (cap->features[MFONT_OTT_GSUB].nfeatures
1063 && (OTF_check_features
1064 (ft_info->otf, 1,
1065 cap->script_tag, cap->langsys_tag,
1066 cap->features[MFONT_OTT_GSUB].tags,
1067 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1068 return -1;
1069 if (cap->features[MFONT_OTT_GPOS].nfeatures
1070 && (OTF_check_features
1071 (ft_info->otf, 0,
1072 cap->script_tag, cap->langsys_tag,
1073 cap->features[MFONT_OTT_GPOS].tags,
1074 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1075 return -1;
1076 return 0;
1077 #else /* not HAVE_OTF */
1078 return -1;
1079 #endif /* not HAVE_OTF */
1080 }
1081
1082 static int
ft_check_language(MFontFT * ft_info,MSymbol language,FT_Face ft_face)1083 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1084 {
1085 MText *mt;
1086 MText *extra;
1087 int ft_face_allocaed = 0;
1088 int len, total_len;
1089 int i;
1090
1091 #ifdef HAVE_FONTCONFIG
1092 if (ft_info->langset
1093 && (FcLangSetHasLang (ft_info->langset,
1094 (FcChar8 *) MSYMBOL_NAME (language))
1095 != FcLangDifferentLang))
1096 return 0;
1097 #endif /* HAVE_FONTCONFIG */
1098
1099 mt = mlanguage_text (language);
1100 if (! mt || mtext_nchars (mt) == 0)
1101 return -1;
1102
1103 if (! ft_face)
1104 {
1105 char *filename = MSYMBOL_NAME (ft_info->font.file);
1106
1107 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1108 return -1;
1109 ft_face_allocaed = 1;
1110 }
1111
1112 len = mtext_nchars (mt);
1113 extra = mtext_get_prop (mt, 0, Mtext);
1114 total_len = len + (extra ? mtext_nchars (extra) : 0);
1115
1116 for (i = 0; i < total_len; i++)
1117 {
1118 int c = (i < len ? mtext_ref_char (mt, i)
1119 : mtext_ref_char (extra, i - len));
1120
1121 #ifdef HAVE_FONTCONFIG
1122 if (ft_info->charset
1123 && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1124 break;
1125 #endif /* HAVE_FONTCONFIG */
1126 if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1127 break;
1128 }
1129
1130 if (ft_face_allocaed)
1131 FT_Done_Face (ft_face);
1132
1133 return (i == total_len ? 0 : -1);
1134 }
1135
1136 static int
ft_check_script(MFontFT * ft_info,MSymbol script,FT_Face ft_face)1137 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1138 {
1139 MPlist *char_list = mscript__char_list (script);
1140
1141 if (! char_list)
1142 return -1;
1143 #ifdef HAVE_FONTCONFIG
1144 if (ft_info->charset)
1145 {
1146 MPLIST_DO (char_list, char_list)
1147 if (FcCharSetHasChar (ft_info->charset,
1148 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1149 break;
1150 }
1151 else
1152 #endif /* HAVE_FONTCONFIG */
1153 {
1154 int ft_face_allocaed = 0;
1155
1156 if (! ft_face)
1157 {
1158 char *filename = MSYMBOL_NAME (ft_info->font.file);
1159
1160 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1161 return -1;
1162 ft_face_allocaed = 1;
1163 }
1164
1165 MPLIST_DO (char_list, char_list)
1166 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1167 == 0)
1168 break;
1169 if (ft_face_allocaed)
1170 FT_Done_Face (ft_face);
1171 }
1172
1173 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1174 }
1175
1176 static MPlist *ft_default_list;
1177
1178 static MPlist *
ft_list_default()1179 ft_list_default ()
1180 {
1181 if (ft_default_list)
1182 return ft_default_list;
1183 ft_default_list = mplist ();
1184 #ifdef HAVE_FONTCONFIG
1185 {
1186 FcPattern *pat = FcPatternCreate ();
1187 FcChar8 *fam;
1188 char *buf;
1189 int bufsize = 0;
1190 int i;
1191
1192 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1193 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1194 i++)
1195 {
1196 MSymbol family;
1197 MPlist *plist;
1198
1199 STRDUP_LOWER (buf, bufsize, (char *) fam);
1200 family = msymbol (buf);
1201 if (msymbol_get (family, Mgeneric_family))
1202 continue;
1203 plist = MPLIST_PLIST (ft_list_family (family, 0, 1));
1204 MPLIST_DO (plist, plist)
1205 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1206 }
1207 }
1208 #else /* not HAVE_FONTCONFIG */
1209 {
1210 MPlist *plist, *pl;
1211
1212 MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
1213 {
1214 pl = MPLIST_PLIST (plist);
1215 if (! MPLIST_TAIL_P (pl))
1216 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1217 }
1218 }
1219 #endif /* not HAVE_FONTCONFIG */
1220 return ft_default_list;
1221 }
1222
1223
1224 static MPlist *ft_capability_list;
1225
1226 static MPlist *
ft_list_capability(MSymbol capability)1227 ft_list_capability (MSymbol capability)
1228 {
1229 MFontCapability *cap;
1230 MPlist *plist = NULL, *pl;
1231
1232 if (! ft_capability_list)
1233 ft_capability_list = mplist ();
1234 else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1235 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1236
1237 cap = mfont__get_capability (capability);
1238
1239 if (cap && cap->language != Mnil)
1240 {
1241 plist = ft_list_language (cap->language);
1242 if (! plist)
1243 return NULL;
1244 plist = mplist_copy (plist);
1245 }
1246
1247 if (cap && cap->script != Mnil)
1248 {
1249 if (! plist)
1250 {
1251 plist = ft_list_script (cap->script);
1252 if (! plist)
1253 return NULL;
1254 plist = mplist_copy (plist);
1255 }
1256 else
1257 {
1258 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1259 {
1260 if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1261 mplist_pop (pl);
1262 else
1263 pl = MPLIST_NEXT (pl);
1264 }
1265 }
1266
1267 if (cap->script_tag)
1268 {
1269 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1270 {
1271 if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1272 mplist_pop (pl);
1273 else
1274 pl = MPLIST_NEXT (pl);
1275 }
1276 }
1277
1278 if (MPLIST_TAIL_P (plist))
1279 {
1280 M17N_OBJECT_UNREF (plist);
1281 plist = NULL;
1282 }
1283 }
1284
1285 mplist_push (ft_capability_list, capability, plist);
1286 return plist;
1287 }
1288
1289
1290 static MPlist *
ft_list_file(MSymbol filename)1291 ft_list_file (MSymbol filename)
1292 {
1293 MPlist *plist = NULL;
1294
1295 if (! ft_file_list)
1296 ft_file_list = mplist ();
1297 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1298 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1299
1300 #ifdef HAVE_FONTCONFIG
1301 {
1302 FcPattern *pattern = FcPatternCreate ();
1303 FcObjectSet *os;
1304 FcFontSet *fs;
1305
1306 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1307 os = FcObjectSetBuild (FC_FAMILY, NULL);
1308 fs = FcFontList (fc_config, pattern, os);
1309 if (fs->nfont > 0)
1310 {
1311 char *fam;
1312 char *buf;
1313 int bufsize = 0;
1314
1315 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1316 (FcChar8 **) &fam) == FcResultMatch)
1317 {
1318 MSymbol family;
1319 MPlist *pl;
1320
1321 STRDUP_LOWER (buf, bufsize, fam);
1322 family = msymbol (buf);
1323 pl = ft_list_family (family, 0, 1);
1324 MPLIST_DO (pl, MPLIST_PLIST (pl))
1325 {
1326 MFontFT *ft_info = MPLIST_VAL (pl);
1327
1328 if (ft_info->font.file == filename)
1329 {
1330 plist = mplist ();
1331 mplist_add (plist, family, ft_info);
1332 break;
1333 }
1334 }
1335 }
1336 }
1337 }
1338 #else /* not HAVE_FONTCONFIG */
1339 {
1340 MPlist *pl, *p;
1341
1342 MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
1343 {
1344 MPLIST_DO (p, MPLIST_PLIST (pl))
1345 {
1346 MFontFT *ft_info = MPLIST_VAL (pl);
1347
1348 if (ft_info->font.file == filename)
1349 {
1350 plist = mplist ();
1351 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1352 break;
1353 }
1354 }
1355 if (plist)
1356 break;
1357 }
1358 }
1359 #endif /* not HAVE_FONTCONFIG */
1360
1361 mplist_push (ft_file_list, filename, plist);
1362 return plist;
1363 }
1364
1365 /* The FreeType font driver function SELECT. */
1366
1367 static MFont *
ft_select(MFrame * frame,MFont * font,int limited_size)1368 ft_select (MFrame *frame, MFont *font, int limited_size)
1369 {
1370 MFont *found = NULL;
1371 #ifdef HAVE_FONTCONFIG
1372 MPlist *plist, *pl;
1373 MFontFT *ft_info;
1374 int check_font_property = 1;
1375
1376 if (font->file != Mnil)
1377 {
1378 plist = ft_list_file (font->file);
1379 if (! plist)
1380 return NULL;
1381 check_font_property = 0;
1382 }
1383 else
1384 {
1385 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1386
1387 if (family)
1388 plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
1389 else
1390 plist = ft_list_default ();
1391 if (MPLIST_TAIL_P (plist))
1392 return NULL;
1393 }
1394
1395 plist = mplist_copy (plist);
1396
1397 if (font->capability != Mnil)
1398 {
1399 MFontCapability *cap = mfont__get_capability (font->capability);
1400
1401 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1402 {
1403 if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1404 {
1405 mplist_pop (pl);
1406 continue;
1407 }
1408 if (cap->language
1409 && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1410 mplist_pop (pl);
1411 else
1412 pl = MPLIST_NEXT (pl);
1413 }
1414 }
1415
1416 if (check_font_property)
1417 {
1418 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1419 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1420 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1421 MSymbol alternate_weight = Mnil;
1422
1423 if (weight == Mnormal)
1424 alternate_weight = Mmedium;
1425 else if (weight == Mmedium)
1426 alternate_weight = Mnormal;
1427 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1428 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1429 {
1430 ft_info = MPLIST_VAL (pl);
1431 if ((weight != Mnil
1432 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1433 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1434 || (style != Mnil
1435 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1436 || (stretch != Mnil
1437 && stretch != FONT_PROPERTY (&ft_info->font,
1438 MFONT_STRETCH))
1439 || (font->size > 0
1440 && ft_info->font.size > 0
1441 && ft_info->font.size != font->size))
1442 mplist_pop (pl);
1443 else
1444 pl = MPLIST_NEXT (pl);
1445 }
1446 }
1447
1448 MPLIST_DO (pl, plist)
1449 {
1450 font = MPLIST_VAL (plist);
1451 if (limited_size == 0
1452 || font->size == 0
1453 || font->size <= limited_size)
1454 {
1455 found = font;
1456 break;
1457 }
1458 }
1459 M17N_OBJECT_UNREF (plist);
1460 #endif /* HAVE_FONTCONFIG */
1461 return found;
1462 }
1463
1464
1465 static MRealizedFont *
ft_open(MFrame * frame,MFont * font,MFont * spec,MRealizedFont * rfont)1466 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1467 {
1468 MFontFT *ft_info = (MFontFT *) font;
1469 int reg = spec->property[MFONT_REGISTRY];
1470 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1471 MRealizedFontFT *ft_rfont;
1472 FT_Face ft_face;
1473 MPlist *plist, *charmap_list = NULL;
1474 int charmap_index;
1475 int size;
1476
1477 if (font->size)
1478 /* non-scalable font */
1479 size = font->size;
1480 else if (spec->size)
1481 {
1482 int ratio = mfont_resize_ratio (font);
1483
1484 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1485 }
1486 else
1487 size = 120;
1488
1489 if (rfont)
1490 {
1491 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1492 for (; rfont; rfont = rfont->next)
1493 if (rfont->font == font
1494 && (rfont->font->size ? rfont->font->size == size
1495 : rfont->spec.size == size)
1496 && rfont->spec.property[MFONT_REGISTRY] == reg
1497 && rfont->driver == &mfont__ft_driver)
1498 return rfont;
1499 }
1500
1501 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1502
1503 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1504 &ft_face))
1505 {
1506 font->type = MFONT_TYPE_FAILURE;
1507 MDEBUG_PRINT (" no (FT_New_Face)\n");
1508 return NULL;
1509 }
1510 if (charmap_list)
1511 M17N_OBJECT_REF (charmap_list);
1512 else
1513 charmap_list = ft_get_charmaps (ft_face);
1514 if (registry == Mnil)
1515 registry = Municode_bmp;
1516 plist = mplist_find_by_key (charmap_list, registry);
1517 if (! plist)
1518 {
1519 FT_Done_Face (ft_face);
1520 M17N_OBJECT_UNREF (charmap_list);
1521 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1522 return NULL;
1523 }
1524 charmap_index = (int) MPLIST_VAL (plist);
1525 if ((charmap_index >= 0
1526 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1527 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1528 {
1529 FT_Done_Face (ft_face);
1530 M17N_OBJECT_UNREF (charmap_list);
1531 font->type = MFONT_TYPE_FAILURE;
1532 MDEBUG_PRINT1 (" no (size %d)\n", size);
1533 return NULL;
1534 }
1535
1536 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1537 ft_rfont->ft_face = ft_face;
1538 ft_rfont->charmap_list = charmap_list;
1539 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1540 rfont->id = ft_info->font.file;
1541 rfont->spec = *font;
1542 rfont->spec.type = MFONT_TYPE_REALIZED;
1543 rfont->spec.property[MFONT_REGISTRY] = reg;
1544 rfont->spec.size = size;
1545 rfont->frame = frame;
1546 rfont->font = font;
1547 rfont->driver = &mfont__ft_driver;
1548 rfont->info = ft_rfont;
1549 rfont->fontp = ft_face;
1550 rfont->ascent = ft_face->size->metrics.ascender;
1551 rfont->descent = - ft_face->size->metrics.descender;
1552 rfont->max_advance = ft_face->size->metrics.max_advance;
1553 rfont->baseline_offset = 0;
1554 rfont->x_ppem = ft_face->size->metrics.x_ppem;
1555 rfont->y_ppem = ft_face->size->metrics.y_ppem;
1556 #ifdef HAVE_FTBDF_H
1557 {
1558 BDF_PropertyRec prop;
1559
1560 if (! FT_IS_SCALABLE (ft_face)
1561 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1562 {
1563 rfont->baseline_offset = prop.u.integer << 6;
1564 rfont->ascent += prop.u.integer << 6;
1565 rfont->descent -= prop.u.integer << 6;
1566 }
1567 }
1568 #endif /* HAVE_FTBDF_H */
1569 if (FT_IS_SCALABLE (ft_face))
1570 rfont->average_width = 0;
1571 else
1572 rfont->average_width = ft_face->available_sizes->width << 6;
1573 rfont->next = MPLIST_VAL (frame->realized_font_list);
1574 MPLIST_VAL (frame->realized_font_list) = rfont;
1575 MDEBUG_PRINT (" ok\n");
1576 return rfont;
1577 }
1578
1579 /* The FreeType font driver function FIND_METRIC. */
1580
1581 static void
ft_find_metric(MRealizedFont * rfont,MGlyphString * gstring,int from,int to)1582 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1583 int from, int to)
1584 {
1585 FT_Face ft_face = rfont->fontp;
1586 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1587
1588 for (; g != gend; g++)
1589 {
1590 if (g->g.measured)
1591 continue;
1592 if (g->g.code == MCHAR_INVALID_CODE)
1593 {
1594 if (FT_IS_SCALABLE (ft_face))
1595 {
1596 g->g.lbearing = 0;
1597 g->g.rbearing = ft_face->size->metrics.max_advance;
1598 g->g.xadv = g->g.rbearing;
1599 g->g.ascent = ft_face->size->metrics.ascender;
1600 g->g.descent = - ft_face->size->metrics.descender;
1601 }
1602 else
1603 {
1604 #ifdef HAVE_FTBDF_H
1605 BDF_PropertyRec prop;
1606 #endif /* HAVE_FTBDF_H */
1607
1608 g->g.lbearing = 0;
1609 g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1610 #ifdef HAVE_FTBDF_H
1611 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1612 {
1613 g->g.ascent = prop.u.integer << 6;
1614 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1615 g->g.descent = prop.u.integer << 6;
1616 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1617 & prop) == 0)
1618 {
1619 g->g.ascent += prop.u.integer << 6;
1620 g->g.descent -= prop.u.integer << 6;
1621 }
1622 }
1623 else
1624 #endif /* HAVE_FTBDF_H */
1625 {
1626 g->g.ascent = ft_face->available_sizes->height << 6;
1627 g->g.descent = 0;
1628 }
1629 }
1630 }
1631 else
1632 {
1633 FT_Glyph_Metrics *metrics;
1634
1635 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
1636 metrics = &ft_face->glyph->metrics;
1637 g->g.lbearing = metrics->horiBearingX;
1638 g->g.rbearing = metrics->horiBearingX + metrics->width;
1639 g->g.xadv = metrics->horiAdvance;
1640 g->g.ascent = metrics->horiBearingY;
1641 g->g.descent = metrics->height - metrics->horiBearingY;
1642 }
1643 g->g.yadv = 0;
1644 g->g.ascent += rfont->baseline_offset;
1645 g->g.descent -= rfont->baseline_offset;
1646 g->g.measured = 1;
1647 }
1648 }
1649
1650 static int
ft_has_char(MFrame * frame,MFont * font,MFont * spec,int c,unsigned code)1651 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1652 {
1653 MRealizedFont *rfont = NULL;
1654 MRealizedFontFT *ft_rfont;
1655 FT_UInt idx;
1656
1657 if (font->type == MFONT_TYPE_REALIZED)
1658 rfont = (MRealizedFont *) font;
1659 else if (font->type == MFONT_TYPE_OBJECT)
1660 {
1661 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1662 rfont = rfont->next)
1663 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1664 break;
1665 if (! rfont)
1666 {
1667 #ifdef HAVE_FONTCONFIG
1668 MFontFT *ft_info = (MFontFT *) font;
1669
1670 if (! ft_info->charset)
1671 {
1672 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1673 MSYMBOL_NAME (font->file),
1674 NULL);
1675 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1676 FcFontSet *fs = FcFontList (fc_config, pat, os);
1677
1678 if (fs->nfont > 0
1679 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1680 &ft_info->charset) == FcResultMatch)
1681 ft_info->charset = FcCharSetCopy (ft_info->charset);
1682 else
1683 ft_info->charset = FcCharSetCreate ();
1684 FcFontSetDestroy (fs);
1685 FcObjectSetDestroy (os);
1686 FcPatternDestroy (pat);
1687 }
1688 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1689 #else /* not HAVE_FONTCONFIG */
1690 rfont = ft_open (frame, font, spec, NULL);
1691 #endif /* not HAVE_FONTCONFIG */
1692 }
1693 }
1694 else
1695 MFATAL (MERROR_FONT_FT);
1696
1697 if (! rfont)
1698 return 0;
1699 ft_rfont = rfont->info;
1700 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1701 return (idx != 0);
1702 }
1703
1704 /* The FreeType font driver function ENCODE_CHAR. */
1705
1706 static unsigned
ft_encode_char(MFrame * frame,MFont * font,MFont * spec,unsigned code)1707 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1708 {
1709 MRealizedFont *rfont;
1710 MRealizedFontFT *ft_rfont;
1711 FT_UInt idx;
1712
1713 if (font->type == MFONT_TYPE_REALIZED)
1714 rfont = (MRealizedFont *) font;
1715 else if (font->type == MFONT_TYPE_OBJECT)
1716 {
1717 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1718 rfont = rfont->next)
1719 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1720 break;
1721 if (! rfont)
1722 {
1723 rfont = ft_open (frame, font, spec, NULL);
1724 if (! rfont)
1725 return -1;
1726 }
1727 }
1728 else
1729 MFATAL (MERROR_FONT_FT);
1730
1731 ft_rfont = rfont->info;
1732 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1733 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1734 }
1735
1736 /* The FreeType font driver function RENDER. */
1737
1738 #define NUM_POINTS 0x1000
1739
1740 typedef struct {
1741 MDrawPoint points[NUM_POINTS];
1742 MDrawPoint *p;
1743 } MPointTable;
1744
1745 static void
ft_render(MDrawWindow win,int x,int y,MGlyphString * gstring,MGlyph * from,MGlyph * to,int reverse,MDrawRegion region)1746 ft_render (MDrawWindow win, int x, int y,
1747 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1748 int reverse, MDrawRegion region)
1749 {
1750 FT_Face ft_face;
1751 MRealizedFace *rface = from->rface;
1752 MFrame *frame = rface->frame;
1753 FT_Int32 load_flags = FT_LOAD_RENDER;
1754 MGlyph *g;
1755 int i, j;
1756 MPointTable point_table[8];
1757 int baseline_offset;
1758 int pixel_mode = -1;
1759
1760 if (from == to)
1761 return;
1762
1763 /* It is assured that the all glyphs in the current range use the
1764 same realized face. */
1765 ft_face = rface->rfont->fontp;
1766 baseline_offset = rface->rfont->baseline_offset >> 6;
1767
1768 if (! gstring->anti_alias)
1769 {
1770 #ifdef FT_LOAD_TARGET_MONO
1771 load_flags |= FT_LOAD_TARGET_MONO;
1772 #else
1773 load_flags |= FT_LOAD_MONOCHROME;
1774 #endif
1775 }
1776
1777 for (i = 0; i < 8; i++)
1778 point_table[i].p = point_table[i].points;
1779
1780 for (g = from; g < to; x += g++->g.xadv)
1781 {
1782 unsigned char *bmp;
1783 int intensity;
1784 MPointTable *ptable;
1785 int xoff, yoff;
1786 int width, pitch;
1787
1788 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
1789 if (pixel_mode < 0)
1790 pixel_mode = ft_face->glyph->bitmap.pixel_mode;
1791 yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
1792 bmp = ft_face->glyph->bitmap.buffer;
1793 width = ft_face->glyph->bitmap.width;
1794 pitch = ft_face->glyph->bitmap.pitch;
1795
1796 if (pixel_mode != FT_PIXEL_MODE_MONO)
1797 for (i = 0; i < ft_face->glyph->bitmap.rows;
1798 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1799 {
1800 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1801 for (j = 0; j < width; j++, xoff++)
1802 {
1803 intensity = bmp[j] >> 5;
1804 if (intensity)
1805 {
1806 ptable = point_table + intensity;
1807 ptable->p->x = xoff;
1808 ptable->p->y = yoff - baseline_offset;
1809 ptable->p++;
1810 if (ptable->p - ptable->points == NUM_POINTS)
1811 {
1812 (*frame->driver->draw_points)
1813 (frame, win, rface,
1814 reverse ? 7 - intensity : intensity,
1815 ptable->points, NUM_POINTS, region);
1816 ptable->p = ptable->points;
1817 }
1818 }
1819 }
1820 }
1821 else
1822 for (i = 0; i < ft_face->glyph->bitmap.rows;
1823 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1824 {
1825 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1826 for (j = 0; j < width; j++, xoff++)
1827 {
1828 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1829 if (intensity)
1830 {
1831 ptable = point_table;
1832 ptable->p->x = xoff;
1833 ptable->p->y = yoff - baseline_offset;
1834 ptable->p++;
1835 if (ptable->p - ptable->points == NUM_POINTS)
1836 {
1837 (*frame->driver->draw_points) (frame, win, rface,
1838 reverse ? 0 : 7,
1839 ptable->points, NUM_POINTS, region);
1840 ptable->p = ptable->points;
1841 }
1842 }
1843 }
1844 }
1845 }
1846
1847 if (pixel_mode != FT_PIXEL_MODE_MONO)
1848 {
1849 for (i = 1; i < 8; i++)
1850 if (point_table[i].p != point_table[i].points)
1851 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1852 point_table[i].points,
1853 point_table[i].p - point_table[i].points, region);
1854 }
1855 else
1856 {
1857 if (point_table[0].p != point_table[0].points)
1858 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1859 point_table[0].points,
1860 point_table[0].p - point_table[0].points, region);
1861 }
1862 }
1863
1864 static int
ft_list(MFrame * frame,MPlist * plist,MFont * font,int maxnum)1865 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1866 {
1867 MPlist *pl = NULL, *p;
1868 int num = 0;
1869 MPlist *file_list = NULL;
1870 MPlist *family_list = NULL, *capability_list = NULL;
1871 MSymbol registry = Mnil;
1872
1873 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1874
1875 if (font)
1876 {
1877 MSymbol family;
1878
1879 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1880 if (registry != Mnil && registry != Miso8859_1)
1881 {
1882 char *reg = MSYMBOL_NAME (registry);
1883
1884 if (strncmp (reg, "unicode-", 8)
1885 && strncmp (reg, "apple-roman", 11)
1886 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1887 goto done;
1888 }
1889
1890 if (font->file != Mnil
1891 && ! (file_list = ft_list_file (font->file)))
1892 goto done;
1893 family = FONT_PROPERTY (font, MFONT_FAMILY);
1894 if (family != Mnil
1895 && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
1896 && MPLIST_TAIL_P (family_list))
1897 goto done;
1898 if (font->capability != Mnil)
1899 {
1900 capability_list = ft_list_capability (font->capability);
1901 if (! capability_list || MPLIST_TAIL_P (capability_list))
1902 goto done;
1903 }
1904 }
1905
1906 if (! file_list && ! family_list && ! capability_list)
1907 {
1908 /* No restriction. Get all fonts. */
1909 pl = mplist ();
1910 MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
1911 {
1912 MPLIST_DO (p, MPLIST_PLIST (family_list))
1913 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1914 }
1915 }
1916 else
1917 {
1918 if (file_list)
1919 {
1920 pl = mplist ();
1921 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1922 }
1923 if (family_list)
1924 {
1925 if (pl)
1926 for (p = pl; ! MPLIST_TAIL_P (p);)
1927 {
1928 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1929 p = MPLIST_NEXT (p);
1930 else
1931 mplist_pop (p);
1932 }
1933 else
1934 {
1935 pl = mplist ();
1936 MPLIST_DO (p, family_list)
1937 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1938 }
1939 }
1940 if (capability_list)
1941 {
1942 if (pl)
1943 for (p = pl; ! MPLIST_TAIL_P (p);)
1944 {
1945 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1946 p = MPLIST_NEXT (p);
1947 else
1948 mplist_pop (p);
1949 }
1950 else
1951 {
1952 pl = mplist ();
1953 MPLIST_DO (p, capability_list)
1954 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1955 }
1956 }
1957 }
1958
1959 if (font
1960 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1961 + font->property[MFONT_STRETCH] + font->size) > 0)
1962 {
1963 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1964 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1965 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1966 int size = font->size;
1967
1968 for (p = pl; ! MPLIST_TAIL_P (p); )
1969 {
1970 MFontFT *ft_info = MPLIST_VAL (p);
1971
1972 if ((weight != Mnil
1973 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1974 || (style != Mnil
1975 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1976 || (stretch != Mnil
1977 && stretch != FONT_PROPERTY (&ft_info->font,
1978 MFONT_STRETCH))
1979 || (size > 0
1980 && ft_info->font.size > 0
1981 && ft_info->font.size != size))
1982 mplist_pop (p);
1983 else
1984 p = MPLIST_NEXT (p);
1985 }
1986 }
1987
1988 MPLIST_DO (p, pl)
1989 {
1990 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1991 num++;
1992 if (maxnum && maxnum <= num)
1993 break;
1994 }
1995 M17N_OBJECT_UNREF (pl);
1996
1997 done:
1998 MDEBUG_PRINT1 (" %d found\n", num);
1999 return num;
2000 }
2001
2002 static void
ft_list_family_names(MFrame * frame,MPlist * plist)2003 ft_list_family_names (MFrame *frame, MPlist *plist)
2004 {
2005 MPlist *pl;
2006
2007 if (! ft_font_list)
2008 {
2009 #ifdef HAVE_FONTCONFIG
2010 fc_init_font_list ();
2011 #else /* not HAVE_FONTCONFIG */
2012 ft_init_font_list ();
2013 #endif /* not HAVE_FONTCONFIG */
2014 }
2015
2016 MPLIST_DO (pl, ft_font_list)
2017 {
2018 MSymbol family = MPLIST_KEY (pl);
2019 MPlist *p;
2020
2021 #ifdef HAVE_FONTCONFIG
2022 if (msymbol_get (family, Mgeneric_family) != Mnil)
2023 continue;
2024 #endif /* HAVE_FONTCONFIG */
2025 MPLIST_DO (p, plist)
2026 {
2027 MSymbol sym = MPLIST_SYMBOL (p);
2028
2029 if (sym == family)
2030 break;
2031 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2032 {
2033 mplist_push (p, Msymbol, family);
2034 break;
2035 }
2036 }
2037 if (MPLIST_TAIL_P (p))
2038 mplist_push (p, Msymbol, family);
2039 }
2040 }
2041
2042 static int
ft_check_capability(MRealizedFont * rfont,MSymbol capability)2043 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2044 {
2045 MFontFT *ft_info = (MFontFT *) rfont->font;
2046 MRealizedFontFT *ft_rfont = rfont->info;
2047 MFontCapability *cap = mfont__get_capability (capability);
2048
2049 if (cap->script_tag)
2050 {
2051 if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2052 return -1;
2053 }
2054 else if (cap->script != Mnil
2055 && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2056 return -1;
2057 if (cap->language != Mnil
2058 && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2059 return -1;
2060 return 0;
2061 }
2062
2063 static MRealizedFont *
ft_encapsulate(MFrame * frame,MSymbol data_type,void * data)2064 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2065 {
2066 MFontFT *ft_info;
2067 MRealizedFont *rfont;
2068 MRealizedFontFT *ft_rfont;
2069 FT_Face ft_face;
2070
2071 if (data_type == Mfontconfig)
2072 {
2073 #ifdef HAVE_FONTCONFIG
2074 FcPattern *pattern = data;
2075
2076 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2077 != FcResultMatch)
2078 return NULL;
2079 ft_info = fc_gen_font (pattern, NULL);
2080 #else /* not HAVE_FONTCONFIG */
2081 return NULL;
2082 #endif /* not HAVE_FONTCONFIG */
2083 }
2084 else if (data_type == Mfreetype)
2085 {
2086 ft_face = data;
2087 ft_info = ft_gen_font (ft_face);
2088 }
2089 else
2090 return NULL;
2091
2092 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2093 ft_rfont->ft_face = ft_face;
2094 ft_rfont->face_encapsulated = 1;
2095
2096 MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
2097
2098 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2099 rfont->id = ft_info->font.file;
2100 rfont->font = (MFont *) ft_info;
2101 rfont->info = ft_rfont;
2102 rfont->fontp = ft_face;
2103 rfont->driver = &mfont__ft_driver;
2104 rfont->spec = ft_info->font;
2105 rfont->spec.type = MFONT_TYPE_REALIZED;
2106 rfont->frame = frame;
2107 rfont->ascent = ft_face->size->metrics.ascender >> 6;
2108 rfont->descent = - ft_face->size->metrics.descender >> 6;
2109 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2110 rfont->baseline_offset = 0;
2111 rfont->x_ppem = ft_face->size->metrics.x_ppem;
2112 rfont->y_ppem = ft_face->size->metrics.y_ppem;
2113 #ifdef HAVE_FTBDF_H
2114 {
2115 BDF_PropertyRec prop;
2116
2117 if (! FT_IS_SCALABLE (ft_face)
2118 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2119 {
2120 rfont->baseline_offset = prop.u.integer << 6;
2121 rfont->ascent += prop.u.integer << 6;
2122 rfont->descent -= prop.u.integer << 6;
2123 }
2124 }
2125 #endif /* HAVE_FTBDF_H */
2126 if (FT_IS_SCALABLE (ft_face))
2127 rfont->average_width = 0;
2128 else
2129 rfont->average_width = ft_face->available_sizes->width << 6;
2130 rfont->next = MPLIST_VAL (frame->realized_font_list);
2131 MPLIST_VAL (frame->realized_font_list) = rfont;
2132
2133 return rfont;
2134 }
2135
2136 static void
ft_close(MRealizedFont * rfont)2137 ft_close (MRealizedFont *rfont)
2138 {
2139 if (! rfont->encapsulating)
2140 return;
2141 free (rfont->font);
2142 M17N_OBJECT_UNREF (rfont->info);
2143 free (rfont);
2144 }
2145
2146 /* See the comment of parse_otf_command (m17n-flt.c). */
2147
2148 static int
ft_check_otf(MFLTFont * font,MFLTOtfSpec * spec)2149 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2150 {
2151 #define FEATURE_NONE(IDX) (! spec->features[IDX])
2152
2153 #define FEATURE_ANY(IDX) \
2154 (spec->features[IDX] \
2155 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
2156
2157 #ifdef HAVE_OTF
2158 OTF_Tag *tags;
2159 int i, n, negative;
2160 OTF *otf = get_otf (font, NULL);
2161
2162 if (FEATURE_ANY (0) && FEATURE_ANY (1))
2163 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
2164 return (otf
2165 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
2166 NULL, 0) > 0
2167 || OTF_check_features (otf, 1, spec->script, spec->langsys,
2168 NULL, 0) > 0));
2169
2170 for (i = 0; i < 2; i++)
2171 if (! FEATURE_ANY (i))
2172 {
2173 if (FEATURE_NONE (i))
2174 {
2175 if (otf
2176 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2177 NULL, 0) > 0)
2178 return 0;
2179 continue;
2180 }
2181 if (spec->features[i][0] == 0xFFFFFFFF)
2182 {
2183 if (! otf
2184 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2185 NULL, 0) <= 0)
2186 continue;
2187 }
2188 else if (! otf)
2189 return 0;
2190 for (n = 1; spec->features[i][n]; n++);
2191 tags = alloca (sizeof (OTF_Tag) * n);
2192 for (n = 0, negative = 0; spec->features[i][n]; n++)
2193 {
2194 if (spec->features[i][n] == 0xFFFFFFFF)
2195 negative = 1;
2196 else if (negative)
2197 tags[n - 1] = spec->features[i][n] | 0x80000000;
2198 else
2199 tags[n] = spec->features[i][n];
2200 }
2201 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2202 tags, n - negative) != 1)
2203 return 0;
2204 }
2205 return 1;
2206
2207 #endif /* HAVE_OTF */
2208 return (FEATURE_NONE (0) ? (FEATURE_NONE (1) || FEATURE_ANY (1))
2209 : (FEATURE_NONE (1) && FEATURE_ANY (0)));
2210 }
2211
2212 #ifdef HAVE_OTF
2213
2214 static OTF *
get_otf(MFLTFont * font,FT_Face * ft_face)2215 get_otf (MFLTFont *font, FT_Face *ft_face)
2216 {
2217 MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2218 MFontFT *ft_info = (MFontFT *) rfont->font;
2219 MRealizedFontFT *ft_rfont = rfont->info;
2220 OTF *otf = ft_info->otf;
2221
2222 if (! otf)
2223 {
2224 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2225 otf = OTF_open_ft_face (ft_rfont->ft_face);
2226 #else
2227 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2228 #endif
2229 if (! otf || OTF_get_table (otf, "head") < 0)
2230 otf = invalid_otf;
2231 ft_info->otf = otf;
2232 }
2233 if (ft_face)
2234 *ft_face = ft_rfont->ft_face;
2235 return (otf == invalid_otf ? NULL : otf);
2236 }
2237
2238 #define DEVICE_DELTA(table, size) \
2239 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2240 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
2241 : 0)
2242
2243 void
adjust_anchor(OTF_Anchor * anchor,FT_Face ft_face,unsigned code,int x_ppem,int y_ppem,int * x,int * y)2244 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2245 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2246 {
2247 if (anchor->AnchorFormat == 2)
2248 {
2249 FT_Outline *outline;
2250 int ap = anchor->f.f1.AnchorPoint;
2251
2252 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2253 outline = &ft_face->glyph->outline;
2254 if (ap < outline->n_points)
2255 {
2256 *x = outline->points[ap].x << 6;
2257 *y = outline->points[ap].y << 6;
2258 }
2259 }
2260 else if (anchor->AnchorFormat == 3)
2261 {
2262 if (anchor->f.f2.XDeviceTable.offset)
2263 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2264 if (anchor->f.f2.YDeviceTable.offset)
2265 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2266 }
2267 }
2268 #endif /* HAVE_OTF */
2269
2270 #ifdef HAVE_OTF
2271
2272 static int
ft_drive_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to,MFLTGlyphString * out,MFLTGlyphAdjustment * adjustment)2273 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2274 MFLTGlyphString *in, int from, int to,
2275 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2276 {
2277 int len = to - from;
2278 int i, j, gidx;
2279 MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2280 MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
2281 OTF *otf;
2282 FT_Face face;
2283 OTF_GlyphString otf_gstring;
2284 OTF_Glyph *otfg;
2285 char script[5], *langsys = NULL;
2286 char *gsub_features = NULL, *gpos_features = NULL;
2287 unsigned int tag;
2288
2289 if (len == 0)
2290 return from;
2291 otf = get_otf (font, &face);
2292 if (! otf)
2293 goto simple_copy;
2294 OTF_tag_name (spec->script, script);
2295 if (spec->langsys)
2296 {
2297 langsys = alloca (5);
2298 OTF_tag_name (spec->langsys, langsys);
2299 }
2300 for (i = 0; i < 2; i++)
2301 {
2302 char *p;
2303
2304 if (spec->features[i])
2305 {
2306 for (j = 0; spec->features[i][j]; j++);
2307 if (i == 0)
2308 p = gsub_features = alloca (6 * j);
2309 else
2310 p = gpos_features = alloca (6 * j);
2311 for (j = 0; spec->features[i][j]; j++)
2312 {
2313 if (spec->features[i][j] == 0xFFFFFFFF)
2314 *p++ = '*', *p++ = ',';
2315 else
2316 {
2317 OTF_tag_name (spec->features[i][j], p);
2318 p[4] = ',';
2319 p += 5;
2320 }
2321 }
2322 *--p = '\0';
2323 }
2324 }
2325
2326 /* Extra room from pseudo glyphs. OTF_drive_features () may need
2327 more rooms. In that case, otf_gstring.glyphs is reallocated. */
2328 otf_gstring.size = len * 2;
2329 if (! MTABLE_CALLOC_SAFE (otf_gstring.glyphs, otf_gstring.size))
2330 MERROR (MERROR_MEMORY, -1);
2331 for (i = 0; i < len; i++)
2332 {
2333 otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
2334 otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2335 otf_gstring.glyphs[i].positioning_type = ((MGlyph *)in->glyphs)[from + i].libotf_positioning_type;
2336 }
2337 otf_gstring.used = len;
2338
2339 OTF_drive_gdef (otf, &otf_gstring);
2340 gidx = out ? out->used : from;
2341
2342 if (gsub_features)
2343 {
2344 OTF_Feature *features;
2345 MGlyph *g;
2346
2347 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2348 if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
2349 gsub_features) < 0)
2350 goto simple_copy;
2351 #else
2352 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
2353 gsub_features) < 0)
2354 goto simple_copy;
2355 #endif
2356 features = otf->gsub->FeatureList.Feature;
2357 if (out)
2358 {
2359 if (out->allocated < gidx + otf_gstring.used)
2360 return -2;
2361 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2362 i < otf_gstring.used; i++, otfg++, g++, out->used++)
2363 {
2364 int j;
2365 int min_from, max_to;
2366 int feature_idx;
2367
2368 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2369 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2370 #else
2371 feature_idx = otfg->positioning_type >> 4;
2372 #endif
2373
2374 *g = in_glyphs[from + otfg->f.index.from];
2375 min_from = g->g.from, max_to = g->g.to;
2376 g->g.c = 0;
2377 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2378 if (in_glyphs[from + j].g.code == otfg->glyph_id)
2379 {
2380 g->g.c = in_glyphs[from + j].g.c;
2381 break;
2382 }
2383 if (feature_idx)
2384 {
2385 tag = features[feature_idx - 1].FeatureTag;
2386 tag = PACK_OTF_TAG (tag);
2387 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2388 }
2389 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2390 {
2391 if (min_from > in_glyphs[from + j].g.from)
2392 min_from = in_glyphs[from + j].g.from;
2393 if (max_to < in_glyphs[from + j].g.to)
2394 max_to = in_glyphs[from + j].g.to;
2395 }
2396 if (g->g.code != otfg->glyph_id)
2397 {
2398 g->g.code = otfg->glyph_id;
2399 g->g.measured = 0;
2400 }
2401 g->g.from = min_from, g->g.to = max_to;
2402 }
2403 }
2404 else
2405 {
2406 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2407 i++, otfg++)
2408 {
2409 int feature_idx;
2410
2411 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2412 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2413 #else
2414 feature_idx = otfg->positioning_type >> 4;
2415 #endif
2416 if (feature_idx)
2417 {
2418 tag = features[feature_idx - 1].FeatureTag;
2419 tag = PACK_OTF_TAG (tag);
2420 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2421 {
2422 g = in_glyphs + (from + j);
2423 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2424 }
2425 }
2426 }
2427 }
2428 }
2429 else if (out)
2430 {
2431 if (out->allocated < gidx + len)
2432 return -2;
2433 for (i = 0; i < len; i++)
2434 out_glyphs[out->used++] = in_glyphs[from + i];
2435 }
2436
2437 if (gpos_features)
2438 {
2439 OTF_Feature *features;
2440 MGlyph *g;
2441
2442 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2443 if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
2444 gpos_features) < 0)
2445 return to;
2446 #else
2447 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2448 gpos_features) < 0)
2449 return to;
2450 #endif
2451 features = otf->gpos->FeatureList.Feature;
2452 if (out)
2453 {
2454 MGlyph *base = NULL, *mark = NULL;
2455 int x_ppem = face->size->metrics.x_ppem;
2456 int y_ppem = face->size->metrics.y_ppem;
2457 int x_scale = face->size->metrics.x_scale;
2458 int y_scale = face->size->metrics.y_scale;
2459
2460 for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2461 i < otf_gstring.used; i++, otfg++)
2462 {
2463 MGlyph *prev;
2464 int adjust_idx = otfg->glyph_id ? j : j - 1;
2465 int positioning_type, feature_idx;
2466
2467 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2468 positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
2469 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2470 #else
2471 positioning_type = otfg->positioning_type & 0xF;
2472 feature_idx = otfg->positioning_type >> 4;
2473 #endif
2474
2475 if (feature_idx)
2476 {
2477 tag = features[feature_idx - 1].FeatureTag;
2478 tag = PACK_OTF_TAG (tag);
2479 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2480 }
2481
2482 switch (positioning_type)
2483 {
2484 case 0:
2485 break;
2486 case 1: /* Single */
2487 case 2: /* Pair */
2488 {
2489 int format = otfg->f.f1.format;
2490
2491 if (format & OTF_XPlacement)
2492 adjustment[adjust_idx].xoff
2493 += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2494 if (format & OTF_XPlaDevice)
2495 adjustment[adjust_idx].xoff
2496 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2497 if (format & OTF_YPlacement)
2498 adjustment[adjust_idx].yoff
2499 -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2500 if (format & OTF_YPlaDevice)
2501 adjustment[adjust_idx].yoff
2502 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2503 if (format & OTF_XAdvance)
2504 adjustment[adjust_idx].xadv
2505 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2506 if (format & OTF_XAdvDevice)
2507 adjustment[adjust_idx].xadv
2508 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2509 if (format & OTF_YAdvance)
2510 adjustment[adjust_idx].yadv
2511 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2512 if (format & OTF_YAdvDevice)
2513 adjustment[adjust_idx].yadv
2514 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2515 adjustment[adjust_idx].set = 1;
2516 }
2517 break;
2518 case 3: /* Cursive */
2519 /* Not yet supported. */
2520 break;
2521 case 4: /* Mark-to-Base */
2522 case 5: /* Mark-to-Ligature */
2523 if (! base)
2524 break;
2525 prev = base;
2526 goto label_adjust_anchor;
2527 default: /* i.e. case 6 Mark-to-Mark */
2528 if (! mark)
2529 break;
2530 prev = mark;
2531 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2532 {
2533 int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2534
2535 if (distance > 0)
2536 {
2537 prev = g - distance;
2538 if (prev < out_glyphs)
2539 prev = mark;
2540 }
2541 }
2542 #endif
2543 label_adjust_anchor:
2544 {
2545 int base_x, base_y, mark_x, mark_y;
2546 int this_from, this_to;
2547 int k;
2548
2549 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2550 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2551 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2552 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2553
2554 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2555 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2556 x_ppem, y_ppem, &base_x, &base_y);
2557 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2558 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2559 x_ppem, y_ppem, &mark_x, &mark_y);
2560 adjustment[adjust_idx].xoff = base_x - mark_x;
2561 adjustment[adjust_idx].yoff = - (base_y - mark_y);
2562 adjustment[adjust_idx].back = (g - prev);
2563 adjustment[adjust_idx].xadv = 0;
2564 adjustment[adjust_idx].advance_is_absolute = 1;
2565 adjustment[adjust_idx].set = 1;
2566 this_from = g->g.from;
2567 this_to = g->g.to;
2568 for (k = 0; prev + k < g; k++)
2569 {
2570 if (this_from > prev[k].g.from)
2571 this_from = prev[k].g.from;
2572 if (this_to < prev[k].g.to)
2573 this_to = prev[k].g.to;
2574 }
2575 for (; prev <= g; prev++)
2576 {
2577 prev->g.from = this_from;
2578 prev->g.to = this_to;
2579 }
2580 }
2581 }
2582 if (otfg->glyph_id)
2583 {
2584 if (otfg->GlyphClass == OTF_GlyphClass0)
2585 base = mark = g;
2586 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2587 mark = g;
2588 else
2589 base = g;
2590 j++, g++;
2591 }
2592 }
2593 }
2594 else
2595 {
2596 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2597 i++, otfg++)
2598 if (otfg->positioning_type & 0xF)
2599 {
2600 int feature_idx;
2601
2602 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2603 feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2604 #else
2605 feature_idx = otfg->positioning_type >> 4;
2606 #endif
2607 if (feature_idx)
2608 {
2609 tag = features[feature_idx - 1].FeatureTag;
2610 tag = PACK_OTF_TAG (tag);
2611 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2612 {
2613 g = in_glyphs + (from + j);
2614 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2615 }
2616 }
2617 }
2618 }
2619 }
2620
2621 free (otf_gstring.glyphs);
2622 return to;
2623
2624 simple_copy:
2625 if (otf_gstring.glyphs)
2626 free (otf_gstring.glyphs);
2627 if (out)
2628 {
2629 if (out->allocated < out->used + len)
2630 return -2;
2631 font->get_metrics (font, in, from, to);
2632 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2633 sizeof (MGlyph) * len);
2634 out->used += len;
2635 }
2636 return to;
2637 }
2638
2639 #else /* not HAVE_OTF */
2640
2641 static int
ft_drive_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to,MFLTGlyphString * out,MFLTGlyphAdjustment * adjustment)2642 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2643 MFLTGlyphString *in, int from, int to,
2644 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2645 {
2646 int len = to - from;
2647 if (out)
2648 {
2649 if (out->allocated < out->used + len)
2650 return -2;
2651 font->get_metrics (font, in, from, to);
2652 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2653 sizeof (MGlyph) * len);
2654 out->used += len;
2655 }
2656 return to;
2657 }
2658
2659 #endif /* not HAVE_OTF */
2660
2661
2662 static int
ft_try_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to)2663 ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2664 MFLTGlyphString *in, int from, int to)
2665 {
2666 return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
2667 }
2668
2669
2670 #ifdef HAVE_OTF
2671 static unsigned char *iterate_bitmap;
2672
2673 static int
iterate_callback(OTF * otf,const char * feature,unsigned glyph_id)2674 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2675 {
2676 if (glyph_id <= otf->cmap->max_glyph_id)
2677 iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2678 return 0;
2679 }
2680
2681 static int
ft_iterate_otf_feature(MFLTFont * font,MFLTOtfSpec * spec,int from,int to,unsigned char * table)2682 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2683 int from, int to, unsigned char *table)
2684 {
2685 OTF *otf = get_otf (font, NULL);
2686 char id[13];
2687 int bmp_size;
2688 unsigned char *bitmap = NULL;
2689 int i, j;
2690 char script[5], *langsys = NULL;
2691
2692 if (! otf)
2693 return -1;
2694 if (OTF_get_table (otf, "cmap") < 0)
2695 return -1;
2696 if (! spec->features[0])
2697 return -1;
2698 strcpy (id, "feature-");
2699 id[12] = '\0';
2700 OTF_tag_name (spec->script, script);
2701 if (spec->langsys)
2702 {
2703 langsys = alloca (5);
2704 OTF_tag_name (spec->langsys, langsys);
2705 }
2706 bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2707 for (i = 0; spec->features[0][i]; i++)
2708 {
2709 unsigned char *bmp;
2710
2711 OTF_tag_name (spec->features[0][i], id + 8);
2712 bmp = OTF_get_data (otf, id);
2713 if (! bmp)
2714 {
2715 iterate_bitmap = bmp = calloc (bmp_size, 1);
2716 OTF_iterate_gsub_feature (otf, iterate_callback,
2717 script, langsys, id + 8);
2718 OTF_put_data (otf, id, bmp, free);
2719 }
2720 if (i == 0 && ! spec->features[0][1])
2721 /* Single feature */
2722 bitmap = bmp;
2723 else
2724 {
2725 if (! bitmap)
2726 {
2727 bitmap = alloca (bmp_size);
2728 memcpy (bitmap, bmp, bmp_size);
2729 }
2730 else
2731 {
2732 int j;
2733
2734 for (j = 0; j < bmp_size; j++)
2735 bitmap[j] &= bmp[j];
2736 }
2737 }
2738 }
2739 for (i = 0; i < bmp_size; i++)
2740 if (bitmap[i])
2741 {
2742 for (j = 0; j < 8; j++)
2743 if (bitmap[i] & (1 << j))
2744 {
2745 int c = OTF_get_unicode (otf, (i * 8) + j);
2746
2747 if (c >= from && c <= to)
2748 table[c - from] = 1;
2749 }
2750 }
2751 return 0;
2752 }
2753 #endif
2754
2755
2756
2757 /* Internal API */
2758
2759 MFontDriver mfont__ft_driver =
2760 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2761 ft_render, ft_list, ft_list_family_names, ft_check_capability,
2762 ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
2763 #ifdef HAVE_OTF
2764 ft_iterate_otf_feature
2765 #endif /* HAVE_OTF */
2766 };
2767
2768 int
mfont__ft_init()2769 mfont__ft_init ()
2770 {
2771 int i;
2772
2773 if (FT_Init_FreeType (&ft_library) != 0)
2774 MERROR (MERROR_FONT_FT, -1);
2775
2776 for (i = 0; i < ft_to_prop_size; i++)
2777 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2778
2779 Mmedium = msymbol ("medium");
2780 Mr = msymbol ("r");
2781 Mnull = msymbol ("");
2782
2783 M0[0] = msymbol ("0-0");
2784 M0[1] = msymbol ("0-1");
2785 M0[2] = msymbol ("0-2");
2786 M0[3] = msymbol ("0-3");
2787 M0[4] = msymbol ("0-4");
2788 M3_1 = msymbol ("3-1");
2789 M1_0 = msymbol ("1-0");
2790
2791 #ifdef HAVE_FONTCONFIG
2792 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2793 {
2794 FC_vs_M17N_font_prop *table = fc_all_table[i];
2795 int j;
2796
2797 for (j = 0; table[j].m17n_value; j++)
2798 table[j].sym = msymbol (table[j].m17n_value);
2799 table[j].sym = table[j - 1].sym;
2800 }
2801
2802 {
2803 char *pathname;
2804 struct stat buf;
2805 MPlist *plist;
2806 MSymbol serif, sans_serif, monospace;
2807
2808 fc_config = FcInitLoadConfigAndFonts ();
2809 if (mfont_freetype_path)
2810 {
2811 MPLIST_DO (plist, mfont_freetype_path)
2812 if (MPLIST_STRING_P (plist)
2813 && (pathname = MPLIST_STRING (plist))
2814 && stat (pathname, &buf) == 0)
2815 {
2816 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2817 FcChar8 *dir;
2818
2819 while ((dir = FcStrListNext (strlist)))
2820 if (strcmp ((char *) dir, pathname) == 0)
2821 break;
2822 if (! dir)
2823 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2824 FcStrListDone (strlist);
2825 }
2826 }
2827 Mgeneric_family = msymbol ("generic famly");
2828 serif = msymbol ("serif");
2829 msymbol_put (serif, Mgeneric_family, serif);
2830 sans_serif = msymbol ("sans-serif");
2831 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2832 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2833 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2834 monospace = msymbol ("monospace");
2835 msymbol_put (monospace, Mgeneric_family, monospace);
2836 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2837 }
2838 #endif /* HAVE_FONTCONFIG */
2839
2840 return 0;
2841 }
2842
2843 void
mfont__ft_fini()2844 mfont__ft_fini ()
2845 {
2846 MPlist *plist, *p;
2847
2848 if (ft_default_list)
2849 {
2850 M17N_OBJECT_UNREF (ft_default_list);
2851 ft_default_list = NULL;
2852 }
2853
2854 if (ft_font_list)
2855 {
2856 MPLIST_DO (plist, ft_font_list)
2857 {
2858 if (MPLIST_VAL (plist))
2859 MPLIST_DO (p, MPLIST_VAL (plist))
2860 {
2861 if (MPLIST_KEY (p) != Mt)
2862 free_ft_info (MPLIST_VAL (p));
2863 }
2864 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2865 }
2866 M17N_OBJECT_UNREF (ft_font_list);
2867 ft_font_list = NULL;
2868
2869 if (ft_language_list)
2870 {
2871 MPLIST_DO (plist, ft_language_list)
2872 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2873 M17N_OBJECT_UNREF (ft_language_list);
2874 ft_language_list = NULL;
2875 }
2876
2877 if (ft_script_list)
2878 {
2879 MPLIST_DO (plist, ft_script_list)
2880 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2881 M17N_OBJECT_UNREF (ft_script_list);
2882 ft_script_list = NULL;
2883 }
2884
2885 if (ft_capability_list)
2886 {
2887 MPLIST_DO (plist, ft_capability_list)
2888 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2889 M17N_OBJECT_UNREF (ft_capability_list);
2890 ft_capability_list = NULL;
2891 }
2892
2893 if (ft_file_list)
2894 {
2895 MPLIST_DO (plist, ft_file_list)
2896 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2897 M17N_OBJECT_UNREF (ft_file_list);
2898 ft_file_list = NULL;
2899 }
2900 }
2901 FT_Done_FreeType (ft_library);
2902 #ifdef HAVE_FONTCONFIG
2903 FcConfigDestroy (fc_config);
2904 fc_config = NULL;
2905 #endif /* HAVE_FONTCONFIG */
2906 all_fonts_scaned = 0;
2907 }
2908
2909 #ifdef HAVE_FONTCONFIG
2910
2911 int
mfont__ft_parse_name(const char * name,MFont * font)2912 mfont__ft_parse_name (const char *name, MFont *font)
2913 {
2914 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2915 FcChar8 *str;
2916 int val;
2917 double size;
2918 char *buf;
2919 int bufsize = 0;
2920
2921 if (! pat)
2922 return -1;
2923 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2924 {
2925 STRDUP_LOWER (buf, bufsize, (char *) str);
2926 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2927 }
2928 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2929 {
2930 STRDUP_LOWER (buf, bufsize, (char *) str);
2931 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2932 }
2933 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2934 mfont__set_property (font, MFONT_WEIGHT,
2935 fc_decode_prop (val, fc_weight_table,
2936 fc_weight_table_size));
2937 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2938 mfont__set_property (font, MFONT_STYLE,
2939 fc_decode_prop (val, fc_slant_table,
2940 fc_slant_table_size));
2941 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2942 mfont__set_property (font, MFONT_STRETCH,
2943 fc_decode_prop (val, fc_width_table,
2944 fc_width_table_size));
2945 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2946 font->size = size * 10 + 0.5;
2947 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2948 font->size = - (size * 10 + 0.5);
2949 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2950 {
2951 font->file = msymbol ((char *) str);
2952 }
2953 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2954 font->type = MFONT_TYPE_SPEC;
2955 FcPatternDestroy (pat);
2956 return 0;
2957 }
2958
2959 char *
mfont__ft_unparse_name(MFont * font)2960 mfont__ft_unparse_name (MFont *font)
2961 {
2962 FcPattern *pat = fc_get_pattern (font);
2963 char *name = (char *) FcNameUnparse (pat);
2964
2965 FcPatternDestroy (pat);
2966 return name;
2967 }
2968 #endif /* HAVE_FONTCONFIG */
2969
2970 #endif /* HAVE_FREETYPE */
2971