(ft_drive_otf): Don't accumulate anchor adjustments.
[m17n/m17n-lib.git] / src / font-ft.c
1 /* font-ft.c -- FreeType interface sub-module.
2    Copyright (C) 2003, 2004, 2007, 2008
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    02111-1307, 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 #endif /* HAVE_OTF */
70
71 typedef struct
72 {
73   MFont font;
74 #ifdef HAVE_OTF
75   /* NULL if not yet opened.  invalid_otf if not OTF.  */
76   OTF *otf;
77 #endif /* HAVE_OTF */
78 #ifdef HAVE_FONTCONFIG
79   FcLangSet *langset;
80   FcCharSet *charset;
81 #endif  /* HAVE_FONTCONFIG */
82 } MFontFT;
83
84 typedef struct
85 {
86   M17NObject control;
87   FT_Face ft_face;              /* This must be the 2nd member. */
88   MPlist *charmap_list;
89   int face_encapsulated;
90 } MRealizedFontFT;
91
92 typedef struct
93 {
94   char *ft_style;
95   int len;
96   enum MFontProperty prop;
97   char *val;
98 } MFTtoProp;
99
100 static MFTtoProp ft_to_prop[] =
101   { { "italic", 0, MFONT_STYLE, "i" },
102     { "roman", 0, MFONT_STYLE, "r" },
103     { "oblique", 0, MFONT_STYLE, "o" },
104     { "regular", 0, MFONT_WEIGHT, "normal" },
105     { "normal", 0, MFONT_WEIGHT, "normal" },
106     /* We need this entry even if "bold" is in commone_weight[] to
107        handle such style names as "bolditalic" and "boldoblique".  */
108     { "bold", 0, MFONT_WEIGHT, "bold" },
109     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
110     { "demi", 0, MFONT_WEIGHT, "demibold" } };
111 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
112
113 /** List of FreeType fonts.  Keys are family names, values are plists
114     containing fonts of the corresponding family.  In the deeper
115     plist, keys are file names, values are (MFontFT *).  */
116 static MPlist *ft_font_list;
117
118 /** List of FreeType fonts.  Keys are script names, values are plists
119     containing fonts supporting the corresponding script.  In the
120     deeper plist, keys are family names, values are (MFontFT *).  */
121 static MPlist *ft_script_list;
122
123 /** List of FreeType fonts.  Keys are language names, values are
124     plists containing fonts supporting the corresponding language.  In
125     the deeper plist, keys are family names, values are (MFontFT *).  */
126 static MPlist *ft_language_list;
127
128 static MPlist *ft_file_list;
129
130 static int all_fonts_scaned;
131
132 #define STRDUP_LOWER(s1, size, s2)                              \
133   do {                                                          \
134     int len = strlen (s2) + 1;                                  \
135     char *p1, *p2;                                              \
136                                                                 \
137     if ((size) < len)                                           \
138       (s1) = alloca (len), (size) = len;                        \
139     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)                 \
140       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
141     *p1 = '\0';                                                 \
142   } while (0)
143
144
145 static MPlist *ft_list_family (MSymbol, int, int);
146
147 static void
148 free_ft_rfont (void *object)
149 {
150   MRealizedFontFT *ft_rfont = object;
151
152   if (! ft_rfont->face_encapsulated)
153     {
154       M17N_OBJECT_UNREF (ft_rfont->charmap_list);
155       FT_Done_Face (ft_rfont->ft_face);
156     }
157   free (ft_rfont);
158 }
159
160 static void
161 free_ft_info (MFontFT *ft_info)
162 {
163 #ifdef HAVE_OTF
164   if (ft_info->otf && ft_info->otf != invalid_otf)
165     OTF_close (ft_info->otf);
166 #endif /* HAVE_OTF */
167 #ifdef HAVE_FONTCONFIG
168   if (ft_info->langset)
169     FcLangSetDestroy (ft_info->langset);
170   if (ft_info->charset)
171     FcCharSetDestroy (ft_info->charset);
172 #endif  /* HAVE_FONTCONFIG */
173   free (ft_info);
174 }
175
176 static MPlist *
177 ft_get_charmaps (FT_Face ft_face)
178 {
179   MPlist *plist = mplist ();
180   int unicode_bmp = -1, unicode_full = -1;
181   int i;
182
183   mplist_add (plist, Mt, (void *) -1);
184   for (i = 0; i < ft_face->num_charmaps; i++)
185     {
186       MSymbol registry = Mnil;
187
188       if (ft_face->charmaps[i]->platform_id == 0)
189         {
190           if (ft_face->charmaps[i]->encoding_id <= 4)
191             registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
192           if (ft_face->charmaps[i]->encoding_id == 4)
193             unicode_bmp = unicode_full = i;
194         }
195       else if (ft_face->charmaps[i]->platform_id == 3)
196         {
197           if (ft_face->charmaps[i]->encoding_id == 1)
198             registry = M3_1, unicode_bmp = i;
199           else if (ft_face->charmaps[i]->encoding_id == 10)
200             unicode_bmp = unicode_full = i;
201         }
202       else if (ft_face->charmaps[i]->platform_id == 1
203                && ft_face->charmaps[i]->encoding_id == 0)
204         {
205           registry = M1_0;
206           mplist_add (plist, Mapple_roman, (void *) i);
207         }
208       if (registry == Mnil)
209         {
210           char registry_buf[16];
211
212           sprintf (registry_buf, "%d-%d",
213                    ft_face->charmaps[i]->platform_id,
214                    ft_face->charmaps[i]->encoding_id);
215           registry = msymbol (registry_buf);
216         }
217       mplist_add (plist, registry, (void *) i);
218     }
219   if (unicode_full >= 0)
220     mplist_add (plist, Municode_full, (void *) unicode_full);
221   if (unicode_bmp >= 0)
222     {
223       int i;
224
225       mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
226       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
227       for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
228       if (i == 0x7F)
229         {
230           for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
231           if (i == 0x100)
232             mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
233         }
234     }
235
236   return plist;
237 }
238
239 static MFontFT *
240 ft_gen_font (FT_Face ft_face)
241 {
242   MFontFT *ft_info;
243   MFont *font;
244   char *buf;
245   int bufsize = 0;
246   char *stylename;
247   MSymbol family;
248   int size;
249
250   if (FT_IS_SCALABLE (ft_face))
251     size = ft_face->size->metrics.y_ppem;
252   else if (ft_face->num_fixed_sizes == 0)
253     return NULL;
254   else
255     size = ft_face->available_sizes[0].height;
256
257   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
258   font = &ft_info->font;
259   STRDUP_LOWER (buf, bufsize, ft_face->family_name);
260   family = msymbol (buf);
261   mfont__set_property (font, MFONT_FAMILY, family);
262   mfont__set_property (font, MFONT_WEIGHT, Mmedium);
263   mfont__set_property (font, MFONT_STYLE, Mr);
264   mfont__set_property (font, MFONT_STRETCH, Mnormal);
265   mfont__set_property (font, MFONT_ADSTYLE, Mnull);
266   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
267   font->size = size * 10;
268   font->type = MFONT_TYPE_OBJECT;
269   font->source = MFONT_SOURCE_FT;
270   font->file = NULL;
271
272   stylename = ft_face->style_name;
273   while (*stylename)
274     {
275       int i;
276
277       for (i = 0; i < ft_to_prop_size; i++)
278         if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
279                            ft_to_prop[i].len))
280           {
281             mfont__set_property (font, ft_to_prop[i].prop,
282                                  msymbol (ft_to_prop[i].val));
283             stylename += ft_to_prop[i].len;
284             break;
285           }
286       if (i == ft_to_prop_size)
287         {
288           char *p1 = stylename + 1;
289           MSymbol sym;
290
291           while (*p1 >= 'a' && *p1 <= 'z') p1++;
292           sym = msymbol__with_len (stylename, p1 - stylename);
293           for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
294             if (msymbol_get (sym, mfont__property_table[i].property))
295               {
296                 mfont__set_property (font, i, sym);
297                 break;
298               }
299           stylename = p1;
300         }
301       while (*stylename && ! isalpha (*stylename))
302         stylename++;
303     }
304   return ft_info;
305 }
306
307 #ifdef HAVE_FONTCONFIG
308
309 typedef struct
310 {
311   int fc_value;
312   char *m17n_value;
313   MSymbol sym;
314 } FC_vs_M17N_font_prop;
315
316 static FC_vs_M17N_font_prop fc_weight_table[] =
317   { { FC_WEIGHT_THIN, "thin" },
318     { FC_WEIGHT_ULTRALIGHT, "extralight" },
319     { FC_WEIGHT_LIGHT, "light" },
320 #ifdef FC_WEIGHT_BOOK
321     { FC_WEIGHT_BOOK, "book" },
322 #endif  /* FC_WEIGHT_BOOK */
323     { FC_WEIGHT_REGULAR, "normal" },
324     { FC_WEIGHT_NORMAL, "normal" },
325     { FC_WEIGHT_MEDIUM, "medium" },
326     { FC_WEIGHT_DEMIBOLD, "demibold" },
327     { FC_WEIGHT_BOLD, "bold" },
328     { FC_WEIGHT_EXTRABOLD, "extrabold" },
329     { FC_WEIGHT_BLACK, "black" },
330     { FC_WEIGHT_HEAVY, "heavy" },
331     { FC_WEIGHT_MEDIUM, NULL } };
332 int fc_weight_table_size =
333   sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
334
335 static FC_vs_M17N_font_prop fc_slant_table[] =
336   { { FC_SLANT_ROMAN, "r" },
337     { FC_SLANT_ITALIC, "i" },
338     { FC_SLANT_OBLIQUE, "o" },
339     { FC_SLANT_ROMAN, NULL } };
340 int fc_slant_table_size =
341   sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
342
343 static FC_vs_M17N_font_prop fc_width_table[] =
344   { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
345     { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
346     { FC_WIDTH_CONDENSED, "condensed" },
347     { FC_WIDTH_SEMICONDENSED, "semicondensed" },
348     { FC_WIDTH_NORMAL, "normal" },
349     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
350     { FC_WIDTH_EXPANDED, "expanded" },
351     { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
352     { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
353     { FC_WIDTH_NORMAL, NULL } };
354 int fc_width_table_size =
355   sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
356
357
358 static FC_vs_M17N_font_prop *fc_all_table[] =
359   { fc_weight_table, fc_slant_table, fc_width_table };
360
361 static MSymbol
362 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
363 {
364   int i = size / 2;
365
366   if (val < table[i].fc_value)
367     {
368       for (i--; i >= 0; i--)
369         if (val > table[i].fc_value)
370           break;
371       i++;
372     }
373   else
374     {
375       for (; i < size; i++)
376         if (val <= table[i].fc_value)
377           break;
378     }
379   return table[i].sym;
380 }
381
382 static int
383 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
384 {
385   int i;
386
387   for (i = 0; table[i].m17n_value; i++)
388     if (table[i].sym == sym)
389       break;
390   return table[i].fc_value;
391 }
392
393 FcPattern *
394 fc_get_pattern (MFont *font)
395 {
396   FcPattern *pat = FcPatternCreate ();
397   MSymbol sym, weight, style, stretch;
398
399
400   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
401     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
402   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
403     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
404   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
405     FcPatternAddInteger (pat, FC_WEIGHT,
406                          fc_encode_prop (weight, fc_weight_table));
407   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
408     FcPatternAddInteger (pat, FC_SLANT,
409                          fc_encode_prop (style, fc_slant_table));
410   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
411     FcPatternAddInteger (pat, FC_WIDTH,
412                          fc_encode_prop (stretch, fc_width_table));
413   if (font->size > 0)
414     {
415       double size = font->size;
416       FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
417     }
418   else if (font->size < 0)
419     {
420       double size = - font->size;
421       FcPatternAddDouble (pat, FC_SIZE, size / 10);
422     }
423   return pat;
424 }
425
426 static void
427 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
428 {
429   FcChar8 *str;
430   int val;
431   double size;
432   char *buf;
433   int bufsize = 0;
434   MSymbol sym;
435   FcLangSet *ls;
436   FcCharSet *cs;
437   MFont *font = &ft_info->font;
438
439   MFONT_INIT (font);
440   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
441     {
442       STRDUP_LOWER (buf, bufsize, (char *) str);
443       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
444     }
445   if (family)
446     mfont__set_property (font, MFONT_FAMILY, msymbol (family));
447   else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
448     {
449       STRDUP_LOWER (buf, bufsize, (char *) str);
450       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
451     }
452   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
453     {
454       sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
455       mfont__set_property (font, MFONT_WEIGHT, sym);
456     }
457   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
458     {
459       sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
460       mfont__set_property (font, MFONT_STYLE, sym);
461     }
462   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
463     {
464       sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
465       mfont__set_property (font, MFONT_STRETCH, sym);
466     }
467   if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
468     {
469       if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
470           || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
471           || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
472         font->for_full_width = 1;
473       ft_info->langset = FcLangSetCopy (ls);
474     }
475   if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
476     ft_info->charset = FcCharSetCopy (cs);
477
478   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
479   font->type = MFONT_TYPE_SPEC;
480   font->source = MFONT_SOURCE_FT;
481   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
482     font->size = size * 10;
483   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
484     font->file = msymbol ((char *) str);
485 }
486
487
488 static MFontFT *
489 fc_gen_font (FcPattern *pat, char *family)
490 {
491   MFontFT *ft_info;
492
493   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
494   fc_parse_pattern (pat, family, ft_info);
495   ft_info->font.type = MFONT_TYPE_OBJECT;
496   return ft_info;
497 }
498
499 static void
500 fc_init_font_list (void)
501 {
502   FcPattern *pattern = FcPatternCreate ();
503   FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
504   FcFontSet *fs = FcFontList (fc_config, pattern, os);
505   MPlist *plist = mplist ();
506   char *buf;
507   int bufsize = 0;
508   int i;
509
510   ft_font_list = plist;
511   for (i = 0; i < fs->nfont; i++)
512     {
513       char *fam;
514
515       if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
516                               (FcChar8 **) &fam) != FcResultMatch)
517         continue;
518       STRDUP_LOWER (buf, bufsize, fam);
519       plist = mplist_add (plist, msymbol (buf), NULL);
520     }
521   FcFontSetDestroy (fs);
522   FcObjectSetDestroy (os);
523   FcPatternDestroy (pattern);
524 }
525
526 static MPlist *
527 fc_list_pattern (FcPattern *pattern)
528 {
529   FcObjectSet *os = NULL;
530   FcFontSet *fs = NULL;
531   MSymbol last_family = Mnil;
532   MPlist *plist = NULL, *pl = NULL;
533   char *buf;
534   int bufsize = 0;
535   int i;
536
537   if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
538     goto err;
539   if (! (fs = FcFontList (fc_config, pattern, os)))
540     goto err;
541
542   for (i = 0; i < fs->nfont; i++)
543     {
544       MSymbol family, file;
545       char *fam, *filename;
546       MFontFT *ft_info;
547
548       if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
549                               (FcChar8 **) &fam) != FcResultMatch)
550         continue;
551       if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
552                               (FcChar8 **) &filename) != FcResultMatch)
553         continue;
554       STRDUP_LOWER (buf, bufsize, fam);
555       family = msymbol (buf);
556       file = msymbol (filename);
557       if (family != last_family)
558         {
559           pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
560           last_family = family;
561         }
562       ft_info = mplist_get (pl, file);
563       if (ft_info)
564         {
565           if (! plist)
566             plist = mplist ();
567           mplist_add (plist, family, ft_info);
568         }
569     }
570
571  err:
572   if (fs) FcFontSetDestroy (fs);
573   if (os) FcObjectSetDestroy (os);
574   return plist;
575 }
576
577 /* Return FcCharSet object built from CHAR_LIST or MT.  In the latter
578    case, it is assured that the M-text contains at least one
579    character.  */
580
581 static FcCharSet *
582 fc_build_charset (MPlist *char_list, MText *mt)
583 {
584   FcCharSet *cs = FcCharSetCreate ();
585
586   if (! cs)
587     return NULL;
588   if (char_list)
589     {
590       for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
591         if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
592           {
593             FcCharSetDestroy (cs);
594             return NULL;
595           }
596     }
597   else
598     {
599       int i;
600
601       for (i = mtext_nchars (mt) - 1; i >= 0; i--)
602         if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
603           {
604             FcCharSetDestroy (cs);
605             return NULL;
606           }
607       if (mtext_nchars (mt) > 0
608           && (mt = mtext_get_prop (mt, 0, Mtext)))
609         for (i = mtext_nchars (mt) - 1; i >= 0; i--)
610           if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
611             {
612               FcCharSetDestroy (cs);
613               return NULL;
614             }
615       }
616   return cs;
617 }
618
619 #else   /* not HAVE_FONTCONFIG */
620
621 static MPlist *
622 ft_add_font (char *filename)
623 {
624   FT_Face ft_face;
625   char *stylename;
626   int size = 0;
627   MSymbol family;
628   MFontFT *ft_info;
629   MFont *font;
630   MPlist *plist;
631   int i;
632   char *buf;
633   int bufsize = 0;
634
635   if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
636     return NULL;
637   ft_info = ft_gen_font (ft_face);
638   FT_Done_Face (ft_face);
639   if (! ft_info)
640     return NULL;
641
642   font = &ft_info->font;
643   font->file = msymbol (filename);
644
645   plist = mplist_find_by_key (ft_font_list, family);
646   if (plist)
647     mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
648   else
649     {
650       plist = mplist ();
651       mplist_add (plist, font->file, ft_info);
652       plist = mplist_push (ft_font_list, family, plist);
653     }
654   return plist;
655 }
656
657 static void
658 ft_init_font_list (void)
659 {
660   MPlist *plist;
661   struct stat buf;
662   char *pathname;
663   char *path;
664   USE_SAFE_ALLOCA;
665
666   ft_font_list = mplist ();
667   MPLIST_DO (plist, mfont_freetype_path)
668     if (MPLIST_STRING_P (plist)
669         && (pathname = MPLIST_STRING (plist))
670         && stat (pathname, &buf) == 0)
671       {
672         if (S_ISREG (buf.st_mode))
673           ft_add_font (pathname);
674         else if (S_ISDIR (buf.st_mode))
675           {
676             DIR *dir = opendir (pathname);
677
678             if (dir)
679               {
680                 int len = strlen (pathname);
681                 struct dirent *dp;
682
683                 while ((dp = readdir (dir)) != NULL)
684                   {
685                     SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
686                     strcpy (path, pathname);
687                     path[len] =  '/';
688                     strcpy (path + len + 1, dp->d_name);
689                     ft_add_font (path);
690                   }
691                 closedir (dir);
692               }
693           }
694       }
695   SAFE_FREE (path);
696 }
697
698 /* Return 1 iff the font pointed by FT_INFO has all characters in
699    CHAR_LIST.  */
700
701 static int
702 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
703 {
704   FT_Face ft_face;
705   MPlist *cl;
706
707   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
708     return 0;
709   MPLIST_DO (cl, char_list)
710     if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
711       break;
712   FT_Done_Face (ft_face);
713   return MPLIST_TAIL_P (cl);
714 }
715
716 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
717    that supports characters in CHAR_LIST or MT.  One of CHAR_LIST or
718    MT must be NULL.  */
719
720 static MPlist *
721 ft_list_char_list (MPlist *char_list, MText *mt)
722 {
723   MPlist *plist = NULL, *pl, *p;
724
725   if (! ft_font_list)
726     ft_list_family (Mnil, 0, 1);
727
728   if (mt)
729     {
730       int len = mtext_nchars (mt);
731       MText *extra = mtext_get_prop (mt, 0, Mtext);
732       int total_len = len + (extra ? mtext_nchars (extra) : 0);
733       int i;
734
735       char_list = mplist ();
736       for (i = 0; i < total_len; i++)
737         {
738           int c = (i < len ? mtext_ref_char (mt, i)
739                    : mtext_ref_char (extra, i - len));
740
741           if (! mplist_find_by_value (char_list, (void *) c))
742             mplist_push (char_list, Minteger, (void *) c);
743         }
744     }
745
746   MPLIST_DO (pl, ft_font_list)
747     {
748       MPLIST_DO (p, MPLIST_PLIST (pl))
749         {
750           MFontFT *ft_info = MPLIST_VAL (p);
751
752           if (ft_has_char_list_p (ft_info, char_list))
753             {
754               MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
755
756               if (! plist)
757                 plist = mplist ();
758               mplist_push (plist, family, ft_info);
759             }
760         }
761     }
762   if (mt)
763     M17N_OBJECT_UNREF (char_list);
764   return plist;
765 }
766 #endif  /* not HAVE_FONTCONFIG */
767
768
769 /* Return an element of ft_font_list for FAMILY.  If FAMILY is Mnil,
770    scan all fonts and return ft_font_list.  */
771
772 static MPlist *
773 ft_list_family (MSymbol family, int check_generic, int check_alias)
774 {
775   MPlist *plist;
776 #ifdef HAVE_FONTCONFIG
777   char *fam;
778   MPlist *pl, *p;
779   FcPattern *pattern;
780   FcObjectSet *os;
781   FcFontSet *fs;
782   int i;
783   char *buf;
784   int bufsize = 0;
785   MSymbol generic;
786
787   if (! ft_font_list)
788     {
789       MSymbol sym;
790
791       plist = ft_font_list = mplist ();
792       pattern = FcPatternCreate ();
793       os = FcObjectSetBuild (FC_FAMILY, NULL);
794       fs = FcFontList (fc_config, pattern, os);
795       for (i = 0; i < fs->nfont; i++)
796         {
797           if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
798                                   (FcChar8 **) &fam) != FcResultMatch)
799             continue;
800           STRDUP_LOWER (buf, bufsize, fam);
801           sym = msymbol (buf);
802           if (! mplist_find_by_key (ft_font_list, sym))
803             plist = mplist_add (plist, sym, NULL);
804         }
805       FcFontSetDestroy (fs);
806       FcObjectSetDestroy (os);
807       FcPatternDestroy (pattern);
808     }
809
810   if (family == Mnil)
811     {
812       if (! all_fonts_scaned)
813         {
814           MPLIST_DO (plist, ft_font_list)
815             {
816               if (! MPLIST_VAL (plist))
817                 ft_list_family (MPLIST_KEY (plist), 0, 1);
818             }
819           all_fonts_scaned = 1;
820         }
821       return ft_font_list;
822     }
823
824   plist = mplist_find_by_key (ft_font_list, family);
825   if (plist)
826     {
827       if (! MPLIST_VAL (plist))
828         {
829           fam = MSYMBOL_NAME (family);
830           pattern = FcPatternCreate ();
831           FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
832           os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
833                                  FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
834                                  NULL);
835           fs = FcFontList (fc_config, pattern, os);
836           p = pl = mplist ();
837           for (i = 0; i < fs->nfont; i++)
838             {
839               MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
840               p = mplist_add (p, ft_info->font.file, ft_info);
841             }
842           MPLIST_VAL (plist) = pl;
843           FcFontSetDestroy (fs);
844           FcObjectSetDestroy (os);
845           FcPatternDestroy (pattern);
846         }
847     }
848   else if (check_generic
849            && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
850     {
851       /* Check if FAMILY is a geneneric family (e.g. `serif').  */
852       FcChar8 *fam8;
853       
854       if (family != generic)
855         plist = ft_list_family (generic, 1, 1);
856       else
857         {
858           fam = MSYMBOL_NAME (family);
859           plist = mplist ();
860           mplist_push (ft_font_list, family, plist);
861           pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
862           FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
863           for (i = 0; 1; i++)
864             {
865               if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
866                   != FcResultMatch)
867                 break;
868               STRDUP_LOWER (buf, bufsize, (char *) fam8);
869               family = msymbol (buf);
870               if (msymbol_get (family, Mgeneric_family))
871                 break;
872               pl = ft_list_family (family, 0, 1);
873               if (! pl)
874                 continue;
875               MPLIST_DO (pl, MPLIST_PLIST (pl))
876                 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
877             }
878           plist = ft_font_list;
879         }
880     }
881   else if (check_alias)
882     {
883       /* Check if there exist an alias.  */
884       pl = mplist ();
885       plist = mplist_add (ft_font_list, family, pl);
886
887       pattern = FcPatternBuild (NULL,
888                                 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
889                                 NULL);
890       FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
891
892       for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
893                                       (FcChar8 **) &fam) == FcResultMatch;
894            i++);
895       if (i > 0)
896         {
897           /* The last one is a generic family.  */
898           MSymbol sym;
899           int j;
900           FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
901                                            NULL);
902
903           FcConfigSubstitute (fc_config, pat, FcMatchPattern);
904           for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
905                                           (FcChar8 **) &fam) == FcResultMatch;
906                j++);
907
908           /* Now we know that the last J fonts in PATTERN are from
909              generic font, and the first one is not available.  So,
910              the remaining ones are aliases.  */
911           j = i - j;
912           for (i = 1; i < j; i++)
913             {
914               FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
915               STRDUP_LOWER (buf, bufsize, fam);
916               sym = msymbol (buf);
917               p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
918               if (! MPLIST_TAIL_P (p))
919                 MPLIST_DO (p, p)
920                   mplist_push (pl, Mt, MPLIST_VAL (p));
921             }
922         }
923     }
924   else
925     {
926       pl = mplist ();
927       plist = mplist_add (ft_font_list, family, pl);
928     }
929
930 #else  /* not HAVE_FONTCONFIG */
931
932   if (! all_fonts_scaned)
933     {
934       ft_init_font_list ();
935       all_fonts_scaned = 1;
936     }
937   if (family == Mnil)
938     plist = ft_font_list;
939   else
940     {
941       plist = mplist_find_by_key (ft_font_list, family);
942       if (! plist)
943         plist = mplist_push (ft_font_list, family, mplist ());
944     }
945 #endif  /* not HAVE_FONTCONFIG */
946
947   return plist;
948 }
949
950 static MPlist *
951 ft_list_language (MSymbol language)
952 {
953   MPlist *plist = NULL;
954   MText *mt;
955
956   if (! ft_language_list)
957     ft_language_list = mplist ();
958   else if ((plist = mplist_find_by_key (ft_language_list, language)))
959     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
960
961   mt = mlanguage_text (language);
962
963 #ifdef HAVE_FONTCONFIG
964   {
965     FcPattern *pattern = NULL;
966     FcCharSet *cs = NULL;
967     FcLangSet *ls = NULL;
968
969     if (! (pattern = FcPatternCreate ()))
970       goto err;
971
972     if (mt && mtext_nchars (mt) > 0)
973       {
974         cs = fc_build_charset (NULL, mt);       
975         if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
976           goto err;
977       }
978     else
979       {
980         if (! (ls = FcLangSetCreate ()))
981           goto err;
982         if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
983             || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
984           goto err;
985       }
986
987     plist = fc_list_pattern (pattern);
988   err:
989     if (cs) FcCharSetDestroy (cs);
990     if (ls) FcLangSetDestroy (ls);
991     if (pattern) FcPatternDestroy (pattern);
992   }
993 #else   /* not HAVE_FONTCONFIG */
994   if (mt && mtext_nchars (mt) > 0)
995     plist = ft_list_char_list (NULL, mt);
996 #endif  /* not HAVE_FONTCONFIG */
997
998   mplist_push (ft_language_list, language, plist);
999   return plist;
1000 }
1001
1002 static MPlist *
1003 ft_list_script (MSymbol script)
1004 {
1005   MPlist *plist = NULL;
1006   MPlist *char_list;
1007
1008   if (! ft_script_list)
1009     ft_script_list = mplist ();
1010   else if ((plist = mplist_find_by_key (ft_script_list, script)))
1011     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1012
1013   char_list = mscript__char_list (script);
1014
1015 #ifdef HAVE_FONTCONFIG
1016   if (char_list)
1017     {
1018       FcPattern *pattern = NULL;
1019       FcCharSet *cs;
1020
1021       if (! (pattern = FcPatternCreate ()))
1022         goto err;
1023       cs = fc_build_charset (char_list, NULL);
1024       if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1025           goto err;
1026       plist = fc_list_pattern (pattern);
1027     err:
1028       if (cs) FcCharSetDestroy (cs);
1029       if (pattern) FcPatternDestroy (pattern);
1030     }
1031 #else  /* not HAVE_FONTCONFIG */
1032   if (char_list)
1033     plist = ft_list_char_list (char_list, NULL);
1034 #endif  /* not HAVE_FONTCONFIG */
1035
1036   mplist_push (ft_script_list, script, plist);
1037   return (plist);
1038 }
1039
1040 static int
1041 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1042 {
1043 #ifdef HAVE_OTF
1044   if (ft_info->otf == invalid_otf)
1045     return -1;
1046   if (! ft_info->otf)
1047     {
1048 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1049       if (ft_face)
1050         ft_info->otf = OTF_open_ft_face (ft_face);
1051       else
1052 #endif
1053         ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1054       if (! ft_info->otf)
1055         {
1056           ft_info->otf = invalid_otf;
1057           return -1;
1058         }
1059     }
1060   if (cap->features[MFONT_OTT_GSUB].nfeatures
1061       && cap->features[MFONT_OTT_GSUB].tags[0]
1062       && (OTF_check_features
1063           (ft_info->otf, 1,
1064            cap->script_tag, cap->langsys_tag,
1065            cap->features[MFONT_OTT_GSUB].tags,
1066            cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1067     return -1;
1068   if (cap->features[MFONT_OTT_GPOS].nfeatures
1069       && cap->features[MFONT_OTT_GPOS].tags[0]
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
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
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 *
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 *
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 *
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 *
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 *
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
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
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
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
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
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
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 
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 *
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_DUMP (" [FONT-FT] encapsulating ", (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
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 static OTF *
2147 get_otf (MFLTFont *font, FT_Face *ft_face)
2148 {
2149   MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2150   MFontFT *ft_info = (MFontFT *) rfont->font;
2151   MRealizedFontFT *ft_rfont = rfont->info;
2152   OTF *otf = ft_info->otf;
2153
2154   if (! otf)
2155     {
2156 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2157       otf = OTF_open_ft_face (ft_rfont->ft_face);
2158 #else
2159       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2160 #endif
2161       if (! otf || OTF_get_table (otf, "head") < 0)
2162         otf = invalid_otf;
2163       ft_info->otf = otf;
2164     }
2165   if (ft_face)
2166     *ft_face = ft_rfont->ft_face;
2167   return (otf == invalid_otf ? NULL : otf);
2168 }
2169
2170 static int 
2171 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2172 {
2173 #ifdef HAVE_OTF
2174   OTF_Tag *tags;
2175   int i, n, negative;
2176   OTF *otf = get_otf (font, NULL);
2177
2178   if (! otf)
2179     goto not_otf;
2180   for (i = 0; i < 2; i++)
2181     {
2182       if (! spec->features[i])
2183         continue;
2184       for (n = 0; spec->features[i][n]; n++);
2185       tags = alloca (sizeof (OTF_Tag) * n);
2186       for (n = 0, negative = 0; spec->features[i][n]; n++)
2187         {
2188           if (spec->features[i][n] == 0xFFFFFFFF)
2189             negative = 1;
2190           else if (negative)
2191             tags[n - 1] = spec->features[i][n] | 0x80000000;
2192           else
2193             tags[n] = spec->features[i][n];
2194         }
2195       if (n - negative > 0
2196           && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2197                                  tags, n - negative) != 1)
2198         return 0;
2199     }
2200   return 1;
2201 #endif  /* HAVE_OTF */
2202  not_otf:
2203   return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
2204           && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
2205 }
2206
2207 #ifdef HAVE_OTF
2208
2209 #define DEVICE_DELTA(table, size)                               \
2210   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
2211    ? (table).DeltaValue[(size) - (table).StartSize] << 6        \
2212    : 0)
2213
2214 void
2215 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2216                unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2217 {
2218   if (anchor->AnchorFormat == 2)
2219     {
2220       FT_Outline *outline;
2221       int ap = anchor->f.f1.AnchorPoint;
2222
2223       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2224       outline = &ft_face->glyph->outline;
2225       if (ap < outline->n_points)
2226         {
2227           *x = outline->points[ap].x << 6;
2228           *y = outline->points[ap].y << 6;
2229         }
2230     }
2231   else if (anchor->AnchorFormat == 3)
2232     {
2233       if (anchor->f.f2.XDeviceTable.offset)
2234         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2235       if (anchor->f.f2.YDeviceTable.offset)
2236         *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2237     }
2238 }
2239 #endif  /* HAVE_OTF */
2240
2241 static int 
2242 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2243               MFLTGlyphString *in, int from, int to,
2244               MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2245 {
2246   int len = to - from;
2247   int i, j, gidx;
2248 #ifdef HAVE_OTF
2249   MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2250   MGlyph *out_glyphs = (MGlyph *) (out->glyphs);
2251   OTF *otf;
2252   FT_Face face;
2253   OTF_GlyphString otf_gstring;
2254   OTF_Glyph *otfg;
2255   char script[5], *langsys = NULL;
2256   char *gsub_features = NULL, *gpos_features = NULL;
2257
2258   if (len == 0)
2259     return from;
2260   otf = get_otf (font, &face);
2261   if (! otf)
2262     goto simple_copy;
2263   OTF_tag_name (spec->script, script);
2264   if (spec->langsys)
2265     {
2266       langsys = alloca (5);
2267       OTF_tag_name (spec->langsys, langsys);
2268     }
2269   for (i = 0; i < 2; i++)
2270     {
2271       char *p;
2272
2273       if (spec->features[i])
2274         {
2275           for (j = 0; spec->features[i][j]; j++);
2276           if (i == 0)
2277             p = gsub_features = alloca (6 * j);
2278           else
2279             p = gpos_features = alloca (6 * j);
2280           for (j = 0; spec->features[i][j]; j++)
2281             {
2282               if (spec->features[i][j] == 0xFFFFFFFF)
2283                 *p++ = '*', *p++ = ',';
2284               else
2285                 {
2286                   OTF_tag_name (spec->features[i][j], p);
2287                   p[4] = ',';
2288                   p += 5;
2289                 }
2290             }
2291           *--p = '\0';
2292         }
2293     }
2294
2295   otf_gstring.size = otf_gstring.used = len;
2296   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2297   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2298   for (i = 0; i < len; i++)
2299     {
2300       otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c;
2301       otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2302     }
2303
2304   OTF_drive_gdef (otf, &otf_gstring);
2305   gidx = out->used;
2306
2307   if (gsub_features)
2308     {
2309       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2310           < 0)
2311         goto simple_copy;
2312       if (out->allocated < out->used + otf_gstring.used)
2313         return -2;
2314       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2315         {
2316           MGlyph *g = out_glyphs + out->used;
2317           int j;
2318           int min_from, max_to;
2319
2320           *g = in_glyphs[from + otfg->f.index.from];
2321           min_from = g->g.from, max_to = g->g.to;
2322           g->g.c = 0;
2323           for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2324             if (in_glyphs[from + j].g.code == otfg->glyph_id)
2325               {
2326                 g->g.c = in_glyphs[from + j].g.c;
2327                 break;
2328               }
2329           for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2330             {
2331               if (min_from > in_glyphs[from + j].g.from)
2332                 min_from = in_glyphs[from + j].g.from;
2333               if (max_to < in_glyphs[from + j].g.to)
2334                 max_to = in_glyphs[from + j].g.to;
2335             }
2336           if (g->g.code != otfg->glyph_id)
2337             {
2338               g->g.code = otfg->glyph_id;
2339               g->g.measured = 0;
2340             }
2341           g->g.from = min_from, g->g.to = max_to;
2342           out->used++;
2343         }
2344     }
2345   else
2346     {
2347       if (out->allocated < out->used + len)
2348         return -2;
2349       for (i = 0; i < len; i++)
2350         out_glyphs[out->used++] = in_glyphs[from + i];
2351     }
2352
2353   if (gpos_features)
2354     {
2355       MGlyph *base = NULL, *mark = NULL, *g;
2356       int x_ppem, y_ppem, x_scale, y_scale;
2357
2358 #ifdef HAVE_OTF_DRIVE_GPOS2
2359       if (OTF_drive_gpos2 (otf, &otf_gstring, script, langsys, gpos_features)
2360           < 0)
2361         return to;
2362 #else  /* not HAVE_OTF_DRIVE_GPOS2 */
2363       if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2364           < 0)
2365         return to;
2366 #endif  /* not HAVE_OTF_DRIVE_GPOS2 */
2367
2368       x_ppem = face->size->metrics.x_ppem;
2369       y_ppem = face->size->metrics.y_ppem;
2370       x_scale = face->size->metrics.x_scale;
2371       y_scale = face->size->metrics.y_scale;
2372
2373       for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2374            i < otf_gstring.used; i++, otfg++)
2375         {
2376           MGlyph *prev;
2377           int adjust_idx = otfg->glyph_id ? j : j - 1;
2378
2379           switch (otfg->positioning_type)
2380             {
2381             case 0:
2382               break;
2383             case 1:             /* Single */
2384             case 2:             /* Pair */
2385               {
2386                 int format = otfg->f.f1.format;
2387
2388                 if (format & OTF_XPlacement)
2389                   adjustment[adjust_idx].xoff
2390                     += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2391                 if (format & OTF_XPlaDevice)
2392                   adjustment[adjust_idx].xoff
2393                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2394                 if (format & OTF_YPlacement)
2395                   adjustment[adjust_idx].yoff
2396                     -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2397                 if (format & OTF_YPlaDevice)
2398                   adjustment[adjust_idx].yoff
2399                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2400                 if (format & OTF_XAdvance)
2401                   adjustment[adjust_idx].xadv
2402                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2403                 if (format & OTF_XAdvDevice)
2404                   adjustment[adjust_idx].xadv
2405                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2406                 if (format & OTF_YAdvance)
2407                   adjustment[adjust_idx].yadv
2408                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2409                 if (format & OTF_YAdvDevice)
2410                   adjustment[adjust_idx].yadv
2411                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2412                 adjustment[adjust_idx].set = 1;
2413               }
2414               break;
2415             case 3:             /* Cursive */
2416               /* Not yet supported.  */
2417               break;
2418             case 4:             /* Mark-to-Base */
2419             case 5:             /* Mark-to-Ligature */
2420               if (! base)
2421                 break;
2422               prev = base;
2423               goto label_adjust_anchor;
2424             default:            /* i.e. case 6 Mark-to-Mark */
2425               if (! mark)
2426                 break;
2427               prev = mark;
2428
2429             label_adjust_anchor:
2430               {
2431                 int base_x, base_y, mark_x, mark_y;
2432                 int this_from, this_to;
2433                 int k;
2434
2435                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2436                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2437                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2438                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2439
2440                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2441                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2442                                  x_ppem, y_ppem, &base_x, &base_y);
2443                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2444                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2445                                  x_ppem, y_ppem, &mark_x, &mark_y);
2446                 adjustment[adjust_idx].xoff = base_x - mark_x;
2447                 adjustment[adjust_idx].yoff = - (base_y - mark_y);
2448                 adjustment[adjust_idx].back = (g - prev);
2449                 adjustment[adjust_idx].xadv = 0;
2450                 adjustment[adjust_idx].advance_is_absolute = 1;
2451                 adjustment[adjust_idx].set = 1;
2452                 this_from = g->g.from;
2453                 this_to = g->g.to;
2454                 for (k = 0; prev + k < g; k++)
2455                   {
2456                     if (this_from > prev[k].g.from)
2457                       this_from = prev[k].g.from;
2458                     if (this_to < prev[k].g.to)
2459                       this_to = prev[k].g.to;
2460                   }
2461                 for (; prev <= g; prev++)
2462                   {
2463                     prev->g.from = this_from;
2464                     prev->g.to = this_to;
2465                   }
2466               }
2467             }
2468           if (otfg->glyph_id)
2469             {
2470               if (otfg->GlyphClass == OTF_GlyphClass0)
2471                 base = mark = g;
2472               else if (otfg->GlyphClass == OTF_GlyphClassMark)
2473                 mark = g;
2474               else
2475                 base = g;
2476               j++, g++;
2477             }
2478         }
2479     }
2480   free (otf_gstring.glyphs);
2481   return to;
2482
2483  simple_copy:
2484   if (otf_gstring.glyphs)
2485     free (otf_gstring.glyphs);
2486 #endif  /* HAVE_OTF */
2487   if (out->allocated < out->used + len)
2488     return -2;
2489   font->get_metrics (font, in, from, to);
2490   memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2491           sizeof (MGlyph) * len);
2492   out->used += len;
2493   return to;
2494 }
2495
2496 #ifdef HAVE_OTF
2497 static unsigned char *iterate_bitmap;
2498
2499 static int
2500 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2501 {
2502   if (glyph_id <= otf->cmap->max_glyph_id)
2503     iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2504   return 0;
2505 }
2506
2507 static int
2508 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2509                         int from, int to, unsigned char *table)
2510 {
2511   OTF *otf = get_otf (font, NULL);
2512   char id[13];
2513   int bmp_size;
2514   unsigned char *bitmap = NULL;
2515   int i, j;
2516   char script[5], *langsys = NULL;
2517
2518   if (! otf)
2519     return -1;
2520   if (OTF_get_table (otf, "cmap") < 0)
2521     return -1;
2522   if (! spec->features[0])
2523     return -1;
2524   strcpy (id, "feature-");
2525   id[12] = '\0';
2526   OTF_tag_name (spec->script, script);
2527   if (spec->langsys)
2528     {
2529       langsys = alloca (5);
2530       OTF_tag_name (spec->langsys, langsys);
2531     }
2532   bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2533   for (i = 0; spec->features[0][i]; i++)
2534     {
2535       unsigned char *bmp;
2536
2537       OTF_tag_name (spec->features[0][i], id + 8);
2538       bmp = OTF_get_data (otf, id);
2539       if (! bmp)
2540         {
2541           iterate_bitmap = bmp = calloc (bmp_size, 1);
2542           OTF_iterate_gsub_feature (otf, iterate_callback,
2543                                     script, langsys, id + 8);
2544           OTF_put_data (otf, id, bmp, free);
2545         }
2546       if (i == 0 && ! spec->features[0][1])
2547         /* Single feature */
2548         bitmap = bmp;
2549       else
2550         {
2551           if (! bitmap)
2552             {
2553               bitmap = alloca (bmp_size);
2554               memcpy (bitmap, bmp, bmp_size);
2555             }
2556           else
2557             {
2558               int j;
2559
2560               for (j = 0; j < bmp_size; j++)
2561                 bitmap[j] &= bmp[j];
2562             }
2563         }
2564     }
2565   for (i = 0; i < bmp_size; i++)
2566     if (bitmap[i])
2567       {
2568         for (j = 0; j < 8; j++)
2569           if (bitmap[i] & (1 << j))
2570             {
2571               int c = OTF_get_unicode (otf, (i * 8) + j);
2572
2573               if (c >= from && c <= to)
2574                 table[c - from] = 1;
2575             }
2576       }
2577   return 0;
2578 }
2579 #endif
2580
2581
2582 \f
2583 /* Internal API */
2584
2585 MFontDriver mfont__ft_driver =
2586   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2587     ft_render, ft_list, ft_list_family_names, ft_check_capability,
2588     ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf,
2589 #ifdef HAVE_OTF
2590     ft_iterate_otf_feature
2591 #endif  /* HAVE_OTF */
2592   };
2593
2594 int
2595 mfont__ft_init ()
2596 {
2597   int i;
2598
2599   if (FT_Init_FreeType (&ft_library) != 0)
2600     MERROR (MERROR_FONT_FT, -1);
2601
2602   for (i = 0; i < ft_to_prop_size; i++)
2603     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2604
2605   Mmedium = msymbol ("medium");
2606   Mr = msymbol ("r");
2607   Mnull = msymbol ("");
2608
2609   M0[0] = msymbol ("0-0");
2610   M0[1] = msymbol ("0-1");
2611   M0[2] = msymbol ("0-2");
2612   M0[3] = msymbol ("0-3");
2613   M0[4] = msymbol ("0-4");
2614   M3_1 = msymbol ("3-1");
2615   M1_0 = msymbol ("1-0");
2616
2617 #ifdef HAVE_FONTCONFIG
2618   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2619     {
2620       FC_vs_M17N_font_prop *table = fc_all_table[i];
2621       int j;
2622
2623       for (j = 0; table[j].m17n_value; j++)
2624         table[j].sym = msymbol (table[j].m17n_value);
2625       table[j].sym = table[j - 1].sym;
2626     }
2627
2628   {
2629     char *pathname;
2630     struct stat buf;
2631     MPlist *plist;
2632     MSymbol serif, sans_serif, monospace;
2633
2634     fc_config = FcInitLoadConfigAndFonts ();
2635     if (mfont_freetype_path)
2636       {
2637         MPLIST_DO (plist, mfont_freetype_path)
2638           if (MPLIST_STRING_P (plist)
2639               && (pathname = MPLIST_STRING (plist))
2640               && stat (pathname, &buf) == 0)
2641             {
2642               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2643               FcChar8 *dir;
2644
2645               while ((dir = FcStrListNext (strlist)))
2646                 if (strcmp ((char *) dir, pathname) == 0)
2647                   break;
2648               if (! dir)
2649                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2650               FcStrListDone (strlist);
2651             }
2652       }
2653     Mgeneric_family = msymbol ("generic famly");
2654     serif = msymbol ("serif");
2655     msymbol_put (serif, Mgeneric_family, serif);
2656     sans_serif = msymbol ("sans-serif");
2657     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2658     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2659     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2660     monospace = msymbol ("monospace");
2661     msymbol_put (monospace, Mgeneric_family, monospace);
2662     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2663   }
2664 #endif  /* HAVE_FONTCONFIG */
2665
2666   return 0;
2667 }
2668
2669 void
2670 mfont__ft_fini ()
2671 {
2672   MPlist *plist, *p;
2673
2674   if (ft_default_list)
2675     {
2676       M17N_OBJECT_UNREF (ft_default_list);
2677       ft_default_list = NULL;
2678     }
2679
2680   if (ft_font_list)
2681     {
2682       MPLIST_DO (plist, ft_font_list)
2683         {
2684           if (MPLIST_VAL (plist))
2685             MPLIST_DO (p, MPLIST_VAL (plist))
2686               {
2687                 if (MPLIST_KEY (p) != Mt)
2688                   free_ft_info (MPLIST_VAL (p));
2689               }
2690           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2691         }
2692       M17N_OBJECT_UNREF (ft_font_list);
2693       ft_font_list = NULL;
2694
2695       if (ft_language_list)
2696         {
2697           MPLIST_DO (plist, ft_language_list)
2698             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2699           M17N_OBJECT_UNREF (ft_language_list);
2700           ft_language_list = NULL;
2701         }
2702
2703       if (ft_script_list)
2704         {
2705           MPLIST_DO (plist, ft_script_list)
2706             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2707           M17N_OBJECT_UNREF (ft_script_list);
2708           ft_script_list = NULL;
2709         }
2710
2711       if (ft_capability_list)
2712         {
2713           MPLIST_DO (plist, ft_capability_list)
2714             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2715           M17N_OBJECT_UNREF (ft_capability_list);
2716           ft_capability_list = NULL;
2717         }
2718
2719       if (ft_file_list)
2720         {
2721           MPLIST_DO (plist, ft_file_list)
2722             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2723           M17N_OBJECT_UNREF (ft_file_list);
2724           ft_file_list = NULL;
2725         }
2726     }
2727   FT_Done_FreeType (ft_library);
2728 #ifdef HAVE_FONTCONFIG
2729   FcConfigDestroy (fc_config);
2730   fc_config = NULL;
2731 #endif  /* HAVE_FONTCONFIG */
2732   all_fonts_scaned = 0;
2733 }
2734
2735 #ifdef HAVE_FONTCONFIG
2736
2737 int
2738 mfont__ft_parse_name (const char *name, MFont *font)
2739 {
2740   FcPattern *pat = FcNameParse ((FcChar8 *) name);
2741   FcChar8 *str;
2742   int val;
2743   double size;
2744   char *buf;
2745   int bufsize = 0;
2746   
2747   if (! pat)
2748     return -1;
2749   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2750     {
2751       STRDUP_LOWER (buf, bufsize, (char *) str);
2752       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2753     }
2754   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2755     {
2756       STRDUP_LOWER (buf, bufsize, (char *) str);
2757       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2758     }
2759   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2760     mfont__set_property (font, MFONT_WEIGHT,
2761                          fc_decode_prop (val, fc_weight_table,
2762                                          fc_weight_table_size));
2763   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2764     mfont__set_property (font, MFONT_STYLE,
2765                          fc_decode_prop (val, fc_slant_table,
2766                                          fc_slant_table_size));
2767   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2768     mfont__set_property (font, MFONT_STRETCH,
2769                          fc_decode_prop (val, fc_width_table,
2770                                          fc_width_table_size));
2771   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2772     font->size = size * 10 + 0.5;
2773   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2774     font->size = - (size * 10 + 0.5);
2775   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2776     {
2777       font->file = msymbol ((char *) str);
2778     }
2779   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2780   font->type = MFONT_TYPE_SPEC;
2781   FcPatternDestroy (pat);
2782   return 0;
2783 }
2784
2785 char *
2786 mfont__ft_unparse_name (MFont *font)
2787 {
2788   FcPattern *pat = fc_get_pattern (font);
2789   char *name = (char *) FcNameUnparse (pat);
2790
2791   FcPatternDestroy (pat);
2792   return name;
2793 }
2794 #endif  /* HAVE_FONTCONFIG */
2795
2796 #endif /* HAVE_FREETYPE */