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