67b331e6c4d22795962ebd7ca7572689d226b36d
[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     contains fonts of the corresponding family.  In the deeper plist,
81     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       FcPatternGetString (fs->fonts[i], FC_FILE, 0, (FcChar8 **) &filename);
350       FcPatternGetString (fs->fonts[i], FC_LANG, 0, (FcChar8 **) &languages);
351       if (family == Mnil)
352         {
353           MSymbol fam;
354           char *fname;
355
356           FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &fname);
357           fam = msymbol (fname);
358           if (! mplist_get (ft_font_list, fam))
359             add_font_info (filename, fam, languages);
360         }
361       else
362         add_font_info (filename, family, languages);
363     }
364   FcFontSetDestroy (fs);
365   FcObjectSetDestroy (os);
366   FcPatternDestroy (pattern);
367 }
368
369 #else  /* not HAVE_FONTCONFIG */
370
371 static void
372 ft_list_all ()
373 {
374   MPlist *plist;
375   struct stat buf;
376   char *pathname;
377
378   MPLIST_DO (plist, mfont_freetype_path)
379     if (MPLIST_STRING_P (plist)
380         && (pathname = MPLIST_STRING (plist))
381         && stat (pathname, &buf) == 0)
382       {
383         if (S_ISREG (buf.st_mode))
384           add_font_info (pathname, Mnil, NULL);
385         else if (S_ISDIR (buf.st_mode))
386           {
387             int len = strlen (pathname);
388             char path[PATH_MAX];
389             DIR *dir = opendir (pathname);
390             struct dirent *dp;
391
392             if (dir)
393               {
394                 strcpy (path, pathname);
395                 strcpy (path + len, "/");
396                 len++;
397                 while ((dp = readdir (dir)) != NULL)
398                   {
399                     strcpy (path + len, dp->d_name);
400                     add_font_info (path, Mnil, NULL);
401                   }
402                 closedir (dir);
403               }
404           }
405       }
406 }
407
408 #endif  /* not HAVE_FONTCONFIG */
409
410 /* The FreeType font driver function SELECT.  */
411
412 static MRealizedFont *
413 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
414 {
415   MPlist *plist, *pl;
416   MFTInfo *best_font;
417   int best_score;
418   MRealizedFont *rfont;
419   MSymbol family, registry;
420
421   best_font = NULL;
422   best_score = 0;
423   family = FONT_PROPERTY (spec, MFONT_FAMILY);
424   if (family == Mnil)
425     family = FONT_PROPERTY (request, MFONT_FAMILY);
426   registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
427   if (registry == Mnil)
428     registry = Mt;
429
430   if (! ft_font_list)
431     ft_font_list = mplist ();
432 #ifdef HAVE_FONTCONFIG
433   if (family != Mnil)
434     {
435       plist = mplist_get (ft_font_list, family);
436       if (! plist)
437         {
438           fc_list (family);
439           plist = mplist_get (ft_font_list, family);
440           if (! plist)
441             {
442               mplist_add (ft_font_list, family, plist = mplist ());
443               return NULL;
444             }
445         }
446     }
447   else
448     {
449       if (! all_fonts_scaned)
450         {
451           fc_list (Mnil);
452           all_fonts_scaned = 1;
453         }
454     }
455 #else  /* not HAVE_FONTCONFIG */
456   if (! all_fonts_scaned)
457     {
458       ft_list_all ();
459       all_fonts_scaned = 1;
460     }
461   if (family != Mnil)
462     {
463       plist = mplist_get (ft_font_list, family);
464       if (! plist)
465         return NULL;
466     }
467 #endif  /* not HAVE_FONTCONFIG */
468
469   if (family == Mnil)
470     plist = MPLIST_VAL (ft_font_list);
471
472  retry:
473   MPLIST_DO (pl, plist)
474     {
475       MFTInfo *ft_info = MPLIST_VAL (pl);
476       int score;
477
478       if (! mplist_find_by_key (ft_info->charmap_list, registry))
479         continue;
480       /* We always ignore FOUNDRY.  */
481       ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
482       score = mfont__score (&ft_info->font, spec, request, limited_size);
483       if (score >= 0
484           && (! best_font
485               || best_score > score))
486         {
487           best_font = ft_info;
488           best_score = score;
489           if (score == 0)
490             break;
491         }
492     }
493   if (family == Mnil)
494     {
495       plist = MPLIST_NEXT (plist);
496       if (! MPLIST_TAIL_P (plist))
497         goto retry;
498     }
499   if (! best_font)
500     return NULL;
501
502   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
503   rfont->frame = frame;
504   rfont->spec = *spec;
505   rfont->request = *request;
506   rfont->font = best_font->font;
507   rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
508   rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
509   rfont->score = best_score;
510   rfont->info = best_font;
511   M17N_OBJECT_REF (best_font);
512   return rfont;
513 }
514
515
516 /* The FreeType font driver function OPEN.  */
517
518 static int
519 ft_open (MRealizedFont *rfont)
520 {
521   MFTInfo *base = rfont->info, *ft_info;
522   MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
523   int mdebug_mask = MDEBUG_FONT;
524   int size;
525
526   M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
527   ft_info->font = base->font;
528   ft_info->filename = strdup (base->filename);
529   ft_info->otf_flag = base->otf_flag;
530   ft_info->charmap_list = base->charmap_list;
531   M17N_OBJECT_REF (ft_info->charmap_list);
532   M17N_OBJECT_UNREF (base);
533   rfont->info = ft_info;
534
535   rfont->status = -1;
536   ft_info->ft_face = NULL;
537   if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
538     goto err;
539   if (registry == Mnil)
540     registry = Mt;
541   ft_info->charmap_index
542     = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
543   if (ft_info->charmap_index >= 0
544       && FT_Set_Charmap (ft_info->ft_face, 
545                          ft_info->ft_face->charmaps[ft_info->charmap_index]))
546     goto err;
547   size = rfont->font.property[MFONT_SIZE] / 10;
548   if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
549     goto err;
550
551   MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
552   rfont->status = 1;
553   rfont->ascent = ft_info->ft_face->ascender >> 6;
554   rfont->descent = - (ft_info->ft_face->descender >> 6);
555   rfont->type = Mfreetype;
556   rfont->fontp = ft_info->ft_face;
557   return 0;
558
559  err:
560   MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
561   if (ft_info->ft_face)
562     FT_Done_Face (ft_info->ft_face);
563   M17N_OBJECT_UNREF (ft_info->charmap_list);
564   free (ft_info->filename);
565   free (ft_info);
566   rfont->info = NULL;
567   return -1;
568 }
569
570 /* The FreeType font driver function FIND_METRIC.  */
571
572 static void
573 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
574                 int from, int to)
575 {
576   MFTInfo *ft_info = (MFTInfo *) rfont->info;
577   FT_Face ft_face = ft_info->ft_face;
578   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
579
580   for (; g != gend; g++)
581     {
582       if (g->code == MCHAR_INVALID_CODE)
583         {
584           if (FT_IS_SCALABLE (ft_face))
585             {
586               unsigned unitsPerEm = ft_face->units_per_EM;
587               int size = rfont->font.property[MFONT_SIZE] / 10;
588
589               g->lbearing = 0;
590               g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
591               g->width = ft_face->max_advance_width * size / unitsPerEm;
592               g->ascent = ft_face->ascender * size / unitsPerEm;
593               g->descent = (- ft_face->descender) * size / unitsPerEm;
594             }
595           else
596             {
597               BDF_PropertyRec prop;
598
599               g->lbearing = 0;
600               g->rbearing = g->width = ft_face->available_sizes->width;
601               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
602                 {
603                   g->ascent = prop.u.integer;
604                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
605                   g->descent = prop.u.integer;
606                 }
607               else
608                 {
609                   g->ascent = ft_face->available_sizes->height;
610                   g->descent = 0;
611                 }
612             }
613         }
614       else
615         {
616           FT_Glyph_Metrics *metrics;
617
618           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
619           metrics = &ft_face->glyph->metrics;
620           g->lbearing = (metrics->horiBearingX >> 6);
621           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
622           g->width = metrics->horiAdvance >> 6;
623           g->ascent = metrics->horiBearingY >> 6;
624           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
625         }
626     }
627 }
628
629 /* The FreeType font driver function ENCODE_CHAR.  */
630
631 static unsigned
632 ft_encode_char (MRealizedFont *rfont, unsigned code)
633 {
634   MFTInfo *ft_info;
635
636   if (rfont->status == 0)
637     {
638       if ((rfont->driver->open) (rfont) < 0)
639         return -1;
640     }
641   ft_info = (MFTInfo *) rfont->info;
642   code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
643   if (! code)
644     return MCHAR_INVALID_CODE;
645   return (code);
646
647 }
648
649 /* The FreeType font driver function RENDER.  */
650
651 #define NUM_POINTS 0x1000
652
653 typedef struct {
654   MDrawPoint points[NUM_POINTS];
655   MDrawPoint *p;
656 } MPointTable;
657
658 static void
659 ft_render (MDrawWindow win, int x, int y,
660            MGlyphString *gstring, MGlyph *from, MGlyph *to,
661            int reverse, MDrawRegion region)
662 {
663   MFTInfo *ft_info;
664   FT_Face ft_face;
665   MRealizedFace *rface = from->rface;
666   MFrame *frame = rface->frame;
667   FT_Int32 load_flags = FT_LOAD_RENDER;
668   MGlyph *g;
669   int i, j;
670   MPointTable point_table[8];
671
672   if (from == to)
673     return;
674
675   /* It is assured that the all glyphs in the current range use the
676      same realized face.  */
677   ft_info = (MFTInfo *) rface->rfont->info;
678   ft_face = ft_info->ft_face;
679
680   if (! gstring->anti_alias)
681     {
682 #ifdef FT_LOAD_TARGET_MONO
683       load_flags |= FT_LOAD_TARGET_MONO;
684 #else
685       load_flags |= FT_LOAD_MONOCHROME;
686 #endif
687     }
688
689   for (i = 0; i < 8; i++)
690     point_table[i].p = point_table[i].points;
691
692   for (g = from; g < to; x += g++->width)
693     {
694       unsigned char *bmp;
695       int intensity;
696       MPointTable *ptable;
697       int xoff, yoff;
698       int width, pitch;
699
700       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
701       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
702       bmp = ft_face->glyph->bitmap.buffer;
703       width = ft_face->glyph->bitmap.width;
704       pitch = ft_face->glyph->bitmap.pitch;
705       if (! gstring->anti_alias)
706         pitch *= 8;
707       if (width > pitch)
708         width = pitch;
709
710       if (gstring->anti_alias)
711         for (i = 0; i < ft_face->glyph->bitmap.rows;
712              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
713           {
714             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
715             for (j = 0; j < width; j++, xoff++)
716               {
717                 intensity = bmp[j] >> 5;
718                 if (intensity)
719                   {
720                     ptable = point_table + intensity;
721                     ptable->p->x = xoff;
722                     ptable->p->y = yoff;
723                     ptable->p++;
724                     if (ptable->p - ptable->points == NUM_POINTS)
725                       {
726                         (*frame->driver->draw_points)
727                           (frame, win, rface,
728                            reverse ? 7 - intensity : intensity,
729                            ptable->points, NUM_POINTS, region);
730                         ptable->p = ptable->points;
731                       }
732                   }
733               }
734           }
735       else
736         for (i = 0; i < ft_face->glyph->bitmap.rows;
737              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
738           {
739             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
740             for (j = 0; j < width; j++, xoff++)
741               {
742                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
743                 if (intensity)
744                   {
745                     ptable = point_table;
746                     ptable->p->x = xoff;
747                     ptable->p->y = yoff;
748                     ptable->p++;
749                     if (ptable->p - ptable->points == NUM_POINTS)
750                       {
751                         (*frame->driver->draw_points) (frame, win, rface,
752                                            reverse ? 0 : 7,
753                                            ptable->points, NUM_POINTS, region);
754                         ptable->p = ptable->points;
755                       }             
756                   }
757               }
758         }
759     }
760
761   if (gstring->anti_alias)
762     {
763       for (i = 1; i < 8; i++)
764         if (point_table[i].p != point_table[i].points)
765           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
766                              point_table[i].points,
767                              point_table[i].p - point_table[i].points, region);
768     }
769   else
770     {
771       if (point_table[0].p != point_table[0].points)
772         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
773                            point_table[0].points,
774                            point_table[0].p - point_table[0].points, region);
775     }
776 }
777
778 static MPlist *
779 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
780 {
781   MPlist *pl, *p;
782   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
783   char *lang = language != Mnil ? MSYMBOL_NAME (language) : NULL;
784
785   if (! all_fonts_scaned)
786     {
787 #ifdef HAVE_FONTCONFIG
788       fc_list (Mnil);
789 #else
790       ft_list_all ();
791 #endif
792       all_fonts_scaned = 1;
793     }
794
795   if (family == Mnil)
796     pl = ft_font_list;
797   else
798     {
799       pl = mplist_find_by_key (ft_font_list, family);
800       if (! pl)
801         return NULL;
802     }
803
804   MPLIST_DO (pl, pl)
805     {
806       MPLIST_DO (p, MPLIST_VAL (pl))
807         {
808           MFTInfo *ft_info = MPLIST_VAL (p);
809
810           if (lang && ft_info->languages && strstr (ft_info->languages, lang))
811             continue;
812           if (font && ! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
813             continue;
814           mplist_push (plist, FONT_PROPERTY (&ft_info->font, MFONT_FAMILY),
815                        &ft_info->font);
816         }
817       if (family != Mnil)
818         break;
819     }
820   return plist;
821 }
822
823 \f
824 /* Internal API */
825
826 MFontDriver mfont__ft_driver =
827   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
828
829 int
830 mfont__ft_init ()
831 {
832   int i;
833
834   if (FT_Init_FreeType (&ft_library) != 0)
835     MERROR (MERROR_FONT_FT, -1);
836
837   for (i = 0; i < ft_to_prop_size; i++)
838     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
839
840   Municode_bmp = msymbol ("unicode-bmp");
841   Municode_full = msymbol ("unicode-full");
842   Miso10646_1 = msymbol ("iso10646-1");
843   Miso8859_1 = msymbol ("iso8859-1");
844
845 #ifdef HAVE_FONTCONFIG
846   fc_generic_family_list = mplist ();
847   mplist_push (fc_generic_family_list, msymbol ("serif"), Mt);
848   mplist_push (fc_generic_family_list, msymbol ("sans-serif"), Mt);
849   mplist_push (fc_generic_family_list, msymbol ("monospace"), Mt);
850   mplist_push (fc_generic_family_list, msymbol ("sans"), Mt);
851   mplist_push (fc_generic_family_list, msymbol ("sans serif"), Mt);
852   mplist_push (fc_generic_family_list, msymbol ("mono"), Mt);
853 #endif
854
855   return 0;
856 }
857
858 void
859 mfont__ft_fini ()
860 {
861   MPlist *plist, *p;
862
863   if (ft_font_list)
864     {
865       MPLIST_DO (plist, ft_font_list)
866         {
867           MPLIST_DO (p, MPLIST_VAL (plist))
868             {
869               MFTInfo *ft_info = MPLIST_VAL (p);
870
871               M17N_OBJECT_UNREF (ft_info);
872             }
873           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
874         }
875       M17N_OBJECT_UNREF (ft_font_list);
876       ft_font_list = NULL;
877     }
878   FT_Done_FreeType (ft_library);
879   all_fonts_scaned = 0;
880
881 #ifdef HAVE_FONTCONFIG
882   m17n_object_unref (fc_generic_family_list);
883 #endif
884
885 }
886
887
888 #ifdef HAVE_FONTCONFIG
889 typedef struct
890 {
891   int fc_value;
892   char *m17n_value;
893 } FC_vs_M17N_font_prop;
894
895 static FC_vs_M17N_font_prop fc_weight_table[] =
896   { { FC_WEIGHT_ULTRALIGHT, "extralight" },
897     { FC_WEIGHT_LIGHT, "light" },
898     { FC_WEIGHT_NORMAL, "normal" },
899     { FC_WEIGHT_MEDIUM, "medium" },
900     { FC_WEIGHT_DEMIBOLD, "demibold" },
901     { FC_WEIGHT_EXTRABOLD, "extrabold" },
902     { FC_WEIGHT_BLACK, "black" },
903     { FC_WEIGHT_MEDIUM, NULL } };
904
905 static FC_vs_M17N_font_prop fc_slant_table[] =
906   { { FC_SLANT_ROMAN, "r" },
907     { FC_SLANT_ITALIC, "i" },
908     { FC_SLANT_OBLIQUE, "o" },
909     { FC_SLANT_ROMAN, NULL } };
910
911 static FC_vs_M17N_font_prop fc_width_table[] =
912   { { FC_WIDTH_CONDENSED, "condensed" },
913     { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
914     { FC_WIDTH_NORMAL, "normal" },
915     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
916     { FC_WIDTH_EXPANDED, "expanded" },
917     { FC_WIDTH_NORMAL, NULL } };
918
919
920 static MSymbol
921 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
922 {
923   int i;
924
925   for (i = 0; table[i].m17n_value; i++)
926     if (val <= table[i].fc_value)
927       msymbol ("table[i].m17n_value");
928   return msymbol ("table[i - 1].m17n_value");
929 }
930
931 static int
932 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
933 {
934   int i;
935
936   for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
937   return table[i].fc_value;
938 }
939
940 int
941 mfont__ft_parse_name (char *name, MFont *font)
942 {
943   FcPattern *pat = FcNameParse ((FcChar8 *) name);
944   FcChar8 *str;
945   int val;
946   double size;
947   
948   if (! pat)
949     return -1;
950   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
951     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
952   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
953     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
954   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
955     mfont__set_property (font, MFONT_WEIGHT,
956                          fc_decode_prop (val, fc_weight_table));
957   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
958     mfont__set_property (font, MFONT_STYLE,
959                          fc_decode_prop (val, fc_slant_table));
960   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
961     mfont__set_property (font, MFONT_STRETCH,
962                          fc_decode_prop (val, fc_width_table));
963   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
964     font->property[MFONT_SIZE] = size * 10;
965   FcPatternDestroy (pat);
966   return 0;
967 }
968
969 char *
970 mfont__ft_unparse_name (MFont *font)
971 {
972   FcPattern *pat = FcPatternCreate ();
973   MSymbol sym, weight, style, stretch;
974   char *name;
975
976   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
977     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
978   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
979     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
980   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
981     FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
982                                                          fc_weight_table));
983   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
984     FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
985                                                         fc_slant_table));
986   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
987     FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
988                                                         fc_width_table));
989   name = (char *) FcNameUnparse (pat);
990   FcPatternDestroy (pat);
991   return name;
992 }
993 #endif  /* HAVE_FONTCONFIG */
994
995 \f
996 #ifdef HAVE_OTF
997
998 #define DEVICE_DELTA(table, size)                               \
999   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
1000    ? (table).DeltaValue[(size) >= (table).StartSize]            \
1001    : 0)
1002
1003 void
1004 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1005                unsigned code, int size, int *x, int *y)
1006 {
1007   if (anchor->AnchorFormat == 2)
1008     {
1009       FT_Outline *outline;
1010       int ap = anchor->f.f1.AnchorPoint;
1011
1012       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1013       outline = &ft_face->glyph->outline;
1014       if (ap < outline->n_points)
1015         {
1016           *x = outline->points[ap].x;
1017           *y = outline->points[ap].y;
1018         }
1019     }
1020   else if (anchor->AnchorFormat == 3)
1021     {
1022       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1023       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1024     }
1025 }
1026
1027 int
1028 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1029                      MSymbol script, MSymbol langsys,
1030                      MSymbol gsub_features, MSymbol gpos_features)
1031 {
1032   int len = to - from;
1033   MGlyph *g = MGLYPH (from);
1034   int i, gidx;
1035   MRealizedFont *rfont;
1036   MFTInfo *ft_info;
1037   OTF *otf;
1038   OTF_GlyphString otf_gstring;
1039   OTF_Glyph *otfg;
1040   char *script_name, *language_name;
1041   char *gsub_feature_names, *gpos_feature_names;
1042   int need_cmap;
1043
1044   if (len == 0)
1045     return from;
1046
1047   rfont = g->rface->rfont;
1048   ft_info = rfont->info;
1049   if (ft_info->otf_flag < 0)
1050     goto simple_copy;
1051   otf = ft_info->otf;
1052   if (! otf)
1053     {
1054       otf = OTF_open (ft_info->filename);
1055       if (otf && OTF_get_table (otf, "head") < 0)
1056         {
1057           OTF_close (otf);
1058           otf = NULL;
1059         }
1060       if (! otf)
1061         {
1062           ft_info->otf_flag = -1;
1063           goto simple_copy;
1064         }
1065       ft_info->otf = otf;
1066     }
1067
1068   if (script != Mnil)
1069     script_name = msymbol_name (script);
1070   else
1071     script_name = NULL;
1072   if (langsys != Mnil)
1073     language_name = msymbol_name (langsys);
1074   else
1075     language_name = NULL;
1076   gsub_feature_names
1077     = (gsub_features == Mt ? "*"
1078        : gsub_features == Mnil ? NULL
1079        : msymbol_name (gsub_features));
1080   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1081     gsub_feature_names = NULL;
1082   gpos_feature_names
1083     = (gpos_features == Mt ? "*"
1084        : gpos_features == Mnil ? NULL
1085        : msymbol_name (gpos_features));
1086   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1087     gpos_feature_names = NULL;
1088
1089   otf_gstring.size = otf_gstring.used = len;
1090   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1091   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1092   for (i = 0, need_cmap = 0; i < len; i++)
1093     {
1094       if (gstring->glyphs[from + i].otf_encoded)
1095         {
1096           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1097           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1098         }
1099       else
1100         {
1101           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1102           need_cmap++;
1103         }
1104     }
1105   if (need_cmap
1106       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1107     goto simple_copy;
1108
1109   OTF_drive_gdef (otf, &otf_gstring);
1110   gidx = gstring->used;
1111
1112   if (gsub_feature_names)
1113     {
1114       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1115                           gsub_feature_names) < 0)
1116         goto simple_copy;
1117       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1118         {
1119           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1120
1121           temp.c = otfg->c;
1122           temp.combining_code = 0;
1123           if (otfg->glyph_id)
1124             {
1125               temp.code = otfg->glyph_id;
1126               temp.otf_encoded = 1;
1127             }
1128           else
1129             {
1130               temp.code = temp.c;
1131               temp.otf_encoded = 0;
1132             }
1133           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1134           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1135         }
1136     }
1137   else
1138     for (i = 0; i < len; i++)
1139       {
1140         MGlyph temp = gstring->glyphs[from + i];
1141
1142         if (otf_gstring.glyphs[i].glyph_id)
1143           {
1144             temp.code = otf_gstring.glyphs[i].glyph_id;
1145             temp.otf_encoded = 1;
1146           }
1147         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1148       }
1149
1150   ft_find_metric (rfont, gstring, gidx, gstring->used);
1151
1152   if (gpos_feature_names)
1153     {
1154       int u;
1155       int size10, size;
1156       MGlyph *base = NULL, *mark = NULL;
1157
1158       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1159                           gpos_feature_names) < 0)
1160         return to;
1161
1162       u = otf->head->unitsPerEm;
1163       size10 = rfont->font.property[MFONT_SIZE];
1164       size = size10 / 10;
1165
1166       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1167            i < otf_gstring.used; i++, otfg++, g++)
1168         {
1169           MGlyph *prev;
1170
1171           if (! otfg->glyph_id)
1172             continue;
1173           switch (otfg->positioning_type)
1174             {
1175             case 0:
1176               break;
1177             case 1: case 2:
1178               {
1179                 int format = otfg->f.f1.format;
1180
1181                 if (format & OTF_XPlacement)
1182                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1183                 if (format & OTF_XPlaDevice)
1184                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1185                 if (format & OTF_YPlacement)
1186                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1187                 if (format & OTF_YPlaDevice)
1188                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1189                 if (format & OTF_XAdvance)
1190                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1191                 if (format & OTF_XAdvDevice)
1192                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1193               }
1194               break;
1195             case 3:
1196               /* Not yet supported.  */
1197               break;
1198             case 4: case 5:
1199               if (! base)
1200                 break;
1201               prev = base;
1202               goto label_adjust_anchor;
1203             default:            /* i.e. case 6 */
1204               if (! mark)
1205                 break;
1206               prev = mark;
1207
1208             label_adjust_anchor:
1209               {
1210                 int base_x, base_y, mark_x, mark_y;
1211
1212                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1213                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1214                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1215                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1216
1217                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1218                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1219                                  prev->code, size, &base_x, &base_y);
1220                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1221                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1222                                  g->code, size, &mark_x, &mark_y);
1223                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1224                 g->yoff = prev->yoff + mark_y - base_y;
1225                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1226               }
1227             }
1228           if (otfg->GlyphClass == OTF_GlyphClass0)
1229             base = mark = g;
1230           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1231             mark = g;
1232           else
1233             base = g;
1234         }
1235     }
1236   free (otf_gstring.glyphs);
1237   return to;
1238
1239  simple_copy:
1240   ft_find_metric (rfont, gstring, from, to);
1241   for (i = 0; i < len; i++)
1242     {
1243       MGlyph temp = gstring->glyphs[from + i];
1244       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1245     }
1246   free (otf_gstring.glyphs);
1247   return to;
1248 }
1249
1250
1251 int
1252 mfont__ft_decode_otf (MGlyph *g)
1253 {
1254   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1255   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1256
1257   return (c ? c : -1);
1258 }
1259
1260 #endif  /* HAVE_OTF */
1261
1262 #endif /* HAVE_FREETYPE */