*** 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 *, 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   int i;
625
626   if (FT_Init_FreeType (&ft_library) != 0)
627     MERROR (MERROR_FONT_FT, -1);
628
629   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
630   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
631   for (i = 0; i < ft_to_prop_size; i++)
632     {
633       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
634       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
635       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
636       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
637     }
638
639   mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
640
641   return 0;
642 }
643
644 void
645 mfont__ft_fini ()
646 {
647   MPlist *plist;
648
649   if (ft_font_list)
650     {
651       MPLIST_DO (plist, ft_font_list)
652         {
653           MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (plist);
654           free (ft_info->filename);
655           M17N_OBJECT_UNREF (ft_info->charmap_list);
656           free (ft_info);
657         }
658       M17N_OBJECT_UNREF (ft_font_list);
659       ft_font_list = NULL;
660     }
661   free (ft_to_prop);
662   FT_Done_FreeType (ft_library);
663 }
664
665
666 int
667 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
668                      MRealizedFont *rfont,
669                      MSymbol script, MSymbol langsys, 
670                      MSymbol gsub_features, MSymbol gpos_features)
671 {
672   int len = to - from;
673   MGlyph g;
674   int i;
675 #ifdef HAVE_OTF
676   MFTInfo *ft_info;
677   OTF *otf;
678   OTF_GlyphString otf_gstring;
679   OTF_Glyph *otfg;
680   char *script_name, *language_name;
681   char *gsub_feature_names, *gpos_feature_names;
682   int from_pos, to_pos;
683   int unitsPerEm;
684
685   if (len == 0)
686     return from;
687
688   ft_info = (MFTInfo *) rfont->info;
689   if (ft_info->otf_flag < 0)
690     goto simple_copy;
691   otf = ft_info->otf;
692   if (! otf && (otf = OTF_open (ft_info->filename)))
693     {
694       if (OTF_get_table (otf, "head") < 0
695           || (OTF_check_table (otf, "GSUB") < 0
696               && OTF_check_table (otf, "GPOS") < 0))
697         {
698           OTF_close (otf);
699           ft_info->otf_flag = -1;
700           ft_info->otf = NULL;
701           goto simple_copy;
702         }
703       ft_info->otf = otf;
704     }
705
706   script_name = msymbol_name (script);
707   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
708   gsub_feature_names
709     = (gsub_features == Mt ? "*"
710        : gsub_features == Mnil ? NULL
711        : msymbol_name (gsub_features));
712   gpos_feature_names
713     = (gpos_features == Mt ? "*"
714        : gpos_features == Mnil ? NULL
715        : msymbol_name (gpos_features));
716
717   g = gstring->glyphs[from];
718   from_pos = g.pos;
719   to_pos = g.to;
720   for (i = from + 1; i < to; i++)
721     {
722       if (from_pos > gstring->glyphs[i].pos)
723         from_pos = gstring->glyphs[i].pos;
724       if (to_pos < gstring->glyphs[i].to)
725         to_pos = gstring->glyphs[i].to;
726     }
727
728   unitsPerEm = otf->head->unitsPerEm;
729   otf_gstring.size = otf_gstring.used = len;
730   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
731   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
732   for (i = 0; i < len; i++)
733     {
734       if (gstring->glyphs[from + i].otf_encoded)
735         {
736           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
737           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
738         }
739       else
740         {
741           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
742         }
743     }
744       
745   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
746                         gsub_feature_names, gpos_feature_names) < 0)
747     goto simple_copy;
748   g.pos = from_pos;
749   g.to = to_pos;
750   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
751     {
752       g.combining_code = 0;
753       g.c = otfg->c;
754       if (otfg->glyph_id)
755         {
756           g.code = otfg->glyph_id;
757           switch (otfg->positioning_type)
758             {
759             case 1: case 2:
760               {
761                 int off_x = 128, off_y = 128;
762
763                 if (otfg->f.f1.format & OTF_XPlacement)
764                   off_x = ((double) (otfg->f.f1.value->XPlacement)
765                            * 100 / unitsPerEm + 128);
766                 if (otfg->f.f1.format & OTF_YPlacement)
767                   off_y = ((double) (otfg->f.f1.value->YPlacement)
768                            * 100 / unitsPerEm + 128);
769                 g.combining_code
770                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
771                 if ((otfg->f.f1.format & OTF_XAdvance)
772                     || (otfg->f.f1.format & OTF_YAdvance))
773                   off_y--;
774               }
775               break;
776             case 3:
777               /* Not yet supported.  */
778               break;
779             case 4:
780               {
781                 int off_x, off_y;
782
783                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
784                                    - otfg->f.f4.mark_anchor->XCoordinate)
785                          * 100 / unitsPerEm + 128);
786                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
787                                    - otfg->f.f4.mark_anchor->YCoordinate)
788                          * 100 / unitsPerEm + 128);
789                 g.combining_code
790                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
791               }
792               break;
793             case 5:
794               /* Not yet supported.  */
795               break;
796             default:            /* i.e case 6 */
797               /* Not yet supported.  */
798               break;
799             }
800           g.otf_encoded = 1;
801         }
802       else
803         {
804           g.code = otfg->c;
805           g.otf_encoded = 0;
806         }
807       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
808     }
809   return to;
810
811  simple_copy:
812 #endif  /* HAVE_OTF */
813   for (i = 0; i < len; i++)
814     {
815       g = gstring->glyphs[from + i];
816       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
817     }
818   return to;
819 }
820
821 int
822 mfont__ft_decode_otf (MGlyph *g)
823 {
824 #ifdef HAVE_OTF
825   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
826   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
827
828   return (c ? c : -1);
829 #else  /* not HAVE_OTF */
830   return -1;
831 #endif  /* not HAVE_OTF */
832 }
833
834 #else /* not HAVE_FREETYPE */
835
836 int
837 mfont__ft_init ()
838 {
839   return 0;
840 }
841
842 void
843 mfont__ft_fini ()
844 {
845 }
846
847 #endif /* HAVE_FREETYPE */