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