*** empty log message ***
[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 "internal-gui.h"
39 #include "font.h"
40 #include "face.h"
41
42 #ifdef HAVE_FREETYPE
43 #include <ft2build.h>
44 #include FT_FREETYPE_H
45
46 #ifdef HAVE_OTF
47 #include <otf.h>
48 #endif /* HAVE_OTF */
49
50 static FT_Library ft_library;
51
52 typedef struct
53 {
54   MSymbol ft_style;
55   MSymbol weight, style, stretch;
56 } MFTtoProp;
57
58 static int ft_to_prop_size;
59 static MFTtoProp *ft_to_prop;
60
61 typedef struct
62 {
63   M17NObject control;
64   MFont font;
65   char *filename;
66   MPlist *charmap_list;
67   FT_Face ft_face;
68   int otf_flag; /* This font 1: is OTF, 0: may be OTF, -1: is not OTF.  */
69 #ifdef HAVE_OTF
70   OTF *otf;
71 #endif /* HAVE_OTF */
72 } MFTInfo;
73
74 /* List of FreeType fonts.  Keys are family names, values are (MFTInfo
75    *) where MFTInfo->ft_face and MFTInfo->otf are NULL.  */
76 static MPlist *ft_font_list;
77
78 /** Return 1 iff the filename in DIRENTRY matches FreeType font file.
79     We select only TrueType/OpenType/Type1 fonts.
80     Used as the arg SELECT of scandir () in list_ft_in_dir ().  */
81
82 static int
83 check_filename (const char *name)
84 {
85   int len = strlen (name);
86   const char *ext = name + (len - 4);
87
88   if (len < 5)
89     return -1;
90   if (! memcmp (ext, ".ttf", 4)
91       || ! memcmp (ext, ".TTF", 4)
92       || ! memcmp (ext, ".otf", 4)
93       || ! memcmp (ext, ".OTF", 4))
94     return 1;
95   if (! memcmp (ext, ".PFA", 4)
96       || ! memcmp (ext, ".pfa", 4)
97       || ! memcmp (ext, ".PFB", 4)
98       || ! memcmp (ext, ".pfb", 4))
99     return 0;
100   return -1;
101 }
102
103 static MSymbol
104 ft_set_property (MFont *font, char *family_name, char *style_name)
105 {
106   MSymbol family;
107   MSymbol style;
108   int len;
109   char *buf, *p;
110
111   MFONT_INIT (font);
112   font->property[MFONT_TYPE] = MFONT_TYPE_FT + 1;
113   mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
114
115   len = strlen (family_name) + 1;
116   buf = (char *) alloca (len);
117   memcpy (buf, family_name, len);
118   for (p = buf; *p; p++)
119     if (*p >= 'A' && *p <= 'Z')
120       *p += 'a' - 'A';
121   family = msymbol (buf);
122   mfont__set_property (font, MFONT_FAMILY, family);
123
124   if (style_name)
125     {
126       len = strlen (style_name) + 1;
127       buf = (char *) alloca (len);
128       memcpy (buf, style_name, len);
129       for (p = buf; *p; p++)
130         if (*p >= 'A' && *p <= 'Z')
131           *p += 'a' - 'A';
132       style = msymbol (buf);
133     }
134   else
135     style = Mnil;
136
137   if (style != Mnil)
138     {
139       int i;
140
141       for (i = 0; i < ft_to_prop_size; i++)
142         if (ft_to_prop[i].ft_style == style)
143           {
144             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
145             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
146             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
147             return family;
148           }
149     }      
150   mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
151   mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
152   mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
153   return family;
154 }
155
156 static void
157 add_font_list (char *filename, int otf_flag)
158 {
159   FT_Face ft_face;
160   MFTInfo *ft_info;
161   MSymbol family;
162   char registry_buf[16];
163   int i;
164
165   if (FT_New_Face (ft_library, filename, 0, &ft_face))
166     return;
167
168   if (ft_face->family_name && ((char *) ft_face->family_name)[0])
169     {
170       int unicode_charmap_bmp = -1, unicode_charmap_full = -1;
171
172       MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
173       family = ft_set_property (&ft_info->font,
174                                 (char *) ft_face->family_name,
175                                 (char *) ft_face->style_name);
176       ft_info->filename = strdup (filename);
177       ft_info->charmap_list = mplist ();
178       mplist_add (ft_info->charmap_list, Mt, (void *) -1);
179       for (i = 0; i < ft_face->num_charmaps; i++)
180         {
181           sprintf (registry_buf, "%d-%d",
182                    ft_face->charmaps[i]->platform_id,
183                    ft_face->charmaps[i]->encoding_id);
184           mplist_add (ft_info->charmap_list, msymbol (registry_buf),
185                       (void *) i);
186           if (ft_face->charmaps[i]->platform_id == 0)
187             {
188               if (ft_face->charmaps[i]->encoding_id == 3)
189                 unicode_charmap_bmp = i;
190               else if (ft_face->charmaps[i]->encoding_id == 4)
191                 unicode_charmap_full = i;
192             }
193           else if (ft_face->charmaps[i]->platform_id == 3)
194             {
195               if (ft_face->charmaps[i]->encoding_id == 1)
196                 unicode_charmap_bmp = i;
197               else if (ft_face->charmaps[i]->encoding_id == 10)
198                 unicode_charmap_full = i;
199             }
200           else if (ft_face->charmaps[i]->platform_id == 1
201                    && ft_face->charmaps[i]->encoding_id == 0)
202             mplist_add (ft_info->charmap_list, msymbol ("apple-roman"),
203                         (void *) i);
204         }
205       if (unicode_charmap_bmp >= 0)
206         mplist_add (ft_info->charmap_list, msymbol ("unicode-bmp"),
207                     (void *) unicode_charmap_bmp);
208       if (unicode_charmap_full >= 0)
209         mplist_add (ft_info->charmap_list, msymbol ("unicode-full"),
210                     (void *) unicode_charmap_full);
211       mplist_add (ft_font_list, family, ft_info);
212     }
213   FT_Done_Face (ft_face);
214 }
215
216 static void
217 build_font_list ()
218 {
219   MPlist *plist;
220   struct stat buf;
221   char *pathname;
222
223   ft_font_list = mplist ();
224
225   MPLIST_DO (plist, mfont_freetype_path)
226     if (MPLIST_STRING_P (plist)
227         && (pathname = MPLIST_STRING (plist))
228         && stat (pathname, &buf) == 0)
229       {
230         if (S_ISREG (buf.st_mode))
231           {
232             int result = check_filename (pathname);
233
234             add_font_list (pathname, result > 0 ? 0 : -1);
235           }
236         else if (S_ISDIR (buf.st_mode))
237           {
238             int len = strlen (pathname);
239             char path[PATH_MAX];
240             DIR *dir = opendir (pathname);
241             struct dirent *dp;
242             int result;
243
244             if (dir)
245               {
246                 strcpy (path, pathname);
247                 strcpy (path + len, "/");
248                 len++;
249                 while ((dp = readdir (dir)) != NULL)
250                   if ((result = check_filename (dp->d_name)) >= 0)
251                     {
252                       strcpy (path + len, dp->d_name);
253                       add_font_list (path, result > 0 ? 0 : -1);
254                     }
255                 closedir (dir);
256               }
257           }
258       }
259 }
260
261 static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int);
262 static int ft_open (MRealizedFont *);
263 static void ft_close (MRealizedFont *);
264 static void ft_find_metric (MRealizedFont *, MGlyph *);
265 static unsigned ft_encode_char (MRealizedFont *, int, unsigned);
266 static void ft_render (MDrawWindow, int, int, MGlyphString *,
267                        MGlyph *, MGlyph *, int, MDrawRegion);
268
269 MFontDriver ft_driver =
270   { ft_select, ft_open, ft_close,
271     ft_find_metric, ft_encode_char, ft_render };
272
273 /* The FreeType font driver function LIST.  */
274
275 static MRealizedFont *
276 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
277 {
278   MPlist *plist;
279   MFTInfo *best_font;
280   int best_score;
281   MRealizedFont *rfont;
282   MSymbol family, registry;
283
284   if (! ft_font_list)
285     build_font_list ();
286   best_font = NULL;
287   best_score = 0;
288   family = FONT_PROPERTY (spec, MFONT_FAMILY);
289   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
290   if (registry == Mnil)
291     registry = Mt;
292
293   MPLIST_DO (plist, ft_font_list)
294     {
295       MFTInfo *ft_info;
296       int score;
297
298       if (family)
299         {
300           plist = mplist_find_by_key (plist, family);
301           if (! plist)
302             break;
303         }
304       ft_info = (MFTInfo *) MPLIST_VAL (plist);
305       if (! mplist_find_by_key (ft_info->charmap_list, registry))
306         continue;
307
308       /* We always ignore FOUNDRY.  */
309       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
310       score = mfont__score (&ft_info->font, spec, request, limited_size);
311       if (score >= 0
312           && (! best_font
313               || best_score > score))
314         {
315           best_font = ft_info;
316           best_score = score;
317           if (score == 0)
318             break;
319         }
320     }
321   if (! best_font)
322     return NULL;
323
324   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
325   rfont->frame = frame;
326   rfont->spec = *spec;
327   rfont->request = *request;
328   rfont->font = best_font->font;
329   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
330   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
331   rfont->score = best_score;
332   rfont->info = best_font;
333   rfont->driver = &ft_driver;
334   return rfont;
335 }
336
337 static void
338 close_ft (void *object)
339 {
340   MFTInfo *ft_info = (MFTInfo *) object;
341
342   if (ft_info->ft_face)
343     FT_Done_Face (ft_info->ft_face);
344 #ifdef HAVE_OTF
345   if (ft_info->otf)
346     OTF_close (ft_info->otf);
347 #endif /* HAVE_OTF */
348   free (object);
349 }
350
351 /* The FreeType font driver function OPEN.  */
352
353 static int
354 ft_open (MRealizedFont *rfont)
355 {
356   MFTInfo *ft_info;
357   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
358   int i;
359   int mdebug_mask = MDEBUG_FONT;
360
361   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
362   ft_info->font = ((MFTInfo *) rfont->info)->font;
363   ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag;
364   ft_info->filename = ((MFTInfo *) rfont->info)->filename;
365   ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list;
366   rfont->info = ft_info;
367
368   rfont->status = -1;
369   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
370     goto err;
371   if (registry == Mnil)
372     registry = Mt;
373   i = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
374   if (i >= 0
375       && FT_Set_Charmap (ft_info->ft_face, ft_info->ft_face->charmaps[i]))
376     goto err;
377   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0,
378                           rfont->font.property[MFONT_SIZE] / 10))
379     goto err;
380
381   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
382   rfont->status = 1;
383   rfont->ascent = ft_info->ft_face->ascender >> 6;
384   rfont->descent = ft_info->ft_face->descender >> 6;
385   return 0;
386
387  err:
388   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
389   return -1;
390 }
391
392 /* The FreeType font driver function CLOSE.  */
393
394 static void
395 ft_close (MRealizedFont *rfont)
396 {
397   M17N_OBJECT_UNREF (rfont->info);
398 }
399
400 /* The FreeType font driver function FIND_METRIC.  */
401
402 static void
403 ft_find_metric (MRealizedFont *rfont, MGlyph *g)
404 {
405   MFTInfo *ft_info = (MFTInfo *) rfont->info;
406   FT_Face ft_face = ft_info->ft_face;
407
408   if (g->code == MCHAR_INVALID_CODE)
409     {
410       unsigned unitsPerEm = ft_face->units_per_EM;
411       int size = rfont->font.property[MFONT_SIZE] / 10;
412
413       g->lbearing = 0;
414       g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
415       g->width = ft_face->max_advance_width * size / unitsPerEm;
416       g->ascent = ft_face->ascender * size / unitsPerEm;
417       g->descent = (- ft_face->descender) * size / unitsPerEm;
418     }
419   else
420     {
421       FT_Glyph_Metrics *metrics;
422       FT_UInt code;
423
424       if (g->otf_encoded)
425         code = g->code;
426       else
427         code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
428
429       FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
430       metrics = &ft_face->glyph->metrics;
431       g->lbearing = metrics->horiBearingX >> 6;
432       g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
433       g->width = metrics->horiAdvance >> 6;
434       g->ascent = metrics->horiBearingY >> 6;
435       g->descent = (metrics->height - metrics->horiBearingY) >> 6;
436     }
437 }
438
439 /* The FreeType font driver function ENCODE_CHAR.  */
440
441 static unsigned
442 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
443 {
444   MFTInfo *ft_info;
445   FT_UInt code;
446
447   if (rfont->status == 0)
448     {
449       if (ft_open (rfont) < 0)
450         return -1;
451     }
452   ft_info = (MFTInfo *) rfont->info;
453   code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
454   if (! code)
455     return MCHAR_INVALID_CODE;
456 #if 0
457   FT_Load_Glyph (ft_info->ft_face, code, FT_LOAD_NO_SCALE);
458   return (ft_info->ft_face->glyph->metrics.width > 0
459           ? (unsigned) c : MCHAR_INVALID_CODE);
460 #endif
461   return ((unsigned) c);
462
463 }
464
465 /* The FreeType font driver function RENDER.  */
466
467 static void
468 ft_render (MDrawWindow win, int x, int y,
469            MGlyphString *gstring, MGlyph *from, MGlyph *to,
470            int reverse, MDrawRegion region)
471 {
472   MRealizedFace *rface;
473   MFrame *frame;
474   MFTInfo *ft_info;
475   FT_Face ft_face = NULL;
476   MGlyph *g;
477
478   if (from == to)
479     return;
480
481   /* It is assured that the all glyphs in the current range use the
482      same realized face.  */
483   rface = from->rface;
484   frame = rface->frame;
485   ft_info = (MFTInfo *) rface->rfont->info;
486   ft_face = ft_info->ft_face;
487
488   g = from;
489   while (g < to)
490     {
491       if (g->type == GLYPH_CHAR)
492         {
493           FT_UInt code;
494
495           if (g->otf_encoded)
496             code = g->code;
497           else
498             code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
499 #ifdef FT_LOAD_TARGET_MONO
500           FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO);
501 #else
502           FT_Render_Glyph (ft_face->glyph, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
503 #endif
504           mwin__draw_bitmap (frame, win, rface, reverse,
505                              x + ft_face->glyph->bitmap_left + g->xoff,
506                              y - ft_face->glyph->bitmap_top + g->yoff,
507                              ft_face->glyph->bitmap.width,
508                              ft_face->glyph->bitmap.rows,
509                              ft_face->glyph->bitmap.pitch,
510                              ft_face->glyph->bitmap.buffer,
511                              region);
512         }
513       x += g++->width;
514     }
515
516   return;
517 }
518
519 \f
520
521 int
522 mfont__ft_init ()
523 {
524   struct {
525     char *ft_style;
526     char *weight, *style, *stretch;
527   } ft_to_prop_name[] =
528     { { "regular", "medium", "r", "normal" },
529       { "italic", "medium", "i", "normal" },
530       { "bold", "bold", "r", "normal" },
531       { "bold italic", "bold", "i", "normal" },
532       { "narrow", "medium", "r", "condensed" },
533       { "narrow italic", "medium", "i", "condensed" },
534       { "narrow bold", "bold", "r", "condensed" },
535       { "narrow bold italic", "bold", "i", "condensed" },
536       { "black", "black", "r", "normal" },
537       { "black italic", "black", "i", "normal" } };
538   int i;
539
540   if (FT_Init_FreeType (&ft_library) != 0)
541     MERROR (MERROR_FONT_FT, -1);
542
543   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
544   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
545   for (i = 0; i < ft_to_prop_size; i++)
546     {
547       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
548       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
549       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
550       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
551     }
552
553   mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
554
555   return 0;
556 }
557
558 void
559 mfont__ft_fini ()
560 {
561   MPlist *plist;
562
563   if (ft_font_list)
564     {
565       MPLIST_DO (plist, ft_font_list)
566         {
567           MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
568           free (ft_info->filename);
569           M17N_OBJECT_UNREF (ft_info->charmap_list);
570           free (ft_info);
571         }
572       M17N_OBJECT_UNREF (ft_font_list);
573       ft_font_list = NULL;
574     }
575   free (ft_to_prop);
576   FT_Done_FreeType (ft_library);
577 }
578
579
580 int
581 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
582                      MSymbol script, MSymbol langsys, 
583                      MSymbol gsub_features, MSymbol gpos_features)
584 {
585   int len = to - from;
586   MGlyph g;
587   int i;
588 #ifdef HAVE_OTF
589   MFTInfo *ft_info;
590   OTF *otf;
591   OTF_GlyphString otf_gstring;
592   OTF_Glyph *otfg;
593   char *script_name, *language_name;
594   char *gsub_feature_names, *gpos_feature_names;
595   int from_pos, to_pos;
596   int unitsPerEm;
597
598   if (len == 0)
599     return from;
600
601   ft_info = (MFTInfo *) gstring->glyphs[from].rface->rfont->info;
602   if (ft_info->otf_flag < 0)
603     goto simple_copy;
604   otf = ft_info->otf;
605   if (! otf && (otf = OTF_open (ft_info->filename)))
606     {
607       if (OTF_get_table (otf, "head") < 0
608           || (OTF_check_table (otf, "GSUB") < 0
609               && OTF_check_table (otf, "GPOS") < 0))
610         {
611           OTF_close (otf);
612           ft_info->otf_flag = -1;
613           ft_info->otf = NULL;
614           goto simple_copy;
615         }
616       ft_info->otf = otf;
617     }
618
619   script_name = msymbol_name (script);
620   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
621   gsub_feature_names
622     = (gsub_features == Mt ? "*"
623        : gsub_features == Mnil ? NULL
624        : msymbol_name (gsub_features));
625   gpos_feature_names
626     = (gpos_features == Mt ? "*"
627        : gpos_features == Mnil ? NULL
628        : msymbol_name (gpos_features));
629
630   g = gstring->glyphs[from];
631   from_pos = g.pos;
632   to_pos = g.to;
633   for (i = from + 1; i < to; i++)
634     {
635       if (from_pos > gstring->glyphs[i].pos)
636         from_pos = gstring->glyphs[i].pos;
637       if (to_pos < gstring->glyphs[i].to)
638         to_pos = gstring->glyphs[i].to;
639     }
640
641   unitsPerEm = otf->head->unitsPerEm;
642   otf_gstring.size = otf_gstring.used = len;
643   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
644   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
645   for (i = 0; i < len; i++)
646     {
647       if (gstring->glyphs[from + i].otf_encoded)
648         {
649           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
650           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
651         }
652       else
653         {
654           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
655         }
656     }
657       
658   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
659                         gsub_feature_names, gpos_feature_names) < 0)
660     goto simple_copy;
661   g.pos = from_pos;
662   g.to = to_pos;
663   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
664     {
665       g.combining_code = 0;
666       g.c = otfg->c;
667       if (otfg->glyph_id)
668         {
669           g.code = otfg->glyph_id;
670           switch (otfg->positioning_type)
671             {
672             case 1: case 2:
673               {
674                 int off_x = 128, off_y = 128;
675
676                 if (otfg->f.f1.format & OTF_XPlacement)
677                   off_x = ((double) (otfg->f.f1.value->XPlacement)
678                            * 100 / unitsPerEm + 128);
679                 if (otfg->f.f1.format & OTF_YPlacement)
680                   off_y = ((double) (otfg->f.f1.value->YPlacement)
681                            * 100 / unitsPerEm + 128);
682                 g.combining_code
683                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
684                 if ((otfg->f.f1.format & OTF_XAdvance)
685                     || (otfg->f.f1.format & OTF_YAdvance))
686                   off_y--;
687               }
688               break;
689             case 3:
690               /* Not yet supported.  */
691               break;
692             case 4:
693               {
694                 int off_x, off_y;
695
696                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
697                                    - otfg->f.f4.mark_anchor->XCoordinate)
698                          * 100 / unitsPerEm + 128);
699                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
700                                    - otfg->f.f4.mark_anchor->YCoordinate)
701                          * 100 / unitsPerEm + 128);
702                 g.combining_code
703                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
704               }
705               break;
706             case 5:
707               /* Not yet supported.  */
708               break;
709             default:            /* i.e case 6 */
710               /* Not yet supported.  */
711               break;
712             }
713           g.otf_encoded = 1;
714         }
715       else
716         {
717           g.code = otfg->c;
718           g.otf_encoded = 0;
719         }
720       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
721     }
722   return to;
723
724  simple_copy:
725 #endif  /* HAVE_OTF */
726   for (i = 0; i < len; i++)
727     {
728       g = gstring->glyphs[from + i];
729       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
730     }
731   return to;
732 }
733
734 int
735 mfont__ft_decode_otf (MGlyph *g)
736 {
737 #ifdef HAVE_OTF
738   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
739   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
740
741   return (c ? c : -1);
742 #else  /* not HAVE_OTF */
743   return -1;
744 #endif  /* not HAVE_OTF */
745 }
746
747 #else /* not HAVE_FREETYPE */
748
749 int
750 mfont__ft_init ()
751 {
752   return 0;
753 }
754
755 void
756 mfont__ft_fini ()
757 {
758 }
759
760 #endif /* HAVE_FREETYPE */