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