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