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