(mfont__ft_init): Add oblique and boldoblique.
[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 *, MGlyphString *, int, int);
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, MGlyphString *gstring,
404                 int from, int to)
405 {
406   MFTInfo *ft_info = (MFTInfo *) rfont->info;
407   FT_Face ft_face = ft_info->ft_face;
408   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
409   FT_Int32 load_flags = FT_LOAD_RENDER;
410
411   if (! gstring->anti_alias)
412     {
413 #ifdef FT_LOAD_TARGET_MONO
414       load_flags |= FT_LOAD_TARGET_MONO;
415 #else
416       load_flags |= FT_LOAD_MONOCHROME;
417 #endif
418     }
419
420   for (; g != gend; g++)
421     {
422       if (g->code == MCHAR_INVALID_CODE)
423         {
424           unsigned unitsPerEm = ft_face->units_per_EM;
425           int size = rfont->font.property[MFONT_SIZE] / 10;
426
427           g->lbearing = 0;
428           g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
429           g->width = ft_face->max_advance_width * size / unitsPerEm;
430           g->ascent = ft_face->ascender * size / unitsPerEm;
431           g->descent = (- ft_face->descender) * size / unitsPerEm;
432         }
433       else
434         {
435           FT_Glyph_Metrics *metrics;
436           FT_UInt code;
437
438           if (g->otf_encoded)
439             code = g->code;
440           else
441             code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
442
443           FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
444           metrics = &ft_face->glyph->metrics;
445           g->lbearing = (metrics->horiBearingX >> 6);
446           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
447           g->width = metrics->horiAdvance >> 6;
448           g->ascent = metrics->horiBearingY >> 6;
449           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
450         }
451     }
452 }
453
454 /* The FreeType font driver function ENCODE_CHAR.  */
455
456 static unsigned
457 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
458 {
459   MFTInfo *ft_info;
460   FT_UInt code;
461
462   if (rfont->status == 0)
463     {
464       if (ft_open (rfont) < 0)
465         return -1;
466     }
467   ft_info = (MFTInfo *) rfont->info;
468   code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
469   if (! code)
470     return MCHAR_INVALID_CODE;
471 #if 0
472   FT_Load_Glyph (ft_info->ft_face, code, FT_LOAD_NO_SCALE);
473   return (ft_info->ft_face->glyph->metrics.width > 0
474           ? (unsigned) c : MCHAR_INVALID_CODE);
475 #endif
476   return ((unsigned) c);
477
478 }
479
480 /* The FreeType font driver function RENDER.  */
481
482 #define NUM_POINTS 0x1000
483
484 typedef struct {
485   MDrawPoint points[NUM_POINTS];
486   MDrawPoint *p;
487 } MPointTable;
488
489 static void
490 ft_render (MDrawWindow win, int x, int y,
491            MGlyphString *gstring, MGlyph *from, MGlyph *to,
492            int reverse, MDrawRegion region)
493 {
494   MRealizedFace *rface = from->rface;
495   MFrame *frame = rface->frame;
496   MFTInfo *ft_info;
497   FT_Face ft_face = NULL;
498   FT_Int32 load_flags = FT_LOAD_RENDER;
499   MGlyph *g;
500   int i, j;
501   MPointTable point_table[8];
502
503   if (from == to)
504     return;
505
506   if (! gstring->anti_alias)
507     {
508 #ifdef FT_LOAD_TARGET_MONO
509       load_flags |= FT_LOAD_TARGET_MONO;
510 #else
511       load_flags |= FT_LOAD_MONOCHROME;
512 #endif
513     }
514
515   /* It is assured that the all glyphs in the current range use the
516      same realized face.  */
517   ft_info = (MFTInfo *) rface->rfont->info;
518   ft_face = ft_info->ft_face;
519
520   for (i = 0; i < 8; i++)
521     point_table[i].p = point_table[i].points;
522
523   for (g = from; g < to; x += g++->width)
524     {
525       FT_UInt code;
526       unsigned char *bmp;
527       int intensity;
528       MPointTable *ptable;
529       int xoff, yoff;
530
531       if (g->otf_encoded)
532         code = g->code;
533       else
534         code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
535       FT_Load_Glyph (ft_face, code, load_flags);
536       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
537       bmp = ft_face->glyph->bitmap.buffer;
538       if (gstring->anti_alias)
539         for (i = 0; i < ft_face->glyph->bitmap.rows;
540              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
541           {
542             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
543             for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
544               {
545                 intensity = bmp[j] >> 5;
546                 if (intensity)
547                   {
548                     ptable = point_table + intensity;
549                     ptable->p->x = xoff;
550                     ptable->p->y = yoff;
551                     ptable->p++;
552                     if (ptable->p - ptable->points == NUM_POINTS)
553                       {
554                         mwin__draw_points (frame, win, rface,
555                                            reverse ? 7 - intensity : intensity,
556                                            ptable->points, NUM_POINTS, region);
557                         ptable->p = ptable->points;
558                       }
559                   }
560               }
561           }
562       else
563         for (i = 0; i < ft_face->glyph->bitmap.rows;
564              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
565           {
566             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
567             for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
568               {
569                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
570                 if (intensity)
571                   {
572                     ptable = point_table;
573                     ptable->p->x = xoff;
574                     ptable->p->y = yoff;
575                     ptable->p++;
576                     if (ptable->p - ptable->points == NUM_POINTS)
577                       {
578                         mwin__draw_points (frame, win, rface,
579                                            reverse ? 0 : 7,
580                                            ptable->points, NUM_POINTS, region);
581                         ptable->p = ptable->points;
582                       }             
583                   }
584               }
585         }
586     }
587
588   if (gstring->anti_alias)
589     {
590       for (i = 1; i < 8; i++)
591         if (point_table[i].p != point_table[i].points)
592           mwin__draw_points (frame, win, rface, reverse ? 7 - i : i,
593                              point_table[i].points,
594                              point_table[i].p - point_table[i].points, region);
595     }
596   else
597     {
598       if (point_table[0].p != point_table[0].points)
599         mwin__draw_points (frame, win, rface, reverse ? 0 : 7,
600                            point_table[0].points,
601                            point_table[0].p - point_table[0].points, region);
602     }
603 }
604
605 \f
606
607 int
608 mfont__ft_init ()
609 {
610   struct {
611     char *ft_style;
612     char *weight, *style, *stretch;
613   } ft_to_prop_name[] =
614     { { "regular", "medium", "r", "normal" },
615       { "italic", "medium", "i", "normal" },
616       { "bold", "bold", "r", "normal" },
617       { "bold italic", "bold", "i", "normal" },
618       { "narrow", "medium", "r", "condensed" },
619       { "narrow italic", "medium", "i", "condensed" },
620       { "narrow bold", "bold", "r", "condensed" },
621       { "narrow bold italic", "bold", "i", "condensed" },
622       { "black", "black", "r", "normal" },
623       { "black italic", "black", "i", "normal" },
624       { "oblique", "medium", "o", "normal" },
625       { "boldoblique", "bold", "o", "normal" } };
626   int i;
627
628   if (FT_Init_FreeType (&ft_library) != 0)
629     MERROR (MERROR_FONT_FT, -1);
630
631   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
632   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
633   for (i = 0; i < ft_to_prop_size; i++)
634     {
635       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
636       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
637       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
638       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
639     }
640
641   mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
642
643   return 0;
644 }
645
646 void
647 mfont__ft_fini ()
648 {
649   MPlist *plist;
650
651   if (ft_font_list)
652     {
653       MPLIST_DO (plist, ft_font_list)
654         {
655           MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
656           free (ft_info->filename);
657           M17N_OBJECT_UNREF (ft_info->charmap_list);
658           free (ft_info);
659         }
660       M17N_OBJECT_UNREF (ft_font_list);
661       ft_font_list = NULL;
662     }
663   free (ft_to_prop);
664   FT_Done_FreeType (ft_library);
665 }
666
667
668 int
669 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
670                      MRealizedFont *rfont,
671                      MSymbol script, MSymbol langsys, 
672                      MSymbol gsub_features, MSymbol gpos_features)
673 {
674   int len = to - from;
675   MGlyph g;
676   int i;
677 #ifdef HAVE_OTF
678   MFTInfo *ft_info;
679   OTF *otf;
680   OTF_GlyphString otf_gstring;
681   OTF_Glyph *otfg;
682   char *script_name, *language_name;
683   char *gsub_feature_names, *gpos_feature_names;
684   int from_pos, to_pos;
685   int unitsPerEm;
686
687   if (len == 0)
688     return from;
689
690   ft_info = (MFTInfo *) rfont->info;
691   if (ft_info->otf_flag < 0)
692     goto simple_copy;
693   otf = ft_info->otf;
694   if (! otf && (otf = OTF_open (ft_info->filename)))
695     {
696       if (OTF_get_table (otf, "head") < 0
697           || (OTF_check_table (otf, "GSUB") < 0
698               && OTF_check_table (otf, "GPOS") < 0))
699         {
700           OTF_close (otf);
701           ft_info->otf_flag = -1;
702           ft_info->otf = NULL;
703           goto simple_copy;
704         }
705       ft_info->otf = otf;
706     }
707
708   script_name = msymbol_name (script);
709   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
710   gsub_feature_names
711     = (gsub_features == Mt ? "*"
712        : gsub_features == Mnil ? NULL
713        : msymbol_name (gsub_features));
714   gpos_feature_names
715     = (gpos_features == Mt ? "*"
716        : gpos_features == Mnil ? NULL
717        : msymbol_name (gpos_features));
718
719   g = gstring->glyphs[from];
720   from_pos = g.pos;
721   to_pos = g.to;
722   for (i = from + 1; i < to; i++)
723     {
724       if (from_pos > gstring->glyphs[i].pos)
725         from_pos = gstring->glyphs[i].pos;
726       if (to_pos < gstring->glyphs[i].to)
727         to_pos = gstring->glyphs[i].to;
728     }
729
730   unitsPerEm = otf->head->unitsPerEm;
731   otf_gstring.size = otf_gstring.used = len;
732   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
733   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
734   for (i = 0; i < len; i++)
735     {
736       if (gstring->glyphs[from + i].otf_encoded)
737         {
738           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
739           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
740         }
741       else
742         {
743           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
744         }
745     }
746       
747   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
748                         gsub_feature_names, gpos_feature_names) < 0)
749     goto simple_copy;
750   g.pos = from_pos;
751   g.to = to_pos;
752   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
753     {
754       g.combining_code = 0;
755       g.c = otfg->c;
756       if (otfg->glyph_id)
757         {
758           g.code = otfg->glyph_id;
759           switch (otfg->positioning_type)
760             {
761             case 1: case 2:
762               {
763                 int off_x = 128, off_y = 128;
764
765                 if (otfg->f.f1.format & OTF_XPlacement)
766                   off_x = ((double) (otfg->f.f1.value->XPlacement)
767                            * 100 / unitsPerEm + 128);
768                 if (otfg->f.f1.format & OTF_YPlacement)
769                   off_y = ((double) (otfg->f.f1.value->YPlacement)
770                            * 100 / unitsPerEm + 128);
771                 g.combining_code
772                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
773                 if ((otfg->f.f1.format & OTF_XAdvance)
774                     || (otfg->f.f1.format & OTF_YAdvance))
775                   off_y--;
776               }
777               break;
778             case 3:
779               /* Not yet supported.  */
780               break;
781             case 4:
782               {
783                 int off_x, off_y;
784
785                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
786                                    - otfg->f.f4.mark_anchor->XCoordinate)
787                          * 100 / unitsPerEm + 128);
788                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
789                                    - otfg->f.f4.mark_anchor->YCoordinate)
790                          * 100 / unitsPerEm + 128);
791                 g.combining_code
792                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
793               }
794               break;
795             case 5:
796               /* Not yet supported.  */
797               break;
798             default:            /* i.e case 6 */
799               /* Not yet supported.  */
800               break;
801             }
802           g.otf_encoded = 1;
803         }
804       else
805         {
806           g.code = otfg->c;
807           g.otf_encoded = 0;
808         }
809       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
810     }
811   return to;
812
813  simple_copy:
814 #endif  /* HAVE_OTF */
815   for (i = 0; i < len; i++)
816     {
817       g = gstring->glyphs[from + i];
818       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
819     }
820   return to;
821 }
822
823 int
824 mfont__ft_decode_otf (MGlyph *g)
825 {
826 #ifdef HAVE_OTF
827   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
828   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
829
830   return (c ? c : -1);
831 #else  /* not HAVE_OTF */
832   return -1;
833 #endif  /* not HAVE_OTF */
834 }
835
836 #else /* not HAVE_FREETYPE */
837
838 int
839 mfont__ft_init ()
840 {
841   return 0;
842 }
843
844 void
845 mfont__ft_fini ()
846 {
847 }
848
849 #endif /* HAVE_FREETYPE */