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