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