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