merge FLT
[m17n/m17n-lib.git] / src / font-ft.c
1 /* font-ft.c -- FreeType interface sub-module.
2    Copyright (C) 2003, 2004
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);
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));
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);
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)
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);
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);
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);
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
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));
918               if (! MPLIST_TAIL_P (p))
919                 MPLIST_DO (p, p)
920                   mplist_push (pl, Mt, MPLIST_VAL (p));
921             }
922         }
923     }
924
925 #else  /* not HAVE_FONTCONFIG */
926
927   if (! all_fonts_scaned)
928     {
929       ft_init_font_list ();
930       all_fonts_scaned = 1;
931     }
932   if (family == Mnil)
933     plist = ft_font_list;
934   else
935     {
936       plist = mplist_find_by_key (ft_font_list, family);
937       if (! plist)
938         plist = mplist_push (ft_font_list, family, mplist ());
939     }
940 #endif  /* not HAVE_FONTCONFIG */
941
942   return plist;
943 }
944
945 static MPlist *
946 ft_list_language (MSymbol language)
947 {
948   MPlist *plist = NULL;
949   MText *mt;
950
951   if (! ft_language_list)
952     ft_language_list = mplist ();
953   else if ((plist = mplist_find_by_key (ft_language_list, language)))
954     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
955
956   mt = mlanguage_text (language);
957
958 #ifdef HAVE_FONTCONFIG
959   {
960     FcPattern *pattern = NULL;
961     FcCharSet *cs = NULL;
962     FcLangSet *ls = NULL;
963
964     if (! (pattern = FcPatternCreate ()))
965       goto err;
966
967     if (mt && mtext_nchars (mt) > 0)
968       {
969         cs = fc_build_charset (NULL, mt);       
970         if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
971           goto err;
972       }
973     else
974       {
975         if (! (ls = FcLangSetCreate ()))
976           goto err;
977         if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
978             || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
979           goto err;
980       }
981
982     plist = fc_list_pattern (pattern);
983   err:
984     if (cs) FcCharSetDestroy (cs);
985     if (ls) FcLangSetDestroy (ls);
986     if (pattern) FcPatternDestroy (pattern);
987   }
988 #else   /* not HAVE_FONTCONFIG */
989   if (mt && mtext_nchars (mt) > 0)
990     plist = ft_list_char_list (NULL, mt);
991 #endif  /* not HAVE_FONTCONFIG */
992
993   mplist_push (ft_language_list, language, plist);
994   return plist;
995 }
996
997 static MPlist *
998 ft_list_script (MSymbol script)
999 {
1000   MPlist *plist = NULL;
1001   MPlist *char_list;
1002
1003   if (! ft_script_list)
1004     ft_script_list = mplist ();
1005   else if ((plist = mplist_find_by_key (ft_script_list, script)))
1006     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1007
1008   char_list = mscript__char_list (script);
1009
1010 #ifdef HAVE_FONTCONFIG
1011   if (char_list)
1012     {
1013       FcPattern *pattern = NULL;
1014       FcCharSet *cs;
1015
1016       if (! (pattern = FcPatternCreate ()))
1017         goto err;
1018       cs = fc_build_charset (char_list, NULL);
1019       if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1020           goto err;
1021       plist = fc_list_pattern (pattern);
1022     err:
1023       if (cs) FcCharSetDestroy (cs);
1024       if (pattern) FcPatternDestroy (pattern);
1025     }
1026 #else  /* not HAVE_FONTCONFIG */
1027   if (char_list)
1028     plist = ft_list_char_list (char_list, NULL);
1029 #endif  /* not HAVE_FONTCONFIG */
1030
1031   mplist_push (ft_script_list, script, plist);
1032   return (plist);
1033 }
1034
1035 static int
1036 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1037 {
1038 #ifdef HAVE_OTF
1039   if (ft_info->otf == invalid_otf)
1040     return -1;
1041   if (! ft_info->otf)
1042     {
1043 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1044       if (ft_face)
1045         ft_info->otf = OTF_open_ft_face (ft_face);
1046       else
1047 #endif
1048         ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1049       if (! ft_info->otf)
1050         {
1051           ft_info->otf = invalid_otf;
1052           return -1;
1053         }
1054     }
1055   if (cap->features[MFONT_OTT_GSUB].nfeatures
1056       && cap->features[MFONT_OTT_GSUB].tags[0]
1057       && (OTF_check_features
1058           (ft_info->otf, 1,
1059            cap->script_tag, cap->langsys_tag,
1060            cap->features[MFONT_OTT_GSUB].tags,
1061            cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1062     return -1;
1063   if (cap->features[MFONT_OTT_GPOS].nfeatures
1064       && cap->features[MFONT_OTT_GPOS].tags[0]
1065       && (OTF_check_features
1066           (ft_info->otf, 0,
1067            cap->script_tag, cap->langsys_tag,
1068            cap->features[MFONT_OTT_GPOS].tags,
1069            cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1070     return -1;
1071   return 0;
1072 #else   /* not HAVE_OTF */
1073   return -1;
1074 #endif  /* not HAVE_OTF */
1075 }
1076
1077 static int
1078 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1079 {
1080   MText *mt;
1081   MText *extra;
1082   int ft_face_allocaed = 0;
1083   int len, total_len;
1084   int i;
1085
1086 #ifdef HAVE_FONTCONFIG
1087   if (ft_info->langset
1088       && (FcLangSetHasLang (ft_info->langset,
1089                             (FcChar8 *) MSYMBOL_NAME (language))
1090           != FcLangDifferentLang))
1091     return 0;
1092 #endif  /* HAVE_FONTCONFIG */
1093
1094   mt = mlanguage_text (language);
1095   if (! mt || mtext_nchars (mt) == 0)
1096     return -1;
1097
1098   if (! ft_face)
1099     {
1100       char *filename = MSYMBOL_NAME (ft_info->font.file);
1101
1102       if (FT_New_Face (ft_library, filename, 0, &ft_face))
1103         return -1;
1104       ft_face_allocaed = 1;
1105     }
1106
1107   len = mtext_nchars (mt);
1108   extra = mtext_get_prop (mt, 0, Mtext);
1109   total_len = len + (extra ? mtext_nchars (extra) : 0);
1110
1111   for (i = 0; i < total_len; i++)
1112     {
1113       int c = (i < len ? mtext_ref_char (mt, i)
1114                : mtext_ref_char (extra, i - len));
1115
1116 #ifdef HAVE_FONTCONFIG
1117       if (ft_info->charset
1118           && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1119         break;
1120 #endif  /* HAVE_FONTCONFIG */
1121       if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1122         break;
1123     }
1124
1125   if (ft_face_allocaed)
1126     FT_Done_Face (ft_face);
1127
1128   return (i == total_len ? 0 : -1);
1129 }
1130
1131 static int
1132 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1133 {
1134   MPlist *char_list = mscript__char_list (script);
1135
1136   if (! char_list)
1137     return -1;
1138 #ifdef HAVE_FONTCONFIG
1139   if (ft_info->charset)
1140     {
1141       MPLIST_DO (char_list, char_list)
1142         if (FcCharSetHasChar (ft_info->charset,
1143                               (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1144           break;
1145     }
1146   else
1147 #endif  /* HAVE_FONTCONFIG */
1148     {
1149       int ft_face_allocaed = 0;
1150
1151       if (! ft_face)
1152         {
1153           char *filename = MSYMBOL_NAME (ft_info->font.file);
1154
1155           if (FT_New_Face (ft_library, filename, 0, &ft_face))
1156             return -1;
1157           ft_face_allocaed = 1;
1158         }
1159
1160       MPLIST_DO (char_list, char_list)
1161         if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1162             == 0)
1163           break;
1164       if (ft_face_allocaed)
1165         FT_Done_Face (ft_face);
1166     }
1167
1168   return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1169 }
1170
1171 static MPlist *ft_default_list;
1172
1173 static MPlist *
1174 ft_list_default ()
1175 {
1176   if (ft_default_list)
1177     return ft_default_list;
1178   ft_default_list = mplist ();
1179 #ifdef HAVE_FONTCONFIG
1180   {
1181     FcPattern *pat = FcPatternCreate ();
1182     FcChar8 *fam;
1183     char *buf;
1184     int bufsize = 0;
1185     int i;
1186
1187     FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1188     for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1189          i++)
1190       {
1191         MSymbol family;
1192         MPlist *plist;
1193
1194         STRDUP_LOWER (buf, bufsize, (char *) fam);
1195         family = msymbol (buf);
1196         if (msymbol_get (family, Mgeneric_family))
1197           continue;
1198         plist = MPLIST_PLIST (ft_list_family (family, 0));
1199         MPLIST_DO (plist, plist)
1200           mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1201       }
1202   }
1203 #else  /* not HAVE_FONTCONFIG */
1204   {
1205     MPlist *plist, *pl;
1206
1207     MPLIST_DO (plist, ft_list_family (Mnil, 0))
1208       {
1209         pl = MPLIST_PLIST (plist);
1210         if (! MPLIST_TAIL_P (pl))
1211           mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1212       }
1213   }
1214 #endif  /* not HAVE_FONTCONFIG */
1215   return ft_default_list;
1216 }
1217
1218
1219 static MPlist *ft_capability_list;
1220
1221 static MPlist *
1222 ft_list_capability (MSymbol capability)
1223 {
1224   MFontCapability *cap;
1225   MPlist *plist = NULL, *pl;
1226
1227   if (! ft_capability_list)
1228     ft_capability_list = mplist ();
1229   else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1230     return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1231
1232   cap = mfont__get_capability (capability);
1233
1234   if (cap && cap->language != Mnil)
1235     {
1236       plist = ft_list_language (cap->language);
1237       if (! plist)
1238         return NULL;
1239       plist = mplist_copy (plist);
1240     }
1241
1242   if (cap && cap->script != Mnil)
1243     {
1244       if (! plist)
1245         {
1246           plist = ft_list_script (cap->script);
1247           if (! plist)
1248             return NULL;
1249           plist = mplist_copy (plist);
1250         }
1251       else
1252         {
1253           for (pl = plist; ! MPLIST_TAIL_P (pl);)
1254             {
1255               if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1256                 mplist_pop (pl);
1257               else
1258                 pl = MPLIST_NEXT (pl);
1259             }
1260         }
1261
1262       if (cap->script_tag)
1263         {
1264           for (pl = plist; ! MPLIST_TAIL_P (pl);)
1265             {
1266               if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1267                 mplist_pop (pl);
1268               else
1269                 pl = MPLIST_NEXT (pl);
1270             }
1271         }
1272
1273       if (MPLIST_TAIL_P (plist))
1274         {
1275           M17N_OBJECT_UNREF (plist);
1276           plist = NULL;
1277         }
1278     }
1279
1280   mplist_push (ft_capability_list, capability, plist);
1281   return plist;
1282 }
1283
1284
1285 static MPlist *
1286 ft_list_file (MSymbol filename)
1287 {
1288   MPlist *plist = NULL;
1289
1290   if (! ft_file_list)
1291     ft_file_list = mplist ();
1292   else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1293     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1294
1295 #ifdef HAVE_FONTCONFIG
1296   {
1297     FcPattern *pattern = FcPatternCreate ();
1298     FcObjectSet *os;
1299     FcFontSet *fs;
1300
1301     FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1302     os = FcObjectSetBuild (FC_FAMILY, NULL);
1303     fs = FcFontList (fc_config, pattern, os);
1304     if (fs->nfont > 0)
1305       {
1306         char *fam;
1307         char *buf;
1308         int bufsize = 0;
1309
1310         if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1311                                 (FcChar8 **) &fam) == FcResultMatch)
1312           {
1313             MSymbol family;
1314             MPlist *pl;
1315
1316             STRDUP_LOWER (buf, bufsize, fam);
1317             family = msymbol (buf);
1318             pl = ft_list_family (family, 0);
1319             MPLIST_DO (pl, MPLIST_PLIST (pl))
1320               {
1321                 MFontFT *ft_info = MPLIST_VAL (pl);
1322
1323                 if (ft_info->font.file == filename)
1324                   {
1325                     plist = mplist ();
1326                     mplist_add (plist, family, ft_info);
1327                     break;
1328                   }
1329               }
1330           }
1331       }
1332   }
1333 #else  /* not HAVE_FONTCONFIG */
1334   {
1335     MPlist *pl, *p;
1336
1337     MPLIST_DO (pl, ft_list_family (Mnil, 0))
1338       {
1339         MPLIST_DO (p, MPLIST_PLIST (pl))
1340           {
1341             MFontFT *ft_info = MPLIST_VAL (pl);
1342
1343             if (ft_info->font.file == filename)
1344               {
1345                 plist = mplist ();
1346                 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1347                 break;
1348               }
1349           }
1350         if (plist)
1351           break;
1352       }
1353   }
1354 #endif  /* not HAVE_FONTCONFIG */
1355
1356   mplist_push (ft_file_list, filename, plist);
1357   return plist;
1358 }
1359
1360 /* The FreeType font driver function SELECT.  */
1361
1362 static MFont *
1363 ft_select (MFrame *frame, MFont *font, int limited_size)
1364 {
1365   MFont *found = NULL;
1366 #ifdef HAVE_FONTCONFIG
1367   MPlist *plist, *pl;
1368   MFontFT *ft_info;
1369   int check_font_property = 1;
1370
1371   if (font->file != Mnil)
1372     {
1373       plist = ft_list_file (font->file);
1374       if (! plist)
1375         return NULL;
1376       check_font_property = 0;
1377     }
1378   else
1379     {
1380       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1381
1382       if (family)
1383         plist = MPLIST_PLIST (ft_list_family (family, 1));
1384       else
1385         plist = ft_list_default ();
1386       if (MPLIST_TAIL_P (plist))
1387         return NULL;
1388     }
1389
1390   plist = mplist_copy (plist);
1391
1392   if (font->capability != Mnil)
1393     {
1394       MFontCapability *cap = mfont__get_capability (font->capability);
1395
1396       for (pl = plist; ! MPLIST_TAIL_P (pl);)
1397         {
1398           if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1399             {
1400               mplist_pop (pl);
1401               continue;
1402             }
1403           if (cap->language
1404               && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1405             mplist_pop (pl);
1406           else
1407             pl = MPLIST_NEXT (pl);
1408         }
1409     }
1410
1411   if (check_font_property)
1412     {
1413       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1414       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1415       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1416       MSymbol alternate_weight = Mnil;
1417
1418       if (weight == Mnormal)
1419         alternate_weight = Mmedium;
1420       else if (weight == Mmedium)
1421         alternate_weight = Mnormal;
1422       if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1423         for (pl = plist; ! MPLIST_TAIL_P (pl); )
1424           {
1425             ft_info = MPLIST_VAL (pl);
1426             if ((weight != Mnil
1427                  && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1428                      && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1429                 || (style != Mnil
1430                     && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1431                 || (stretch != Mnil
1432                     && stretch != FONT_PROPERTY (&ft_info->font,
1433                                                  MFONT_STRETCH))
1434                 || (font->size > 0
1435                     && ft_info->font.size > 0
1436                     && ft_info->font.size != font->size))
1437               mplist_pop (pl);
1438             else
1439               pl = MPLIST_NEXT (pl);
1440           }
1441     }
1442
1443   MPLIST_DO (pl, plist)
1444     {
1445       font = MPLIST_VAL (plist);
1446       if (limited_size == 0
1447           || font->size == 0
1448           || font->size <= limited_size)
1449         {
1450           found = font;
1451           break;
1452         }
1453     }
1454   M17N_OBJECT_UNREF (plist);
1455 #endif  /* HAVE_FONTCONFIG */
1456   return found;
1457 }
1458
1459
1460 static MRealizedFont *
1461 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1462 {
1463   MFontFT *ft_info = (MFontFT *) font;
1464   int reg = spec->property[MFONT_REGISTRY];
1465   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1466   MRealizedFontFT *ft_rfont;
1467   FT_Face ft_face;
1468   MPlist *plist, *charmap_list = NULL;
1469   int charmap_index;
1470   int size;
1471
1472   if (font->size)
1473     /* non-scalable font */
1474     size = font->size;
1475   else if (spec->size)
1476     {
1477       int ratio = mfont_resize_ratio (font);
1478
1479       size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1480     }
1481   else
1482     size = 120;
1483
1484   if (rfont)
1485     {
1486       charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1487       for (; rfont; rfont = rfont->next)
1488         if (rfont->font == font
1489             && (rfont->font->size ? rfont->font->size == size
1490                 : rfont->spec.size == size)
1491             && rfont->spec.property[MFONT_REGISTRY] == reg
1492             && rfont->driver == &mfont__ft_driver)
1493           return rfont;
1494     }
1495
1496   MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1497
1498   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1499                    &ft_face))
1500     {
1501       font->type = MFONT_TYPE_FAILURE;
1502       MDEBUG_PRINT ("  no (FT_New_Face)\n");
1503       return NULL;
1504     }
1505   if (charmap_list)
1506     M17N_OBJECT_REF (charmap_list);
1507   else
1508     charmap_list = ft_get_charmaps (ft_face);
1509   if (registry == Mnil)
1510     registry = Municode_bmp;
1511   plist = mplist_find_by_key (charmap_list, registry);
1512   if (! plist)
1513     {
1514       FT_Done_Face (ft_face);
1515       M17N_OBJECT_UNREF (charmap_list);
1516       MDEBUG_PRINT1 ("  no (%s)\n", MSYMBOL_NAME (registry));
1517       return NULL;
1518     }
1519   charmap_index = (int) MPLIST_VAL (plist);
1520   if ((charmap_index >= 0
1521        && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1522       || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1523     {
1524       FT_Done_Face (ft_face);
1525       M17N_OBJECT_UNREF (charmap_list);
1526       font->type = MFONT_TYPE_FAILURE;
1527       MDEBUG_PRINT1 ("  no (size %d)\n", size);
1528       return NULL;
1529     }
1530
1531   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1532   ft_rfont->ft_face = ft_face;
1533   ft_rfont->charmap_list = charmap_list;
1534   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1535   rfont->spec = *font;
1536   rfont->spec.type = MFONT_TYPE_REALIZED;
1537   rfont->spec.property[MFONT_REGISTRY] = reg;
1538   rfont->spec.size = size;
1539   rfont->frame = frame;
1540   rfont->font = font;
1541   rfont->driver = &mfont__ft_driver;
1542   rfont->info = ft_rfont;
1543   rfont->fontp = ft_face;
1544   rfont->ascent = ft_face->size->metrics.ascender;
1545   rfont->descent = - ft_face->size->metrics.descender;
1546   rfont->max_advance = ft_face->size->metrics.max_advance;
1547   rfont->baseline_offset = 0;
1548   rfont->x_ppem = ft_face->size->metrics.x_ppem;
1549   rfont->y_ppem = ft_face->size->metrics.y_ppem;
1550 #ifdef HAVE_FTBDF_H
1551   {
1552     BDF_PropertyRec prop;
1553
1554     if (! FT_IS_SCALABLE (ft_face)
1555         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1556       {
1557         rfont->baseline_offset = prop.u.integer << 6;
1558         rfont->ascent += prop.u.integer << 6;
1559         rfont->descent -= prop.u.integer << 6;
1560       }
1561   }
1562 #endif  /* HAVE_FTBDF_H */
1563   if (FT_IS_SCALABLE (ft_face))
1564     rfont->average_width = 0;
1565   else
1566     rfont->average_width = ft_face->available_sizes->width << 6;
1567   rfont->next = MPLIST_VAL (frame->realized_font_list);
1568   MPLIST_VAL (frame->realized_font_list) = rfont;
1569   MDEBUG_PRINT ("  ok\n");
1570   return rfont;
1571 }
1572
1573 /* The FreeType font driver function FIND_METRIC.  */
1574
1575 static void
1576 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1577                 int from, int to)
1578 {
1579   FT_Face ft_face = rfont->fontp;
1580   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1581
1582   for (; g != gend; g++)
1583     {
1584       if (g->g.measured)
1585         continue;
1586       if (g->g.code == MCHAR_INVALID_CODE)
1587         {
1588           if (FT_IS_SCALABLE (ft_face))
1589             {
1590               g->g.lbearing = 0;
1591               g->g.rbearing = ft_face->size->metrics.max_advance;
1592               g->g.xadv = g->g.rbearing;
1593               g->g.ascent = ft_face->size->metrics.ascender;
1594               g->g.descent = - ft_face->size->metrics.descender;
1595             }
1596           else
1597             {
1598 #ifdef HAVE_FTBDF_H
1599               BDF_PropertyRec prop;
1600 #endif  /* HAVE_FTBDF_H */
1601
1602               g->g.lbearing = 0;
1603               g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1604 #ifdef HAVE_FTBDF_H
1605               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1606                 {
1607                   g->g.ascent = prop.u.integer << 6;
1608                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1609                   g->g.descent = prop.u.integer << 6;
1610                   if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1611                                            & prop) == 0)
1612                     {
1613                       g->g.ascent += prop.u.integer << 6;
1614                       g->g.descent -= prop.u.integer << 6;
1615                     }
1616                 }
1617               else
1618 #endif  /* HAVE_FTBDF_H */
1619                 {
1620                   g->g.ascent = ft_face->available_sizes->height << 6;
1621                   g->g.descent = 0;
1622                 }
1623             }
1624         }
1625       else
1626         {
1627           FT_Glyph_Metrics *metrics;
1628
1629           FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
1630           metrics = &ft_face->glyph->metrics;
1631           g->g.lbearing = metrics->horiBearingX;
1632           g->g.rbearing = metrics->horiBearingX + metrics->width;
1633           g->g.xadv = metrics->horiAdvance;
1634           g->g.ascent = metrics->horiBearingY;
1635           g->g.descent = metrics->height - metrics->horiBearingY;
1636         }
1637       g->g.yadv = 0;
1638       g->g.ascent += rfont->baseline_offset;
1639       g->g.descent -= rfont->baseline_offset;
1640       g->g.measured = 1;
1641     }
1642 }
1643
1644 static int
1645 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1646 {
1647   MRealizedFont *rfont = NULL;
1648   MRealizedFontFT *ft_rfont;
1649   FT_UInt idx;
1650
1651   if (font->type == MFONT_TYPE_REALIZED)
1652     rfont = (MRealizedFont *) font;
1653   else if (font->type == MFONT_TYPE_OBJECT)
1654     {
1655       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1656            rfont = rfont->next)
1657         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1658           break;
1659       if (! rfont)
1660         {
1661 #ifdef HAVE_FONTCONFIG
1662           MFontFT *ft_info = (MFontFT *) font;
1663
1664           if (! ft_info->charset)
1665             {
1666               FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1667                                                MSYMBOL_NAME (font->file),
1668                                                NULL);
1669               FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1670               FcFontSet *fs = FcFontList (fc_config, pat, os);
1671
1672               if (fs->nfont > 0
1673                   && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1674                                           &ft_info->charset) == FcResultMatch)
1675                 ft_info->charset = FcCharSetCopy (ft_info->charset);
1676               else
1677                 ft_info->charset = FcCharSetCreate ();
1678               FcFontSetDestroy (fs);
1679               FcObjectSetDestroy (os);
1680               FcPatternDestroy (pat);
1681             }
1682           return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1683 #else  /* not HAVE_FONTCONFIG */
1684           rfont = ft_open (frame, font, spec, NULL);
1685 #endif  /* not HAVE_FONTCONFIG */
1686         }
1687     }
1688   else
1689     MFATAL (MERROR_FONT_FT);
1690
1691   if (! rfont)
1692     return 0;
1693   ft_rfont = rfont->info;
1694   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1695   return (idx != 0);
1696 }
1697
1698 /* The FreeType font driver function ENCODE_CHAR.  */
1699
1700 static unsigned
1701 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1702 {
1703   MRealizedFont *rfont;
1704   MRealizedFontFT *ft_rfont;
1705   FT_UInt idx;
1706
1707   if (font->type == MFONT_TYPE_REALIZED)
1708     rfont = (MRealizedFont *) font;
1709   else if (font->type == MFONT_TYPE_OBJECT)
1710     {
1711       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1712            rfont = rfont->next)
1713         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1714           break;
1715       if (! rfont)
1716         {
1717           rfont = ft_open (frame, font, spec, NULL);
1718           if (! rfont)
1719             return -1;
1720         }
1721     }
1722   else
1723     MFATAL (MERROR_FONT_FT);
1724
1725   ft_rfont = rfont->info;
1726   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1727   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1728 }
1729
1730 /* The FreeType font driver function RENDER.  */
1731
1732 #define NUM_POINTS 0x1000
1733
1734 typedef struct {
1735   MDrawPoint points[NUM_POINTS];
1736   MDrawPoint *p;
1737 } MPointTable;
1738
1739 static void
1740 ft_render (MDrawWindow win, int x, int y,
1741            MGlyphString *gstring, MGlyph *from, MGlyph *to,
1742            int reverse, MDrawRegion region)
1743 {
1744   FT_Face ft_face;
1745   MRealizedFace *rface = from->rface;
1746   MFrame *frame = rface->frame;
1747   FT_Int32 load_flags = FT_LOAD_RENDER;
1748   MGlyph *g;
1749   int i, j;
1750   MPointTable point_table[8];
1751   int baseline_offset;
1752   int pixel_mode = -1;
1753
1754   if (from == to)
1755     return;
1756
1757   /* It is assured that the all glyphs in the current range use the
1758      same realized face.  */
1759   ft_face = rface->rfont->fontp;
1760   baseline_offset = rface->rfont->baseline_offset >> 6;
1761
1762   if (! gstring->anti_alias)
1763     {
1764 #ifdef FT_LOAD_TARGET_MONO
1765       load_flags |= FT_LOAD_TARGET_MONO;
1766 #else
1767       load_flags |= FT_LOAD_MONOCHROME;
1768 #endif
1769     }
1770
1771   for (i = 0; i < 8; i++)
1772     point_table[i].p = point_table[i].points;
1773
1774   for (g = from; g < to; x += g++->g.xadv)
1775     {
1776       unsigned char *bmp;
1777       int intensity;
1778       MPointTable *ptable;
1779       int xoff, yoff;
1780       int width, pitch;
1781
1782       FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
1783       if (pixel_mode < 0)
1784         pixel_mode = ft_face->glyph->bitmap.pixel_mode;
1785       yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
1786       bmp = ft_face->glyph->bitmap.buffer;
1787       width = ft_face->glyph->bitmap.width;
1788       pitch = ft_face->glyph->bitmap.pitch;
1789
1790       if (pixel_mode != FT_PIXEL_MODE_MONO)
1791         for (i = 0; i < ft_face->glyph->bitmap.rows;
1792              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1793           {
1794             xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1795             for (j = 0; j < width; j++, xoff++)
1796               {
1797                 intensity = bmp[j] >> 5;
1798                 if (intensity)
1799                   {
1800                     ptable = point_table + intensity;
1801                     ptable->p->x = xoff;
1802                     ptable->p->y = yoff - baseline_offset;
1803                     ptable->p++;
1804                     if (ptable->p - ptable->points == NUM_POINTS)
1805                       {
1806                         (*frame->driver->draw_points)
1807                           (frame, win, rface,
1808                            reverse ? 7 - intensity : intensity,
1809                            ptable->points, NUM_POINTS, region);
1810                         ptable->p = ptable->points;
1811                       }
1812                   }
1813               }
1814           }
1815       else
1816         for (i = 0; i < ft_face->glyph->bitmap.rows;
1817              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1818           {
1819             xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1820             for (j = 0; j < width; j++, xoff++)
1821               {
1822                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1823                 if (intensity)
1824                   {
1825                     ptable = point_table;
1826                     ptable->p->x = xoff;
1827                     ptable->p->y = yoff - baseline_offset;
1828                     ptable->p++;
1829                     if (ptable->p - ptable->points == NUM_POINTS)
1830                       {
1831                         (*frame->driver->draw_points) (frame, win, rface,
1832                                            reverse ? 0 : 7,
1833                                            ptable->points, NUM_POINTS, region);
1834                         ptable->p = ptable->points;
1835                       }             
1836                   }
1837               }
1838         }
1839     }
1840
1841   if (pixel_mode != FT_PIXEL_MODE_MONO)
1842     {
1843       for (i = 1; i < 8; i++)
1844         if (point_table[i].p != point_table[i].points)
1845           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1846                              point_table[i].points,
1847                              point_table[i].p - point_table[i].points, region);
1848     }
1849   else
1850     {
1851       if (point_table[0].p != point_table[0].points)
1852         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1853                            point_table[0].points,
1854                            point_table[0].p - point_table[0].points, region);
1855     }
1856 }
1857
1858 static int
1859 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1860 {
1861   MPlist *pl = NULL, *p;
1862   int num = 0;
1863   MPlist *file_list = NULL;
1864   MPlist *family_list = NULL, *capability_list = NULL;
1865   MSymbol registry = Mnil;
1866
1867   MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1868
1869   if (font)
1870     {
1871       MSymbol family;
1872
1873       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1874       if (registry != Mnil && registry != Miso8859_1)
1875         {
1876           char *reg = MSYMBOL_NAME (registry);
1877
1878           if (strncmp (reg, "unicode-", 8)
1879               && strncmp (reg, "apple-roman", 11)
1880               && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1881             goto done;
1882         }
1883
1884       if (font->file != Mnil
1885           && ! (file_list = ft_list_file (font->file)))
1886         goto done;
1887       family = FONT_PROPERTY (font, MFONT_FAMILY);
1888       if (family != Mnil
1889           && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1890           && MPLIST_TAIL_P (family_list))
1891         goto done;
1892       if (font->capability != Mnil)
1893         {
1894           capability_list = ft_list_capability (font->capability);
1895           if (! capability_list || MPLIST_TAIL_P (capability_list))
1896             goto done;
1897         }
1898     }
1899
1900   if (! file_list && ! family_list && ! capability_list)
1901     {
1902       /* No restriction.  Get all fonts.  */
1903       pl = mplist ();
1904       MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1905         {
1906           MPLIST_DO (p, MPLIST_PLIST (family_list))
1907             mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1908         }
1909     }
1910   else
1911     {
1912       if (file_list)
1913         {
1914           pl = mplist ();
1915           mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1916         }
1917       if (family_list)
1918         {
1919           if (pl)
1920             for (p = pl; ! MPLIST_TAIL_P (p);)
1921               {
1922                 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1923                   p = MPLIST_NEXT (p);
1924                 else
1925                   mplist_pop (p);
1926               }
1927           else
1928             {
1929               pl = mplist ();
1930               MPLIST_DO (p, family_list)
1931                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1932             }
1933         }
1934       if (capability_list)
1935         {
1936           if (pl)
1937             for (p = pl; ! MPLIST_TAIL_P (p);)
1938               {
1939                 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1940                   p = MPLIST_NEXT (p);
1941                 else
1942                   mplist_pop (p);
1943               }
1944           else
1945             {
1946               pl = mplist ();
1947               MPLIST_DO (p, capability_list)
1948                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1949             }
1950         }
1951     }
1952               
1953   if (font
1954       && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1955           + font->property[MFONT_STRETCH] + font->size) > 0)
1956     {
1957       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1958       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1959       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1960       int size = font->size;
1961
1962       for (p = pl; ! MPLIST_TAIL_P (p); )
1963         {
1964           MFontFT *ft_info = MPLIST_VAL (p);
1965
1966           if ((weight != Mnil
1967                && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1968               || (style != Mnil
1969                   && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1970               || (stretch != Mnil
1971                   && stretch != FONT_PROPERTY (&ft_info->font,
1972                                                MFONT_STRETCH))
1973               || (size > 0
1974                   && ft_info->font.size > 0
1975                   && ft_info->font.size != size))
1976             mplist_pop (p);
1977           else
1978             p = MPLIST_NEXT (p);
1979         }
1980     }
1981
1982   MPLIST_DO (p, pl)
1983     {
1984       mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1985       num++;
1986       if (maxnum && maxnum <= num)
1987         break;
1988     }
1989   M17N_OBJECT_UNREF (pl);
1990
1991  done:
1992   MDEBUG_PRINT1 ("  %d found\n", num);
1993   return num;
1994 }
1995
1996 static void
1997 ft_list_family_names (MFrame *frame, MPlist *plist)
1998 {
1999   MPlist *pl;
2000
2001   if (! ft_font_list)
2002     {
2003 #ifdef HAVE_FONTCONFIG
2004       fc_init_font_list ();
2005 #else  /* not HAVE_FONTCONFIG */
2006       ft_init_font_list ();
2007 #endif  /* not HAVE_FONTCONFIG */
2008     }
2009
2010   MPLIST_DO (pl, ft_font_list)
2011     {
2012       MSymbol family = MPLIST_KEY (pl);
2013       MPlist *p;
2014
2015 #ifdef HAVE_FONTCONFIG
2016       if (msymbol_get (family, Mgeneric_family) != Mnil)
2017         continue;
2018 #endif  /* HAVE_FONTCONFIG */
2019       MPLIST_DO (p, plist)
2020         {
2021           MSymbol sym = MPLIST_SYMBOL (p);
2022
2023           if (sym == family)
2024             break;
2025           if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2026             {
2027               mplist_push (p, Msymbol, family);
2028               break;
2029             }
2030         }
2031       if (MPLIST_TAIL_P (p))
2032         mplist_push (p, Msymbol, family);
2033     }
2034 }
2035
2036 static int 
2037 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2038 {
2039   MFontFT *ft_info = (MFontFT *) rfont->font;
2040   MRealizedFontFT *ft_rfont = rfont->info;
2041   MFontCapability *cap = mfont__get_capability (capability);
2042
2043   if (cap->script_tag)
2044     {
2045       if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2046         return -1;
2047     }
2048   else if (cap->script != Mnil
2049            && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2050     return -1;
2051   if (cap->language != Mnil
2052       && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2053     return -1;
2054   return 0;
2055 }
2056
2057 static MRealizedFont *
2058 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2059 {
2060   MFontFT *ft_info;
2061   MRealizedFont *rfont;
2062   MRealizedFontFT *ft_rfont;
2063   FT_Face ft_face;
2064
2065   if (data_type == Mfontconfig)
2066     {
2067 #ifdef HAVE_FONTCONFIG
2068       FcPattern *pattern = data;
2069
2070       if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2071           != FcResultMatch)
2072         return NULL;
2073       ft_info = fc_gen_font (pattern, NULL);
2074 #else  /* not HAVE_FONTCONFIG */
2075       return NULL;
2076 #endif  /* not HAVE_FONTCONFIG */
2077     }
2078   else if (data_type == Mfreetype)
2079     {
2080       ft_face = data;
2081       ft_info = ft_gen_font (ft_face);
2082     }
2083   else
2084     return NULL;
2085
2086   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2087   ft_rfont->ft_face = ft_face;
2088   ft_rfont->face_encapsulated = 1;
2089
2090   MDEBUG_DUMP (" [FONT-FT] encapsulating ", (char *) ft_face->family_name,);
2091
2092   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2093   rfont->font = (MFont *) ft_info;
2094   rfont->info = ft_rfont;
2095   rfont->fontp = ft_face;
2096   rfont->driver = &mfont__ft_driver;
2097   rfont->spec = ft_info->font;
2098   rfont->spec.type = MFONT_TYPE_REALIZED;
2099   rfont->frame = frame;
2100   rfont->ascent = ft_face->size->metrics.ascender >> 6;
2101   rfont->descent = - ft_face->size->metrics.descender >> 6;
2102   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2103   rfont->baseline_offset = 0;
2104   rfont->x_ppem = ft_face->size->metrics.x_ppem;
2105   rfont->y_ppem = ft_face->size->metrics.y_ppem;
2106 #ifdef HAVE_FTBDF_H
2107   {
2108     BDF_PropertyRec prop;
2109
2110     if (! FT_IS_SCALABLE (ft_face)
2111         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2112       {
2113         rfont->baseline_offset = prop.u.integer << 6;
2114         rfont->ascent += prop.u.integer << 6;
2115         rfont->descent -= prop.u.integer << 6;
2116       }
2117   }
2118 #endif  /* HAVE_FTBDF_H */
2119   if (FT_IS_SCALABLE (ft_face))
2120     rfont->average_width = 0;
2121   else
2122     rfont->average_width = ft_face->available_sizes->width << 6;
2123   rfont->next = MPLIST_VAL (frame->realized_font_list);
2124   MPLIST_VAL (frame->realized_font_list) = rfont;
2125
2126   return rfont;
2127 }
2128
2129 static void
2130 ft_close (MRealizedFont *rfont)
2131 {
2132   if (! rfont->encapsulating)
2133     return;
2134   free (rfont->font);
2135   M17N_OBJECT_UNREF (rfont->info);
2136   free (rfont);
2137 }
2138
2139 static int 
2140 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2141 {
2142 #ifdef HAVE_OTF
2143   MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2144   MFontFT *ft_info = (MFontFT *) rfont->font;
2145   OTF *otf;
2146   OTF_Tag *tags;
2147   int i, n, negative;
2148
2149   if (ft_info->otf == invalid_otf)
2150     goto not_otf;
2151   otf = ft_info->otf;
2152   if (! otf)
2153     {
2154       MRealizedFontFT *ft_rfont = rfont->info;
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)
2162         {
2163           ft_info->otf = invalid_otf;
2164           goto not_otf;
2165         }
2166       ft_info->otf = otf;
2167     }
2168
2169   for (i = 0; i < 2; i++)
2170     {
2171       if (! spec->features[i])
2172         continue;
2173       for (n = 0; spec->features[i][n]; n++);
2174       tags = alloca (sizeof (OTF_Tag) * n);
2175       for (n = 0, negative = 0; spec->features[i][n]; n++)
2176         {
2177           if (spec->features[i][n] == 0xFFFFFFFF)
2178             negative = 1;
2179           else if (negative)
2180             tags[n - 1] = spec->features[i][n] | 0x80000000;
2181           else
2182             tags[n] = spec->features[i][n];
2183         }
2184       if (n - negative > 0
2185           && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2186                                  tags, n - negative) != 1)
2187         return 0;
2188     }
2189   return 1;
2190 #endif  /* HAVE_OTF */
2191  not_otf:
2192   return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
2193           && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
2194 }
2195
2196 #ifdef HAVE_OTF
2197
2198 #define DEVICE_DELTA(table, size)                               \
2199   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
2200    ? (table).DeltaValue[(size) - (table).StartSize] << 6        \
2201    : 0)
2202
2203 void
2204 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2205                unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2206 {
2207   if (anchor->AnchorFormat == 2)
2208     {
2209       FT_Outline *outline;
2210       int ap = anchor->f.f1.AnchorPoint;
2211
2212       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2213       outline = &ft_face->glyph->outline;
2214       if (ap < outline->n_points)
2215         {
2216           *x = outline->points[ap].x << 6;
2217           *y = outline->points[ap].y << 6;
2218         }
2219     }
2220   else if (anchor->AnchorFormat == 3)
2221     {
2222       if (anchor->f.f2.XDeviceTable.offset)
2223         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2224       if (anchor->f.f2.YDeviceTable.offset)
2225         *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2226     }
2227 }
2228 #endif  /* HAVE_OTF */
2229
2230 static int 
2231 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2232               MFLTGlyphString *in, int from, int to,
2233               MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2234 {
2235   int len = to - from;
2236   int i, j, gidx;
2237   MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2238   MRealizedFontFT *ft_rfont = rfont->info;
2239   MFontFT *ft_info = (MFontFT *) rfont->font;
2240 #ifdef HAVE_OTF
2241   MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2242   MGlyph *out_glyphs = (MGlyph *) (out->glyphs);
2243   OTF *otf;
2244   OTF_GlyphString otf_gstring;
2245   OTF_Glyph *otfg;
2246   char script[5], *langsys = NULL;
2247   char *gsub_features = NULL, *gpos_features = NULL;
2248
2249   if (len == 0)
2250     return from;
2251   if (ft_info->otf == invalid_otf)
2252     goto simple_copy;
2253   otf = ft_info->otf;
2254   if (! otf)
2255     {
2256       MRealizedFontFT *ft_rfont = rfont->info;
2257
2258 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2259       otf = OTF_open_ft_face (ft_rfont->ft_face);
2260 #else
2261       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2262 #endif
2263       if (! otf)
2264         {
2265           ft_info->otf = invalid_otf;
2266           goto simple_copy;
2267         }
2268       ft_info->otf = otf;
2269     }
2270
2271   if (OTF_get_table (otf, "head") < 0)
2272     {
2273       OTF_close (otf);
2274       ft_info->otf = invalid_otf;
2275       goto simple_copy;
2276     }
2277
2278   OTF_tag_name (spec->script, script);
2279   if (spec->langsys)
2280     {
2281       langsys = alloca (5);
2282       OTF_tag_name (spec->langsys, langsys);
2283     }
2284   for (i = 0; i < 2; i++)
2285     {
2286       char *p;
2287
2288       if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2289         {
2290           for (j = 0; spec->features[i][j]; j++);
2291           if (i == 0)
2292             p = gsub_features = alloca (6 * j);
2293           else
2294             p = gpos_features = alloca (6 * j);
2295           for (j = 0; spec->features[i][j]; j++)
2296             {
2297               if (spec->features[i][j] == 0xFFFFFFFF)
2298                 *p++ = '*', *p++ = ',';
2299               else
2300                 {
2301                   OTF_tag_name (spec->features[i][j], p);
2302                   p[4] = ',';
2303                   p += 5;
2304                 }
2305             }
2306           *--p = '\0';
2307         }
2308     }
2309
2310   otf_gstring.size = otf_gstring.used = len;
2311   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2312   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2313   for (i = 0; i < len; i++)
2314     {
2315       otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c;
2316       otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2317     }
2318
2319   OTF_drive_gdef (otf, &otf_gstring);
2320   gidx = out->used;
2321
2322   if (gsub_features)
2323     {
2324       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2325           < 0)
2326         goto simple_copy;
2327       if (out->allocated < out->used + otf_gstring.used)
2328         return -2;
2329       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2330         {
2331           MGlyph *g = out_glyphs + out->used;
2332           int j;
2333
2334           *g = in_glyphs[from + otfg->f.index.from];
2335           g->g.c = 0;
2336           for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
2337             if (in_glyphs[j].g.code == otfg->glyph_id)
2338               {
2339                 g->g.c = in_glyphs[j].g.c;
2340                 break;
2341               }
2342           if (g->g.code != otfg->glyph_id)
2343             {
2344               g->g.code = otfg->glyph_id;
2345               g->g.measured = 0;
2346             }
2347           out->used++;
2348         }
2349     }
2350   else
2351     {
2352       if (out->allocated < out->used + len)
2353         return -2;
2354       for (i = 0; i < len; i++)
2355         out_glyphs[out->used++] = in_glyphs[from + i];
2356     }
2357
2358   if (gpos_features)
2359     {
2360       FT_Face face;
2361       MGlyph *base = NULL, *mark = NULL, *g;
2362       int x_ppem, y_ppem, x_scale, y_scale;
2363
2364       if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2365           < 0)
2366         return to;
2367
2368       face = ft_rfont->ft_face;
2369       x_ppem = face->size->metrics.x_ppem;
2370       y_ppem = face->size->metrics.y_ppem;
2371       x_scale = face->size->metrics.x_scale;
2372       y_scale = face->size->metrics.y_scale;
2373
2374       for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2375            i < otf_gstring.used; i++, otfg++, g++)
2376         {
2377           MGlyph *prev;
2378
2379           if (! otfg->glyph_id)
2380             continue;
2381           switch (otfg->positioning_type)
2382             {
2383             case 0:
2384               break;
2385             case 1:             /* Single */
2386             case 2:             /* Pair */
2387               {
2388                 int format = otfg->f.f1.format;
2389
2390                 if (format & OTF_XPlacement)
2391                   adjustment[i].xoff
2392                     = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2393                 if (format & OTF_XPlaDevice)
2394                   adjustment[i].xoff
2395                     += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2396                 if (format & OTF_YPlacement)
2397                   adjustment[i].yoff
2398                     = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2399                 if (format & OTF_YPlaDevice)
2400                   adjustment[i].yoff
2401                     -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2402                 if (format & OTF_XAdvance)
2403                   adjustment[i].xadv
2404                     += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2405                 if (format & OTF_XAdvDevice)
2406                   adjustment[i].xadv
2407                     += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2408                 if (format & OTF_YAdvance)
2409                   adjustment[i].yadv
2410                     += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2411                 if (format & OTF_YAdvDevice)
2412                   adjustment[i].yadv
2413                     += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2414                 adjustment[i].set = 1;
2415               }
2416               break;
2417             case 3:             /* Cursive */
2418               /* Not yet supported.  */
2419               break;
2420             case 4:             /* Mark-to-Base */
2421             case 5:             /* Mark-to-Ligature */
2422               if (! base)
2423                 break;
2424               prev = base;
2425               goto label_adjust_anchor;
2426             default:            /* i.e. case 6 Mark-to-Mark */
2427               if (! mark)
2428                 break;
2429               prev = mark;
2430
2431             label_adjust_anchor:
2432               {
2433                 int base_x, base_y, mark_x, mark_y;
2434                 int this_from, this_to;
2435
2436                 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2437                 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2438                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2439                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2440
2441                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2442                   adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2443                                  x_ppem, y_ppem, &base_x, &base_y);
2444                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2445                   adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2446                                  x_ppem, y_ppem, &mark_x, &mark_y);
2447                 adjustment[i].xoff = (base_x - mark_x);
2448                 adjustment[i].yoff = - (base_y - mark_y);
2449                 adjustment[i].back = (g - prev);
2450                 adjustment[i].xadv = 0;
2451                 adjustment[i].advance_is_absolute = 1;
2452                 adjustment[i].set = 1;
2453                 this_from = g->g.from;
2454                 this_to = g->g.to;
2455                 for (j = 0; prev + j < g; j++)
2456                   {
2457                     if (this_from > prev[j].g.from)
2458                       this_from = prev[j].g.from;
2459                     if (this_to < prev[j].g.to)
2460                       this_to = prev[j].g.to;
2461                   }
2462                 for (; prev <= g; prev++)
2463                   {
2464                     prev->g.from = this_from;
2465                     prev->g.to = this_to;
2466                   }
2467               }
2468             }
2469           if (otfg->GlyphClass == OTF_GlyphClass0)
2470             base = mark = g;
2471           else if (otfg->GlyphClass == OTF_GlyphClassMark)
2472             mark = g;
2473           else
2474             base = g;
2475         }
2476     }
2477   free (otf_gstring.glyphs);
2478   return to;
2479
2480  simple_copy:
2481 #endif  /* HAVE_OTF */
2482   if (out->allocated < out->used + len)
2483     return -2;
2484   font->get_metrics (font, in, from, to);
2485   memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2486           sizeof (MGlyph) * len);
2487   out->used += len;
2488   if (otf_gstring.glyphs)
2489     free (otf_gstring.glyphs);
2490   return to;
2491 }
2492
2493 \f
2494 /* Internal API */
2495
2496 MFontDriver mfont__ft_driver =
2497   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2498     ft_render, ft_list, ft_list_family_names, ft_check_capability,
2499     ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf };
2500
2501 int
2502 mfont__ft_init ()
2503 {
2504   int i;
2505
2506   if (FT_Init_FreeType (&ft_library) != 0)
2507     MERROR (MERROR_FONT_FT, -1);
2508
2509   for (i = 0; i < ft_to_prop_size; i++)
2510     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2511
2512   Mmedium = msymbol ("medium");
2513   Mr = msymbol ("r");
2514   Mnull = msymbol ("");
2515
2516   M0[0] = msymbol ("0-0");
2517   M0[1] = msymbol ("0-1");
2518   M0[2] = msymbol ("0-2");
2519   M0[3] = msymbol ("0-3");
2520   M0[4] = msymbol ("0-4");
2521   M3_1 = msymbol ("3-1");
2522   M1_0 = msymbol ("1-0");
2523
2524 #ifdef HAVE_FONTCONFIG
2525   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2526     {
2527       FC_vs_M17N_font_prop *table = fc_all_table[i];
2528       int j;
2529
2530       for (j = 0; table[j].m17n_value; j++)
2531         table[j].sym = msymbol (table[j].m17n_value);
2532       table[j].sym = table[j - 1].sym;
2533     }
2534
2535   {
2536     char *pathname;
2537     struct stat buf;
2538     MPlist *plist;
2539     MSymbol serif, sans_serif, monospace;
2540
2541     fc_config = FcInitLoadConfigAndFonts ();
2542     if (mfont_freetype_path)
2543       {
2544         MPLIST_DO (plist, mfont_freetype_path)
2545           if (MPLIST_STRING_P (plist)
2546               && (pathname = MPLIST_STRING (plist))
2547               && stat (pathname, &buf) == 0)
2548             {
2549               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2550               FcChar8 *dir;
2551
2552               while ((dir = FcStrListNext (strlist)))
2553                 if (strcmp ((char *) dir, pathname) == 0)
2554                   break;
2555               if (! dir)
2556                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2557               FcStrListDone (strlist);
2558             }
2559       }
2560     Mgeneric_family = msymbol ("generic famly");
2561     serif = msymbol ("serif");
2562     msymbol_put (serif, Mgeneric_family, serif);
2563     sans_serif = msymbol ("sans-serif");
2564     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2565     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2566     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2567     monospace = msymbol ("monospace");
2568     msymbol_put (monospace, Mgeneric_family, monospace);
2569     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2570   }
2571 #endif  /* HAVE_FONTCONFIG */
2572
2573   return 0;
2574 }
2575
2576 void
2577 mfont__ft_fini ()
2578 {
2579   MPlist *plist, *p;
2580
2581   if (ft_default_list)
2582     {
2583       M17N_OBJECT_UNREF (ft_default_list);
2584       ft_default_list = NULL;
2585     }
2586
2587   if (ft_font_list)
2588     {
2589       MPLIST_DO (plist, ft_font_list)
2590         {
2591           if (MPLIST_VAL (plist))
2592             MPLIST_DO (p, MPLIST_VAL (plist))
2593               {
2594                 if (MPLIST_KEY (p) != Mt)
2595                   free_ft_info (MPLIST_VAL (p));
2596               }
2597           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2598         }
2599       M17N_OBJECT_UNREF (ft_font_list);
2600       ft_font_list = NULL;
2601
2602       if (ft_language_list)
2603         {
2604           MPLIST_DO (plist, ft_language_list)
2605             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2606           M17N_OBJECT_UNREF (ft_language_list);
2607           ft_language_list = NULL;
2608         }
2609
2610       if (ft_script_list)
2611         {
2612           MPLIST_DO (plist, ft_script_list)
2613             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2614           M17N_OBJECT_UNREF (ft_script_list);
2615           ft_script_list = NULL;
2616         }
2617
2618       if (ft_capability_list)
2619         {
2620           MPLIST_DO (plist, ft_capability_list)
2621             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2622           M17N_OBJECT_UNREF (ft_capability_list);
2623           ft_capability_list = NULL;
2624         }
2625
2626       if (ft_file_list)
2627         {
2628           MPLIST_DO (plist, ft_file_list)
2629             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2630           M17N_OBJECT_UNREF (ft_file_list);
2631           ft_file_list = NULL;
2632         }
2633     }
2634   FT_Done_FreeType (ft_library);
2635 #ifdef HAVE_FONTCONFIG
2636   FcConfigDestroy (fc_config);
2637   fc_config = NULL;
2638 #endif  /* HAVE_FONTCONFIG */
2639   all_fonts_scaned = 0;
2640 }
2641
2642 #ifdef HAVE_FONTCONFIG
2643
2644 int
2645 mfont__ft_parse_name (const char *name, MFont *font)
2646 {
2647   FcPattern *pat = FcNameParse ((FcChar8 *) name);
2648   FcChar8 *str;
2649   int val;
2650   double size;
2651   char *buf;
2652   int bufsize = 0;
2653   
2654   if (! pat)
2655     return -1;
2656   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2657     {
2658       STRDUP_LOWER (buf, bufsize, (char *) str);
2659       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2660     }
2661   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2662     {
2663       STRDUP_LOWER (buf, bufsize, (char *) str);
2664       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2665     }
2666   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2667     mfont__set_property (font, MFONT_WEIGHT,
2668                          fc_decode_prop (val, fc_weight_table,
2669                                          fc_weight_table_size));
2670   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2671     mfont__set_property (font, MFONT_STYLE,
2672                          fc_decode_prop (val, fc_slant_table,
2673                                          fc_slant_table_size));
2674   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2675     mfont__set_property (font, MFONT_STRETCH,
2676                          fc_decode_prop (val, fc_width_table,
2677                                          fc_width_table_size));
2678   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2679     font->size = size * 10 + 0.5;
2680   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2681     font->size = - (size * 10 + 0.5);
2682   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2683     {
2684       font->file = msymbol ((char *) str);
2685     }
2686   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2687   font->type = MFONT_TYPE_SPEC;
2688   FcPatternDestroy (pat);
2689   return 0;
2690 }
2691
2692 char *
2693 mfont__ft_unparse_name (MFont *font)
2694 {
2695   FcPattern *pat = fc_get_pattern (font);
2696   char *name = (char *) FcNameUnparse (pat);
2697
2698   FcPatternDestroy (pat);
2699   return name;
2700 }
2701 #endif  /* HAVE_FONTCONFIG */
2702
2703 #endif /* HAVE_FREETYPE */