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