b1e092bf54c531a96028acdc37ba1eeb95e9d78e
[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
309             if (dir)
310               {
311                 strcpy (path, pathname);
312                 strcpy (path + len, "/");
313                 len++;
314                 while ((dp = readdir (dir)) != NULL)
315                   {
316                     strcpy (path + len, dp->d_name);
317                     mplist_add (font_list, Mt, strdup (path));
318                   }
319                 closedir (dir);
320               }
321           }
322       }
323   return font_list;
324 }
325
326 #endif
327
328 static MRealizedFont *ft_select (MFrame *, MFont *, MFont *, int);
329 static int ft_open (MRealizedFont *);
330 static void ft_close (MRealizedFont *);
331 static void ft_find_metric (MRealizedFont *, MGlyphString *, int, int);
332 static unsigned ft_encode_char (MRealizedFont *, int, unsigned);
333 static void ft_render (MDrawWindow, int, int, MGlyphString *,
334                        MGlyph *, MGlyph *, int, MDrawRegion);
335
336 MFontDriver ft_driver =
337   { ft_select, ft_open, ft_close,
338     ft_find_metric, ft_encode_char, ft_render };
339
340 /* The FreeType font driver function LIST.  */
341
342 static MRealizedFont *
343 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
344 {
345   MPlist *plist;
346   MFTInfo *best_font;
347   int best_score;
348   MRealizedFont *rfont;
349   MSymbol family, registry;
350
351   best_font = NULL;
352   best_score = 0;
353   family = FONT_PROPERTY (spec, MFONT_FAMILY);
354   if (family == Mnil)
355     family = FONT_PROPERTY (request, MFONT_FAMILY);
356   if (family == Mnil)
357     return NULL;
358   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
359   if (registry == Mnil)
360     registry = Mt;
361
362 #ifdef HAVE_XFT2
363   if (! ft_font_list)
364     ft_font_list = mplist ();
365   plist = mplist_get (ft_font_list, family);
366   if (! plist)
367     {
368       add_font_list (xft_list (family));
369       plist = mplist_get (ft_font_list, family);
370       if (! plist)
371         mplist_add (ft_font_list, family, plist = mplist ());
372     }
373 #else  /* not HAVE_XFT2 */
374   if (! ft_font_list)
375     {
376       ft_font_list = mplist ();
377       add_font_list (ft_list ());
378     }
379   plist = mplist_get (ft_font_list, family);
380   if (! plist)
381     return NULL;
382 #endif  /* not HAVE_XFT2 */
383
384   MPLIST_DO (plist, plist)
385     {
386       MFTInfo *ft_info = MPLIST_VAL (plist);
387       MPlist *p = mplist_find_by_key (ft_info->charmap_list, registry);
388       int score;
389
390       if (! p)
391         continue;
392       /* We always ignore FOUNDRY.  */
393       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
394       score = mfont__score (&ft_info->font, spec, request, limited_size);
395       if (score >= 0
396           && (! best_font
397               || best_score > score))
398         {
399           best_font = ft_info;
400           best_score = score;
401           if (score == 0)
402             break;
403         }
404     }
405   if (! best_font)
406     return NULL;
407
408   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
409   rfont->frame = frame;
410   rfont->spec = *spec;
411   rfont->request = *request;
412   rfont->font = best_font->font;
413   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
414   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
415   rfont->score = best_score;
416   rfont->info = best_font;
417   rfont->driver = &ft_driver;
418   return rfont;
419 }
420
421 static void
422 close_ft (void *object)
423 {
424   MFTInfo *ft_info = (MFTInfo *) object;
425
426   if (ft_info->ft_face)
427     FT_Done_Face (ft_info->ft_face);
428 #ifdef HAVE_XFT2
429   if (ft_info->xft_info)
430     mwin__xft_close (ft_info->xft_info);
431 #endif  /* HAVE_XFT2 */
432 #ifdef HAVE_OTF
433   if (ft_info->otf)
434     OTF_close (ft_info->otf);
435 #endif /* HAVE_OTF */
436   free (object);
437 }
438
439 /* The FreeType font driver function OPEN.  */
440
441 static int
442 ft_open (MRealizedFont *rfont)
443 {
444   MFTInfo *ft_info;
445   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
446   int mdebug_mask = MDEBUG_FONT;
447   int size;
448
449   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
450   ft_info->font = ((MFTInfo *) rfont->info)->font;
451   ft_info->otf_flag = ((MFTInfo *) rfont->info)->otf_flag;
452   ft_info->filename = ((MFTInfo *) rfont->info)->filename;
453   ft_info->charmap_list = ((MFTInfo *) rfont->info)->charmap_list;
454   rfont->info = ft_info;
455
456   rfont->status = -1;
457   ft_info->ft_face = NULL;
458   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
459     goto err;
460   if (registry == Mnil)
461     registry = Mt;
462   ft_info->charmap_index
463     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
464   if (ft_info->charmap_index >= 0
465       && FT_Set_Charmap (ft_info->ft_face, 
466                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
467     goto err;
468   size = rfont->font.property[MFONT_SIZE] / 10;
469 #ifdef HAVE_XFT2
470   ft_info->xft_info = mwin__xft_open (rfont->frame, ft_info->filename, size);
471   if (! ft_info->xft_info)
472     goto err;
473 #else  /* not HAVE_XFT2 */
474   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
475     goto err;
476 #endif  /* not HAVE_XFT2 */
477
478   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
479   rfont->status = 1;
480   rfont->ascent = ft_info->ft_face->ascender >> 6;
481   rfont->descent = ft_info->ft_face->descender >> 6;
482   return 0;
483
484  err:
485   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
486   return -1;
487 }
488
489 /* The FreeType font driver function CLOSE.  */
490
491 static void
492 ft_close (MRealizedFont *rfont)
493 {
494   M17N_OBJECT_UNREF (rfont->info);
495 }
496
497 /* The FreeType font driver function FIND_METRIC.  */
498
499 static void
500 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
501                 int from, int to)
502 {
503   MFTInfo *ft_info = (MFTInfo *) rfont->info;
504   FT_Face ft_face = ft_info->ft_face;
505   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
506   FT_Int32 load_flags = FT_LOAD_RENDER;
507
508   if (! gstring->anti_alias)
509     {
510 #ifdef FT_LOAD_TARGET_MONO
511       load_flags |= FT_LOAD_TARGET_MONO;
512 #else
513       load_flags |= FT_LOAD_MONOCHROME;
514 #endif
515     }
516
517   for (; g != gend; g++)
518     {
519       if (g->code == MCHAR_INVALID_CODE)
520         {
521           unsigned unitsPerEm = ft_face->units_per_EM;
522           int size = rfont->font.property[MFONT_SIZE] / 10;
523
524           g->lbearing = 0;
525           g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
526           g->width = ft_face->max_advance_width * size / unitsPerEm;
527           g->ascent = ft_face->ascender * size / unitsPerEm;
528           g->descent = (- ft_face->descender) * size / unitsPerEm;
529         }
530       else
531         {
532 #ifdef HAVE_XFT2
533           mwin__xft_get_metric (ft_info->xft_info, ft_info->ft_face, g);
534 #else  /* not HAVE_XFT2 */
535           FT_Glyph_Metrics *metrics;
536           FT_UInt code;
537
538           if (g->otf_encoded)
539             code = g->code;
540           else
541             code = FT_Get_Char_Index (ft_face, (FT_ULong) g->code);
542
543           FT_Load_Glyph (ft_face, code, FT_LOAD_RENDER);
544           metrics = &ft_face->glyph->metrics;
545           g->lbearing = (metrics->horiBearingX >> 6);
546           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
547           g->width = metrics->horiAdvance >> 6;
548           g->ascent = metrics->horiBearingY >> 6;
549           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
550 #endif  /* not HAVE_XFT2 */
551         }
552     }
553 }
554
555 /* The FreeType font driver function ENCODE_CHAR.  */
556
557 static unsigned
558 ft_encode_char (MRealizedFont *rfont, int c, unsigned ignored)
559 {
560   MFTInfo *ft_info;
561   FT_UInt code;
562
563   if (rfont->status == 0)
564     {
565       if (ft_open (rfont) < 0)
566         return -1;
567     }
568   ft_info = (MFTInfo *) rfont->info;
569   code = FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) c);
570   if (! code)
571     return MCHAR_INVALID_CODE;
572   return ((unsigned) c);
573
574 }
575
576 /* The FreeType font driver function RENDER.  */
577
578 #define NUM_POINTS 0x1000
579
580 typedef struct {
581   MDrawPoint points[NUM_POINTS];
582   MDrawPoint *p;
583 } MPointTable;
584
585 static void
586 ft_render (MDrawWindow win, int x, int y,
587            MGlyphString *gstring, MGlyph *from, MGlyph *to,
588            int reverse, MDrawRegion region)
589 {
590   MFTInfo *ft_info;
591   FT_Face ft_face;
592   MRealizedFace *rface = from->rface;
593 #ifndef HAVE_XFT2
594   MFrame *frame = rface->frame;
595   FT_Int32 load_flags = FT_LOAD_RENDER;
596   MGlyph *g;
597   int i, j;
598   MPointTable point_table[8];
599 #endif  /* not HAVE_XFT2 */
600
601   if (from == to)
602     return;
603
604   /* It is assured that the all glyphs in the current range use the
605      same realized face.  */
606   ft_info = (MFTInfo *) rface->rfont->info;
607   ft_face = ft_info->ft_face;
608
609 #ifdef HAVE_XFT2
610   mwin__xft_render (win, x, y, gstring, from, to, reverse, region,
611                     ft_info->xft_info, ft_face);
612 #else  /* not HAVE_XFT2 */
613   if (! gstring->anti_alias)
614     {
615 #ifdef FT_LOAD_TARGET_MONO
616       load_flags |= FT_LOAD_TARGET_MONO;
617 #else
618       load_flags |= FT_LOAD_MONOCHROME;
619 #endif
620     }
621
622   for (i = 0; i < 8; i++)
623     point_table[i].p = point_table[i].points;
624
625   for (g = from; g < to; x += g++->width)
626     {
627       FT_UInt code;
628       unsigned char *bmp;
629       int intensity;
630       MPointTable *ptable;
631       int xoff, yoff;
632       int width;
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       width = ft_face->glyph->bitmap.width;
642       if (ft_face->glyph->bitmap.pitch < ft_face->glyph->bitmap.width)
643         width = ft_face->glyph->bitmap.pitch;
644
645       if (gstring->anti_alias)
646         for (i = 0; i < ft_face->glyph->bitmap.rows;
647              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
648           {
649             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
650             for (j = 0; j < width; j++, xoff++)
651               {
652                 intensity = bmp[j] >> 5;
653                 if (intensity)
654                   {
655                     ptable = point_table + intensity;
656                     ptable->p->x = xoff;
657                     ptable->p->y = yoff;
658                     ptable->p++;
659                     if (ptable->p - ptable->points == NUM_POINTS)
660                       {
661                         mwin__draw_points (frame, win, rface,
662                                            reverse ? 7 - intensity : intensity,
663                                            ptable->points, NUM_POINTS, region);
664                         ptable->p = ptable->points;
665                       }
666                   }
667               }
668           }
669       else
670         for (i = 0; i < ft_face->glyph->bitmap.rows;
671              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
672           {
673             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
674             for (j = 0; j < width; j++, xoff++)
675               {
676                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
677                 if (intensity)
678                   {
679                     ptable = point_table;
680                     ptable->p->x = xoff;
681                     ptable->p->y = yoff;
682                     ptable->p++;
683                     if (ptable->p - ptable->points == NUM_POINTS)
684                       {
685                         mwin__draw_points (frame, win, rface,
686                                            reverse ? 0 : 7,
687                                            ptable->points, NUM_POINTS, region);
688                         ptable->p = ptable->points;
689                       }             
690                   }
691               }
692         }
693     }
694
695   if (gstring->anti_alias)
696     {
697       for (i = 1; i < 8; i++)
698         if (point_table[i].p != point_table[i].points)
699           mwin__draw_points (frame, win, rface, reverse ? 7 - i : i,
700                              point_table[i].points,
701                              point_table[i].p - point_table[i].points, region);
702     }
703   else
704     {
705       if (point_table[0].p != point_table[0].points)
706         mwin__draw_points (frame, win, rface, reverse ? 0 : 7,
707                            point_table[0].points,
708                            point_table[0].p - point_table[0].points, region);
709     }
710 #endif  /* not HAVE_XFT2 */
711 }
712
713 \f
714
715 int
716 mfont__ft_init ()
717 {
718   struct {
719     char *ft_style;
720     char *weight, *style, *stretch;
721   } ft_to_prop_name[] =
722     { { "regular", "medium", "r", "normal" },
723       { "italic", "medium", "i", "normal" },
724       { "bold", "bold", "r", "normal" },
725       { "bold italic", "bold", "i", "normal" },
726       { "narrow", "medium", "r", "condensed" },
727       { "narrow italic", "medium", "i", "condensed" },
728       { "narrow bold", "bold", "r", "condensed" },
729       { "narrow bold italic", "bold", "i", "condensed" },
730       { "black", "black", "r", "normal" },
731       { "black italic", "black", "i", "normal" },
732       { "oblique", "medium", "o", "normal" },
733       { "boldoblique", "bold", "o", "normal" } };
734   int i;
735
736   if (FT_Init_FreeType (&ft_library) != 0)
737     MERROR (MERROR_FONT_FT, -1);
738
739   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
740   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
741   for (i = 0; i < ft_to_prop_size; i++)
742     {
743       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
744       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
745       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
746       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
747     }
748
749   mfont__driver_list[MFONT_TYPE_FT] = &ft_driver;
750
751   return 0;
752 }
753
754 void
755 mfont__ft_fini ()
756 {
757   MPlist *plist, *p;
758
759   if (ft_font_list)
760     {
761       MPLIST_DO (plist, ft_font_list)
762         {
763           MPLIST_DO (p, MPLIST_VAL (plist))
764             {
765               MFTInfo *ft_info = (MFTInfo *) MPLIST_VAL (p);
766               free (ft_info->filename);
767               M17N_OBJECT_UNREF (ft_info->charmap_list);
768               free (ft_info);
769             }
770           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
771         }
772       M17N_OBJECT_UNREF (ft_font_list);
773       ft_font_list = NULL;
774     }
775   free (ft_to_prop);
776   FT_Done_FreeType (ft_library);
777 }
778
779
780 int
781 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
782                      MRealizedFont *rfont,
783                      MSymbol script, MSymbol langsys, 
784                      MSymbol gsub_features, MSymbol gpos_features)
785 {
786   int len = to - from;
787   MGlyph g;
788   int i;
789 #ifdef HAVE_OTF
790   MFTInfo *ft_info;
791   OTF *otf;
792   OTF_GlyphString otf_gstring;
793   OTF_Glyph *otfg;
794   char *script_name, *language_name;
795   char *gsub_feature_names, *gpos_feature_names;
796   int from_pos, to_pos;
797   int unitsPerEm;
798
799   if (len == 0)
800     return from;
801
802   ft_info = (MFTInfo *) rfont->info;
803   if (ft_info->otf_flag < 0)
804     goto simple_copy;
805   otf = ft_info->otf;
806   if (! otf && (otf = OTF_open (ft_info->filename)))
807     {
808       if (OTF_get_table (otf, "head") < 0
809           || (OTF_check_table (otf, "GSUB") < 0
810               && OTF_check_table (otf, "GPOS") < 0))
811         {
812           OTF_close (otf);
813           ft_info->otf_flag = -1;
814           ft_info->otf = NULL;
815           goto simple_copy;
816         }
817       ft_info->otf = otf;
818     }
819
820   script_name = msymbol_name (script);
821   language_name = langsys != Mnil ? msymbol_name (langsys) : NULL;
822   gsub_feature_names
823     = (gsub_features == Mt ? "*"
824        : gsub_features == Mnil ? NULL
825        : msymbol_name (gsub_features));
826   gpos_feature_names
827     = (gpos_features == Mt ? "*"
828        : gpos_features == Mnil ? NULL
829        : msymbol_name (gpos_features));
830
831   g = gstring->glyphs[from];
832   from_pos = g.pos;
833   to_pos = g.to;
834   for (i = from + 1; i < to; i++)
835     {
836       if (from_pos > gstring->glyphs[i].pos)
837         from_pos = gstring->glyphs[i].pos;
838       if (to_pos < gstring->glyphs[i].to)
839         to_pos = gstring->glyphs[i].to;
840     }
841
842   unitsPerEm = otf->head->unitsPerEm;
843   otf_gstring.size = otf_gstring.used = len;
844   otf_gstring.glyphs = (OTF_Glyph *) alloca (sizeof (OTF_Glyph) * len);
845   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
846   for (i = 0; i < len; i++)
847     {
848       if (gstring->glyphs[from + i].otf_encoded)
849         {
850           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
851           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
852         }
853       else
854         {
855           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
856         }
857     }
858       
859   if (OTF_drive_tables (otf, &otf_gstring, script_name, language_name,
860                         gsub_feature_names, gpos_feature_names) < 0)
861     goto simple_copy;
862   g.pos = from_pos;
863   g.to = to_pos;
864   for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
865     {
866       g.combining_code = 0;
867       g.c = otfg->c;
868       if (otfg->glyph_id)
869         {
870           g.code = otfg->glyph_id;
871           switch (otfg->positioning_type)
872             {
873             case 1: case 2:
874               {
875                 int off_x = 128, off_y = 128;
876
877                 if (otfg->f.f1.format & OTF_XPlacement)
878                   off_x = ((double) (otfg->f.f1.value->XPlacement)
879                            * 100 / unitsPerEm + 128);
880                 if (otfg->f.f1.format & OTF_YPlacement)
881                   off_y = ((double) (otfg->f.f1.value->YPlacement)
882                            * 100 / unitsPerEm + 128);
883                 g.combining_code
884                   = MAKE_COMBINING_CODE (3, 2, 3, 0, off_y, off_x);
885                 if ((otfg->f.f1.format & OTF_XAdvance)
886                     || (otfg->f.f1.format & OTF_YAdvance))
887                   off_y--;
888               }
889               break;
890             case 3:
891               /* Not yet supported.  */
892               break;
893             case 4:
894               {
895                 int off_x, off_y;
896
897                 off_x = ((double) (otfg->f.f4.base_anchor->XCoordinate
898                                    - otfg->f.f4.mark_anchor->XCoordinate)
899                          * 100 / unitsPerEm + 128);
900                 off_y = ((double) (otfg->f.f4.base_anchor->YCoordinate
901                                    - otfg->f.f4.mark_anchor->YCoordinate)
902                          * 100 / unitsPerEm + 128);
903                 g.combining_code
904                   = MAKE_COMBINING_CODE (3, 0, 3, 0, off_y, off_x);
905               }
906               break;
907             case 5:
908               /* Not yet supported.  */
909               break;
910             default:            /* i.e case 6 */
911               /* Not yet supported.  */
912               break;
913             }
914           g.otf_encoded = 1;
915         }
916       else
917         {
918           g.code = otfg->c;
919           g.otf_encoded = 0;
920         }
921       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
922     }
923   return to;
924
925  simple_copy:
926 #endif  /* HAVE_OTF */
927   for (i = 0; i < len; i++)
928     {
929       g = gstring->glyphs[from + i];
930       MLIST_APPEND1 (gstring, glyphs, g, MERROR_FONT_OTF);
931     }
932   return to;
933 }
934
935 int
936 mfont__ft_decode_otf (MGlyph *g)
937 {
938 #ifdef HAVE_OTF
939   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
940   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
941
942   return (c ? c : -1);
943 #else  /* not HAVE_OTF */
944   return -1;
945 #endif  /* not HAVE_OTF */
946 }
947
948 #else /* not HAVE_FREETYPE */
949
950 int
951 mfont__ft_init ()
952 {
953   return 0;
954 }
955
956 void
957 mfont__ft_fini ()
958 {
959 }
960
961 #endif /* HAVE_FREETYPE */