590fd76e58605d836f5b4f7bfe66939884414226
[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 void
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;
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 }
821
822 \f
823 /* Internal API */
824
825 MFontDriver mfont__ft_driver =
826   { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
827
828 int
829 mfont__ft_init ()
830 {
831   int i;
832
833   if (FT_Init_FreeType (&ft_library) != 0)
834     MERROR (MERROR_FONT_FT, -1);
835
836   for (i = 0; i < ft_to_prop_size; i++)
837     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
838
839   Municode_bmp = msymbol ("unicode-bmp");
840   Municode_full = msymbol ("unicode-full");
841   Miso10646_1 = msymbol ("iso10646-1");
842   Miso8859_1 = msymbol ("iso8859-1");
843
844 #ifdef HAVE_FONTCONFIG
845   fc_generic_family_list = mplist ();
846   mplist_push (fc_generic_family_list, msymbol ("serif"), Mt);
847   mplist_push (fc_generic_family_list, msymbol ("sans-serif"), Mt);
848   mplist_push (fc_generic_family_list, msymbol ("monospace"), Mt);
849   mplist_push (fc_generic_family_list, msymbol ("sans"), Mt);
850   mplist_push (fc_generic_family_list, msymbol ("sans serif"), Mt);
851   mplist_push (fc_generic_family_list, msymbol ("mono"), Mt);
852 #endif
853
854   return 0;
855 }
856
857 void
858 mfont__ft_fini ()
859 {
860   MPlist *plist, *p;
861
862   if (ft_font_list)
863     {
864       MPLIST_DO (plist, ft_font_list)
865         {
866           MPLIST_DO (p, MPLIST_VAL (plist))
867             {
868               MFTInfo *ft_info = MPLIST_VAL (p);
869
870               M17N_OBJECT_UNREF (ft_info);
871             }
872           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
873         }
874       M17N_OBJECT_UNREF (ft_font_list);
875       ft_font_list = NULL;
876     }
877   FT_Done_FreeType (ft_library);
878   all_fonts_scaned = 0;
879
880 #ifdef HAVE_FONTCONFIG
881   m17n_object_unref (fc_generic_family_list);
882 #endif
883
884 }
885
886
887 #ifdef HAVE_FONTCONFIG
888 typedef struct
889 {
890   int fc_value;
891   char *m17n_value;
892 } FC_vs_M17N_font_prop;
893
894 static FC_vs_M17N_font_prop fc_weight_table[] =
895   { { FC_WEIGHT_ULTRALIGHT, "extralight" },
896     { FC_WEIGHT_LIGHT, "light" },
897     { FC_WEIGHT_NORMAL, "normal" },
898     { FC_WEIGHT_MEDIUM, "medium" },
899     { FC_WEIGHT_DEMIBOLD, "demibold" },
900     { FC_WEIGHT_EXTRABOLD, "extrabold" },
901     { FC_WEIGHT_BLACK, "black" },
902     { FC_WEIGHT_MEDIUM, NULL } };
903
904 static FC_vs_M17N_font_prop fc_slant_table[] =
905   { { FC_SLANT_ROMAN, "r" },
906     { FC_SLANT_ITALIC, "i" },
907     { FC_SLANT_OBLIQUE, "o" },
908     { FC_SLANT_ROMAN, NULL } };
909
910 static FC_vs_M17N_font_prop fc_width_table[] =
911   { { FC_WIDTH_CONDENSED, "condensed" },
912     { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
913     { FC_WIDTH_NORMAL, "normal" },
914     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
915     { FC_WIDTH_EXPANDED, "expanded" },
916     { FC_WIDTH_NORMAL, NULL } };
917
918
919 static MSymbol
920 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
921 {
922   int i;
923
924   for (i = 0; table[i].m17n_value; i++)
925     if (val <= table[i].fc_value)
926       msymbol ("table[i].m17n_value");
927   return msymbol ("table[i - 1].m17n_value");
928 }
929
930 static int
931 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
932 {
933   int i;
934
935   for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
936   return table[i].fc_value;
937 }
938
939 int
940 mfont__ft_parse_name (char *name, MFont *font)
941 {
942   FcPattern *pat = FcNameParse ((FcChar8 *) name);
943   FcChar8 *str;
944   int val;
945   double size;
946   
947   if (! pat)
948     return -1;
949   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
950     mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
951   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
952     mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
953   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
954     mfont__set_property (font, MFONT_WEIGHT,
955                          fc_decode_prop (val, fc_weight_table));
956   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
957     mfont__set_property (font, MFONT_STYLE,
958                          fc_decode_prop (val, fc_slant_table));
959   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
960     mfont__set_property (font, MFONT_STRETCH,
961                          fc_decode_prop (val, fc_width_table));
962   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
963     font->property[MFONT_SIZE] = size * 10;
964   FcPatternDestroy (pat);
965   return 0;
966 }
967
968 char *
969 mfont__ft_unparse_name (MFont *font)
970 {
971   FcPattern *pat = FcPatternCreate ();
972   MSymbol sym, weight, style, stretch;
973   char *name;
974
975   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
976     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
977   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
978     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
979   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
980     FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
981                                                          fc_weight_table));
982   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
983     FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
984                                                         fc_slant_table));
985   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
986     FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
987                                                         fc_width_table));
988   name = (char *) FcNameUnparse (pat);
989   FcPatternDestroy (pat);
990   return name;
991 }
992 #endif  /* HAVE_FONTCONFIG */
993
994 \f
995 #ifdef HAVE_OTF
996
997 #define DEVICE_DELTA(table, size)                               \
998   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
999    ? (table).DeltaValue[(size) >= (table).StartSize]            \
1000    : 0)
1001
1002 void
1003 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1004                unsigned code, int size, int *x, int *y)
1005 {
1006   if (anchor->AnchorFormat == 2)
1007     {
1008       FT_Outline *outline;
1009       int ap = anchor->f.f1.AnchorPoint;
1010
1011       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1012       outline = &ft_face->glyph->outline;
1013       if (ap < outline->n_points)
1014         {
1015           *x = outline->points[ap].x;
1016           *y = outline->points[ap].y;
1017         }
1018     }
1019   else if (anchor->AnchorFormat == 3)
1020     {
1021       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1022       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1023     }
1024 }
1025
1026 int
1027 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1028                      MSymbol script, MSymbol langsys,
1029                      MSymbol gsub_features, MSymbol gpos_features)
1030 {
1031   int len = to - from;
1032   MGlyph *g = MGLYPH (from);
1033   int i, gidx;
1034   MRealizedFont *rfont;
1035   MFTInfo *ft_info;
1036   OTF *otf;
1037   OTF_GlyphString otf_gstring;
1038   OTF_Glyph *otfg;
1039   char *script_name, *language_name;
1040   char *gsub_feature_names, *gpos_feature_names;
1041   int need_cmap;
1042
1043   if (len == 0)
1044     return from;
1045
1046   rfont = g->rface->rfont;
1047   ft_info = rfont->info;
1048   if (ft_info->otf_flag < 0)
1049     goto simple_copy;
1050   otf = ft_info->otf;
1051   if (! otf)
1052     {
1053       otf = OTF_open (ft_info->filename);
1054       if (otf && OTF_get_table (otf, "head") < 0)
1055         {
1056           OTF_close (otf);
1057           otf = NULL;
1058         }
1059       if (! otf)
1060         {
1061           ft_info->otf_flag = -1;
1062           goto simple_copy;
1063         }
1064       ft_info->otf = otf;
1065     }
1066
1067   if (script != Mnil)
1068     script_name = msymbol_name (script);
1069   else
1070     script_name = NULL;
1071   if (langsys != Mnil)
1072     language_name = msymbol_name (langsys);
1073   else
1074     language_name = NULL;
1075   gsub_feature_names
1076     = (gsub_features == Mt ? "*"
1077        : gsub_features == Mnil ? NULL
1078        : msymbol_name (gsub_features));
1079   if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1080     gsub_feature_names = NULL;
1081   gpos_feature_names
1082     = (gpos_features == Mt ? "*"
1083        : gpos_features == Mnil ? NULL
1084        : msymbol_name (gpos_features));
1085   if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1086     gpos_feature_names = NULL;
1087
1088   otf_gstring.size = otf_gstring.used = len;
1089   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1090   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1091   for (i = 0, need_cmap = 0; i < len; i++)
1092     {
1093       if (gstring->glyphs[from + i].otf_encoded)
1094         {
1095           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1096           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1097         }
1098       else
1099         {
1100           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1101           need_cmap++;
1102         }
1103     }
1104   if (need_cmap
1105       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1106     goto simple_copy;
1107
1108   OTF_drive_gdef (otf, &otf_gstring);
1109   gidx = gstring->used;
1110
1111   if (gsub_feature_names)
1112     {
1113       if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1114                           gsub_feature_names) < 0)
1115         goto simple_copy;
1116       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1117         {
1118           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1119
1120           temp.c = otfg->c;
1121           temp.combining_code = 0;
1122           if (otfg->glyph_id)
1123             {
1124               temp.code = otfg->glyph_id;
1125               temp.otf_encoded = 1;
1126             }
1127           else
1128             {
1129               temp.code = temp.c;
1130               temp.otf_encoded = 0;
1131             }
1132           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1133           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1134         }
1135     }
1136   else
1137     for (i = 0; i < len; i++)
1138       {
1139         MGlyph temp = gstring->glyphs[from + i];
1140
1141         if (otf_gstring.glyphs[i].glyph_id)
1142           {
1143             temp.code = otf_gstring.glyphs[i].glyph_id;
1144             temp.otf_encoded = 1;
1145           }
1146         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1147       }
1148
1149   ft_find_metric (rfont, gstring, gidx, gstring->used);
1150
1151   if (gpos_feature_names)
1152     {
1153       int u;
1154       int size10, size;
1155       MGlyph *base = NULL, *mark = NULL;
1156
1157       if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1158                           gpos_feature_names) < 0)
1159         return to;
1160
1161       u = otf->head->unitsPerEm;
1162       size10 = rfont->font.property[MFONT_SIZE];
1163       size = size10 / 10;
1164
1165       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1166            i < otf_gstring.used; i++, otfg++, g++)
1167         {
1168           MGlyph *prev;
1169
1170           if (! otfg->glyph_id)
1171             continue;
1172           switch (otfg->positioning_type)
1173             {
1174             case 0:
1175               break;
1176             case 1: case 2:
1177               {
1178                 int format = otfg->f.f1.format;
1179
1180                 if (format & OTF_XPlacement)
1181                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1182                 if (format & OTF_XPlaDevice)
1183                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1184                 if (format & OTF_YPlacement)
1185                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1186                 if (format & OTF_YPlaDevice)
1187                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1188                 if (format & OTF_XAdvance)
1189                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1190                 if (format & OTF_XAdvDevice)
1191                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1192               }
1193               break;
1194             case 3:
1195               /* Not yet supported.  */
1196               break;
1197             case 4: case 5:
1198               if (! base)
1199                 break;
1200               prev = base;
1201               goto label_adjust_anchor;
1202             default:            /* i.e. case 6 */
1203               if (! mark)
1204                 break;
1205               prev = mark;
1206
1207             label_adjust_anchor:
1208               {
1209                 int base_x, base_y, mark_x, mark_y;
1210
1211                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1212                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1213                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1214                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1215
1216                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1217                   adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1218                                  prev->code, size, &base_x, &base_y);
1219                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1220                   adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1221                                  g->code, size, &mark_x, &mark_y);
1222                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1223                 g->yoff = prev->yoff + mark_y - base_y;
1224                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1225               }
1226             }
1227           if (otfg->GlyphClass == OTF_GlyphClass0)
1228             base = mark = g;
1229           else if (otfg->GlyphClass == OTF_GlyphClassMark)
1230             mark = g;
1231           else
1232             base = g;
1233         }
1234     }
1235   free (otf_gstring.glyphs);
1236   return to;
1237
1238  simple_copy:
1239   ft_find_metric (rfont, gstring, from, to);
1240   for (i = 0; i < len; i++)
1241     {
1242       MGlyph temp = gstring->glyphs[from + i];
1243       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1244     }
1245   free (otf_gstring.glyphs);
1246   return to;
1247 }
1248
1249
1250 int
1251 mfont__ft_decode_otf (MGlyph *g)
1252 {
1253   MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1254   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1255
1256   return (c ? c : -1);
1257 }
1258
1259 #endif  /* HAVE_OTF */
1260
1261 #endif /* HAVE_FREETYPE */