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