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