45fe673cdd8cbadf351f65f9fa90da363cc26c4b
[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 "symbol.h"
39 #include "internal-gui.h"
40 #include "font.h"
41 #include "face.h"
42
43 #ifdef HAVE_FREETYPE
44
45 #include <freetype/ftbdf.h>
46
47 #ifdef HAVE_FONTCONFIG
48 #include <fontconfig/fontconfig.h>
49
50 int fontconfig_initialized = 0;
51 FcConfig *fc_config;
52 #endif  /* not HAVE_FONTCONFIG */
53
54 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
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 /** List of FreeType fonts.  Keys are family names, values are plists
68     contains fonts of the corresponding family.  In the deeper plist,
69     keys are Mt, values are (MFTInfo *).  */
70 static MPlist *ft_font_list;
71
72 static int all_fonts_scaned;
73
74 /** Return 0 if NAME implies TrueType or OpenType fonts.  Othersize
75     return -1.  */
76
77 static int
78 check_otf_filename (const char *name)
79 {
80   int len = strlen (name);
81   const char *ext = name + (len - 4);
82
83   if (len < 5
84       || (memcmp (ext, ".ttf", 4)
85           && memcmp (ext, ".TTF", 4)
86           && memcmp (ext, ".otf", 4)
87           && memcmp (ext, ".OTF", 4)))
88     return -1;
89   return 0;
90 }
91
92 /** Setup members of FT_INFO from FT_FACE.  Return the family name.  */
93
94 static MSymbol
95 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family)
96 {
97   MFont *font = &ft_info->font;
98   MSymbol style;
99   int len;
100   char *buf, *p;
101   MPlist *charmap_list;
102   int unicode_bmp = -1, unicode_full = -1, unicode = -1;
103   int i;
104
105   MFONT_INIT (font);
106
107   if (family == Mnil)
108     {
109       len = strlen (ft_face->family_name) + 1;
110       buf = (char *) alloca (len);
111       memcpy (buf, ft_face->family_name, len);
112       for (p = buf; *p; p++)
113         if (*p >= 'A' && *p <= 'Z')
114           *p += 'a' - 'A';
115       family = msymbol (buf);
116     }
117   mfont__set_property (font, MFONT_FAMILY, family);
118
119   if (ft_face->style_name)
120     {
121       len = strlen (ft_face->style_name) + 1;
122       buf = (char *) alloca (len);
123       memcpy (buf, ft_face->style_name, len);
124       for (p = buf; *p; p++)
125         if (*p >= 'A' && *p <= 'Z')
126           *p += 'a' - 'A';
127       style = msymbol (buf);
128       for (i = 0; i < ft_to_prop_size; i++)
129         if (ft_to_prop[i].ft_style == style)
130           {
131             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
132             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
133             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
134             break;
135           }
136     }
137   else
138     i = ft_to_prop_size;
139
140   if (i == ft_to_prop_size)
141     {
142       mfont__set_property (font, MFONT_WEIGHT, msymbol ("medium"));
143       mfont__set_property (font, MFONT_STYLE, msymbol ("r"));
144       mfont__set_property (font, MFONT_STRETCH, msymbol ("normal"));
145     }
146
147   mfont__set_property (font, MFONT_ADSTYLE, msymbol (""));
148
149   charmap_list = mplist ();
150   mplist_add (charmap_list, Mt, (void *) -1);
151   for (i = 0; i < ft_face->num_charmaps; i++)
152     {
153       char registry_buf[16];
154       MSymbol registry;
155
156       sprintf (registry_buf, "%d-%d",
157                ft_face->charmaps[i]->platform_id,
158                ft_face->charmaps[i]->encoding_id);
159       registry = msymbol (registry_buf);
160       mplist_add (charmap_list, registry, (void *) i);
161       
162       if (ft_face->charmaps[i]->platform_id == 0)
163         {
164           if (ft_face->charmaps[i]->encoding_id == 3)
165             unicode_bmp = i;
166           else if (ft_face->charmaps[i]->encoding_id == 4)
167             unicode_full = i;
168         }
169       else if (ft_face->charmaps[i]->platform_id == 3)
170         {
171           if (ft_face->charmaps[i]->encoding_id == 1)
172             unicode_bmp = i;
173           else if (ft_face->charmaps[i]->encoding_id == 10)
174             unicode_full = i;
175         }
176       else if (ft_face->charmaps[i]->platform_id == 1
177                && ft_face->charmaps[i]->encoding_id == 0)
178         mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
179     }
180   if (unicode_full >= 0)
181     {
182       mplist_add (charmap_list, Municode_full, (void *) unicode_full);
183       mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
184       mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
185       unicode = unicode_full;
186     }
187   else if (unicode_bmp >= 0)
188     {
189       mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
190       mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
191       unicode = unicode_bmp;
192     }
193   if (unicode >= 0)
194     {
195       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
196       for (i = 255; i >= 32; i--)
197         {
198           if (i == 160)
199             i = 126;
200           if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
201             break;
202         }
203       if (i == 31)
204         mplist_add (charmap_list, Miso8859_1, (void *) unicode);
205     }
206
207   ft_info->charmap_list = charmap_list;
208
209   if (! FT_IS_SCALABLE (ft_face))
210     {
211       BDF_PropertyRec prop;
212       
213       FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
214       font->property[MFONT_SIZE] = prop.u.integer * 10;
215       FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
216       font->property[MFONT_RESY] = prop.u.integer;
217     }
218
219   return family;
220 }
221
222
223 static void
224 close_ft (void *object)
225 {
226   MFTInfo *ft_info = object;
227
228   if (ft_info->ft_face)
229     {
230       if (ft_info->extra_info)
231         M17N_OBJECT_UNREF (ft_info->extra_info);
232       FT_Done_Face (ft_info->ft_face);
233 #ifdef HAVE_OTF
234       if (ft_info->otf)
235         OTF_close (ft_info->otf);
236 #endif /* HAVE_OTF */
237     }
238   free (ft_info->filename);
239   M17N_OBJECT_UNREF (ft_info->charmap_list);
240   free (ft_info);
241 }
242
243 static void
244 add_font_info (char *filename, MSymbol family)
245 {
246   FT_Face ft_face;
247   BDF_PropertyRec prop;
248   MFTInfo *ft_info = NULL;
249
250   if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
251     {
252       if (FT_IS_SCALABLE (ft_face)
253           || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
254         {
255           MSymbol fam;
256           MPlist *plist;
257
258           M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
259           ft_info->filename = strdup (filename);
260           ft_info->otf_flag = check_otf_filename (filename);
261           fam = set_font_info (ft_face, ft_info, family);
262           plist = mplist_get (ft_font_list, fam);
263           if (! plist)
264             {
265               plist = mplist ();
266               mplist_add (ft_font_list, fam, plist);
267             }
268           mplist_add (plist, fam, ft_info);
269         }
270       FT_Done_Face (ft_face);
271     }
272 }
273
274 #ifdef HAVE_FONTCONFIG
275
276 static void
277 fc_list (MSymbol family)
278 {
279   FcPattern *pattern;
280   FcObjectSet *os;
281   FcFontSet *fs;
282   int i;
283
284   if (! fc_config)
285     {
286       char *pathname;
287       struct stat buf;
288       MPlist *plist;
289
290       FcInit ();
291       fc_config = FcConfigGetCurrent ();
292       MPLIST_DO (plist, mfont_freetype_path)
293         if (MPLIST_STRING_P (plist)
294             && (pathname = MPLIST_STRING (plist))
295             && stat (pathname, &buf) == 0)
296           FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
297     }
298
299   pattern = FcPatternCreate ();
300   if (family)
301     FcPatternAddString (pattern, FC_FAMILY,
302                         (FcChar8 *) (msymbol_name (family)));
303   os = FcObjectSetBuild (FC_FILE, NULL);
304   fs = FcFontList (fc_config, pattern, os);
305   if (fs)
306     {
307       char *filename;
308
309       for (i = 0; i < fs->nfont; i++)
310         {
311           FcPatternGetString (fs->fonts[i], FC_FILE, 0, (FcChar8 **) &filename);
312           add_font_info (filename, family);
313         }
314       FcFontSetDestroy (fs);
315     }
316   FcObjectSetDestroy (os);
317   FcPatternDestroy (pattern);
318 }
319
320 #else  /* not HAVE_FONTCONFIG */
321
322 static void
323 ft_list ()
324 {
325   MPlist *plist;
326   struct stat buf;
327   char *pathname;
328
329   MPLIST_DO (plist, mfont_freetype_path)
330     if (MPLIST_STRING_P (plist)
331         && (pathname = MPLIST_STRING (plist))
332         && stat (pathname, &buf) == 0)
333       {
334         if (S_ISREG (buf.st_mode))
335           add_font_info (pathname, Mnil);
336         else if (S_ISDIR (buf.st_mode))
337           {
338             int len = strlen (pathname);
339             char path[PATH_MAX];
340             DIR *dir = opendir (pathname);
341             struct dirent *dp;
342
343             if (dir)
344               {
345                 strcpy (path, pathname);
346                 strcpy (path + len, "/");
347                 len++;
348                 while ((dp = readdir (dir)) != NULL)
349                   {
350                     strcpy (path + len, dp->d_name);
351                     add_font_info (path, Mnil);
352                   }
353                 closedir (dir);
354               }
355           }
356       }
357 }
358
359 #endif  /* not HAVE_FONTCONFIG */
360
361 /* The FreeType font driver function SELECT.  */
362
363 static MRealizedFont *
364 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
365 {
366   MPlist *plist, *pl;
367   MFTInfo *best_font;
368   int best_score;
369   MRealizedFont *rfont;
370   MSymbol family, registry;
371
372   best_font = NULL;
373   best_score = 0;
374   family = FONT_PROPERTY (spec, MFONT_FAMILY);
375   if (family == Mnil)
376     family = FONT_PROPERTY (request, MFONT_FAMILY);
377   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
378   if (registry == Mnil)
379     registry = Mt;
380
381   if (! ft_font_list)
382     ft_font_list = mplist ();
383 #ifdef HAVE_FONTCONFIG
384   if (family != Mnil)
385     {
386       plist = mplist_get (ft_font_list, family);
387       if (! plist)
388         {
389           fc_list (family);
390           plist = mplist_get (ft_font_list, family);
391           if (! plist)
392             {
393               mplist_add (ft_font_list, family, plist = mplist ());
394               return NULL;
395             }
396         }
397     }
398   else
399     {
400       if (! all_fonts_scaned)
401         {
402           fc_list (Mnil);
403           all_fonts_scaned = 1;
404         }
405     }
406 #else  /* not HAVE_FONTCONFIG */
407   if (! all_fonts_scaned)
408     {
409       ft_list ();
410       all_fonts_scaned = 1;
411     }
412   if (family != Mnil)
413     {
414       plist = mplist_get (ft_font_list, family);
415       if (! plist)
416         return NULL;
417     }
418 #endif  /* not HAVE_FONTCONFIG */
419
420   if (family == Mnil)
421     plist = MPLIST_VAL (ft_font_list);
422
423  retry:
424   MPLIST_DO (pl, plist)
425     {
426       MFTInfo *ft_info = MPLIST_VAL (pl);
427       int score;
428
429       if (! mplist_find_by_key (ft_info->charmap_list, registry))
430         continue;
431       /* We always ignore FOUNDRY.  */
432       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
433       score = mfont__score (&ft_info->font, spec, request, limited_size);
434       if (score >= 0
435           && (! best_font
436               || best_score > score))
437         {
438           best_font = ft_info;
439           best_score = score;
440           if (score == 0)
441             break;
442         }
443     }
444   if (family == Mnil)
445     {
446       plist = MPLIST_NEXT (plist);
447       if (! MPLIST_TAIL_P (plist))
448         goto retry;
449     }
450   if (! best_font)
451     return NULL;
452
453   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
454   rfont->frame = frame;
455   rfont->spec = *spec;
456   rfont->request = *request;
457   rfont->font = best_font->font;
458   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
459   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
460   rfont->score = best_score;
461   rfont->info = best_font;
462   M17N_OBJECT_REF (best_font);
463   return rfont;
464 }
465
466
467 /* The FreeType font driver function OPEN.  */
468
469 static int
470 ft_open (MRealizedFont *rfont)
471 {
472   MFTInfo *base = rfont->info, *ft_info;
473   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
474   int mdebug_mask = MDEBUG_FONT;
475   int size;
476
477   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
478   ft_info->font = base->font;
479   ft_info->filename = strdup (base->filename);
480   ft_info->otf_flag = base->otf_flag;
481   ft_info->charmap_list = base->charmap_list;
482   M17N_OBJECT_REF (ft_info->charmap_list);
483   M17N_OBJECT_UNREF (base);
484   rfont->info = ft_info;
485
486   rfont->status = -1;
487   ft_info->ft_face = NULL;
488   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
489     goto err;
490   if (registry == Mnil)
491     registry = Mt;
492   ft_info->charmap_index
493     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
494   if (ft_info->charmap_index >= 0
495       && FT_Set_Charmap (ft_info->ft_face, 
496                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
497     goto err;
498   size = rfont->font.property[MFONT_SIZE] / 10;
499   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
500     goto err;
501
502   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
503   rfont->status = 1;
504   rfont->ascent = ft_info->ft_face->ascender >> 6;
505   rfont->descent = - (ft_info->ft_face->descender >> 6);
506   rfont->type = Mfreetype;
507   rfont->fontp = ft_info->ft_face;
508   return 0;
509
510  err:
511   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
512   if (ft_info->ft_face)
513     FT_Done_Face (ft_info->ft_face);
514   M17N_OBJECT_UNREF (ft_info->charmap_list);
515   free (ft_info->filename);
516   free (ft_info);
517   rfont->info = NULL;
518   return -1;
519 }
520
521 /* The FreeType font driver function FIND_METRIC.  */
522
523 static void
524 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
525                 int from, int to)
526 {
527   MFTInfo *ft_info = (MFTInfo *) rfont->info;
528   FT_Face ft_face = ft_info->ft_face;
529   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
530
531   for (; g != gend; g++)
532     {
533       if (g->code == MCHAR_INVALID_CODE)
534         {
535           if (FT_IS_SCALABLE (ft_face))
536             {
537               unsigned unitsPerEm = ft_face->units_per_EM;
538               int size = rfont->font.property[MFONT_SIZE] / 10;
539
540               g->lbearing = 0;
541               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
542               g->width = ft_face->max_advance_width * size / unitsPerEm;
543               g->ascent = ft_face->ascender * size / unitsPerEm;
544               g->descent = (- ft_face->descender) * size / unitsPerEm;
545             }
546           else
547             {
548               BDF_PropertyRec prop;
549
550               g->lbearing = 0;
551               g->rbearing = g->width = ft_face->available_sizes->width;
552               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
553                 {
554                   g->ascent = prop.u.integer;
555                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
556                   g->descent = prop.u.integer;
557                 }
558               else
559                 {
560                   g->ascent = ft_face->available_sizes->height;
561                   g->descent = 0;
562                 }
563             }
564         }
565       else
566         {
567           FT_Glyph_Metrics *metrics;
568
569           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
570           metrics = &ft_face->glyph->metrics;
571           g->lbearing = (metrics->horiBearingX >> 6);
572           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
573           g->width = metrics->horiAdvance >> 6;
574           g->ascent = metrics->horiBearingY >> 6;
575           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
576         }
577     }
578 }
579
580 /* The FreeType font driver function ENCODE_CHAR.  */
581
582 static unsigned
583 ft_encode_char (MRealizedFont *rfont, unsigned code)
584 {
585   MFTInfo *ft_info;
586
587   if (rfont->status == 0)
588     {
589       if ((rfont->driver->open) (rfont) < 0)
590         return -1;
591     }
592   ft_info = (MFTInfo *) rfont->info;
593   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
594   if (! code)
595     return MCHAR_INVALID_CODE;
596   return (code);
597
598 }
599
600 /* The FreeType font driver function RENDER.  */
601
602 #define NUM_POINTS 0x1000
603
604 typedef struct {
605   MDrawPoint points[NUM_POINTS];
606   MDrawPoint *p;
607 } MPointTable;
608
609 static void
610 ft_render (MDrawWindow win, int x, int y,
611            MGlyphString *gstring, MGlyph *from, MGlyph *to,
612            int reverse, MDrawRegion region)
613 {
614   MFTInfo *ft_info;
615   FT_Face ft_face;
616   MRealizedFace *rface = from->rface;
617   MFrame *frame = rface->frame;
618   FT_Int32 load_flags = FT_LOAD_RENDER;
619   MGlyph *g;
620   int i, j;
621   MPointTable point_table[8];
622
623   if (from == to)
624     return;
625
626   /* It is assured that the all glyphs in the current range use the
627      same realized face.  */
628   ft_info = (MFTInfo *) rface->rfont->info;
629   ft_face = ft_info->ft_face;
630
631   if (! gstring->anti_alias)
632     {
633 #ifdef FT_LOAD_TARGET_MONO
634       load_flags |= FT_LOAD_TARGET_MONO;
635 #else
636       load_flags |= FT_LOAD_MONOCHROME;
637 #endif
638     }
639
640   for (i = 0; i < 8; i++)
641     point_table[i].p = point_table[i].points;
642
643   for (g = from; g < to; x += g++->width)
644     {
645       unsigned char *bmp;
646       int intensity;
647       MPointTable *ptable;
648       int xoff, yoff;
649       int width, pitch;
650
651       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
652       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
653       bmp = ft_face->glyph->bitmap.buffer;
654       width = ft_face->glyph->bitmap.width;
655       pitch = ft_face->glyph->bitmap.pitch;
656       if (! gstring->anti_alias)
657         pitch *= 8;
658       if (width > pitch)
659         width = pitch;
660
661       if (gstring->anti_alias)
662         for (i = 0; i < ft_face->glyph->bitmap.rows;
663              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
664           {
665             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
666             for (j = 0; j < width; j++, xoff++)
667               {
668                 intensity = bmp[j] >> 5;
669                 if (intensity)
670                   {
671                     ptable = point_table + intensity;
672                     ptable->p->x = xoff;
673                     ptable->p->y = yoff;
674                     ptable->p++;
675                     if (ptable->p - ptable->points == NUM_POINTS)
676                       {
677                         (*frame->driver->draw_points)
678                           (frame, win, rface,
679                            reverse ? 7 - intensity : intensity,
680                            ptable->points, NUM_POINTS, region);
681                         ptable->p = ptable->points;
682                       }
683                   }
684               }
685           }
686       else
687         for (i = 0; i < ft_face->glyph->bitmap.rows;
688              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
689           {
690             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
691             for (j = 0; j < width; j++, xoff++)
692               {
693                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
694                 if (intensity)
695                   {
696                     ptable = point_table;
697                     ptable->p->x = xoff;
698                     ptable->p->y = yoff;
699                     ptable->p++;
700                     if (ptable->p - ptable->points == NUM_POINTS)
701                       {
702                         (*frame->driver->draw_points) (frame, win, rface,
703                                            reverse ? 0 : 7,
704                                            ptable->points, NUM_POINTS, region);
705                         ptable->p = ptable->points;
706                       }             
707                   }
708               }
709         }
710     }
711
712   if (gstring->anti_alias)
713     {
714       for (i = 1; i < 8; i++)
715         if (point_table[i].p != point_table[i].points)
716           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
717                              point_table[i].points,
718                              point_table[i].p - point_table[i].points, region);
719     }
720   else
721     {
722       if (point_table[0].p != point_table[0].points)
723         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
724                            point_table[0].points,
725                            point_table[0].p - point_table[0].points, region);
726     }
727 }
728
729 \f
730 /* Internal API */
731
732 MFontDriver mfont__ft_driver =
733   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render };
734
735 int
736 mfont__ft_init ()
737 {
738   struct {
739     char *ft_style;
740     char *weight, *style, *stretch;
741   } ft_to_prop_name[] =
742     { { "regular", "medium", "r", "normal" },
743       { "medium", "medium", "r", "normal" },
744       { "normal", "medium", "r", "normal" },
745       { "italic", "medium", "i", "normal" },
746       { "bold", "bold", "r", "normal" },
747       { "bolditalic", "bold", "i", "normal" },
748       { "bold italic", "bold", "i", "normal" },
749       { "narrow", "medium", "r", "condensed" },
750       { "narrow italic", "medium", "i", "condensed" },
751       { "narrow bold", "bold", "r", "condensed" },
752       { "narrow bold italic", "bold", "i", "condensed" },
753       { "black", "black", "r", "normal" },
754       { "black italic", "black", "i", "normal" },
755       { "oblique", "medium", "o", "normal" },
756       { "boldoblique", "bold", "o", "normal" },
757       { "bold oblique", "bold", "o", "normal" } };
758   int i;
759
760   if (FT_Init_FreeType (&ft_library) != 0)
761     MERROR (MERROR_FONT_FT, -1);
762
763   ft_to_prop_size = sizeof (ft_to_prop_name) / sizeof (ft_to_prop_name[0]);
764   MTABLE_MALLOC (ft_to_prop, ft_to_prop_size, MERROR_FONT_FT);
765   for (i = 0; i < ft_to_prop_size; i++)
766     {
767       ft_to_prop[i].ft_style = msymbol (ft_to_prop_name[i].ft_style);
768       ft_to_prop[i].weight = msymbol (ft_to_prop_name[i].weight);
769       ft_to_prop[i].style = msymbol (ft_to_prop_name[i].style);
770       ft_to_prop[i].stretch = msymbol (ft_to_prop_name[i].stretch);
771     }
772
773   Municode_bmp = msymbol ("unicode-bmp");
774   Municode_full = msymbol ("unicode-full");
775   Miso10646_1 = msymbol ("iso10646-1");
776   Miso8859_1 = msymbol ("iso8859-1");
777
778   return 0;
779 }
780
781 void
782 mfont__ft_fini ()
783 {
784   MPlist *plist, *p;
785
786   if (ft_font_list)
787     {
788       MPLIST_DO (plist, ft_font_list)
789         {
790           MPLIST_DO (p, MPLIST_VAL (plist))
791             {
792               MFTInfo *ft_info = MPLIST_VAL (p);
793
794               M17N_OBJECT_UNREF (ft_info);
795             }
796           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
797         }
798       M17N_OBJECT_UNREF (ft_font_list);
799       ft_font_list = NULL;
800     }
801   free (ft_to_prop);
802   FT_Done_FreeType (ft_library);
803   all_fonts_scaned = 0;
804 }
805
806
807 #ifdef HAVE_FONTCONFIG
808 int
809 mfont__ft_parse_name (char *name, MFont *font)
810 {
811   FcPattern *pat = FcNameParse ((FcChar8 *) name);
812   FcResult result;
813   FcChar8 *str;
814   double size;
815   
816   if (! pat)
817     return -1;
818   if ((result = FcPatternGetString (pat, FC_FOUNDRY, 0, &str)) == FcResultMatch)
819     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
820   if ((result = FcPatternGetString (pat, FC_FAMILY, 0, &str)) == FcResultMatch)
821     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
822   if ((result = FcPatternGetString (pat, FC_STYLE, 0, &str)) == FcResultMatch)
823     {
824       MSymbol style = msymbol ((char *) str);
825       int i;
826
827       for (i = 0; i < ft_to_prop_size; i++)
828         if (ft_to_prop[i].ft_style == style)
829           {
830             mfont__set_property (font, MFONT_WEIGHT, ft_to_prop[i].weight);
831             mfont__set_property (font, MFONT_STYLE, ft_to_prop[i].style);
832             mfont__set_property (font, MFONT_STRETCH, ft_to_prop[i].stretch);
833             break;
834           }
835     }
836   if ((result = FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size))
837       == FcResultMatch)
838     font->property[MFONT_SIZE] = size * 10;
839   FcPatternDestroy (pat);
840   return 0;
841 }
842
843 char *
844 mfont__ft_unparse_name (MFont *font)
845 {
846   FcPattern *pat = FcPatternCreate ();
847   MSymbol sym, weight, style, stretch;
848   char *name;
849   int i;
850
851   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
852     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
853   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
854     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
855   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) == Mnil)
856     weight = msymbol ("medium");
857   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) == Mnil)
858     style = msymbol ("r");
859   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) == Mnil)
860     stretch = msymbol ("normal");
861   for (i = 0; i < ft_to_prop_size; i++)
862     if (ft_to_prop[i].weight == weight
863         && ft_to_prop[i].style == style
864         && ft_to_prop[i].stretch == stretch)
865       FcPatternAddString (pat, FC_STYLE,
866                           (FcChar8 *) MSYMBOL_NAME (ft_to_prop[i].ft_style));
867   name = (char *) FcNameUnparse (pat);
868   FcPatternDestroy (pat);
869   return name;
870 }
871 #endif  /* HAVE_FONTCONFIG */
872
873 \f
874 #ifdef HAVE_OTF
875
876 #define DEVICE_DELTA(table, size)                               \
877   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
878    ? (table).DeltaValue[(size) >= (table).StartSize]            \
879    : 0)
880
881 void
882 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
883                unsigned code, int size, int *x, int *y)
884 {
885   if (anchor->AnchorFormat == 2)
886     {
887       FT_Outline *outline;
888       int ap = anchor->f.f1.AnchorPoint;
889
890       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
891       outline = &ft_face->glyph->outline;
892       if (ap < outline->n_points)
893         {
894           *x = outline->points[ap].x;
895           *y = outline->points[ap].y;
896         }
897     }
898   else if (anchor->AnchorFormat == 3)
899     {
900       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
901       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
902     }
903 }
904
905 int
906 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
907                      MSymbol script, MSymbol langsys,
908                      MSymbol gsub_features, MSymbol gpos_features)
909 {
910   int len = to - from;
911   MGlyph *g = MGLYPH (from);
912   int i, gidx;
913   MRealizedFont *rfont;
914   MFTInfo *ft_info;
915   OTF *otf;
916   OTF_GlyphString otf_gstring;
917   OTF_Glyph *otfg;
918   char *script_name, *language_name;
919   char *gsub_feature_names, *gpos_feature_names;
920   int need_cmap;
921
922   if (len == 0)
923     return from;
924
925   rfont = g->rface->rfont;
926   ft_info = rfont->info;
927   if (ft_info->otf_flag < 0)
928     goto simple_copy;
929   otf = ft_info->otf;
930   if (! otf)
931     {
932       otf = OTF_open (ft_info->filename);
933       if (otf && OTF_get_table (otf, "head") < 0)
934         {
935           OTF_close (otf);
936           otf = NULL;
937         }
938       if (! otf)
939         {
940           ft_info->otf_flag = -1;
941           goto simple_copy;
942         }
943       ft_info->otf = otf;
944     }
945
946   if (script != Mnil)
947     script_name = msymbol_name (script);
948   else
949     script_name = NULL;
950   if (langsys != Mnil)
951     language_name = msymbol_name (langsys);
952   else
953     language_name = NULL;
954   gsub_feature_names
955     = (gsub_features == Mt ? "*"
956        : gsub_features == Mnil ? NULL
957        : msymbol_name (gsub_features));
958   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
959     gsub_feature_names = NULL;
960   gpos_feature_names
961     = (gpos_features == Mt ? "*"
962        : gpos_features == Mnil ? NULL
963        : msymbol_name (gpos_features));
964   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
965     gpos_feature_names = NULL;
966
967   otf_gstring.size = otf_gstring.used = len;
968   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
969   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
970   for (i = 0, need_cmap = 0; i < len; i++)
971     {
972       if (gstring->glyphs[from + i].otf_encoded)
973         {
974           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
975           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
976         }
977       else
978         {
979           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
980           need_cmap++;
981         }
982     }
983   if (need_cmap
984       && OTF_drive_cmap (otf, &otf_gstring) < 0)
985     goto simple_copy;
986
987   OTF_drive_gdef (otf, &otf_gstring);
988   gidx = gstring->used;
989
990   if (gsub_feature_names)
991     {
992       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
993                           gsub_feature_names) < 0)
994         goto simple_copy;
995       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
996         {
997           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
998
999           temp.c = otfg->c;
1000           temp.combining_code = 0;
1001           if (otfg->glyph_id)
1002             {
1003               temp.code = otfg->glyph_id;
1004               temp.otf_encoded = 1;
1005             }
1006           else
1007             {
1008               temp.code = temp.c;
1009               temp.otf_encoded = 0;
1010             }
1011           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1012           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1013         }
1014     }
1015   else
1016     for (i = 0; i < len; i++)
1017       {
1018         MGlyph temp = gstring->glyphs[from + i];
1019
1020         if (otf_gstring.glyphs[i].glyph_id)
1021           {
1022             temp.code = otf_gstring.glyphs[i].glyph_id;
1023             temp.otf_encoded = 1;
1024           }
1025         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1026       }
1027
1028   ft_find_metric (rfont, gstring, gidx, gstring->used);
1029
1030   if (gpos_feature_names)
1031     {
1032       int u;
1033       int size10, size;
1034       MGlyph *base = NULL, *mark = NULL;
1035
1036       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1037                           gpos_feature_names) < 0)
1038         return to;
1039
1040       u = otf->head->unitsPerEm;
1041       size10 = rfont->font.property[MFONT_SIZE];
1042       size = size10 / 10;
1043
1044       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1045            i < otf_gstring.used; i++, otfg++, g++)
1046         {
1047           MGlyph *prev;
1048
1049           if (! otfg->glyph_id)
1050             continue;
1051           switch (otfg->positioning_type)
1052             {
1053             case 0:
1054               break;
1055             case 1: case 2:
1056               {
1057                 int format = otfg->f.f1.format;
1058
1059                 if (format & OTF_XPlacement)
1060                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1061                 if (format & OTF_XPlaDevice)
1062                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1063                 if (format & OTF_YPlacement)
1064                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1065                 if (format & OTF_YPlaDevice)
1066                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1067                 if (format & OTF_XAdvance)
1068                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1069                 if (format & OTF_XAdvDevice)
1070                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1071               }
1072               break;
1073             case 3:
1074               /* Not yet supported.  */
1075               break;
1076             case 4: case 5:
1077               if (! base)
1078                 break;
1079               prev = base;
1080               goto label_adjust_anchor;
1081             default:            /* i.e. case 6 */
1082               if (! mark)
1083                 break;
1084               prev = mark;
1085
1086             label_adjust_anchor:
1087               {
1088                 int base_x, base_y, mark_x, mark_y;
1089
1090                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1091                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1092                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1093                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1094
1095                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1096                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1097                                  prev->code, size, &base_x, &base_y);
1098                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1099                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1100                                  g->code, size, &mark_x, &mark_y);
1101                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1102                 g->yoff = prev->yoff + mark_y - base_y;
1103                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1104               }
1105             }
1106           if (otfg->GlyphClass == OTF_GlyphClass0)
1107             base = mark = g;
1108           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1109             mark = g;
1110           else
1111             base = g;
1112         }
1113     }
1114   free (otf_gstring.glyphs);
1115   return to;
1116
1117  simple_copy:
1118   ft_find_metric (rfont, gstring, from, to);
1119   for (i = 0; i < len; i++)
1120     {
1121       MGlyph temp = gstring->glyphs[from + i];
1122       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1123     }
1124   free (otf_gstring.glyphs);
1125   return to;
1126 }
1127
1128
1129 int
1130 mfont__ft_decode_otf (MGlyph *g)
1131 {
1132   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1133   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1134
1135   return (c ? c : -1);
1136 }
1137
1138 #endif  /* HAVE_OTF */
1139
1140 #endif /* HAVE_FREETYPE */