(STRDUP_LOWER): Ignore the tailing spaces.
[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 "language.h"
40 #include "internal-gui.h"
41 #include "font.h"
42 #include "face.h"
43
44 #ifdef HAVE_FREETYPE
45
46 #ifdef HAVE_FTBDF_H
47 #include <freetype/ftbdf.h>
48 #endif
49
50 static int mdebug_mask = MDEBUG_FONT;
51
52 #ifdef HAVE_FONTCONFIG
53 static FcConfig *fc_config;
54 static MSymbol Mgeneric_family;
55 #endif  /* HAVE_FONTCONFIG */
56
57 /* Font properties; Mnormal is already defined in face.c.  */
58 static MSymbol Mmedium, Mr, Mnull;
59
60 static MSymbol M0_3, M3_1, M1_0;
61
62 static FT_Library ft_library;
63
64 #ifdef HAVE_OTF
65 static OTF *invalid_otf = (OTF *) "";
66 #endif /* HAVE_OTF */
67
68 typedef struct
69 {
70   MFont font;
71   MPlist *lang;
72 #ifdef HAVE_OTF
73   /* NULL if not yet opened.  invalid_otf if not OTF.  */
74   OTF *otf;
75 #endif /* HAVE_OTF */
76 #ifdef HAVE_FONTCONFIG
77   FcLangSet *langset;
78   FcCharSet *charset;
79 #endif  /* HAVE_FONTCONFIG */
80 } MFontFT;
81
82 typedef struct
83 {
84   M17NObject control;
85   FT_Face ft_face;
86   MPlist *charmap_list;
87 } MRealizedFontFT;
88
89 typedef struct
90 {
91   char *ft_style;
92   int len;
93   enum MFontProperty prop;
94   char *val;
95 } MFTtoProp;
96
97 static MFTtoProp ft_to_prop[] =
98   { { "italic", 0, MFONT_STYLE, "i" },
99     { "roman", 0, MFONT_STYLE, "r" },
100     { "oblique", 0, MFONT_STYLE, "o" },
101     { "regular", 0, MFONT_WEIGHT, "normal" },
102     { "normal", 0, MFONT_WEIGHT, "normal" },
103     /* We need this entry even if "bold" is in commone_weight[] to
104        handle such style names as "bolditalic" and "boldoblique".  */
105     { "bold", 0, MFONT_WEIGHT, "bold" },
106     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
107     { "demi", 0, MFONT_WEIGHT, "demibold" } };
108 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
109
110 /** List of FreeType fonts.  Keys are family names, values are plists
111     containing fonts of the corresponding family.  In the deeper
112     plist, keys are file names, values are (MFontFT *).  */
113 static MPlist *ft_font_list;
114
115 /** List of FreeType fonts.  Keys are script names, values are plists
116     containing fonts supporting the corresponding script.  In the
117     deeper plist, keys are family names, values are (MFontFT *).  */
118 static MPlist *ft_script_list;
119
120 /** List of FreeType fonts.  Keys are language names, values are
121     plists containing fonts supporting the corresponding language.  In
122     the deeper plist, keys are family names, values are (MFontFT *).  */
123 static MPlist *ft_language_list;
124
125 static MPlist *ft_file_list;
126
127 static int all_fonts_scaned;
128
129 #define STRDUP_LOWER(s1, size, s2)                              \
130   do {                                                          \
131     int len = strlen (s2) + 1;                                  \
132     char *p1, *p2;                                              \
133                                                                 \
134     if ((size) < len)                                           \
135       (s1) = alloca (len), (size) = len;                        \
136     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)                 \
137       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
138     while (p1 > (s1) && p1[-1] == ' ') p1--;                    \
139     *p1 = '\0';                                                 \
140   } while (0)
141
142
143 static void
144 free_ft_rfont (void *object)
145 {
146   MRealizedFontFT *ft_rfont = object;
147
148   M17N_OBJECT_UNREF (ft_rfont->charmap_list);
149   FT_Done_Face (ft_rfont->ft_face);
150   free (ft_rfont);
151 }
152
153 static void
154 free_ft_info (MFontFT *ft_info)
155 {
156   M17N_OBJECT_UNREF (ft_info->lang);
157 #ifdef HAVE_OTF
158   if (ft_info->otf && ft_info->otf != invalid_otf)
159     OTF_close (ft_info->otf);
160 #endif /* HAVE_OTF */
161   free (ft_info);
162 }
163
164 static MPlist *
165 ft_get_charmaps (FT_Face ft_face)
166 {
167   MPlist *plist = mplist ();
168   int unicode_bmp = -1, unicode_full = -1;
169   int i;
170
171   mplist_add (plist, Mt, (void *) -1);
172   for (i = 0; i < ft_face->num_charmaps; i++)
173     {
174       MSymbol registry = Mnil;
175
176       if (ft_face->charmaps[i]->platform_id == 0)
177         {
178           if (ft_face->charmaps[i]->encoding_id == 3)
179             registry = M0_3, unicode_bmp = i;
180           else if (ft_face->charmaps[i]->encoding_id == 4)
181             unicode_full = i;
182         }
183       else if (ft_face->charmaps[i]->platform_id == 3)
184         {
185           if (ft_face->charmaps[i]->encoding_id == 1)
186             registry = M3_1, unicode_bmp = i;
187           else if (ft_face->charmaps[i]->encoding_id == 10)
188             unicode_full = i;
189         }
190       else if (ft_face->charmaps[i]->platform_id == 1
191                && ft_face->charmaps[i]->encoding_id == 0)
192         {
193           registry = M1_0;
194           mplist_add (plist, Mapple_roman, (void *) i);
195         }
196       if (registry == Mnil)
197         {
198           char registry_buf[16];
199
200           sprintf (registry_buf, "%d-%d",
201                    ft_face->charmaps[i]->platform_id,
202                    ft_face->charmaps[i]->encoding_id);
203           registry = msymbol (registry_buf);
204         }
205       mplist_add (plist, registry, (void *) i);
206     }
207   if (unicode_full >= 0)
208     {
209       mplist_add (plist, Municode_full, (void *) unicode_full);
210       mplist_add (plist, Municode_bmp, (void *) unicode_full);
211     }
212   else if (unicode_bmp >= 0)
213     {
214       mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
215     }
216   return plist;
217 }
218
219 #ifdef HAVE_FONTCONFIG
220
221 typedef struct
222 {
223   int fc_value;
224   char *m17n_value;
225   MSymbol sym;
226 } FC_vs_M17N_font_prop;
227
228 static FC_vs_M17N_font_prop fc_weight_table[] =
229   { { FC_WEIGHT_THIN, "thin" },
230     { FC_WEIGHT_ULTRALIGHT, "extralight" },
231     { FC_WEIGHT_LIGHT, "light" },
232 #ifdef FC_WEIGHT_BOOK
233     { FC_WEIGHT_BOOK, "book" },
234 #endif  /* FC_WEIGHT_BOOK */
235     { FC_WEIGHT_NORMAL, "normal" },
236     { FC_WEIGHT_MEDIUM, "medium" },
237     { FC_WEIGHT_DEMIBOLD, "demibold" },
238     { FC_WEIGHT_BOLD, "bold" },
239     { FC_WEIGHT_EXTRABOLD, "extrabold" },
240     { FC_WEIGHT_BLACK, "black" },
241     { FC_WEIGHT_HEAVY, "heavy" },
242     { FC_WEIGHT_MEDIUM, NULL } };
243 int fc_weight_table_size =
244   sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
245
246 static FC_vs_M17N_font_prop fc_slant_table[] =
247   { { FC_SLANT_ROMAN, "r" },
248     { FC_SLANT_ITALIC, "i" },
249     { FC_SLANT_OBLIQUE, "o" },
250     { FC_SLANT_ROMAN, NULL } };
251 int fc_slant_table_size =
252   sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
253
254 static FC_vs_M17N_font_prop fc_width_table[] =
255   { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
256     { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
257     { FC_WIDTH_CONDENSED, "condensed" },
258     { FC_WIDTH_SEMICONDENSED, "semicondensed" },
259     { FC_WIDTH_NORMAL, "normal" },
260     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
261     { FC_WIDTH_EXPANDED, "expanded" },
262     { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
263     { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
264     { FC_WIDTH_NORMAL, NULL } };
265 int fc_width_table_size =
266   sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
267
268
269 static FC_vs_M17N_font_prop *fc_all_table[] =
270   { fc_weight_table, fc_slant_table, fc_width_table };
271
272 static MSymbol
273 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
274 {
275   int i = size / 2;
276
277   if (val < table[i].fc_value)
278     {
279       for (i--; i >= 0; i--)
280         if (val > table[i].fc_value)
281           break;
282       i++;
283     }
284   else
285     {
286       for (; i < size; i++)
287         if (val <= table[i].fc_value)
288           break;
289     }
290   return table[i].sym;
291 }
292
293 static int
294 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
295 {
296   int i;
297
298   for (i = 0; table[i].m17n_value; i++)
299     if (table[i].sym == sym)
300       break;
301   return table[i].fc_value;
302 }
303
304 FcPattern *
305 fc_get_pattern (MFont *font)
306 {
307   FcPattern *pat = FcPatternCreate ();
308   MSymbol sym, weight, style, stretch;
309
310
311   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
312     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
313   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
314     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
315   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
316     FcPatternAddInteger (pat, FC_WEIGHT,
317                          fc_encode_prop (weight, fc_weight_table));
318   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
319     FcPatternAddInteger (pat, FC_SLANT,
320                          fc_encode_prop (style, fc_slant_table));
321   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
322     FcPatternAddInteger (pat, FC_WIDTH,
323                          fc_encode_prop (stretch, fc_width_table));
324   if (font->size > 0)
325     {
326       double size = font->size;
327       FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
328     }
329   else if (font->size < 0)
330     {
331       double size = - font->size;
332       FcPatternAddDouble (pat, FC_SIZE, size / 10);
333     }
334   return pat;
335 }
336
337 static void
338 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
339 {
340   FcChar8 *str;
341   int val;
342   double size;
343   char *buf;
344   int bufsize = 0;
345   MSymbol sym;
346
347   MFONT_INIT (font);
348   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
349     {
350       STRDUP_LOWER (buf, bufsize, (char *) str);
351       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
352     }
353   if (family)
354     mfont__set_property (font, MFONT_FAMILY, msymbol (family));
355   else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
356     {
357       STRDUP_LOWER (buf, bufsize, (char *) str);
358       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
359     }
360   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
361     {
362       sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
363       mfont__set_property (font, MFONT_WEIGHT, sym);
364     }
365   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
366     {
367       sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
368       mfont__set_property (font, MFONT_STYLE, sym);
369     }
370   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
371     {
372       sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
373       mfont__set_property (font, MFONT_STRETCH, sym);
374     }
375   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
376   font->type = MFONT_TYPE_SPEC;
377   font->source = MFONT_SOURCE_FT;
378   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
379     font->size = size * 10;
380   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
381     font->file = msymbol ((char *) str);
382 }
383
384
385 static MFontFT *
386 fc_gen_font (FcPattern *pat, char *family)
387 {
388   MFontFT *ft_info;
389
390   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
391   fc_parse_pattern (pat, family, &ft_info->font);
392   ft_info->font.type = MFONT_TYPE_OBJECT;
393   return ft_info;
394 }
395
396 #else   /* not HAVE_FONTCONFIG */
397
398 static MPlist *
399 ft_add_font (char *filename)
400 {
401   FT_Face ft_face;
402   char *stylename;
403   int size = 0;
404   MSymbol family;
405   MFontFT *ft_info;
406   MFont *font;
407   MPlist *plist;
408   int i;
409   char *buf;
410   int bufsize = 0;
411
412   if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
413     return NULL;
414   if (! FT_IS_SCALABLE (ft_face))
415     {
416       int reject;
417 #ifdef HAVE_FTBDF_H
418       BDF_PropertyRec prop;
419
420       reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
421       size = prop.u.integer * 10;
422 #else  /* not HAVE_FTBDF_H */
423       reject = 1;
424 #endif  /* not HAVE_FTBDF_H */
425       if (reject)
426         {
427           FT_Done_Face (ft_face);
428           return NULL;
429         }
430     }
431
432   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
433   font = &ft_info->font;
434   STRDUP_LOWER (buf, bufsize, ft_face->family_name);
435   family = msymbol (buf);
436   mfont__set_property (font, MFONT_FAMILY, family);
437   mfont__set_property (font, MFONT_WEIGHT, Mmedium);
438   mfont__set_property (font, MFONT_STYLE, Mr);
439   mfont__set_property (font, MFONT_STRETCH, Mnormal);
440   mfont__set_property (font, MFONT_ADSTYLE, Mnull);
441   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
442   font->type = MFONT_TYPE_OBJECT;
443   font->source = MFONT_SOURCE_FT;
444   font->size = size;
445   font->file = msymbol (filename);
446
447   stylename = ft_face->style_name;
448   while (*stylename)
449     {
450       for (i = 0; i < ft_to_prop_size; i++)
451         if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
452                            ft_to_prop[i].len))
453           {
454             mfont__set_property (font, ft_to_prop[i].prop,
455                                  msymbol (ft_to_prop[i].val));
456             stylename += ft_to_prop[i].len;
457             break;
458           }
459       if (i == ft_to_prop_size)
460         {
461           char *p1 = stylename + 1;
462           MSymbol sym;
463
464           while (*p1 >= 'a' && *p1 <= 'z') p1++;
465           sym = msymbol__with_len (stylename, p1 - stylename);
466           for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
467             if (msymbol_get (sym, mfont__property_table[i].property))
468               {
469                 mfont__set_property (font, i, sym);
470                 break;
471               }
472           stylename = p1;
473         }
474       while (*stylename && ! isalpha (*stylename))
475         stylename++;
476     }
477
478   FT_Done_Face (ft_face);
479
480   plist = mplist_find_by_key (ft_font_list, family);
481   if (plist)
482     mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
483   else
484     {
485       plist = mplist ();
486       mplist_add (plist, font->file, ft_info);
487       plist = mplist_push (ft_font_list, family, plist);
488     }
489   return plist;
490 }
491
492 #endif  /* not HAVE_FONTCONFIG */
493
494
495 /* Return an element of ft_font_list for FAMILY.  If FAMILY is Mnil,
496    scan all fonts and return ft_font_list.  */
497
498 static MPlist *
499 ft_list_family (MSymbol family, int check_generic)
500 {
501   MPlist *plist;
502 #ifdef HAVE_FONTCONFIG
503   char *fam;
504   MPlist *pl, *p;
505   FcPattern *pattern;
506   FcObjectSet *os;
507   FcFontSet *fs;
508   int i;
509   char *buf;
510   int bufsize = 0;
511   MSymbol generic;
512
513   if (! ft_font_list)
514     {
515       MSymbol sym;
516
517       plist = ft_font_list = mplist ();
518       pattern = FcPatternCreate ();
519       os = FcObjectSetBuild (FC_FAMILY, NULL);
520       fs = FcFontList (fc_config, pattern, os);
521       for (i = 0; i < fs->nfont; i++)
522         {
523           if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
524                                   (FcChar8 **) &fam) != FcResultMatch)
525             continue;
526           STRDUP_LOWER (buf, bufsize, fam);
527           sym = msymbol (buf);
528           if (! mplist_find_by_key (ft_font_list, sym))
529             plist = mplist_add (plist, sym, NULL);
530         }
531       FcFontSetDestroy (fs);
532       FcObjectSetDestroy (os);
533       FcPatternDestroy (pattern);
534     }
535
536   if (family == Mnil)
537     {
538       if (! all_fonts_scaned)
539         {
540           MPLIST_DO (plist, ft_font_list)
541             {
542               if (! MPLIST_VAL (plist))
543                 ft_list_family (MPLIST_KEY (plist), 0);
544             }
545           all_fonts_scaned = 1;
546         }
547       return ft_font_list;
548     }
549
550   plist = mplist_find_by_key (ft_font_list, family);
551   if (plist)
552     {
553       if (! MPLIST_VAL (plist))
554         {
555           fam = MSYMBOL_NAME (family);
556           pattern = FcPatternCreate ();
557           FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
558           os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
559                                  FC_PIXEL_SIZE, FC_FILE, NULL);
560           fs = FcFontList (fc_config, pattern, os);
561           p = pl = mplist ();
562           for (i = 0; i < fs->nfont; i++)
563             {
564               MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
565               p = mplist_add (p, ft_info->font.file, ft_info);
566             }
567           MPLIST_VAL (plist) = pl;
568           FcFontSetDestroy (fs);
569           FcObjectSetDestroy (os);
570           FcPatternDestroy (pattern);
571         }
572     }
573   else if (check_generic
574            && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
575     {
576       /* Check if FAMILY is a geneneric family (e.g. `serif').  */
577       FcChar8 *fam8;
578       
579       if (family != generic)
580         plist = ft_list_family (generic, 1);
581       else
582         {
583           fam = MSYMBOL_NAME (family);
584           plist = mplist ();
585           mplist_push (ft_font_list, family, plist);
586           pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
587           FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
588           for (i = 0; 1; i++)
589             {
590               if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
591                   != FcResultMatch)
592                 break;
593               STRDUP_LOWER (buf, bufsize, (char *) fam8);
594               family = msymbol (buf);
595               if (msymbol_get (family, Mgeneric_family))
596                 break;
597               pl = ft_list_family (family, 0);
598               if (! pl)
599                 continue;
600               MPLIST_DO (pl, MPLIST_PLIST (pl))
601                 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
602             }
603           plist = ft_font_list;
604         }
605     }
606   else
607     plist = mplist_add (ft_font_list, family, mplist ());
608
609 #else  /* not HAVE_FONTCONFIG */
610
611   if (! all_fonts_scaned)
612     {
613       MPlist *plist;
614       struct stat buf;
615       char *pathname;
616       char *path;
617       USE_SAFE_ALLOCA;
618
619       ft_font_list = mplist ();
620       MPLIST_DO (plist, mfont_freetype_path)
621         if (MPLIST_STRING_P (plist)
622             && (pathname = MPLIST_STRING (plist))
623             && stat (pathname, &buf) == 0)
624           {
625             if (S_ISREG (buf.st_mode))
626               ft_add_font (pathname);
627             else if (S_ISDIR (buf.st_mode))
628               {
629                 DIR *dir = opendir (pathname);
630
631                 if (dir)
632                   {
633                     int len = strlen (pathname);
634                     struct dirent *dp;
635
636                     while ((dp = readdir (dir)) != NULL)
637                       {
638                         SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
639                         strcpy (path, pathname);
640                         path[len] =  '/';
641                         strcpy (path + len + 1, dp->d_name);
642                         ft_add_font (path);
643                       }
644                     closedir (dir);
645                   }
646               }
647           }
648       SAFE_FREE (path);
649       all_fonts_scaned = 1;
650     }
651   if (family == Mnil)
652     plist = ft_font_list;
653   else
654     {
655       plist = mplist_find_by_key (ft_font_list, family);
656       if (! plist)
657         plist = mplist_push (ft_font_list, family, mplist ());
658     }
659 #endif  /* not HAVE_FONTCONFIG */
660
661   return plist;
662 }
663
664 static MPlist *
665 ft_list_language (MSymbol language)
666 {
667   MPlist *plist = NULL;
668   MText *mt;
669   int step;
670
671   if (! ft_language_list)
672     ft_language_list = mplist ();
673   else if ((plist = mplist_find_by_key (ft_language_list, language)))
674     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
675
676 #ifdef HAVE_FONTCONFIG
677   for (step = 0; step < 2; step++)
678     {
679       FcPattern *pattern = NULL;
680       FcObjectSet *os = NULL;
681       FcFontSet *fs = NULL;
682       char *buf;
683       int bufsize = 0;
684       int i;
685
686       if (! (pattern = FcPatternCreate ())
687           || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
688         goto err;
689       if (step == 0)
690         {
691           FcLangSet *ls = FcLangSetCreate ();
692
693           if (! ls)
694             goto err;
695           if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
696               && FcPatternAddLangSet (pattern, FC_LANG, ls))
697             fs = FcFontList (fc_config, pattern, os);
698           FcLangSetDestroy (ls);
699           if (! fs)
700             goto err;
701         }
702       else
703         {
704           FcCharSet *cs;
705
706           if (! (mt = msymbol_get (language, Mtext)))
707             break;
708           if (! (cs = FcCharSetCreate ()))
709             goto err;
710           for (i = mtext_nchars (mt) - 1; i >= 0; i--)
711             if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
712               break;
713           if (i < 0)
714             {
715               if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
716                 fs = FcFontList (fc_config, pattern, os);
717             }
718           FcCharSetDestroy (cs);
719           if (! fs)
720             goto err;
721         }
722
723       for (i = 0; i < fs->nfont; i++)
724         {
725           MSymbol family, file;
726           char *fam, *filename;
727           MPlist *pl;
728           MFontFT *ft_info;
729
730           if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
731                                   (FcChar8 **) &fam) != FcResultMatch)
732             continue;
733           if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
734                                   (FcChar8 **) &filename) != FcResultMatch)
735             continue;
736           STRDUP_LOWER (buf, bufsize, fam);
737           family = msymbol (buf);
738           file = msymbol (filename);
739           pl = MPLIST_PLIST (ft_list_family (family, 0));
740           ft_info = mplist_get (pl, file);
741           if (ft_info)
742             {
743               if (! plist)
744                 plist = mplist ();
745               mplist_add (plist, family, ft_info);
746             }
747         }
748       FcFontSetDestroy (fs);
749       FcObjectSetDestroy (os);
750       FcPatternDestroy (pattern);
751       continue;
752
753     err:
754       if (os)
755         FcObjectSetDestroy (os);
756       if (pattern)
757         FcPatternDestroy (pattern);
758       MEMORY_FULL (MERROR_FONT_FT);
759       return NULL;
760     }
761
762   mplist_push (ft_language_list, language, plist);
763   return plist;
764
765 #else   /* not HAVE_FONTCONFIG */
766   
767   if ((mt = msymbol_get (language, Mtext)))
768     {
769       MPlist *pl, *p;
770       int len = mtext_nchars (mt);
771       int i;
772
773       if (! ft_font_list)
774         ft_list_family (Mnil, 0);
775       MPLIST_DO (pl, ft_font_list)
776         {
777           MPLIST_DO (p, MPLIST_PLIST (pl))
778             {
779               MFontFT *ft_info = MPLIST_VAL (p);
780               MSymbol family; 
781               FT_Face ft_face;
782
783               if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
784                                0, &ft_face) != 0)
785                 continue;
786               for (i = 0; i < len; i++)
787                 if (FT_Get_Char_Index (ft_face, 
788                                        (FT_ULong) mtext_ref_char (mt, i)) == 0)
789                   break;
790               FT_Done_Face (ft_face);
791               if (i < len)
792                 continue;
793               if (! plist)
794                 plist = mplist ();
795               family = mfont_get_prop (&ft_info->font, Mfamily);
796               mplist_push (plist, family, ft_info);
797             }
798         }
799     }
800   return plist;
801 #endif  /* not HAVE_FONTCONFIG */
802 }
803
804 static MPlist *
805 ft_list_script (MSymbol script)
806 {
807   MPlist *plist = NULL;
808   MPlist *language_list, *pl;
809
810   if (! ft_script_list)
811     ft_script_list = mplist ();
812   else if ((plist = mplist_find_by_key (ft_script_list, script)))
813     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
814
815   language_list = mlanguage__list (script);
816   MPLIST_DO (pl, language_list)
817     {
818       MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
819       MPlist *p = ft_list_language (language);
820       MSymbol family;
821
822       if (! p)
823         continue;
824       if (! plist)
825         plist = mplist ();
826       MPLIST_DO (p, p)
827         {
828           family = MPLIST_KEY (p);
829           if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
830             mplist_add (plist, family, MPLIST_VAL (p));
831         }
832     }
833   mplist_push (ft_script_list, script, plist);
834   M17N_OBJECT_UNREF (language_list);
835   return (plist);
836 }
837
838 static int
839 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
840 {
841   if (ft_info->otf == invalid_otf)
842     return -1;
843   if (! ft_info->otf)
844     {
845       ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
846       if (! ft_info->otf)
847         {
848           ft_info->otf = invalid_otf;
849           return -1;
850         }
851     }
852   if (cap->features[MFONT_OTT_GSUB].nfeatures
853       && cap->features[MFONT_OTT_GSUB].tags[0]
854       && (OTF_check_features
855           (ft_info->otf, 1,
856            cap->script_tag, cap->langsys_tag,
857            cap->features[MFONT_OTT_GSUB].tags,
858            cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
859     return -1;
860   if (cap->features[MFONT_OTT_GPOS].nfeatures
861       && cap->features[MFONT_OTT_GPOS].tags[0]
862       && (OTF_check_features
863           (ft_info->otf, 0,
864            cap->script_tag, cap->langsys_tag,
865            cap->features[MFONT_OTT_GPOS].tags,
866            cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
867     return -1;
868   return 0;
869 }
870
871 static int
872 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
873 {
874 #ifdef HAVE_FONTCONFIG
875   MPlist *plist;
876   MText *mt;
877   int i, j;
878
879   for (i = 0; cap->lang[i] != Mnil; i++)
880     {
881       if (ft_info->lang
882           && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
883         {
884           if (MPLIST_VAL (plist))
885             return 0;
886           continue;
887         }
888
889       if (! ft_info->langset)
890         {
891           FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
892                                            MSYMBOL_NAME (ft_info->font.file),
893                                            NULL);
894           FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
895           FcFontSet *fs = FcFontList (fc_config, pat, os);
896
897           if (fs->nfont == 0)
898             return -1;
899           if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
900               == FcResultMatch)
901             ft_info->langset = FcLangSetCopy (ft_info->langset);
902           else
903             ft_info->langset = FcLangSetCreate ();
904           FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
905           FcFontSetDestroy (fs);
906           FcObjectSetDestroy (os);
907           FcPatternDestroy (pat);
908         }
909       if (! ft_info->lang)
910         ft_info->lang = mplist ();
911       if (FcLangSetHasLang (ft_info->langset,
912                             (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
913           == FcLangEqual)
914         {
915           mplist_push (ft_info->lang, cap->lang[i], Mt);
916           return 0;
917         }
918
919       mt = msymbol_get (cap->lang[i], Mtext);
920       if (! mt)
921         {
922           mplist_push (ft_info->lang, cap->lang[i], Mnil);
923           continue;
924         }
925
926       for (j = mtext_nchars (mt) - 1; j >= 0; j--)
927         if (! FcCharSetAddChar (ft_info->charset,
928                                 (FcChar32) mtext_ref_char (mt, j)))
929           break;
930       mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
931       if (j < 0)
932         return 0;
933     }
934 #endif  /* HAVE_FONTCONFIG */
935   return -1;
936 }
937
938 static MPlist *ft_capability_list;
939
940 static MPlist *
941 ft_list_capability (MSymbol sym)
942 {
943   MPlist *plist, *pl, *p;
944   MFontCapability *cap = mfont__get_capability (sym);
945
946   if (! cap)
947     return NULL;
948   if (ft_capability_list)
949     {
950       plist = mplist_find_by_key (ft_capability_list, sym);
951       if (plist)
952         return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
953     }
954   else
955     {
956       plist = NULL;
957       ft_capability_list = mplist ();
958     }
959
960   if (cap->script != Mnil)
961     {
962       pl = ft_list_script (cap->script);
963       if (pl)
964         MPLIST_DO (pl, pl)
965           {
966             if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
967               continue;
968             if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
969               continue;
970             if (! plist)
971               plist = mplist ();
972             mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
973         }
974       mplist_push (ft_capability_list, sym, plist);
975       return plist;
976     }
977
978   if (cap->lang)
979     {
980       int i;
981
982       for (i = 0; cap->lang[i] != Mnil; i++)
983         {
984           p = ft_list_language (cap->lang[i]);
985           if (p)
986             {
987               if (! plist)
988                 plist = mplist ();
989               MPLIST_DO (p, p)
990                 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
991             }
992         }
993     }
994   mplist_push (ft_capability_list, sym, plist);
995   return plist;
996 }
997
998
999 static MPlist *
1000 ft_list_file (MSymbol filename)
1001 {
1002   MPlist *plist = NULL;
1003
1004   if (! ft_file_list)
1005     ft_file_list = mplist ();
1006   else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1007     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1008
1009 #ifdef HAVE_FONTCONFIG
1010   {
1011     FcPattern *pattern = FcPatternCreate ();
1012     FcObjectSet *os;
1013     FcFontSet *fs;
1014
1015     FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1016     os = FcObjectSetBuild (FC_FAMILY, NULL);
1017     fs = FcFontList (fc_config, pattern, os);
1018     if (fs->nfont > 0)
1019       {
1020         char *fam;
1021         char *buf;
1022         int bufsize = 0;
1023
1024         if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1025                                 (FcChar8 **) &fam) == FcResultMatch)
1026           {
1027             MSymbol family;
1028             MPlist *pl;
1029
1030             STRDUP_LOWER (buf, bufsize, fam);
1031             family = msymbol (buf);
1032             pl = ft_list_family (family, 0);
1033             MPLIST_DO (pl, MPLIST_PLIST (pl))
1034               {
1035                 MFontFT *ft_info = MPLIST_VAL (pl);
1036
1037                 if (ft_info->font.file == filename)
1038                   {
1039                     plist = mplist ();
1040                     mplist_add (plist, family, ft_info);
1041                     break;
1042                   }
1043               }
1044           }
1045       }
1046   }
1047 #else  /* not HAVE_FONTCONFIG */
1048   {
1049     MPlist *pl, *p;
1050
1051     MPLIST_DO (pl, ft_list_family (Mnil, 0))
1052       {
1053         MPLIST_DO (p, MPLIST_PLIST (pl))
1054           {
1055             MFontFT *ft_info = MPLIST_VAL (pl);
1056
1057             if (ft_info->font.file == filename)
1058               {
1059                 plist = mplist ();
1060                 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1061                 break;
1062               }
1063           }
1064         if (plist)
1065           break;
1066       }
1067   }
1068 #endif  /* not HAVE_FONTCONFIG */
1069
1070   mplist_push (ft_file_list, filename, plist);
1071   return plist;
1072 }
1073
1074 /* The FreeType font driver function SELECT.  */
1075
1076 static MFont *
1077 ft_select (MFrame *frame, MFont *font, int limited_size)
1078 {
1079   MFont *found = NULL;
1080 #ifdef HAVE_FONTCONFIG
1081   MPlist *plist, *pl;
1082   MFontFT *ft_info;
1083   int check_font_property = 1;
1084
1085   if (font->file != Mnil)
1086     {
1087       plist = ft_list_file (font->file);
1088       if (! plist)
1089         return NULL;
1090       check_font_property = 0;
1091     }
1092   else
1093     {
1094       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1095
1096       if (! family)
1097         return NULL;
1098       plist = MPLIST_PLIST (ft_list_family (family, 1));
1099       if (MPLIST_TAIL_P (plist))
1100         return NULL;
1101     }
1102
1103   plist = mplist_copy (plist);
1104
1105   if (font->capability != Mnil)
1106     {
1107       MFontCapability *cap = mfont__get_capability (font->capability);
1108
1109       for (pl = plist; ! MPLIST_TAIL_P (pl);)
1110         {
1111           if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1112               || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1113             mplist_pop (pl);
1114           else
1115             pl = MPLIST_NEXT (pl);
1116         }
1117     }
1118
1119   if (check_font_property)
1120     {
1121       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1122       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1123       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1124
1125       if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1126         for (pl = plist; ! MPLIST_TAIL_P (pl); )
1127           {
1128             ft_info = MPLIST_VAL (pl);
1129             if ((weight != Mnil
1130                  && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1131                 || (style != Mnil
1132                     && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1133                 || (stretch != Mnil
1134                     && stretch != FONT_PROPERTY (&ft_info->font,
1135                                                  MFONT_STRETCH))
1136                 || (font->size > 0
1137                     && ft_info->font.size > 0
1138                     && ft_info->font.size != font->size))
1139               mplist_pop (pl);
1140             else
1141               pl = MPLIST_NEXT (pl);
1142           }
1143     }
1144
1145   MPLIST_DO (pl, plist)
1146     {
1147       font = MPLIST_VAL (plist);
1148       if (limited_size == 0
1149           || font->size == 0
1150           || font->size <= limited_size)
1151         {
1152           found = font;
1153           break;
1154         }
1155     }
1156   M17N_OBJECT_UNREF (plist);
1157 #endif
1158   return found;
1159 }
1160
1161
1162 static MRealizedFont *
1163 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1164 {
1165   MFontFT *ft_info = (MFontFT *) font;
1166   int reg = spec->property[MFONT_REGISTRY];
1167   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1168   MRealizedFontFT *ft_rfont;
1169   FT_Face ft_face;
1170   MPlist *plist, *charmap_list = NULL;
1171   int charmap_index;
1172   int size = font->size ? font->size : spec->size;
1173
1174   if (rfont)
1175     {
1176       charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1177       for (; rfont; rfont = rfont->next)
1178         if (rfont->font == font
1179             && (rfont->font->size ? rfont->font->size == size
1180                 : rfont->spec.size == size)
1181             && rfont->spec.property[MFONT_REGISTRY] == reg
1182             && rfont->driver == &mfont__ft_driver)
1183           return rfont;
1184     }
1185
1186   MDEBUG_PRINT3 (" [FONT-FT] opening %s-%d:file=%s ...",
1187                  MSYMBOL_NAME ((MSymbol) mfont_get_prop (font, Mfamily)),
1188                  size / 10, MSYMBOL_NAME (font->file));
1189
1190   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1191                    &ft_face))
1192     {
1193       font->type = MFONT_TYPE_FAILURE;
1194       MDEBUG_PRINT ("failed\n");
1195       return NULL;
1196     }
1197   if (charmap_list)
1198     M17N_OBJECT_REF (charmap_list);
1199   else
1200     charmap_list = ft_get_charmaps (ft_face);
1201   if (registry == Mnil)
1202     registry = Mt;
1203   plist = mplist_find_by_key (charmap_list, registry);
1204   if (! plist)
1205     {
1206       FT_Done_Face (ft_face);
1207       M17N_OBJECT_UNREF (charmap_list);
1208       MDEBUG_PRINT ("failed\n");
1209       return NULL;
1210     }
1211   charmap_index = (int) MPLIST_VAL (plist);
1212   if (FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index])
1213       || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1214     {
1215       FT_Done_Face (ft_face);
1216       M17N_OBJECT_UNREF (charmap_list);
1217       font->type = MFONT_TYPE_FAILURE;
1218       MDEBUG_PRINT ("failed\n");
1219       return NULL;
1220     }
1221
1222   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1223   ft_rfont->ft_face = ft_face;
1224   ft_rfont->charmap_list = charmap_list;
1225   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1226   rfont->spec = *font;
1227   rfont->spec.type = MFONT_TYPE_REALIZED;
1228   rfont->spec.property[MFONT_REGISTRY] = reg;
1229   rfont->spec.size = size;
1230   rfont->frame = frame;
1231   rfont->font = font;
1232   rfont->driver = &mfont__ft_driver;
1233   rfont->info = ft_rfont;
1234   rfont->fontp = ft_face;
1235   rfont->ascent = ft_face->size->metrics.ascender >> 6;
1236   rfont->descent = - ft_face->size->metrics.descender >> 6;
1237   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1238   rfont->next = MPLIST_VAL (frame->realized_font_list);
1239   MPLIST_VAL (frame->realized_font_list) = rfont;
1240   MDEBUG_PRINT ("ok\n");
1241   return rfont;
1242 }
1243
1244 /* The FreeType font driver function FIND_METRIC.  */
1245
1246 static void
1247 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1248                 int from, int to)
1249 {
1250   FT_Face ft_face = rfont->fontp;
1251   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1252
1253   for (; g != gend; g++)
1254     {
1255       if (g->code == MCHAR_INVALID_CODE)
1256         {
1257           if (FT_IS_SCALABLE (ft_face))
1258             {
1259               unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1260               int size = rfont->spec.size;
1261
1262               g->lbearing = 0;
1263               g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1264               g->width = g->rbearing;
1265               g->ascent = ft_face->ascender * size / unitsPerEm10;
1266               g->descent = (- ft_face->descender) * size / unitsPerEm10;
1267             }
1268           else
1269             {
1270 #ifdef HAVE_FTBDF_H
1271               BDF_PropertyRec prop;
1272 #endif
1273
1274               g->lbearing = 0;
1275               g->rbearing = g->width = ft_face->available_sizes->width;
1276 #ifdef HAVE_FTBDF_H
1277               if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1278                 {
1279                   g->ascent = prop.u.integer;
1280                   FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1281                   g->descent = prop.u.integer;
1282                 }
1283               else
1284 #endif
1285                 {
1286                   g->ascent = ft_face->available_sizes->height;
1287                   g->descent = 0;
1288                 }
1289             }
1290         }
1291       else
1292         {
1293           FT_Glyph_Metrics *metrics;
1294
1295           FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1296           metrics = &ft_face->glyph->metrics;
1297           g->lbearing = (metrics->horiBearingX >> 6);
1298           g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1299           g->width = metrics->horiAdvance >> 6;
1300           g->ascent = metrics->horiBearingY >> 6;
1301           g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1302         }
1303     }
1304 }
1305
1306 static int
1307 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1308 {
1309   MRealizedFont *rfont = NULL;
1310   MRealizedFontFT *ft_rfont;
1311   FT_UInt idx;
1312
1313   if (font->type == MFONT_TYPE_REALIZED)
1314     rfont = (MRealizedFont *) font;
1315   else if (font->type == MFONT_TYPE_OBJECT)
1316     {
1317       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1318            rfont = rfont->next)
1319         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1320           break;
1321       if (! rfont)
1322         {
1323 #ifdef HAVE_FONTCONFIG
1324           MFontFT *ft_info = (MFontFT *) font;
1325
1326           if (! ft_info->charset)
1327             {
1328               FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1329                                                MSYMBOL_NAME (font->file),
1330                                                NULL);
1331               FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1332               FcFontSet *fs = FcFontList (fc_config, pat, os);
1333
1334               if (fs->nfont > 0
1335                   && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1336                                           &ft_info->charset) == FcResultMatch)
1337                 ft_info->charset = FcCharSetCopy (ft_info->charset);
1338               else
1339                 ft_info->charset = FcCharSetCreate ();
1340               FcFontSetDestroy (fs);
1341               FcObjectSetDestroy (os);
1342               FcPatternDestroy (pat);
1343             }
1344           return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1345 #else  /* not HAVE_FONTCONFIG */
1346           rfont = ft_open (frame, font, spec, NULL);
1347 #endif  /* not HAVE_FONTCONFIG */
1348         }
1349     }
1350   else
1351     MFATAL (MERROR_FONT_FT);
1352
1353   if (! rfont)
1354     return 0;
1355   ft_rfont = rfont->info;
1356   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1357   return (idx != 0);
1358 }
1359
1360 /* The FreeType font driver function ENCODE_CHAR.  */
1361
1362 static unsigned
1363 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1364 {
1365   MRealizedFont *rfont;
1366   MRealizedFontFT *ft_rfont;
1367   FT_UInt idx;
1368
1369   if (font->type == MFONT_TYPE_REALIZED)
1370     rfont = (MRealizedFont *) font;
1371   else if (font->type == MFONT_TYPE_OBJECT)
1372     {
1373       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1374            rfont = rfont->next)
1375         if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1376           break;
1377       if (! rfont)
1378         {
1379           rfont = ft_open (frame, font, spec, NULL);
1380           if (! rfont)
1381             return -1;
1382         }
1383     }
1384   else
1385     MFATAL (MERROR_FONT_FT);
1386
1387   ft_rfont = rfont->info;
1388   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1389   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1390 }
1391
1392 /* The FreeType font driver function RENDER.  */
1393
1394 #define NUM_POINTS 0x1000
1395
1396 typedef struct {
1397   MDrawPoint points[NUM_POINTS];
1398   MDrawPoint *p;
1399 } MPointTable;
1400
1401 static void
1402 ft_render (MDrawWindow win, int x, int y,
1403            MGlyphString *gstring, MGlyph *from, MGlyph *to,
1404            int reverse, MDrawRegion region)
1405 {
1406   FT_Face ft_face;
1407   MRealizedFace *rface = from->rface;
1408   MFrame *frame = rface->frame;
1409   FT_Int32 load_flags = FT_LOAD_RENDER;
1410   MGlyph *g;
1411   int i, j;
1412   MPointTable point_table[8];
1413
1414   if (from == to)
1415     return;
1416
1417   /* It is assured that the all glyphs in the current range use the
1418      same realized face.  */
1419   ft_face = rface->rfont->fontp;
1420
1421   if (! gstring->anti_alias)
1422     {
1423 #ifdef FT_LOAD_TARGET_MONO
1424       load_flags |= FT_LOAD_TARGET_MONO;
1425 #else
1426       load_flags |= FT_LOAD_MONOCHROME;
1427 #endif
1428     }
1429
1430   for (i = 0; i < 8; i++)
1431     point_table[i].p = point_table[i].points;
1432
1433   for (g = from; g < to; x += g++->width)
1434     {
1435       unsigned char *bmp;
1436       int intensity;
1437       MPointTable *ptable;
1438       int xoff, yoff;
1439       int width, pitch;
1440
1441       FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1442       yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1443       bmp = ft_face->glyph->bitmap.buffer;
1444       width = ft_face->glyph->bitmap.width;
1445       pitch = ft_face->glyph->bitmap.pitch;
1446       if (! gstring->anti_alias)
1447         pitch *= 8;
1448       if (width > pitch)
1449         width = pitch;
1450
1451       if (gstring->anti_alias)
1452         for (i = 0; i < ft_face->glyph->bitmap.rows;
1453              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1454           {
1455             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1456             for (j = 0; j < width; j++, xoff++)
1457               {
1458                 intensity = bmp[j] >> 5;
1459                 if (intensity)
1460                   {
1461                     ptable = point_table + intensity;
1462                     ptable->p->x = xoff;
1463                     ptable->p->y = yoff;
1464                     ptable->p++;
1465                     if (ptable->p - ptable->points == NUM_POINTS)
1466                       {
1467                         (*frame->driver->draw_points)
1468                           (frame, win, rface,
1469                            reverse ? 7 - intensity : intensity,
1470                            ptable->points, NUM_POINTS, region);
1471                         ptable->p = ptable->points;
1472                       }
1473                   }
1474               }
1475           }
1476       else
1477         for (i = 0; i < ft_face->glyph->bitmap.rows;
1478              i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1479           {
1480             xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1481             for (j = 0; j < width; j++, xoff++)
1482               {
1483                 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1484                 if (intensity)
1485                   {
1486                     ptable = point_table;
1487                     ptable->p->x = xoff;
1488                     ptable->p->y = yoff;
1489                     ptable->p++;
1490                     if (ptable->p - ptable->points == NUM_POINTS)
1491                       {
1492                         (*frame->driver->draw_points) (frame, win, rface,
1493                                            reverse ? 0 : 7,
1494                                            ptable->points, NUM_POINTS, region);
1495                         ptable->p = ptable->points;
1496                       }             
1497                   }
1498               }
1499         }
1500     }
1501
1502   if (gstring->anti_alias)
1503     {
1504       for (i = 1; i < 8; i++)
1505         if (point_table[i].p != point_table[i].points)
1506           (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1507                              point_table[i].points,
1508                              point_table[i].p - point_table[i].points, region);
1509     }
1510   else
1511     {
1512       if (point_table[0].p != point_table[0].points)
1513         (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1514                            point_table[0].points,
1515                            point_table[0].p - point_table[0].points, region);
1516     }
1517 }
1518
1519 static int
1520 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1521 {
1522   MPlist *pl = NULL, *p;
1523   int num = 0;
1524   MPlist *file_list = NULL;
1525   MPlist *family_list = NULL, *capability_list = NULL;
1526   MSymbol registry = Mnil;
1527
1528   MDEBUG_PRINT2 (" [FONT-FT] listing %s%s...",
1529                  FONT_PROPERTY (font, MFONT_FAMILY)
1530                  ? msymbol_name (FONT_PROPERTY (font, MFONT_FAMILY)) : "*",
1531                  font->capability ? msymbol_name (font->capability) : "");
1532
1533   if (font)
1534     {
1535       MSymbol family;
1536
1537       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1538       if (registry != Mnil)
1539         {
1540           char *reg = MSYMBOL_NAME (registry);
1541
1542           if (strncmp (reg, "unicode-", 8)
1543               && strncmp (reg, "apple-roman", 11)
1544               && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1545             goto done;
1546         }
1547
1548       if (font->file != Mnil
1549           && ! (file_list = ft_list_file (font->file)))
1550         goto done;
1551       family = FONT_PROPERTY (font, MFONT_FAMILY);
1552       if (family != Mnil
1553           && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1554           && MPLIST_TAIL_P (family_list))
1555         goto done;
1556       if (font->capability != Mnil
1557           && (capability_list = ft_list_capability (font->capability))
1558           && MPLIST_TAIL_P (capability_list))
1559         goto done;
1560     }
1561
1562   if (! file_list && ! family_list && ! capability_list)
1563     {
1564       /* No restriction.  Get all fonts.  */
1565       pl = mplist ();
1566       MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1567         {
1568           MPLIST_DO (p, MPLIST_PLIST (family_list))
1569             mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1570         }
1571     }
1572   else
1573     {
1574       if (file_list)
1575         {
1576           pl = mplist ();
1577           mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1578         }
1579       if (family_list)
1580         {
1581           if (pl)
1582             for (p = pl; ! MPLIST_TAIL_P (p);)
1583               {
1584                 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1585                   p = MPLIST_NEXT (p);
1586                 else
1587                   mplist_pop (p);
1588               }
1589           else
1590             {
1591               pl = mplist ();
1592               MPLIST_DO (p, family_list)
1593                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1594             }
1595         }
1596       if (capability_list)
1597         {
1598           if (pl)
1599             for (p = pl; ! MPLIST_TAIL_P (p);)
1600               {
1601                 MFontFT *ft_info = MPLIST_VAL (p);
1602                 
1603                 if (mplist_find_by_value (capability_list, ft_info))
1604                   p = MPLIST_NEXT (p);
1605                 else
1606                   mplist_pop (p);
1607               }
1608           else
1609             {
1610               pl = mplist ();
1611               MPLIST_DO (p, capability_list)
1612                 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1613             }
1614         }
1615     }
1616               
1617   if (font)
1618     {
1619       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1620       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1621       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1622       int size = font->size;
1623
1624       if (weight != Mnil || style != Mnil || stretch != Mnil || size > 0)
1625         for (p = pl; ! MPLIST_TAIL_P (p); )
1626           {
1627             MFontFT *ft_info = MPLIST_VAL (p);
1628
1629             if ((weight != Mnil
1630                  && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1631                 || (style != Mnil
1632                     && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1633                 || (stretch != Mnil
1634                     && stretch != FONT_PROPERTY (&ft_info->font,
1635                                                  MFONT_STRETCH))
1636                 || (size > 0
1637                     && ft_info->font.size > 0
1638                     && ft_info->font.size != size))
1639               mplist_pop (p);
1640             else
1641               p = MPLIST_NEXT (p);
1642           }
1643     }
1644
1645   MPLIST_DO (p, pl)
1646     {
1647       plist = mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1648       num++;
1649       if (maxnum && maxnum <= num)
1650         break;
1651     }
1652   M17N_OBJECT_UNREF (pl);
1653
1654  done:
1655   MDEBUG_PRINT1 (" %d found\n", num);
1656   return num;
1657 }
1658
1659 \f
1660 /* Internal API */
1661
1662 MFontDriver mfont__ft_driver =
1663   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1664     ft_render, ft_list };
1665
1666 int
1667 mfont__ft_init ()
1668 {
1669   int i;
1670
1671   if (FT_Init_FreeType (&ft_library) != 0)
1672     MERROR (MERROR_FONT_FT, -1);
1673
1674   for (i = 0; i < ft_to_prop_size; i++)
1675     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1676
1677   Mmedium = msymbol ("medium");
1678   Mr = msymbol ("r");
1679   Mnull = msymbol ("");
1680
1681   M0_3 = msymbol ("0-3");
1682   M3_1 = msymbol ("3-1");
1683   M1_0 = msymbol ("1-0");
1684
1685 #ifdef HAVE_FONTCONFIG
1686   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1687     {
1688       FC_vs_M17N_font_prop *table = fc_all_table[i];
1689       int j;
1690
1691       for (j = 0; table[j].m17n_value; j++)
1692         table[j].sym = msymbol (table[j].m17n_value);
1693       table[j].sym = table[j - 1].sym;
1694     }
1695
1696   {
1697     char *pathname;
1698     struct stat buf;
1699     MPlist *plist;
1700     MSymbol serif, sans_serif, monospace;
1701
1702     fc_config = FcInitLoadConfigAndFonts ();
1703     if (mfont_freetype_path)
1704       {
1705         MPLIST_DO (plist, mfont_freetype_path)
1706           if (MPLIST_STRING_P (plist)
1707               && (pathname = MPLIST_STRING (plist))
1708               && stat (pathname, &buf) == 0)
1709             {
1710               FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1711               FcChar8 *dir;
1712
1713               while ((dir = FcStrListNext (strlist)))
1714                 if (strcmp ((char *) dir, pathname) == 0)
1715                   break;
1716               if (! dir)
1717                 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1718               FcStrListDone (strlist);
1719             }
1720       }
1721     Mgeneric_family = msymbol ("generic famly");
1722     serif = msymbol ("serif");
1723     msymbol_put (serif, Mgeneric_family, serif);
1724     sans_serif = msymbol ("sans-serif");
1725     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1726     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1727     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1728     monospace = msymbol ("monospace");
1729     msymbol_put (monospace, Mgeneric_family, monospace);
1730     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1731   }
1732 #endif
1733
1734   return 0;
1735 }
1736
1737 void
1738 mfont__ft_fini ()
1739 {
1740   MPlist *plist, *p;
1741
1742   if (ft_font_list)
1743     {
1744       MPLIST_DO (plist, ft_font_list)
1745         {
1746           if (MPLIST_VAL (plist))
1747             MPLIST_DO (p, MPLIST_VAL (plist))
1748               {
1749                 if (MPLIST_KEY (p) != Mt)
1750                   free_ft_info (MPLIST_VAL (p));
1751               }
1752           M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1753         }
1754       M17N_OBJECT_UNREF (ft_font_list);
1755
1756       if (ft_language_list)
1757         {
1758           MPLIST_DO (plist, ft_language_list)
1759             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1760           M17N_OBJECT_UNREF (ft_language_list);
1761         }
1762
1763       if (ft_script_list)
1764         {
1765           MPLIST_DO (plist, ft_script_list)
1766             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1767           M17N_OBJECT_UNREF (ft_script_list);
1768         }
1769
1770       if (ft_capability_list)
1771         {
1772           MPLIST_DO (plist, ft_capability_list)
1773             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1774           M17N_OBJECT_UNREF (ft_capability_list);
1775         }
1776
1777       if (ft_file_list)
1778         {
1779           MPLIST_DO (plist, ft_file_list)
1780             M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1781           M17N_OBJECT_UNREF (ft_file_list);
1782         }
1783
1784     }
1785   FT_Done_FreeType (ft_library);
1786 #ifdef HAVE_FONTCONFIG
1787   FcConfigDestroy (fc_config);
1788   fc_config = NULL;
1789 #endif  /* HAVE_FONTCONFIG */
1790   all_fonts_scaned = 0;
1791 }
1792
1793 #ifdef HAVE_FONTCONFIG
1794
1795 int
1796 mfont__ft_parse_name (const char *name, MFont *font)
1797 {
1798   FcPattern *pat = FcNameParse ((FcChar8 *) name);
1799   FcChar8 *str;
1800   int val;
1801   double size;
1802   char *buf;
1803   int bufsize = 0;
1804   
1805   if (! pat)
1806     return -1;
1807   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1808     {
1809       STRDUP_LOWER (buf, bufsize, (char *) str);
1810       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1811     }
1812   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1813     {
1814       STRDUP_LOWER (buf, bufsize, (char *) str);
1815       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1816     }
1817   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1818     mfont__set_property (font, MFONT_WEIGHT,
1819                          fc_decode_prop (val, fc_weight_table,
1820                                          fc_weight_table_size));
1821   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1822     mfont__set_property (font, MFONT_STYLE,
1823                          fc_decode_prop (val, fc_slant_table,
1824                                          fc_slant_table_size));
1825   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1826     mfont__set_property (font, MFONT_STRETCH,
1827                          fc_decode_prop (val, fc_width_table,
1828                                          fc_width_table_size));
1829   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1830     font->size = size * 10 + 0.5;
1831   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1832     font->size = - (size * 10 + 0.5);
1833   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1834     {
1835       font->file = msymbol ((char *) str);
1836     }
1837   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1838   font->type = MFONT_TYPE_SPEC;
1839   FcPatternDestroy (pat);
1840   return 0;
1841 }
1842
1843 char *
1844 mfont__ft_unparse_name (MFont *font)
1845 {
1846   FcPattern *pat = fc_get_pattern (font);
1847   char *name = (char *) FcNameUnparse (pat);
1848
1849   FcPatternDestroy (pat);
1850   return name;
1851 }
1852 #endif  /* HAVE_FONTCONFIG */
1853
1854 \f
1855 #ifdef HAVE_OTF
1856
1857 #define DEVICE_DELTA(table, size)                               \
1858   (((size) >= (table).StartSize && (size) <= (table).EndSize)   \
1859    ? (table).DeltaValue[(size) >= (table).StartSize]            \
1860    : 0)
1861
1862 void
1863 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1864                unsigned code, int size, int *x, int *y)
1865 {
1866   if (anchor->AnchorFormat == 2)
1867     {
1868       FT_Outline *outline;
1869       int ap = anchor->f.f1.AnchorPoint;
1870
1871       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1872       outline = &ft_face->glyph->outline;
1873       if (ap < outline->n_points)
1874         {
1875           *x = outline->points[ap].x;
1876           *y = outline->points[ap].y;
1877         }
1878     }
1879   else if (anchor->AnchorFormat == 3)
1880     {
1881       if (anchor->f.f2.XDeviceTable.offset)
1882         *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1883       if (anchor->f.f2.YDeviceTable.offset)
1884       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1885     }
1886 }
1887
1888 int
1889 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1890                      MFontCapability *cap)
1891 {
1892   int len = to - from;
1893   MGlyph *g = MGLYPH (from);
1894   int i, gidx;
1895   MRealizedFont *rfont;
1896   MFontFT *ft_info;
1897   OTF *otf;
1898   OTF_GlyphString otf_gstring;
1899   OTF_Glyph *otfg;
1900   char *script, *langsys;
1901   char *gsub_features, *gpos_features;
1902   int need_cmap;
1903
1904   if (len == 0)
1905     return from;
1906
1907   otf_gstring.glyphs = NULL;
1908   rfont = g->rface->rfont;
1909   ft_info = (MFontFT *) rfont->font;
1910   if (ft_info->otf == invalid_otf)
1911     goto simple_copy;
1912   otf = ft_info->otf;
1913   if (! otf)
1914     {
1915       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1916       if (! otf)
1917         {
1918           ft_info->otf = invalid_otf;
1919           goto simple_copy;
1920         }
1921       ft_info->otf = otf;
1922     }
1923   if (OTF_get_table (otf, "head") < 0)
1924     {
1925       OTF_close (otf);
1926       ft_info->otf = invalid_otf;
1927       goto simple_copy;
1928     }
1929
1930   if (cap->script_tag)
1931     {
1932       script = alloca (5);
1933       OTF_tag_name (cap->script_tag, script);
1934     }
1935   else
1936     script = NULL;
1937   if (cap->langsys_tag)
1938     {
1939       langsys = alloca (5);
1940       OTF_tag_name (cap->langsys_tag, langsys);
1941     }
1942   else
1943     langsys = NULL;
1944   gsub_features = cap->features[MFONT_OTT_GSUB].str;
1945   if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
1946     gsub_features = NULL;
1947   gpos_features = cap->features[MFONT_OTT_GPOS].str;
1948   if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
1949     gpos_features = NULL;
1950
1951   otf_gstring.size = otf_gstring.used = len;
1952   otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1953   memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1954   for (i = 0, need_cmap = 0; i < len; i++)
1955     {
1956       if (gstring->glyphs[from + i].otf_encoded)
1957         {
1958           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1959           otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1960         }
1961       else
1962         {
1963           otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1964           need_cmap++;
1965         }
1966     }
1967   if (need_cmap
1968       && OTF_drive_cmap (otf, &otf_gstring) < 0)
1969     goto simple_copy;
1970
1971   OTF_drive_gdef (otf, &otf_gstring);
1972   gidx = gstring->used;
1973
1974   if (gsub_features)
1975     {
1976       if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1977           < 0)
1978         goto simple_copy;
1979       for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1980         {
1981           MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1982
1983           temp.c = otfg->c;
1984           temp.combining_code = 0;
1985           if (otfg->glyph_id)
1986             {
1987               temp.code = otfg->glyph_id;
1988               temp.otf_encoded = 1;
1989             }
1990           else
1991             {
1992               temp.code = temp.c;
1993               temp.otf_encoded = 0;
1994             }
1995           temp.to = MGLYPH (from + otfg->f.index.to)->to;
1996           MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1997         }
1998     }
1999   else
2000     for (i = 0; i < len; i++)
2001       {
2002         MGlyph temp = gstring->glyphs[from + i];
2003
2004         if (otf_gstring.glyphs[i].glyph_id)
2005           {
2006             temp.code = otf_gstring.glyphs[i].glyph_id;
2007             temp.otf_encoded = 1;
2008           }
2009         MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2010       }
2011
2012   (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2013
2014   if (gpos_features)
2015     {
2016       int u;
2017       int size10, size;
2018       MGlyph *base = NULL, *mark = NULL;
2019
2020       if (OTF_check_features (otf, 1,
2021                               cap->script_tag, cap->langsys_tag,
2022                               cap->features[MFONT_OTT_GPOS].tags,
2023                               cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2024           || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2025                               gpos_features) < 0))
2026         return to;
2027
2028       u = otf->head->unitsPerEm;
2029       size10 = rfont->spec.size;
2030       size = size10 / 10;
2031
2032       for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2033            i < otf_gstring.used; i++, otfg++, g++)
2034         {
2035           MGlyph *prev;
2036
2037           if (! otfg->glyph_id)
2038             continue;
2039           switch (otfg->positioning_type)
2040             {
2041             case 0:
2042               break;
2043             case 1: case 2:
2044               {
2045                 int format = otfg->f.f1.format;
2046
2047                 if (format & OTF_XPlacement)
2048                   g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2049                 if (format & OTF_XPlaDevice)
2050                   g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2051                 if (format & OTF_YPlacement)
2052                   g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2053                 if (format & OTF_YPlaDevice)
2054                   g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2055                 if (format & OTF_XAdvance)
2056                   g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2057                 if (format & OTF_XAdvDevice)
2058                   g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2059               }
2060               break;
2061             case 3:
2062               /* Not yet supported.  */
2063               break;
2064             case 4: case 5:
2065               if (! base)
2066                 break;
2067               prev = base;
2068               goto label_adjust_anchor;
2069             default:            /* i.e. case 6 */
2070               if (! mark)
2071                 break;
2072               prev = mark;
2073
2074             label_adjust_anchor:
2075               {
2076                 int base_x, base_y, mark_x, mark_y;
2077
2078                 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2079                 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2080                 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2081                 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2082
2083                 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2084                   adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2085                                  prev->code, size, &base_x, &base_y);
2086                 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2087                   adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2088                                  g->code, size, &mark_x, &mark_y);
2089                 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2090                 g->yoff = prev->yoff + mark_y - base_y;
2091                 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2092               }
2093             }
2094           if (otfg->GlyphClass == OTF_GlyphClass0)
2095             base = mark = g;
2096           else if (otfg->GlyphClass == OTF_GlyphClassMark)
2097             mark = g;
2098           else
2099             base = g;
2100         }
2101     }
2102   free (otf_gstring.glyphs);
2103   return to;
2104
2105  simple_copy:
2106   ft_find_metric (rfont, gstring, from, to);
2107   for (i = 0; i < len; i++)
2108     {
2109       MGlyph temp = gstring->glyphs[from + i];
2110       MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2111     }
2112   if (otf_gstring.glyphs)
2113     free (otf_gstring.glyphs);
2114   return to;
2115 }
2116
2117
2118 int
2119 mfont__ft_decode_otf (MGlyph *g)
2120 {
2121   MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2122   int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2123
2124   return (c ? c : -1);
2125 }
2126
2127 #endif  /* HAVE_OTF */
2128
2129 #endif /* HAVE_FREETYPE */