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