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