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