1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
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.
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.
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,
28 #include <sys/types.h>
35 #include "m17n-misc.h"
40 #include "internal-flt.h"
41 #include "internal-gui.h"
51 static int mdebug_flag = MDEBUG_FONT;
53 #ifdef HAVE_FONTCONFIG
54 #include <fontconfig/fcfreetype.h>
56 static FcConfig *fc_config;
57 static MSymbol Mgeneric_family;
58 #endif /* HAVE_FONTCONFIG */
60 /* Font properties; Mnormal is already defined in face.c. */
61 static MSymbol Mmedium, Mr, Mnull;
63 static MSymbol M0[5], M3_1, M1_0;
65 static FT_Library ft_library;
68 static OTF *invalid_otf = (OTF *) "";
69 static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
76 /* NULL if not yet opened. invalid_otf if not OTF. */
79 #ifdef HAVE_FONTCONFIG
82 #endif /* HAVE_FONTCONFIG */
88 FT_Face ft_face; /* This must be the 2nd member. */
90 int face_encapsulated;
97 enum MFontProperty prop;
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];
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;
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;
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;
129 static MPlist *ft_file_list;
131 static int all_fonts_scaned;
133 #define STRDUP_LOWER(s1, size, s2) \
135 int len = strlen (s2) + 1; \
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); \
146 static MPlist *ft_list_family (MSymbol, int, int);
149 free_ft_rfont (void *object)
151 MRealizedFontFT *ft_rfont = object;
153 if (! ft_rfont->face_encapsulated)
155 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
156 FT_Done_Face (ft_rfont->ft_face);
162 free_ft_info (MFontFT *ft_info)
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 */
178 ft_get_charmaps (FT_Face ft_face)
180 MPlist *plist = mplist ();
181 int unicode_bmp = -1, unicode_full = -1;
184 mplist_add (plist, Mt, (void *) -1);
185 for (i = 0; i < ft_face->num_charmaps; i++)
187 MSymbol registry = Mnil;
189 if (ft_face->charmaps[i]->platform_id == 0)
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;
196 else if (ft_face->charmaps[i]->platform_id == 3)
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;
203 else if (ft_face->charmaps[i]->platform_id == 1
204 && ft_face->charmaps[i]->encoding_id == 0)
207 mplist_add (plist, Mapple_roman, (void *) i);
209 if (registry == Mnil)
211 char registry_buf[16];
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);
218 mplist_add (plist, registry, (void *) i);
220 if (unicode_full >= 0)
221 mplist_add (plist, Municode_full, (void *) unicode_full);
222 if (unicode_bmp >= 0)
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++);
231 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
233 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
241 ft_gen_font (FT_Face ft_face)
251 if (FT_IS_SCALABLE (ft_face))
252 size = ft_face->size->metrics.y_ppem;
253 else if (ft_face->num_fixed_sizes == 0)
256 size = ft_face->available_sizes[0].height;
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;
273 stylename = ft_face->style_name;
278 for (i = 0; i < ft_to_prop_size; i++)
279 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
282 mfont__set_property (font, ft_to_prop[i].prop,
283 msymbol (ft_to_prop[i].val));
284 stylename += ft_to_prop[i].len;
287 if (i == ft_to_prop_size)
289 char *p1 = stylename + 1;
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))
297 mfont__set_property (font, i, sym);
302 while (*stylename && ! isalpha (*stylename))
308 #ifdef HAVE_FONTCONFIG
315 } FC_vs_M17N_font_prop;
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);
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);
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);
359 static FC_vs_M17N_font_prop *fc_all_table[] =
360 { fc_weight_table, fc_slant_table, fc_width_table };
363 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
367 if (val < table[i].fc_value)
369 for (i--; i >= 0; i--)
370 if (val > table[i].fc_value)
374 else if (val > table[i].fc_value)
376 for (i++; i < size; i++)
377 if (val < table[i].fc_value)
385 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
389 for (i = 0; table[i].m17n_value; i++)
390 if (table[i].sym == sym)
392 return table[i].fc_value;
396 fc_get_pattern (MFont *font)
398 FcPattern *pat = FcPatternCreate ();
399 MSymbol sym, weight, style, stretch;
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));
417 double size = font->size;
418 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
420 else if (font->size < 0)
422 double size = - font->size;
423 FcPatternAddDouble (pat, FC_SIZE, size / 10);
429 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
439 MFont *font = &ft_info->font;
442 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
444 STRDUP_LOWER (buf, bufsize, (char *) str);
445 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
448 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
449 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
451 STRDUP_LOWER (buf, bufsize, (char *) str);
452 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
454 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
456 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
457 mfont__set_property (font, MFONT_WEIGHT, sym);
459 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
461 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
462 mfont__set_property (font, MFONT_STYLE, sym);
464 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
466 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
467 mfont__set_property (font, MFONT_STRETCH, sym);
469 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
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);
477 if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
478 ft_info->charset = FcCharSetCopy (cs);
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);
491 fc_gen_font (FcPattern *pat, char *family)
495 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
496 fc_parse_pattern (pat, family, ft_info);
497 ft_info->font.type = MFONT_TYPE_OBJECT;
502 fc_init_font_list (void)
504 FcPattern *pattern = FcPatternCreate ();
505 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
506 FcFontSet *fs = FcFontList (fc_config, pattern, os);
507 MPlist *plist = mplist ();
512 ft_font_list = plist;
513 for (i = 0; i < fs->nfont; i++)
517 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
518 (FcChar8 **) &fam) != FcResultMatch)
520 STRDUP_LOWER (buf, bufsize, fam);
521 plist = mplist_add (plist, msymbol (buf), NULL);
523 FcFontSetDestroy (fs);
524 FcObjectSetDestroy (os);
525 FcPatternDestroy (pattern);
529 fc_list_pattern (FcPattern *pattern)
531 FcObjectSet *os = NULL;
532 FcFontSet *fs = NULL;
533 MSymbol last_family = Mnil;
534 MPlist *plist = NULL, *pl = NULL;
539 if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
541 if (! (fs = FcFontList (fc_config, pattern, os)))
544 for (i = 0; i < fs->nfont; i++)
546 MSymbol family, file;
547 char *fam, *filename;
550 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
551 (FcChar8 **) &fam) != FcResultMatch)
553 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
554 (FcChar8 **) &filename) != FcResultMatch)
556 STRDUP_LOWER (buf, bufsize, fam);
557 family = msymbol (buf);
558 file = msymbol (filename);
559 if (family != last_family)
561 pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
562 last_family = family;
564 ft_info = mplist_get (pl, file);
569 mplist_add (plist, family, ft_info);
574 if (fs) FcFontSetDestroy (fs);
575 if (os) FcObjectSetDestroy (os);
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
584 fc_build_charset (MPlist *char_list, MText *mt)
586 FcCharSet *cs = FcCharSetCreate ();
592 for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
593 if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
595 FcCharSetDestroy (cs);
603 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
604 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
606 FcCharSetDestroy (cs);
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)))
614 FcCharSetDestroy (cs);
621 #else /* not HAVE_FONTCONFIG */
624 ft_add_font (char *filename)
637 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
639 ft_info = ft_gen_font (ft_face);
640 FT_Done_Face (ft_face);
644 font = &ft_info->font;
645 font->file = msymbol (filename);
647 plist = mplist_find_by_key (ft_font_list, family);
649 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
653 mplist_add (plist, font->file, ft_info);
654 plist = mplist_push (ft_font_list, family, plist);
660 ft_init_font_list (void)
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)
674 if (S_ISREG (buf.st_mode))
675 ft_add_font (pathname);
676 else if (S_ISDIR (buf.st_mode))
678 DIR *dir = opendir (pathname);
682 int len = strlen (pathname);
685 while ((dp = readdir (dir)) != NULL)
687 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
688 strcpy (path, pathname);
690 strcpy (path + len + 1, dp->d_name);
700 /* Return 1 iff the font pointed by FT_INFO has all characters in
704 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
709 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
711 MPLIST_DO (cl, char_list)
712 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
714 FT_Done_Face (ft_face);
715 return MPLIST_TAIL_P (cl);
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
723 ft_list_char_list (MPlist *char_list, MText *mt)
725 MPlist *plist = NULL, *pl, *p;
728 ft_list_family (Mnil, 0, 1);
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);
737 char_list = mplist ();
738 for (i = 0; i < total_len; i++)
740 int c = (i < len ? mtext_ref_char (mt, i)
741 : mtext_ref_char (extra, i - len));
743 if (! mplist_find_by_value (char_list, (void *) c))
744 mplist_push (char_list, Minteger, (void *) c);
748 MPLIST_DO (pl, ft_font_list)
750 MPLIST_DO (p, MPLIST_PLIST (pl))
752 MFontFT *ft_info = MPLIST_VAL (p);
754 if (ft_has_char_list_p (ft_info, char_list))
756 MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
760 mplist_push (plist, family, ft_info);
765 M17N_OBJECT_UNREF (char_list);
768 #endif /* not HAVE_FONTCONFIG */
771 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
772 scan all fonts and return ft_font_list. */
775 ft_list_family (MSymbol family, int check_generic, int check_alias)
778 #ifdef HAVE_FONTCONFIG
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++)
799 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
800 (FcChar8 **) &fam) != FcResultMatch)
802 STRDUP_LOWER (buf, bufsize, fam);
804 if (! mplist_find_by_key (ft_font_list, sym))
805 plist = mplist_add (plist, sym, NULL);
807 FcFontSetDestroy (fs);
808 FcObjectSetDestroy (os);
809 FcPatternDestroy (pattern);
814 if (! all_fonts_scaned)
816 MPLIST_DO (plist, ft_font_list)
818 if (! MPLIST_VAL (plist))
819 ft_list_family (MPLIST_KEY (plist), 0, 1);
821 all_fonts_scaned = 1;
826 plist = mplist_find_by_key (ft_font_list, family);
829 if (! MPLIST_VAL (plist))
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,
837 fs = FcFontList (fc_config, pattern, os);
839 for (i = 0; i < fs->nfont; i++)
841 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
842 p = mplist_add (p, ft_info->font.file, ft_info);
844 MPLIST_VAL (plist) = pl;
845 FcFontSetDestroy (fs);
846 FcObjectSetDestroy (os);
847 FcPatternDestroy (pattern);
850 else if (check_generic
851 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
853 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
856 if (family != generic)
857 plist = ft_list_family (generic, 1, 1);
860 fam = MSYMBOL_NAME (family);
862 mplist_push (ft_font_list, family, plist);
863 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
864 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
867 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
870 STRDUP_LOWER (buf, bufsize, (char *) fam8);
871 family = msymbol (buf);
872 if (msymbol_get (family, Mgeneric_family))
874 pl = ft_list_family (family, 0, 1);
877 MPLIST_DO (pl, MPLIST_PLIST (pl))
878 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
880 plist = ft_font_list;
883 else if (check_alias)
885 /* Check if there exist an alias. */
887 plist = mplist_add (ft_font_list, family, pl);
889 pattern = FcPatternBuild (NULL,
890 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
892 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
894 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
895 (FcChar8 **) &fam) == FcResultMatch;
899 /* The last one is a generic family. */
902 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
905 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
906 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
907 (FcChar8 **) &fam) == FcResultMatch;
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. */
914 for (i = 1; i < j; i++)
916 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
917 STRDUP_LOWER (buf, bufsize, fam);
919 p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
920 if (! MPLIST_TAIL_P (p))
922 mplist_push (pl, Mt, MPLIST_VAL (p));
929 plist = mplist_add (ft_font_list, family, pl);
932 #else /* not HAVE_FONTCONFIG */
934 if (! all_fonts_scaned)
936 ft_init_font_list ();
937 all_fonts_scaned = 1;
940 plist = ft_font_list;
943 plist = mplist_find_by_key (ft_font_list, family);
945 plist = mplist_push (ft_font_list, family, mplist ());
947 #endif /* not HAVE_FONTCONFIG */
953 ft_list_language (MSymbol language)
955 MPlist *plist = NULL;
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);
963 mt = mlanguage_text (language);
965 #ifdef HAVE_FONTCONFIG
967 FcPattern *pattern = NULL;
968 FcCharSet *cs = NULL;
969 FcLangSet *ls = NULL;
971 if (! (pattern = FcPatternCreate ()))
974 if (mt && mtext_nchars (mt) > 0)
976 cs = fc_build_charset (NULL, mt);
977 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
982 if (! (ls = FcLangSetCreate ()))
984 if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
985 || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
989 plist = fc_list_pattern (pattern);
991 if (cs) FcCharSetDestroy (cs);
992 if (ls) FcLangSetDestroy (ls);
993 if (pattern) FcPatternDestroy (pattern);
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 */
1000 mplist_push (ft_language_list, language, plist);
1005 ft_list_script (MSymbol script)
1007 MPlist *plist = NULL;
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);
1015 char_list = mscript__char_list (script);
1017 #ifdef HAVE_FONTCONFIG
1020 FcPattern *pattern = NULL;
1023 if (! (pattern = FcPatternCreate ()))
1025 cs = fc_build_charset (char_list, NULL);
1026 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1028 plist = fc_list_pattern (pattern);
1030 if (cs) FcCharSetDestroy (cs);
1031 if (pattern) FcPatternDestroy (pattern);
1033 #else /* not HAVE_FONTCONFIG */
1035 plist = ft_list_char_list (char_list, NULL);
1036 #endif /* not HAVE_FONTCONFIG */
1038 mplist_push (ft_script_list, script, plist);
1043 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1046 if (ft_info->otf == invalid_otf)
1050 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1052 ft_info->otf = OTF_open_ft_face (ft_face);
1055 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1058 ft_info->otf = invalid_otf;
1062 if (cap->features[MFONT_OTT_GSUB].nfeatures
1063 && (OTF_check_features
1065 cap->script_tag, cap->langsys_tag,
1066 cap->features[MFONT_OTT_GSUB].tags,
1067 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1069 if (cap->features[MFONT_OTT_GPOS].nfeatures
1070 && (OTF_check_features
1072 cap->script_tag, cap->langsys_tag,
1073 cap->features[MFONT_OTT_GPOS].tags,
1074 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1077 #else /* not HAVE_OTF */
1079 #endif /* not HAVE_OTF */
1083 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1087 int ft_face_allocaed = 0;
1091 #ifdef HAVE_FONTCONFIG
1092 if (ft_info->langset
1093 && (FcLangSetHasLang (ft_info->langset,
1094 (FcChar8 *) MSYMBOL_NAME (language))
1095 != FcLangDifferentLang))
1097 #endif /* HAVE_FONTCONFIG */
1099 mt = mlanguage_text (language);
1100 if (! mt || mtext_nchars (mt) == 0)
1105 char *filename = MSYMBOL_NAME (ft_info->font.file);
1107 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1109 ft_face_allocaed = 1;
1112 len = mtext_nchars (mt);
1113 extra = mtext_get_prop (mt, 0, Mtext);
1114 total_len = len + (extra ? mtext_nchars (extra) : 0);
1116 for (i = 0; i < total_len; i++)
1118 int c = (i < len ? mtext_ref_char (mt, i)
1119 : mtext_ref_char (extra, i - len));
1121 #ifdef HAVE_FONTCONFIG
1122 if (ft_info->charset
1123 && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1125 #endif /* HAVE_FONTCONFIG */
1126 if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1130 if (ft_face_allocaed)
1131 FT_Done_Face (ft_face);
1133 return (i == total_len ? 0 : -1);
1137 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1139 MPlist *char_list = mscript__char_list (script);
1143 #ifdef HAVE_FONTCONFIG
1144 if (ft_info->charset)
1146 MPLIST_DO (char_list, char_list)
1147 if (FcCharSetHasChar (ft_info->charset,
1148 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1152 #endif /* HAVE_FONTCONFIG */
1154 int ft_face_allocaed = 0;
1158 char *filename = MSYMBOL_NAME (ft_info->font.file);
1160 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1162 ft_face_allocaed = 1;
1165 MPLIST_DO (char_list, char_list)
1166 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1169 if (ft_face_allocaed)
1170 FT_Done_Face (ft_face);
1173 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1176 static MPlist *ft_default_list;
1181 if (ft_default_list)
1182 return ft_default_list;
1183 ft_default_list = mplist ();
1184 #ifdef HAVE_FONTCONFIG
1186 FcPattern *pat = FcPatternCreate ();
1192 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1193 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1199 STRDUP_LOWER (buf, bufsize, (char *) fam);
1200 family = msymbol (buf);
1201 if (msymbol_get (family, Mgeneric_family))
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));
1208 #else /* not HAVE_FONTCONFIG */
1212 MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
1214 pl = MPLIST_PLIST (plist);
1215 if (! MPLIST_TAIL_P (pl))
1216 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1219 #endif /* not HAVE_FONTCONFIG */
1220 return ft_default_list;
1224 static MPlist *ft_capability_list;
1227 ft_list_capability (MSymbol capability)
1229 MFontCapability *cap;
1230 MPlist *plist = NULL, *pl;
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);
1237 cap = mfont__get_capability (capability);
1239 if (cap && cap->language != Mnil)
1241 plist = ft_list_language (cap->language);
1244 plist = mplist_copy (plist);
1247 if (cap && cap->script != Mnil)
1251 plist = ft_list_script (cap->script);
1254 plist = mplist_copy (plist);
1258 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1260 if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1263 pl = MPLIST_NEXT (pl);
1267 if (cap->script_tag)
1269 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1271 if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1274 pl = MPLIST_NEXT (pl);
1278 if (MPLIST_TAIL_P (plist))
1280 M17N_OBJECT_UNREF (plist);
1285 mplist_push (ft_capability_list, capability, plist);
1291 ft_list_file (MSymbol filename)
1293 MPlist *plist = NULL;
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);
1300 #ifdef HAVE_FONTCONFIG
1302 FcPattern *pattern = FcPatternCreate ();
1306 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1307 os = FcObjectSetBuild (FC_FAMILY, NULL);
1308 fs = FcFontList (fc_config, pattern, os);
1315 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1316 (FcChar8 **) &fam) == FcResultMatch)
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))
1326 MFontFT *ft_info = MPLIST_VAL (pl);
1328 if (ft_info->font.file == filename)
1331 mplist_add (plist, family, ft_info);
1338 #else /* not HAVE_FONTCONFIG */
1342 MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
1344 MPLIST_DO (p, MPLIST_PLIST (pl))
1346 MFontFT *ft_info = MPLIST_VAL (pl);
1348 if (ft_info->font.file == filename)
1351 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1359 #endif /* not HAVE_FONTCONFIG */
1361 mplist_push (ft_file_list, filename, plist);
1365 /* The FreeType font driver function SELECT. */
1368 ft_select (MFrame *frame, MFont *font, int limited_size)
1370 MFont *found = NULL;
1371 #ifdef HAVE_FONTCONFIG
1374 int check_font_property = 1;
1376 if (font->file != Mnil)
1378 plist = ft_list_file (font->file);
1381 check_font_property = 0;
1385 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1388 plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
1390 plist = ft_list_default ();
1391 if (MPLIST_TAIL_P (plist))
1395 plist = mplist_copy (plist);
1397 if (font->capability != Mnil)
1399 MFontCapability *cap = mfont__get_capability (font->capability);
1401 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1403 if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1409 && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1412 pl = MPLIST_NEXT (pl);
1416 if (check_font_property)
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;
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); )
1430 ft_info = MPLIST_VAL (pl);
1432 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1433 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1435 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1437 && stretch != FONT_PROPERTY (&ft_info->font,
1440 && ft_info->font.size > 0
1441 && ft_info->font.size != font->size))
1444 pl = MPLIST_NEXT (pl);
1448 MPLIST_DO (pl, plist)
1450 font = MPLIST_VAL (plist);
1451 if (limited_size == 0
1453 || font->size <= limited_size)
1459 M17N_OBJECT_UNREF (plist);
1460 #endif /* HAVE_FONTCONFIG */
1465 static MRealizedFont *
1466 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
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;
1473 MPlist *plist, *charmap_list = NULL;
1478 /* non-scalable font */
1480 else if (spec->size)
1482 int ratio = mfont_resize_ratio (font);
1484 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
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)
1501 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1503 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1506 font->type = MFONT_TYPE_FAILURE;
1507 MDEBUG_PRINT (" no (FT_New_Face)\n");
1511 M17N_OBJECT_REF (charmap_list);
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);
1519 FT_Done_Face (ft_face);
1520 M17N_OBJECT_UNREF (charmap_list);
1521 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
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))
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);
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;
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;
1558 BDF_PropertyRec prop;
1560 if (! FT_IS_SCALABLE (ft_face)
1561 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1563 rfont->baseline_offset = prop.u.integer << 6;
1564 rfont->ascent += prop.u.integer << 6;
1565 rfont->descent -= prop.u.integer << 6;
1568 #endif /* HAVE_FTBDF_H */
1569 if (FT_IS_SCALABLE (ft_face))
1570 rfont->average_width = 0;
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");
1579 /* The FreeType font driver function FIND_METRIC. */
1582 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1585 FT_Face ft_face = rfont->fontp;
1586 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1588 for (; g != gend; g++)
1592 if (g->g.code == MCHAR_INVALID_CODE)
1594 if (FT_IS_SCALABLE (ft_face))
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;
1605 BDF_PropertyRec prop;
1606 #endif /* HAVE_FTBDF_H */
1609 g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1611 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
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",
1619 g->g.ascent += prop.u.integer << 6;
1620 g->g.descent -= prop.u.integer << 6;
1624 #endif /* HAVE_FTBDF_H */
1626 g->g.ascent = ft_face->available_sizes->height << 6;
1633 FT_Glyph_Metrics *metrics;
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;
1644 g->g.ascent += rfont->baseline_offset;
1645 g->g.descent -= rfont->baseline_offset;
1651 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1653 MRealizedFont *rfont = NULL;
1654 MRealizedFontFT *ft_rfont;
1657 if (font->type == MFONT_TYPE_REALIZED)
1658 rfont = (MRealizedFont *) font;
1659 else if (font->type == MFONT_TYPE_OBJECT)
1661 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1662 rfont = rfont->next)
1663 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1667 #ifdef HAVE_FONTCONFIG
1668 MFontFT *ft_info = (MFontFT *) font;
1670 if (! ft_info->charset)
1672 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1673 MSYMBOL_NAME (font->file),
1675 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1676 FcFontSet *fs = FcFontList (fc_config, pat, os);
1679 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1680 &ft_info->charset) == FcResultMatch)
1681 ft_info->charset = FcCharSetCopy (ft_info->charset);
1683 ft_info->charset = FcCharSetCreate ();
1684 FcFontSetDestroy (fs);
1685 FcObjectSetDestroy (os);
1686 FcPatternDestroy (pat);
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 */
1695 MFATAL (MERROR_FONT_FT);
1699 ft_rfont = rfont->info;
1700 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1704 /* The FreeType font driver function ENCODE_CHAR. */
1707 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1709 MRealizedFont *rfont;
1710 MRealizedFontFT *ft_rfont;
1713 if (font->type == MFONT_TYPE_REALIZED)
1714 rfont = (MRealizedFont *) font;
1715 else if (font->type == MFONT_TYPE_OBJECT)
1717 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1718 rfont = rfont->next)
1719 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1723 rfont = ft_open (frame, font, spec, NULL);
1729 MFATAL (MERROR_FONT_FT);
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);
1736 /* The FreeType font driver function RENDER. */
1738 #define NUM_POINTS 0x1000
1741 MDrawPoint points[NUM_POINTS];
1746 ft_render (MDrawWindow win, int x, int y,
1747 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1748 int reverse, MDrawRegion region)
1751 MRealizedFace *rface = from->rface;
1752 MFrame *frame = rface->frame;
1753 FT_Int32 load_flags = FT_LOAD_RENDER;
1756 MPointTable point_table[8];
1757 int baseline_offset;
1758 int pixel_mode = -1;
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;
1768 if (! gstring->anti_alias)
1770 #ifdef FT_LOAD_TARGET_MONO
1771 load_flags |= FT_LOAD_TARGET_MONO;
1773 load_flags |= FT_LOAD_MONOCHROME;
1777 for (i = 0; i < 8; i++)
1778 point_table[i].p = point_table[i].points;
1780 for (g = from; g < to; x += g++->g.xadv)
1784 MPointTable *ptable;
1788 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
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;
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++)
1800 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1801 for (j = 0; j < width; j++, xoff++)
1803 intensity = bmp[j] >> 5;
1806 ptable = point_table + intensity;
1807 ptable->p->x = xoff;
1808 ptable->p->y = yoff - baseline_offset;
1810 if (ptable->p - ptable->points == NUM_POINTS)
1812 (*frame->driver->draw_points)
1814 reverse ? 7 - intensity : intensity,
1815 ptable->points, NUM_POINTS, region);
1816 ptable->p = ptable->points;
1822 for (i = 0; i < ft_face->glyph->bitmap.rows;
1823 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1825 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1826 for (j = 0; j < width; j++, xoff++)
1828 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1831 ptable = point_table;
1832 ptable->p->x = xoff;
1833 ptable->p->y = yoff - baseline_offset;
1835 if (ptable->p - ptable->points == NUM_POINTS)
1837 (*frame->driver->draw_points) (frame, win, rface,
1839 ptable->points, NUM_POINTS, region);
1840 ptable->p = ptable->points;
1847 if (pixel_mode != FT_PIXEL_MODE_MONO)
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);
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);
1865 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1867 MPlist *pl = NULL, *p;
1869 MPlist *file_list = NULL;
1870 MPlist *family_list = NULL, *capability_list = NULL;
1871 MSymbol registry = Mnil;
1873 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1879 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1880 if (registry != Mnil && registry != Miso8859_1)
1882 char *reg = MSYMBOL_NAME (registry);
1884 if (strncmp (reg, "unicode-", 8)
1885 && strncmp (reg, "apple-roman", 11)
1886 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1890 if (font->file != Mnil
1891 && ! (file_list = ft_list_file (font->file)))
1893 family = FONT_PROPERTY (font, MFONT_FAMILY);
1895 && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
1896 && MPLIST_TAIL_P (family_list))
1898 if (font->capability != Mnil)
1900 capability_list = ft_list_capability (font->capability);
1901 if (! capability_list || MPLIST_TAIL_P (capability_list))
1906 if (! file_list && ! family_list && ! capability_list)
1908 /* No restriction. Get all fonts. */
1910 MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
1912 MPLIST_DO (p, MPLIST_PLIST (family_list))
1913 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1921 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1926 for (p = pl; ! MPLIST_TAIL_P (p);)
1928 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1929 p = MPLIST_NEXT (p);
1936 MPLIST_DO (p, family_list)
1937 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1940 if (capability_list)
1943 for (p = pl; ! MPLIST_TAIL_P (p);)
1945 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1946 p = MPLIST_NEXT (p);
1953 MPLIST_DO (p, capability_list)
1954 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1960 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1961 + font->property[MFONT_STRETCH] + font->size) > 0)
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;
1968 for (p = pl; ! MPLIST_TAIL_P (p); )
1970 MFontFT *ft_info = MPLIST_VAL (p);
1973 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1975 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1977 && stretch != FONT_PROPERTY (&ft_info->font,
1980 && ft_info->font.size > 0
1981 && ft_info->font.size != size))
1984 p = MPLIST_NEXT (p);
1990 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1992 if (maxnum && maxnum <= num)
1995 M17N_OBJECT_UNREF (pl);
1998 MDEBUG_PRINT1 (" %d found\n", num);
2003 ft_list_family_names (MFrame *frame, MPlist *plist)
2009 #ifdef HAVE_FONTCONFIG
2010 fc_init_font_list ();
2011 #else /* not HAVE_FONTCONFIG */
2012 ft_init_font_list ();
2013 #endif /* not HAVE_FONTCONFIG */
2016 MPLIST_DO (pl, ft_font_list)
2018 MSymbol family = MPLIST_KEY (pl);
2021 #ifdef HAVE_FONTCONFIG
2022 if (msymbol_get (family, Mgeneric_family) != Mnil)
2024 #endif /* HAVE_FONTCONFIG */
2025 MPLIST_DO (p, plist)
2027 MSymbol sym = MPLIST_SYMBOL (p);
2031 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2033 mplist_push (p, Msymbol, family);
2037 if (MPLIST_TAIL_P (p))
2038 mplist_push (p, Msymbol, family);
2043 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2045 MFontFT *ft_info = (MFontFT *) rfont->font;
2046 MRealizedFontFT *ft_rfont = rfont->info;
2047 MFontCapability *cap = mfont__get_capability (capability);
2049 if (cap->script_tag)
2051 if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2054 else if (cap->script != Mnil
2055 && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2057 if (cap->language != Mnil
2058 && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2063 static MRealizedFont *
2064 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2067 MRealizedFont *rfont;
2068 MRealizedFontFT *ft_rfont;
2071 if (data_type == Mfontconfig)
2073 #ifdef HAVE_FONTCONFIG
2074 FcPattern *pattern = data;
2076 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2079 ft_info = fc_gen_font (pattern, NULL);
2080 #else /* not HAVE_FONTCONFIG */
2082 #endif /* not HAVE_FONTCONFIG */
2084 else if (data_type == Mfreetype)
2087 ft_info = ft_gen_font (ft_face);
2092 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2093 ft_rfont->ft_face = ft_face;
2094 ft_rfont->face_encapsulated = 1;
2096 MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
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;
2115 BDF_PropertyRec prop;
2117 if (! FT_IS_SCALABLE (ft_face)
2118 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2120 rfont->baseline_offset = prop.u.integer << 6;
2121 rfont->ascent += prop.u.integer << 6;
2122 rfont->descent -= prop.u.integer << 6;
2125 #endif /* HAVE_FTBDF_H */
2126 if (FT_IS_SCALABLE (ft_face))
2127 rfont->average_width = 0;
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;
2137 ft_close (MRealizedFont *rfont)
2139 if (! rfont->encapsulating)
2142 M17N_OBJECT_UNREF (rfont->info);
2146 /* See the comment of parse_otf_command (m17n-flt.c). */
2149 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2151 #define FEATURE_NONE(IDX) (! spec->features[IDX])
2153 #define FEATURE_ANY(IDX) \
2154 (spec->features[IDX] \
2155 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
2160 OTF *otf = get_otf (font, NULL);
2162 if (FEATURE_ANY (0) && FEATURE_ANY (1))
2163 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
2165 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
2167 || OTF_check_features (otf, 1, spec->script, spec->langsys,
2170 for (i = 0; i < 2; i++)
2171 if (! FEATURE_ANY (i))
2173 if (FEATURE_NONE (i))
2176 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2181 if (spec->features[i][0] == 0xFFFFFFFF)
2184 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
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++)
2194 if (spec->features[i][n] == 0xFFFFFFFF)
2197 tags[n - 1] = spec->features[i][n] | 0x80000000;
2199 tags[n] = spec->features[i][n];
2201 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2202 tags, n - negative) != 1)
2207 #endif /* HAVE_OTF */
2208 return (FEATURE_NONE (0) ? (FEATURE_NONE (1) || FEATURE_ANY (1))
2209 : (FEATURE_NONE (1) && FEATURE_ANY (0)));
2215 get_otf (MFLTFont *font, FT_Face *ft_face)
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;
2224 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2225 otf = OTF_open_ft_face (ft_rfont->ft_face);
2227 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2229 if (! otf || OTF_get_table (otf, "head") < 0)
2234 *ft_face = ft_rfont->ft_face;
2235 return (otf == invalid_otf ? NULL : otf);
2238 #define DEVICE_DELTA(table, size) \
2239 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2240 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
2244 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2245 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2247 if (anchor->AnchorFormat == 2)
2249 FT_Outline *outline;
2250 int ap = anchor->f.f1.AnchorPoint;
2252 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2253 outline = &ft_face->glyph->outline;
2254 if (ap < outline->n_points)
2256 *x = outline->points[ap].x << 6;
2257 *y = outline->points[ap].y << 6;
2260 else if (anchor->AnchorFormat == 3)
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);
2268 #endif /* HAVE_OTF */
2271 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2272 MFLTGlyphString *in, int from, int to,
2273 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2275 int len = to - from;
2278 MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2279 MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
2282 OTF_GlyphString otf_gstring;
2284 char script[5], *langsys = NULL;
2285 char *gsub_features = NULL, *gpos_features = NULL;
2290 otf = get_otf (font, &face);
2293 OTF_tag_name (spec->script, script);
2296 langsys = alloca (5);
2297 OTF_tag_name (spec->langsys, langsys);
2299 for (i = 0; i < 2; i++)
2303 if (spec->features[i])
2305 for (j = 0; spec->features[i][j]; j++);
2307 p = gsub_features = alloca (6 * j);
2309 p = gpos_features = alloca (6 * j);
2310 for (j = 0; spec->features[i][j]; j++)
2312 if (spec->features[i][j] == 0xFFFFFFFF)
2313 *p++ = '*', *p++ = ',';
2316 OTF_tag_name (spec->features[i][j], p);
2325 otf_gstring.size = otf_gstring.used = len;
2326 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2327 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2328 for (i = 0; i < len; i++)
2330 otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
2331 otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2334 OTF_drive_gdef (otf, &otf_gstring);
2335 gidx = out ? out->used : from;
2339 OTF_Feature *features;
2342 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
2345 features = otf->gsub->FeatureList.Feature;
2348 if (out->allocated < gidx + otf_gstring.used)
2350 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2351 i < otf_gstring.used; i++, otfg++, g++, out->used++)
2353 int feature_idx = otfg->positioning_type >> 4;
2355 int min_from, max_to;
2357 *g = in_glyphs[from + otfg->f.index.from];
2358 min_from = g->g.from, max_to = g->g.to;
2360 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2361 if (in_glyphs[from + j].g.code == otfg->glyph_id)
2363 g->g.c = in_glyphs[from + j].g.c;
2368 tag = features[feature_idx - 1].FeatureTag;
2369 tag = PACK_OTF_TAG (tag);
2370 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2372 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2374 if (min_from > in_glyphs[from + j].g.from)
2375 min_from = in_glyphs[from + j].g.from;
2376 if (max_to < in_glyphs[from + j].g.to)
2377 max_to = in_glyphs[from + j].g.to;
2379 if (g->g.code != otfg->glyph_id)
2381 g->g.code = otfg->glyph_id;
2384 g->g.from = min_from, g->g.to = max_to;
2389 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2392 int feature_idx = otfg->positioning_type >> 4;
2396 tag = features[feature_idx - 1].FeatureTag;
2397 tag = PACK_OTF_TAG (tag);
2398 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2400 g = in_glyphs + (from + j);
2401 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2409 if (out->allocated < gidx + len)
2411 for (i = 0; i < len; i++)
2412 out_glyphs[out->used++] = in_glyphs[from + i];
2417 OTF_Feature *features;
2420 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2423 features = otf->gpos->FeatureList.Feature;
2426 MGlyph *base = NULL, *mark = NULL;
2427 int x_ppem = face->size->metrics.x_ppem;
2428 int y_ppem = face->size->metrics.y_ppem;
2429 int x_scale = face->size->metrics.x_scale;
2430 int y_scale = face->size->metrics.y_scale;
2432 for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2433 i < otf_gstring.used; i++, otfg++)
2436 int adjust_idx = otfg->glyph_id ? j : j - 1;
2437 int feature_idx = otfg->positioning_type >> 4;
2441 tag = features[feature_idx - 1].FeatureTag;
2442 tag = PACK_OTF_TAG (tag);
2443 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2445 switch (otfg->positioning_type & 0xF)
2449 case 1: /* Single */
2452 int format = otfg->f.f1.format;
2454 if (format & OTF_XPlacement)
2455 adjustment[adjust_idx].xoff
2456 += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2457 if (format & OTF_XPlaDevice)
2458 adjustment[adjust_idx].xoff
2459 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2460 if (format & OTF_YPlacement)
2461 adjustment[adjust_idx].yoff
2462 -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2463 if (format & OTF_YPlaDevice)
2464 adjustment[adjust_idx].yoff
2465 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2466 if (format & OTF_XAdvance)
2467 adjustment[adjust_idx].xadv
2468 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2469 if (format & OTF_XAdvDevice)
2470 adjustment[adjust_idx].xadv
2471 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2472 if (format & OTF_YAdvance)
2473 adjustment[adjust_idx].yadv
2474 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2475 if (format & OTF_YAdvDevice)
2476 adjustment[adjust_idx].yadv
2477 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2478 adjustment[adjust_idx].set = 1;
2481 case 3: /* Cursive */
2482 /* Not yet supported. */
2484 case 4: /* Mark-to-Base */
2485 case 5: /* Mark-to-Ligature */
2489 goto label_adjust_anchor;
2490 default: /* i.e. case 6 Mark-to-Mark */
2495 label_adjust_anchor:
2497 int base_x, base_y, mark_x, mark_y;
2498 int this_from, this_to;
2501 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2502 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2503 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2504 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2506 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2507 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2508 x_ppem, y_ppem, &base_x, &base_y);
2509 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2510 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2511 x_ppem, y_ppem, &mark_x, &mark_y);
2512 adjustment[adjust_idx].xoff = base_x - mark_x;
2513 adjustment[adjust_idx].yoff = - (base_y - mark_y);
2514 adjustment[adjust_idx].back = (g - prev);
2515 adjustment[adjust_idx].xadv = 0;
2516 adjustment[adjust_idx].advance_is_absolute = 1;
2517 adjustment[adjust_idx].set = 1;
2518 this_from = g->g.from;
2520 for (k = 0; prev + k < g; k++)
2522 if (this_from > prev[k].g.from)
2523 this_from = prev[k].g.from;
2524 if (this_to < prev[k].g.to)
2525 this_to = prev[k].g.to;
2527 for (; prev <= g; prev++)
2529 prev->g.from = this_from;
2530 prev->g.to = this_to;
2536 if (otfg->GlyphClass == OTF_GlyphClass0)
2538 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2548 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2550 if (otfg->positioning_type & 0xF)
2552 int feature_idx = otfg->positioning_type >> 4;
2556 tag = features[feature_idx - 1].FeatureTag;
2557 tag = PACK_OTF_TAG (tag);
2558 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2560 g = in_glyphs + (from + j);
2561 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2568 free (otf_gstring.glyphs);
2572 if (otf_gstring.glyphs)
2573 free (otf_gstring.glyphs);
2574 #endif /* HAVE_OTF */
2577 if (out->allocated < out->used + len)
2579 font->get_metrics (font, in, from, to);
2580 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2581 sizeof (MGlyph) * len);
2588 ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2589 MFLTGlyphString *in, int from, int to)
2591 return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
2596 static unsigned char *iterate_bitmap;
2599 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2601 if (glyph_id <= otf->cmap->max_glyph_id)
2602 iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2607 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2608 int from, int to, unsigned char *table)
2610 OTF *otf = get_otf (font, NULL);
2613 unsigned char *bitmap = NULL;
2615 char script[5], *langsys = NULL;
2619 if (OTF_get_table (otf, "cmap") < 0)
2621 if (! spec->features[0])
2623 strcpy (id, "feature-");
2625 OTF_tag_name (spec->script, script);
2628 langsys = alloca (5);
2629 OTF_tag_name (spec->langsys, langsys);
2631 bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2632 for (i = 0; spec->features[0][i]; i++)
2636 OTF_tag_name (spec->features[0][i], id + 8);
2637 bmp = OTF_get_data (otf, id);
2640 iterate_bitmap = bmp = calloc (bmp_size, 1);
2641 OTF_iterate_gsub_feature (otf, iterate_callback,
2642 script, langsys, id + 8);
2643 OTF_put_data (otf, id, bmp, free);
2645 if (i == 0 && ! spec->features[0][1])
2646 /* Single feature */
2652 bitmap = alloca (bmp_size);
2653 memcpy (bitmap, bmp, bmp_size);
2659 for (j = 0; j < bmp_size; j++)
2660 bitmap[j] &= bmp[j];
2664 for (i = 0; i < bmp_size; i++)
2667 for (j = 0; j < 8; j++)
2668 if (bitmap[i] & (1 << j))
2670 int c = OTF_get_unicode (otf, (i * 8) + j);
2672 if (c >= from && c <= to)
2673 table[c - from] = 1;
2684 MFontDriver mfont__ft_driver =
2685 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2686 ft_render, ft_list, ft_list_family_names, ft_check_capability,
2687 ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
2689 ft_iterate_otf_feature
2690 #endif /* HAVE_OTF */
2698 if (FT_Init_FreeType (&ft_library) != 0)
2699 MERROR (MERROR_FONT_FT, -1);
2701 for (i = 0; i < ft_to_prop_size; i++)
2702 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2704 Mmedium = msymbol ("medium");
2706 Mnull = msymbol ("");
2708 M0[0] = msymbol ("0-0");
2709 M0[1] = msymbol ("0-1");
2710 M0[2] = msymbol ("0-2");
2711 M0[3] = msymbol ("0-3");
2712 M0[4] = msymbol ("0-4");
2713 M3_1 = msymbol ("3-1");
2714 M1_0 = msymbol ("1-0");
2716 #ifdef HAVE_FONTCONFIG
2717 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2719 FC_vs_M17N_font_prop *table = fc_all_table[i];
2722 for (j = 0; table[j].m17n_value; j++)
2723 table[j].sym = msymbol (table[j].m17n_value);
2724 table[j].sym = table[j - 1].sym;
2731 MSymbol serif, sans_serif, monospace;
2733 fc_config = FcInitLoadConfigAndFonts ();
2734 if (mfont_freetype_path)
2736 MPLIST_DO (plist, mfont_freetype_path)
2737 if (MPLIST_STRING_P (plist)
2738 && (pathname = MPLIST_STRING (plist))
2739 && stat (pathname, &buf) == 0)
2741 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2744 while ((dir = FcStrListNext (strlist)))
2745 if (strcmp ((char *) dir, pathname) == 0)
2748 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2749 FcStrListDone (strlist);
2752 Mgeneric_family = msymbol ("generic famly");
2753 serif = msymbol ("serif");
2754 msymbol_put (serif, Mgeneric_family, serif);
2755 sans_serif = msymbol ("sans-serif");
2756 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2757 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2758 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2759 monospace = msymbol ("monospace");
2760 msymbol_put (monospace, Mgeneric_family, monospace);
2761 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2763 #endif /* HAVE_FONTCONFIG */
2773 if (ft_default_list)
2775 M17N_OBJECT_UNREF (ft_default_list);
2776 ft_default_list = NULL;
2781 MPLIST_DO (plist, ft_font_list)
2783 if (MPLIST_VAL (plist))
2784 MPLIST_DO (p, MPLIST_VAL (plist))
2786 if (MPLIST_KEY (p) != Mt)
2787 free_ft_info (MPLIST_VAL (p));
2789 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2791 M17N_OBJECT_UNREF (ft_font_list);
2792 ft_font_list = NULL;
2794 if (ft_language_list)
2796 MPLIST_DO (plist, ft_language_list)
2797 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2798 M17N_OBJECT_UNREF (ft_language_list);
2799 ft_language_list = NULL;
2804 MPLIST_DO (plist, ft_script_list)
2805 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2806 M17N_OBJECT_UNREF (ft_script_list);
2807 ft_script_list = NULL;
2810 if (ft_capability_list)
2812 MPLIST_DO (plist, ft_capability_list)
2813 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2814 M17N_OBJECT_UNREF (ft_capability_list);
2815 ft_capability_list = NULL;
2820 MPLIST_DO (plist, ft_file_list)
2821 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2822 M17N_OBJECT_UNREF (ft_file_list);
2823 ft_file_list = NULL;
2826 FT_Done_FreeType (ft_library);
2827 #ifdef HAVE_FONTCONFIG
2828 FcConfigDestroy (fc_config);
2830 #endif /* HAVE_FONTCONFIG */
2831 all_fonts_scaned = 0;
2834 #ifdef HAVE_FONTCONFIG
2837 mfont__ft_parse_name (const char *name, MFont *font)
2839 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2848 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2850 STRDUP_LOWER (buf, bufsize, (char *) str);
2851 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2853 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2855 STRDUP_LOWER (buf, bufsize, (char *) str);
2856 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2858 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2859 mfont__set_property (font, MFONT_WEIGHT,
2860 fc_decode_prop (val, fc_weight_table,
2861 fc_weight_table_size));
2862 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2863 mfont__set_property (font, MFONT_STYLE,
2864 fc_decode_prop (val, fc_slant_table,
2865 fc_slant_table_size));
2866 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2867 mfont__set_property (font, MFONT_STRETCH,
2868 fc_decode_prop (val, fc_width_table,
2869 fc_width_table_size));
2870 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2871 font->size = size * 10 + 0.5;
2872 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2873 font->size = - (size * 10 + 0.5);
2874 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2876 font->file = msymbol ((char *) str);
2878 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2879 font->type = MFONT_TYPE_SPEC;
2880 FcPatternDestroy (pat);
2885 mfont__ft_unparse_name (MFont *font)
2887 FcPattern *pat = fc_get_pattern (font);
2888 char *name = (char *) FcNameUnparse (pat);
2890 FcPatternDestroy (pat);
2893 #endif /* HAVE_FONTCONFIG */
2895 #endif /* HAVE_FREETYPE */