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