1 /* font-ft.c -- FreeType interface sub-module.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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., 51 Franklin Street, Fifth Floor,
21    Boston, MA 02110-1301 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-flt.h"
41 #include "internal-gui.h"
42 #include "font.h"
43 #include "face.h"
44 
45 #ifdef HAVE_FREETYPE
46 
47 #ifdef HAVE_FTBDF_H
48 #include FT_BDF_H
49 #endif
50 
51 static int mdebug_flag = MDEBUG_FONT;
52 
53 #ifdef HAVE_FONTCONFIG
54 #include <fontconfig/fcfreetype.h>
55 
56 static FcConfig *fc_config;
57 static MSymbol Mgeneric_family;
58 #endif	/* HAVE_FONTCONFIG */
59 
60 /* Font properties; Mnormal is already defined in face.c.  */
61 static MSymbol Mmedium, Mr, Mnull;
62 
63 static MSymbol M0[5], M3_1, M1_0;
64 
65 static FT_Library ft_library;
66 
67 #ifdef HAVE_OTF
68 static OTF *invalid_otf = (OTF *) "";
69 static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
70 #endif /* HAVE_OTF */
71 
72 typedef struct
73 {
74   MFont font;
75 #ifdef HAVE_OTF
76   /* NULL if not yet opened.  invalid_otf if not OTF.  */
77   OTF *otf;
78 #endif /* HAVE_OTF */
79 #ifdef HAVE_FONTCONFIG
80   FcLangSet *langset;
81   FcCharSet *charset;
82 #endif	/* HAVE_FONTCONFIG */
83 } MFontFT;
84 
85 typedef struct
86 {
87   M17NObject control;
88   FT_Face ft_face;		/* This must be the 2nd member. */
89   MPlist *charmap_list;
90   int face_encapsulated;
91 } MRealizedFontFT;
92 
93 typedef struct
94 {
95   char *ft_style;
96   int len;
97   enum MFontProperty prop;
98   char *val;
99 } MFTtoProp;
100 
101 static MFTtoProp ft_to_prop[] =
102   { { "italic", 0, MFONT_STYLE, "i" },
103     { "roman", 0, MFONT_STYLE, "r" },
104     { "oblique", 0, MFONT_STYLE, "o" },
105     { "regular", 0, MFONT_WEIGHT, "normal" },
106     { "normal", 0, MFONT_WEIGHT, "normal" },
107     /* We need this entry even if "bold" is in commone_weight[] to
108        handle such style names as "bolditalic" and "boldoblique".  */
109     { "bold", 0, MFONT_WEIGHT, "bold" },
110     { "demi bold", 0, MFONT_WEIGHT, "demibold" },
111     { "demi", 0, MFONT_WEIGHT, "demibold" } };
112 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
113 
114 /** List of FreeType fonts.  Keys are family names, values are plists
115     containing fonts of the corresponding family.  In the deeper
116     plist, keys are file names, values are (MFontFT *).  */
117 static MPlist *ft_font_list;
118 
119 /** List of FreeType fonts.  Keys are script names, values are plists
120     containing fonts supporting the corresponding script.  In the
121     deeper plist, keys are family names, values are (MFontFT *).  */
122 static MPlist *ft_script_list;
123 
124 /** List of FreeType fonts.  Keys are language names, values are
125     plists containing fonts supporting the corresponding language.  In
126     the deeper plist, keys are family names, values are (MFontFT *).  */
127 static MPlist *ft_language_list;
128 
129 static MPlist *ft_file_list;
130 
131 static int all_fonts_scaned;
132 
133 #define STRDUP_LOWER(s1, size, s2)				\
134   do {								\
135     int len = strlen (s2) + 1;					\
136     char *p1, *p2;						\
137 								\
138     if ((size) < len)						\
139       (s1) = alloca (len), (size) = len;			\
140     for (p1 = (s1), p2 = (s2); *p2; p1++, p2++)			\
141       *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2);	\
142     *p1 = '\0';							\
143   } while (0)
144 
145 
146 static MPlist *ft_list_family (MSymbol, int, int);
147 
148 static void
free_ft_rfont(void * object)149 free_ft_rfont (void *object)
150 {
151   MRealizedFontFT *ft_rfont = object;
152 
153   if (! ft_rfont->face_encapsulated)
154     {
155       M17N_OBJECT_UNREF (ft_rfont->charmap_list);
156       FT_Done_Face (ft_rfont->ft_face);
157     }
158   free (ft_rfont);
159 }
160 
161 static void
free_ft_info(MFontFT * ft_info)162 free_ft_info (MFontFT *ft_info)
163 {
164 #ifdef HAVE_OTF
165   if (ft_info->otf && ft_info->otf != invalid_otf)
166     OTF_close (ft_info->otf);
167 #endif /* HAVE_OTF */
168 #ifdef HAVE_FONTCONFIG
169   if (ft_info->langset)
170     FcLangSetDestroy (ft_info->langset);
171   if (ft_info->charset)
172     FcCharSetDestroy (ft_info->charset);
173 #endif	/* HAVE_FONTCONFIG */
174   free (ft_info);
175 }
176 
177 static MPlist *
ft_get_charmaps(FT_Face ft_face)178 ft_get_charmaps (FT_Face ft_face)
179 {
180   MPlist *plist = mplist ();
181   int unicode_bmp = -1, unicode_full = -1;
182   int i;
183 
184   mplist_add (plist, Mt, (void *) -1);
185   for (i = 0; i < ft_face->num_charmaps; i++)
186     {
187       MSymbol registry = Mnil;
188 
189       if (ft_face->charmaps[i]->platform_id == 0)
190 	{
191 	  if (ft_face->charmaps[i]->encoding_id <= 4)
192 	    registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
193 	  if (ft_face->charmaps[i]->encoding_id == 4)
194 	    unicode_bmp = unicode_full = i;
195 	}
196       else if (ft_face->charmaps[i]->platform_id == 3)
197 	{
198 	  if (ft_face->charmaps[i]->encoding_id == 1)
199 	    registry = M3_1, unicode_bmp = i;
200 	  else if (ft_face->charmaps[i]->encoding_id == 10)
201 	    unicode_bmp = unicode_full = i;
202 	}
203       else if (ft_face->charmaps[i]->platform_id == 1
204 	       && ft_face->charmaps[i]->encoding_id == 0)
205 	{
206 	  registry = M1_0;
207 	  mplist_add (plist, Mapple_roman, (void *) i);
208 	}
209       if (registry == Mnil)
210 	{
211 	  char registry_buf[16];
212 
213 	  sprintf (registry_buf, "%d-%d",
214 		   ft_face->charmaps[i]->platform_id,
215 		   ft_face->charmaps[i]->encoding_id);
216 	  registry = msymbol (registry_buf);
217 	}
218       mplist_add (plist, registry, (void *) i);
219     }
220   if (unicode_full >= 0)
221     mplist_add (plist, Municode_full, (void *) unicode_full);
222   if (unicode_bmp >= 0)
223     {
224       int i;
225 
226       mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
227       FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
228       for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
229       if (i == 0x7F)
230 	{
231 	  for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
232 	  if (i == 0x100)
233 	    mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
234 	}
235     }
236 
237   return plist;
238 }
239 
240 static MFontFT *
ft_gen_font(FT_Face ft_face)241 ft_gen_font (FT_Face ft_face)
242 {
243   MFontFT *ft_info;
244   MFont *font;
245   char *buf;
246   int bufsize = 0;
247   char *stylename;
248   MSymbol family;
249   int size;
250 
251   if (FT_IS_SCALABLE (ft_face))
252     size = ft_face->size->metrics.y_ppem;
253   else if (ft_face->num_fixed_sizes == 0)
254     return NULL;
255   else
256     size = ft_face->available_sizes[0].height;
257 
258   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
259   font = &ft_info->font;
260   STRDUP_LOWER (buf, bufsize, ft_face->family_name);
261   family = msymbol (buf);
262   mfont__set_property (font, MFONT_FAMILY, family);
263   mfont__set_property (font, MFONT_WEIGHT, Mmedium);
264   mfont__set_property (font, MFONT_STYLE, Mr);
265   mfont__set_property (font, MFONT_STRETCH, Mnormal);
266   mfont__set_property (font, MFONT_ADSTYLE, Mnull);
267   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
268   font->size = size * 10;
269   font->type = MFONT_TYPE_OBJECT;
270   font->source = MFONT_SOURCE_FT;
271   font->file = NULL;
272 
273   stylename = ft_face->style_name;
274   while (*stylename)
275     {
276       int i;
277 
278       for (i = 0; i < ft_to_prop_size; i++)
279 	if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
280 			   ft_to_prop[i].len))
281 	  {
282 	    mfont__set_property (font, ft_to_prop[i].prop,
283 				 msymbol (ft_to_prop[i].val));
284 	    stylename += ft_to_prop[i].len;
285 	    break;
286 	  }
287       if (i == ft_to_prop_size)
288 	{
289 	  char *p1 = stylename + 1;
290 	  MSymbol sym;
291 
292 	  while (*p1 >= 'a' && *p1 <= 'z') p1++;
293 	  sym = msymbol__with_len (stylename, p1 - stylename);
294 	  for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
295 	    if (msymbol_get (sym, mfont__property_table[i].property))
296 	      {
297 		mfont__set_property (font, i, sym);
298 		break;
299 	      }
300 	  stylename = p1;
301 	}
302       while (*stylename && ! isalpha (*stylename))
303 	stylename++;
304     }
305   return ft_info;
306 }
307 
308 #ifdef HAVE_FONTCONFIG
309 
310 typedef struct
311 {
312   int fc_value;
313   char *m17n_value;
314   MSymbol sym;
315 } FC_vs_M17N_font_prop;
316 
317 static FC_vs_M17N_font_prop fc_weight_table[] =
318   { { FC_WEIGHT_THIN, "thin" },
319     { FC_WEIGHT_ULTRALIGHT, "extralight" },
320     { FC_WEIGHT_LIGHT, "light" },
321 #ifdef FC_WEIGHT_BOOK
322     { FC_WEIGHT_BOOK, "book" },
323 #endif	/* FC_WEIGHT_BOOK */
324     { FC_WEIGHT_REGULAR, "normal" },
325     { FC_WEIGHT_NORMAL, "normal" },
326     { FC_WEIGHT_MEDIUM, "medium" },
327     { FC_WEIGHT_DEMIBOLD, "demibold" },
328     { FC_WEIGHT_BOLD, "bold" },
329     { FC_WEIGHT_EXTRABOLD, "extrabold" },
330     { FC_WEIGHT_BLACK, "black" },
331     { FC_WEIGHT_HEAVY, "heavy" },
332     { FC_WEIGHT_MEDIUM, NULL } };
333 int fc_weight_table_size =
334   sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
335 
336 static FC_vs_M17N_font_prop fc_slant_table[] =
337   { { FC_SLANT_ROMAN, "r" },
338     { FC_SLANT_ITALIC, "i" },
339     { FC_SLANT_OBLIQUE, "o" },
340     { FC_SLANT_ROMAN, NULL } };
341 int fc_slant_table_size =
342   sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
343 
344 static FC_vs_M17N_font_prop fc_width_table[] =
345   { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
346     { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
347     { FC_WIDTH_CONDENSED, "condensed" },
348     { FC_WIDTH_SEMICONDENSED, "semicondensed" },
349     { FC_WIDTH_NORMAL, "normal" },
350     { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
351     { FC_WIDTH_EXPANDED, "expanded" },
352     { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
353     { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
354     { FC_WIDTH_NORMAL, NULL } };
355 int fc_width_table_size =
356   sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
357 
358 
359 static FC_vs_M17N_font_prop *fc_all_table[] =
360   { fc_weight_table, fc_slant_table, fc_width_table };
361 
362 static MSymbol
fc_decode_prop(int val,FC_vs_M17N_font_prop * table,int size)363 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
364 {
365   int i = size / 2;
366 
367   if (val < table[i].fc_value)
368     {
369       for (i--; i >= 0; i--)
370 	if (val > table[i].fc_value)
371 	  break;
372       i++;
373     }
374   else if (val > table[i].fc_value)
375     {
376       for (i++; i < size; i++)
377 	if (val < table[i].fc_value)
378 	  break;
379       i--;
380     }
381   return table[i].sym;
382 }
383 
384 static int
fc_encode_prop(MSymbol sym,FC_vs_M17N_font_prop * table)385 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
386 {
387   int i;
388 
389   for (i = 0; table[i].m17n_value; i++)
390     if (table[i].sym == sym)
391       break;
392   return table[i].fc_value;
393 }
394 
395 FcPattern *
fc_get_pattern(MFont * font)396 fc_get_pattern (MFont *font)
397 {
398   FcPattern *pat = FcPatternCreate ();
399   MSymbol sym, weight, style, stretch;
400 
401 
402   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
403     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
404   if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
405     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
406   if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
407     FcPatternAddInteger (pat, FC_WEIGHT,
408 			 fc_encode_prop (weight, fc_weight_table));
409   if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
410     FcPatternAddInteger (pat, FC_SLANT,
411 			 fc_encode_prop (style, fc_slant_table));
412   if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
413     FcPatternAddInteger (pat, FC_WIDTH,
414 			 fc_encode_prop (stretch, fc_width_table));
415   if (font->size > 0)
416     {
417       double size = font->size;
418       FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
419     }
420   else if (font->size < 0)
421     {
422       double size = - font->size;
423       FcPatternAddDouble (pat, FC_SIZE, size / 10);
424     }
425   return pat;
426 }
427 
428 static void
fc_parse_pattern(FcPattern * pat,char * family,MFontFT * ft_info)429 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
430 {
431   FcChar8 *str;
432   int val;
433   double size;
434   char *buf;
435   int bufsize = 0;
436   MSymbol sym;
437   FcLangSet *ls;
438   FcCharSet *cs;
439   MFont *font = &ft_info->font;
440 
441   MFONT_INIT (font);
442   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
443     {
444       STRDUP_LOWER (buf, bufsize, (char *) str);
445       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
446     }
447   if (family)
448     mfont__set_property (font, MFONT_FAMILY, msymbol (family));
449   else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
450     {
451       STRDUP_LOWER (buf, bufsize, (char *) str);
452       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
453     }
454   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
455     {
456       sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
457       mfont__set_property (font, MFONT_WEIGHT, sym);
458     }
459   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
460     {
461       sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
462       mfont__set_property (font, MFONT_STYLE, sym);
463     }
464   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
465     {
466       sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
467       mfont__set_property (font, MFONT_STRETCH, sym);
468     }
469   if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
470     {
471       if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
472 	  || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
473 	  || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
474 	font->for_full_width = 1;
475       ft_info->langset = FcLangSetCopy (ls);
476     }
477   if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
478     ft_info->charset = FcCharSetCopy (cs);
479 
480   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
481   font->type = MFONT_TYPE_SPEC;
482   font->source = MFONT_SOURCE_FT;
483   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
484     font->size = size * 10;
485   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
486     font->file = msymbol ((char *) str);
487 }
488 
489 
490 static MFontFT *
fc_gen_font(FcPattern * pat,char * family)491 fc_gen_font (FcPattern *pat, char *family)
492 {
493   MFontFT *ft_info;
494 
495   MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
496   fc_parse_pattern (pat, family, ft_info);
497   ft_info->font.type = MFONT_TYPE_OBJECT;
498   return ft_info;
499 }
500 
501 static void
fc_init_font_list(void)502 fc_init_font_list (void)
503 {
504   FcPattern *pattern = FcPatternCreate ();
505   FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
506   FcFontSet *fs = FcFontList (fc_config, pattern, os);
507   MPlist *plist = mplist ();
508   char *buf;
509   int bufsize = 0;
510   int i;
511 
512   ft_font_list = plist;
513   for (i = 0; i < fs->nfont; i++)
514     {
515       char *fam;
516 
517       if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
518 			      (FcChar8 **) &fam) != FcResultMatch)
519 	continue;
520       STRDUP_LOWER (buf, bufsize, fam);
521       plist = mplist_add (plist, msymbol (buf), NULL);
522     }
523   FcFontSetDestroy (fs);
524   FcObjectSetDestroy (os);
525   FcPatternDestroy (pattern);
526 }
527 
528 static MPlist *
fc_list_pattern(FcPattern * pattern)529 fc_list_pattern (FcPattern *pattern)
530 {
531   FcObjectSet *os = NULL;
532   FcFontSet *fs = NULL;
533   MSymbol last_family = Mnil;
534   MPlist *plist = NULL, *pl = NULL;
535   char *buf;
536   int bufsize = 0;
537   int i;
538 
539   if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
540     goto err;
541   if (! (fs = FcFontList (fc_config, pattern, os)))
542     goto err;
543 
544   for (i = 0; i < fs->nfont; i++)
545     {
546       MSymbol family, file;
547       char *fam, *filename;
548       MFontFT *ft_info;
549 
550       if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
551 			      (FcChar8 **) &fam) != FcResultMatch)
552 	continue;
553       if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
554 			      (FcChar8 **) &filename) != FcResultMatch)
555 	continue;
556       STRDUP_LOWER (buf, bufsize, fam);
557       family = msymbol (buf);
558       file = msymbol (filename);
559       if (family != last_family)
560 	{
561 	  pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
562 	  last_family = family;
563 	}
564       ft_info = mplist_get (pl, file);
565       if (ft_info)
566 	{
567 	  if (! plist)
568 	    plist = mplist ();
569 	  mplist_add (plist, family, ft_info);
570 	}
571     }
572 
573  err:
574   if (fs) FcFontSetDestroy (fs);
575   if (os) FcObjectSetDestroy (os);
576   return plist;
577 }
578 
579 /* Return FcCharSet object built from CHAR_LIST or MT.  In the latter
580    case, it is assured that the M-text contains at least one
581    character.  */
582 
583 static FcCharSet *
fc_build_charset(MPlist * char_list,MText * mt)584 fc_build_charset (MPlist *char_list, MText *mt)
585 {
586   FcCharSet *cs = FcCharSetCreate ();
587 
588   if (! cs)
589     return NULL;
590   if (char_list)
591     {
592       for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
593 	if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
594 	  {
595 	    FcCharSetDestroy (cs);
596 	    return NULL;
597 	  }
598     }
599   else
600     {
601       int i;
602 
603       for (i = mtext_nchars (mt) - 1; i >= 0; i--)
604 	if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
605 	  {
606 	    FcCharSetDestroy (cs);
607 	    return NULL;
608 	  }
609       if (mtext_nchars (mt) > 0
610 	  && (mt = mtext_get_prop (mt, 0, Mtext)))
611 	for (i = mtext_nchars (mt) - 1; i >= 0; i--)
612 	  if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
613 	    {
614 	      FcCharSetDestroy (cs);
615 	      return NULL;
616 	    }
617       }
618   return cs;
619 }
620 
621 #else	/* not HAVE_FONTCONFIG */
622 
623 static MPlist *
ft_add_font(char * filename)624 ft_add_font (char *filename)
625 {
626   FT_Face ft_face;
627   char *stylename;
628   int size = 0;
629   MSymbol family;
630   MFontFT *ft_info;
631   MFont *font;
632   MPlist *plist;
633   int i;
634   char *buf;
635   int bufsize = 0;
636 
637   if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
638     return NULL;
639   ft_info = ft_gen_font (ft_face);
640   FT_Done_Face (ft_face);
641   if (! ft_info)
642     return NULL;
643 
644   font = &ft_info->font;
645   font->file = msymbol (filename);
646 
647   plist = mplist_find_by_key (ft_font_list, family);
648   if (plist)
649     mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
650   else
651     {
652       plist = mplist ();
653       mplist_add (plist, font->file, ft_info);
654       plist = mplist_push (ft_font_list, family, plist);
655     }
656   return plist;
657 }
658 
659 static void
ft_init_font_list(void)660 ft_init_font_list (void)
661 {
662   MPlist *plist;
663   struct stat buf;
664   char *pathname;
665   char *path;
666   USE_SAFE_ALLOCA;
667 
668   ft_font_list = mplist ();
669   MPLIST_DO (plist, mfont_freetype_path)
670     if (MPLIST_STRING_P (plist)
671 	&& (pathname = MPLIST_STRING (plist))
672 	&& stat (pathname, &buf) == 0)
673       {
674 	if (S_ISREG (buf.st_mode))
675 	  ft_add_font (pathname);
676 	else if (S_ISDIR (buf.st_mode))
677 	  {
678 	    DIR *dir = opendir (pathname);
679 
680 	    if (dir)
681 	      {
682 		int len = strlen (pathname);
683 		struct dirent *dp;
684 
685 		while ((dp = readdir (dir)) != NULL)
686 		  {
687 		    SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
688 		    strcpy (path, pathname);
689 		    path[len] =  '/';
690 		    strcpy (path + len + 1, dp->d_name);
691 		    ft_add_font (path);
692 		  }
693 		closedir (dir);
694 	      }
695 	  }
696       }
697   SAFE_FREE (path);
698 }
699 
700 /* Return 1 iff the font pointed by FT_INFO has all characters in
701    CHAR_LIST.  */
702 
703 static int
ft_has_char_list_p(MFontFT * ft_info,MPlist * char_list)704 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
705 {
706   FT_Face ft_face;
707   MPlist *cl;
708 
709   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
710     return 0;
711   MPLIST_DO (cl, char_list)
712     if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
713       break;
714   FT_Done_Face (ft_face);
715   return MPLIST_TAIL_P (cl);
716 }
717 
718 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
719    that supports characters in CHAR_LIST or MT.  One of CHAR_LIST or
720    MT must be NULL.  */
721 
722 static MPlist *
ft_list_char_list(MPlist * char_list,MText * mt)723 ft_list_char_list (MPlist *char_list, MText *mt)
724 {
725   MPlist *plist = NULL, *pl, *p;
726 
727   if (! ft_font_list)
728     ft_list_family (Mnil, 0, 1);
729 
730   if (mt)
731     {
732       int len = mtext_nchars (mt);
733       MText *extra = mtext_get_prop (mt, 0, Mtext);
734       int total_len = len + (extra ? mtext_nchars (extra) : 0);
735       int i;
736 
737       char_list = mplist ();
738       for (i = 0; i < total_len; i++)
739 	{
740 	  int c = (i < len ? mtext_ref_char (mt, i)
741 		   : mtext_ref_char (extra, i - len));
742 
743 	  if (! mplist_find_by_value (char_list, (void *) c))
744 	    mplist_push (char_list, Minteger, (void *) c);
745 	}
746     }
747 
748   MPLIST_DO (pl, ft_font_list)
749     {
750       MPLIST_DO (p, MPLIST_PLIST (pl))
751 	{
752 	  MFontFT *ft_info = MPLIST_VAL (p);
753 
754 	  if (ft_has_char_list_p (ft_info, char_list))
755 	    {
756 	      MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
757 
758 	      if (! plist)
759 		plist = mplist ();
760 	      mplist_push (plist, family, ft_info);
761 	    }
762 	}
763     }
764   if (mt)
765     M17N_OBJECT_UNREF (char_list);
766   return plist;
767 }
768 #endif	/* not HAVE_FONTCONFIG */
769 
770 
771 /* Return an element of ft_font_list for FAMILY.  If FAMILY is Mnil,
772    scan all fonts and return ft_font_list.  */
773 
774 static MPlist *
ft_list_family(MSymbol family,int check_generic,int check_alias)775 ft_list_family (MSymbol family, int check_generic, int check_alias)
776 {
777   MPlist *plist;
778 #ifdef HAVE_FONTCONFIG
779   char *fam;
780   MPlist *pl, *p;
781   FcPattern *pattern;
782   FcObjectSet *os;
783   FcFontSet *fs;
784   int i;
785   char *buf;
786   int bufsize = 0;
787   MSymbol generic;
788 
789   if (! ft_font_list)
790     {
791       MSymbol sym;
792 
793       plist = ft_font_list = mplist ();
794       pattern = FcPatternCreate ();
795       os = FcObjectSetBuild (FC_FAMILY, NULL);
796       fs = FcFontList (fc_config, pattern, os);
797       for (i = 0; i < fs->nfont; i++)
798 	{
799 	  if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
800 				  (FcChar8 **) &fam) != FcResultMatch)
801 	    continue;
802 	  STRDUP_LOWER (buf, bufsize, fam);
803 	  sym = msymbol (buf);
804 	  if (! mplist_find_by_key (ft_font_list, sym))
805 	    plist = mplist_add (plist, sym, NULL);
806 	}
807       FcFontSetDestroy (fs);
808       FcObjectSetDestroy (os);
809       FcPatternDestroy (pattern);
810     }
811 
812   if (family == Mnil)
813     {
814       if (! all_fonts_scaned)
815 	{
816 	  MPLIST_DO (plist, ft_font_list)
817 	    {
818 	      if (! MPLIST_VAL (plist))
819 		ft_list_family (MPLIST_KEY (plist), 0, 1);
820 	    }
821 	  all_fonts_scaned = 1;
822 	}
823       return ft_font_list;
824     }
825 
826   plist = mplist_find_by_key (ft_font_list, family);
827   if (plist)
828     {
829       if (! MPLIST_VAL (plist))
830 	{
831 	  fam = MSYMBOL_NAME (family);
832 	  pattern = FcPatternCreate ();
833 	  FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
834 	  os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
835 				 FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
836 				 NULL);
837 	  fs = FcFontList (fc_config, pattern, os);
838 	  p = pl = mplist ();
839 	  for (i = 0; i < fs->nfont; i++)
840 	    {
841 	      MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
842 	      p = mplist_add (p, ft_info->font.file, ft_info);
843 	    }
844 	  MPLIST_VAL (plist) = pl;
845 	  FcFontSetDestroy (fs);
846 	  FcObjectSetDestroy (os);
847 	  FcPatternDestroy (pattern);
848 	}
849     }
850   else if (check_generic
851 	   && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
852     {
853       /* Check if FAMILY is a geneneric family (e.g. `serif').  */
854       FcChar8 *fam8;
855 
856       if (family != generic)
857 	plist = ft_list_family (generic, 1, 1);
858       else
859 	{
860 	  fam = MSYMBOL_NAME (family);
861 	  plist = mplist ();
862 	  mplist_push (ft_font_list, family, plist);
863 	  pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
864 	  FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
865 	  for (i = 0; 1; i++)
866 	    {
867 	      if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
868 		  != FcResultMatch)
869 		break;
870 	      STRDUP_LOWER (buf, bufsize, (char *) fam8);
871 	      family = msymbol (buf);
872 	      if (msymbol_get (family, Mgeneric_family))
873 		break;
874 	      pl = ft_list_family (family, 0, 1);
875 	      if (! pl)
876 		continue;
877 	      MPLIST_DO (pl, MPLIST_PLIST (pl))
878 		plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
879 	    }
880 	  plist = ft_font_list;
881 	}
882     }
883   else if (check_alias)
884     {
885       /* Check if there exist an alias.  */
886       pl = mplist ();
887       plist = mplist_add (ft_font_list, family, pl);
888 
889       pattern = FcPatternBuild (NULL,
890 				FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
891 				NULL);
892       FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
893 
894       for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
895 				      (FcChar8 **) &fam) == FcResultMatch;
896 	   i++);
897       if (i > 0)
898 	{
899 	  /* The last one is a generic family.  */
900 	  MSymbol sym;
901 	  int j;
902 	  FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
903 					   NULL);
904 
905 	  FcConfigSubstitute (fc_config, pat, FcMatchPattern);
906 	  for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
907 					  (FcChar8 **) &fam) == FcResultMatch;
908 	       j++);
909 
910 	  /* Now we know that the last J fonts in PATTERN are from
911 	     generic font, and the first one is not available.  So,
912 	     the remaining ones are aliases.  */
913 	  j = i - j;
914 	  for (i = 1; i < j; i++)
915 	    {
916 	      FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
917 	      STRDUP_LOWER (buf, bufsize, fam);
918 	      sym = msymbol (buf);
919 	      p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
920 	      if (! MPLIST_TAIL_P (p))
921 		MPLIST_DO (p, p)
922 		  mplist_push (pl, Mt, MPLIST_VAL (p));
923 	    }
924 	}
925     }
926   else
927     {
928       pl = mplist ();
929       plist = mplist_add (ft_font_list, family, pl);
930     }
931 
932 #else  /* not HAVE_FONTCONFIG */
933 
934   if (! all_fonts_scaned)
935     {
936       ft_init_font_list ();
937       all_fonts_scaned = 1;
938     }
939   if (family == Mnil)
940     plist = ft_font_list;
941   else
942     {
943       plist = mplist_find_by_key (ft_font_list, family);
944       if (! plist)
945 	plist = mplist_push (ft_font_list, family, mplist ());
946     }
947 #endif  /* not HAVE_FONTCONFIG */
948 
949   return plist;
950 }
951 
952 static MPlist *
ft_list_language(MSymbol language)953 ft_list_language (MSymbol language)
954 {
955   MPlist *plist = NULL;
956   MText *mt;
957 
958   if (! ft_language_list)
959     ft_language_list = mplist ();
960   else if ((plist = mplist_find_by_key (ft_language_list, language)))
961     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
962 
963   mt = mlanguage_text (language);
964 
965 #ifdef HAVE_FONTCONFIG
966   {
967     FcPattern *pattern = NULL;
968     FcCharSet *cs = NULL;
969     FcLangSet *ls = NULL;
970 
971     if (! (pattern = FcPatternCreate ()))
972       goto err;
973 
974     if (mt && mtext_nchars (mt) > 0)
975       {
976 	cs = fc_build_charset (NULL, mt);
977 	if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
978 	  goto err;
979       }
980     else
981       {
982 	if (! (ls = FcLangSetCreate ()))
983 	  goto err;
984 	if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
985 	    || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
986 	  goto err;
987       }
988 
989     plist = fc_list_pattern (pattern);
990   err:
991     if (cs) FcCharSetDestroy (cs);
992     if (ls) FcLangSetDestroy (ls);
993     if (pattern) FcPatternDestroy (pattern);
994   }
995 #else	/* not HAVE_FONTCONFIG */
996   if (mt && mtext_nchars (mt) > 0)
997     plist = ft_list_char_list (NULL, mt);
998 #endif  /* not HAVE_FONTCONFIG */
999 
1000   mplist_push (ft_language_list, language, plist);
1001   return plist;
1002 }
1003 
1004 static MPlist *
ft_list_script(MSymbol script)1005 ft_list_script (MSymbol script)
1006 {
1007   MPlist *plist = NULL;
1008   MPlist *char_list;
1009 
1010   if (! ft_script_list)
1011     ft_script_list = mplist ();
1012   else if ((plist = mplist_find_by_key (ft_script_list, script)))
1013     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1014 
1015   char_list = mscript__char_list (script);
1016 
1017 #ifdef HAVE_FONTCONFIG
1018   if (char_list)
1019     {
1020       FcPattern *pattern = NULL;
1021       FcCharSet *cs;
1022 
1023       if (! (pattern = FcPatternCreate ()))
1024 	goto err;
1025       cs = fc_build_charset (char_list, NULL);
1026       if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1027 	  goto err;
1028       plist = fc_list_pattern (pattern);
1029     err:
1030       if (cs) FcCharSetDestroy (cs);
1031       if (pattern) FcPatternDestroy (pattern);
1032     }
1033 #else  /* not HAVE_FONTCONFIG */
1034   if (char_list)
1035     plist = ft_list_char_list (char_list, NULL);
1036 #endif	/* not HAVE_FONTCONFIG */
1037 
1038   mplist_push (ft_script_list, script, plist);
1039   return (plist);
1040 }
1041 
1042 static int
ft_check_cap_otf(MFontFT * ft_info,MFontCapability * cap,FT_Face ft_face)1043 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1044 {
1045 #ifdef HAVE_OTF
1046   if (ft_info->otf == invalid_otf)
1047     return -1;
1048   if (! ft_info->otf)
1049     {
1050 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1051       if (ft_face)
1052 	ft_info->otf = OTF_open_ft_face (ft_face);
1053       else
1054 #endif
1055 	ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1056       if (! ft_info->otf)
1057 	{
1058 	  ft_info->otf = invalid_otf;
1059 	  return -1;
1060 	}
1061     }
1062   if (cap->features[MFONT_OTT_GSUB].nfeatures
1063       && (OTF_check_features
1064 	  (ft_info->otf, 1,
1065 	   cap->script_tag, cap->langsys_tag,
1066 	   cap->features[MFONT_OTT_GSUB].tags,
1067 	   cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1068     return -1;
1069   if (cap->features[MFONT_OTT_GPOS].nfeatures
1070       && (OTF_check_features
1071 	  (ft_info->otf, 0,
1072 	   cap->script_tag, cap->langsys_tag,
1073 	   cap->features[MFONT_OTT_GPOS].tags,
1074 	   cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1075     return -1;
1076   return 0;
1077 #else	/* not HAVE_OTF */
1078   return -1;
1079 #endif	/* not HAVE_OTF */
1080 }
1081 
1082 static int
ft_check_language(MFontFT * ft_info,MSymbol language,FT_Face ft_face)1083 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1084 {
1085   MText *mt;
1086   MText *extra;
1087   int ft_face_allocaed = 0;
1088   int len, total_len;
1089   int i;
1090 
1091 #ifdef HAVE_FONTCONFIG
1092   if (ft_info->langset
1093       && (FcLangSetHasLang (ft_info->langset,
1094 			    (FcChar8 *) MSYMBOL_NAME (language))
1095 	  != FcLangDifferentLang))
1096     return 0;
1097 #endif	/* HAVE_FONTCONFIG */
1098 
1099   mt = mlanguage_text (language);
1100   if (! mt || mtext_nchars (mt) == 0)
1101     return -1;
1102 
1103   if (! ft_face)
1104     {
1105       char *filename = MSYMBOL_NAME (ft_info->font.file);
1106 
1107       if (FT_New_Face (ft_library, filename, 0, &ft_face))
1108 	return -1;
1109       ft_face_allocaed = 1;
1110     }
1111 
1112   len = mtext_nchars (mt);
1113   extra = mtext_get_prop (mt, 0, Mtext);
1114   total_len = len + (extra ? mtext_nchars (extra) : 0);
1115 
1116   for (i = 0; i < total_len; i++)
1117     {
1118       int c = (i < len ? mtext_ref_char (mt, i)
1119 	       : mtext_ref_char (extra, i - len));
1120 
1121 #ifdef HAVE_FONTCONFIG
1122       if (ft_info->charset
1123 	  && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1124 	break;
1125 #endif	/* HAVE_FONTCONFIG */
1126       if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1127 	break;
1128     }
1129 
1130   if (ft_face_allocaed)
1131     FT_Done_Face (ft_face);
1132 
1133   return (i == total_len ? 0 : -1);
1134 }
1135 
1136 static int
ft_check_script(MFontFT * ft_info,MSymbol script,FT_Face ft_face)1137 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1138 {
1139   MPlist *char_list = mscript__char_list (script);
1140 
1141   if (! char_list)
1142     return -1;
1143 #ifdef HAVE_FONTCONFIG
1144   if (ft_info->charset)
1145     {
1146       MPLIST_DO (char_list, char_list)
1147 	if (FcCharSetHasChar (ft_info->charset,
1148 			      (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1149 	  break;
1150     }
1151   else
1152 #endif	/* HAVE_FONTCONFIG */
1153     {
1154       int ft_face_allocaed = 0;
1155 
1156       if (! ft_face)
1157 	{
1158 	  char *filename = MSYMBOL_NAME (ft_info->font.file);
1159 
1160 	  if (FT_New_Face (ft_library, filename, 0, &ft_face))
1161 	    return -1;
1162 	  ft_face_allocaed = 1;
1163 	}
1164 
1165       MPLIST_DO (char_list, char_list)
1166 	if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1167 	    == 0)
1168 	  break;
1169       if (ft_face_allocaed)
1170 	FT_Done_Face (ft_face);
1171     }
1172 
1173   return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1174 }
1175 
1176 static MPlist *ft_default_list;
1177 
1178 static MPlist *
ft_list_default()1179 ft_list_default ()
1180 {
1181   if (ft_default_list)
1182     return ft_default_list;
1183   ft_default_list = mplist ();
1184 #ifdef HAVE_FONTCONFIG
1185   {
1186     FcPattern *pat = FcPatternCreate ();
1187     FcChar8 *fam;
1188     char *buf;
1189     int bufsize = 0;
1190     int i;
1191 
1192     FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1193     for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1194 	 i++)
1195       {
1196 	MSymbol family;
1197 	MPlist *plist;
1198 
1199 	STRDUP_LOWER (buf, bufsize, (char *) fam);
1200 	family = msymbol (buf);
1201 	if (msymbol_get (family, Mgeneric_family))
1202 	  continue;
1203 	plist = MPLIST_PLIST (ft_list_family (family, 0, 1));
1204 	MPLIST_DO (plist, plist)
1205 	  mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1206       }
1207   }
1208 #else  /* not HAVE_FONTCONFIG */
1209   {
1210     MPlist *plist, *pl;
1211 
1212     MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
1213       {
1214 	pl = MPLIST_PLIST (plist);
1215 	if (! MPLIST_TAIL_P (pl))
1216 	  mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1217       }
1218   }
1219 #endif	/* not HAVE_FONTCONFIG */
1220   return ft_default_list;
1221 }
1222 
1223 
1224 static MPlist *ft_capability_list;
1225 
1226 static MPlist *
ft_list_capability(MSymbol capability)1227 ft_list_capability (MSymbol capability)
1228 {
1229   MFontCapability *cap;
1230   MPlist *plist = NULL, *pl;
1231 
1232   if (! ft_capability_list)
1233     ft_capability_list = mplist ();
1234   else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1235     return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1236 
1237   cap = mfont__get_capability (capability);
1238 
1239   if (cap && cap->language != Mnil)
1240     {
1241       plist = ft_list_language (cap->language);
1242       if (! plist)
1243 	return NULL;
1244       plist = mplist_copy (plist);
1245     }
1246 
1247   if (cap && cap->script != Mnil)
1248     {
1249       if (! plist)
1250 	{
1251 	  plist = ft_list_script (cap->script);
1252 	  if (! plist)
1253 	    return NULL;
1254 	  plist = mplist_copy (plist);
1255 	}
1256       else
1257 	{
1258 	  for (pl = plist; ! MPLIST_TAIL_P (pl);)
1259 	    {
1260 	      if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1261 		mplist_pop (pl);
1262 	      else
1263 		pl = MPLIST_NEXT (pl);
1264 	    }
1265 	}
1266 
1267       if (cap->script_tag)
1268 	{
1269 	  for (pl = plist; ! MPLIST_TAIL_P (pl);)
1270 	    {
1271 	      if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1272 		mplist_pop (pl);
1273 	      else
1274 		pl = MPLIST_NEXT (pl);
1275 	    }
1276 	}
1277 
1278       if (MPLIST_TAIL_P (plist))
1279 	{
1280 	  M17N_OBJECT_UNREF (plist);
1281 	  plist = NULL;
1282 	}
1283     }
1284 
1285   mplist_push (ft_capability_list, capability, plist);
1286   return plist;
1287 }
1288 
1289 
1290 static MPlist *
ft_list_file(MSymbol filename)1291 ft_list_file (MSymbol filename)
1292 {
1293   MPlist *plist = NULL;
1294 
1295   if (! ft_file_list)
1296     ft_file_list = mplist ();
1297   else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1298     return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1299 
1300 #ifdef HAVE_FONTCONFIG
1301   {
1302     FcPattern *pattern = FcPatternCreate ();
1303     FcObjectSet *os;
1304     FcFontSet *fs;
1305 
1306     FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1307     os = FcObjectSetBuild (FC_FAMILY, NULL);
1308     fs = FcFontList (fc_config, pattern, os);
1309     if (fs->nfont > 0)
1310       {
1311 	char *fam;
1312 	char *buf;
1313 	int bufsize = 0;
1314 
1315 	if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1316 				(FcChar8 **) &fam) == FcResultMatch)
1317 	  {
1318 	    MSymbol family;
1319 	    MPlist *pl;
1320 
1321 	    STRDUP_LOWER (buf, bufsize, fam);
1322 	    family = msymbol (buf);
1323 	    pl = ft_list_family (family, 0, 1);
1324 	    MPLIST_DO (pl, MPLIST_PLIST (pl))
1325 	      {
1326 		MFontFT *ft_info = MPLIST_VAL (pl);
1327 
1328 		if (ft_info->font.file == filename)
1329 		  {
1330 		    plist = mplist ();
1331 		    mplist_add (plist, family, ft_info);
1332 		    break;
1333 		  }
1334 	      }
1335 	  }
1336       }
1337   }
1338 #else  /* not HAVE_FONTCONFIG */
1339   {
1340     MPlist *pl, *p;
1341 
1342     MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
1343       {
1344 	MPLIST_DO (p, MPLIST_PLIST (pl))
1345 	  {
1346 	    MFontFT *ft_info = MPLIST_VAL (pl);
1347 
1348 	    if (ft_info->font.file == filename)
1349 	      {
1350 		plist = mplist ();
1351 		mplist_add (plist, MPLIST_KEY (pl), ft_info);
1352 		break;
1353 	      }
1354 	  }
1355 	if (plist)
1356 	  break;
1357       }
1358   }
1359 #endif	/* not HAVE_FONTCONFIG */
1360 
1361   mplist_push (ft_file_list, filename, plist);
1362   return plist;
1363 }
1364 
1365 /* The FreeType font driver function SELECT.  */
1366 
1367 static MFont *
ft_select(MFrame * frame,MFont * font,int limited_size)1368 ft_select (MFrame *frame, MFont *font, int limited_size)
1369 {
1370   MFont *found = NULL;
1371 #ifdef HAVE_FONTCONFIG
1372   MPlist *plist, *pl;
1373   MFontFT *ft_info;
1374   int check_font_property = 1;
1375 
1376   if (font->file != Mnil)
1377     {
1378       plist = ft_list_file (font->file);
1379       if (! plist)
1380 	return NULL;
1381       check_font_property = 0;
1382     }
1383   else
1384     {
1385       MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1386 
1387       if (family)
1388 	plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
1389       else
1390 	plist = ft_list_default ();
1391       if (MPLIST_TAIL_P (plist))
1392 	return NULL;
1393     }
1394 
1395   plist = mplist_copy (plist);
1396 
1397   if (font->capability != Mnil)
1398     {
1399       MFontCapability *cap = mfont__get_capability (font->capability);
1400 
1401       for (pl = plist; ! MPLIST_TAIL_P (pl);)
1402 	{
1403 	  if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1404 	    {
1405 	      mplist_pop (pl);
1406 	      continue;
1407 	    }
1408 	  if (cap->language
1409 	      && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1410 	    mplist_pop (pl);
1411 	  else
1412 	    pl = MPLIST_NEXT (pl);
1413 	}
1414     }
1415 
1416   if (check_font_property)
1417     {
1418       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1419       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1420       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1421       MSymbol alternate_weight = Mnil;
1422 
1423       if (weight == Mnormal)
1424 	alternate_weight = Mmedium;
1425       else if (weight == Mmedium)
1426 	alternate_weight = Mnormal;
1427       if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1428 	for (pl = plist; ! MPLIST_TAIL_P (pl); )
1429 	  {
1430 	    ft_info = MPLIST_VAL (pl);
1431 	    if ((weight != Mnil
1432 		 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1433 		     && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1434 		|| (style != Mnil
1435 		    && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1436 		|| (stretch != Mnil
1437 		    && stretch != FONT_PROPERTY (&ft_info->font,
1438 						 MFONT_STRETCH))
1439 		|| (font->size > 0
1440 		    && ft_info->font.size > 0
1441 		    && ft_info->font.size != font->size))
1442 	      mplist_pop (pl);
1443 	    else
1444 	      pl = MPLIST_NEXT (pl);
1445 	  }
1446     }
1447 
1448   MPLIST_DO (pl, plist)
1449     {
1450       font = MPLIST_VAL (plist);
1451       if (limited_size == 0
1452 	  || font->size == 0
1453 	  || font->size <= limited_size)
1454 	{
1455 	  found = font;
1456 	  break;
1457 	}
1458     }
1459   M17N_OBJECT_UNREF (plist);
1460 #endif	/* HAVE_FONTCONFIG */
1461   return found;
1462 }
1463 
1464 
1465 static MRealizedFont *
ft_open(MFrame * frame,MFont * font,MFont * spec,MRealizedFont * rfont)1466 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1467 {
1468   MFontFT *ft_info = (MFontFT *) font;
1469   int reg = spec->property[MFONT_REGISTRY];
1470   MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1471   MRealizedFontFT *ft_rfont;
1472   FT_Face ft_face;
1473   MPlist *plist, *charmap_list = NULL;
1474   int charmap_index;
1475   int size;
1476 
1477   if (font->size)
1478     /* non-scalable font */
1479     size = font->size;
1480   else if (spec->size)
1481     {
1482       int ratio = mfont_resize_ratio (font);
1483 
1484       size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1485     }
1486   else
1487     size = 120;
1488 
1489   if (rfont)
1490     {
1491       charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1492       for (; rfont; rfont = rfont->next)
1493 	if (rfont->font == font
1494 	    && (rfont->font->size ? rfont->font->size == size
1495 		: rfont->spec.size == size)
1496 	    && rfont->spec.property[MFONT_REGISTRY] == reg
1497 	    && rfont->driver == &mfont__ft_driver)
1498 	  return rfont;
1499     }
1500 
1501   MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1502 
1503   if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1504 		   &ft_face))
1505     {
1506       font->type = MFONT_TYPE_FAILURE;
1507       MDEBUG_PRINT ("  no (FT_New_Face)\n");
1508       return NULL;
1509     }
1510   if (charmap_list)
1511     M17N_OBJECT_REF (charmap_list);
1512   else
1513     charmap_list = ft_get_charmaps (ft_face);
1514   if (registry == Mnil)
1515     registry = Municode_bmp;
1516   plist = mplist_find_by_key (charmap_list, registry);
1517   if (! plist)
1518     {
1519       FT_Done_Face (ft_face);
1520       M17N_OBJECT_UNREF (charmap_list);
1521       MDEBUG_PRINT1 ("  no (%s)\n", MSYMBOL_NAME (registry));
1522       return NULL;
1523     }
1524   charmap_index = (int) MPLIST_VAL (plist);
1525   if ((charmap_index >= 0
1526        && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1527       || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1528     {
1529       FT_Done_Face (ft_face);
1530       M17N_OBJECT_UNREF (charmap_list);
1531       font->type = MFONT_TYPE_FAILURE;
1532       MDEBUG_PRINT1 ("  no (size %d)\n", size);
1533       return NULL;
1534     }
1535 
1536   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1537   ft_rfont->ft_face = ft_face;
1538   ft_rfont->charmap_list = charmap_list;
1539   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1540   rfont->id = ft_info->font.file;
1541   rfont->spec = *font;
1542   rfont->spec.type = MFONT_TYPE_REALIZED;
1543   rfont->spec.property[MFONT_REGISTRY] = reg;
1544   rfont->spec.size = size;
1545   rfont->frame = frame;
1546   rfont->font = font;
1547   rfont->driver = &mfont__ft_driver;
1548   rfont->info = ft_rfont;
1549   rfont->fontp = ft_face;
1550   rfont->ascent = ft_face->size->metrics.ascender;
1551   rfont->descent = - ft_face->size->metrics.descender;
1552   rfont->max_advance = ft_face->size->metrics.max_advance;
1553   rfont->baseline_offset = 0;
1554   rfont->x_ppem = ft_face->size->metrics.x_ppem;
1555   rfont->y_ppem = ft_face->size->metrics.y_ppem;
1556 #ifdef HAVE_FTBDF_H
1557   {
1558     BDF_PropertyRec prop;
1559 
1560     if (! FT_IS_SCALABLE (ft_face)
1561 	&& FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1562       {
1563 	rfont->baseline_offset = prop.u.integer << 6;
1564 	rfont->ascent += prop.u.integer << 6;
1565 	rfont->descent -= prop.u.integer << 6;
1566       }
1567   }
1568 #endif	/* HAVE_FTBDF_H */
1569   if (FT_IS_SCALABLE (ft_face))
1570     rfont->average_width = 0;
1571   else
1572     rfont->average_width = ft_face->available_sizes->width << 6;
1573   rfont->next = MPLIST_VAL (frame->realized_font_list);
1574   MPLIST_VAL (frame->realized_font_list) = rfont;
1575   MDEBUG_PRINT ("  ok\n");
1576   return rfont;
1577 }
1578 
1579 /* The FreeType font driver function FIND_METRIC.  */
1580 
1581 static void
ft_find_metric(MRealizedFont * rfont,MGlyphString * gstring,int from,int to)1582 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1583 		int from, int to)
1584 {
1585   FT_Face ft_face = rfont->fontp;
1586   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1587 
1588   for (; g != gend; g++)
1589     {
1590       if (g->g.measured)
1591 	continue;
1592       if (g->g.code == MCHAR_INVALID_CODE)
1593 	{
1594 	  if (FT_IS_SCALABLE (ft_face))
1595 	    {
1596 	      g->g.lbearing = 0;
1597 	      g->g.rbearing = ft_face->size->metrics.max_advance;
1598 	      g->g.xadv = g->g.rbearing;
1599 	      g->g.ascent = ft_face->size->metrics.ascender;
1600 	      g->g.descent = - ft_face->size->metrics.descender;
1601 	    }
1602 	  else
1603 	    {
1604 #ifdef HAVE_FTBDF_H
1605 	      BDF_PropertyRec prop;
1606 #endif	/* HAVE_FTBDF_H */
1607 
1608 	      g->g.lbearing = 0;
1609 	      g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1610 #ifdef HAVE_FTBDF_H
1611 	      if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1612 		{
1613 		  g->g.ascent = prop.u.integer << 6;
1614 		  FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1615 		  g->g.descent = prop.u.integer << 6;
1616 		  if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1617 					   & prop) == 0)
1618 		    {
1619 		      g->g.ascent += prop.u.integer << 6;
1620 		      g->g.descent -= prop.u.integer << 6;
1621 		    }
1622 		}
1623 	      else
1624 #endif	/* HAVE_FTBDF_H */
1625 		{
1626 		  g->g.ascent = ft_face->available_sizes->height << 6;
1627 		  g->g.descent = 0;
1628 		}
1629 	    }
1630 	}
1631       else
1632 	{
1633 	  FT_Glyph_Metrics *metrics;
1634 
1635 	  FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
1636 	  metrics = &ft_face->glyph->metrics;
1637 	  g->g.lbearing = metrics->horiBearingX;
1638 	  g->g.rbearing = metrics->horiBearingX + metrics->width;
1639 	  g->g.xadv = metrics->horiAdvance;
1640 	  g->g.ascent = metrics->horiBearingY;
1641 	  g->g.descent = metrics->height - metrics->horiBearingY;
1642 	}
1643       g->g.yadv = 0;
1644       g->g.ascent += rfont->baseline_offset;
1645       g->g.descent -= rfont->baseline_offset;
1646       g->g.measured = 1;
1647     }
1648 }
1649 
1650 static int
ft_has_char(MFrame * frame,MFont * font,MFont * spec,int c,unsigned code)1651 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1652 {
1653   MRealizedFont *rfont = NULL;
1654   MRealizedFontFT *ft_rfont;
1655   FT_UInt idx;
1656 
1657   if (font->type == MFONT_TYPE_REALIZED)
1658     rfont = (MRealizedFont *) font;
1659   else if (font->type == MFONT_TYPE_OBJECT)
1660     {
1661       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1662 	   rfont = rfont->next)
1663 	if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1664 	  break;
1665       if (! rfont)
1666 	{
1667 #ifdef HAVE_FONTCONFIG
1668 	  MFontFT *ft_info = (MFontFT *) font;
1669 
1670 	  if (! ft_info->charset)
1671 	    {
1672 	      FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1673 					       MSYMBOL_NAME (font->file),
1674 					       NULL);
1675 	      FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1676 	      FcFontSet *fs = FcFontList (fc_config, pat, os);
1677 
1678 	      if (fs->nfont > 0
1679 		  && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1680 					  &ft_info->charset) == FcResultMatch)
1681 		ft_info->charset = FcCharSetCopy (ft_info->charset);
1682 	      else
1683 		ft_info->charset = FcCharSetCreate ();
1684 	      FcFontSetDestroy (fs);
1685 	      FcObjectSetDestroy (os);
1686 	      FcPatternDestroy (pat);
1687 	    }
1688 	  return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1689 #else  /* not HAVE_FONTCONFIG */
1690 	  rfont = ft_open (frame, font, spec, NULL);
1691 #endif	/* not HAVE_FONTCONFIG */
1692 	}
1693     }
1694   else
1695     MFATAL (MERROR_FONT_FT);
1696 
1697   if (! rfont)
1698     return 0;
1699   ft_rfont = rfont->info;
1700   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1701   return (idx != 0);
1702 }
1703 
1704 /* The FreeType font driver function ENCODE_CHAR.  */
1705 
1706 static unsigned
ft_encode_char(MFrame * frame,MFont * font,MFont * spec,unsigned code)1707 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1708 {
1709   MRealizedFont *rfont;
1710   MRealizedFontFT *ft_rfont;
1711   FT_UInt idx;
1712 
1713   if (font->type == MFONT_TYPE_REALIZED)
1714     rfont = (MRealizedFont *) font;
1715   else if (font->type == MFONT_TYPE_OBJECT)
1716     {
1717       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1718 	   rfont = rfont->next)
1719 	if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1720 	  break;
1721       if (! rfont)
1722 	{
1723 	  rfont = ft_open (frame, font, spec, NULL);
1724 	  if (! rfont)
1725 	    return -1;
1726 	}
1727     }
1728   else
1729     MFATAL (MERROR_FONT_FT);
1730 
1731   ft_rfont = rfont->info;
1732   idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1733   return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1734 }
1735 
1736 /* The FreeType font driver function RENDER.  */
1737 
1738 #define NUM_POINTS 0x1000
1739 
1740 typedef struct {
1741   MDrawPoint points[NUM_POINTS];
1742   MDrawPoint *p;
1743 } MPointTable;
1744 
1745 static void
ft_render(MDrawWindow win,int x,int y,MGlyphString * gstring,MGlyph * from,MGlyph * to,int reverse,MDrawRegion region)1746 ft_render (MDrawWindow win, int x, int y,
1747 	   MGlyphString *gstring, MGlyph *from, MGlyph *to,
1748 	   int reverse, MDrawRegion region)
1749 {
1750   FT_Face ft_face;
1751   MRealizedFace *rface = from->rface;
1752   MFrame *frame = rface->frame;
1753   FT_Int32 load_flags = FT_LOAD_RENDER;
1754   MGlyph *g;
1755   int i, j;
1756   MPointTable point_table[8];
1757   int baseline_offset;
1758   int pixel_mode = -1;
1759 
1760   if (from == to)
1761     return;
1762 
1763   /* It is assured that the all glyphs in the current range use the
1764      same realized face.  */
1765   ft_face = rface->rfont->fontp;
1766   baseline_offset = rface->rfont->baseline_offset >> 6;
1767 
1768   if (! gstring->anti_alias)
1769     {
1770 #ifdef FT_LOAD_TARGET_MONO
1771       load_flags |= FT_LOAD_TARGET_MONO;
1772 #else
1773       load_flags |= FT_LOAD_MONOCHROME;
1774 #endif
1775     }
1776 
1777   for (i = 0; i < 8; i++)
1778     point_table[i].p = point_table[i].points;
1779 
1780   for (g = from; g < to; x += g++->g.xadv)
1781     {
1782       unsigned char *bmp;
1783       int intensity;
1784       MPointTable *ptable;
1785       int xoff, yoff;
1786       int width, pitch;
1787 
1788       FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
1789       if (pixel_mode < 0)
1790 	pixel_mode = ft_face->glyph->bitmap.pixel_mode;
1791       yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
1792       bmp = ft_face->glyph->bitmap.buffer;
1793       width = ft_face->glyph->bitmap.width;
1794       pitch = ft_face->glyph->bitmap.pitch;
1795 
1796       if (pixel_mode != FT_PIXEL_MODE_MONO)
1797 	for (i = 0; i < ft_face->glyph->bitmap.rows;
1798 	     i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1799 	  {
1800 	    xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1801 	    for (j = 0; j < width; j++, xoff++)
1802 	      {
1803 		intensity = bmp[j] >> 5;
1804 		if (intensity)
1805 		  {
1806 		    ptable = point_table + intensity;
1807 		    ptable->p->x = xoff;
1808 		    ptable->p->y = yoff - baseline_offset;
1809 		    ptable->p++;
1810 		    if (ptable->p - ptable->points == NUM_POINTS)
1811 		      {
1812 			(*frame->driver->draw_points)
1813 			  (frame, win, rface,
1814 			   reverse ? 7 - intensity : intensity,
1815 			   ptable->points, NUM_POINTS, region);
1816 			ptable->p = ptable->points;
1817 		      }
1818 		  }
1819 	      }
1820 	  }
1821       else
1822 	for (i = 0; i < ft_face->glyph->bitmap.rows;
1823 	     i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1824 	  {
1825 	    xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1826 	    for (j = 0; j < width; j++, xoff++)
1827 	      {
1828 		intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1829 		if (intensity)
1830 		  {
1831 		    ptable = point_table;
1832 		    ptable->p->x = xoff;
1833 		    ptable->p->y = yoff - baseline_offset;
1834 		    ptable->p++;
1835 		    if (ptable->p - ptable->points == NUM_POINTS)
1836 		      {
1837 			(*frame->driver->draw_points) (frame, win, rface,
1838 					   reverse ? 0 : 7,
1839 					   ptable->points, NUM_POINTS, region);
1840 			ptable->p = ptable->points;
1841 		      }
1842 		  }
1843 	      }
1844 	}
1845     }
1846 
1847   if (pixel_mode != FT_PIXEL_MODE_MONO)
1848     {
1849       for (i = 1; i < 8; i++)
1850 	if (point_table[i].p != point_table[i].points)
1851 	  (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1852 			     point_table[i].points,
1853 			     point_table[i].p - point_table[i].points, region);
1854     }
1855   else
1856     {
1857       if (point_table[0].p != point_table[0].points)
1858 	(*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1859 			   point_table[0].points,
1860 			   point_table[0].p - point_table[0].points, region);
1861     }
1862 }
1863 
1864 static int
ft_list(MFrame * frame,MPlist * plist,MFont * font,int maxnum)1865 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1866 {
1867   MPlist *pl = NULL, *p;
1868   int num = 0;
1869   MPlist *file_list = NULL;
1870   MPlist *family_list = NULL, *capability_list = NULL;
1871   MSymbol registry = Mnil;
1872 
1873   MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1874 
1875   if (font)
1876     {
1877       MSymbol family;
1878 
1879       registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1880       if (registry != Mnil && registry != Miso8859_1)
1881 	{
1882 	  char *reg = MSYMBOL_NAME (registry);
1883 
1884 	  if (strncmp (reg, "unicode-", 8)
1885 	      && strncmp (reg, "apple-roman", 11)
1886 	      && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1887 	    goto done;
1888 	}
1889 
1890       if (font->file != Mnil
1891 	  && ! (file_list = ft_list_file (font->file)))
1892 	goto done;
1893       family = FONT_PROPERTY (font, MFONT_FAMILY);
1894       if (family != Mnil
1895 	  && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
1896 	  && MPLIST_TAIL_P (family_list))
1897 	goto done;
1898       if (font->capability != Mnil)
1899 	{
1900 	  capability_list = ft_list_capability (font->capability);
1901 	  if (! capability_list || MPLIST_TAIL_P (capability_list))
1902 	    goto done;
1903 	}
1904     }
1905 
1906   if (! file_list && ! family_list && ! capability_list)
1907     {
1908       /* No restriction.  Get all fonts.  */
1909       pl = mplist ();
1910       MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
1911 	{
1912 	  MPLIST_DO (p, MPLIST_PLIST (family_list))
1913 	    mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1914 	}
1915     }
1916   else
1917     {
1918       if (file_list)
1919 	{
1920 	  pl = mplist ();
1921 	  mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1922 	}
1923       if (family_list)
1924 	{
1925 	  if (pl)
1926 	    for (p = pl; ! MPLIST_TAIL_P (p);)
1927 	      {
1928 		if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1929 		  p = MPLIST_NEXT (p);
1930 		else
1931 		  mplist_pop (p);
1932 	      }
1933 	  else
1934 	    {
1935 	      pl = mplist ();
1936 	      MPLIST_DO (p, family_list)
1937 		mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1938 	    }
1939 	}
1940       if (capability_list)
1941 	{
1942 	  if (pl)
1943 	    for (p = pl; ! MPLIST_TAIL_P (p);)
1944 	      {
1945 		if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1946 		  p = MPLIST_NEXT (p);
1947 		else
1948 		  mplist_pop (p);
1949 	      }
1950 	  else
1951 	    {
1952 	      pl = mplist ();
1953 	      MPLIST_DO (p, capability_list)
1954 		mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1955 	    }
1956 	}
1957     }
1958 
1959   if (font
1960       && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1961 	  + font->property[MFONT_STRETCH] + font->size) > 0)
1962     {
1963       MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1964       MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1965       MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1966       int size = font->size;
1967 
1968       for (p = pl; ! MPLIST_TAIL_P (p); )
1969 	{
1970 	  MFontFT *ft_info = MPLIST_VAL (p);
1971 
1972 	  if ((weight != Mnil
1973 	       && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1974 	      || (style != Mnil
1975 		  && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1976 	      || (stretch != Mnil
1977 		  && stretch != FONT_PROPERTY (&ft_info->font,
1978 					       MFONT_STRETCH))
1979 	      || (size > 0
1980 		  && ft_info->font.size > 0
1981 		  && ft_info->font.size != size))
1982 	    mplist_pop (p);
1983 	  else
1984 	    p = MPLIST_NEXT (p);
1985 	}
1986     }
1987 
1988   MPLIST_DO (p, pl)
1989     {
1990       mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1991       num++;
1992       if (maxnum && maxnum <= num)
1993 	break;
1994     }
1995   M17N_OBJECT_UNREF (pl);
1996 
1997  done:
1998   MDEBUG_PRINT1 ("  %d found\n", num);
1999   return num;
2000 }
2001 
2002 static void
ft_list_family_names(MFrame * frame,MPlist * plist)2003 ft_list_family_names (MFrame *frame, MPlist *plist)
2004 {
2005   MPlist *pl;
2006 
2007   if (! ft_font_list)
2008     {
2009 #ifdef HAVE_FONTCONFIG
2010       fc_init_font_list ();
2011 #else  /* not HAVE_FONTCONFIG */
2012       ft_init_font_list ();
2013 #endif	/* not HAVE_FONTCONFIG */
2014     }
2015 
2016   MPLIST_DO (pl, ft_font_list)
2017     {
2018       MSymbol family = MPLIST_KEY (pl);
2019       MPlist *p;
2020 
2021 #ifdef HAVE_FONTCONFIG
2022       if (msymbol_get (family, Mgeneric_family) != Mnil)
2023 	continue;
2024 #endif	/* HAVE_FONTCONFIG */
2025       MPLIST_DO (p, plist)
2026 	{
2027 	  MSymbol sym = MPLIST_SYMBOL (p);
2028 
2029 	  if (sym == family)
2030 	    break;
2031 	  if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2032 	    {
2033 	      mplist_push (p, Msymbol, family);
2034 	      break;
2035 	    }
2036 	}
2037       if (MPLIST_TAIL_P (p))
2038 	mplist_push (p, Msymbol, family);
2039     }
2040 }
2041 
2042 static int
ft_check_capability(MRealizedFont * rfont,MSymbol capability)2043 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2044 {
2045   MFontFT *ft_info = (MFontFT *) rfont->font;
2046   MRealizedFontFT *ft_rfont = rfont->info;
2047   MFontCapability *cap = mfont__get_capability (capability);
2048 
2049   if (cap->script_tag)
2050     {
2051       if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2052 	return -1;
2053     }
2054   else if (cap->script != Mnil
2055 	   && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2056     return -1;
2057   if (cap->language != Mnil
2058       && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2059     return -1;
2060   return 0;
2061 }
2062 
2063 static MRealizedFont *
ft_encapsulate(MFrame * frame,MSymbol data_type,void * data)2064 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2065 {
2066   MFontFT *ft_info;
2067   MRealizedFont *rfont;
2068   MRealizedFontFT *ft_rfont;
2069   FT_Face ft_face;
2070 
2071   if (data_type == Mfontconfig)
2072     {
2073 #ifdef HAVE_FONTCONFIG
2074       FcPattern *pattern = data;
2075 
2076       if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2077 	  != FcResultMatch)
2078 	return NULL;
2079       ft_info = fc_gen_font (pattern, NULL);
2080 #else  /* not HAVE_FONTCONFIG */
2081       return NULL;
2082 #endif	/* not HAVE_FONTCONFIG */
2083     }
2084   else if (data_type == Mfreetype)
2085     {
2086       ft_face = data;
2087       ft_info = ft_gen_font (ft_face);
2088     }
2089   else
2090     return NULL;
2091 
2092   M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2093   ft_rfont->ft_face = ft_face;
2094   ft_rfont->face_encapsulated = 1;
2095 
2096   MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
2097 
2098   MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2099   rfont->id = ft_info->font.file;
2100   rfont->font = (MFont *) ft_info;
2101   rfont->info = ft_rfont;
2102   rfont->fontp = ft_face;
2103   rfont->driver = &mfont__ft_driver;
2104   rfont->spec = ft_info->font;
2105   rfont->spec.type = MFONT_TYPE_REALIZED;
2106   rfont->frame = frame;
2107   rfont->ascent = ft_face->size->metrics.ascender >> 6;
2108   rfont->descent = - ft_face->size->metrics.descender >> 6;
2109   rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2110   rfont->baseline_offset = 0;
2111   rfont->x_ppem = ft_face->size->metrics.x_ppem;
2112   rfont->y_ppem = ft_face->size->metrics.y_ppem;
2113 #ifdef HAVE_FTBDF_H
2114   {
2115     BDF_PropertyRec prop;
2116 
2117     if (! FT_IS_SCALABLE (ft_face)
2118 	&& FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2119       {
2120 	rfont->baseline_offset = prop.u.integer << 6;
2121 	rfont->ascent += prop.u.integer << 6;
2122 	rfont->descent -= prop.u.integer << 6;
2123       }
2124   }
2125 #endif	/* HAVE_FTBDF_H */
2126   if (FT_IS_SCALABLE (ft_face))
2127     rfont->average_width = 0;
2128   else
2129     rfont->average_width = ft_face->available_sizes->width << 6;
2130   rfont->next = MPLIST_VAL (frame->realized_font_list);
2131   MPLIST_VAL (frame->realized_font_list) = rfont;
2132 
2133   return rfont;
2134 }
2135 
2136 static void
ft_close(MRealizedFont * rfont)2137 ft_close (MRealizedFont *rfont)
2138 {
2139   if (! rfont->encapsulating)
2140     return;
2141   free (rfont->font);
2142   M17N_OBJECT_UNREF (rfont->info);
2143   free (rfont);
2144 }
2145 
2146 /* See the comment of parse_otf_command (m17n-flt.c).  */
2147 
2148 static int
ft_check_otf(MFLTFont * font,MFLTOtfSpec * spec)2149 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2150 {
2151 #define FEATURE_NONE(IDX) (! spec->features[IDX])
2152 
2153 #define FEATURE_ANY(IDX)	\
2154   (spec->features[IDX]		\
2155    && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
2156 
2157 #ifdef HAVE_OTF
2158   OTF_Tag *tags;
2159   int i, n, negative;
2160   OTF *otf = get_otf (font, NULL);
2161 
2162   if (FEATURE_ANY (0) && FEATURE_ANY (1))
2163     /* Return 1 iff any of GSUB or GPOS support the script (and language).  */
2164     return (otf
2165 	    && (OTF_check_features (otf, 0, spec->script, spec->langsys,
2166 				    NULL, 0) > 0
2167 		|| OTF_check_features (otf, 1, spec->script, spec->langsys,
2168 				       NULL, 0) > 0));
2169 
2170   for (i = 0; i < 2; i++)
2171     if (! FEATURE_ANY (i))
2172       {
2173 	if (FEATURE_NONE (i))
2174 	  {
2175 	    if (otf
2176 		&& OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2177 				       NULL, 0) > 0)
2178 	      return 0;
2179 	    continue;
2180 	  }
2181 	if (spec->features[i][0] == 0xFFFFFFFF)
2182 	  {
2183 	    if (! otf
2184 		|| OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2185 				       NULL, 0) <= 0)
2186 	      continue;
2187 	  }
2188 	else if (! otf)
2189 	  return 0;
2190 	for (n = 1; spec->features[i][n]; n++);
2191 	tags = alloca (sizeof (OTF_Tag) * n);
2192 	for (n = 0, negative = 0; spec->features[i][n]; n++)
2193 	  {
2194 	    if (spec->features[i][n] == 0xFFFFFFFF)
2195 	      negative = 1;
2196 	    else if (negative)
2197 	      tags[n - 1] = spec->features[i][n] | 0x80000000;
2198 	    else
2199 	      tags[n] = spec->features[i][n];
2200 	  }
2201 	if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2202 				tags, n - negative) != 1)
2203 	  return 0;
2204       }
2205   return 1;
2206 
2207 #endif	/* HAVE_OTF */
2208   return (FEATURE_NONE (0) ? (FEATURE_NONE (1) || FEATURE_ANY (1))
2209 	  : (FEATURE_NONE (1) && FEATURE_ANY (0)));
2210 }
2211 
2212 #ifdef HAVE_OTF
2213 
2214 static OTF *
get_otf(MFLTFont * font,FT_Face * ft_face)2215 get_otf (MFLTFont *font, FT_Face *ft_face)
2216 {
2217   MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2218   MFontFT *ft_info = (MFontFT *) rfont->font;
2219   MRealizedFontFT *ft_rfont = rfont->info;
2220   OTF *otf = ft_info->otf;
2221 
2222   if (! otf)
2223     {
2224 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2225       otf = OTF_open_ft_face (ft_rfont->ft_face);
2226 #else
2227       otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2228 #endif
2229       if (! otf || OTF_get_table (otf, "head") < 0)
2230 	otf = invalid_otf;
2231       ft_info->otf = otf;
2232     }
2233   if (ft_face)
2234     *ft_face = ft_rfont->ft_face;
2235   return (otf == invalid_otf ? NULL : otf);
2236 }
2237 
2238 #define DEVICE_DELTA(table, size)				\
2239   (((size) >= (table).StartSize && (size) <= (table).EndSize)	\
2240    ? (table).DeltaValue[(size) - (table).StartSize] << 6	\
2241    : 0)
2242 
2243 void
adjust_anchor(OTF_Anchor * anchor,FT_Face ft_face,unsigned code,int x_ppem,int y_ppem,int * x,int * y)2244 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2245 	       unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2246 {
2247   if (anchor->AnchorFormat == 2)
2248     {
2249       FT_Outline *outline;
2250       int ap = anchor->f.f1.AnchorPoint;
2251 
2252       FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2253       outline = &ft_face->glyph->outline;
2254       if (ap < outline->n_points)
2255 	{
2256 	  *x = outline->points[ap].x << 6;
2257 	  *y = outline->points[ap].y << 6;
2258 	}
2259     }
2260   else if (anchor->AnchorFormat == 3)
2261     {
2262       if (anchor->f.f2.XDeviceTable.offset)
2263 	*x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2264       if (anchor->f.f2.YDeviceTable.offset)
2265 	*y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2266     }
2267 }
2268 #endif	/* HAVE_OTF */
2269 
2270 #ifdef HAVE_OTF
2271 
2272 static int
ft_drive_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to,MFLTGlyphString * out,MFLTGlyphAdjustment * adjustment)2273 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2274 	      MFLTGlyphString *in, int from, int to,
2275 	      MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2276 {
2277   int len = to - from;
2278   int i, j, gidx;
2279   MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2280   MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
2281   OTF *otf;
2282   FT_Face face;
2283   OTF_GlyphString otf_gstring;
2284   OTF_Glyph *otfg;
2285   char script[5], *langsys = NULL;
2286   char *gsub_features = NULL, *gpos_features = NULL;
2287   unsigned int tag;
2288 
2289   if (len == 0)
2290     return from;
2291   otf = get_otf (font, &face);
2292   if (! otf)
2293     goto simple_copy;
2294   OTF_tag_name (spec->script, script);
2295   if (spec->langsys)
2296     {
2297       langsys = alloca (5);
2298       OTF_tag_name (spec->langsys, langsys);
2299     }
2300   for (i = 0; i < 2; i++)
2301     {
2302       char *p;
2303 
2304       if (spec->features[i])
2305 	{
2306 	  for (j = 0; spec->features[i][j]; j++);
2307 	  if (i == 0)
2308 	    p = gsub_features = alloca (6 * j);
2309 	  else
2310 	    p = gpos_features = alloca (6 * j);
2311 	  for (j = 0; spec->features[i][j]; j++)
2312 	    {
2313 	      if (spec->features[i][j] == 0xFFFFFFFF)
2314 		*p++ = '*', *p++ = ',';
2315 	      else
2316 		{
2317 		  OTF_tag_name (spec->features[i][j], p);
2318 		  p[4] = ',';
2319 		  p += 5;
2320 		}
2321 	    }
2322 	  *--p = '\0';
2323 	}
2324     }
2325 
2326   /* Extra room from pseudo glyphs.  OTF_drive_features () may need
2327      more rooms.  In that case, otf_gstring.glyphs is reallocated.  */
2328   otf_gstring.size = len * 2;
2329   if (! MTABLE_CALLOC_SAFE (otf_gstring.glyphs, otf_gstring.size))
2330     MERROR (MERROR_MEMORY, -1);
2331   for (i = 0; i < len; i++)
2332     {
2333       otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
2334       otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2335       otf_gstring.glyphs[i].positioning_type = ((MGlyph *)in->glyphs)[from + i].libotf_positioning_type;
2336     }
2337   otf_gstring.used = len;
2338 
2339   OTF_drive_gdef (otf, &otf_gstring);
2340   gidx = out ? out->used : from;
2341 
2342   if (gsub_features)
2343     {
2344       OTF_Feature *features;
2345       MGlyph *g;
2346 
2347 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2348       if (OTF_drive_gsub_features (otf, &otf_gstring, script, langsys,
2349 				   gsub_features) < 0)
2350 	goto simple_copy;
2351 #else
2352       if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
2353 				   gsub_features) < 0)
2354 	goto simple_copy;
2355 #endif
2356       features = otf->gsub->FeatureList.Feature;
2357       if (out)
2358 	{
2359 	  if (out->allocated < gidx + otf_gstring.used)
2360 	    return -2;
2361 	  for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2362 	       i < otf_gstring.used; i++, otfg++, g++, out->used++)
2363 	    {
2364 	      int j;
2365 	      int min_from, max_to;
2366 	      int feature_idx;
2367 
2368 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2369 	      feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2370 #else
2371 	      feature_idx = otfg->positioning_type >> 4;
2372 #endif
2373 
2374 	      *g = in_glyphs[from + otfg->f.index.from];
2375 	      min_from = g->g.from, max_to = g->g.to;
2376 	      g->g.c = 0;
2377 	      for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2378 		if (in_glyphs[from + j].g.code == otfg->glyph_id)
2379 		  {
2380 		    g->g.c = in_glyphs[from + j].g.c;
2381 		    break;
2382 		  }
2383 	      if (feature_idx)
2384 		{
2385 		  tag = features[feature_idx - 1].FeatureTag;
2386 		  tag = PACK_OTF_TAG (tag);
2387 		  g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2388 		}
2389 	      for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2390 		{
2391 		  if (min_from > in_glyphs[from + j].g.from)
2392 		    min_from = in_glyphs[from + j].g.from;
2393 		  if (max_to < in_glyphs[from + j].g.to)
2394 		    max_to = in_glyphs[from + j].g.to;
2395 		}
2396 	      if (g->g.code != otfg->glyph_id)
2397 		{
2398 		  g->g.code = otfg->glyph_id;
2399 		  g->g.measured = 0;
2400 		}
2401 	      g->g.from = min_from, g->g.to = max_to;
2402 	    }
2403 	}
2404       else
2405 	{
2406 	  for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2407 	       i++, otfg++)
2408 	    {
2409 	      int feature_idx;
2410 
2411 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2412 	      feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2413 #else
2414 	      feature_idx = otfg->positioning_type >> 4;
2415 #endif
2416 	      if (feature_idx)
2417 		{
2418 		  tag = features[feature_idx - 1].FeatureTag;
2419 		  tag = PACK_OTF_TAG (tag);
2420 		  for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2421 		    {
2422 		      g = in_glyphs + (from + j);
2423 		      g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2424 		    }
2425 		}
2426 	    }
2427 	}
2428     }
2429   else if (out)
2430     {
2431       if (out->allocated < gidx + len)
2432 	return -2;
2433       for (i = 0; i < len; i++)
2434 	out_glyphs[out->used++] = in_glyphs[from + i];
2435     }
2436 
2437   if (gpos_features)
2438     {
2439       OTF_Feature *features;
2440       MGlyph *g;
2441 
2442 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2443       if (OTF_drive_gpos_features (otf, &otf_gstring, script, langsys,
2444 				   gpos_features) < 0)
2445 	return to;
2446 #else
2447       if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2448 				   gpos_features) < 0)
2449 	return to;
2450 #endif
2451       features = otf->gpos->FeatureList.Feature;
2452       if (out)
2453 	{
2454 	  MGlyph *base = NULL, *mark = NULL;
2455 	  int x_ppem = face->size->metrics.x_ppem;
2456 	  int y_ppem = face->size->metrics.y_ppem;
2457 	  int x_scale = face->size->metrics.x_scale;
2458 	  int y_scale = face->size->metrics.y_scale;
2459 
2460 	  for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2461 	       i < otf_gstring.used; i++, otfg++)
2462 	    {
2463 	      MGlyph *prev;
2464 	      int adjust_idx = otfg->glyph_id ? j : j - 1;
2465 	      int positioning_type, feature_idx;
2466 
2467 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2468 	      positioning_type = OTF_POSITIONING_TYPE_GET_FORMAT (otfg);
2469 	      feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2470 #else
2471 	      positioning_type = otfg->positioning_type & 0xF;
2472 	      feature_idx = otfg->positioning_type >> 4;
2473 #endif
2474 
2475 	      if (feature_idx)
2476 		{
2477 		  tag = features[feature_idx - 1].FeatureTag;
2478 		  tag = PACK_OTF_TAG (tag);
2479 		  g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2480 		}
2481 
2482 	      switch (positioning_type)
2483 		{
2484 		case 0:
2485 		  break;
2486 		case 1: 		/* Single */
2487 		case 2: 		/* Pair */
2488 		  {
2489 		    int format = otfg->f.f1.format;
2490 
2491 		    if (format & OTF_XPlacement)
2492 		      adjustment[adjust_idx].xoff
2493 			+= otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2494 		    if (format & OTF_XPlaDevice)
2495 		      adjustment[adjust_idx].xoff
2496 			+= DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2497 		    if (format & OTF_YPlacement)
2498 		      adjustment[adjust_idx].yoff
2499 			-= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2500 		    if (format & OTF_YPlaDevice)
2501 		      adjustment[adjust_idx].yoff
2502 			-= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2503 		    if (format & OTF_XAdvance)
2504 		      adjustment[adjust_idx].xadv
2505 			+= otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2506 		    if (format & OTF_XAdvDevice)
2507 		      adjustment[adjust_idx].xadv
2508 			+= DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2509 		    if (format & OTF_YAdvance)
2510 		      adjustment[adjust_idx].yadv
2511 			+= otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2512 		    if (format & OTF_YAdvDevice)
2513 		      adjustment[adjust_idx].yadv
2514 			+= DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2515 		    adjustment[adjust_idx].set = 1;
2516 		  }
2517 		  break;
2518 		case 3:		/* Cursive */
2519 		  /* Not yet supported.  */
2520 		  break;
2521 		case 4:		/* Mark-to-Base */
2522 		case 5:		/* Mark-to-Ligature */
2523 		  if (! base)
2524 		    break;
2525 		  prev = base;
2526 		  goto label_adjust_anchor;
2527 		default:		/* i.e. case 6 Mark-to-Mark */
2528 		  if (! mark)
2529 		    break;
2530 		  prev = mark;
2531 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2532 		  {
2533 		    int distance = OTF_POSITIONING_TYPE_GET_MARKDISTANCE (otfg);
2534 
2535 		    if (distance > 0)
2536 		      {
2537 			prev = g - distance;
2538 			if (prev < out_glyphs)
2539 			  prev = mark;
2540 		      }
2541 		  }
2542 #endif
2543 		label_adjust_anchor:
2544 		  {
2545 		    int base_x, base_y, mark_x, mark_y;
2546 		    int this_from, this_to;
2547 		    int k;
2548 
2549 		    base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2550 		    base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2551 		    mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2552 		    mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2553 
2554 		    if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2555 		      adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2556 				     x_ppem, y_ppem, &base_x, &base_y);
2557 		    if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2558 		      adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2559 				     x_ppem, y_ppem, &mark_x, &mark_y);
2560 		    adjustment[adjust_idx].xoff = base_x - mark_x;
2561 		    adjustment[adjust_idx].yoff = - (base_y - mark_y);
2562 		    adjustment[adjust_idx].back = (g - prev);
2563 		    adjustment[adjust_idx].xadv = 0;
2564 		    adjustment[adjust_idx].advance_is_absolute = 1;
2565 		    adjustment[adjust_idx].set = 1;
2566 		    this_from = g->g.from;
2567 		    this_to = g->g.to;
2568 		    for (k = 0; prev + k < g; k++)
2569 		      {
2570 			if (this_from > prev[k].g.from)
2571 			  this_from = prev[k].g.from;
2572 			if (this_to < prev[k].g.to)
2573 			  this_to = prev[k].g.to;
2574 		      }
2575 		    for (; prev <= g; prev++)
2576 		      {
2577 			prev->g.from = this_from;
2578 			prev->g.to = this_to;
2579 		      }
2580 		  }
2581 		}
2582 	      if (otfg->glyph_id)
2583 		{
2584 		  if (otfg->GlyphClass == OTF_GlyphClass0)
2585 		    base = mark = g;
2586 		  else if (otfg->GlyphClass == OTF_GlyphClassMark)
2587 		    mark = g;
2588 		  else
2589 		    base = g;
2590 		  j++, g++;
2591 		}
2592 	    }
2593 	}
2594       else
2595 	{
2596 	  for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2597 	       i++, otfg++)
2598 	    if (otfg->positioning_type & 0xF)
2599 	      {
2600 		int feature_idx;
2601 
2602 #ifdef OTF_POSITIONING_TYPE_GET_FORMAT
2603 		feature_idx = OTF_POSITIONING_TYPE_GET_FEATURE (otfg);
2604 #else
2605 		feature_idx = otfg->positioning_type >> 4;
2606 #endif
2607 		if (feature_idx)
2608 		  {
2609 		    tag = features[feature_idx - 1].FeatureTag;
2610 		    tag = PACK_OTF_TAG (tag);
2611 		    for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2612 		      {
2613 			g = in_glyphs + (from + j);
2614 			g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2615 		      }
2616 		  }
2617 	      }
2618 	}
2619     }
2620 
2621   free (otf_gstring.glyphs);
2622   return to;
2623 
2624  simple_copy:
2625   if (otf_gstring.glyphs)
2626     free (otf_gstring.glyphs);
2627   if (out)
2628     {
2629       if (out->allocated < out->used + len)
2630 	return -2;
2631       font->get_metrics (font, in, from, to);
2632       memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2633 	      sizeof (MGlyph) * len);
2634       out->used += len;
2635     }
2636   return to;
2637 }
2638 
2639 #else  /* not HAVE_OTF */
2640 
2641 static int
ft_drive_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to,MFLTGlyphString * out,MFLTGlyphAdjustment * adjustment)2642 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2643 	      MFLTGlyphString *in, int from, int to,
2644 	      MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2645 {
2646   int len = to - from;
2647   if (out)
2648     {
2649       if (out->allocated < out->used + len)
2650 	return -2;
2651       font->get_metrics (font, in, from, to);
2652       memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2653 	      sizeof (MGlyph) * len);
2654       out->used += len;
2655     }
2656   return to;
2657 }
2658 
2659 #endif	/* not HAVE_OTF */
2660 
2661 
2662 static int
ft_try_otf(MFLTFont * font,MFLTOtfSpec * spec,MFLTGlyphString * in,int from,int to)2663 ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2664 	    MFLTGlyphString *in, int from, int to)
2665 {
2666   return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
2667 }
2668 
2669 
2670 #ifdef HAVE_OTF
2671 static unsigned char *iterate_bitmap;
2672 
2673 static int
iterate_callback(OTF * otf,const char * feature,unsigned glyph_id)2674 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2675 {
2676   if (glyph_id <= otf->cmap->max_glyph_id)
2677     iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2678   return 0;
2679 }
2680 
2681 static int
ft_iterate_otf_feature(MFLTFont * font,MFLTOtfSpec * spec,int from,int to,unsigned char * table)2682 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2683 			int from, int to, unsigned char *table)
2684 {
2685   OTF *otf = get_otf (font, NULL);
2686   char id[13];
2687   int bmp_size;
2688   unsigned char *bitmap = NULL;
2689   int i, j;
2690   char script[5], *langsys = NULL;
2691 
2692   if (! otf)
2693     return -1;
2694   if (OTF_get_table (otf, "cmap") < 0)
2695     return -1;
2696   if (! spec->features[0])
2697     return -1;
2698   strcpy (id, "feature-");
2699   id[12] = '\0';
2700   OTF_tag_name (spec->script, script);
2701   if (spec->langsys)
2702     {
2703       langsys = alloca (5);
2704       OTF_tag_name (spec->langsys, langsys);
2705     }
2706   bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2707   for (i = 0; spec->features[0][i]; i++)
2708     {
2709       unsigned char *bmp;
2710 
2711       OTF_tag_name (spec->features[0][i], id + 8);
2712       bmp = OTF_get_data (otf, id);
2713       if (! bmp)
2714 	{
2715 	  iterate_bitmap = bmp = calloc (bmp_size, 1);
2716 	  OTF_iterate_gsub_feature (otf, iterate_callback,
2717 				    script, langsys, id + 8);
2718 	  OTF_put_data (otf, id, bmp, free);
2719 	}
2720       if (i == 0 && ! spec->features[0][1])
2721 	/* Single feature */
2722 	bitmap = bmp;
2723       else
2724 	{
2725 	  if (! bitmap)
2726 	    {
2727 	      bitmap = alloca (bmp_size);
2728 	      memcpy (bitmap, bmp, bmp_size);
2729 	    }
2730 	  else
2731 	    {
2732 	      int j;
2733 
2734 	      for (j = 0; j < bmp_size; j++)
2735 		bitmap[j] &= bmp[j];
2736 	    }
2737 	}
2738     }
2739   for (i = 0; i < bmp_size; i++)
2740     if (bitmap[i])
2741       {
2742 	for (j = 0; j < 8; j++)
2743 	  if (bitmap[i] & (1 << j))
2744 	    {
2745 	      int c = OTF_get_unicode (otf, (i * 8) + j);
2746 
2747 	      if (c >= from && c <= to)
2748 		table[c - from] = 1;
2749 	    }
2750       }
2751   return 0;
2752 }
2753 #endif
2754 
2755 
2756 
2757 /* Internal API */
2758 
2759 MFontDriver mfont__ft_driver =
2760   { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2761     ft_render, ft_list, ft_list_family_names, ft_check_capability,
2762     ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
2763 #ifdef HAVE_OTF
2764     ft_iterate_otf_feature
2765 #endif	/* HAVE_OTF */
2766   };
2767 
2768 int
mfont__ft_init()2769 mfont__ft_init ()
2770 {
2771   int i;
2772 
2773   if (FT_Init_FreeType (&ft_library) != 0)
2774     MERROR (MERROR_FONT_FT, -1);
2775 
2776   for (i = 0; i < ft_to_prop_size; i++)
2777     ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2778 
2779   Mmedium = msymbol ("medium");
2780   Mr = msymbol ("r");
2781   Mnull = msymbol ("");
2782 
2783   M0[0] = msymbol ("0-0");
2784   M0[1] = msymbol ("0-1");
2785   M0[2] = msymbol ("0-2");
2786   M0[3] = msymbol ("0-3");
2787   M0[4] = msymbol ("0-4");
2788   M3_1 = msymbol ("3-1");
2789   M1_0 = msymbol ("1-0");
2790 
2791 #ifdef HAVE_FONTCONFIG
2792   for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2793     {
2794       FC_vs_M17N_font_prop *table = fc_all_table[i];
2795       int j;
2796 
2797       for (j = 0; table[j].m17n_value; j++)
2798 	table[j].sym = msymbol (table[j].m17n_value);
2799       table[j].sym = table[j - 1].sym;
2800     }
2801 
2802   {
2803     char *pathname;
2804     struct stat buf;
2805     MPlist *plist;
2806     MSymbol serif, sans_serif, monospace;
2807 
2808     fc_config = FcInitLoadConfigAndFonts ();
2809     if (mfont_freetype_path)
2810       {
2811 	MPLIST_DO (plist, mfont_freetype_path)
2812 	  if (MPLIST_STRING_P (plist)
2813 	      && (pathname = MPLIST_STRING (plist))
2814 	      && stat (pathname, &buf) == 0)
2815 	    {
2816 	      FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2817 	      FcChar8 *dir;
2818 
2819 	      while ((dir = FcStrListNext (strlist)))
2820 		if (strcmp ((char *) dir, pathname) == 0)
2821 		  break;
2822 	      if (! dir)
2823 		FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2824 	      FcStrListDone (strlist);
2825 	    }
2826       }
2827     Mgeneric_family = msymbol ("generic famly");
2828     serif = msymbol ("serif");
2829     msymbol_put (serif, Mgeneric_family, serif);
2830     sans_serif = msymbol ("sans-serif");
2831     msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2832     msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2833     msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2834     monospace = msymbol ("monospace");
2835     msymbol_put (monospace, Mgeneric_family, monospace);
2836     msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2837   }
2838 #endif	/* HAVE_FONTCONFIG */
2839 
2840   return 0;
2841 }
2842 
2843 void
mfont__ft_fini()2844 mfont__ft_fini ()
2845 {
2846   MPlist *plist, *p;
2847 
2848   if (ft_default_list)
2849     {
2850       M17N_OBJECT_UNREF (ft_default_list);
2851       ft_default_list = NULL;
2852     }
2853 
2854   if (ft_font_list)
2855     {
2856       MPLIST_DO (plist, ft_font_list)
2857 	{
2858 	  if (MPLIST_VAL (plist))
2859 	    MPLIST_DO (p, MPLIST_VAL (plist))
2860 	      {
2861 		if (MPLIST_KEY (p) != Mt)
2862 		  free_ft_info (MPLIST_VAL (p));
2863 	      }
2864 	  M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2865 	}
2866       M17N_OBJECT_UNREF (ft_font_list);
2867       ft_font_list = NULL;
2868 
2869       if (ft_language_list)
2870 	{
2871 	  MPLIST_DO (plist, ft_language_list)
2872 	    M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2873 	  M17N_OBJECT_UNREF (ft_language_list);
2874 	  ft_language_list = NULL;
2875 	}
2876 
2877       if (ft_script_list)
2878 	{
2879 	  MPLIST_DO (plist, ft_script_list)
2880 	    M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2881 	  M17N_OBJECT_UNREF (ft_script_list);
2882 	  ft_script_list = NULL;
2883 	}
2884 
2885       if (ft_capability_list)
2886 	{
2887 	  MPLIST_DO (plist, ft_capability_list)
2888 	    M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2889 	  M17N_OBJECT_UNREF (ft_capability_list);
2890 	  ft_capability_list = NULL;
2891 	}
2892 
2893       if (ft_file_list)
2894 	{
2895 	  MPLIST_DO (plist, ft_file_list)
2896 	    M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2897 	  M17N_OBJECT_UNREF (ft_file_list);
2898 	  ft_file_list = NULL;
2899 	}
2900     }
2901   FT_Done_FreeType (ft_library);
2902 #ifdef HAVE_FONTCONFIG
2903   FcConfigDestroy (fc_config);
2904   fc_config = NULL;
2905 #endif	/* HAVE_FONTCONFIG */
2906   all_fonts_scaned = 0;
2907 }
2908 
2909 #ifdef HAVE_FONTCONFIG
2910 
2911 int
mfont__ft_parse_name(const char * name,MFont * font)2912 mfont__ft_parse_name (const char *name, MFont *font)
2913 {
2914   FcPattern *pat = FcNameParse ((FcChar8 *) name);
2915   FcChar8 *str;
2916   int val;
2917   double size;
2918   char *buf;
2919   int bufsize = 0;
2920 
2921   if (! pat)
2922     return -1;
2923   if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2924     {
2925       STRDUP_LOWER (buf, bufsize, (char *) str);
2926       mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2927     }
2928   if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2929     {
2930       STRDUP_LOWER (buf, bufsize, (char *) str);
2931       mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2932     }
2933   if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2934     mfont__set_property (font, MFONT_WEIGHT,
2935 			 fc_decode_prop (val, fc_weight_table,
2936 					 fc_weight_table_size));
2937   if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2938     mfont__set_property (font, MFONT_STYLE,
2939 			 fc_decode_prop (val, fc_slant_table,
2940 					 fc_slant_table_size));
2941   if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2942     mfont__set_property (font, MFONT_STRETCH,
2943 			 fc_decode_prop (val, fc_width_table,
2944 					 fc_width_table_size));
2945   if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2946     font->size = size * 10 + 0.5;
2947   else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2948     font->size = - (size * 10 + 0.5);
2949   if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2950     {
2951       font->file = msymbol ((char *) str);
2952     }
2953   mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2954   font->type = MFONT_TYPE_SPEC;
2955   FcPatternDestroy (pat);
2956   return 0;
2957 }
2958 
2959 char *
mfont__ft_unparse_name(MFont * font)2960 mfont__ft_unparse_name (MFont *font)
2961 {
2962   FcPattern *pat = fc_get_pattern (font);
2963   char *name = (char *) FcNameUnparse (pat);
2964 
2965   FcPatternDestroy (pat);
2966   return name;
2967 }
2968 #endif	/* HAVE_FONTCONFIG */
2969 
2970 #endif /* HAVE_FREETYPE */
2971