35a63a193a1a2c79b5036a829e24fe7e23ef6ad9
[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
44 #ifdef HAVE_OTF
45 #include <otf.h>
46 #endif /* HAVE_OTF */
47
48 #ifdef HAVE_XFT2
49 /* Having Xft2 means having fontconfig.  */
50 #include <fontconfig/fontconfig.h>
51
52 int fontconfig_initialized = 0;
53 FcConfig *fc_config;
54 #endif  /* not HAVE_XFT2 */
55
56 static FT_Library ft_library;
57
58 typedef struct
59 {
60   MSymbol ft_style;
61   MSymbol weight, style, stretch;
62 } MFTtoProp;
63
64 static int ft_to_prop_size;
65 static MFTtoProp *ft_to_prop;
66
67 typedef struct
68 {
69   M17NObject control;
70   MFont font;
71   char *filename;
72   int otf_flag; /* This font 1: is OTF, 0: may be OTF, -1: is not OTF.  */
73   MPlist *charmap_list;
74   int charmap_index;
75   FT_Face ft_face;
76 #ifdef HAVE_OTF
77   OTF *otf;
78 #endif /* HAVE_OTF */
79 #ifdef HAVE_XFT2
80   void *xft_info;
81 #endif  /* not HAVE_XFT2 */
82 } MFTInfo;
83
84 /* List of FreeType fonts.  Keys are family names, values are plists
85    contains fonts of the corresponding family.  In the deeper plist,
86    keys are Mt, values are (MFTInfo *).  */
87 static MPlist *ft_font_list;
88
89 /** Return 0 if NAME implies TrueType or OpenType fonts.  Othersize
90     return -1.  */
91
92 static int
93 check_otf_filename (const char *name)
94 {
95   int len = strlen (name);
96   const char *ext = name + (len - 4);
97
98   if (len < 5
99       || (memcmp (ext, ".ttf", 4)
100           && memcmp (ext, ".TTF", 4)
101           && memcmp (ext, ".otf", 4)
102           && memcmp (ext, ".OTF", 4)))
103     return -1;
104   return 0;
105 }
106
107 /** Setup members of FT_INFO from FT_FACE.  Return the family name.  */
108
109 static MSymbol
110 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family)
111 {
112   MFont *font = &ft_info->font;
113   MSymbol style;
114   int len;
115   char *buf, *p;
116   MPlist *charmap_list;
117   int unicode_bmp = -1, unicode_full = -1;
118   int i;
119
120   MFONT_INIT (font);
121
122   if (family == Mt)
123     {
124       len = strlen (ft_face->family_name) + 1;
125       buf = (char *) alloca (len);
126       memcpy (buf, ft_face->family_name, len);
127       for (p = buf; *p; p++)
128         if (*p >= 'A' && *p <= 'Z')
129           *p += 'a' - 'A';
130       family = msymbol (buf);
131     }
132   mfont__set_property (font, MFONT_FAMILY, family);
133
134   if (ft_face->style_name)
135     {
136       len = strlen (ft_face->style_name) + 1;
137       buf = (char *) alloca (len);
138       memcpy (buf, ft_face->style_name, len);
139       for (p = buf; *p; p++)
140         if (*p >= 'A' && *p <= 'Z')
141           *p += 'a' - 'A';
142       style = msymbol (buf);
143       for (i = 0; i < ft_to_prop_size; i++)
144         if (ft_to_prop[i].ft_style == style)
145           {
146             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
147             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
148             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
149             break;
150           }
151     }
152   else
153     i = ft_to_prop_size;
154
155   if (i == ft_to_prop_size)
156     {
157       mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
158       mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
159       mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
160     }
161
162   font->property[MFONT_TYPE] = MFONT_TYPE_FT + 1;
163   mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
164
165   charmap_list = mplist ();
166   mplist_add (charmap_list, Mt, (void *) -1);
167   for (i = 0; i < ft_face->num_charmaps; i++)
168     {
169       char registry_buf[16];
170
171       sprintf (registry_buf, "%d-%d",
172                ft_face->charmaps[i]->platform_id,
173                ft_face->charmaps[i]->encoding_id);
174       mplist_add (charmap_list, msymbol (registry_buf), (void *) i);
175       if (ft_face->charmaps[i]->platform_id == 0)
176         {
177           if (ft_face->charmaps[i]->encoding_id == 3)
178             unicode_bmp = i;
179           else if (ft_face->charmaps[i]->encoding_id == 4)
180             unicode_full = i;
181         }
182       else if (ft_face->charmaps[i]->platform_id == 3)
183         {
184           if (ft_face->charmaps[i]->encoding_id == 1)
185             unicode_bmp = i;
186           else if (ft_face->charmaps[i]->encoding_id == 10)
187             unicode_full = i;
188         }
189       else if (ft_face->charmaps[i]->platform_id == 1
190                && ft_face->charmaps[i]->encoding_id == 0)
191         mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
192     }
193   if (unicode_bmp >= 0)
194     mplist_add (charmap_list, msymbol ("unicode-bmp"), (void *) unicode_bmp);
195   if (unicode_full >= 0)
196     mplist_add (charmap_list, msymbol ("unicode-full"), (void *) unicode_full);
197
198   ft_info->charmap_list = charmap_list;
199
200   return family;
201 }
202
203
204 static void
205 add_font_list (MPlist *font_list)
206 {
207   MPlist *plist;
208
209   MPLIST_DO (plist, font_list)
210     {
211       char *filename = MPLIST_VAL (plist);
212       FT_Face ft_face;
213
214       if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
215         {
216           if (ft_face->family_name && ((char *) ft_face->family_name)[0])
217             {
218               MSymbol family = MPLIST_KEY (plist);
219               MFTInfo *ft_info;
220               MPlist *p;
221
222               MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
223               ft_info->filename = filename;
224               ft_info->otf_flag = check_otf_filename (filename);
225               family = set_font_info (ft_face, ft_info, family);
226               p = mplist_get (ft_font_list, family);
227               if (! p)
228                 {
229                   p = mplist ();
230                   mplist_add (ft_font_list, family, p);
231                 }
232               mplist_add (p, family, ft_info);
233             }
234           FT_Done_Face (ft_face);
235         }
236       else
237         free (filename);
238     }
239   M17N_OBJECT_UNREF (font_list);
240 }
241
242 #ifdef HAVE_XFT2
243 static MPlist *
244 xft_list (MSymbol family)
245 {
246   FcPattern *pattern;
247   FcObjectSet *os;
248   FcFontSet *fs;
249   MPlist *plist;
250   int i;
251
252   if (! fc_config)
253     {
254       char *pathname;
255       struct stat buf;
256
257       FcInit ();
258       fc_config = FcConfigGetCurrent ();
259       MPLIST_DO (plist, mfont_freetype_path)
260         if (MPLIST_STRING_P (plist)
261             && (pathname = MPLIST_STRING (plist))
262             && stat (pathname, &buf) == 0)
263           FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
264     }
265
266   pattern = FcPatternCreate ();
267   FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) (msymbol_name (family)));
268   os = FcObjectSetBuild (FC_FILE, NULL);
269   fs = FcFontList (fc_config, pattern, os);
270   plist = mplist ();
271   if (fs)
272     {
273       for (i = 0; i < fs->nfont; i++)
274         {
275           FcChar8 *filename;
276
277           FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename);
278           mplist_add (plist, family, strdup ((char *) filename));
279         }
280       FcFontSetDestroy (fs);
281     }
282   FcObjectSetDestroy (os);
283   FcPatternDestroy (pattern);
284   return plist;
285 }
286
287 #else  /* not HAVE_XFT2 */
288 static MPlist *
289 ft_list ()
290 {
291   MPlist *font_list = mplist (), *plist;
292   struct stat buf;
293   char *pathname;
294
295   MPLIST_DO (plist, mfont_freetype_path)
296     if (MPLIST_STRING_P (plist)
297         && (pathname = MPLIST_STRING (plist))
298         && stat (pathname, &buf) == 0)
299       {
300         if (S_ISREG (buf.st_mode))
301           mplist_add (font_list, Mt, strdup (pathname));
302         else if (S_ISDIR (buf.st_mode))
303           {
304             int len = strlen (pathname);
305             char path[PATH_MAX];
306             DIR *dir = opendir (pathname);
307             struct dirent *dp;
308             int result;
309
310             if (dir)
311               {
312                 strcpy (path, pathname);
313                 strcpy (path + len, "/");
314                 len++;
315                 while ((dp = readdir (dir)) != NULL)
316                   {
317                     strcpy (path + len, dp->d_name);
318                     mplist_add (font_list, Mt, strdup (path));
319                   }
320                 closedir (dir);
321               }
322           }
323       }
324   return font_list;
325 }
326
327 #endif
328
329 static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int);
330 static int ft_open (MRealizedFont *);
331 static void ft_close (MRealizedFont *);
332 static void ft_find_metric (MRealizedFont *, MGlyphString *, int, int);
333 static unsigned ft_encode_char (MRealizedFont *, int, unsigned);
334 static void ft_render (MDrawWindow, int, int, MGlyphString *,
335                        MGlyph *, MGlyph *, int, MDrawRegion);
336
337 MFontDriver ft_driver =
338   { ft_select, ft_open, ft_close,
339     ft_find_metric, ft_encode_char, ft_render };
340
341 /* The FreeType font driver function LIST.  */
342
343 static MRealizedFont *
344 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
345 {
346   MPlist *plist;
347   MFTInfo *best_font;
348   int best_score;
349   MRealizedFont *rfont;
350   MSymbol family, registry;
351
352   best_font = NULL;
353   best_score = 0;
354   family = FONT_PROPERTY (spec, MFONT_FAMILY);
355   if (family == Mnil)
356     family = FONT_PROPERTY (request, MFONT_FAMILY);
357   if (family == Mnil)
358     return NULL;
359   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
360   if (registry == Mnil)
361     registry = Mt;
362
363 #ifdef HAVE_XFT2
364   if (! ft_font_list)
365     ft_font_list = mplist ();
366   plist = mplist_get (ft_font_list, family);
367   if (! plist)
368     {
369       add_font_list (xft_list (family));
370       plist = mplist_get (ft_font_list, family);
371       if (! plist)
372         mplist_add (ft_font_list, family, plist = mplist ());
373     }
374 #else  /* not HAVE_XFT2 */
375   if (! ft_font_list)
376     {
377       ft_font_list = mplist ();
378       add_font_list (ft_list ());
379     }
380   plist = mplist_get (ft_font_list, family);
381   if (! plist)
382     return NULL;
383 #endif  /* not HAVE_XFT2 */
384
385   MPLIST_DO (plist, plist)
386     {
387       MFTInfo *ft_info = MPLIST_VAL (plist);
388       MPlist *p = mplist_find_by_key (ft_info->charmap_list, registry);
389       int score;
390
391       if (! p)
392         continue;
393       /* We always ignore FOUNDRY.  */
394       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
395       score = mfont__score (&ft_info->font, spec, request, limited_size);
396       if (score >= 0
397           && (! best_font
398               || best_score > score))
399         {
400           best_font = ft_info;
401           best_score = score;
402           if (score == 0)
403             break;
404         }
405     }
406   if (! best_font)
407     return NULL;
408
409   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
410   rfont->frame = frame;
411   rfont->spec = *spec;
412   rfont->request = *request;
413   rfont->font = best_font->font;
414   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
415   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
416   rfont->score = best_score;
417   rfont->info = best_font;
418   rfont->driver = &ft_driver;
419   return rfont;
420 }
421
422 static void
423 close_ft (void *object)
424 {
425   MFTInfo *ft_info = (MFTInfo *) object;
426
427   if (ft_info->ft_face)
428     FT_Done_Face (ft_info->ft_face);
429 #ifdef HAVE_XFT2
430   if (ft_info->xft_info)
431     mwin__xft_close (ft_info->xft_info);
432 #endif  /* HAVE_XFT2 */
433 #ifdef HAVE_OTF
434   if (ft_info->otf)
435     OTF_close (ft_info->otf);
436 #endif /* HAVE_OTF */
437   free (object);
438 }
439
440 /* The FreeType font driver function OPEN.  */
441
442 static int
443 ft_open (MRealizedFont *rfont)
444 {
445   MFTInfo *ft_info;
446   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
447   int mdebug_mask = MDEBUG_FONT;
448   int size;
449
450   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
451   ft_info->font = ((MFTInfo *) rfont->info)->font;
452   ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag;
453   ft_info->filename = ((MFTInfo *) rfont->info)->filename;
454   ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list;
455   rfont->info = ft_info;
456
457   rfont->status = -1;
458   ft_info->ft_face = NULL;
459   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
460     goto err;
461   if (registry == Mnil)
462     registry = Mt;
463   ft_info->charmap_index
464     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
465   if (ft_info->charmap_index >= 0
466       && FT_Set_Charmap (ft_info->ft_face, 
467                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
468     goto err;
469   size = rfont->font.property[MFONT_SIZE] / 10;
470 #ifdef HAVE_XFT2
471   ft_info->xft_info = mwin__xft_open (rfont->frame, ft_info->filename, size);
472   if (! ft_info->xft_info)
473     goto err;
474 #else  /* not HAVE_XFT2 */
475   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
476     goto err;
477 #endif  /* not HAVE_XFT2 */
478
479   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
480   rfont->status = 1;
481   rfont->ascent = ft_info->ft_face->ascender >> 6;
482   rfont->descent = ft_info->ft_face->descender >> 6;
483   return 0;
484
485  err:
486   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
487   return -1;
488 }
489
490 /* The FreeType font driver function CLOSE.  */
491
492 static void
493 ft_close (MRealizedFont *rfont)
494 {
495   M17N_OBJECT_UNREF (rfont->info);
496 }
497
498 /* The FreeType font driver function FIND_METRIC.  */
499
500 static void
501 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
502                 int from, int to)
503 {
504   MFTInfo *ft_info = (MFTInfo *) rfont->info;
505   FT_Face ft_face = ft_info->ft_face;
506   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
507   FT_Int32 load_flags = FT_LOAD_RENDER;
508
509   if (! gstring->anti_alias)
510     {
511 #ifdef FT_LOAD_TARGET_MONO
512       load_flags |= FT_LOAD_TARGET_MONO;
513 #else
514       load_flags |= FT_LOAD_MONOCHROME;
515 #endif
516     }
517
518   for (; g != gend; g++)
519     {
520       if (g->code == MCHAR_INVALID_CODE)
521         {
522           unsigned unitsPerEm = ft_face->units_per_EM;
523           int size = rfont->font.property[MFONT_SIZE] / 10;
524
525           g->lbearing = 0;
526           g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
527           g->width = ft_face->max_advance_width * size / unitsPerEm;
528           g->ascent = ft_face->ascender * size / unitsPerEm;
529           g->descent = (- ft_face->descender) * size / unitsPerEm;
530         }
531       else
532         {
533 #ifdef HAVE_XFT2
534           mwin__xft_get_metric (ft_info->xft_info, ft_info->ft_face, g);
535 #else  /* not HAVE_XFT2 */
536           FT_Glyph_Metrics *metrics;
537           FT_UInt code;
538
539           if (g->otf_encoded)
540             code = g->code;
541           else
542             code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
543
544           FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
545           metrics = &ft_face->glyph->metrics;
546           g->lbearing = (metrics->horiBearingX >> 6);
547           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
548           g->width = metrics->horiAdvance >> 6;
549           g->ascent = metrics->horiBearingY >> 6;
550           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
551 #endif  /* not HAVE_XFT2 */
552         }
553     }
554 }
555
556 /* The FreeType font driver function ENCODE_CHAR.  */
557
558 static unsigned
559 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
560 {
561   MFTInfo *ft_info;
562   FT_UInt code;
563
564   if (rfont->status == 0)
565     {
566       if (ft_open (rfont) < 0)
567         return -1;
568     }
569   ft_info = (MFTInfo *) rfont->info;
570   code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
571   if (! code)
572     return MCHAR_INVALID_CODE;
573   return ((unsigned) c);
574
575 }
576
577 /* The FreeType font driver function RENDER.  */
578
579 #define NUM_POINTS 0x1000
580
581 typedef struct {
582   MDrawPoint points[NUM_POINTS];
583   MDrawPoint *p;
584 } MPointTable;
585
586 static void
587 ft_render (MDrawWindow win, int x, int y,
588            MGlyphString *gstring, MGlyph *from, MGlyph *to,
589            int reverse, MDrawRegion region)
590 {
591   MFTInfo *ft_info;
592   FT_Face ft_face;
593   MRealizedFace *rface = from->rface;
594 #ifndef HAVE_XFT2
595   MFrame *frame = rface->frame;
596   FT_Int32 load_flags = FT_LOAD_RENDER;
597   MGlyph *g;
598   int i, j;
599   MPointTable point_table[8];
600 #endif  /* not HAVE_XFT2 */
601
602   if (from == to)
603     return;
604
605   /* It is assured that the all glyphs in the current range use the
606      same realized face.  */
607   ft_info = (MFTInfo *) rface->rfont->info;
608   ft_face = ft_info->ft_face;
609
610 #ifdef HAVE_XFT2
611   mwin__xft_render (win, x, y, gstring, from, to, reverse, region,
612                     ft_info->xft_info, ft_face);
613 #else  /* not HAVE_XFT2 */
614   if (! gstring->anti_alias)
615     {
616 #ifdef FT_LOAD_TARGET_MONO
617       load_flags |= FT_LOAD_TARGET_MONO;
618 #else
619       load_flags |= FT_LOAD_MONOCHROME;
620 #endif
621     }
622
623   for (i = 0; i < 8; i++)
624     point_table[i].p = point_table[i].points;
625
626   for (g = from; g < to; x += g++->width)
627     {
628       FT_UInt code;
629       unsigned char *bmp;
630       int intensity;
631       MPointTable *ptable;
632       int xoff, yoff;
633
634       if (g->otf_encoded)
635         code = g->code;
636       else
637         code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
638       FT_Load_Glyph (ft_face, code, load_flags);
639       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
640       bmp = ft_face->glyph->bitmap.buffer;
641       if (gstring->anti_alias)
642         for (i = 0; i < ft_face->glyph->bitmap.rows;
643              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
644           {
645             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
646             for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
647               {
648                 intensity = bmp[j] >> 5;
649                 if (intensity)
650                   {
651                     ptable = point_table + intensity;
652                     ptable->p->x = xoff;
653                     ptable->p->y = yoff;
654                     ptable->p++;
655                     if (ptable->p - ptable->points == NUM_POINTS)
656                       {
657                         mwin__draw_points (frame, win, rface,
658                                            reverse ? 7 - intensity : intensity,
659                                            ptable->points, NUM_POINTS, region);
660                         ptable->p = ptable->points;
661                       }
662                   }
663               }
664           }
665       else
666         for (i = 0; i < ft_face->glyph->bitmap.rows;
667              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
668           {
669             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
670             for (j = 0; j < ft_face->glyph->bitmap.width; j++, xoff++)
671               {
672                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
673                 if (intensity)
674                   {
675                     ptable = point_table;
676                     ptable->p->x = xoff;
677                     ptable->p->y = yoff;
678                     ptable->p++;
679                     if (ptable->p - ptable->points == NUM_POINTS)
680                       {
681                         mwin__draw_points (frame, win, rface,
682                                            reverse ? 0 : 7,
683                                            ptable->points, NUM_POINTS, region);
684                         ptable->p = ptable->points;
685                       }             
686                   }
687               }
688         }
689     }
690
691   if (gstring->anti_alias)
692     {
693       for (i = 1; i < 8; i++)
694         if (point_table[i].p != point_table[i].points)
695           mwin__draw_points (frame, win, rface, reverse ? 7 - i : i,
696                              point_table[i].points,
697                              point_table[i].p - point_table[i].points, region);
698     }
699   else
700     {
701       if (point_table[0].p != point_table[0].points)
702         mwin__draw_points (frame, win, rface, reverse ? 0 : 7,
703                            point_table[0].points,
704                            point_table[0].p - point_table[0].points, region);
705     }
706 #endif  /* not HAVE_XFT2 */
707 }
708
709 \f
710
711 int
712 mfont__ft_init ()
713 {
714   struct {
715     char *ft_style;
716     char *weight, *style, *stretch;
717   } ft_to_prop_name[] =
718     { { "regular", "medium", "r", "normal" },
719       { "italic", "medium", "i", "normal" },
720       { "bold", "bold", "r", "normal" },
721       { "bold italic", "bold", "i", "normal" },
722       { "narrow", "medium", "r", "condensed" },
723       { "narrow italic", "medium", "i", "condensed" },
724       { "narrow bold", "bold", "r", "condensed" },
725       { "narrow bold italic", "bold", "i", "condensed" },
726       { "black", "black", "r", "normal" },
727       { "black italic", "black", "i", "normal" },
728       { "oblique", "medium", "o", "normal" },
729       { "boldoblique", "bold", "o", "normal" } };
730   int i;
731
732   if (FT_Init_FreeType (&ft_library) != 0)
733     MERROR (MERROR_FONT_FT, -1);
734
735   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
736   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
737   for (i = 0; i < ft_to_prop_size; i++)
738     {
739       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
740       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
741       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
742       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
743     }
744
745   mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
746
747   return 0;
748 }
749
750 void
751 mfont__ft_fini ()
752 {
753   MPlist *plist, *p;
754
755   if (ft_font_list)
756     {
757       MPLIST_DO (plist, ft_font_list)
758         {
759           MPLIST_DO (p, MPLIST_VAL (plist))
760             {
761               MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (p);
762               free (ft_info->filename);
763               M17N_OBJECT_UNREF (ft_info->charmap_list);
764               free (ft_info);
765             }
766           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
767         }
768       M17N_OBJECT_UNREF (ft_font_list);
769       ft_font_list = NULL;
770     }
771   free (ft_to_prop);
772   FT_Done_FreeType (ft_library);
773 }
774
775
776 int
777 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
778                      MRealizedFont *rfont,
779                      MSymbol script, MSymbol langsys, 
780                      MSymbol gsub_features, MSymbol gpos_features)
781 {
782   int len = to - from;
783   MGlyph g;
784   int i;
785 #ifdef HAVE_OTF
786   MFTInfo *ft_info;
787   OTF *otf;
788   OTF_GlyphString otf_gstring;
789   OTF_Glyph *otfg;
790   char *script_name, *language_name;
791   char *gsub_feature_names, *gpos_feature_names;
792   int from_pos, to_pos;
793   int unitsPerEm;
794
795   if (len == 0)
796     return from;
797
798   ft_info = (MFTInfo *) rfont->info;
799   if (ft_info->otf_flag < 0)
800     goto simple_copy;
801   otf = ft_info->otf;
802   if (! otf && (otf = OTF_open (ft_info->filename)))
803     {
804       if (OTF_get_table (otf, "head") < 0
805           || (OTF_check_table (otf, "GSUB") < 0
806               && OTF_check_table (otf, "GPOS") < 0))
807         {
808           OTF_close (otf);
809           ft_info->otf_flag = -1;
810           ft_info->otf = NULL;
811           goto simple_copy;
812         }
813       ft_info->otf = otf;
814     }
815
816   script_name = msymbol_name (script);
817   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
818   gsub_feature_names
819     = (gsub_features == Mt ? "*"
820        : gsub_features == Mnil ? NULL
821        : msymbol_name (gsub_features));
822   gpos_feature_names
823     = (gpos_features == Mt ? "*"
824        : gpos_features == Mnil ? NULL
825        : msymbol_name (gpos_features));
826
827   g = gstring->glyphs[from];
828   from_pos = g.pos;
829   to_pos = g.to;
830   for (i = from + 1; i < to; i++)
831     {
832       if (from_pos > gstring->glyphs[i].pos)
833         from_pos = gstring->glyphs[i].pos;
834       if (to_pos < gstring->glyphs[i].to)
835         to_pos = gstring->glyphs[i].to;
836     }
837
838   unitsPerEm = otf->head->unitsPerEm;
839   otf_gstring.size = otf_gstring.used = len;
840   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
841   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
842   for (i = 0; i < len; i++)
843     {
844       if (gstring->glyphs[from + i].otf_encoded)
845         {
846           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
847           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
848         }
849       else
850         {
851           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
852         }
853     }
854       
855   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
856                         gsub_feature_names, gpos_feature_names) < 0)
857     goto simple_copy;
858   g.pos = from_pos;
859   g.to = to_pos;
860   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
861     {
862       g.combining_code = 0;
863       g.c = otfg->c;
864       if (otfg->glyph_id)
865         {
866           g.code = otfg->glyph_id;
867           switch (otfg->positioning_type)
868             {
869             case 1: case 2:
870               {
871                 int off_x = 128, off_y = 128;
872
873                 if (otfg->f.f1.format & OTF_XPlacement)
874                   off_x = ((double) (otfg->f.f1.value->XPlacement)
875                            * 100 / unitsPerEm + 128);
876                 if (otfg->f.f1.format & OTF_YPlacement)
877                   off_y = ((double) (otfg->f.f1.value->YPlacement)
878                            * 100 / unitsPerEm + 128);
879                 g.combining_code
880                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
881                 if ((otfg->f.f1.format & OTF_XAdvance)
882                     || (otfg->f.f1.format & OTF_YAdvance))
883                   off_y--;
884               }
885               break;
886             case 3:
887               /* Not yet supported.  */
888               break;
889             case 4:
890               {
891                 int off_x, off_y;
892
893                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
894                                    - otfg->f.f4.mark_anchor->XCoordinate)
895                          * 100 / unitsPerEm + 128);
896                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
897                                    - otfg->f.f4.mark_anchor->YCoordinate)
898                          * 100 / unitsPerEm + 128);
899                 g.combining_code
900                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
901               }
902               break;
903             case 5:
904               /* Not yet supported.  */
905               break;
906             default:            /* i.e case 6 */
907               /* Not yet supported.  */
908               break;
909             }
910           g.otf_encoded = 1;
911         }
912       else
913         {
914           g.code = otfg->c;
915           g.otf_encoded = 0;
916         }
917       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
918     }
919   return to;
920
921  simple_copy:
922 #endif  /* HAVE_OTF */
923   for (i = 0; i < len; i++)
924     {
925       g = gstring->glyphs[from + i];
926       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
927     }
928   return to;
929 }
930
931 int
932 mfont__ft_decode_otf (MGlyph *g)
933 {
934 #ifdef HAVE_OTF
935   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
936   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
937
938   return (c ? c : -1);
939 #else  /* not HAVE_OTF */
940   return -1;
941 #endif  /* not HAVE_OTF */
942 }
943
944 #else /* not HAVE_FREETYPE */
945
946 int
947 mfont__ft_init ()
948 {
949   return 0;
950 }
951
952 void
953 mfont__ft_fini ()
954 {
955 }
956
957 #endif /* HAVE_FREETYPE */