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