*** empty log message ***
[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., 59 Temple Place, Suite 330, Boston, MA
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-gui.h"
41 #include "font.h"
42 #include "face.h"
43
44 #ifdef HAVE_FREETYPE
45
46 #ifdef HAVE_FTBDF_H
47 #include FT_BDF_H
48 #endif
49
50 static int mdebug_mask = MDEBUG_FONT;
51
52 #ifdef HAVE_FONTCONFIG
53 #include <fontconfig/fcfreetype.h>
54
55 static FcConfig *fc_config;
56 static MSymbol Mgeneric_family;
57 #endif  /* HAVE_FONTCONFIG */
58
59 /* Font properties; Mnormal is already defined in face.c.  */
60 static MSymbol Mmedium, Mr, Mnull;
61
62 static MSymbol M0[5], M3_1, M1_0;
63
64 static FT_Library ft_library;
65
66 #ifdef HAVE_OTF
67 static OTF *invalid_otf = (OTF *) "";
68 #endif /* HAVE_OTF */
69
70 typedef struct
71 {
72   MFont font;
73 #ifdef HAVE_OTF
74   /* NULL if not yet opened.  invalid_otf if not OTF.  */
75   OTF *otf;
76 #endif /* HAVE_OTF */
77 #ifdef HAVE_FONTCONFIG
78   FcLangSet *langset;
79   FcCharSet *charset;
80 #endif  /* HAVE_FONTCONFIG */
81 } MFontFT;
82
83 typedef struct
84 {
85   M17NObject control;
86   FT_Face ft_face;
87   MPlist *charmap_list;
88   int face_encapsulated;
89 } MRealizedFontFT;
90
91 typedef struct
92 {
93   char *ft_style;
94   int len;
95   enum MFontProperty prop;
96   char *val;
97 } MFTtoProp;
98
99 static MFTtoProp ft_to_prop[] =
100   { { "italic", 0, MFONT_STYLE, "i" },
101     { "roman", 0, MFONT_STYLE, "r" },
102     { "oblique", 0, MFONT_STYLE, "o" },
103     { "regular", 0, MFONT_WEIGHT, "normal" },
104     { "normal", 0, MFONT_WEIGHT, "normal" },
105     /* We need this entry even if "bold" is in commone_weight[] to
106        handle such style names as "bolditalic" and "boldoblique".  */
107     { "bold", 0, MFONT_WEIGHT, "bold" },
108     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
109     { "demi", 0, MFONT_WEIGHT, "demibold" } };
110 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
111
112 /** List of FreeType fonts.  Keys are family names, values are plists
113     containing fonts of the corresponding family.  In the deeper
114     plist, keys are file names, values are (MFontFT *).  */
115 static MPlist *ft_font_list;
116
117 /** List of FreeType fonts.  Keys are script names, values are plists
118     containing fonts supporting the corresponding script.  In the
119     deeper plist, keys are family names, values are (MFontFT *).  */
120 static MPlist *ft_script_list;
121
122 /** List of FreeType fonts.  Keys are language names, values are
123     plists containing fonts supporting the corresponding language.  In
124     the deeper plist, keys are family names, values are (MFontFT *).  */
125 static MPlist *ft_language_list;
126
127 static MPlist *ft_file_list;
128
129 static int all_fonts_scaned;
130
131 #define STRDUP_LOWER(s1, size, s2)                              \
132   do {                                                          \
133     int len = strlen (s2) + 1;                                  \
134     char *p1, *p2;                                              \
135                                                                 \
136     if ((size) < len)                                           \
137       (s1) = alloca (len), (size) = len;                        \
138     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)                 \
139       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
140     while (p1 > (s1) && p1[-1] == ' ') p1--;                    \
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_inf)
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_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_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_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 >> 6;
1545   rfont->descent = - ft_face->size->metrics.descender >> 6;
1546   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1547   rfont->baseline_offset = 0;
1548 #ifdef HAVE_FTBDF_H
1549   {
1550     BDF_PropertyRec prop;
1551
1552     if (! FT_IS_SCALABLE (ft_face)
1553         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1554       {
1555         rfont->baseline_offset = prop.u.integer;
1556         rfont->ascent += prop.u.integer;
1557         rfont->descent -= prop.u.integer;
1558       }
1559   }
1560 #endif  /* HAVE_FTBDF_H */
1561   if (FT_IS_SCALABLE (ft_face))
1562     rfont->average_width = 0;
1563   else
1564     rfont->average_width = ft_face->available_sizes->width;
1565   rfont->next = MPLIST_VAL (frame->realized_font_list);
1566   MPLIST_VAL (frame->realized_font_list) = rfont;
1567   MDEBUG_PRINT ("  ok\n");
1568   return rfont;
1569 }
1570
1571 /* The FreeType font driver function FIND_METRIC.  */
1572
1573 static void
1574 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1575                 int from, int to)
1576 {
1577   FT_Face ft_face = rfont->fontp;
1578   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1579
1580   for (; g != gend; g++)
1581     {
1582       if (g->code == MCHAR_INVALID_CODE)
1583         {
1584           if (FT_IS_SCALABLE (ft_face))
1585             {
1586               unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1587               int size = rfont->spec.size;
1588
1589               g->lbearing = 0;
1590               g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1591               g->width = g->rbearing;
1592               g->ascent = ft_face->ascender * size / unitsPerEm10;
1593               g->descent = (- ft_face->descender) * size / unitsPerEm10;
1594             }
1595           else
1596             {
1597 #ifdef HAVE_FTBDF_H
1598               BDF_PropertyRec prop;
1599 #endif  /* HAVE_FTBDF_H */
1600
1601               g->lbearing = 0;
1602               g->rbearing = g->width = ft_face->available_sizes->width;
1603 #ifdef HAVE_FTBDF_H
1604               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1605                 {
1606                   g->ascent = prop.u.integer;
1607                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1608                   g->descent = prop.u.integer;
1609                   if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1610                                            & prop) == 0)
1611                     {
1612                       g->ascent += prop.u.integer;
1613                       g->descent -= prop.u.integer;
1614                     }
1615                 }
1616               else
1617 #endif  /* HAVE_FTBDF_H */
1618                 {
1619                   g->ascent = ft_face->available_sizes->height;
1620                   g->descent = 0;
1621                 }
1622             }
1623         }
1624       else
1625         {
1626           FT_Glyph_Metrics *metrics;
1627
1628           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1629           metrics = &ft_face->glyph->metrics;
1630           g->lbearing = (metrics->horiBearingX >> 6);
1631           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1632           g->width = metrics->horiAdvance >> 6;
1633           g->ascent = metrics->horiBearingY >> 6;
1634           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1635         }
1636       g->ascent += rfont->baseline_offset;
1637       g->descent -= rfont->baseline_offset;
1638     }
1639 }
1640
1641 static int
1642 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1643 {
1644   MRealizedFont *rfont = NULL;
1645   MRealizedFontFT *ft_rfont;
1646   FT_UInt idx;
1647
1648   if (font->type == MFONT_TYPE_REALIZED)
1649     rfont = (MRealizedFont *) font;
1650   else if (font->type == MFONT_TYPE_OBJECT)
1651     {
1652       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1653            rfont = rfont->next)
1654         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1655           break;
1656       if (! rfont)
1657         {
1658 #ifdef HAVE_FONTCONFIG
1659           MFontFT *ft_info = (MFontFT *) font;
1660
1661           if (! ft_info->charset)
1662             {
1663               FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1664                                                MSYMBOL_NAME (font->file),
1665                                                NULL);
1666               FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1667               FcFontSet *fs = FcFontList (fc_config, pat, os);
1668
1669               if (fs->nfont > 0
1670                   && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1671                                           &ft_info->charset) == FcResultMatch)
1672                 ft_info->charset = FcCharSetCopy (ft_info->charset);
1673               else
1674                 ft_info->charset = FcCharSetCreate ();
1675               FcFontSetDestroy (fs);
1676               FcObjectSetDestroy (os);
1677               FcPatternDestroy (pat);
1678             }
1679           return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1680 #else  /* not HAVE_FONTCONFIG */
1681           rfont = ft_open (frame, font, spec, NULL);
1682 #endif  /* not HAVE_FONTCONFIG */
1683         }
1684     }
1685   else
1686     MFATAL (MERROR_FONT_FT);
1687
1688   if (! rfont)
1689     return 0;
1690   ft_rfont = rfont->info;
1691   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1692   return (idx != 0);
1693 }
1694
1695 /* The FreeType font driver function ENCODE_CHAR.  */
1696
1697 static unsigned
1698 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1699 {
1700   MRealizedFont *rfont;
1701   MRealizedFontFT *ft_rfont;
1702   FT_UInt idx;
1703
1704   if (font->type == MFONT_TYPE_REALIZED)
1705     rfont = (MRealizedFont *) font;
1706   else if (font->type == MFONT_TYPE_OBJECT)
1707     {
1708       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1709            rfont = rfont->next)
1710         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1711           break;
1712       if (! rfont)
1713         {
1714           rfont = ft_open (frame, font, spec, NULL);
1715           if (! rfont)
1716             return -1;
1717         }
1718     }
1719   else
1720     MFATAL (MERROR_FONT_FT);
1721
1722   ft_rfont = rfont->info;
1723   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1724   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1725 }
1726
1727 /* The FreeType font driver function RENDER.  */
1728
1729 #define NUM_POINTS 0x1000
1730
1731 typedef struct {
1732   MDrawPoint points[NUM_POINTS];
1733   MDrawPoint *p;
1734 } MPointTable;
1735
1736 static void
1737 ft_render (MDrawWindow win, int x, int y,
1738            MGlyphString *gstring, MGlyph *from, MGlyph *to,
1739            int reverse, MDrawRegion region)
1740 {
1741   FT_Face ft_face;
1742   MRealizedFace *rface = from->rface;
1743   MFrame *frame = rface->frame;
1744   FT_Int32 load_flags = FT_LOAD_RENDER;
1745   MGlyph *g;
1746   int i, j;
1747   MPointTable point_table[8];
1748   int baseline_offset;
1749
1750   if (from == to)
1751     return;
1752
1753   /* It is assured that the all glyphs in the current range use the
1754      same realized face.  */
1755   ft_face = rface->rfont->fontp;
1756   baseline_offset = rface->rfont->baseline_offset;
1757
1758   if (! gstring->anti_alias)
1759     {
1760 #ifdef FT_LOAD_TARGET_MONO
1761       load_flags |= FT_LOAD_TARGET_MONO;
1762 #else
1763       load_flags |= FT_LOAD_MONOCHROME;
1764 #endif
1765     }
1766
1767   for (i = 0; i < 8; i++)
1768     point_table[i].p = point_table[i].points;
1769
1770   for (g = from; g < to; x += g++->width)
1771     {
1772       unsigned char *bmp;
1773       int intensity;
1774       MPointTable *ptable;
1775       int xoff, yoff;
1776       int width, pitch;
1777
1778       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1779       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1780       bmp = ft_face->glyph->bitmap.buffer;
1781       width = ft_face->glyph->bitmap.width;
1782       pitch = ft_face->glyph->bitmap.pitch;
1783       if (! gstring->anti_alias)
1784         pitch *= 8;
1785       if (width > pitch)
1786         width = pitch;
1787
1788       if (gstring->anti_alias)
1789         for (i = 0; i < ft_face->glyph->bitmap.rows;
1790              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1791           {
1792             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1793             for (j = 0; j < width; j++, xoff++)
1794               {
1795                 intensity = bmp[j] >> 5;
1796                 if (intensity)
1797                   {
1798                     ptable = point_table + intensity;
1799                     ptable->p->x = xoff;
1800                     ptable->p->y = yoff - baseline_offset;
1801                     ptable->p++;
1802                     if (ptable->p - ptable->points == NUM_POINTS)
1803                       {
1804                         (*frame->driver->draw_points)
1805                           (frame, win, rface,
1806                            reverse ? 7 - intensity : intensity,
1807                            ptable->points, NUM_POINTS, region);
1808                         ptable->p = ptable->points;
1809                       }
1810                   }
1811               }
1812           }
1813       else
1814         for (i = 0; i < ft_face->glyph->bitmap.rows;
1815              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1816           {
1817             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1818             for (j = 0; j < width; j++, xoff++)
1819               {
1820                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1821                 if (intensity)
1822                   {
1823                     ptable = point_table;
1824                     ptable->p->x = xoff;
1825                     ptable->p->y = yoff - baseline_offset;
1826                     ptable->p++;
1827                     if (ptable->p - ptable->points == NUM_POINTS)
1828                       {
1829                         (*frame->driver->draw_points) (frame, win, rface,
1830                                            reverse ? 0 : 7,
1831                                            ptable->points, NUM_POINTS, region);
1832                         ptable->p = ptable->points;
1833                       }             
1834                   }
1835               }
1836         }
1837     }
1838
1839   if (gstring->anti_alias)
1840     {
1841       for (i = 1; i < 8; i++)
1842         if (point_table[i].p != point_table[i].points)
1843           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1844                              point_table[i].points,
1845                              point_table[i].p - point_table[i].points, region);
1846     }
1847   else
1848     {
1849       if (point_table[0].p != point_table[0].points)
1850         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1851                            point_table[0].points,
1852                            point_table[0].p - point_table[0].points, region);
1853     }
1854 }
1855
1856 static int
1857 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1858 {
1859   MPlist *pl = NULL, *p;
1860   int num = 0;
1861   MPlist *file_list = NULL;
1862   MPlist *family_list = NULL, *capability_list = NULL;
1863   MSymbol registry = Mnil;
1864
1865   MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1866
1867   if (font)
1868     {
1869       MSymbol family;
1870
1871       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1872       if (registry != Mnil && registry != Miso8859_1)
1873         {
1874           char *reg = MSYMBOL_NAME (registry);
1875
1876           if (strncmp (reg, "unicode-", 8)
1877               && strncmp (reg, "apple-roman", 11)
1878               && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1879             goto done;
1880         }
1881
1882       if (font->file != Mnil
1883           && ! (file_list = ft_list_file (font->file)))
1884         goto done;
1885       family = FONT_PROPERTY (font, MFONT_FAMILY);
1886       if (family != Mnil
1887           && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1888           && MPLIST_TAIL_P (family_list))
1889         goto done;
1890       if (font->capability != Mnil)
1891         {
1892           capability_list = ft_list_capability (font->capability);
1893           if (! capability_list || MPLIST_TAIL_P (capability_list))
1894             goto done;
1895         }
1896     }
1897
1898   if (! file_list && ! family_list && ! capability_list)
1899     {
1900       /* No restriction.  Get all fonts.  */
1901       pl = mplist ();
1902       MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1903         {
1904           MPLIST_DO (p, MPLIST_PLIST (family_list))
1905             mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1906         }
1907     }
1908   else
1909     {
1910       if (file_list)
1911         {
1912           pl = mplist ();
1913           mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1914         }
1915       if (family_list)
1916         {
1917           if (pl)
1918             for (p = pl; ! MPLIST_TAIL_P (p);)
1919               {
1920                 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1921                   p = MPLIST_NEXT (p);
1922                 else
1923                   mplist_pop (p);
1924               }
1925           else
1926             {
1927               pl = mplist ();
1928               MPLIST_DO (p, family_list)
1929                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1930             }
1931         }
1932       if (capability_list)
1933         {
1934           if (pl)
1935             for (p = pl; ! MPLIST_TAIL_P (p);)
1936               {
1937                 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1938                   p = MPLIST_NEXT (p);
1939                 else
1940                   mplist_pop (p);
1941               }
1942           else
1943             {
1944               pl = mplist ();
1945               MPLIST_DO (p, capability_list)
1946                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1947             }
1948         }
1949     }
1950               
1951   if (font
1952       && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1953           + font->property[MFONT_STRETCH] + font->size) > 0)
1954     {
1955       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1956       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1957       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1958       int size = font->size;
1959
1960       for (p = pl; ! MPLIST_TAIL_P (p); )
1961         {
1962           MFontFT *ft_info = MPLIST_VAL (p);
1963
1964           if ((weight != Mnil
1965                && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1966               || (style != Mnil
1967                   && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1968               || (stretch != Mnil
1969                   && stretch != FONT_PROPERTY (&ft_info->font,
1970                                                MFONT_STRETCH))
1971               || (size > 0
1972                   && ft_info->font.size > 0
1973                   && ft_info->font.size != size))
1974             mplist_pop (p);
1975           else
1976             p = MPLIST_NEXT (p);
1977         }
1978     }
1979
1980   MPLIST_DO (p, pl)
1981     {
1982       mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1983       num++;
1984       if (maxnum && maxnum <= num)
1985         break;
1986     }
1987   M17N_OBJECT_UNREF (pl);
1988
1989  done:
1990   MDEBUG_PRINT1 ("  %d found\n", num);
1991   return num;
1992 }
1993
1994 static void
1995 ft_list_family_names (MFrame *frame, MPlist *plist)
1996 {
1997   MPlist *pl;
1998
1999   if (! ft_font_list)
2000     {
2001 #ifdef HAVE_FONTCONFIG
2002       fc_init_font_list ();
2003 #else  /* not HAVE_FONTCONFIG */
2004       ft_init_font_list ();
2005 #endif  /* not HAVE_FONTCONFIG */
2006     }
2007
2008   MPLIST_DO (pl, ft_font_list)
2009     {
2010       MSymbol family = MPLIST_KEY (pl);
2011       MPlist *p;
2012
2013 #ifdef HAVE_FONTCONFIG
2014       if (msymbol_get (family, Mgeneric_family) != Mnil)
2015         continue;
2016 #endif  /* HAVE_FONTCONFIG */
2017       MPLIST_DO (p, plist)
2018         {
2019           MSymbol sym = MPLIST_SYMBOL (p);
2020
2021           if (sym == family)
2022             break;
2023           if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2024             {
2025               mplist_push (p, Msymbol, family);
2026               break;
2027             }
2028         }
2029       if (MPLIST_TAIL_P (p))
2030         mplist_push (p, Msymbol, family);
2031     }
2032 }
2033
2034 static int 
2035 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2036 {
2037   MFontFT *ft_info = (MFontFT *) rfont->font;
2038   MRealizedFontFT *ft_rfont = rfont->info;
2039   MFontCapability *cap = mfont__get_capability (capability);
2040
2041   if (cap->script != Mnil
2042       && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2043     return -1;
2044   if (cap->language != Mnil
2045       && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2046     return -1;
2047   if (cap->script_tag && ft_check_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2048     return -1;
2049   return 0;
2050 }
2051
2052 static MRealizedFont *
2053 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2054 {
2055   MFontFT *ft_info;
2056   MRealizedFont *rfont;
2057   MRealizedFontFT *ft_rfont;
2058   FT_Face ft_face;
2059
2060   if (data_type == Mfontconfig)
2061     {
2062 #ifdef HAVE_FONTCONFIG
2063       FcPattern *pattern = data;
2064
2065       if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2066           != FcResultMatch)
2067         return NULL;
2068       ft_info = fc_gen_font (pattern, NULL);
2069 #else  /* not HAVE_FONTCONFIG */
2070       return NULL;
2071 #endif  /* not HAVE_FONTCONFIG */
2072     }
2073   else if (data_type == Mfreetype)
2074     {
2075       ft_face = data;
2076       ft_info = ft_gen_font (ft_face);
2077     }
2078   else
2079     return NULL;
2080
2081   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2082   ft_rfont->ft_face = ft_face;
2083   ft_rfont->face_encapsulated = 1;
2084
2085   MDEBUG_DUMP (" [FONT-FT] encapsulating ", (char *) ft_face->family_name,);
2086
2087   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2088   rfont->font = (MFont *) ft_info;
2089   rfont->info = ft_rfont;
2090   rfont->fontp = ft_face;
2091   rfont->driver = &mfont__ft_driver;
2092   rfont->spec = ft_info->font;
2093   rfont->spec.type = MFONT_TYPE_REALIZED;
2094   rfont->frame = frame;
2095   rfont->ascent = ft_face->size->metrics.ascender >> 6;
2096   rfont->descent = - ft_face->size->metrics.descender >> 6;
2097   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2098   rfont->baseline_offset = 0;
2099 #ifdef HAVE_FTBDF_H
2100   {
2101     BDF_PropertyRec prop;
2102
2103     if (! FT_IS_SCALABLE (ft_face)
2104         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2105       {
2106         rfont->baseline_offset = prop.u.integer;
2107         rfont->ascent += prop.u.integer;
2108         rfont->descent -= prop.u.integer;
2109       }
2110   }
2111 #endif  /* HAVE_FTBDF_H */
2112   if (FT_IS_SCALABLE (ft_face))
2113     rfont->average_width = 0;
2114   else
2115     rfont->average_width = ft_face->available_sizes->width;
2116   rfont->next = MPLIST_VAL (frame->realized_font_list);
2117   MPLIST_VAL (frame->realized_font_list) = rfont;
2118
2119   return rfont;
2120 }
2121
2122 static void
2123 ft_close (MRealizedFont *rfont)
2124 {
2125   if (! rfont->encapsulating)
2126     return;
2127   free (rfont->font);
2128   M17N_OBJECT_UNREF (rfont->info);
2129   free (rfont);
2130 }
2131
2132
2133 \f
2134 /* Internal API */
2135
2136 MFontDriver mfont__ft_driver =
2137   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2138     ft_render, ft_list, ft_list_family_names, ft_check_capability,
2139     ft_encapsulate, ft_close };
2140
2141 int
2142 mfont__ft_init ()
2143 {
2144   int i;
2145
2146   if (FT_Init_FreeType (&ft_library) != 0)
2147     MERROR (MERROR_FONT_FT, -1);
2148
2149   for (i = 0; i < ft_to_prop_size; i++)
2150     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2151
2152   Mmedium = msymbol ("medium");
2153   Mr = msymbol ("r");
2154   Mnull = msymbol ("");
2155
2156   M0[0] = msymbol ("0-0");
2157   M0[1] = msymbol ("0-1");
2158   M0[2] = msymbol ("0-2");
2159   M0[3] = msymbol ("0-3");
2160   M0[4] = msymbol ("0-4");
2161   M3_1 = msymbol ("3-1");
2162   M1_0 = msymbol ("1-0");
2163
2164 #ifdef HAVE_FONTCONFIG
2165   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2166     {
2167       FC_vs_M17N_font_prop *table = fc_all_table[i];
2168       int j;
2169
2170       for (j = 0; table[j].m17n_value; j++)
2171         table[j].sym = msymbol (table[j].m17n_value);
2172       table[j].sym = table[j - 1].sym;
2173     }
2174
2175   {
2176     char *pathname;
2177     struct stat buf;
2178     MPlist *plist;
2179     MSymbol serif, sans_serif, monospace;
2180
2181     fc_config = FcInitLoadConfigAndFonts ();
2182     if (mfont_freetype_path)
2183       {
2184         MPLIST_DO (plist, mfont_freetype_path)
2185           if (MPLIST_STRING_P (plist)
2186               && (pathname = MPLIST_STRING (plist))
2187               && stat (pathname, &buf) == 0)
2188             {
2189               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2190               FcChar8 *dir;
2191
2192               while ((dir = FcStrListNext (strlist)))
2193                 if (strcmp ((char *) dir, pathname) == 0)
2194                   break;
2195               if (! dir)
2196                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2197               FcStrListDone (strlist);
2198             }
2199       }
2200     Mgeneric_family = msymbol ("generic famly");
2201     serif = msymbol ("serif");
2202     msymbol_put (serif, Mgeneric_family, serif);
2203     sans_serif = msymbol ("sans-serif");
2204     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2205     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2206     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2207     monospace = msymbol ("monospace");
2208     msymbol_put (monospace, Mgeneric_family, monospace);
2209     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2210   }
2211 #endif
2212
2213   return 0;
2214 }
2215
2216 void
2217 mfont__ft_fini ()
2218 {
2219   MPlist *plist, *p;
2220
2221   if (ft_default_list)
2222     {
2223       M17N_OBJECT_UNREF (ft_default_list);
2224       ft_default_list = NULL;
2225     }
2226
2227   if (ft_font_list)
2228     {
2229       MPLIST_DO (plist, ft_font_list)
2230         {
2231           if (MPLIST_VAL (plist))
2232             MPLIST_DO (p, MPLIST_VAL (plist))
2233               {
2234                 if (MPLIST_KEY (p) != Mt)
2235                   free_ft_info (MPLIST_VAL (p));
2236               }
2237           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2238         }
2239       M17N_OBJECT_UNREF (ft_font_list);
2240       ft_font_list = NULL;
2241
2242       if (ft_language_list)
2243         {
2244           MPLIST_DO (plist, ft_language_list)
2245             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2246           M17N_OBJECT_UNREF (ft_language_list);
2247           ft_language_list = NULL;
2248         }
2249
2250       if (ft_script_list)
2251         {
2252           MPLIST_DO (plist, ft_script_list)
2253             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2254           M17N_OBJECT_UNREF (ft_script_list);
2255           ft_script_list = NULL;
2256         }
2257
2258       if (ft_capability_list)
2259         {
2260           MPLIST_DO (plist, ft_capability_list)
2261             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2262           M17N_OBJECT_UNREF (ft_capability_list);
2263           ft_capability_list = NULL;
2264         }
2265
2266       if (ft_file_list)
2267         {
2268           MPLIST_DO (plist, ft_file_list)
2269             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2270           M17N_OBJECT_UNREF (ft_file_list);
2271           ft_file_list = NULL;
2272         }
2273     }
2274   FT_Done_FreeType (ft_library);
2275 #ifdef HAVE_FONTCONFIG
2276   FcConfigDestroy (fc_config);
2277   fc_config = NULL;
2278 #endif  /* HAVE_FONTCONFIG */
2279   all_fonts_scaned = 0;
2280 }
2281
2282 #ifdef HAVE_FONTCONFIG
2283
2284 int
2285 mfont__ft_parse_name (const char *name, MFont *font)
2286 {
2287   FcPattern *pat = FcNameParse ((FcChar8 *) name);
2288   FcChar8 *str;
2289   int val;
2290   double size;
2291   char *buf;
2292   int bufsize = 0;
2293   
2294   if (! pat)
2295     return -1;
2296   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2297     {
2298       STRDUP_LOWER (buf, bufsize, (char *) str);
2299       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2300     }
2301   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2302     {
2303       STRDUP_LOWER (buf, bufsize, (char *) str);
2304       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2305     }
2306   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2307     mfont__set_property (font, MFONT_WEIGHT,
2308                          fc_decode_prop (val, fc_weight_table,
2309                                          fc_weight_table_size));
2310   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2311     mfont__set_property (font, MFONT_STYLE,
2312                          fc_decode_prop (val, fc_slant_table,
2313                                          fc_slant_table_size));
2314   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2315     mfont__set_property (font, MFONT_STRETCH,
2316                          fc_decode_prop (val, fc_width_table,
2317                                          fc_width_table_size));
2318   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2319     font->size = size * 10 + 0.5;
2320   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2321     font->size = - (size * 10 + 0.5);
2322   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2323     {
2324       font->file = msymbol ((char *) str);
2325     }
2326   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2327   font->type = MFONT_TYPE_SPEC;
2328   FcPatternDestroy (pat);
2329   return 0;
2330 }
2331
2332 char *
2333 mfont__ft_unparse_name (MFont *font)
2334 {
2335   FcPattern *pat = fc_get_pattern (font);
2336   char *name = (char *) FcNameUnparse (pat);
2337
2338   FcPatternDestroy (pat);
2339   return name;
2340 }
2341 #endif  /* HAVE_FONTCONFIG */
2342
2343 \f
2344 #ifdef HAVE_OTF
2345
2346 #define DEVICE_DELTA(table, size)                               \
2347   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
2348    ? (table).DeltaValue[(size) - (table).StartSize]             \
2349    : 0)
2350
2351 void
2352 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2353                unsigned code, int size, int *x, int *y)
2354 {
2355   if (anchor->AnchorFormat == 2)
2356     {
2357       FT_Outline *outline;
2358       int ap = anchor->f.f1.AnchorPoint;
2359
2360       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2361       outline = &ft_face->glyph->outline;
2362       if (ap < outline->n_points)
2363         {
2364           *x = outline->points[ap].x;
2365           *y = outline->points[ap].y;
2366         }
2367     }
2368   else if (anchor->AnchorFormat == 3)
2369     {
2370       if (anchor->f.f2.XDeviceTable.offset)
2371         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2372       if (anchor->f.f2.YDeviceTable.offset)
2373       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2374     }
2375 }
2376
2377 int
2378 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2379                      MFontCapability *cap)
2380 {
2381   int len = to - from;
2382   MGlyph *g = MGLYPH (from);
2383   int i, gidx;
2384   MRealizedFont *rfont;
2385   MFontFT *ft_info;
2386   OTF *otf;
2387   OTF_GlyphString otf_gstring;
2388   OTF_Glyph *otfg;
2389   char *script, *langsys;
2390   char *gsub_features, *gpos_features;
2391   int need_cmap;
2392
2393   if (len == 0)
2394     return from;
2395
2396   otf_gstring.glyphs = NULL;
2397   rfont = g->rface->rfont;
2398   ft_info = (MFontFT *) rfont->font;
2399   if (ft_info->otf == invalid_otf)
2400     goto simple_copy;
2401   otf = ft_info->otf;
2402   if (! otf)
2403     {
2404       MRealizedFontFT *ft_rfont = rfont->info;
2405
2406 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2407       otf = OTF_open_ft_face (ft_rfont->ft_face);
2408 #else
2409       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2410 #endif
2411       if (! otf)
2412         {
2413           ft_info->otf = invalid_otf;
2414           goto simple_copy;
2415         }
2416       ft_info->otf = otf;
2417     }
2418   if (OTF_get_table (otf, "head") < 0)
2419     {
2420       OTF_close (otf);
2421       ft_info->otf = invalid_otf;
2422       goto simple_copy;
2423     }
2424
2425   if (cap->script_tag)
2426     {
2427       script = alloca (5);
2428       OTF_tag_name (cap->script_tag, script);
2429     }
2430   else
2431     script = NULL;
2432   if (cap->langsys_tag)
2433     {
2434       langsys = alloca (5);
2435       OTF_tag_name (cap->langsys_tag, langsys);
2436     }
2437   else
2438     langsys = NULL;
2439   gsub_features = cap->features[MFONT_OTT_GSUB].str;
2440   if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2441     gsub_features = NULL;
2442   gpos_features = cap->features[MFONT_OTT_GPOS].str;
2443   if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2444     gpos_features = NULL;
2445
2446   otf_gstring.size = otf_gstring.used = len;
2447   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2448   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2449   for (i = 0, need_cmap = 0; i < len; i++)
2450     {
2451       if (gstring->glyphs[from + i].otf_encoded)
2452         {
2453           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2454           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2455         }
2456       else
2457         {
2458           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2459           need_cmap++;
2460         }
2461     }
2462   if (need_cmap
2463       && OTF_drive_cmap (otf, &otf_gstring) < 0)
2464     goto simple_copy;
2465
2466   OTF_drive_gdef (otf, &otf_gstring);
2467   gidx = gstring->used;
2468
2469   if (gsub_features)
2470     {
2471       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2472           < 0)
2473         goto simple_copy;
2474       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2475         {
2476           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2477
2478           temp.c = otfg->c;
2479           temp.combining_code = 0;
2480           if (otfg->glyph_id)
2481             {
2482               temp.code = otfg->glyph_id;
2483               temp.otf_encoded = 1;
2484             }
2485           else
2486             {
2487               temp.code = temp.c;
2488               temp.otf_encoded = 0;
2489             }
2490           temp.to = MGLYPH (from + otfg->f.index.to)->to;
2491           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2492         }
2493     }
2494   else
2495     for (i = 0; i < len; i++)
2496       {
2497         MGlyph temp = gstring->glyphs[from + i];
2498
2499         if (otf_gstring.glyphs[i].glyph_id)
2500           {
2501             temp.code = otf_gstring.glyphs[i].glyph_id;
2502             temp.otf_encoded = 1;
2503           }
2504         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2505       }
2506
2507   (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2508
2509   if (gpos_features)
2510     {
2511       int u;
2512       int size10, size;
2513       MGlyph *base = NULL, *mark = NULL;
2514
2515       if (OTF_check_features (otf, 1,
2516                               cap->script_tag, cap->langsys_tag,
2517                               cap->features[MFONT_OTT_GPOS].tags,
2518                               cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2519           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2520                               gpos_features) < 0))
2521         return to;
2522
2523       u = otf->head->unitsPerEm;
2524       size10 = rfont->spec.size;
2525       size = size10 / 10;
2526
2527       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2528            i < otf_gstring.used; i++, otfg++, g++)
2529         {
2530           MGlyph *prev;
2531
2532           if (! otfg->glyph_id)
2533             continue;
2534           switch (otfg->positioning_type)
2535             {
2536             case 0:
2537               break;
2538             case 1: case 2:
2539               {
2540                 int format = otfg->f.f1.format;
2541
2542                 if (format & OTF_XPlacement)
2543                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2544                 if (format & OTF_XPlaDevice)
2545                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2546                 if (format & OTF_YPlacement)
2547                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2548                 if (format & OTF_YPlaDevice)
2549                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2550                 if (format & OTF_XAdvance)
2551                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2552                 if (format & OTF_XAdvDevice)
2553                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2554               }
2555               break;
2556             case 3:
2557               /* Not yet supported.  */
2558               break;
2559             case 4: case 5:
2560               if (! base)
2561                 break;
2562               prev = base;
2563               goto label_adjust_anchor;
2564             default:            /* i.e. case 6 */
2565               if (! mark)
2566                 break;
2567               prev = mark;
2568
2569             label_adjust_anchor:
2570               {
2571                 int base_x, base_y, mark_x, mark_y;
2572
2573                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2574                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2575                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2576                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2577
2578                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2579                   adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2580                                  prev->code, size, &base_x, &base_y);
2581                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2582                   adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2583                                  g->code, size, &mark_x, &mark_y);
2584                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2585                 g->yoff = prev->yoff + mark_y - base_y;
2586                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2587               }
2588             }
2589           if (otfg->GlyphClass == OTF_GlyphClass0)
2590             base = mark = g;
2591           else if (otfg->GlyphClass == OTF_GlyphClassMark)
2592             mark = g;
2593           else
2594             base = g;
2595         }
2596     }
2597   free (otf_gstring.glyphs);
2598   return to;
2599
2600  simple_copy:
2601   for (i = 0; i < len; i++)
2602     {
2603       MGlyph *g = MGLYPH (from + i);
2604
2605       if (! g->otf_encoded)
2606         {
2607           g->code = rfont->driver->encode_char (gstring->frame, (MFont *) rfont,
2608                                                 NULL, g->code);
2609           g->otf_encoded = 1;
2610         }
2611     }
2612
2613   rfont->driver->find_metric (rfont, gstring, from, to);
2614   for (i = 0; i < len; i++)
2615     {
2616       MGlyph temp = gstring->glyphs[from + i];
2617       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2618     }
2619   if (otf_gstring.glyphs)
2620     free (otf_gstring.glyphs);
2621   return to;
2622 }
2623
2624
2625 int
2626 mfont__ft_decode_otf (MGlyph *g)
2627 {
2628   MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2629   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2630
2631   return (c ? c : -1);
2632 }
2633
2634 #endif  /* HAVE_OTF */
2635
2636 #endif /* HAVE_FREETYPE */