(DEVICE_DELTA): Fix typo.
[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;
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   int i;
1113
1114 #ifdef HAVE_FONTCONFIG
1115   if (! char_list || ! ft_info->charset)
1116     return -1;
1117   MPLIST_DO (char_list, char_list)
1118     if (FcCharSetHasChar (ft_info->charset,
1119                           (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1120       break;
1121
1122 #else  /* not HAVE_FONTCONFIG */
1123   FT_Face ft_face;
1124
1125   if (! char_list
1126       || FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, 
1127                       &ft_face))
1128     return -1;
1129
1130   MPLIST_DO (char_list, char_list)
1131     if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list)) == 0)
1132       break;
1133   FT_Done_Face (ft_face);
1134 #endif  /* not HAVE_FONTCONFIG */
1135
1136   return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1137 }
1138
1139 static MPlist *ft_default_list;
1140
1141 static MPlist *
1142 ft_list_default ()
1143 {
1144   if (ft_default_list)
1145     return ft_default_list;
1146   ft_default_list = mplist ();
1147 #ifdef HAVE_FONTCONFIG
1148   {
1149     FcPattern *pat = FcPatternCreate ();
1150     FcChar8 *fam;
1151     char *buf;
1152     int bufsize = 0;
1153     int i;
1154
1155     FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1156     for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1157          i++)
1158       {
1159         MSymbol family;
1160         MPlist *plist;
1161
1162         STRDUP_LOWER (buf, bufsize, (char *) fam);
1163         family = msymbol (buf);
1164         if (msymbol_get (family, Mgeneric_family))
1165           continue;
1166         plist = MPLIST_PLIST (ft_list_family (family, 0));
1167         MPLIST_DO (plist, plist)
1168           mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1169       }
1170   }
1171 #else  /* not HAVE_FONTCONFIG */
1172   {
1173     MPlist *plist, *pl;
1174
1175     MPLIST_DO (plist, ft_list_family (Mnil, 0))
1176       {
1177         pl = MPLIST_PLIST (plist);
1178         if (! MPLIST_TAIL_P (pl))
1179           mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1180       }
1181   }
1182 #endif  /* not HAVE_FONTCONFIG */
1183   return ft_default_list;
1184 }
1185
1186
1187 static MPlist *ft_capability_list;
1188
1189 static MPlist *
1190 ft_list_capability (MSymbol capability)
1191 {
1192   MFontCapability *cap;
1193   MPlist *plist = NULL, *pl, *p;
1194
1195   if (! ft_capability_list)
1196     ft_capability_list = mplist ();
1197   else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1198     return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1199
1200   cap = mfont__get_capability (capability);
1201
1202   if (cap && cap->language != Mnil)
1203     {
1204       plist = ft_list_language (cap->language);
1205       if (! plist)
1206         return NULL;
1207       plist = mplist_copy (plist);
1208     }
1209
1210   if (cap && cap->script != Mnil)
1211     {
1212       if (! plist)
1213         {
1214           plist = ft_list_script (cap->script);
1215           if (! plist)
1216             return NULL;
1217           plist = mplist_copy (plist);
1218         }
1219       else
1220         {
1221           for (pl = plist; ! MPLIST_TAIL_P (pl);)
1222             {
1223               if (ft_check_script (MPLIST_VAL (pl), cap->script) < 0)
1224                 mplist_pop (pl);
1225               else
1226                 pl = MPLIST_NEXT (pl);
1227             }
1228         }
1229
1230       if (cap->script_tag)
1231         {
1232           for (pl = plist; ! MPLIST_TAIL_P (pl);)
1233             {
1234               if (ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1235                 mplist_pop (pl);
1236               else
1237                 pl = MPLIST_NEXT (pl);
1238             }
1239         }
1240
1241       if (MPLIST_TAIL_P (plist))
1242         {
1243           M17N_OBJECT_UNREF (plist);
1244           plist = NULL;
1245         }
1246     }
1247
1248   mplist_push (ft_capability_list, capability, plist);
1249   return plist;
1250 }
1251
1252
1253 static MPlist *
1254 ft_list_file (MSymbol filename)
1255 {
1256   MPlist *plist = NULL;
1257
1258   if (! ft_file_list)
1259     ft_file_list = mplist ();
1260   else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1261     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1262
1263 #ifdef HAVE_FONTCONFIG
1264   {
1265     FcPattern *pattern = FcPatternCreate ();
1266     FcObjectSet *os;
1267     FcFontSet *fs;
1268
1269     FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1270     os = FcObjectSetBuild (FC_FAMILY, NULL);
1271     fs = FcFontList (fc_config, pattern, os);
1272     if (fs->nfont > 0)
1273       {
1274         char *fam;
1275         char *buf;
1276         int bufsize = 0;
1277
1278         if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1279                                 (FcChar8 **) &fam) == FcResultMatch)
1280           {
1281             MSymbol family;
1282             MPlist *pl;
1283
1284             STRDUP_LOWER (buf, bufsize, fam);
1285             family = msymbol (buf);
1286             pl = ft_list_family (family, 0);
1287             MPLIST_DO (pl, MPLIST_PLIST (pl))
1288               {
1289                 MFontFT *ft_info = MPLIST_VAL (pl);
1290
1291                 if (ft_info->font.file == filename)
1292                   {
1293                     plist = mplist ();
1294                     mplist_add (plist, family, ft_info);
1295                     break;
1296                   }
1297               }
1298           }
1299       }
1300   }
1301 #else  /* not HAVE_FONTCONFIG */
1302   {
1303     MPlist *pl, *p;
1304
1305     MPLIST_DO (pl, ft_list_family (Mnil, 0))
1306       {
1307         MPLIST_DO (p, MPLIST_PLIST (pl))
1308           {
1309             MFontFT *ft_info = MPLIST_VAL (pl);
1310
1311             if (ft_info->font.file == filename)
1312               {
1313                 plist = mplist ();
1314                 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1315                 break;
1316               }
1317           }
1318         if (plist)
1319           break;
1320       }
1321   }
1322 #endif  /* not HAVE_FONTCONFIG */
1323
1324   mplist_push (ft_file_list, filename, plist);
1325   return plist;
1326 }
1327
1328 /* The FreeType font driver function SELECT.  */
1329
1330 static MFont *
1331 ft_select (MFrame *frame, MFont *font, int limited_size)
1332 {
1333   MFont *found = NULL;
1334 #ifdef HAVE_FONTCONFIG
1335   MPlist *plist, *pl;
1336   MFontFT *ft_info;
1337   int check_font_property = 1;
1338
1339   if (font->file != Mnil)
1340     {
1341       plist = ft_list_file (font->file);
1342       if (! plist)
1343         return NULL;
1344       check_font_property = 0;
1345     }
1346   else
1347     {
1348       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1349
1350       if (family)
1351         plist = MPLIST_PLIST (ft_list_family (family, 1));
1352       else
1353         plist = ft_list_default ();
1354       if (MPLIST_TAIL_P (plist))
1355         return NULL;
1356     }
1357
1358   plist = mplist_copy (plist);
1359
1360   if (font->capability != Mnil)
1361     {
1362       MFontCapability *cap = mfont__get_capability (font->capability);
1363
1364       for (pl = plist; ! MPLIST_TAIL_P (pl);)
1365         {
1366           if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1367             {
1368               mplist_pop (pl);
1369               continue;
1370             }
1371           if (cap->language
1372               && ft_check_language (MPLIST_VAL (pl), cap->language) < 0)
1373             mplist_pop (pl);
1374           else
1375             pl = MPLIST_NEXT (pl);
1376         }
1377     }
1378
1379   if (check_font_property)
1380     {
1381       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1382       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1383       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1384       MSymbol alternate_weight = Mnil;
1385
1386       if (weight == Mnormal)
1387         alternate_weight = Mmedium;
1388       else if (weight == Mmedium)
1389         alternate_weight = Mnormal;
1390       if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1391         for (pl = plist; ! MPLIST_TAIL_P (pl); )
1392           {
1393             ft_info = MPLIST_VAL (pl);
1394             if ((weight != Mnil
1395                  && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1396                      && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1397                 || (style != Mnil
1398                     && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1399                 || (stretch != Mnil
1400                     && stretch != FONT_PROPERTY (&ft_info->font,
1401                                                  MFONT_STRETCH))
1402                 || (font->size > 0
1403                     && ft_info->font.size > 0
1404                     && ft_info->font.size != font->size))
1405               mplist_pop (pl);
1406             else
1407               pl = MPLIST_NEXT (pl);
1408           }
1409     }
1410
1411   MPLIST_DO (pl, plist)
1412     {
1413       font = MPLIST_VAL (plist);
1414       if (limited_size == 0
1415           || font->size == 0
1416           || font->size <= limited_size)
1417         {
1418           found = font;
1419           break;
1420         }
1421     }
1422   M17N_OBJECT_UNREF (plist);
1423 #endif  /* HAVE_FONTCONFIG */
1424   return found;
1425 }
1426
1427
1428 static MRealizedFont *
1429 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1430 {
1431   MFontFT *ft_info = (MFontFT *) font;
1432   int reg = spec->property[MFONT_REGISTRY];
1433   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1434   MRealizedFontFT *ft_rfont;
1435   FT_Face ft_face;
1436   MPlist *plist, *charmap_list = NULL;
1437   int charmap_index;
1438   int size;
1439
1440   if (font->size)
1441     /* non-scalable font */
1442     size = font->size;
1443   else if (spec->size)
1444     {
1445       int ratio = mfont_resize_ratio (font);
1446
1447       size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1448     }
1449   else
1450     size = 120;
1451
1452   if (rfont)
1453     {
1454       charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1455       for (; rfont; rfont = rfont->next)
1456         if (rfont->font == font
1457             && (rfont->font->size ? rfont->font->size == size
1458                 : rfont->spec.size == size)
1459             && rfont->spec.property[MFONT_REGISTRY] == reg
1460             && rfont->driver == &mfont__ft_driver)
1461           return rfont;
1462     }
1463
1464   MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1465
1466   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1467                    &ft_face))
1468     {
1469       font->type = MFONT_TYPE_FAILURE;
1470       MDEBUG_PRINT ("  no (FT_New_Face)\n");
1471       return NULL;
1472     }
1473   if (charmap_list)
1474     M17N_OBJECT_REF (charmap_list);
1475   else
1476     charmap_list = ft_get_charmaps (ft_face);
1477   if (registry == Mnil)
1478     registry = Municode_bmp;
1479   plist = mplist_find_by_key (charmap_list, registry);
1480   if (! plist)
1481     {
1482       FT_Done_Face (ft_face);
1483       M17N_OBJECT_UNREF (charmap_list);
1484       MDEBUG_PRINT1 ("  no (%s)\n", MSYMBOL_NAME (registry));
1485       return NULL;
1486     }
1487   charmap_index = (int) MPLIST_VAL (plist);
1488   if ((charmap_index >= 0
1489        && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1490       || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1491     {
1492       FT_Done_Face (ft_face);
1493       M17N_OBJECT_UNREF (charmap_list);
1494       font->type = MFONT_TYPE_FAILURE;
1495       MDEBUG_PRINT1 ("  no (size %d)\n", size);
1496       return NULL;
1497     }
1498
1499   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1500   ft_rfont->ft_face = ft_face;
1501   ft_rfont->charmap_list = charmap_list;
1502   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1503   rfont->spec = *font;
1504   rfont->spec.type = MFONT_TYPE_REALIZED;
1505   rfont->spec.property[MFONT_REGISTRY] = reg;
1506   rfont->spec.size = size;
1507   rfont->frame = frame;
1508   rfont->font = font;
1509   rfont->driver = &mfont__ft_driver;
1510   rfont->info = ft_rfont;
1511   rfont->fontp = ft_face;
1512   rfont->ascent = ft_face->size->metrics.ascender >> 6;
1513   rfont->descent = - ft_face->size->metrics.descender >> 6;
1514   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1515   rfont->baseline_offset = 0;
1516 #ifdef HAVE_FTBDF_H
1517   {
1518     BDF_PropertyRec prop;
1519
1520     if (! FT_IS_SCALABLE (ft_face)
1521         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1522       {
1523         rfont->baseline_offset = prop.u.integer;
1524         rfont->ascent += prop.u.integer;
1525         rfont->descent -= prop.u.integer;
1526       }
1527   }
1528 #endif  /* HAVE_FTBDF_H */
1529   if (FT_IS_SCALABLE (ft_face))
1530     rfont->average_width = 0;
1531   else
1532     rfont->average_width = ft_face->available_sizes->width;
1533   rfont->next = MPLIST_VAL (frame->realized_font_list);
1534   MPLIST_VAL (frame->realized_font_list) = rfont;
1535   MDEBUG_PRINT ("  ok\n");
1536   return rfont;
1537 }
1538
1539 /* The FreeType font driver function FIND_METRIC.  */
1540
1541 static void
1542 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1543                 int from, int to)
1544 {
1545   FT_Face ft_face = rfont->fontp;
1546   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1547
1548   for (; g != gend; g++)
1549     {
1550       if (g->code == MCHAR_INVALID_CODE)
1551         {
1552           if (FT_IS_SCALABLE (ft_face))
1553             {
1554               unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1555               int size = rfont->spec.size;
1556
1557               g->lbearing = 0;
1558               g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1559               g->width = g->rbearing;
1560               g->ascent = ft_face->ascender * size / unitsPerEm10;
1561               g->descent = (- ft_face->descender) * size / unitsPerEm10;
1562             }
1563           else
1564             {
1565 #ifdef HAVE_FTBDF_H
1566               BDF_PropertyRec prop;
1567 #endif  /* HAVE_FTBDF_H */
1568
1569               g->lbearing = 0;
1570               g->rbearing = g->width = ft_face->available_sizes->width;
1571 #ifdef HAVE_FTBDF_H
1572               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1573                 {
1574                   g->ascent = prop.u.integer;
1575                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1576                   g->descent = prop.u.integer;
1577                   if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1578                                            & prop) == 0)
1579                     {
1580                       g->ascent += prop.u.integer;
1581                       g->descent -= prop.u.integer;
1582                     }
1583                 }
1584               else
1585 #endif  /* HAVE_FTBDF_H */
1586                 {
1587                   g->ascent = ft_face->available_sizes->height;
1588                   g->descent = 0;
1589                 }
1590             }
1591         }
1592       else
1593         {
1594           FT_Glyph_Metrics *metrics;
1595
1596           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1597           metrics = &ft_face->glyph->metrics;
1598           g->lbearing = (metrics->horiBearingX >> 6);
1599           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1600           g->width = metrics->horiAdvance >> 6;
1601           g->ascent = metrics->horiBearingY >> 6;
1602           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1603         }
1604       g->ascent += rfont->baseline_offset;
1605       g->descent -= rfont->baseline_offset;
1606     }
1607 }
1608
1609 static int
1610 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1611 {
1612   MRealizedFont *rfont = NULL;
1613   MRealizedFontFT *ft_rfont;
1614   FT_UInt idx;
1615
1616   if (font->type == MFONT_TYPE_REALIZED)
1617     rfont = (MRealizedFont *) font;
1618   else if (font->type == MFONT_TYPE_OBJECT)
1619     {
1620       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1621            rfont = rfont->next)
1622         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1623           break;
1624       if (! rfont)
1625         {
1626 #ifdef HAVE_FONTCONFIG
1627           MFontFT *ft_info = (MFontFT *) font;
1628
1629           if (! ft_info->charset)
1630             {
1631               FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1632                                                MSYMBOL_NAME (font->file),
1633                                                NULL);
1634               FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1635               FcFontSet *fs = FcFontList (fc_config, pat, os);
1636
1637               if (fs->nfont > 0
1638                   && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1639                                           &ft_info->charset) == FcResultMatch)
1640                 ft_info->charset = FcCharSetCopy (ft_info->charset);
1641               else
1642                 ft_info->charset = FcCharSetCreate ();
1643               FcFontSetDestroy (fs);
1644               FcObjectSetDestroy (os);
1645               FcPatternDestroy (pat);
1646             }
1647           return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1648 #else  /* not HAVE_FONTCONFIG */
1649           rfont = ft_open (frame, font, spec, NULL);
1650 #endif  /* not HAVE_FONTCONFIG */
1651         }
1652     }
1653   else
1654     MFATAL (MERROR_FONT_FT);
1655
1656   if (! rfont)
1657     return 0;
1658   ft_rfont = rfont->info;
1659   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1660   return (idx != 0);
1661 }
1662
1663 /* The FreeType font driver function ENCODE_CHAR.  */
1664
1665 static unsigned
1666 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1667 {
1668   MRealizedFont *rfont;
1669   MRealizedFontFT *ft_rfont;
1670   FT_UInt idx;
1671
1672   if (font->type == MFONT_TYPE_REALIZED)
1673     rfont = (MRealizedFont *) font;
1674   else if (font->type == MFONT_TYPE_OBJECT)
1675     {
1676       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1677            rfont = rfont->next)
1678         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1679           break;
1680       if (! rfont)
1681         {
1682           rfont = ft_open (frame, font, spec, NULL);
1683           if (! rfont)
1684             return -1;
1685         }
1686     }
1687   else
1688     MFATAL (MERROR_FONT_FT);
1689
1690   ft_rfont = rfont->info;
1691   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1692   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1693 }
1694
1695 /* The FreeType font driver function RENDER.  */
1696
1697 #define NUM_POINTS 0x1000
1698
1699 typedef struct {
1700   MDrawPoint points[NUM_POINTS];
1701   MDrawPoint *p;
1702 } MPointTable;
1703
1704 static void
1705 ft_render (MDrawWindow win, int x, int y,
1706            MGlyphString *gstring, MGlyph *from, MGlyph *to,
1707            int reverse, MDrawRegion region)
1708 {
1709   FT_Face ft_face;
1710   MRealizedFace *rface = from->rface;
1711   MFrame *frame = rface->frame;
1712   FT_Int32 load_flags = FT_LOAD_RENDER;
1713   MGlyph *g;
1714   int i, j;
1715   MPointTable point_table[8];
1716   int baseline_offset;
1717
1718   if (from == to)
1719     return;
1720
1721   /* It is assured that the all glyphs in the current range use the
1722      same realized face.  */
1723   ft_face = rface->rfont->fontp;
1724   baseline_offset = rface->rfont->baseline_offset;
1725
1726   if (! gstring->anti_alias)
1727     {
1728 #ifdef FT_LOAD_TARGET_MONO
1729       load_flags |= FT_LOAD_TARGET_MONO;
1730 #else
1731       load_flags |= FT_LOAD_MONOCHROME;
1732 #endif
1733     }
1734
1735   for (i = 0; i < 8; i++)
1736     point_table[i].p = point_table[i].points;
1737
1738   for (g = from; g < to; x += g++->width)
1739     {
1740       unsigned char *bmp;
1741       int intensity;
1742       MPointTable *ptable;
1743       int xoff, yoff;
1744       int width, pitch;
1745
1746       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1747       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1748       bmp = ft_face->glyph->bitmap.buffer;
1749       width = ft_face->glyph->bitmap.width;
1750       pitch = ft_face->glyph->bitmap.pitch;
1751       if (! gstring->anti_alias)
1752         pitch *= 8;
1753       if (width > pitch)
1754         width = pitch;
1755
1756       if (gstring->anti_alias)
1757         for (i = 0; i < ft_face->glyph->bitmap.rows;
1758              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1759           {
1760             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1761             for (j = 0; j < width; j++, xoff++)
1762               {
1763                 intensity = bmp[j] >> 5;
1764                 if (intensity)
1765                   {
1766                     ptable = point_table + intensity;
1767                     ptable->p->x = xoff;
1768                     ptable->p->y = yoff - baseline_offset;
1769                     ptable->p++;
1770                     if (ptable->p - ptable->points == NUM_POINTS)
1771                       {
1772                         (*frame->driver->draw_points)
1773                           (frame, win, rface,
1774                            reverse ? 7 - intensity : intensity,
1775                            ptable->points, NUM_POINTS, region);
1776                         ptable->p = ptable->points;
1777                       }
1778                   }
1779               }
1780           }
1781       else
1782         for (i = 0; i < ft_face->glyph->bitmap.rows;
1783              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1784           {
1785             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1786             for (j = 0; j < width; j++, xoff++)
1787               {
1788                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1789                 if (intensity)
1790                   {
1791                     ptable = point_table;
1792                     ptable->p->x = xoff;
1793                     ptable->p->y = yoff - baseline_offset;
1794                     ptable->p++;
1795                     if (ptable->p - ptable->points == NUM_POINTS)
1796                       {
1797                         (*frame->driver->draw_points) (frame, win, rface,
1798                                            reverse ? 0 : 7,
1799                                            ptable->points, NUM_POINTS, region);
1800                         ptable->p = ptable->points;
1801                       }             
1802                   }
1803               }
1804         }
1805     }
1806
1807   if (gstring->anti_alias)
1808     {
1809       for (i = 1; i < 8; i++)
1810         if (point_table[i].p != point_table[i].points)
1811           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1812                              point_table[i].points,
1813                              point_table[i].p - point_table[i].points, region);
1814     }
1815   else
1816     {
1817       if (point_table[0].p != point_table[0].points)
1818         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1819                            point_table[0].points,
1820                            point_table[0].p - point_table[0].points, region);
1821     }
1822 }
1823
1824 static int
1825 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1826 {
1827   MPlist *pl = NULL, *p;
1828   int num = 0;
1829   MPlist *file_list = NULL;
1830   MPlist *family_list = NULL, *capability_list = NULL;
1831   MSymbol registry = Mnil;
1832
1833   MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1834
1835   if (font)
1836     {
1837       MSymbol family;
1838
1839       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1840       if (registry != Mnil && registry != Miso8859_1)
1841         {
1842           char *reg = MSYMBOL_NAME (registry);
1843
1844           if (strncmp (reg, "unicode-", 8)
1845               && strncmp (reg, "apple-roman", 11)
1846               && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1847             goto done;
1848         }
1849
1850       if (font->file != Mnil
1851           && ! (file_list = ft_list_file (font->file)))
1852         goto done;
1853       family = FONT_PROPERTY (font, MFONT_FAMILY);
1854       if (family != Mnil
1855           && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1856           && MPLIST_TAIL_P (family_list))
1857         goto done;
1858       if (font->capability != Mnil)
1859         {
1860           capability_list = ft_list_capability (font->capability);
1861           if (! capability_list || MPLIST_TAIL_P (capability_list))
1862             goto done;
1863         }
1864     }
1865
1866   if (! file_list && ! family_list && ! capability_list)
1867     {
1868       /* No restriction.  Get all fonts.  */
1869       pl = mplist ();
1870       MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1871         {
1872           MPLIST_DO (p, MPLIST_PLIST (family_list))
1873             mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1874         }
1875     }
1876   else
1877     {
1878       if (file_list)
1879         {
1880           pl = mplist ();
1881           mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1882         }
1883       if (family_list)
1884         {
1885           if (pl)
1886             for (p = pl; ! MPLIST_TAIL_P (p);)
1887               {
1888                 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1889                   p = MPLIST_NEXT (p);
1890                 else
1891                   mplist_pop (p);
1892               }
1893           else
1894             {
1895               pl = mplist ();
1896               MPLIST_DO (p, family_list)
1897                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1898             }
1899         }
1900       if (capability_list)
1901         {
1902           if (pl)
1903             for (p = pl; ! MPLIST_TAIL_P (p);)
1904               {
1905                 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1906                   p = MPLIST_NEXT (p);
1907                 else
1908                   mplist_pop (p);
1909               }
1910           else
1911             {
1912               pl = mplist ();
1913               MPLIST_DO (p, capability_list)
1914                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1915             }
1916         }
1917     }
1918               
1919   if (font
1920       && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1921           + font->property[MFONT_STRETCH] + font->size) > 0)
1922     {
1923       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1924       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1925       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1926       int size = font->size;
1927
1928       for (p = pl; ! MPLIST_TAIL_P (p); )
1929         {
1930           MFontFT *ft_info = MPLIST_VAL (p);
1931
1932           if ((weight != Mnil
1933                && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1934               || (style != Mnil
1935                   && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1936               || (stretch != Mnil
1937                   && stretch != FONT_PROPERTY (&ft_info->font,
1938                                                MFONT_STRETCH))
1939               || (size > 0
1940                   && ft_info->font.size > 0
1941                   && ft_info->font.size != size))
1942             mplist_pop (p);
1943           else
1944             p = MPLIST_NEXT (p);
1945         }
1946     }
1947
1948   MPLIST_DO (p, pl)
1949     {
1950       mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1951       num++;
1952       if (maxnum && maxnum <= num)
1953         break;
1954     }
1955   M17N_OBJECT_UNREF (pl);
1956
1957  done:
1958   MDEBUG_PRINT1 ("  %d found\n", num);
1959   return num;
1960 }
1961
1962 static void
1963 ft_list_family_names (MFrame *frame, MPlist *plist)
1964 {
1965   MPlist *pl;
1966
1967   if (! ft_font_list)
1968     {
1969 #ifdef HAVE_FONTCONFIG
1970       fc_init_font_list ();
1971 #else  /* not HAVE_FONTCONFIG */
1972       ft_init_font_list ();
1973 #endif  /* not HAVE_FONTCONFIG */
1974     }
1975
1976   MPLIST_DO (pl, ft_font_list)
1977     {
1978       MSymbol family = MPLIST_KEY (pl);
1979       MPlist *p;
1980
1981 #ifdef HAVE_FONTCONFIG
1982       if (msymbol_get (family, Mgeneric_family) != Mnil)
1983         continue;
1984 #endif  /* HAVE_FONTCONFIG */
1985       MPLIST_DO (p, plist)
1986         {
1987           MSymbol sym = MPLIST_SYMBOL (p);
1988
1989           if (sym == family)
1990             break;
1991           if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
1992             {
1993               mplist_push (p, Msymbol, family);
1994               break;
1995             }
1996         }
1997       if (MPLIST_TAIL_P (p))
1998         mplist_push (p, Msymbol, family);
1999     }
2000 }
2001
2002 static int 
2003 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2004 {
2005   MFontFT *ft_info = (MFontFT *) rfont->font;
2006   MFontCapability *cap = mfont__get_capability (capability);
2007
2008   if (cap->script != Mnil
2009       && ft_check_script (ft_info, cap->script) < 0)
2010     return -1;
2011   if (cap->language != Mnil
2012       && ft_check_language (ft_info, cap->language) < 0)
2013     return -1;
2014   if (cap->script_tag && ft_check_otf (ft_info, cap) < 0)
2015     return -1;
2016   return 0;
2017 }
2018
2019
2020 \f
2021 /* Internal API */
2022
2023 MFontDriver mfont__ft_driver =
2024   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2025     ft_render, ft_list, ft_list_family_names, ft_check_capability};
2026
2027 int
2028 mfont__ft_init ()
2029 {
2030   int i;
2031
2032   if (FT_Init_FreeType (&ft_library) != 0)
2033     MERROR (MERROR_FONT_FT, -1);
2034
2035   for (i = 0; i < ft_to_prop_size; i++)
2036     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2037
2038   Mmedium = msymbol ("medium");
2039   Mr = msymbol ("r");
2040   Mnull = msymbol ("");
2041
2042   M0[0] = msymbol ("0-0");
2043   M0[1] = msymbol ("0-1");
2044   M0[2] = msymbol ("0-2");
2045   M0[3] = msymbol ("0-3");
2046   M0[4] = msymbol ("0-4");
2047   M3_1 = msymbol ("3-1");
2048   M1_0 = msymbol ("1-0");
2049
2050 #ifdef HAVE_FONTCONFIG
2051   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2052     {
2053       FC_vs_M17N_font_prop *table = fc_all_table[i];
2054       int j;
2055
2056       for (j = 0; table[j].m17n_value; j++)
2057         table[j].sym = msymbol (table[j].m17n_value);
2058       table[j].sym = table[j - 1].sym;
2059     }
2060
2061   {
2062     char *pathname;
2063     struct stat buf;
2064     MPlist *plist;
2065     MSymbol serif, sans_serif, monospace;
2066
2067     fc_config = FcInitLoadConfigAndFonts ();
2068     if (mfont_freetype_path)
2069       {
2070         MPLIST_DO (plist, mfont_freetype_path)
2071           if (MPLIST_STRING_P (plist)
2072               && (pathname = MPLIST_STRING (plist))
2073               && stat (pathname, &buf) == 0)
2074             {
2075               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2076               FcChar8 *dir;
2077
2078               while ((dir = FcStrListNext (strlist)))
2079                 if (strcmp ((char *) dir, pathname) == 0)
2080                   break;
2081               if (! dir)
2082                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2083               FcStrListDone (strlist);
2084             }
2085       }
2086     Mgeneric_family = msymbol ("generic famly");
2087     serif = msymbol ("serif");
2088     msymbol_put (serif, Mgeneric_family, serif);
2089     sans_serif = msymbol ("sans-serif");
2090     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2091     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2092     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2093     monospace = msymbol ("monospace");
2094     msymbol_put (monospace, Mgeneric_family, monospace);
2095     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2096   }
2097 #endif
2098
2099   return 0;
2100 }
2101
2102 void
2103 mfont__ft_fini ()
2104 {
2105   MPlist *plist, *p;
2106
2107   if (ft_default_list)
2108     {
2109       M17N_OBJECT_UNREF (ft_default_list);
2110       ft_default_list = NULL;
2111     }
2112
2113   if (ft_font_list)
2114     {
2115       MPLIST_DO (plist, ft_font_list)
2116         {
2117           if (MPLIST_VAL (plist))
2118             MPLIST_DO (p, MPLIST_VAL (plist))
2119               {
2120                 if (MPLIST_KEY (p) != Mt)
2121                   free_ft_info (MPLIST_VAL (p));
2122               }
2123           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2124         }
2125       M17N_OBJECT_UNREF (ft_font_list);
2126       ft_font_list = NULL;
2127
2128       if (ft_language_list)
2129         {
2130           MPLIST_DO (plist, ft_language_list)
2131             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2132           M17N_OBJECT_UNREF (ft_language_list);
2133           ft_language_list = NULL;
2134         }
2135
2136       if (ft_script_list)
2137         {
2138           MPLIST_DO (plist, ft_script_list)
2139             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2140           M17N_OBJECT_UNREF (ft_script_list);
2141           ft_script_list = NULL;
2142         }
2143
2144       if (ft_capability_list)
2145         {
2146           MPLIST_DO (plist, ft_capability_list)
2147             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2148           M17N_OBJECT_UNREF (ft_capability_list);
2149           ft_capability_list = NULL;
2150         }
2151
2152       if (ft_file_list)
2153         {
2154           MPLIST_DO (plist, ft_file_list)
2155             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2156           M17N_OBJECT_UNREF (ft_file_list);
2157           ft_file_list = NULL;
2158         }
2159     }
2160   FT_Done_FreeType (ft_library);
2161 #ifdef HAVE_FONTCONFIG
2162   FcConfigDestroy (fc_config);
2163   fc_config = NULL;
2164 #endif  /* HAVE_FONTCONFIG */
2165   all_fonts_scaned = 0;
2166 }
2167
2168 #ifdef HAVE_FONTCONFIG
2169
2170 int
2171 mfont__ft_parse_name (const char *name, MFont *font)
2172 {
2173   FcPattern *pat = FcNameParse ((FcChar8 *) name);
2174   FcChar8 *str;
2175   int val;
2176   double size;
2177   char *buf;
2178   int bufsize = 0;
2179   
2180   if (! pat)
2181     return -1;
2182   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2183     {
2184       STRDUP_LOWER (buf, bufsize, (char *) str);
2185       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2186     }
2187   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2188     {
2189       STRDUP_LOWER (buf, bufsize, (char *) str);
2190       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2191     }
2192   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2193     mfont__set_property (font, MFONT_WEIGHT,
2194                          fc_decode_prop (val, fc_weight_table,
2195                                          fc_weight_table_size));
2196   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2197     mfont__set_property (font, MFONT_STYLE,
2198                          fc_decode_prop (val, fc_slant_table,
2199                                          fc_slant_table_size));
2200   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2201     mfont__set_property (font, MFONT_STRETCH,
2202                          fc_decode_prop (val, fc_width_table,
2203                                          fc_width_table_size));
2204   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2205     font->size = size * 10 + 0.5;
2206   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2207     font->size = - (size * 10 + 0.5);
2208   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2209     {
2210       font->file = msymbol ((char *) str);
2211     }
2212   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2213   font->type = MFONT_TYPE_SPEC;
2214   FcPatternDestroy (pat);
2215   return 0;
2216 }
2217
2218 char *
2219 mfont__ft_unparse_name (MFont *font)
2220 {
2221   FcPattern *pat = fc_get_pattern (font);
2222   char *name = (char *) FcNameUnparse (pat);
2223
2224   FcPatternDestroy (pat);
2225   return name;
2226 }
2227 #endif  /* HAVE_FONTCONFIG */
2228
2229 \f
2230 #ifdef HAVE_OTF
2231
2232 #define DEVICE_DELTA(table, size)                               \
2233   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
2234    ? (table).DeltaValue[(size) - (table).StartSize]             \
2235    : 0)
2236
2237 void
2238 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2239                unsigned code, int size, int *x, int *y)
2240 {
2241   if (anchor->AnchorFormat == 2)
2242     {
2243       FT_Outline *outline;
2244       int ap = anchor->f.f1.AnchorPoint;
2245
2246       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2247       outline = &ft_face->glyph->outline;
2248       if (ap < outline->n_points)
2249         {
2250           *x = outline->points[ap].x;
2251           *y = outline->points[ap].y;
2252         }
2253     }
2254   else if (anchor->AnchorFormat == 3)
2255     {
2256       if (anchor->f.f2.XDeviceTable.offset)
2257         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2258       if (anchor->f.f2.YDeviceTable.offset)
2259       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2260     }
2261 }
2262
2263 int
2264 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2265                      MFontCapability *cap)
2266 {
2267   int len = to - from;
2268   MGlyph *g = MGLYPH (from);
2269   int i, gidx;
2270   MRealizedFont *rfont;
2271   MFontFT *ft_info;
2272   OTF *otf;
2273   OTF_GlyphString otf_gstring;
2274   OTF_Glyph *otfg;
2275   char *script, *langsys;
2276   char *gsub_features, *gpos_features;
2277   int need_cmap;
2278
2279   if (len == 0)
2280     return from;
2281
2282   otf_gstring.glyphs = NULL;
2283   rfont = g->rface->rfont;
2284   ft_info = (MFontFT *) rfont->font;
2285   if (ft_info->otf == invalid_otf)
2286     goto simple_copy;
2287   otf = ft_info->otf;
2288   if (! otf)
2289     {
2290       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2291       if (! otf)
2292         {
2293           ft_info->otf = invalid_otf;
2294           goto simple_copy;
2295         }
2296       ft_info->otf = otf;
2297     }
2298   if (OTF_get_table (otf, "head") < 0)
2299     {
2300       OTF_close (otf);
2301       ft_info->otf = invalid_otf;
2302       goto simple_copy;
2303     }
2304
2305   if (cap->script_tag)
2306     {
2307       script = alloca (5);
2308       OTF_tag_name (cap->script_tag, script);
2309     }
2310   else
2311     script = NULL;
2312   if (cap->langsys_tag)
2313     {
2314       langsys = alloca (5);
2315       OTF_tag_name (cap->langsys_tag, langsys);
2316     }
2317   else
2318     langsys = NULL;
2319   gsub_features = cap->features[MFONT_OTT_GSUB].str;
2320   if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2321     gsub_features = NULL;
2322   gpos_features = cap->features[MFONT_OTT_GPOS].str;
2323   if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2324     gpos_features = NULL;
2325
2326   otf_gstring.size = otf_gstring.used = len;
2327   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2328   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2329   for (i = 0, need_cmap = 0; i < len; i++)
2330     {
2331       if (gstring->glyphs[from + i].otf_encoded)
2332         {
2333           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2334           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2335         }
2336       else
2337         {
2338           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2339           need_cmap++;
2340         }
2341     }
2342   if (need_cmap
2343       && OTF_drive_cmap (otf, &otf_gstring) < 0)
2344     goto simple_copy;
2345
2346   OTF_drive_gdef (otf, &otf_gstring);
2347   gidx = gstring->used;
2348
2349   if (gsub_features)
2350     {
2351       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2352           < 0)
2353         goto simple_copy;
2354       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2355         {
2356           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2357
2358           temp.c = otfg->c;
2359           temp.combining_code = 0;
2360           if (otfg->glyph_id)
2361             {
2362               temp.code = otfg->glyph_id;
2363               temp.otf_encoded = 1;
2364             }
2365           else
2366             {
2367               temp.code = temp.c;
2368               temp.otf_encoded = 0;
2369             }
2370           temp.to = MGLYPH (from + otfg->f.index.to)->to;
2371           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2372         }
2373     }
2374   else
2375     for (i = 0; i < len; i++)
2376       {
2377         MGlyph temp = gstring->glyphs[from + i];
2378
2379         if (otf_gstring.glyphs[i].glyph_id)
2380           {
2381             temp.code = otf_gstring.glyphs[i].glyph_id;
2382             temp.otf_encoded = 1;
2383           }
2384         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2385       }
2386
2387   (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2388
2389   if (gpos_features)
2390     {
2391       int u;
2392       int size10, size;
2393       MGlyph *base = NULL, *mark = NULL;
2394
2395       if (OTF_check_features (otf, 1,
2396                               cap->script_tag, cap->langsys_tag,
2397                               cap->features[MFONT_OTT_GPOS].tags,
2398                               cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2399           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2400                               gpos_features) < 0))
2401         return to;
2402
2403       u = otf->head->unitsPerEm;
2404       size10 = rfont->spec.size;
2405       size = size10 / 10;
2406
2407       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2408            i < otf_gstring.used; i++, otfg++, g++)
2409         {
2410           MGlyph *prev;
2411
2412           if (! otfg->glyph_id)
2413             continue;
2414           switch (otfg->positioning_type)
2415             {
2416             case 0:
2417               break;
2418             case 1: case 2:
2419               {
2420                 int format = otfg->f.f1.format;
2421
2422                 if (format & OTF_XPlacement)
2423                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2424                 if (format & OTF_XPlaDevice)
2425                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2426                 if (format & OTF_YPlacement)
2427                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2428                 if (format & OTF_YPlaDevice)
2429                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2430                 if (format & OTF_XAdvance)
2431                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2432                 if (format & OTF_XAdvDevice)
2433                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2434               }
2435               break;
2436             case 3:
2437               /* Not yet supported.  */
2438               break;
2439             case 4: case 5:
2440               if (! base)
2441                 break;
2442               prev = base;
2443               goto label_adjust_anchor;
2444             default:            /* i.e. case 6 */
2445               if (! mark)
2446                 break;
2447               prev = mark;
2448
2449             label_adjust_anchor:
2450               {
2451                 int base_x, base_y, mark_x, mark_y;
2452
2453                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2454                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2455                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2456                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2457
2458                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2459                   adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2460                                  prev->code, size, &base_x, &base_y);
2461                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2462                   adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2463                                  g->code, size, &mark_x, &mark_y);
2464                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2465                 g->yoff = prev->yoff + mark_y - base_y;
2466                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2467               }
2468             }
2469           if (otfg->GlyphClass == OTF_GlyphClass0)
2470             base = mark = g;
2471           else if (otfg->GlyphClass == OTF_GlyphClassMark)
2472             mark = g;
2473           else
2474             base = g;
2475         }
2476     }
2477   free (otf_gstring.glyphs);
2478   return to;
2479
2480  simple_copy:
2481   ft_find_metric (rfont, gstring, from, to);
2482   for (i = 0; i < len; i++)
2483     {
2484       MGlyph temp = gstring->glyphs[from + i];
2485       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2486     }
2487   if (otf_gstring.glyphs)
2488     free (otf_gstring.glyphs);
2489   return to;
2490 }
2491
2492
2493 int
2494 mfont__ft_decode_otf (MGlyph *g)
2495 {
2496   MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2497   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2498
2499   return (c ? c : -1);
2500 }
2501
2502 #endif  /* HAVE_OTF */
2503
2504 #endif /* HAVE_FREETYPE */