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