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