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