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