(mface__realize): Delete args langauge and charset.
[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_add (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_add (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, *pat;
367     FcObjectSet *os;
368     FcFontSet *fs;
369     char *buf;
370     int bufsize = 0;
371     int i, j;
372     MSymbol generic = Mnil;
373
374     if (! fc_config)
375       {
376         char *pathname;
377         struct stat buf;
378         MPlist *plist;
379
380         FcInit ();
381         fc_config = FcConfigGetCurrent ();
382         MPLIST_DO (plist, mfont_freetype_path)
383           if (MPLIST_STRING_P (plist)
384               && (pathname = MPLIST_STRING (plist))
385               && stat (pathname, &buf) == 0)
386             {
387               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
388               FcChar8 *dir;
389
390               while ((dir = FcStrListNext (strlist)))
391                 if (strcmp ((char *) dir, pathname) == 0)
392                   break;
393               if (! dir)
394                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
395               FcStrListDone (strlist);
396             }
397       }
398
399     pattern = FcPatternCreate ();
400     if (family)
401       {
402         generic = mplist_get (fc_generic_family_list, family);
403         if (generic != Mnil)
404           {
405             family = generic;
406             plist = mplist_find_by_key (ft_font_list, family);
407             if (plist)
408               return plist;
409           }
410         plist = mplist ();
411         mplist_push (ft_font_list, family, plist);
412
413         FcPatternAddString (pattern, FC_FAMILY,
414                             (FcChar8 *) (msymbol_name (family)));
415         if (generic != Mnil
416             && FcConfigSubstitute (fc_config, pattern, FcMatchPattern)
417             != FcTrue)
418           {
419             FcPatternDestroy (pattern);
420             return plist;
421           }
422       }
423
424     os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
425     pat = FcPatternCreate ();
426     for (j = 0; 1; j++)
427       {
428         FcChar8 *fname;
429
430         if (generic)
431           {
432             if (FcPatternGetString (pattern, FC_FAMILY, j, &fname)
433                 != FcResultMatch)
434               break;
435             FcPatternAddString (pat, FC_FAMILY, fname);
436             fs = FcFontList (fc_config, pat, os);
437           }
438         else
439           fs = FcFontList (fc_config, pattern, os);
440
441         for (i = 0; i < fs->nfont; i++)
442           {
443             FcChar8 *filename;
444             FcLangSet *langset;
445
446             if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename)
447                 != FcResultMatch)
448               continue;
449             if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, &langset)
450                 != FcResultMatch)
451               langset = NULL;
452             if (family == Mnil)
453               {
454                 MSymbol fam;
455
456                 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, &fname);
457                 STRDUP_LOWER (buf, bufsize, fname);
458                 fam = msymbol ((char *) buf);
459                 plist = mplist_get (ft_font_list, fam);
460                 if (! plist)
461                   {
462                     plist = mplist ();
463                     mplist_push (ft_font_list, fam, plist);
464                     add_font_info ((char *) filename, fam, langset, plist);
465                   }
466               }
467             else
468               add_font_info ((char *) filename, family, langset, plist);
469           }
470
471         if (generic)
472           FcPatternDel (pat, FC_FAMILY);
473         else
474           break;
475       }
476
477     FcFontSetDestroy (fs);
478     FcObjectSetDestroy (os);
479     FcPatternDestroy (pattern);
480     FcPatternDestroy (pat);
481
482     if (family == Mnil)
483       {
484         MPLIST_DO (plist, fc_generic_family_list)
485           if (MPLIST_KEY (plist) == MPLIST_SYMBOL (plist)
486               && ! mplist_get (ft_font_list, MPLIST_KEY (plist)))
487             ft_list_family (MPLIST_KEY (plist));
488         all_fonts_scaned = 1;
489       }
490   }
491
492 #else  /* not HAVE_FONTCONFIG */
493
494   {
495     struct stat buf;
496     char *pathname;
497
498     MPLIST_DO (plist, mfont_freetype_path)
499       if (MPLIST_STRING_P (plist)
500           && (pathname = MPLIST_STRING (plist))
501           && stat (pathname, &buf) == 0)
502         {
503           if (S_ISREG (buf.st_mode))
504             add_font_info (pathname, Mnil, NULL, NULL);
505           else if (S_ISDIR (buf.st_mode))
506             {
507               int len = strlen (pathname);
508               char path[PATH_MAX];
509               DIR *dir = opendir (pathname);
510               struct dirent *dp;
511
512               if (dir)
513                 {
514                   strcpy (path, pathname);
515                   strcpy (path + len, "/");
516                   len++;
517                   while ((dp = readdir (dir)) != NULL)
518                     {
519                       strcpy (path + len, dp->d_name);
520                       add_font_info (path, Mnil, NULL, NULL);
521                     }
522                   closedir (dir);
523                 }
524             }
525         }
526
527     if (family != Mnil)
528       {
529         plist = mplist_find_by_key (ft_font_list, family);
530         if (plist)
531           return plist;
532         plist = mplist ();
533         mplist_push (ft_font_list, family, plist);
534       }
535   }
536
537 #endif  /* not HAVE_FONTCONFIG */
538
539   return ft_font_list;
540 }
541
542
543 /* The FreeType font driver function SELECT.  */
544
545 static MRealizedFont *
546 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
547 {
548   MPlist *plist, *pl, *p;
549   MFTInfo *best_font;
550   int best_score;
551   MRealizedFont *rfont;
552   MSymbol family, registry;
553
554   family = FONT_PROPERTY (spec, MFONT_FAMILY);
555   if (family == Mnil)
556     family = FONT_PROPERTY (request, MFONT_FAMILY);
557   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
558   if (registry == Mnil)
559     registry = Mt;
560
561   plist = ft_list_family (family);
562   best_font = NULL;
563   best_score = -1;
564   MPLIST_DO (pl, plist)
565     {
566       MPLIST_DO (p, MPLIST_VAL (pl))
567         {
568           MFTInfo *ft_info = MPLIST_VAL (p);
569           int score;
570           unsigned short family_id;
571
572           if (! mplist_find_by_key (ft_info->charmap_list, registry))
573             continue;
574           /* Always ignore FOUNDRY.  */
575           ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
576           /* Ignore FAMILY too.  */
577           family_id = ft_info->font.property[MFONT_FAMILY];
578           ft_info->font.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
579           score = mfont__score (&ft_info->font, spec, request, limited_size);
580           ft_info->font.property[MFONT_FAMILY] = family_id;
581
582           if (score >= 0
583               && (! best_font
584                   || best_score > score))
585             {
586               best_font = ft_info;
587               best_score = score;
588               if (best_score == 0)
589                 break;
590             }
591         }
592       if (best_score == 0 || family != Mnil)
593         break;
594     }
595   if (! best_font)
596     return NULL;
597
598   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
599   rfont->frame = frame;
600   rfont->spec = *spec;
601   rfont->request = *request;
602   rfont->font = best_font->font;
603   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
604   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
605   rfont->score = best_score;
606   rfont->info = best_font;
607   M17N_OBJECT_REF (best_font);
608   return rfont;
609 }
610
611
612 /* The FreeType font driver function OPEN.  */
613
614 static int
615 ft_open (MRealizedFont *rfont)
616 {
617   MFTInfo *base = rfont->info, *ft_info;
618   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
619   int mdebug_mask = MDEBUG_FONT;
620   int size;
621
622   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
623   ft_info->font = base->font;
624   ft_info->filename = strdup (base->filename);
625   ft_info->otf_flag = base->otf_flag;
626   ft_info->charmap_list = base->charmap_list;
627   M17N_OBJECT_REF (ft_info->charmap_list);
628   M17N_OBJECT_UNREF (base);
629   rfont->info = ft_info;
630
631   rfont->status = -1;
632   ft_info->ft_face = NULL;
633   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
634     goto err;
635   if (registry == Mnil)
636     registry = Mt;
637   ft_info->charmap_index
638     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
639   if (ft_info->charmap_index >= 0
640       && FT_Set_Charmap (ft_info->ft_face, 
641                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
642     goto err;
643   size = rfont->font.property[MFONT_SIZE] / 10;
644   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
645     goto err;
646
647   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
648   rfont->status = 1;
649   rfont->ascent = ft_info->ft_face->ascender >> 6;
650   rfont->descent = - (ft_info->ft_face->descender >> 6);
651   rfont->type = Mfreetype;
652   rfont->fontp = ft_info->ft_face;
653   return 0;
654
655  err:
656   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
657   if (ft_info->ft_face)
658     FT_Done_Face (ft_info->ft_face);
659   M17N_OBJECT_UNREF (ft_info->charmap_list);
660   free (ft_info->filename);
661   free (ft_info);
662   rfont->info = NULL;
663   return -1;
664 }
665
666 /* The FreeType font driver function FIND_METRIC.  */
667
668 static void
669 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
670                 int from, int to)
671 {
672   MFTInfo *ft_info = (MFTInfo *) rfont->info;
673   FT_Face ft_face = ft_info->ft_face;
674   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
675
676   for (; g != gend; g++)
677     {
678       if (g->code == MCHAR_INVALID_CODE)
679         {
680           if (FT_IS_SCALABLE (ft_face))
681             {
682               unsigned unitsPerEm = ft_face->units_per_EM;
683               int size = rfont->font.property[MFONT_SIZE] / 10;
684
685               g->lbearing = 0;
686               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
687               g->width = ft_face->max_advance_width * size / unitsPerEm;
688               g->ascent = ft_face->ascender * size / unitsPerEm;
689               g->descent = (- ft_face->descender) * size / unitsPerEm;
690             }
691           else
692             {
693               BDF_PropertyRec prop;
694
695               g->lbearing = 0;
696               g->rbearing = g->width = ft_face->available_sizes->width;
697               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
698                 {
699                   g->ascent = prop.u.integer;
700                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
701                   g->descent = prop.u.integer;
702                 }
703               else
704                 {
705                   g->ascent = ft_face->available_sizes->height;
706                   g->descent = 0;
707                 }
708             }
709         }
710       else
711         {
712           FT_Glyph_Metrics *metrics;
713
714           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
715           metrics = &ft_face->glyph->metrics;
716           g->lbearing = (metrics->horiBearingX >> 6);
717           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
718           g->width = metrics->horiAdvance >> 6;
719           g->ascent = metrics->horiBearingY >> 6;
720           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
721         }
722     }
723 }
724
725 /* The FreeType font driver function ENCODE_CHAR.  */
726
727 static unsigned
728 ft_encode_char (MRealizedFont *rfont, unsigned code)
729 {
730   MFTInfo *ft_info;
731
732   if (rfont->status == 0)
733     {
734       if ((rfont->driver->open) (rfont) < 0)
735         return -1;
736     }
737   ft_info = (MFTInfo *) rfont->info;
738   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
739   if (! code)
740     return MCHAR_INVALID_CODE;
741   return (code);
742
743 }
744
745 /* The FreeType font driver function RENDER.  */
746
747 #define NUM_POINTS 0x1000
748
749 typedef struct {
750   MDrawPoint points[NUM_POINTS];
751   MDrawPoint *p;
752 } MPointTable;
753
754 static void
755 ft_render (MDrawWindow win, int x, int y,
756            MGlyphString *gstring, MGlyph *from, MGlyph *to,
757            int reverse, MDrawRegion region)
758 {
759   MFTInfo *ft_info;
760   FT_Face ft_face;
761   MRealizedFace *rface = from->rface;
762   MFrame *frame = rface->frame;
763   FT_Int32 load_flags = FT_LOAD_RENDER;
764   MGlyph *g;
765   int i, j;
766   MPointTable point_table[8];
767
768   if (from == to)
769     return;
770
771   /* It is assured that the all glyphs in the current range use the
772      same realized face.  */
773   ft_info = (MFTInfo *) rface->rfont->info;
774   ft_face = ft_info->ft_face;
775
776   if (! gstring->anti_alias)
777     {
778 #ifdef FT_LOAD_TARGET_MONO
779       load_flags |= FT_LOAD_TARGET_MONO;
780 #else
781       load_flags |= FT_LOAD_MONOCHROME;
782 #endif
783     }
784
785   for (i = 0; i < 8; i++)
786     point_table[i].p = point_table[i].points;
787
788   for (g = from; g < to; x += g++->width)
789     {
790       unsigned char *bmp;
791       int intensity;
792       MPointTable *ptable;
793       int xoff, yoff;
794       int width, pitch;
795
796       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
797       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
798       bmp = ft_face->glyph->bitmap.buffer;
799       width = ft_face->glyph->bitmap.width;
800       pitch = ft_face->glyph->bitmap.pitch;
801       if (! gstring->anti_alias)
802         pitch *= 8;
803       if (width > pitch)
804         width = pitch;
805
806       if (gstring->anti_alias)
807         for (i = 0; i < ft_face->glyph->bitmap.rows;
808              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
809           {
810             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
811             for (j = 0; j < width; j++, xoff++)
812               {
813                 intensity = bmp[j] >> 5;
814                 if (intensity)
815                   {
816                     ptable = point_table + intensity;
817                     ptable->p->x = xoff;
818                     ptable->p->y = yoff;
819                     ptable->p++;
820                     if (ptable->p - ptable->points == NUM_POINTS)
821                       {
822                         (*frame->driver->draw_points)
823                           (frame, win, rface,
824                            reverse ? 7 - intensity : intensity,
825                            ptable->points, NUM_POINTS, region);
826                         ptable->p = ptable->points;
827                       }
828                   }
829               }
830           }
831       else
832         for (i = 0; i < ft_face->glyph->bitmap.rows;
833              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
834           {
835             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
836             for (j = 0; j < width; j++, xoff++)
837               {
838                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
839                 if (intensity)
840                   {
841                     ptable = point_table;
842                     ptable->p->x = xoff;
843                     ptable->p->y = yoff;
844                     ptable->p++;
845                     if (ptable->p - ptable->points == NUM_POINTS)
846                       {
847                         (*frame->driver->draw_points) (frame, win, rface,
848                                            reverse ? 0 : 7,
849                                            ptable->points, NUM_POINTS, region);
850                         ptable->p = ptable->points;
851                       }             
852                   }
853               }
854         }
855     }
856
857   if (gstring->anti_alias)
858     {
859       for (i = 1; i < 8; i++)
860         if (point_table[i].p != point_table[i].points)
861           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
862                              point_table[i].points,
863                              point_table[i].p - point_table[i].points, region);
864     }
865   else
866     {
867       if (point_table[0].p != point_table[0].points)
868         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
869                            point_table[0].points,
870                            point_table[0].p - point_table[0].points, region);
871     }
872 }
873
874 static void
875 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
876 {
877   MPlist *pl, *p;
878   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
879 #ifdef HAVE_FONTCONFIG
880   FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
881                    : NULL);
882 #endif
883
884   pl = ft_list_family (Mnil);
885   if (font)
886     {
887       MPLIST_DO (pl, pl)
888         {
889           MPLIST_DO (p, MPLIST_PLIST (pl))
890             {
891               MFTInfo *ft_info = MPLIST_VAL (p);
892
893 #ifdef HAVE_FONTCONFIG
894               if (lang && ft_info->langset
895                   && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
896                 continue;
897 #endif
898               if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
899                 continue;
900               mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
901             }
902           if (family != Mnil)
903             break;
904         }
905     }
906   else
907     {
908       MPLIST_DO (p, ft_family_list)
909         {
910           MFTInfo *ft_info = MPLIST_VAL (p);
911
912 #ifdef HAVE_FONTCONFIG
913           if (lang && ft_info->langset
914               && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
915             continue;
916 #endif
917           mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
918         }
919     }
920 }
921
922 \f
923 /* Internal API */
924
925 MFontDriver mfont__ft_driver =
926   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
927
928 int
929 mfont__ft_init ()
930 {
931   int i;
932
933   if (FT_Init_FreeType (&ft_library) != 0)
934     MERROR (MERROR_FONT_FT, -1);
935
936   for (i = 0; i < ft_to_prop_size; i++)
937     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
938
939   Municode_bmp = msymbol ("unicode-bmp");
940   Municode_full = msymbol ("unicode-full");
941   Miso10646_1 = msymbol ("iso10646-1");
942   Miso8859_1 = msymbol ("iso8859-1");
943
944   Mserif = msymbol ("serif");
945   Msans_serif = msymbol ("sans-serif");
946   Mmonospace = msymbol ("monospace");
947
948   Mmedium = msymbol ("medium");
949   Mr = msymbol ("r");
950   Mnull = msymbol ("");
951
952 #ifdef HAVE_FONTCONFIG
953   fc_generic_family_list = mplist ();
954   mplist_push (fc_generic_family_list, Mserif, Mserif);
955   mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
956   mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
957   /* These are (deprecated) aliases.  */
958   mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
959   mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
960   mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
961 #endif
962
963   return 0;
964 }
965
966 void
967 mfont__ft_fini ()
968 {
969   MPlist *plist, *p;
970
971   if (ft_font_list)
972     {
973       MPLIST_DO (plist, ft_font_list)
974         {
975           MPLIST_DO (p, MPLIST_VAL (plist))
976             {
977               MFTInfo *ft_info = MPLIST_VAL (p);
978
979               M17N_OBJECT_UNREF (ft_info);
980             }
981           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
982         }
983       M17N_OBJECT_UNREF (ft_font_list);
984       ft_font_list = NULL;
985
986       M17N_OBJECT_UNREF (ft_family_list);
987       ft_family_list = NULL;
988     }
989   FT_Done_FreeType (ft_library);
990   all_fonts_scaned = 0;
991
992 #ifdef HAVE_FONTCONFIG
993   m17n_object_unref (fc_generic_family_list);
994 #endif
995
996 }
997
998
999 #ifdef HAVE_FONTCONFIG
1000 typedef struct
1001 {
1002   int fc_value;
1003   char *m17n_value;
1004 } FC_vs_M17N_font_prop;
1005
1006 static FC_vs_M17N_font_prop fc_weight_table[] =
1007   { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1008     { FC_WEIGHT_LIGHT, "light" },
1009     { FC_WEIGHT_NORMAL, "normal" },
1010     { FC_WEIGHT_MEDIUM, "medium" },
1011     { FC_WEIGHT_DEMIBOLD, "demibold" },
1012     { FC_WEIGHT_EXTRABOLD, "extrabold" },
1013     { FC_WEIGHT_BLACK, "black" },
1014     { FC_WEIGHT_MEDIUM, NULL } };
1015
1016 static FC_vs_M17N_font_prop fc_slant_table[] =
1017   { { FC_SLANT_ROMAN, "r" },
1018     { FC_SLANT_ITALIC, "i" },
1019     { FC_SLANT_OBLIQUE, "o" },
1020     { FC_SLANT_ROMAN, NULL } };
1021
1022 static FC_vs_M17N_font_prop fc_width_table[] =
1023   { { FC_WIDTH_CONDENSED, "condensed" },
1024     { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1025     { FC_WIDTH_NORMAL, "normal" },
1026     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1027     { FC_WIDTH_EXPANDED, "expanded" },
1028     { FC_WIDTH_NORMAL, NULL } };
1029
1030
1031 static MSymbol
1032 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1033 {
1034   int i;
1035
1036   for (i = 0; table[i].m17n_value; i++)
1037     if (val <= table[i].fc_value)
1038       return msymbol ("table[i].m17n_value");
1039   return msymbol ("table[i - 1].m17n_value");
1040 }
1041
1042 static int
1043 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1044 {
1045   int i;
1046
1047   for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1048   return table[i].fc_value;
1049 }
1050
1051 int
1052 mfont__ft_parse_name (char *name, MFont *font)
1053 {
1054   FcPattern *pat = FcNameParse ((FcChar8 *) name);
1055   FcChar8 *str;
1056   int val;
1057   double size;
1058   
1059   if (! pat)
1060     return -1;
1061   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1062     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1063   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1064     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1065   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1066     mfont__set_property (font, MFONT_WEIGHT,
1067                          fc_decode_prop (val, fc_weight_table));
1068   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1069     mfont__set_property (font, MFONT_STYLE,
1070                          fc_decode_prop (val, fc_slant_table));
1071   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1072     mfont__set_property (font, MFONT_STRETCH,
1073                          fc_decode_prop (val, fc_width_table));
1074   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1075     font->property[MFONT_SIZE] = size * 10;
1076   FcPatternDestroy (pat);
1077   return 0;
1078 }
1079
1080 char *
1081 mfont__ft_unparse_name (MFont *font)
1082 {
1083   FcPattern *pat = FcPatternCreate ();
1084   MSymbol sym, weight, style, stretch;
1085   char *name;
1086
1087   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1088     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1089   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1090     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1091   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1092     FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1093                                                          fc_weight_table));
1094   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1095     FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1096                                                         fc_slant_table));
1097   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1098     FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1099                                                         fc_width_table));
1100   name = (char *) FcNameUnparse (pat);
1101   FcPatternDestroy (pat);
1102   return name;
1103 }
1104 #endif  /* HAVE_FONTCONFIG */
1105
1106 \f
1107 #ifdef HAVE_OTF
1108
1109 #define DEVICE_DELTA(table, size)                               \
1110   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
1111    ? (table).DeltaValue[(size) >= (table).StartSize]            \
1112    : 0)
1113
1114 void
1115 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1116                unsigned code, int size, int *x, int *y)
1117 {
1118   if (anchor->AnchorFormat == 2)
1119     {
1120       FT_Outline *outline;
1121       int ap = anchor->f.f1.AnchorPoint;
1122
1123       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1124       outline = &ft_face->glyph->outline;
1125       if (ap < outline->n_points)
1126         {
1127           *x = outline->points[ap].x;
1128           *y = outline->points[ap].y;
1129         }
1130     }
1131   else if (anchor->AnchorFormat == 3)
1132     {
1133       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1134       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1135     }
1136 }
1137
1138 int
1139 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1140                      MSymbol script, MSymbol langsys,
1141                      MSymbol gsub_features, MSymbol gpos_features)
1142 {
1143   int len = to - from;
1144   MGlyph *g = MGLYPH (from);
1145   int i, gidx;
1146   MRealizedFont *rfont;
1147   MFTInfo *ft_info;
1148   OTF *otf;
1149   OTF_GlyphString otf_gstring;
1150   OTF_Glyph *otfg;
1151   char *script_name, *language_name;
1152   char *gsub_feature_names, *gpos_feature_names;
1153   int need_cmap;
1154
1155   if (len == 0)
1156     return from;
1157
1158   rfont = g->rface->rfont;
1159   ft_info = rfont->info;
1160   if (ft_info->otf_flag < 0)
1161     goto simple_copy;
1162   otf = ft_info->otf;
1163   if (! otf)
1164     {
1165       otf = OTF_open (ft_info->filename);
1166       if (otf && OTF_get_table (otf, "head") < 0)
1167         {
1168           OTF_close (otf);
1169           otf = NULL;
1170         }
1171       if (! otf)
1172         {
1173           ft_info->otf_flag = -1;
1174           goto simple_copy;
1175         }
1176       ft_info->otf = otf;
1177     }
1178
1179   if (script != Mnil)
1180     script_name = msymbol_name (script);
1181   else
1182     script_name = NULL;
1183   if (langsys != Mnil)
1184     language_name = msymbol_name (langsys);
1185   else
1186     language_name = NULL;
1187   gsub_feature_names
1188     = (gsub_features == Mt ? "*"
1189        : gsub_features == Mnil ? NULL
1190        : msymbol_name (gsub_features));
1191   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1192     gsub_feature_names = NULL;
1193   gpos_feature_names
1194     = (gpos_features == Mt ? "*"
1195        : gpos_features == Mnil ? NULL
1196        : msymbol_name (gpos_features));
1197   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1198     gpos_feature_names = NULL;
1199
1200   otf_gstring.size = otf_gstring.used = len;
1201   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1202   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1203   for (i = 0, need_cmap = 0; i < len; i++)
1204     {
1205       if (gstring->glyphs[from + i].otf_encoded)
1206         {
1207           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1208           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1209         }
1210       else
1211         {
1212           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1213           need_cmap++;
1214         }
1215     }
1216   if (need_cmap
1217       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1218     goto simple_copy;
1219
1220   OTF_drive_gdef (otf, &otf_gstring);
1221   gidx = gstring->used;
1222
1223   if (gsub_feature_names)
1224     {
1225       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1226                           gsub_feature_names) < 0)
1227         goto simple_copy;
1228       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1229         {
1230           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1231
1232           temp.c = otfg->c;
1233           temp.combining_code = 0;
1234           if (otfg->glyph_id)
1235             {
1236               temp.code = otfg->glyph_id;
1237               temp.otf_encoded = 1;
1238             }
1239           else
1240             {
1241               temp.code = temp.c;
1242               temp.otf_encoded = 0;
1243             }
1244           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1245           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1246         }
1247     }
1248   else
1249     for (i = 0; i < len; i++)
1250       {
1251         MGlyph temp = gstring->glyphs[from + i];
1252
1253         if (otf_gstring.glyphs[i].glyph_id)
1254           {
1255             temp.code = otf_gstring.glyphs[i].glyph_id;
1256             temp.otf_encoded = 1;
1257           }
1258         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1259       }
1260
1261   ft_find_metric (rfont, gstring, gidx, gstring->used);
1262
1263   if (gpos_feature_names)
1264     {
1265       int u;
1266       int size10, size;
1267       MGlyph *base = NULL, *mark = NULL;
1268
1269       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1270                           gpos_feature_names) < 0)
1271         return to;
1272
1273       u = otf->head->unitsPerEm;
1274       size10 = rfont->font.property[MFONT_SIZE];
1275       size = size10 / 10;
1276
1277       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1278            i < otf_gstring.used; i++, otfg++, g++)
1279         {
1280           MGlyph *prev;
1281
1282           if (! otfg->glyph_id)
1283             continue;
1284           switch (otfg->positioning_type)
1285             {
1286             case 0:
1287               break;
1288             case 1: case 2:
1289               {
1290                 int format = otfg->f.f1.format;
1291
1292                 if (format & OTF_XPlacement)
1293                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1294                 if (format & OTF_XPlaDevice)
1295                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1296                 if (format & OTF_YPlacement)
1297                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1298                 if (format & OTF_YPlaDevice)
1299                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1300                 if (format & OTF_XAdvance)
1301                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1302                 if (format & OTF_XAdvDevice)
1303                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1304               }
1305               break;
1306             case 3:
1307               /* Not yet supported.  */
1308               break;
1309             case 4: case 5:
1310               if (! base)
1311                 break;
1312               prev = base;
1313               goto label_adjust_anchor;
1314             default:            /* i.e. case 6 */
1315               if (! mark)
1316                 break;
1317               prev = mark;
1318
1319             label_adjust_anchor:
1320               {
1321                 int base_x, base_y, mark_x, mark_y;
1322
1323                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1324                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1325                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1326                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1327
1328                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1329                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1330                                  prev->code, size, &base_x, &base_y);
1331                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1332                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1333                                  g->code, size, &mark_x, &mark_y);
1334                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1335                 g->yoff = prev->yoff + mark_y - base_y;
1336                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1337               }
1338             }
1339           if (otfg->GlyphClass == OTF_GlyphClass0)
1340             base = mark = g;
1341           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1342             mark = g;
1343           else
1344             base = g;
1345         }
1346     }
1347   free (otf_gstring.glyphs);
1348   return to;
1349
1350  simple_copy:
1351   ft_find_metric (rfont, gstring, from, to);
1352   for (i = 0; i < len; i++)
1353     {
1354       MGlyph temp = gstring->glyphs[from + i];
1355       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1356     }
1357   free (otf_gstring.glyphs);
1358   return to;
1359 }
1360
1361
1362 int
1363 mfont__ft_decode_otf (MGlyph *g)
1364 {
1365   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1366   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1367
1368   return (c ? c : -1);
1369 }
1370
1371 #endif  /* HAVE_OTF */
1372
1373 #endif /* HAVE_FREETYPE */