(mfont__ft_fini): Unref ft_default_list. Set all
[m17n/m17n-lib.git] / src / font-ft.c
1 /* font-ft.c -- FreeType interface sub-module.
2    Copyright (C) 2003, 2004
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., 59 Temple Place, Suite 330, Boston, MA
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-gui.h"
41 #include "font.h"
42 #include "face.h"
43
44 #ifdef HAVE_FREETYPE
45
46 #ifdef HAVE_FTBDF_H
47 #include <freetype/ftbdf.h>
48 #endif
49
50 static int mdebug_mask = MDEBUG_FONT;
51
52 #ifdef HAVE_FONTCONFIG
53 static FcConfig *fc_config;
54 static MSymbol Mgeneric_family;
55 #endif  /* HAVE_FONTCONFIG */
56
57 /* Font properties; Mnormal is already defined in face.c.  */
58 static MSymbol Mmedium, Mr, Mnull;
59
60 static MSymbol M0_3, M3_1, M1_0;
61
62 static FT_Library ft_library;
63
64 #ifdef HAVE_OTF
65 static OTF *invalid_otf = (OTF *) "";
66 #endif /* HAVE_OTF */
67
68 typedef struct
69 {
70   MFont font;
71   MPlist *lang;
72 #ifdef HAVE_OTF
73   /* NULL if not yet opened.  invalid_otf if not OTF.  */
74   OTF *otf;
75 #endif /* HAVE_OTF */
76 #ifdef HAVE_FONTCONFIG
77   FcLangSet *langset;
78   FcCharSet *charset;
79 #endif  /* HAVE_FONTCONFIG */
80 } MFontFT;
81
82 typedef struct
83 {
84   M17NObject control;
85   FT_Face ft_face;
86   MPlist *charmap_list;
87 } MRealizedFontFT;
88
89 typedef struct
90 {
91   char *ft_style;
92   int len;
93   enum MFontProperty prop;
94   char *val;
95 } MFTtoProp;
96
97 static MFTtoProp ft_to_prop[] =
98   { { "italic", 0, MFONT_STYLE, "i" },
99     { "roman", 0, MFONT_STYLE, "r" },
100     { "oblique", 0, MFONT_STYLE, "o" },
101     { "regular", 0, MFONT_WEIGHT, "normal" },
102     { "normal", 0, MFONT_WEIGHT, "normal" },
103     /* We need this entry even if "bold" is in commone_weight[] to
104        handle such style names as "bolditalic" and "boldoblique".  */
105     { "bold", 0, MFONT_WEIGHT, "bold" },
106     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
107     { "demi", 0, MFONT_WEIGHT, "demibold" } };
108 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
109
110 /** List of FreeType fonts.  Keys are family names, values are plists
111     containing fonts of the corresponding family.  In the deeper
112     plist, keys are file names, values are (MFontFT *).  */
113 static MPlist *ft_font_list;
114
115 /** List of FreeType fonts.  Keys are script names, values are plists
116     containing fonts supporting the corresponding script.  In the
117     deeper plist, keys are family names, values are (MFontFT *).  */
118 static MPlist *ft_script_list;
119
120 /** List of FreeType fonts.  Keys are language names, values are
121     plists containing fonts supporting the corresponding language.  In
122     the deeper plist, keys are family names, values are (MFontFT *).  */
123 static MPlist *ft_language_list;
124
125 static MPlist *ft_file_list;
126
127 static int all_fonts_scaned;
128
129 #define STRDUP_LOWER(s1, size, s2)                              \
130   do {                                                          \
131     int len = strlen (s2) + 1;                                  \
132     char *p1, *p2;                                              \
133                                                                 \
134     if ((size) < len)                                           \
135       (s1) = alloca (len), (size) = len;                        \
136     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)                 \
137       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
138     while (p1 > (s1) && p1[-1] == ' ') p1--;                    \
139     *p1 = '\0';                                                 \
140   } while (0)
141
142
143 static void
144 free_ft_rfont (void *object)
145 {
146   MRealizedFontFT *ft_rfont = object;
147
148   M17N_OBJECT_UNREF (ft_rfont->charmap_list);
149   FT_Done_Face (ft_rfont->ft_face);
150   free (ft_rfont);
151 }
152
153 static void
154 free_ft_info (MFontFT *ft_info)
155 {
156   M17N_OBJECT_UNREF (ft_info->lang);
157 #ifdef HAVE_OTF
158   if (ft_info->otf && ft_info->otf != invalid_otf)
159     OTF_close (ft_info->otf);
160 #endif /* HAVE_OTF */
161   free (ft_info);
162 }
163
164 static MPlist *
165 ft_get_charmaps (FT_Face ft_face)
166 {
167   MPlist *plist = mplist ();
168   int unicode_bmp = -1, unicode_full = -1;
169   int i;
170
171   mplist_add (plist, Mt, (void *) -1);
172   for (i = 0; i < ft_face->num_charmaps; i++)
173     {
174       MSymbol registry = Mnil;
175
176       if (ft_face->charmaps[i]->platform_id == 0)
177         {
178           if (ft_face->charmaps[i]->encoding_id == 3)
179             registry = M0_3, unicode_bmp = i;
180           else if (ft_face->charmaps[i]->encoding_id == 4)
181             unicode_bmp = unicode_full = i;
182         }
183       else if (ft_face->charmaps[i]->platform_id == 3)
184         {
185           if (ft_face->charmaps[i]->encoding_id == 1)
186             registry = M3_1, unicode_bmp = i;
187           else if (ft_face->charmaps[i]->encoding_id == 10)
188             unicode_bmp = unicode_full = i;
189         }
190       else if (ft_face->charmaps[i]->platform_id == 1
191                && ft_face->charmaps[i]->encoding_id == 0)
192         {
193           registry = M1_0;
194           mplist_add (plist, Mapple_roman, (void *) i);
195         }
196       if (registry == Mnil)
197         {
198           char registry_buf[16];
199
200           sprintf (registry_buf, "%d-%d",
201                    ft_face->charmaps[i]->platform_id,
202                    ft_face->charmaps[i]->encoding_id);
203           registry = msymbol (registry_buf);
204         }
205       mplist_add (plist, registry, (void *) i);
206     }
207   if (unicode_full >= 0)
208     mplist_add (plist, Municode_full, (void *) unicode_full);
209   if (unicode_bmp >= 0)
210     {
211       int i;
212
213       mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
214       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
215       for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
216       if (i == 0x7F)
217         {
218           for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
219           if (i == 0x100)
220             mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
221         }
222     }
223
224   return plist;
225 }
226
227 #ifdef HAVE_FONTCONFIG
228
229 typedef struct
230 {
231   int fc_value;
232   char *m17n_value;
233   MSymbol sym;
234 } FC_vs_M17N_font_prop;
235
236 static FC_vs_M17N_font_prop fc_weight_table[] =
237   { { FC_WEIGHT_THIN, "thin" },
238     { FC_WEIGHT_ULTRALIGHT, "extralight" },
239     { FC_WEIGHT_LIGHT, "light" },
240 #ifdef FC_WEIGHT_BOOK
241     { FC_WEIGHT_BOOK, "book" },
242 #endif  /* FC_WEIGHT_BOOK */
243     { FC_WEIGHT_REGULAR, "normal" },
244     { FC_WEIGHT_NORMAL, "normal" },
245     { FC_WEIGHT_MEDIUM, "medium" },
246     { FC_WEIGHT_DEMIBOLD, "demibold" },
247     { FC_WEIGHT_BOLD, "bold" },
248     { FC_WEIGHT_EXTRABOLD, "extrabold" },
249     { FC_WEIGHT_BLACK, "black" },
250     { FC_WEIGHT_HEAVY, "heavy" },
251     { FC_WEIGHT_MEDIUM, NULL } };
252 int fc_weight_table_size =
253   sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
254
255 static FC_vs_M17N_font_prop fc_slant_table[] =
256   { { FC_SLANT_ROMAN, "r" },
257     { FC_SLANT_ITALIC, "i" },
258     { FC_SLANT_OBLIQUE, "o" },
259     { FC_SLANT_ROMAN, NULL } };
260 int fc_slant_table_size =
261   sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
262
263 static FC_vs_M17N_font_prop fc_width_table[] =
264   { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
265     { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
266     { FC_WIDTH_CONDENSED, "condensed" },
267     { FC_WIDTH_SEMICONDENSED, "semicondensed" },
268     { FC_WIDTH_NORMAL, "normal" },
269     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
270     { FC_WIDTH_EXPANDED, "expanded" },
271     { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
272     { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
273     { FC_WIDTH_NORMAL, NULL } };
274 int fc_width_table_size =
275   sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
276
277
278 static FC_vs_M17N_font_prop *fc_all_table[] =
279   { fc_weight_table, fc_slant_table, fc_width_table };
280
281 static MSymbol
282 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
283 {
284   int i = size / 2;
285
286   if (val < table[i].fc_value)
287     {
288       for (i--; i >= 0; i--)
289         if (val > table[i].fc_value)
290           break;
291       i++;
292     }
293   else
294     {
295       for (; i < size; i++)
296         if (val <= table[i].fc_value)
297           break;
298     }
299   return table[i].sym;
300 }
301
302 static int
303 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
304 {
305   int i;
306
307   for (i = 0; table[i].m17n_value; i++)
308     if (table[i].sym == sym)
309       break;
310   return table[i].fc_value;
311 }
312
313 FcPattern *
314 fc_get_pattern (MFont *font)
315 {
316   FcPattern *pat = FcPatternCreate ();
317   MSymbol sym, weight, style, stretch;
318
319
320   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
321     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
322   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
323     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
324   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
325     FcPatternAddInteger (pat, FC_WEIGHT,
326                          fc_encode_prop (weight, fc_weight_table));
327   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
328     FcPatternAddInteger (pat, FC_SLANT,
329                          fc_encode_prop (style, fc_slant_table));
330   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
331     FcPatternAddInteger (pat, FC_WIDTH,
332                          fc_encode_prop (stretch, fc_width_table));
333   if (font->size > 0)
334     {
335       double size = font->size;
336       FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
337     }
338   else if (font->size < 0)
339     {
340       double size = - font->size;
341       FcPatternAddDouble (pat, FC_SIZE, size / 10);
342     }
343   return pat;
344 }
345
346 static void
347 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
348 {
349   FcChar8 *str;
350   int val;
351   double size;
352   char *buf;
353   int bufsize = 0;
354   MSymbol sym;
355   FcLangSet *ls;
356
357   MFONT_INIT (font);
358   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
359     {
360       STRDUP_LOWER (buf, bufsize, (char *) str);
361       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
362     }
363   if (family)
364     mfont__set_property (font, MFONT_FAMILY, msymbol (family));
365   else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
366     {
367       STRDUP_LOWER (buf, bufsize, (char *) str);
368       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
369     }
370   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
371     {
372       sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
373       mfont__set_property (font, MFONT_WEIGHT, sym);
374     }
375   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
376     {
377       sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
378       mfont__set_property (font, MFONT_STYLE, sym);
379     }
380   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
381     {
382       sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
383       mfont__set_property (font, MFONT_STRETCH, sym);
384     }
385   if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
386     {
387       if (FcLangSetHasLang (ls, (FcChar8 *) "ja") == FcLangEqual
388           || FcLangSetHasLang (ls, (FcChar8 *) "zh-cn") == FcLangEqual
389           || FcLangSetHasLang (ls, (FcChar8 *) "zh-hk") == FcLangEqual
390           || FcLangSetHasLang (ls, (FcChar8 *) "zh-tw") == FcLangEqual
391           || FcLangSetHasLang (ls, (FcChar8 *) "ko") == FcLangEqual)
392         font->for_full_width = 1;
393     }
394
395   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
396   font->type = MFONT_TYPE_SPEC;
397   font->source = MFONT_SOURCE_FT;
398   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
399     font->size = size * 10;
400   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
401     font->file = msymbol ((char *) str);
402 }
403
404
405 static MFontFT *
406 fc_gen_font (FcPattern *pat, char *family)
407 {
408   MFontFT *ft_info;
409
410   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
411   fc_parse_pattern (pat, family, &ft_info->font);
412   ft_info->font.type = MFONT_TYPE_OBJECT;
413   return ft_info;
414 }
415
416 #else   /* not HAVE_FONTCONFIG */
417
418 static MPlist *
419 ft_add_font (char *filename)
420 {
421   FT_Face ft_face;
422   char *stylename;
423   int size = 0;
424   MSymbol family;
425   MFontFT *ft_info;
426   MFont *font;
427   MPlist *plist;
428   int i;
429   char *buf;
430   int bufsize = 0;
431
432   if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
433     return NULL;
434   if (! FT_IS_SCALABLE (ft_face))
435     {
436       int reject;
437 #ifdef HAVE_FTBDF_H
438       BDF_PropertyRec prop;
439
440       reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
441       size = prop.u.integer * 10;
442 #else  /* not HAVE_FTBDF_H */
443       reject = 1;
444 #endif  /* not HAVE_FTBDF_H */
445       if (reject)
446         {
447           FT_Done_Face (ft_face);
448           return NULL;
449         }
450     }
451
452   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
453   font = &ft_info->font;
454   STRDUP_LOWER (buf, bufsize, ft_face->family_name);
455   family = msymbol (buf);
456   mfont__set_property (font, MFONT_FAMILY, family);
457   mfont__set_property (font, MFONT_WEIGHT, Mmedium);
458   mfont__set_property (font, MFONT_STYLE, Mr);
459   mfont__set_property (font, MFONT_STRETCH, Mnormal);
460   mfont__set_property (font, MFONT_ADSTYLE, Mnull);
461   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
462   font->type = MFONT_TYPE_OBJECT;
463   font->source = MFONT_SOURCE_FT;
464   font->size = size;
465   font->file = msymbol (filename);
466
467   stylename = ft_face->style_name;
468   while (*stylename)
469     {
470       for (i = 0; i < ft_to_prop_size; i++)
471         if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
472                            ft_to_prop[i].len))
473           {
474             mfont__set_property (font, ft_to_prop[i].prop,
475                                  msymbol (ft_to_prop[i].val));
476             stylename += ft_to_prop[i].len;
477             break;
478           }
479       if (i == ft_to_prop_size)
480         {
481           char *p1 = stylename + 1;
482           MSymbol sym;
483
484           while (*p1 >= 'a' && *p1 <= 'z') p1++;
485           sym = msymbol__with_len (stylename, p1 - stylename);
486           for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
487             if (msymbol_get (sym, mfont__property_table[i].property))
488               {
489                 mfont__set_property (font, i, sym);
490                 break;
491               }
492           stylename = p1;
493         }
494       while (*stylename && ! isalpha (*stylename))
495         stylename++;
496     }
497
498   FT_Done_Face (ft_face);
499
500   plist = mplist_find_by_key (ft_font_list, family);
501   if (plist)
502     mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
503   else
504     {
505       plist = mplist ();
506       mplist_add (plist, font->file, ft_info);
507       plist = mplist_push (ft_font_list, family, plist);
508     }
509   return plist;
510 }
511
512 #endif  /* not HAVE_FONTCONFIG */
513
514
515 /* Return an element of ft_font_list for FAMILY.  If FAMILY is Mnil,
516    scan all fonts and return ft_font_list.  */
517
518 static MPlist *
519 ft_list_family (MSymbol family, int check_generic)
520 {
521   MPlist *plist;
522 #ifdef HAVE_FONTCONFIG
523   char *fam;
524   MPlist *pl, *p;
525   FcPattern *pattern;
526   FcObjectSet *os;
527   FcFontSet *fs;
528   int i;
529   char *buf;
530   int bufsize = 0;
531   MSymbol generic;
532
533   if (! ft_font_list)
534     {
535       MSymbol sym;
536
537       plist = ft_font_list = mplist ();
538       pattern = FcPatternCreate ();
539       os = FcObjectSetBuild (FC_FAMILY, NULL);
540       fs = FcFontList (fc_config, pattern, os);
541       for (i = 0; i < fs->nfont; i++)
542         {
543           if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
544                                   (FcChar8 **) &fam) != FcResultMatch)
545             continue;
546           STRDUP_LOWER (buf, bufsize, fam);
547           sym = msymbol (buf);
548           if (! mplist_find_by_key (ft_font_list, sym))
549             plist = mplist_add (plist, sym, NULL);
550         }
551       FcFontSetDestroy (fs);
552       FcObjectSetDestroy (os);
553       FcPatternDestroy (pattern);
554     }
555
556   if (family == Mnil)
557     {
558       if (! all_fonts_scaned)
559         {
560           MPLIST_DO (plist, ft_font_list)
561             {
562               if (! MPLIST_VAL (plist))
563                 ft_list_family (MPLIST_KEY (plist), 0);
564             }
565           all_fonts_scaned = 1;
566         }
567       return ft_font_list;
568     }
569
570   plist = mplist_find_by_key (ft_font_list, family);
571   if (plist)
572     {
573       if (! MPLIST_VAL (plist))
574         {
575           fam = MSYMBOL_NAME (family);
576           pattern = FcPatternCreate ();
577           FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
578           os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
579                                  FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL);
580           fs = FcFontList (fc_config, pattern, os);
581           p = pl = mplist ();
582           for (i = 0; i < fs->nfont; i++)
583             {
584               MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
585               p = mplist_add (p, ft_info->font.file, ft_info);
586             }
587           MPLIST_VAL (plist) = pl;
588           FcFontSetDestroy (fs);
589           FcObjectSetDestroy (os);
590           FcPatternDestroy (pattern);
591         }
592     }
593   else if (check_generic
594            && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
595     {
596       /* Check if FAMILY is a geneneric family (e.g. `serif').  */
597       FcChar8 *fam8;
598       
599       if (family != generic)
600         plist = ft_list_family (generic, 1);
601       else
602         {
603           fam = MSYMBOL_NAME (family);
604           plist = mplist ();
605           mplist_push (ft_font_list, family, plist);
606           pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
607           FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
608           for (i = 0; 1; i++)
609             {
610               if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
611                   != FcResultMatch)
612                 break;
613               STRDUP_LOWER (buf, bufsize, (char *) fam8);
614               family = msymbol (buf);
615               if (msymbol_get (family, Mgeneric_family))
616                 break;
617               pl = ft_list_family (family, 0);
618               if (! pl)
619                 continue;
620               MPLIST_DO (pl, MPLIST_PLIST (pl))
621                 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
622             }
623           plist = ft_font_list;
624         }
625     }
626   else
627     {
628       /* Check if there exist an alias.  */
629       pl = mplist ();
630       plist = mplist_add (ft_font_list, family, pl);
631
632       pattern = FcPatternBuild (NULL,
633                                 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
634                                 NULL);
635       FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
636
637       for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
638                                       (FcChar8 **) &fam) == FcResultMatch;
639            i++);
640       if (i > 0)
641         {
642           /* The last one is a generic family.  */
643           MSymbol sym;
644           int j;
645           FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
646                                            NULL);
647
648           FcConfigSubstitute (fc_config, pat, FcMatchPattern);
649           for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
650                                           (FcChar8 **) &fam) == FcResultMatch;
651                j++);
652
653           /* Now we know that the last J fonts in PATTERN are from
654              generic font, and the first one is not available.  So,
655              the remaining ones are aliases.  */
656           j = i - j;
657           for (i = 1; i < j; i++)
658             {
659               FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
660               STRDUP_LOWER (buf, bufsize, fam);
661               sym = msymbol (buf);
662               p = MPLIST_PLIST (ft_list_family (sym, 0));
663               if (! MPLIST_TAIL_P (p))
664                 MPLIST_DO (p, p)
665                   mplist_push (pl, Mt, MPLIST_VAL (p));
666             }
667         }
668     }
669
670 #else  /* not HAVE_FONTCONFIG */
671
672   if (! all_fonts_scaned)
673     {
674       MPlist *plist;
675       struct stat buf;
676       char *pathname;
677       char *path;
678       USE_SAFE_ALLOCA;
679
680       ft_font_list = mplist ();
681       MPLIST_DO (plist, mfont_freetype_path)
682         if (MPLIST_STRING_P (plist)
683             && (pathname = MPLIST_STRING (plist))
684             && stat (pathname, &buf) == 0)
685           {
686             if (S_ISREG (buf.st_mode))
687               ft_add_font (pathname);
688             else if (S_ISDIR (buf.st_mode))
689               {
690                 DIR *dir = opendir (pathname);
691
692                 if (dir)
693                   {
694                     int len = strlen (pathname);
695                     struct dirent *dp;
696
697                     while ((dp = readdir (dir)) != NULL)
698                       {
699                         SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
700                         strcpy (path, pathname);
701                         path[len] =  '/';
702                         strcpy (path + len + 1, dp->d_name);
703                         ft_add_font (path);
704                       }
705                     closedir (dir);
706                   }
707               }
708           }
709       SAFE_FREE (path);
710       all_fonts_scaned = 1;
711     }
712   if (family == Mnil)
713     plist = ft_font_list;
714   else
715     {
716       plist = mplist_find_by_key (ft_font_list, family);
717       if (! plist)
718         plist = mplist_push (ft_font_list, family, mplist ());
719     }
720 #endif  /* not HAVE_FONTCONFIG */
721
722   return plist;
723 }
724
725 static MPlist *
726 ft_list_language (MSymbol language)
727 {
728   MPlist *plist = NULL;
729   MText *mt;
730   int step;
731
732   if (! ft_language_list)
733     ft_language_list = mplist ();
734   else if ((plist = mplist_find_by_key (ft_language_list, language)))
735     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
736
737 #ifdef HAVE_FONTCONFIG
738   for (step = 0; step < 2; step++)
739     {
740       FcPattern *pattern = NULL;
741       FcObjectSet *os = NULL;
742       FcFontSet *fs = NULL;
743       char *buf;
744       int bufsize = 0;
745       int i;
746
747       if (! (pattern = FcPatternCreate ())
748           || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
749         goto err;
750       if (step == 0)
751         {
752           FcLangSet *ls = FcLangSetCreate ();
753
754           if (! ls)
755             goto err;
756           if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
757               && FcPatternAddLangSet (pattern, FC_LANG, ls))
758             fs = FcFontList (fc_config, pattern, os);
759           FcLangSetDestroy (ls);
760           if (! fs)
761             goto err;
762         }
763       else
764         {
765           FcCharSet *cs;
766
767           if (! (mt = msymbol_get (language, Mtext)))
768             break;
769           if (! (cs = FcCharSetCreate ()))
770             goto err;
771           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
772             if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
773               break;
774           if (i < 0)
775             {
776               if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
777                 fs = FcFontList (fc_config, pattern, os);
778             }
779           FcCharSetDestroy (cs);
780           if (! fs)
781             goto err;
782         }
783
784       for (i = 0; i < fs->nfont; i++)
785         {
786           MSymbol family, file;
787           char *fam, *filename;
788           MPlist *pl;
789           MFontFT *ft_info;
790
791           if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
792                                   (FcChar8 **) &fam) != FcResultMatch)
793             continue;
794           if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
795                                   (FcChar8 **) &filename) != FcResultMatch)
796             continue;
797           STRDUP_LOWER (buf, bufsize, fam);
798           family = msymbol (buf);
799           file = msymbol (filename);
800           pl = MPLIST_PLIST (ft_list_family (family, 0));
801           ft_info = mplist_get (pl, file);
802           if (ft_info)
803             {
804               if (! plist)
805                 plist = mplist ();
806               mplist_add (plist, family, ft_info);
807             }
808         }
809       FcFontSetDestroy (fs);
810       FcObjectSetDestroy (os);
811       FcPatternDestroy (pattern);
812       if (language == msymbol ("en"))
813         break;
814       continue;
815
816     err:
817       if (os)
818         FcObjectSetDestroy (os);
819       if (pattern)
820         FcPatternDestroy (pattern);
821       MEMORY_FULL (MERROR_FONT_FT);
822       return NULL;
823     }
824
825   mplist_push (ft_language_list, language, plist);
826   return plist;
827
828 #else   /* not HAVE_FONTCONFIG */
829   
830   if ((mt = msymbol_get (language, Mtext)))
831     {
832       MPlist *pl, *p;
833       int len = mtext_nchars (mt);
834       int i;
835
836       if (! ft_font_list)
837         ft_list_family (Mnil, 0);
838       MPLIST_DO (pl, ft_font_list)
839         {
840           MPLIST_DO (p, MPLIST_PLIST (pl))
841             {
842               MFontFT *ft_info = MPLIST_VAL (p);
843               MSymbol family; 
844               FT_Face ft_face;
845
846               if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
847                                0, &ft_face) != 0)
848                 continue;
849               for (i = 0; i < len; i++)
850                 if (FT_Get_Char_Index (ft_face, 
851                                        (FT_ULong) mtext_ref_char (mt, i)) == 0)
852                   break;
853               FT_Done_Face (ft_face);
854               if (i < len)
855                 continue;
856               if (! plist)
857                 plist = mplist ();
858               family = mfont_get_prop (&ft_info->font, Mfamily);
859               mplist_push (plist, family, ft_info);
860             }
861         }
862     }
863   return plist;
864 #endif  /* not HAVE_FONTCONFIG */
865 }
866
867 static MPlist *
868 ft_list_script (MSymbol script)
869 {
870   MPlist *plist = NULL;
871   MPlist *language_list, *pl;
872
873   if (! ft_script_list)
874     ft_script_list = mplist ();
875   else if ((plist = mplist_find_by_key (ft_script_list, script)))
876     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
877
878   language_list = mlanguage__list (script);
879   MPLIST_DO (pl, language_list)
880     {
881       MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
882       MPlist *p = ft_list_language (language);
883       MSymbol family;
884
885       if (! p)
886         continue;
887       if (! plist)
888         plist = mplist ();
889       MPLIST_DO (p, p)
890         {
891           family = MPLIST_KEY (p);
892           if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
893             mplist_add (plist, family, MPLIST_VAL (p));
894         }
895     }
896   mplist_push (ft_script_list, script, plist);
897   M17N_OBJECT_UNREF (language_list);
898   return (plist);
899 }
900
901 static int
902 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
903 {
904   if (ft_info->otf == invalid_otf)
905     return -1;
906   if (! ft_info->otf)
907     {
908       ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
909       if (! ft_info->otf)
910         {
911           ft_info->otf = invalid_otf;
912           return -1;
913         }
914     }
915   if (cap->features[MFONT_OTT_GSUB].nfeatures
916       && cap->features[MFONT_OTT_GSUB].tags[0]
917       && (OTF_check_features
918           (ft_info->otf, 1,
919            cap->script_tag, cap->langsys_tag,
920            cap->features[MFONT_OTT_GSUB].tags,
921            cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
922     return -1;
923   if (cap->features[MFONT_OTT_GPOS].nfeatures
924       && cap->features[MFONT_OTT_GPOS].tags[0]
925       && (OTF_check_features
926           (ft_info->otf, 0,
927            cap->script_tag, cap->langsys_tag,
928            cap->features[MFONT_OTT_GPOS].tags,
929            cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
930     return -1;
931   return 0;
932 }
933
934 static int
935 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
936 {
937 #ifdef HAVE_FONTCONFIG
938   MPlist *plist;
939   MText *mt;
940   int i, j;
941
942   for (i = 0; cap->lang[i] != Mnil; i++)
943     {
944       if (ft_info->lang
945           && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
946         {
947           if (MPLIST_VAL (plist))
948             return 0;
949           continue;
950         }
951
952       if (! ft_info->langset)
953         {
954           FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
955                                            MSYMBOL_NAME (ft_info->font.file),
956                                            NULL);
957           FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
958           FcFontSet *fs = FcFontList (fc_config, pat, os);
959
960           if (fs->nfont == 0)
961             return -1;
962           if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
963               == FcResultMatch)
964             ft_info->langset = FcLangSetCopy (ft_info->langset);
965           else
966             ft_info->langset = FcLangSetCreate ();
967           FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
968           FcFontSetDestroy (fs);
969           FcObjectSetDestroy (os);
970           FcPatternDestroy (pat);
971         }
972       if (! ft_info->lang)
973         ft_info->lang = mplist ();
974       if (FcLangSetHasLang (ft_info->langset,
975                             (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
976           == FcLangEqual)
977         {
978           mplist_push (ft_info->lang, cap->lang[i], Mt);
979           return 0;
980         }
981
982       mt = msymbol_get (cap->lang[i], Mtext);
983       if (! mt)
984         {
985           mplist_push (ft_info->lang, cap->lang[i], Mnil);
986           continue;
987         }
988
989       for (j = mtext_nchars (mt) - 1; j >= 0; j--)
990         if (! FcCharSetAddChar (ft_info->charset,
991                                 (FcChar32) mtext_ref_char (mt, j)))
992           break;
993       mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
994       if (j < 0)
995         return 0;
996     }
997 #endif  /* HAVE_FONTCONFIG */
998   return -1;
999 }
1000
1001 static MPlist *ft_default_list;
1002
1003 static MPlist *
1004 ft_list_default ()
1005 {
1006   if (ft_default_list)
1007     return ft_default_list;
1008   ft_default_list = mplist ();
1009 #ifdef HAVE_FONTCONFIG
1010   {
1011     FcPattern *pat = FcPatternCreate ();
1012     FcChar8 *fam;
1013     char *buf;
1014     int bufsize = 0;
1015     int i;
1016
1017     FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1018     for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1019          i++)
1020       {
1021         MSymbol family;
1022         MPlist *plist;
1023
1024         STRDUP_LOWER (buf, bufsize, (char *) fam);
1025         family = msymbol (buf);
1026         if (msymbol_get (family, Mgeneric_family))
1027           continue;
1028         plist = MPLIST_PLIST (ft_list_family (family, 0));
1029         MPLIST_DO (plist, plist)
1030           mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1031       }
1032   }
1033 #else  /* not HAVE_FONTCONFIG */
1034   {
1035     MPlist *plist, *pl;
1036
1037     MPLIST_DO (plist, ft_list_family (Mnil, 0))
1038       {
1039         pl = MPLIST_PLIST (plist);
1040         if (! MPLIST_TAIL_P (pl))
1041           mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1042       }
1043   }
1044 #endif  /* not HAVE_FONTCONFIG */
1045   return ft_default_list;
1046 }
1047
1048
1049 static MPlist *ft_capability_list;
1050
1051 static MPlist *
1052 ft_list_capability (MSymbol sym)
1053 {
1054   MPlist *plist, *pl, *p;
1055   MFontCapability *cap = mfont__get_capability (sym);
1056
1057   if (! cap)
1058     return NULL;
1059   if (ft_capability_list)
1060     {
1061       plist = mplist_find_by_key (ft_capability_list, sym);
1062       if (plist)
1063         return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1064     }
1065   else
1066     {
1067       plist = NULL;
1068       ft_capability_list = mplist ();
1069     }
1070
1071   if (cap->script != Mnil)
1072     {
1073       pl = ft_list_script (cap->script);
1074       if (pl)
1075         MPLIST_DO (pl, pl)
1076           {
1077             if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1078               continue;
1079             if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
1080               continue;
1081             if (! plist)
1082               plist = mplist ();
1083             mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
1084         }
1085       mplist_push (ft_capability_list, sym, plist);
1086       return plist;
1087     }
1088
1089   if (cap->lang)
1090     {
1091       int i;
1092
1093       for (i = 0; cap->lang[i] != Mnil; i++)
1094         {
1095           p = ft_list_language (cap->lang[i]);
1096           if (p)
1097             {
1098               if (! plist)
1099                 plist = mplist ();
1100               MPLIST_DO (p, p)
1101                 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1102             }
1103         }
1104     }
1105   mplist_push (ft_capability_list, sym, plist);
1106   return plist;
1107 }
1108
1109
1110 static MPlist *
1111 ft_list_file (MSymbol filename)
1112 {
1113   MPlist *plist = NULL;
1114
1115   if (! ft_file_list)
1116     ft_file_list = mplist ();
1117   else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1118     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1119
1120 #ifdef HAVE_FONTCONFIG
1121   {
1122     FcPattern *pattern = FcPatternCreate ();
1123     FcObjectSet *os;
1124     FcFontSet *fs;
1125
1126     FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1127     os = FcObjectSetBuild (FC_FAMILY, NULL);
1128     fs = FcFontList (fc_config, pattern, os);
1129     if (fs->nfont > 0)
1130       {
1131         char *fam;
1132         char *buf;
1133         int bufsize = 0;
1134
1135         if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1136                                 (FcChar8 **) &fam) == FcResultMatch)
1137           {
1138             MSymbol family;
1139             MPlist *pl;
1140
1141             STRDUP_LOWER (buf, bufsize, fam);
1142             family = msymbol (buf);
1143             pl = ft_list_family (family, 0);
1144             MPLIST_DO (pl, MPLIST_PLIST (pl))
1145               {
1146                 MFontFT *ft_info = MPLIST_VAL (pl);
1147
1148                 if (ft_info->font.file == filename)
1149                   {
1150                     plist = mplist ();
1151                     mplist_add (plist, family, ft_info);
1152                     break;
1153                   }
1154               }
1155           }
1156       }
1157   }
1158 #else  /* not HAVE_FONTCONFIG */
1159   {
1160     MPlist *pl, *p;
1161
1162     MPLIST_DO (pl, ft_list_family (Mnil, 0))
1163       {
1164         MPLIST_DO (p, MPLIST_PLIST (pl))
1165           {
1166             MFontFT *ft_info = MPLIST_VAL (pl);
1167
1168             if (ft_info->font.file == filename)
1169               {
1170                 plist = mplist ();
1171                 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1172                 break;
1173               }
1174           }
1175         if (plist)
1176           break;
1177       }
1178   }
1179 #endif  /* not HAVE_FONTCONFIG */
1180
1181   mplist_push (ft_file_list, filename, plist);
1182   return plist;
1183 }
1184
1185 /* The FreeType font driver function SELECT.  */
1186
1187 static MFont *
1188 ft_select (MFrame *frame, MFont *font, int limited_size)
1189 {
1190   MFont *found = NULL;
1191 #ifdef HAVE_FONTCONFIG
1192   MPlist *plist, *pl;
1193   MFontFT *ft_info;
1194   int check_font_property = 1;
1195
1196   if (font->file != Mnil)
1197     {
1198       plist = ft_list_file (font->file);
1199       if (! plist)
1200         return NULL;
1201       check_font_property = 0;
1202     }
1203   else
1204     {
1205       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1206
1207       if (family)
1208         plist = MPLIST_PLIST (ft_list_family (family, 1));
1209       else
1210         plist = ft_list_default ();
1211       if (MPLIST_TAIL_P (plist))
1212         return NULL;
1213     }
1214
1215   plist = mplist_copy (plist);
1216
1217   if (font->capability != Mnil)
1218     {
1219       MFontCapability *cap = mfont__get_capability (font->capability);
1220
1221       for (pl = plist; ! MPLIST_TAIL_P (pl);)
1222         {
1223           if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1224               || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1225             mplist_pop (pl);
1226           else
1227             pl = MPLIST_NEXT (pl);
1228         }
1229     }
1230
1231   if (check_font_property)
1232     {
1233       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1234       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1235       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1236       MSymbol alternate_weight = Mnil;
1237
1238       if (weight == Mnormal)
1239         alternate_weight = Mmedium;
1240       else if (weight == Mmedium)
1241         alternate_weight = Mnormal;
1242       if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1243         for (pl = plist; ! MPLIST_TAIL_P (pl); )
1244           {
1245             ft_info = MPLIST_VAL (pl);
1246             if ((weight != Mnil
1247                  && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1248                      && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1249                 || (style != Mnil
1250                     && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1251                 || (stretch != Mnil
1252                     && stretch != FONT_PROPERTY (&ft_info->font,
1253                                                  MFONT_STRETCH))
1254                 || (font->size > 0
1255                     && ft_info->font.size > 0
1256                     && ft_info->font.size != font->size))
1257               mplist_pop (pl);
1258             else
1259               pl = MPLIST_NEXT (pl);
1260           }
1261     }
1262
1263   MPLIST_DO (pl, plist)
1264     {
1265       font = MPLIST_VAL (plist);
1266       if (limited_size == 0
1267           || font->size == 0
1268           || font->size <= limited_size)
1269         {
1270           found = font;
1271           break;
1272         }
1273     }
1274   M17N_OBJECT_UNREF (plist);
1275 #endif
1276   return found;
1277 }
1278
1279
1280 static MRealizedFont *
1281 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1282 {
1283   MFontFT *ft_info = (MFontFT *) font;
1284   int reg = spec->property[MFONT_REGISTRY];
1285   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1286   MRealizedFontFT *ft_rfont;
1287   FT_Face ft_face;
1288   MPlist *plist, *charmap_list = NULL;
1289   int charmap_index;
1290   int size = font->size ? font->size : spec->size;
1291
1292   if (rfont)
1293     {
1294       charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1295       for (; rfont; rfont = rfont->next)
1296         if (rfont->font == font
1297             && (rfont->font->size ? rfont->font->size == size
1298                 : rfont->spec.size == size)
1299             && rfont->spec.property[MFONT_REGISTRY] == reg
1300             && rfont->driver == &mfont__ft_driver)
1301           return rfont;
1302     }
1303
1304   MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (spec));
1305
1306   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1307                    &ft_face))
1308     {
1309       font->type = MFONT_TYPE_FAILURE;
1310       MDEBUG_PRINT ("  no\n");
1311       return NULL;
1312     }
1313   if (charmap_list)
1314     M17N_OBJECT_REF (charmap_list);
1315   else
1316     charmap_list = ft_get_charmaps (ft_face);
1317   if (registry == Mnil)
1318     registry = Municode_bmp;
1319   plist = mplist_find_by_key (charmap_list, registry);
1320   if (! plist)
1321     {
1322       FT_Done_Face (ft_face);
1323       M17N_OBJECT_UNREF (charmap_list);
1324       MDEBUG_PRINT ("  no\n");
1325       return NULL;
1326     }
1327   charmap_index = (int) MPLIST_VAL (plist);
1328   if ((charmap_index >= 0
1329        && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1330       || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1331     {
1332       FT_Done_Face (ft_face);
1333       M17N_OBJECT_UNREF (charmap_list);
1334       font->type = MFONT_TYPE_FAILURE;
1335       MDEBUG_PRINT ("  no\n");
1336       return NULL;
1337     }
1338
1339   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1340   ft_rfont->ft_face = ft_face;
1341   ft_rfont->charmap_list = charmap_list;
1342   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1343   rfont->spec = *font;
1344   rfont->spec.type = MFONT_TYPE_REALIZED;
1345   rfont->spec.property[MFONT_REGISTRY] = reg;
1346   rfont->spec.size = size;
1347   rfont->frame = frame;
1348   rfont->font = font;
1349   rfont->driver = &mfont__ft_driver;
1350   rfont->info = ft_rfont;
1351   rfont->fontp = ft_face;
1352   rfont->ascent = ft_face->size->metrics.ascender >> 6;
1353   rfont->descent = - ft_face->size->metrics.descender >> 6;
1354   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1355   rfont->baseline_offset = 0;
1356 #ifdef HAVE_FTBDF_H
1357   {
1358     BDF_PropertyRec prop;
1359
1360     if (! FT_IS_SCALABLE (ft_face)
1361         && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1362       {
1363         rfont->baseline_offset = prop.u.integer;
1364         rfont->ascent += prop.u.integer;
1365         rfont->descent -= prop.u.integer;
1366       }
1367   }
1368 #endif
1369   if (FT_IS_SCALABLE (ft_face))
1370     rfont->average_width = 0;
1371   else
1372     rfont->average_width = ft_face->available_sizes->width;
1373   rfont->next = MPLIST_VAL (frame->realized_font_list);
1374   MPLIST_VAL (frame->realized_font_list) = rfont;
1375   MDEBUG_PRINT ("  ok\n");
1376   return rfont;
1377 }
1378
1379 /* The FreeType font driver function FIND_METRIC.  */
1380
1381 static void
1382 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1383                 int from, int to)
1384 {
1385   FT_Face ft_face = rfont->fontp;
1386   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1387
1388   for (; g != gend; g++)
1389     {
1390       if (g->code == MCHAR_INVALID_CODE)
1391         {
1392           if (FT_IS_SCALABLE (ft_face))
1393             {
1394               unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1395               int size = rfont->spec.size;
1396
1397               g->lbearing = 0;
1398               g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1399               g->width = g->rbearing;
1400               g->ascent = ft_face->ascender * size / unitsPerEm10;
1401               g->descent = (- ft_face->descender) * size / unitsPerEm10;
1402             }
1403           else
1404             {
1405 #ifdef HAVE_FTBDF_H
1406               BDF_PropertyRec prop;
1407 #endif
1408
1409               g->lbearing = 0;
1410               g->rbearing = g->width = ft_face->available_sizes->width;
1411 #ifdef HAVE_FTBDF_H
1412               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1413                 {
1414                   g->ascent = prop.u.integer;
1415                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1416                   g->descent = prop.u.integer;
1417                   if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1418                                            & prop) == 0)
1419                     {
1420                       g->ascent += prop.u.integer;
1421                       g->descent -= prop.u.integer;
1422                     }
1423                 }
1424               else
1425 #endif
1426                 {
1427                   g->ascent = ft_face->available_sizes->height;
1428                   g->descent = 0;
1429                 }
1430             }
1431         }
1432       else
1433         {
1434           FT_Glyph_Metrics *metrics;
1435
1436           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1437           metrics = &ft_face->glyph->metrics;
1438           g->lbearing = (metrics->horiBearingX >> 6);
1439           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1440           g->width = metrics->horiAdvance >> 6;
1441           g->ascent = metrics->horiBearingY >> 6;
1442           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1443         }
1444       g->ascent += rfont->baseline_offset;
1445       g->descent -= rfont->baseline_offset;
1446     }
1447 }
1448
1449 static int
1450 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1451 {
1452   MRealizedFont *rfont = NULL;
1453   MRealizedFontFT *ft_rfont;
1454   FT_UInt idx;
1455
1456   if (font->type == MFONT_TYPE_REALIZED)
1457     rfont = (MRealizedFont *) font;
1458   else if (font->type == MFONT_TYPE_OBJECT)
1459     {
1460       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1461            rfont = rfont->next)
1462         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1463           break;
1464       if (! rfont)
1465         {
1466 #ifdef HAVE_FONTCONFIG
1467           MFontFT *ft_info = (MFontFT *) font;
1468
1469           if (! ft_info->charset)
1470             {
1471               FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1472                                                MSYMBOL_NAME (font->file),
1473                                                NULL);
1474               FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1475               FcFontSet *fs = FcFontList (fc_config, pat, os);
1476
1477               if (fs->nfont > 0
1478                   && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1479                                           &ft_info->charset) == FcResultMatch)
1480                 ft_info->charset = FcCharSetCopy (ft_info->charset);
1481               else
1482                 ft_info->charset = FcCharSetCreate ();
1483               FcFontSetDestroy (fs);
1484               FcObjectSetDestroy (os);
1485               FcPatternDestroy (pat);
1486             }
1487           return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1488 #else  /* not HAVE_FONTCONFIG */
1489           rfont = ft_open (frame, font, spec, NULL);
1490 #endif  /* not HAVE_FONTCONFIG */
1491         }
1492     }
1493   else
1494     MFATAL (MERROR_FONT_FT);
1495
1496   if (! rfont)
1497     return 0;
1498   ft_rfont = rfont->info;
1499   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1500   return (idx != 0);
1501 }
1502
1503 /* The FreeType font driver function ENCODE_CHAR.  */
1504
1505 static unsigned
1506 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1507 {
1508   MRealizedFont *rfont;
1509   MRealizedFontFT *ft_rfont;
1510   FT_UInt idx;
1511
1512   if (font->type == MFONT_TYPE_REALIZED)
1513     rfont = (MRealizedFont *) font;
1514   else if (font->type == MFONT_TYPE_OBJECT)
1515     {
1516       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1517            rfont = rfont->next)
1518         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1519           break;
1520       if (! rfont)
1521         {
1522           rfont = ft_open (frame, font, spec, NULL);
1523           if (! rfont)
1524             return -1;
1525         }
1526     }
1527   else
1528     MFATAL (MERROR_FONT_FT);
1529
1530   ft_rfont = rfont->info;
1531   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1532   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1533 }
1534
1535 /* The FreeType font driver function RENDER.  */
1536
1537 #define NUM_POINTS 0x1000
1538
1539 typedef struct {
1540   MDrawPoint points[NUM_POINTS];
1541   MDrawPoint *p;
1542 } MPointTable;
1543
1544 static void
1545 ft_render (MDrawWindow win, int x, int y,
1546            MGlyphString *gstring, MGlyph *from, MGlyph *to,
1547            int reverse, MDrawRegion region)
1548 {
1549   FT_Face ft_face;
1550   MRealizedFace *rface = from->rface;
1551   MFrame *frame = rface->frame;
1552   FT_Int32 load_flags = FT_LOAD_RENDER;
1553   MGlyph *g;
1554   int i, j;
1555   MPointTable point_table[8];
1556   int baseline_offset;
1557
1558   if (from == to)
1559     return;
1560
1561   /* It is assured that the all glyphs in the current range use the
1562      same realized face.  */
1563   ft_face = rface->rfont->fontp;
1564   baseline_offset = rface->rfont->baseline_offset;
1565
1566   if (! gstring->anti_alias)
1567     {
1568 #ifdef FT_LOAD_TARGET_MONO
1569       load_flags |= FT_LOAD_TARGET_MONO;
1570 #else
1571       load_flags |= FT_LOAD_MONOCHROME;
1572 #endif
1573     }
1574
1575   for (i = 0; i < 8; i++)
1576     point_table[i].p = point_table[i].points;
1577
1578   for (g = from; g < to; x += g++->width)
1579     {
1580       unsigned char *bmp;
1581       int intensity;
1582       MPointTable *ptable;
1583       int xoff, yoff;
1584       int width, pitch;
1585
1586       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1587       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1588       bmp = ft_face->glyph->bitmap.buffer;
1589       width = ft_face->glyph->bitmap.width;
1590       pitch = ft_face->glyph->bitmap.pitch;
1591       if (! gstring->anti_alias)
1592         pitch *= 8;
1593       if (width > pitch)
1594         width = pitch;
1595
1596       if (gstring->anti_alias)
1597         for (i = 0; i < ft_face->glyph->bitmap.rows;
1598              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1599           {
1600             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1601             for (j = 0; j < width; j++, xoff++)
1602               {
1603                 intensity = bmp[j] >> 5;
1604                 if (intensity)
1605                   {
1606                     ptable = point_table + intensity;
1607                     ptable->p->x = xoff;
1608                     ptable->p->y = yoff - baseline_offset;
1609                     ptable->p++;
1610                     if (ptable->p - ptable->points == NUM_POINTS)
1611                       {
1612                         (*frame->driver->draw_points)
1613                           (frame, win, rface,
1614                            reverse ? 7 - intensity : intensity,
1615                            ptable->points, NUM_POINTS, region);
1616                         ptable->p = ptable->points;
1617                       }
1618                   }
1619               }
1620           }
1621       else
1622         for (i = 0; i < ft_face->glyph->bitmap.rows;
1623              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1624           {
1625             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1626             for (j = 0; j < width; j++, xoff++)
1627               {
1628                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1629                 if (intensity)
1630                   {
1631                     ptable = point_table;
1632                     ptable->p->x = xoff;
1633                     ptable->p->y = yoff - baseline_offset;
1634                     ptable->p++;
1635                     if (ptable->p - ptable->points == NUM_POINTS)
1636                       {
1637                         (*frame->driver->draw_points) (frame, win, rface,
1638                                            reverse ? 0 : 7,
1639                                            ptable->points, NUM_POINTS, region);
1640                         ptable->p = ptable->points;
1641                       }             
1642                   }
1643               }
1644         }
1645     }
1646
1647   if (gstring->anti_alias)
1648     {
1649       for (i = 1; i < 8; i++)
1650         if (point_table[i].p != point_table[i].points)
1651           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1652                              point_table[i].points,
1653                              point_table[i].p - point_table[i].points, region);
1654     }
1655   else
1656     {
1657       if (point_table[0].p != point_table[0].points)
1658         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1659                            point_table[0].points,
1660                            point_table[0].p - point_table[0].points, region);
1661     }
1662 }
1663
1664 static int
1665 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1666 {
1667   MPlist *pl = NULL, *p;
1668   int num = 0;
1669   MPlist *file_list = NULL;
1670   MPlist *family_list = NULL, *capability_list = NULL;
1671   MSymbol registry = Mnil;
1672
1673   MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1674
1675   if (font)
1676     {
1677       MSymbol family;
1678
1679       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1680       if (registry != Mnil && registry != Miso8859_1)
1681         {
1682           char *reg = MSYMBOL_NAME (registry);
1683
1684           if (strncmp (reg, "unicode-", 8)
1685               && strncmp (reg, "apple-roman", 11)
1686               && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1687             goto done;
1688         }
1689
1690       if (font->file != Mnil
1691           && ! (file_list = ft_list_file (font->file)))
1692         goto done;
1693       family = FONT_PROPERTY (font, MFONT_FAMILY);
1694       if (family != Mnil
1695           && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1696           && MPLIST_TAIL_P (family_list))
1697         goto done;
1698       if (font->capability != Mnil)
1699         {
1700           capability_list = ft_list_capability (font->capability);
1701           if (! capability_list || MPLIST_TAIL_P (capability_list))
1702             goto done;
1703         }
1704       else if (family == Mnil)
1705         {
1706           capability_list = ft_list_default ();
1707         }
1708     }
1709
1710   if (! file_list && ! family_list && ! capability_list)
1711     {
1712       /* No restriction.  Get all fonts.  */
1713       pl = mplist ();
1714       MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1715         {
1716           MPLIST_DO (p, MPLIST_PLIST (family_list))
1717             mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1718         }
1719     }
1720   else
1721     {
1722       if (file_list)
1723         {
1724           pl = mplist ();
1725           mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1726         }
1727       if (family_list)
1728         {
1729           if (pl)
1730             for (p = pl; ! MPLIST_TAIL_P (p);)
1731               {
1732                 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1733                   p = MPLIST_NEXT (p);
1734                 else
1735                   mplist_pop (p);
1736               }
1737           else
1738             {
1739               pl = mplist ();
1740               MPLIST_DO (p, family_list)
1741                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1742             }
1743         }
1744       if (capability_list)
1745         {
1746           if (pl)
1747             for (p = pl; ! MPLIST_TAIL_P (p);)
1748               {
1749                 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1750                   p = MPLIST_NEXT (p);
1751                 else
1752                   mplist_pop (p);
1753               }
1754           else
1755             {
1756               pl = mplist ();
1757               MPLIST_DO (p, capability_list)
1758                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1759             }
1760         }
1761     }
1762               
1763   if (font
1764       && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1765           + font->property[MFONT_STRETCH] + font->size) > 0)
1766     {
1767       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1768       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1769       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1770       int size = font->size;
1771
1772       for (p = pl; ! MPLIST_TAIL_P (p); )
1773         {
1774           MFontFT *ft_info = MPLIST_VAL (p);
1775
1776           if ((weight != Mnil
1777                && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1778               || (style != Mnil
1779                   && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1780               || (stretch != Mnil
1781                   && stretch != FONT_PROPERTY (&ft_info->font,
1782                                                MFONT_STRETCH))
1783               || (size > 0
1784                   && ft_info->font.size > 0
1785                   && ft_info->font.size != size))
1786             mplist_pop (p);
1787           else
1788             p = MPLIST_NEXT (p);
1789         }
1790     }
1791
1792   MPLIST_DO (p, pl)
1793     {
1794       mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1795       num++;
1796       if (maxnum && maxnum <= num)
1797         break;
1798     }
1799   M17N_OBJECT_UNREF (pl);
1800
1801  done:
1802   MDEBUG_PRINT1 ("  %d found\n", num);
1803   return num;
1804 }
1805
1806 \f
1807 /* Internal API */
1808
1809 MFontDriver mfont__ft_driver =
1810   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1811     ft_render, ft_list };
1812
1813 int
1814 mfont__ft_init ()
1815 {
1816   int i;
1817
1818   if (FT_Init_FreeType (&ft_library) != 0)
1819     MERROR (MERROR_FONT_FT, -1);
1820
1821   for (i = 0; i < ft_to_prop_size; i++)
1822     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1823
1824   Mmedium = msymbol ("medium");
1825   Mr = msymbol ("r");
1826   Mnull = msymbol ("");
1827
1828   M0_3 = msymbol ("0-3");
1829   M3_1 = msymbol ("3-1");
1830   M1_0 = msymbol ("1-0");
1831
1832 #ifdef HAVE_FONTCONFIG
1833   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1834     {
1835       FC_vs_M17N_font_prop *table = fc_all_table[i];
1836       int j;
1837
1838       for (j = 0; table[j].m17n_value; j++)
1839         table[j].sym = msymbol (table[j].m17n_value);
1840       table[j].sym = table[j - 1].sym;
1841     }
1842
1843   {
1844     char *pathname;
1845     struct stat buf;
1846     MPlist *plist;
1847     MSymbol serif, sans_serif, monospace;
1848
1849     fc_config = FcInitLoadConfigAndFonts ();
1850     if (mfont_freetype_path)
1851       {
1852         MPLIST_DO (plist, mfont_freetype_path)
1853           if (MPLIST_STRING_P (plist)
1854               && (pathname = MPLIST_STRING (plist))
1855               && stat (pathname, &buf) == 0)
1856             {
1857               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1858               FcChar8 *dir;
1859
1860               while ((dir = FcStrListNext (strlist)))
1861                 if (strcmp ((char *) dir, pathname) == 0)
1862                   break;
1863               if (! dir)
1864                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1865               FcStrListDone (strlist);
1866             }
1867       }
1868     Mgeneric_family = msymbol ("generic famly");
1869     serif = msymbol ("serif");
1870     msymbol_put (serif, Mgeneric_family, serif);
1871     sans_serif = msymbol ("sans-serif");
1872     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1873     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1874     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1875     monospace = msymbol ("monospace");
1876     msymbol_put (monospace, Mgeneric_family, monospace);
1877     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1878   }
1879 #endif
1880
1881   return 0;
1882 }
1883
1884 void
1885 mfont__ft_fini ()
1886 {
1887   MPlist *plist, *p;
1888
1889   if (ft_default_list)
1890     {
1891       M17N_OBJECT_UNREF (ft_default_list);
1892       ft_default_list = NULL;
1893     }
1894
1895   if (ft_font_list)
1896     {
1897       MPLIST_DO (plist, ft_font_list)
1898         {
1899           if (MPLIST_VAL (plist))
1900             MPLIST_DO (p, MPLIST_VAL (plist))
1901               {
1902                 if (MPLIST_KEY (p) != Mt)
1903                   free_ft_info (MPLIST_VAL (p));
1904               }
1905           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1906         }
1907       M17N_OBJECT_UNREF (ft_font_list);
1908       ft_font_list = NULL;
1909
1910       if (ft_language_list)
1911         {
1912           MPLIST_DO (plist, ft_language_list)
1913             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1914           M17N_OBJECT_UNREF (ft_language_list);
1915           ft_language_list = NULL;
1916         }
1917
1918       if (ft_script_list)
1919         {
1920           MPLIST_DO (plist, ft_script_list)
1921             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1922           M17N_OBJECT_UNREF (ft_script_list);
1923           ft_script_list = NULL;
1924         }
1925
1926       if (ft_capability_list)
1927         {
1928           MPLIST_DO (plist, ft_capability_list)
1929             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1930           M17N_OBJECT_UNREF (ft_capability_list);
1931           ft_capability_list = NULL;
1932         }
1933
1934       if (ft_file_list)
1935         {
1936           MPLIST_DO (plist, ft_file_list)
1937             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1938           M17N_OBJECT_UNREF (ft_file_list);
1939           ft_file_list = NULL;
1940         }
1941     }
1942   FT_Done_FreeType (ft_library);
1943 #ifdef HAVE_FONTCONFIG
1944   FcConfigDestroy (fc_config);
1945   fc_config = NULL;
1946 #endif  /* HAVE_FONTCONFIG */
1947   all_fonts_scaned = 0;
1948 }
1949
1950 #ifdef HAVE_FONTCONFIG
1951
1952 int
1953 mfont__ft_parse_name (const char *name, MFont *font)
1954 {
1955   FcPattern *pat = FcNameParse ((FcChar8 *) name);
1956   FcChar8 *str;
1957   int val;
1958   double size;
1959   char *buf;
1960   int bufsize = 0;
1961   
1962   if (! pat)
1963     return -1;
1964   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1965     {
1966       STRDUP_LOWER (buf, bufsize, (char *) str);
1967       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1968     }
1969   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1970     {
1971       STRDUP_LOWER (buf, bufsize, (char *) str);
1972       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1973     }
1974   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1975     mfont__set_property (font, MFONT_WEIGHT,
1976                          fc_decode_prop (val, fc_weight_table,
1977                                          fc_weight_table_size));
1978   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1979     mfont__set_property (font, MFONT_STYLE,
1980                          fc_decode_prop (val, fc_slant_table,
1981                                          fc_slant_table_size));
1982   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1983     mfont__set_property (font, MFONT_STRETCH,
1984                          fc_decode_prop (val, fc_width_table,
1985                                          fc_width_table_size));
1986   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1987     font->size = size * 10 + 0.5;
1988   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1989     font->size = - (size * 10 + 0.5);
1990   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1991     {
1992       font->file = msymbol ((char *) str);
1993     }
1994   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1995   font->type = MFONT_TYPE_SPEC;
1996   FcPatternDestroy (pat);
1997   return 0;
1998 }
1999
2000 char *
2001 mfont__ft_unparse_name (MFont *font)
2002 {
2003   FcPattern *pat = fc_get_pattern (font);
2004   char *name = (char *) FcNameUnparse (pat);
2005
2006   FcPatternDestroy (pat);
2007   return name;
2008 }
2009 #endif  /* HAVE_FONTCONFIG */
2010
2011 \f
2012 #ifdef HAVE_OTF
2013
2014 #define DEVICE_DELTA(table, size)                               \
2015   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
2016    ? (table).DeltaValue[(size) >= (table).StartSize]            \
2017    : 0)
2018
2019 void
2020 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2021                unsigned code, int size, int *x, int *y)
2022 {
2023   if (anchor->AnchorFormat == 2)
2024     {
2025       FT_Outline *outline;
2026       int ap = anchor->f.f1.AnchorPoint;
2027
2028       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2029       outline = &ft_face->glyph->outline;
2030       if (ap < outline->n_points)
2031         {
2032           *x = outline->points[ap].x;
2033           *y = outline->points[ap].y;
2034         }
2035     }
2036   else if (anchor->AnchorFormat == 3)
2037     {
2038       if (anchor->f.f2.XDeviceTable.offset)
2039         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2040       if (anchor->f.f2.YDeviceTable.offset)
2041       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2042     }
2043 }
2044
2045 int
2046 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2047                      MFontCapability *cap)
2048 {
2049   int len = to - from;
2050   MGlyph *g = MGLYPH (from);
2051   int i, gidx;
2052   MRealizedFont *rfont;
2053   MFontFT *ft_info;
2054   OTF *otf;
2055   OTF_GlyphString otf_gstring;
2056   OTF_Glyph *otfg;
2057   char *script, *langsys;
2058   char *gsub_features, *gpos_features;
2059   int need_cmap;
2060
2061   if (len == 0)
2062     return from;
2063
2064   otf_gstring.glyphs = NULL;
2065   rfont = g->rface->rfont;
2066   ft_info = (MFontFT *) rfont->font;
2067   if (ft_info->otf == invalid_otf)
2068     goto simple_copy;
2069   otf = ft_info->otf;
2070   if (! otf)
2071     {
2072       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2073       if (! otf)
2074         {
2075           ft_info->otf = invalid_otf;
2076           goto simple_copy;
2077         }
2078       ft_info->otf = otf;
2079     }
2080   if (OTF_get_table (otf, "head") < 0)
2081     {
2082       OTF_close (otf);
2083       ft_info->otf = invalid_otf;
2084       goto simple_copy;
2085     }
2086
2087   if (cap->script_tag)
2088     {
2089       script = alloca (5);
2090       OTF_tag_name (cap->script_tag, script);
2091     }
2092   else
2093     script = NULL;
2094   if (cap->langsys_tag)
2095     {
2096       langsys = alloca (5);
2097       OTF_tag_name (cap->langsys_tag, langsys);
2098     }
2099   else
2100     langsys = NULL;
2101   gsub_features = cap->features[MFONT_OTT_GSUB].str;
2102   if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2103     gsub_features = NULL;
2104   gpos_features = cap->features[MFONT_OTT_GPOS].str;
2105   if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2106     gpos_features = NULL;
2107
2108   otf_gstring.size = otf_gstring.used = len;
2109   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2110   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2111   for (i = 0, need_cmap = 0; i < len; i++)
2112     {
2113       if (gstring->glyphs[from + i].otf_encoded)
2114         {
2115           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2116           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2117         }
2118       else
2119         {
2120           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2121           need_cmap++;
2122         }
2123     }
2124   if (need_cmap
2125       && OTF_drive_cmap (otf, &otf_gstring) < 0)
2126     goto simple_copy;
2127
2128   OTF_drive_gdef (otf, &otf_gstring);
2129   gidx = gstring->used;
2130
2131   if (gsub_features)
2132     {
2133       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2134           < 0)
2135         goto simple_copy;
2136       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2137         {
2138           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2139
2140           temp.c = otfg->c;
2141           temp.combining_code = 0;
2142           if (otfg->glyph_id)
2143             {
2144               temp.code = otfg->glyph_id;
2145               temp.otf_encoded = 1;
2146             }
2147           else
2148             {
2149               temp.code = temp.c;
2150               temp.otf_encoded = 0;
2151             }
2152           temp.to = MGLYPH (from + otfg->f.index.to)->to;
2153           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2154         }
2155     }
2156   else
2157     for (i = 0; i < len; i++)
2158       {
2159         MGlyph temp = gstring->glyphs[from + i];
2160
2161         if (otf_gstring.glyphs[i].glyph_id)
2162           {
2163             temp.code = otf_gstring.glyphs[i].glyph_id;
2164             temp.otf_encoded = 1;
2165           }
2166         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2167       }
2168
2169   (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2170
2171   if (gpos_features)
2172     {
2173       int u;
2174       int size10, size;
2175       MGlyph *base = NULL, *mark = NULL;
2176
2177       if (OTF_check_features (otf, 1,
2178                               cap->script_tag, cap->langsys_tag,
2179                               cap->features[MFONT_OTT_GPOS].tags,
2180                               cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2181           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2182                               gpos_features) < 0))
2183         return to;
2184
2185       u = otf->head->unitsPerEm;
2186       size10 = rfont->spec.size;
2187       size = size10 / 10;
2188
2189       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2190            i < otf_gstring.used; i++, otfg++, g++)
2191         {
2192           MGlyph *prev;
2193
2194           if (! otfg->glyph_id)
2195             continue;
2196           switch (otfg->positioning_type)
2197             {
2198             case 0:
2199               break;
2200             case 1: case 2:
2201               {
2202                 int format = otfg->f.f1.format;
2203
2204                 if (format & OTF_XPlacement)
2205                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2206                 if (format & OTF_XPlaDevice)
2207                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2208                 if (format & OTF_YPlacement)
2209                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2210                 if (format & OTF_YPlaDevice)
2211                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2212                 if (format & OTF_XAdvance)
2213                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2214                 if (format & OTF_XAdvDevice)
2215                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2216               }
2217               break;
2218             case 3:
2219               /* Not yet supported.  */
2220               break;
2221             case 4: case 5:
2222               if (! base)
2223                 break;
2224               prev = base;
2225               goto label_adjust_anchor;
2226             default:            /* i.e. case 6 */
2227               if (! mark)
2228                 break;
2229               prev = mark;
2230
2231             label_adjust_anchor:
2232               {
2233                 int base_x, base_y, mark_x, mark_y;
2234
2235                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2236                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2237                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2238                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2239
2240                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2241                   adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2242                                  prev->code, size, &base_x, &base_y);
2243                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2244                   adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2245                                  g->code, size, &mark_x, &mark_y);
2246                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2247                 g->yoff = prev->yoff + mark_y - base_y;
2248                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2249               }
2250             }
2251           if (otfg->GlyphClass == OTF_GlyphClass0)
2252             base = mark = g;
2253           else if (otfg->GlyphClass == OTF_GlyphClassMark)
2254             mark = g;
2255           else
2256             base = g;
2257         }
2258     }
2259   free (otf_gstring.glyphs);
2260   return to;
2261
2262  simple_copy:
2263   ft_find_metric (rfont, gstring, from, to);
2264   for (i = 0; i < len; i++)
2265     {
2266       MGlyph temp = gstring->glyphs[from + i];
2267       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2268     }
2269   if (otf_gstring.glyphs)
2270     free (otf_gstring.glyphs);
2271   return to;
2272 }
2273
2274
2275 int
2276 mfont__ft_decode_otf (MGlyph *g)
2277 {
2278   MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2279   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2280
2281   return (c ? c : -1);
2282 }
2283
2284 #endif  /* HAVE_OTF */
2285
2286 #endif /* HAVE_FREETYPE */