(device_open): Handle Mfont key in PLIST.
[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 "internal-gui.h"
40 #include "font.h"
41 #include "face.h"
42
43 #ifdef HAVE_FREETYPE
44
45 #include <freetype/ftbdf.h>
46
47 #ifdef HAVE_FONTCONFIG
48
49 static FcConfig *fc_config;
50
51 /** List of generic families supported by Fontconfig.  Keys are
52     generic family names (including aliases) and values are real
53     generic family names. */
54
55 static MPlist *fc_generic_family_list;
56
57 #endif  /* not HAVE_FONTCONFIG */
58
59 /* Registries.  */
60 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
61 /* Fontconfig's generic font family names.  */
62 static MSymbol Mserif, Msans_serif, Mmonospace;
63 /* Font properties; Mnormal is already defined in face.c.  */
64 static MSymbol Mmedium, Mr, Mnull;
65
66 static FT_Library ft_library;
67
68 typedef struct
69 {
70   char *ft_style;
71   int len;
72   enum MFontProperty prop;
73   char *val;
74 } MFTtoProp;
75
76 static MFTtoProp ft_to_prop[] =
77   { { "italic", 0, MFONT_STYLE, "i" },
78     { "roman", 0, MFONT_STYLE, "r" },
79     { "oblique", 0, MFONT_STYLE, "p" },
80     { "regular", 0, MFONT_WEIGHT, "medium" },
81     { "normal", 0, MFONT_WEIGHT, "medium" },
82     /* We need this entry even if "bold" is in commone_weight[] to
83        handle such style names as "bolditalic" and "boldoblique".  */
84     { "bold", 0, MFONT_WEIGHT, "bold" },
85     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
86     { "demi", 0, MFONT_WEIGHT, "demibold" } };
87 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
88
89 /** List of FreeType fonts.  Keys are family names, values are plists
90     containing fonts of the corresponding family.  In the deeper
91     plist, keys are Mt, values are (MFTInfo *).  */
92 static MPlist *ft_font_list;
93
94 /** List of FreeType base fonts.  Keys are family names, values are
95     (MFTInfo *).  */
96 static MPlist *ft_family_list;
97
98 static int all_fonts_scaned;
99
100 /** Return 0 if NAME implies TrueType or OpenType fonts.  Othersize
101     return -1.  */
102
103 static int
104 check_otf_filename (const char *name)
105 {
106   int len = strlen (name);
107   const char *ext = name + (len - 4);
108
109   if (len < 5
110       || (memcmp (ext, ".ttf", 4)
111           && memcmp (ext, ".TTF", 4)
112           && memcmp (ext, ".otf", 4)
113           && memcmp (ext, ".OTF", 4)))
114     return -1;
115   return 0;
116 }
117
118 #define STRDUP_LOWER(s1, size, s2)                              \
119   do {                                                          \
120     int len = strlen (s2) + 1;                                  \
121     char *p1, *p2;                                              \
122                                                                 \
123     if (size < len)                                             \
124       s1 = alloca (len), size = len;                            \
125     for (p1 = s1, p2 = s2; *p2; p1++, p2++)                     \
126       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
127     *p1 = *p2;                                                  \
128   } while (0)
129
130 /** Setup members of FT_INFO from FT_FACE.  If the font is a base one
131     (i.e. medium-r-normal), set BASEP to 1.  Otherwise set BASEP to 0.
132     Return the family name.  */
133
134 static MSymbol
135 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family, int *basep)
136 {
137   MFont *font = &ft_info->font;
138   MPlist *charmap_list;
139   int unicode_bmp = -1, unicode_full = -1, unicode = -1;
140   int i;
141   char *buf;
142   int bufsize = 0;
143
144   MFONT_INIT (font);
145
146   if (family == Mnil)
147     {
148       STRDUP_LOWER (buf, bufsize, ft_face->family_name);
149       family = msymbol (buf);
150     }
151   mfont__set_property (font, MFONT_FAMILY, family);
152   mfont__set_property (font, MFONT_WEIGHT, Mmedium);
153   mfont__set_property (font, MFONT_STYLE, Mr);
154   mfont__set_property (font, MFONT_STRETCH, Mnormal);
155   mfont__set_property (font, MFONT_ADSTYLE, Mnull);
156   *basep = 1;
157
158   if (ft_face->style_name)
159     {
160       char *p;
161
162       STRDUP_LOWER (buf, bufsize, ft_face->style_name);
163       p = buf;
164       while (*p)
165         {
166           for (i = 0; i < ft_to_prop_size; i++)
167             if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
168               {
169                 mfont__set_property (font, ft_to_prop[i].prop,
170                                      msymbol (ft_to_prop[i].val));
171                 p += ft_to_prop[i].len;
172                 break;
173               }
174           if (i == ft_to_prop_size)
175             {
176               char *p1 = p + 1;
177               MSymbol sym;
178
179               while (*p1 >= 'a' && *p1 <= 'z') p1++;
180               sym = msymbol__with_len (p, p1 - p);
181               for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
182                 if (msymbol_get (sym, mfont__property_table[i].property))
183                   {
184                     mfont__set_property (font, i, sym);
185                     break;
186                   }
187               p = p1;
188             }
189           while (*p && (*p < 'a' || *p > 'z')) p++;
190         }
191     }
192
193   *basep =  (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium
194              && FONT_PROPERTY (font, MFONT_STYLE) == Mr
195              && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal);
196
197   charmap_list = mplist ();
198   mplist_add (charmap_list, Mt, (void *) -1);
199   for (i = 0; i < ft_face->num_charmaps; i++)
200     {
201       char registry_buf[16];
202       MSymbol registry;
203
204       sprintf (registry_buf, "%d-%d",
205                ft_face->charmaps[i]->platform_id,
206                ft_face->charmaps[i]->encoding_id);
207       registry = msymbol (registry_buf);
208       mplist_add (charmap_list, registry, (void *) i);
209       
210       if (ft_face->charmaps[i]->platform_id == 0)
211         {
212           if (ft_face->charmaps[i]->encoding_id == 3)
213             unicode_bmp = i;
214           else if (ft_face->charmaps[i]->encoding_id == 4)
215             unicode_full = i;
216         }
217       else if (ft_face->charmaps[i]->platform_id == 3)
218         {
219           if (ft_face->charmaps[i]->encoding_id == 1)
220             unicode_bmp = i;
221           else if (ft_face->charmaps[i]->encoding_id == 10)
222             unicode_full = i;
223         }
224       else if (ft_face->charmaps[i]->platform_id == 1
225                && ft_face->charmaps[i]->encoding_id == 0)
226         mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
227     }
228   if (unicode_full >= 0)
229     {
230       mplist_add (charmap_list, Municode_full, (void *) unicode_full);
231       mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
232       mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
233       unicode = unicode_full;
234     }
235   else if (unicode_bmp >= 0)
236     {
237       mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
238       mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
239       unicode = unicode_bmp;
240     }
241   if (unicode >= 0)
242     {
243       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
244       for (i = 255; i >= 32; i--)
245         {
246           if (i == 160)
247             i = 126;
248           if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
249             break;
250         }
251       if (i == 31)
252         mplist_add (charmap_list, Miso8859_1, (void *) unicode);
253     }
254
255   ft_info->charmap_list = charmap_list;
256
257   if (! FT_IS_SCALABLE (ft_face))
258     {
259       BDF_PropertyRec prop;
260       
261       FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
262       font->property[MFONT_SIZE] = prop.u.integer * 10;
263       FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
264       font->property[MFONT_RESY] = prop.u.integer;
265     }
266
267   return family;
268 }
269
270
271 static void
272 close_ft (void *object)
273 {
274   MFTInfo *ft_info = object;
275
276   if (ft_info->ft_face)
277     {
278       if (ft_info->extra_info)
279         M17N_OBJECT_UNREF (ft_info->extra_info);
280       FT_Done_Face (ft_info->ft_face);
281 #ifdef HAVE_OTF
282       if (ft_info->otf)
283         OTF_close (ft_info->otf);
284 #endif /* HAVE_OTF */
285     }
286   free (ft_info->filename);
287   if (ft_info->languages)
288     free (ft_info->languages);
289   M17N_OBJECT_UNREF (ft_info->charmap_list);
290   free (ft_info);
291 }
292
293 static void
294 add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist)
295 {
296   FT_Face ft_face;
297   BDF_PropertyRec prop;
298   MFTInfo *ft_info = NULL;
299
300   if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
301     {
302       if (FT_IS_SCALABLE (ft_face)
303           || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
304         {
305           MSymbol fam;
306           int basep;
307
308           M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
309           ft_info->filename = strdup (filename);
310           ft_info->otf_flag = check_otf_filename (filename);
311 #ifdef HAVE_FONTCONFIG
312           if (langset)
313             ft_info->langset = FcLangSetCopy (langset);
314 #endif
315           fam = set_font_info (ft_face, ft_info, family, &basep);
316           if (! plist
317               && ! (plist = mplist_get (ft_font_list, fam)))
318             {
319               plist = mplist ();
320               mplist_push (ft_font_list, fam, plist);
321             }
322           mplist_push (plist, fam, ft_info);
323
324           if (basep)
325             mplist_put (ft_family_list, fam, ft_info);
326           else if (! mplist_get (ft_family_list, fam))
327             mplist_push (ft_family_list, fam, ft_info);
328         }
329       FT_Done_Face (ft_face);
330     }
331 }
332
333 /* Return an element of ft_font_list for FAMILY.  If FAMILY is Mnil,
334    scan all fonts and return ft_font_list.  */
335 static MPlist *
336 ft_list_family (MSymbol family)
337 {
338   MPlist *plist;
339
340   if (! ft_font_list)
341     {
342       ft_font_list = mplist ();
343       ft_family_list = mplist ();
344     }
345
346   if (family == Mnil)
347     {
348       if (all_fonts_scaned)
349         return ft_font_list;
350     }
351   else
352     {
353       plist = mplist_find_by_key (ft_font_list, family);
354       if (plist)
355         return plist;
356       if (all_fonts_scaned)
357         {
358           plist = mplist ();
359           mplist_push (ft_font_list, family, plist);
360           return ft_font_list;
361         }
362     }
363
364 #ifdef HAVE_FONTCONFIG
365   {
366     FcPattern *pattern;
367     FcObjectSet *os;
368     FcFontSet *fs;
369     char *buf;
370     int bufsize = 0;
371     int i;
372
373     if (! fc_config)
374       {
375         char *pathname;
376         struct stat buf;
377         MPlist *plist;
378
379         FcInit ();
380         fc_config = FcConfigGetCurrent ();
381         MPLIST_DO (plist, mfont_freetype_path)
382           if (MPLIST_STRING_P (plist)
383               && (pathname = MPLIST_STRING (plist))
384               && stat (pathname, &buf) == 0)
385             {
386               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
387               FcChar8 *dir;
388
389               while ((dir = FcStrListNext (strlist)))
390                 if (strcmp ((char *) dir, pathname) == 0)
391                   break;
392               if (! dir)
393                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
394               FcStrListDone (strlist);
395             }
396       }
397
398     pattern = FcPatternCreate ();
399     if (family)
400       {
401         MSymbol generic = mplist_get (fc_generic_family_list, family);
402
403         if (generic != Mnil)
404           family = generic;
405         plist = mplist_find_by_key (ft_font_list, family);
406         if (plist)
407           return plist;
408         plist = mplist ();
409         mplist_push (ft_font_list, family, plist);
410
411         FcPatternAddString (pattern, FC_FAMILY,
412                             (FcChar8 *) (msymbol_name (family)));
413         if (generic != Mnil
414             && FcConfigSubstitute (fc_config, pattern, FcMatchPattern)
415             != FcTrue)
416           {
417             FcPatternDestroy (pattern);
418             return plist;
419           }
420       }
421
422     os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
423     fs = FcFontList (fc_config, pattern, os);
424
425     for (i = 0; i < fs->nfont; i++)
426       {
427         FcChar8 *filename;
428         FcLangSet *langset;
429
430         if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename)
431             != FcResultMatch)
432           continue;
433         if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, &langset)
434             != FcResultMatch)
435           langset = NULL;
436         if (family == Mnil)
437           {
438             MSymbol fam;
439             char *fname;
440
441             FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
442                                 (FcChar8 **) &fname);
443             STRDUP_LOWER (buf, bufsize, fname);
444             fam = msymbol ((char *) buf);
445             plist = mplist_get (ft_font_list, fam);
446             if (! plist)
447               {
448                 plist = mplist ();
449                 mplist_push (ft_font_list, fam, plist);
450                 add_font_info ((char *) filename, fam, langset, plist);
451               }
452           }
453         else
454           add_font_info ((char *) filename, family, langset, plist);
455       }
456     FcFontSetDestroy (fs);
457     FcObjectSetDestroy (os);
458     FcPatternDestroy (pattern);
459
460     if (family == Mnil)
461       {
462         MPLIST_DO (plist, fc_generic_family_list)
463           if (MPLIST_KEY (plist) == MPLIST_SYMBOL (plist)
464               && ! mplist_get (ft_font_list, MPLIST_KEY (plist)))
465             ft_list_family (MPLIST_KEY (plist));
466         all_fonts_scaned = 1;
467       }
468   }
469
470 #else  /* not HAVE_FONTCONFIG */
471
472   {
473     struct stat buf;
474     char *pathname;
475
476     MPLIST_DO (plist, mfont_freetype_path)
477       if (MPLIST_STRING_P (plist)
478           && (pathname = MPLIST_STRING (plist))
479           && stat (pathname, &buf) == 0)
480         {
481           if (S_ISREG (buf.st_mode))
482             add_font_info (pathname, Mnil, NULL, NULL);
483           else if (S_ISDIR (buf.st_mode))
484             {
485               int len = strlen (pathname);
486               char path[PATH_MAX];
487               DIR *dir = opendir (pathname);
488               struct dirent *dp;
489
490               if (dir)
491                 {
492                   strcpy (path, pathname);
493                   strcpy (path + len, "/");
494                   len++;
495                   while ((dp = readdir (dir)) != NULL)
496                     {
497                       strcpy (path + len, dp->d_name);
498                       add_font_info (path, Mnil, NULL, NULL);
499                     }
500                   closedir (dir);
501                 }
502             }
503         }
504
505     if (family != Mnil)
506       {
507         plist = mplist_find_by_key (ft_font_list, family);
508         if (plist)
509           return plist;
510         plist = mplist ();
511         mplist_push (ft_font_list, family, plist);
512       }
513   }
514
515 #endif  /* not HAVE_FONTCONFIG */
516
517   return ft_font_list;
518 }
519
520
521 /* The FreeType font driver function SELECT.  */
522
523 static MRealizedFont *
524 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
525 {
526   MPlist *plist, *pl, *p;
527   MFTInfo *best_font;
528   int best_score;
529   MRealizedFont *rfont;
530   MSymbol family, registry;
531
532   family = FONT_PROPERTY (spec, MFONT_FAMILY);
533   if (family == Mnil)
534     family = FONT_PROPERTY (request, MFONT_FAMILY);
535   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
536   if (registry == Mnil)
537     registry = Mt;
538
539   plist = ft_list_family (family);
540   best_font = NULL;
541   best_score = -1;
542   MPLIST_DO (pl, plist)
543     {
544       MPLIST_DO (p, MPLIST_VAL (pl))
545         {
546           MFTInfo *ft_info = MPLIST_VAL (p);
547           int score;
548           unsigned short family_id;
549
550           if (! mplist_find_by_key (ft_info->charmap_list, registry))
551             continue;
552           /* Always ignore FOUNDRY.  */
553           ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
554           /* Ignore FAMILY too.  */
555           family_id = ft_info->font.property[MFONT_FAMILY];
556           ft_info->font.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
557           score = mfont__score (&ft_info->font, spec, request, limited_size);
558           ft_info->font.property[MFONT_FAMILY] = family_id;
559
560           if (score >= 0
561               && (! best_font
562                   || best_score > score))
563             {
564               best_font = ft_info;
565               best_score = score;
566               if (best_score == 0)
567                 break;
568             }
569         }
570       if (best_score == 0 || family != Mnil)
571         break;
572     }
573   if (! best_font)
574     return NULL;
575
576   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
577   rfont->frame = frame;
578   rfont->spec = *spec;
579   rfont->request = *request;
580   rfont->font = best_font->font;
581   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
582   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
583   rfont->score = best_score;
584   rfont->info = best_font;
585   M17N_OBJECT_REF (best_font);
586   return rfont;
587 }
588
589
590 /* The FreeType font driver function OPEN.  */
591
592 static int
593 ft_open (MRealizedFont *rfont)
594 {
595   MFTInfo *base = rfont->info, *ft_info;
596   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
597   int mdebug_mask = MDEBUG_FONT;
598   int size;
599
600   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
601   ft_info->font = base->font;
602   ft_info->filename = strdup (base->filename);
603   ft_info->otf_flag = base->otf_flag;
604   ft_info->charmap_list = base->charmap_list;
605   M17N_OBJECT_REF (ft_info->charmap_list);
606   M17N_OBJECT_UNREF (base);
607   rfont->info = ft_info;
608
609   rfont->status = -1;
610   ft_info->ft_face = NULL;
611   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
612     goto err;
613   if (registry == Mnil)
614     registry = Mt;
615   ft_info->charmap_index
616     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
617   if (ft_info->charmap_index >= 0
618       && FT_Set_Charmap (ft_info->ft_face, 
619                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
620     goto err;
621   size = rfont->font.property[MFONT_SIZE] / 10;
622   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
623     goto err;
624
625   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
626   rfont->status = 1;
627   rfont->ascent = ft_info->ft_face->ascender >> 6;
628   rfont->descent = - (ft_info->ft_face->descender >> 6);
629   rfont->type = Mfreetype;
630   rfont->fontp = ft_info->ft_face;
631   return 0;
632
633  err:
634   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
635   if (ft_info->ft_face)
636     FT_Done_Face (ft_info->ft_face);
637   M17N_OBJECT_UNREF (ft_info->charmap_list);
638   free (ft_info->filename);
639   free (ft_info);
640   rfont->info = NULL;
641   return -1;
642 }
643
644 /* The FreeType font driver function FIND_METRIC.  */
645
646 static void
647 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
648                 int from, int to)
649 {
650   MFTInfo *ft_info = (MFTInfo *) rfont->info;
651   FT_Face ft_face = ft_info->ft_face;
652   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
653
654   for (; g != gend; g++)
655     {
656       if (g->code == MCHAR_INVALID_CODE)
657         {
658           if (FT_IS_SCALABLE (ft_face))
659             {
660               unsigned unitsPerEm = ft_face->units_per_EM;
661               int size = rfont->font.property[MFONT_SIZE] / 10;
662
663               g->lbearing = 0;
664               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
665               g->width = ft_face->max_advance_width * size / unitsPerEm;
666               g->ascent = ft_face->ascender * size / unitsPerEm;
667               g->descent = (- ft_face->descender) * size / unitsPerEm;
668             }
669           else
670             {
671               BDF_PropertyRec prop;
672
673               g->lbearing = 0;
674               g->rbearing = g->width = ft_face->available_sizes->width;
675               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
676                 {
677                   g->ascent = prop.u.integer;
678                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
679                   g->descent = prop.u.integer;
680                 }
681               else
682                 {
683                   g->ascent = ft_face->available_sizes->height;
684                   g->descent = 0;
685                 }
686             }
687         }
688       else
689         {
690           FT_Glyph_Metrics *metrics;
691
692           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
693           metrics = &ft_face->glyph->metrics;
694           g->lbearing = (metrics->horiBearingX >> 6);
695           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
696           g->width = metrics->horiAdvance >> 6;
697           g->ascent = metrics->horiBearingY >> 6;
698           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
699         }
700     }
701 }
702
703 /* The FreeType font driver function ENCODE_CHAR.  */
704
705 static unsigned
706 ft_encode_char (MRealizedFont *rfont, unsigned code)
707 {
708   MFTInfo *ft_info;
709
710   if (rfont->status == 0)
711     {
712       if ((rfont->driver->open) (rfont) < 0)
713         return -1;
714     }
715   ft_info = (MFTInfo *) rfont->info;
716   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
717   if (! code)
718     return MCHAR_INVALID_CODE;
719   return (code);
720
721 }
722
723 /* The FreeType font driver function RENDER.  */
724
725 #define NUM_POINTS 0x1000
726
727 typedef struct {
728   MDrawPoint points[NUM_POINTS];
729   MDrawPoint *p;
730 } MPointTable;
731
732 static void
733 ft_render (MDrawWindow win, int x, int y,
734            MGlyphString *gstring, MGlyph *from, MGlyph *to,
735            int reverse, MDrawRegion region)
736 {
737   MFTInfo *ft_info;
738   FT_Face ft_face;
739   MRealizedFace *rface = from->rface;
740   MFrame *frame = rface->frame;
741   FT_Int32 load_flags = FT_LOAD_RENDER;
742   MGlyph *g;
743   int i, j;
744   MPointTable point_table[8];
745
746   if (from == to)
747     return;
748
749   /* It is assured that the all glyphs in the current range use the
750      same realized face.  */
751   ft_info = (MFTInfo *) rface->rfont->info;
752   ft_face = ft_info->ft_face;
753
754   if (! gstring->anti_alias)
755     {
756 #ifdef FT_LOAD_TARGET_MONO
757       load_flags |= FT_LOAD_TARGET_MONO;
758 #else
759       load_flags |= FT_LOAD_MONOCHROME;
760 #endif
761     }
762
763   for (i = 0; i < 8; i++)
764     point_table[i].p = point_table[i].points;
765
766   for (g = from; g < to; x += g++->width)
767     {
768       unsigned char *bmp;
769       int intensity;
770       MPointTable *ptable;
771       int xoff, yoff;
772       int width, pitch;
773
774       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
775       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
776       bmp = ft_face->glyph->bitmap.buffer;
777       width = ft_face->glyph->bitmap.width;
778       pitch = ft_face->glyph->bitmap.pitch;
779       if (! gstring->anti_alias)
780         pitch *= 8;
781       if (width > pitch)
782         width = pitch;
783
784       if (gstring->anti_alias)
785         for (i = 0; i < ft_face->glyph->bitmap.rows;
786              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
787           {
788             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
789             for (j = 0; j < width; j++, xoff++)
790               {
791                 intensity = bmp[j] >> 5;
792                 if (intensity)
793                   {
794                     ptable = point_table + intensity;
795                     ptable->p->x = xoff;
796                     ptable->p->y = yoff;
797                     ptable->p++;
798                     if (ptable->p - ptable->points == NUM_POINTS)
799                       {
800                         (*frame->driver->draw_points)
801                           (frame, win, rface,
802                            reverse ? 7 - intensity : intensity,
803                            ptable->points, NUM_POINTS, region);
804                         ptable->p = ptable->points;
805                       }
806                   }
807               }
808           }
809       else
810         for (i = 0; i < ft_face->glyph->bitmap.rows;
811              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
812           {
813             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
814             for (j = 0; j < width; j++, xoff++)
815               {
816                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
817                 if (intensity)
818                   {
819                     ptable = point_table;
820                     ptable->p->x = xoff;
821                     ptable->p->y = yoff;
822                     ptable->p++;
823                     if (ptable->p - ptable->points == NUM_POINTS)
824                       {
825                         (*frame->driver->draw_points) (frame, win, rface,
826                                            reverse ? 0 : 7,
827                                            ptable->points, NUM_POINTS, region);
828                         ptable->p = ptable->points;
829                       }             
830                   }
831               }
832         }
833     }
834
835   if (gstring->anti_alias)
836     {
837       for (i = 1; i < 8; i++)
838         if (point_table[i].p != point_table[i].points)
839           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
840                              point_table[i].points,
841                              point_table[i].p - point_table[i].points, region);
842     }
843   else
844     {
845       if (point_table[0].p != point_table[0].points)
846         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
847                            point_table[0].points,
848                            point_table[0].p - point_table[0].points, region);
849     }
850 }
851
852 static void
853 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
854 {
855   MPlist *pl, *p;
856   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
857 #ifdef HAVE_FONTCONFIG
858   FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
859                    : NULL);
860 #endif
861
862   pl = ft_list_family (Mnil);
863   if (font)
864     {
865       MPLIST_DO (pl, pl)
866         {
867           MPLIST_DO (p, MPLIST_PLIST (pl))
868             {
869               MFTInfo *ft_info = MPLIST_VAL (p);
870
871 #ifdef HAVE_FONTCONFIG
872               if (lang && ft_info->langset
873                   && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
874                 continue;
875 #endif
876               if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
877                 continue;
878               mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
879             }
880           if (family != Mnil)
881             break;
882         }
883     }
884   else
885     {
886       MPLIST_DO (p, ft_family_list)
887         {
888           MFTInfo *ft_info = MPLIST_VAL (p);
889
890 #ifdef HAVE_FONTCONFIG
891           if (lang && ft_info->langset
892               && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
893             continue;
894 #endif
895           mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
896         }
897     }
898 }
899
900 \f
901 /* Internal API */
902
903 MFontDriver mfont__ft_driver =
904   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
905
906 int
907 mfont__ft_init ()
908 {
909   int i;
910
911   if (FT_Init_FreeType (&ft_library) != 0)
912     MERROR (MERROR_FONT_FT, -1);
913
914   for (i = 0; i < ft_to_prop_size; i++)
915     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
916
917   Municode_bmp = msymbol ("unicode-bmp");
918   Municode_full = msymbol ("unicode-full");
919   Miso10646_1 = msymbol ("iso10646-1");
920   Miso8859_1 = msymbol ("iso8859-1");
921
922   Mserif = msymbol ("serif");
923   Msans_serif = msymbol ("sans-serif");
924   Mmonospace = msymbol ("monospace");
925
926   Mmedium = msymbol ("medium");
927   Mr = msymbol ("r");
928   Mnull = msymbol ("");
929
930 #ifdef HAVE_FONTCONFIG
931   fc_generic_family_list = mplist ();
932   mplist_push (fc_generic_family_list, Mserif, Mserif);
933   mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
934   mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
935   /* These are (deprecated) aliases.  */
936   mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
937   mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
938   mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
939 #endif
940
941   return 0;
942 }
943
944 void
945 mfont__ft_fini ()
946 {
947   MPlist *plist, *p;
948
949   if (ft_font_list)
950     {
951       MPLIST_DO (plist, ft_font_list)
952         {
953           MPLIST_DO (p, MPLIST_VAL (plist))
954             {
955               MFTInfo *ft_info = MPLIST_VAL (p);
956
957               M17N_OBJECT_UNREF (ft_info);
958             }
959           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
960         }
961       M17N_OBJECT_UNREF (ft_font_list);
962       ft_font_list = NULL;
963
964       M17N_OBJECT_UNREF (ft_family_list);
965       ft_family_list = NULL;
966     }
967   FT_Done_FreeType (ft_library);
968   all_fonts_scaned = 0;
969
970 #ifdef HAVE_FONTCONFIG
971   m17n_object_unref (fc_generic_family_list);
972 #endif
973
974 }
975
976
977 #ifdef HAVE_FONTCONFIG
978 typedef struct
979 {
980   int fc_value;
981   char *m17n_value;
982 } FC_vs_M17N_font_prop;
983
984 static FC_vs_M17N_font_prop fc_weight_table[] =
985   { { FC_WEIGHT_ULTRALIGHT, "extralight" },
986     { FC_WEIGHT_LIGHT, "light" },
987     { FC_WEIGHT_NORMAL, "normal" },
988     { FC_WEIGHT_MEDIUM, "medium" },
989     { FC_WEIGHT_DEMIBOLD, "demibold" },
990     { FC_WEIGHT_EXTRABOLD, "extrabold" },
991     { FC_WEIGHT_BLACK, "black" },
992     { FC_WEIGHT_MEDIUM, NULL } };
993
994 static FC_vs_M17N_font_prop fc_slant_table[] =
995   { { FC_SLANT_ROMAN, "r" },
996     { FC_SLANT_ITALIC, "i" },
997     { FC_SLANT_OBLIQUE, "o" },
998     { FC_SLANT_ROMAN, NULL } };
999
1000 static FC_vs_M17N_font_prop fc_width_table[] =
1001   { { FC_WIDTH_CONDENSED, "condensed" },
1002     { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1003     { FC_WIDTH_NORMAL, "normal" },
1004     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1005     { FC_WIDTH_EXPANDED, "expanded" },
1006     { FC_WIDTH_NORMAL, NULL } };
1007
1008
1009 static MSymbol
1010 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1011 {
1012   int i;
1013
1014   for (i = 0; table[i].m17n_value; i++)
1015     if (val <= table[i].fc_value)
1016       return msymbol ("table[i].m17n_value");
1017   return msymbol ("table[i - 1].m17n_value");
1018 }
1019
1020 static int
1021 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1022 {
1023   int i;
1024
1025   for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1026   return table[i].fc_value;
1027 }
1028
1029 int
1030 mfont__ft_parse_name (char *name, MFont *font)
1031 {
1032   FcPattern *pat = FcNameParse ((FcChar8 *) name);
1033   FcChar8 *str;
1034   int val;
1035   double size;
1036   
1037   if (! pat)
1038     return -1;
1039   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1040     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1041   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1042     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1043   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1044     mfont__set_property (font, MFONT_WEIGHT,
1045                          fc_decode_prop (val, fc_weight_table));
1046   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1047     mfont__set_property (font, MFONT_STYLE,
1048                          fc_decode_prop (val, fc_slant_table));
1049   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1050     mfont__set_property (font, MFONT_STRETCH,
1051                          fc_decode_prop (val, fc_width_table));
1052   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1053     font->property[MFONT_SIZE] = size * 10;
1054   FcPatternDestroy (pat);
1055   return 0;
1056 }
1057
1058 char *
1059 mfont__ft_unparse_name (MFont *font)
1060 {
1061   FcPattern *pat = FcPatternCreate ();
1062   MSymbol sym, weight, style, stretch;
1063   char *name;
1064
1065   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1066     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1067   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1068     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1069   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1070     FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1071                                                          fc_weight_table));
1072   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1073     FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1074                                                         fc_slant_table));
1075   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1076     FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1077                                                         fc_width_table));
1078   name = (char *) FcNameUnparse (pat);
1079   FcPatternDestroy (pat);
1080   return name;
1081 }
1082 #endif  /* HAVE_FONTCONFIG */
1083
1084 \f
1085 #ifdef HAVE_OTF
1086
1087 #define DEVICE_DELTA(table, size)                               \
1088   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
1089    ? (table).DeltaValue[(size) >= (table).StartSize]            \
1090    : 0)
1091
1092 void
1093 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1094                unsigned code, int size, int *x, int *y)
1095 {
1096   if (anchor->AnchorFormat == 2)
1097     {
1098       FT_Outline *outline;
1099       int ap = anchor->f.f1.AnchorPoint;
1100
1101       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1102       outline = &ft_face->glyph->outline;
1103       if (ap < outline->n_points)
1104         {
1105           *x = outline->points[ap].x;
1106           *y = outline->points[ap].y;
1107         }
1108     }
1109   else if (anchor->AnchorFormat == 3)
1110     {
1111       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1112       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1113     }
1114 }
1115
1116 int
1117 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1118                      MSymbol script, MSymbol langsys,
1119                      MSymbol gsub_features, MSymbol gpos_features)
1120 {
1121   int len = to - from;
1122   MGlyph *g = MGLYPH (from);
1123   int i, gidx;
1124   MRealizedFont *rfont;
1125   MFTInfo *ft_info;
1126   OTF *otf;
1127   OTF_GlyphString otf_gstring;
1128   OTF_Glyph *otfg;
1129   char *script_name, *language_name;
1130   char *gsub_feature_names, *gpos_feature_names;
1131   int need_cmap;
1132
1133   if (len == 0)
1134     return from;
1135
1136   rfont = g->rface->rfont;
1137   ft_info = rfont->info;
1138   if (ft_info->otf_flag < 0)
1139     goto simple_copy;
1140   otf = ft_info->otf;
1141   if (! otf)
1142     {
1143       otf = OTF_open (ft_info->filename);
1144       if (otf && OTF_get_table (otf, "head") < 0)
1145         {
1146           OTF_close (otf);
1147           otf = NULL;
1148         }
1149       if (! otf)
1150         {
1151           ft_info->otf_flag = -1;
1152           goto simple_copy;
1153         }
1154       ft_info->otf = otf;
1155     }
1156
1157   if (script != Mnil)
1158     script_name = msymbol_name (script);
1159   else
1160     script_name = NULL;
1161   if (langsys != Mnil)
1162     language_name = msymbol_name (langsys);
1163   else
1164     language_name = NULL;
1165   gsub_feature_names
1166     = (gsub_features == Mt ? "*"
1167        : gsub_features == Mnil ? NULL
1168        : msymbol_name (gsub_features));
1169   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1170     gsub_feature_names = NULL;
1171   gpos_feature_names
1172     = (gpos_features == Mt ? "*"
1173        : gpos_features == Mnil ? NULL
1174        : msymbol_name (gpos_features));
1175   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1176     gpos_feature_names = NULL;
1177
1178   otf_gstring.size = otf_gstring.used = len;
1179   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1180   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1181   for (i = 0, need_cmap = 0; i < len; i++)
1182     {
1183       if (gstring->glyphs[from + i].otf_encoded)
1184         {
1185           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1186           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1187         }
1188       else
1189         {
1190           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1191           need_cmap++;
1192         }
1193     }
1194   if (need_cmap
1195       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1196     goto simple_copy;
1197
1198   OTF_drive_gdef (otf, &otf_gstring);
1199   gidx = gstring->used;
1200
1201   if (gsub_feature_names)
1202     {
1203       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1204                           gsub_feature_names) < 0)
1205         goto simple_copy;
1206       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1207         {
1208           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1209
1210           temp.c = otfg->c;
1211           temp.combining_code = 0;
1212           if (otfg->glyph_id)
1213             {
1214               temp.code = otfg->glyph_id;
1215               temp.otf_encoded = 1;
1216             }
1217           else
1218             {
1219               temp.code = temp.c;
1220               temp.otf_encoded = 0;
1221             }
1222           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1223           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1224         }
1225     }
1226   else
1227     for (i = 0; i < len; i++)
1228       {
1229         MGlyph temp = gstring->glyphs[from + i];
1230
1231         if (otf_gstring.glyphs[i].glyph_id)
1232           {
1233             temp.code = otf_gstring.glyphs[i].glyph_id;
1234             temp.otf_encoded = 1;
1235           }
1236         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1237       }
1238
1239   ft_find_metric (rfont, gstring, gidx, gstring->used);
1240
1241   if (gpos_feature_names)
1242     {
1243       int u;
1244       int size10, size;
1245       MGlyph *base = NULL, *mark = NULL;
1246
1247       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1248                           gpos_feature_names) < 0)
1249         return to;
1250
1251       u = otf->head->unitsPerEm;
1252       size10 = rfont->font.property[MFONT_SIZE];
1253       size = size10 / 10;
1254
1255       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1256            i < otf_gstring.used; i++, otfg++, g++)
1257         {
1258           MGlyph *prev;
1259
1260           if (! otfg->glyph_id)
1261             continue;
1262           switch (otfg->positioning_type)
1263             {
1264             case 0:
1265               break;
1266             case 1: case 2:
1267               {
1268                 int format = otfg->f.f1.format;
1269
1270                 if (format & OTF_XPlacement)
1271                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1272                 if (format & OTF_XPlaDevice)
1273                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1274                 if (format & OTF_YPlacement)
1275                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1276                 if (format & OTF_YPlaDevice)
1277                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1278                 if (format & OTF_XAdvance)
1279                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1280                 if (format & OTF_XAdvDevice)
1281                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1282               }
1283               break;
1284             case 3:
1285               /* Not yet supported.  */
1286               break;
1287             case 4: case 5:
1288               if (! base)
1289                 break;
1290               prev = base;
1291               goto label_adjust_anchor;
1292             default:            /* i.e. case 6 */
1293               if (! mark)
1294                 break;
1295               prev = mark;
1296
1297             label_adjust_anchor:
1298               {
1299                 int base_x, base_y, mark_x, mark_y;
1300
1301                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1302                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1303                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1304                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1305
1306                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1307                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1308                                  prev->code, size, &base_x, &base_y);
1309                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1310                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1311                                  g->code, size, &mark_x, &mark_y);
1312                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1313                 g->yoff = prev->yoff + mark_y - base_y;
1314                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1315               }
1316             }
1317           if (otfg->GlyphClass == OTF_GlyphClass0)
1318             base = mark = g;
1319           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1320             mark = g;
1321           else
1322             base = g;
1323         }
1324     }
1325   free (otf_gstring.glyphs);
1326   return to;
1327
1328  simple_copy:
1329   ft_find_metric (rfont, gstring, from, to);
1330   for (i = 0; i < len; i++)
1331     {
1332       MGlyph temp = gstring->glyphs[from + i];
1333       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1334     }
1335   free (otf_gstring.glyphs);
1336   return to;
1337 }
1338
1339
1340 int
1341 mfont__ft_decode_otf (MGlyph *g)
1342 {
1343   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1344   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1345
1346   return (c ? c : -1);
1347 }
1348
1349 #endif  /* HAVE_OTF */
1350
1351 #endif /* HAVE_FREETYPE */