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