1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
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 *) "";
75 /* NULL if not yet opened. invalid_otf if not OTF. */
78 #ifdef HAVE_FONTCONFIG
81 #endif /* HAVE_FONTCONFIG */
87 FT_Face ft_face; /* This must be the 2nd member. */
89 int face_encapsulated;
96 enum MFontProperty prop;
100 static MFTtoProp ft_to_prop[] =
101 { { "italic", 0, MFONT_STYLE, "i" },
102 { "roman", 0, MFONT_STYLE, "r" },
103 { "oblique", 0, MFONT_STYLE, "o" },
104 { "regular", 0, MFONT_WEIGHT, "normal" },
105 { "normal", 0, MFONT_WEIGHT, "normal" },
106 /* We need this entry even if "bold" is in commone_weight[] to
107 handle such style names as "bolditalic" and "boldoblique". */
108 { "bold", 0, MFONT_WEIGHT, "bold" },
109 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
110 { "demi", 0, MFONT_WEIGHT, "demibold" } };
111 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
113 /** List of FreeType fonts. Keys are family names, values are plists
114 containing fonts of the corresponding family. In the deeper
115 plist, keys are file names, values are (MFontFT *). */
116 static MPlist *ft_font_list;
118 /** List of FreeType fonts. Keys are script names, values are plists
119 containing fonts supporting the corresponding script. In the
120 deeper plist, keys are family names, values are (MFontFT *). */
121 static MPlist *ft_script_list;
123 /** List of FreeType fonts. Keys are language names, values are
124 plists containing fonts supporting the corresponding language. In
125 the deeper plist, keys are family names, values are (MFontFT *). */
126 static MPlist *ft_language_list;
128 static MPlist *ft_file_list;
130 static int all_fonts_scaned;
132 #define STRDUP_LOWER(s1, size, s2) \
134 int len = strlen (s2) + 1; \
138 (s1) = alloca (len), (size) = len; \
139 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
140 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
145 static MPlist *ft_list_family (MSymbol, int);
148 free_ft_rfont (void *object)
150 MRealizedFontFT *ft_rfont = object;
152 if (! ft_rfont->face_encapsulated)
154 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
155 FT_Done_Face (ft_rfont->ft_face);
161 free_ft_info (MFontFT *ft_info)
164 if (ft_info->otf && ft_info->otf != invalid_otf)
165 OTF_close (ft_info->otf);
166 #endif /* HAVE_OTF */
167 #ifdef HAVE_FONTCONFIG
168 if (ft_info->langset)
169 FcLangSetDestroy (ft_info->langset);
170 if (ft_info->charset)
171 FcCharSetDestroy (ft_info->charset);
172 #endif /* HAVE_FONTCONFIG */
177 ft_get_charmaps (FT_Face ft_face)
179 MPlist *plist = mplist ();
180 int unicode_bmp = -1, unicode_full = -1;
183 mplist_add (plist, Mt, (void *) -1);
184 for (i = 0; i < ft_face->num_charmaps; i++)
186 MSymbol registry = Mnil;
188 if (ft_face->charmaps[i]->platform_id == 0)
190 if (ft_face->charmaps[i]->encoding_id <= 4)
191 registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
192 if (ft_face->charmaps[i]->encoding_id == 4)
193 unicode_bmp = unicode_full = i;
195 else if (ft_face->charmaps[i]->platform_id == 3)
197 if (ft_face->charmaps[i]->encoding_id == 1)
198 registry = M3_1, unicode_bmp = i;
199 else if (ft_face->charmaps[i]->encoding_id == 10)
200 unicode_bmp = unicode_full = i;
202 else if (ft_face->charmaps[i]->platform_id == 1
203 && ft_face->charmaps[i]->encoding_id == 0)
206 mplist_add (plist, Mapple_roman, (void *) i);
208 if (registry == Mnil)
210 char registry_buf[16];
212 sprintf (registry_buf, "%d-%d",
213 ft_face->charmaps[i]->platform_id,
214 ft_face->charmaps[i]->encoding_id);
215 registry = msymbol (registry_buf);
217 mplist_add (plist, registry, (void *) i);
219 if (unicode_full >= 0)
220 mplist_add (plist, Municode_full, (void *) unicode_full);
221 if (unicode_bmp >= 0)
225 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
226 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
227 for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
230 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
232 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
240 ft_gen_font (FT_Face ft_face)
250 if (FT_IS_SCALABLE (ft_face))
251 size = ft_face->size->metrics.y_ppem;
252 else if (ft_face->num_fixed_sizes == 0)
255 size = ft_face->available_sizes[0].height;
257 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
258 font = &ft_info->font;
259 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
260 family = msymbol (buf);
261 mfont__set_property (font, MFONT_FAMILY, family);
262 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
263 mfont__set_property (font, MFONT_STYLE, Mr);
264 mfont__set_property (font, MFONT_STRETCH, Mnormal);
265 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
266 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
267 font->size = size * 10;
268 font->type = MFONT_TYPE_OBJECT;
269 font->source = MFONT_SOURCE_FT;
272 stylename = ft_face->style_name;
277 for (i = 0; i < ft_to_prop_size; i++)
278 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
281 mfont__set_property (font, ft_to_prop[i].prop,
282 msymbol (ft_to_prop[i].val));
283 stylename += ft_to_prop[i].len;
286 if (i == ft_to_prop_size)
288 char *p1 = stylename + 1;
291 while (*p1 >= 'a' && *p1 <= 'z') p1++;
292 sym = msymbol__with_len (stylename, p1 - stylename);
293 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
294 if (msymbol_get (sym, mfont__property_table[i].property))
296 mfont__set_property (font, i, sym);
301 while (*stylename && ! isalpha (*stylename))
307 #ifdef HAVE_FONTCONFIG
314 } FC_vs_M17N_font_prop;
316 static FC_vs_M17N_font_prop fc_weight_table[] =
317 { { FC_WEIGHT_THIN, "thin" },
318 { FC_WEIGHT_ULTRALIGHT, "extralight" },
319 { FC_WEIGHT_LIGHT, "light" },
320 #ifdef FC_WEIGHT_BOOK
321 { FC_WEIGHT_BOOK, "book" },
322 #endif /* FC_WEIGHT_BOOK */
323 { FC_WEIGHT_REGULAR, "normal" },
324 { FC_WEIGHT_NORMAL, "normal" },
325 { FC_WEIGHT_MEDIUM, "medium" },
326 { FC_WEIGHT_DEMIBOLD, "demibold" },
327 { FC_WEIGHT_BOLD, "bold" },
328 { FC_WEIGHT_EXTRABOLD, "extrabold" },
329 { FC_WEIGHT_BLACK, "black" },
330 { FC_WEIGHT_HEAVY, "heavy" },
331 { FC_WEIGHT_MEDIUM, NULL } };
332 int fc_weight_table_size =
333 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
335 static FC_vs_M17N_font_prop fc_slant_table[] =
336 { { FC_SLANT_ROMAN, "r" },
337 { FC_SLANT_ITALIC, "i" },
338 { FC_SLANT_OBLIQUE, "o" },
339 { FC_SLANT_ROMAN, NULL } };
340 int fc_slant_table_size =
341 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
343 static FC_vs_M17N_font_prop fc_width_table[] =
344 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
345 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
346 { FC_WIDTH_CONDENSED, "condensed" },
347 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
348 { FC_WIDTH_NORMAL, "normal" },
349 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
350 { FC_WIDTH_EXPANDED, "expanded" },
351 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
352 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
353 { FC_WIDTH_NORMAL, NULL } };
354 int fc_width_table_size =
355 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
358 static FC_vs_M17N_font_prop *fc_all_table[] =
359 { fc_weight_table, fc_slant_table, fc_width_table };
362 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
366 if (val < table[i].fc_value)
368 for (i--; i >= 0; i--)
369 if (val > table[i].fc_value)
375 for (; i < size; i++)
376 if (val <= table[i].fc_value)
383 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
387 for (i = 0; table[i].m17n_value; i++)
388 if (table[i].sym == sym)
390 return table[i].fc_value;
394 fc_get_pattern (MFont *font)
396 FcPattern *pat = FcPatternCreate ();
397 MSymbol sym, weight, style, stretch;
400 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
401 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
402 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
403 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
404 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
405 FcPatternAddInteger (pat, FC_WEIGHT,
406 fc_encode_prop (weight, fc_weight_table));
407 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
408 FcPatternAddInteger (pat, FC_SLANT,
409 fc_encode_prop (style, fc_slant_table));
410 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
411 FcPatternAddInteger (pat, FC_WIDTH,
412 fc_encode_prop (stretch, fc_width_table));
415 double size = font->size;
416 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
418 else if (font->size < 0)
420 double size = - font->size;
421 FcPatternAddDouble (pat, FC_SIZE, size / 10);
427 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
437 MFont *font = &ft_info->font;
440 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
442 STRDUP_LOWER (buf, bufsize, (char *) str);
443 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
446 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
447 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
449 STRDUP_LOWER (buf, bufsize, (char *) str);
450 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
452 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
454 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
455 mfont__set_property (font, MFONT_WEIGHT, sym);
457 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
459 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
460 mfont__set_property (font, MFONT_STYLE, sym);
462 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
464 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
465 mfont__set_property (font, MFONT_STRETCH, sym);
467 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
469 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
470 || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
471 || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
472 font->for_full_width = 1;
473 ft_info->langset = FcLangSetCopy (ls);
475 if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
476 ft_info->charset = FcCharSetCopy (cs);
478 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
479 font->type = MFONT_TYPE_SPEC;
480 font->source = MFONT_SOURCE_FT;
481 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
482 font->size = size * 10;
483 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
484 font->file = msymbol ((char *) str);
489 fc_gen_font (FcPattern *pat, char *family)
493 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
494 fc_parse_pattern (pat, family, ft_info);
495 ft_info->font.type = MFONT_TYPE_OBJECT;
500 fc_init_font_list (void)
502 FcPattern *pattern = FcPatternCreate ();
503 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
504 FcFontSet *fs = FcFontList (fc_config, pattern, os);
505 MPlist *plist = mplist ();
510 ft_font_list = plist;
511 for (i = 0; i < fs->nfont; i++)
515 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
516 (FcChar8 **) &fam) != FcResultMatch)
518 STRDUP_LOWER (buf, bufsize, fam);
519 plist = mplist_add (plist, msymbol (buf), NULL);
521 FcFontSetDestroy (fs);
522 FcObjectSetDestroy (os);
523 FcPatternDestroy (pattern);
527 fc_list_pattern (FcPattern *pattern)
529 FcObjectSet *os = NULL;
530 FcFontSet *fs = NULL;
531 MSymbol last_family = Mnil;
532 MPlist *plist = NULL, *pl = NULL;
537 if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
539 if (! (fs = FcFontList (fc_config, pattern, os)))
542 for (i = 0; i < fs->nfont; i++)
544 MSymbol family, file;
545 char *fam, *filename;
548 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
549 (FcChar8 **) &fam) != FcResultMatch)
551 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
552 (FcChar8 **) &filename) != FcResultMatch)
554 STRDUP_LOWER (buf, bufsize, fam);
555 family = msymbol (buf);
556 file = msymbol (filename);
557 if (family != last_family)
559 pl = MPLIST_PLIST (ft_list_family (family, 0));
560 last_family = family;
562 ft_info = mplist_get (pl, file);
567 mplist_add (plist, family, ft_info);
572 if (fs) FcFontSetDestroy (fs);
573 if (os) FcObjectSetDestroy (os);
577 /* Return FcCharSet object built from CHAR_LIST or MT. In the latter
578 case, it is assured that the M-text contains at least one
582 fc_build_charset (MPlist *char_list, MText *mt)
584 FcCharSet *cs = FcCharSetCreate ();
590 for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
591 if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
593 FcCharSetDestroy (cs);
601 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
602 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
604 FcCharSetDestroy (cs);
607 if (mtext_nchars (mt) > 0
608 && (mt = mtext_get_prop (mt, 0, Mtext)))
609 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
610 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
612 FcCharSetDestroy (cs);
619 #else /* not HAVE_FONTCONFIG */
622 ft_add_font (char *filename)
635 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
637 ft_info = ft_gen_font (ft_face);
638 FT_Done_Face (ft_face);
642 font = &ft_info->font;
643 font->file = msymbol (filename);
645 plist = mplist_find_by_key (ft_font_list, family);
647 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
651 mplist_add (plist, font->file, ft_info);
652 plist = mplist_push (ft_font_list, family, plist);
658 ft_init_font_list (void)
666 ft_font_list = mplist ();
667 MPLIST_DO (plist, mfont_freetype_path)
668 if (MPLIST_STRING_P (plist)
669 && (pathname = MPLIST_STRING (plist))
670 && stat (pathname, &buf) == 0)
672 if (S_ISREG (buf.st_mode))
673 ft_add_font (pathname);
674 else if (S_ISDIR (buf.st_mode))
676 DIR *dir = opendir (pathname);
680 int len = strlen (pathname);
683 while ((dp = readdir (dir)) != NULL)
685 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
686 strcpy (path, pathname);
688 strcpy (path + len + 1, dp->d_name);
698 /* Return 1 iff the font pointed by FT_INFO has all characters in
702 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
707 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
709 MPLIST_DO (cl, char_list)
710 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
712 FT_Done_Face (ft_face);
713 return MPLIST_TAIL_P (cl);
716 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
717 that supports characters in CHAR_LIST or MT. One of CHAR_LIST or
721 ft_list_char_list (MPlist *char_list, MText *mt)
723 MPlist *plist = NULL, *pl, *p;
726 ft_list_family (Mnil, 0);
730 int len = mtext_nchars (mt);
731 MText *extra = mtext_get_prop (mt, 0, Mtext);
732 int total_len = len + (extra ? mtext_nchars (extra) : 0);
735 char_list = mplist ();
736 for (i = 0; i < total_len; i++)
738 int c = (i < len ? mtext_ref_char (mt, i)
739 : mtext_ref_char (extra, i - len));
741 if (! mplist_find_by_value (char_list, (void *) c))
742 mplist_push (char_list, Minteger, (void *) c);
746 MPLIST_DO (pl, ft_font_list)
748 MPLIST_DO (p, MPLIST_PLIST (pl))
750 MFontFT *ft_info = MPLIST_VAL (p);
752 if (ft_has_char_list_p (ft_info, char_list))
754 MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
758 mplist_push (plist, family, ft_info);
763 M17N_OBJECT_UNREF (char_list);
766 #endif /* not HAVE_FONTCONFIG */
769 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
770 scan all fonts and return ft_font_list. */
773 ft_list_family (MSymbol family, int check_generic)
776 #ifdef HAVE_FONTCONFIG
791 plist = ft_font_list = mplist ();
792 pattern = FcPatternCreate ();
793 os = FcObjectSetBuild (FC_FAMILY, NULL);
794 fs = FcFontList (fc_config, pattern, os);
795 for (i = 0; i < fs->nfont; i++)
797 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
798 (FcChar8 **) &fam) != FcResultMatch)
800 STRDUP_LOWER (buf, bufsize, fam);
802 if (! mplist_find_by_key (ft_font_list, sym))
803 plist = mplist_add (plist, sym, NULL);
805 FcFontSetDestroy (fs);
806 FcObjectSetDestroy (os);
807 FcPatternDestroy (pattern);
812 if (! all_fonts_scaned)
814 MPLIST_DO (plist, ft_font_list)
816 if (! MPLIST_VAL (plist))
817 ft_list_family (MPLIST_KEY (plist), 0);
819 all_fonts_scaned = 1;
824 plist = mplist_find_by_key (ft_font_list, family);
827 if (! MPLIST_VAL (plist))
829 fam = MSYMBOL_NAME (family);
830 pattern = FcPatternCreate ();
831 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
832 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
833 FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
835 fs = FcFontList (fc_config, pattern, os);
837 for (i = 0; i < fs->nfont; i++)
839 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
840 p = mplist_add (p, ft_info->font.file, ft_info);
842 MPLIST_VAL (plist) = pl;
843 FcFontSetDestroy (fs);
844 FcObjectSetDestroy (os);
845 FcPatternDestroy (pattern);
848 else if (check_generic
849 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
851 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
854 if (family != generic)
855 plist = ft_list_family (generic, 1);
858 fam = MSYMBOL_NAME (family);
860 mplist_push (ft_font_list, family, plist);
861 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
862 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
865 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
868 STRDUP_LOWER (buf, bufsize, (char *) fam8);
869 family = msymbol (buf);
870 if (msymbol_get (family, Mgeneric_family))
872 pl = ft_list_family (family, 0);
875 MPLIST_DO (pl, MPLIST_PLIST (pl))
876 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
878 plist = ft_font_list;
883 /* Check if there exist an alias. */
885 plist = mplist_add (ft_font_list, family, pl);
887 pattern = FcPatternBuild (NULL,
888 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
890 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
892 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
893 (FcChar8 **) &fam) == FcResultMatch;
897 /* The last one is a generic family. */
900 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
903 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
904 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
905 (FcChar8 **) &fam) == FcResultMatch;
908 /* Now we know that the last J fonts in PATTERN are from
909 generic font, and the first one is not available. So,
910 the remaining ones are aliases. */
912 for (i = 1; i < j; i++)
914 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
915 STRDUP_LOWER (buf, bufsize, fam);
917 p = MPLIST_PLIST (ft_list_family (sym, 0));
918 if (! MPLIST_TAIL_P (p))
920 mplist_push (pl, Mt, MPLIST_VAL (p));
925 #else /* not HAVE_FONTCONFIG */
927 if (! all_fonts_scaned)
929 ft_init_font_list ();
930 all_fonts_scaned = 1;
933 plist = ft_font_list;
936 plist = mplist_find_by_key (ft_font_list, family);
938 plist = mplist_push (ft_font_list, family, mplist ());
940 #endif /* not HAVE_FONTCONFIG */
946 ft_list_language (MSymbol language)
948 MPlist *plist = NULL;
951 if (! ft_language_list)
952 ft_language_list = mplist ();
953 else if ((plist = mplist_find_by_key (ft_language_list, language)))
954 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
956 mt = mlanguage_text (language);
958 #ifdef HAVE_FONTCONFIG
960 FcPattern *pattern = NULL;
961 FcCharSet *cs = NULL;
962 FcLangSet *ls = NULL;
964 if (! (pattern = FcPatternCreate ()))
967 if (mt && mtext_nchars (mt) > 0)
969 cs = fc_build_charset (NULL, mt);
970 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
975 if (! (ls = FcLangSetCreate ()))
977 if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
978 || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
982 plist = fc_list_pattern (pattern);
984 if (cs) FcCharSetDestroy (cs);
985 if (ls) FcLangSetDestroy (ls);
986 if (pattern) FcPatternDestroy (pattern);
988 #else /* not HAVE_FONTCONFIG */
989 if (mt && mtext_nchars (mt) > 0)
990 plist = ft_list_char_list (NULL, mt);
991 #endif /* not HAVE_FONTCONFIG */
993 mplist_push (ft_language_list, language, plist);
998 ft_list_script (MSymbol script)
1000 MPlist *plist = NULL;
1003 if (! ft_script_list)
1004 ft_script_list = mplist ();
1005 else if ((plist = mplist_find_by_key (ft_script_list, script)))
1006 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1008 char_list = mscript__char_list (script);
1010 #ifdef HAVE_FONTCONFIG
1013 FcPattern *pattern = NULL;
1016 if (! (pattern = FcPatternCreate ()))
1018 cs = fc_build_charset (char_list, NULL);
1019 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1021 plist = fc_list_pattern (pattern);
1023 if (cs) FcCharSetDestroy (cs);
1024 if (pattern) FcPatternDestroy (pattern);
1026 #else /* not HAVE_FONTCONFIG */
1028 plist = ft_list_char_list (char_list, NULL);
1029 #endif /* not HAVE_FONTCONFIG */
1031 mplist_push (ft_script_list, script, plist);
1036 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1039 if (ft_info->otf == invalid_otf)
1043 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1045 ft_info->otf = OTF_open_ft_face (ft_face);
1048 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1051 ft_info->otf = invalid_otf;
1055 if (cap->features[MFONT_OTT_GSUB].nfeatures
1056 && cap->features[MFONT_OTT_GSUB].tags[0]
1057 && (OTF_check_features
1059 cap->script_tag, cap->langsys_tag,
1060 cap->features[MFONT_OTT_GSUB].tags,
1061 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1063 if (cap->features[MFONT_OTT_GPOS].nfeatures
1064 && cap->features[MFONT_OTT_GPOS].tags[0]
1065 && (OTF_check_features
1067 cap->script_tag, cap->langsys_tag,
1068 cap->features[MFONT_OTT_GPOS].tags,
1069 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1072 #else /* not HAVE_OTF */
1074 #endif /* not HAVE_OTF */
1078 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1082 int ft_face_allocaed = 0;
1086 #ifdef HAVE_FONTCONFIG
1087 if (ft_info->langset
1088 && (FcLangSetHasLang (ft_info->langset,
1089 (FcChar8 *) MSYMBOL_NAME (language))
1090 != FcLangDifferentLang))
1092 #endif /* HAVE_FONTCONFIG */
1094 mt = mlanguage_text (language);
1095 if (! mt || mtext_nchars (mt) == 0)
1100 char *filename = MSYMBOL_NAME (ft_info->font.file);
1102 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1104 ft_face_allocaed = 1;
1107 len = mtext_nchars (mt);
1108 extra = mtext_get_prop (mt, 0, Mtext);
1109 total_len = len + (extra ? mtext_nchars (extra) : 0);
1111 for (i = 0; i < total_len; i++)
1113 int c = (i < len ? mtext_ref_char (mt, i)
1114 : mtext_ref_char (extra, i - len));
1116 #ifdef HAVE_FONTCONFIG
1117 if (ft_info->charset
1118 && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1120 #endif /* HAVE_FONTCONFIG */
1121 if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1125 if (ft_face_allocaed)
1126 FT_Done_Face (ft_face);
1128 return (i == total_len ? 0 : -1);
1132 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1134 MPlist *char_list = mscript__char_list (script);
1138 #ifdef HAVE_FONTCONFIG
1139 if (ft_info->charset)
1141 MPLIST_DO (char_list, char_list)
1142 if (FcCharSetHasChar (ft_info->charset,
1143 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1147 #endif /* HAVE_FONTCONFIG */
1149 int ft_face_allocaed = 0;
1153 char *filename = MSYMBOL_NAME (ft_info->font.file);
1155 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1157 ft_face_allocaed = 1;
1160 MPLIST_DO (char_list, char_list)
1161 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1164 if (ft_face_allocaed)
1165 FT_Done_Face (ft_face);
1168 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1171 static MPlist *ft_default_list;
1176 if (ft_default_list)
1177 return ft_default_list;
1178 ft_default_list = mplist ();
1179 #ifdef HAVE_FONTCONFIG
1181 FcPattern *pat = FcPatternCreate ();
1187 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1188 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1194 STRDUP_LOWER (buf, bufsize, (char *) fam);
1195 family = msymbol (buf);
1196 if (msymbol_get (family, Mgeneric_family))
1198 plist = MPLIST_PLIST (ft_list_family (family, 0));
1199 MPLIST_DO (plist, plist)
1200 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1203 #else /* not HAVE_FONTCONFIG */
1207 MPLIST_DO (plist, ft_list_family (Mnil, 0))
1209 pl = MPLIST_PLIST (plist);
1210 if (! MPLIST_TAIL_P (pl))
1211 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1214 #endif /* not HAVE_FONTCONFIG */
1215 return ft_default_list;
1219 static MPlist *ft_capability_list;
1222 ft_list_capability (MSymbol capability)
1224 MFontCapability *cap;
1225 MPlist *plist = NULL, *pl;
1227 if (! ft_capability_list)
1228 ft_capability_list = mplist ();
1229 else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1230 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1232 cap = mfont__get_capability (capability);
1234 if (cap && cap->language != Mnil)
1236 plist = ft_list_language (cap->language);
1239 plist = mplist_copy (plist);
1242 if (cap && cap->script != Mnil)
1246 plist = ft_list_script (cap->script);
1249 plist = mplist_copy (plist);
1253 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1255 if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1258 pl = MPLIST_NEXT (pl);
1262 if (cap->script_tag)
1264 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1266 if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1269 pl = MPLIST_NEXT (pl);
1273 if (MPLIST_TAIL_P (plist))
1275 M17N_OBJECT_UNREF (plist);
1280 mplist_push (ft_capability_list, capability, plist);
1286 ft_list_file (MSymbol filename)
1288 MPlist *plist = NULL;
1291 ft_file_list = mplist ();
1292 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1293 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1295 #ifdef HAVE_FONTCONFIG
1297 FcPattern *pattern = FcPatternCreate ();
1301 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1302 os = FcObjectSetBuild (FC_FAMILY, NULL);
1303 fs = FcFontList (fc_config, pattern, os);
1310 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1311 (FcChar8 **) &fam) == FcResultMatch)
1316 STRDUP_LOWER (buf, bufsize, fam);
1317 family = msymbol (buf);
1318 pl = ft_list_family (family, 0);
1319 MPLIST_DO (pl, MPLIST_PLIST (pl))
1321 MFontFT *ft_info = MPLIST_VAL (pl);
1323 if (ft_info->font.file == filename)
1326 mplist_add (plist, family, ft_info);
1333 #else /* not HAVE_FONTCONFIG */
1337 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1339 MPLIST_DO (p, MPLIST_PLIST (pl))
1341 MFontFT *ft_info = MPLIST_VAL (pl);
1343 if (ft_info->font.file == filename)
1346 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1354 #endif /* not HAVE_FONTCONFIG */
1356 mplist_push (ft_file_list, filename, plist);
1360 /* The FreeType font driver function SELECT. */
1363 ft_select (MFrame *frame, MFont *font, int limited_size)
1365 MFont *found = NULL;
1366 #ifdef HAVE_FONTCONFIG
1369 int check_font_property = 1;
1371 if (font->file != Mnil)
1373 plist = ft_list_file (font->file);
1376 check_font_property = 0;
1380 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1383 plist = MPLIST_PLIST (ft_list_family (family, 1));
1385 plist = ft_list_default ();
1386 if (MPLIST_TAIL_P (plist))
1390 plist = mplist_copy (plist);
1392 if (font->capability != Mnil)
1394 MFontCapability *cap = mfont__get_capability (font->capability);
1396 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1398 if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1404 && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1407 pl = MPLIST_NEXT (pl);
1411 if (check_font_property)
1413 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1414 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1415 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1416 MSymbol alternate_weight = Mnil;
1418 if (weight == Mnormal)
1419 alternate_weight = Mmedium;
1420 else if (weight == Mmedium)
1421 alternate_weight = Mnormal;
1422 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1423 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1425 ft_info = MPLIST_VAL (pl);
1427 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1428 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1430 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1432 && stretch != FONT_PROPERTY (&ft_info->font,
1435 && ft_info->font.size > 0
1436 && ft_info->font.size != font->size))
1439 pl = MPLIST_NEXT (pl);
1443 MPLIST_DO (pl, plist)
1445 font = MPLIST_VAL (plist);
1446 if (limited_size == 0
1448 || font->size <= limited_size)
1454 M17N_OBJECT_UNREF (plist);
1455 #endif /* HAVE_FONTCONFIG */
1460 static MRealizedFont *
1461 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1463 MFontFT *ft_info = (MFontFT *) font;
1464 int reg = spec->property[MFONT_REGISTRY];
1465 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1466 MRealizedFontFT *ft_rfont;
1468 MPlist *plist, *charmap_list = NULL;
1473 /* non-scalable font */
1475 else if (spec->size)
1477 int ratio = mfont_resize_ratio (font);
1479 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1486 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1487 for (; rfont; rfont = rfont->next)
1488 if (rfont->font == font
1489 && (rfont->font->size ? rfont->font->size == size
1490 : rfont->spec.size == size)
1491 && rfont->spec.property[MFONT_REGISTRY] == reg
1492 && rfont->driver == &mfont__ft_driver)
1496 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1498 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1501 font->type = MFONT_TYPE_FAILURE;
1502 MDEBUG_PRINT (" no (FT_New_Face)\n");
1506 M17N_OBJECT_REF (charmap_list);
1508 charmap_list = ft_get_charmaps (ft_face);
1509 if (registry == Mnil)
1510 registry = Municode_bmp;
1511 plist = mplist_find_by_key (charmap_list, registry);
1514 FT_Done_Face (ft_face);
1515 M17N_OBJECT_UNREF (charmap_list);
1516 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1519 charmap_index = (int) MPLIST_VAL (plist);
1520 if ((charmap_index >= 0
1521 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1522 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1524 FT_Done_Face (ft_face);
1525 M17N_OBJECT_UNREF (charmap_list);
1526 font->type = MFONT_TYPE_FAILURE;
1527 MDEBUG_PRINT1 (" no (size %d)\n", size);
1531 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1532 ft_rfont->ft_face = ft_face;
1533 ft_rfont->charmap_list = charmap_list;
1534 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1535 rfont->spec = *font;
1536 rfont->spec.type = MFONT_TYPE_REALIZED;
1537 rfont->spec.property[MFONT_REGISTRY] = reg;
1538 rfont->spec.size = size;
1539 rfont->frame = frame;
1541 rfont->driver = &mfont__ft_driver;
1542 rfont->info = ft_rfont;
1543 rfont->fontp = ft_face;
1544 rfont->ascent = ft_face->size->metrics.ascender;
1545 rfont->descent = - ft_face->size->metrics.descender;
1546 rfont->max_advance = ft_face->size->metrics.max_advance;
1547 rfont->baseline_offset = 0;
1548 rfont->x_ppem = ft_face->size->metrics.x_ppem;
1549 rfont->y_ppem = ft_face->size->metrics.y_ppem;
1552 BDF_PropertyRec prop;
1554 if (! FT_IS_SCALABLE (ft_face)
1555 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1557 rfont->baseline_offset = prop.u.integer << 6;
1558 rfont->ascent += prop.u.integer << 6;
1559 rfont->descent -= prop.u.integer << 6;
1562 #endif /* HAVE_FTBDF_H */
1563 if (FT_IS_SCALABLE (ft_face))
1564 rfont->average_width = 0;
1566 rfont->average_width = ft_face->available_sizes->width << 6;
1567 rfont->next = MPLIST_VAL (frame->realized_font_list);
1568 MPLIST_VAL (frame->realized_font_list) = rfont;
1569 MDEBUG_PRINT (" ok\n");
1573 /* The FreeType font driver function FIND_METRIC. */
1576 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1579 FT_Face ft_face = rfont->fontp;
1580 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1582 for (; g != gend; g++)
1586 if (g->g.code == MCHAR_INVALID_CODE)
1588 if (FT_IS_SCALABLE (ft_face))
1591 g->g.rbearing = ft_face->size->metrics.max_advance;
1592 g->g.xadv = g->g.rbearing;
1593 g->g.ascent = ft_face->size->metrics.ascender;
1594 g->g.descent = - ft_face->size->metrics.descender;
1599 BDF_PropertyRec prop;
1600 #endif /* HAVE_FTBDF_H */
1603 g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1605 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1607 g->g.ascent = prop.u.integer << 6;
1608 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1609 g->g.descent = prop.u.integer << 6;
1610 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1613 g->g.ascent += prop.u.integer << 6;
1614 g->g.descent -= prop.u.integer << 6;
1618 #endif /* HAVE_FTBDF_H */
1620 g->g.ascent = ft_face->available_sizes->height << 6;
1627 FT_Glyph_Metrics *metrics;
1629 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
1630 metrics = &ft_face->glyph->metrics;
1631 g->g.lbearing = metrics->horiBearingX;
1632 g->g.rbearing = metrics->horiBearingX + metrics->width;
1633 g->g.xadv = metrics->horiAdvance;
1634 g->g.ascent = metrics->horiBearingY;
1635 g->g.descent = metrics->height - metrics->horiBearingY;
1638 g->g.ascent += rfont->baseline_offset;
1639 g->g.descent -= rfont->baseline_offset;
1645 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1647 MRealizedFont *rfont = NULL;
1648 MRealizedFontFT *ft_rfont;
1651 if (font->type == MFONT_TYPE_REALIZED)
1652 rfont = (MRealizedFont *) font;
1653 else if (font->type == MFONT_TYPE_OBJECT)
1655 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1656 rfont = rfont->next)
1657 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1661 #ifdef HAVE_FONTCONFIG
1662 MFontFT *ft_info = (MFontFT *) font;
1664 if (! ft_info->charset)
1666 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1667 MSYMBOL_NAME (font->file),
1669 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1670 FcFontSet *fs = FcFontList (fc_config, pat, os);
1673 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1674 &ft_info->charset) == FcResultMatch)
1675 ft_info->charset = FcCharSetCopy (ft_info->charset);
1677 ft_info->charset = FcCharSetCreate ();
1678 FcFontSetDestroy (fs);
1679 FcObjectSetDestroy (os);
1680 FcPatternDestroy (pat);
1682 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1683 #else /* not HAVE_FONTCONFIG */
1684 rfont = ft_open (frame, font, spec, NULL);
1685 #endif /* not HAVE_FONTCONFIG */
1689 MFATAL (MERROR_FONT_FT);
1693 ft_rfont = rfont->info;
1694 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1698 /* The FreeType font driver function ENCODE_CHAR. */
1701 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1703 MRealizedFont *rfont;
1704 MRealizedFontFT *ft_rfont;
1707 if (font->type == MFONT_TYPE_REALIZED)
1708 rfont = (MRealizedFont *) font;
1709 else if (font->type == MFONT_TYPE_OBJECT)
1711 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1712 rfont = rfont->next)
1713 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1717 rfont = ft_open (frame, font, spec, NULL);
1723 MFATAL (MERROR_FONT_FT);
1725 ft_rfont = rfont->info;
1726 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1727 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1730 /* The FreeType font driver function RENDER. */
1732 #define NUM_POINTS 0x1000
1735 MDrawPoint points[NUM_POINTS];
1740 ft_render (MDrawWindow win, int x, int y,
1741 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1742 int reverse, MDrawRegion region)
1745 MRealizedFace *rface = from->rface;
1746 MFrame *frame = rface->frame;
1747 FT_Int32 load_flags = FT_LOAD_RENDER;
1750 MPointTable point_table[8];
1751 int baseline_offset;
1752 int pixel_mode = -1;
1757 /* It is assured that the all glyphs in the current range use the
1758 same realized face. */
1759 ft_face = rface->rfont->fontp;
1760 baseline_offset = rface->rfont->baseline_offset >> 6;
1762 if (! gstring->anti_alias)
1764 #ifdef FT_LOAD_TARGET_MONO
1765 load_flags |= FT_LOAD_TARGET_MONO;
1767 load_flags |= FT_LOAD_MONOCHROME;
1771 for (i = 0; i < 8; i++)
1772 point_table[i].p = point_table[i].points;
1774 for (g = from; g < to; x += g++->g.xadv)
1778 MPointTable *ptable;
1782 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
1784 pixel_mode = ft_face->glyph->bitmap.pixel_mode;
1785 yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
1786 bmp = ft_face->glyph->bitmap.buffer;
1787 width = ft_face->glyph->bitmap.width;
1788 pitch = ft_face->glyph->bitmap.pitch;
1790 if (pixel_mode != FT_PIXEL_MODE_MONO)
1791 for (i = 0; i < ft_face->glyph->bitmap.rows;
1792 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1794 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1795 for (j = 0; j < width; j++, xoff++)
1797 intensity = bmp[j] >> 5;
1800 ptable = point_table + intensity;
1801 ptable->p->x = xoff;
1802 ptable->p->y = yoff - baseline_offset;
1804 if (ptable->p - ptable->points == NUM_POINTS)
1806 (*frame->driver->draw_points)
1808 reverse ? 7 - intensity : intensity,
1809 ptable->points, NUM_POINTS, region);
1810 ptable->p = ptable->points;
1816 for (i = 0; i < ft_face->glyph->bitmap.rows;
1817 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1819 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1820 for (j = 0; j < width; j++, xoff++)
1822 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1825 ptable = point_table;
1826 ptable->p->x = xoff;
1827 ptable->p->y = yoff - baseline_offset;
1829 if (ptable->p - ptable->points == NUM_POINTS)
1831 (*frame->driver->draw_points) (frame, win, rface,
1833 ptable->points, NUM_POINTS, region);
1834 ptable->p = ptable->points;
1841 if (pixel_mode != FT_PIXEL_MODE_MONO)
1843 for (i = 1; i < 8; i++)
1844 if (point_table[i].p != point_table[i].points)
1845 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1846 point_table[i].points,
1847 point_table[i].p - point_table[i].points, region);
1851 if (point_table[0].p != point_table[0].points)
1852 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1853 point_table[0].points,
1854 point_table[0].p - point_table[0].points, region);
1859 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1861 MPlist *pl = NULL, *p;
1863 MPlist *file_list = NULL;
1864 MPlist *family_list = NULL, *capability_list = NULL;
1865 MSymbol registry = Mnil;
1867 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1873 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1874 if (registry != Mnil && registry != Miso8859_1)
1876 char *reg = MSYMBOL_NAME (registry);
1878 if (strncmp (reg, "unicode-", 8)
1879 && strncmp (reg, "apple-roman", 11)
1880 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1884 if (font->file != Mnil
1885 && ! (file_list = ft_list_file (font->file)))
1887 family = FONT_PROPERTY (font, MFONT_FAMILY);
1889 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1890 && MPLIST_TAIL_P (family_list))
1892 if (font->capability != Mnil)
1894 capability_list = ft_list_capability (font->capability);
1895 if (! capability_list || MPLIST_TAIL_P (capability_list))
1900 if (! file_list && ! family_list && ! capability_list)
1902 /* No restriction. Get all fonts. */
1904 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1906 MPLIST_DO (p, MPLIST_PLIST (family_list))
1907 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1915 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1920 for (p = pl; ! MPLIST_TAIL_P (p);)
1922 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1923 p = MPLIST_NEXT (p);
1930 MPLIST_DO (p, family_list)
1931 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1934 if (capability_list)
1937 for (p = pl; ! MPLIST_TAIL_P (p);)
1939 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1940 p = MPLIST_NEXT (p);
1947 MPLIST_DO (p, capability_list)
1948 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1954 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1955 + font->property[MFONT_STRETCH] + font->size) > 0)
1957 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1958 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1959 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1960 int size = font->size;
1962 for (p = pl; ! MPLIST_TAIL_P (p); )
1964 MFontFT *ft_info = MPLIST_VAL (p);
1967 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1969 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1971 && stretch != FONT_PROPERTY (&ft_info->font,
1974 && ft_info->font.size > 0
1975 && ft_info->font.size != size))
1978 p = MPLIST_NEXT (p);
1984 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1986 if (maxnum && maxnum <= num)
1989 M17N_OBJECT_UNREF (pl);
1992 MDEBUG_PRINT1 (" %d found\n", num);
1997 ft_list_family_names (MFrame *frame, MPlist *plist)
2003 #ifdef HAVE_FONTCONFIG
2004 fc_init_font_list ();
2005 #else /* not HAVE_FONTCONFIG */
2006 ft_init_font_list ();
2007 #endif /* not HAVE_FONTCONFIG */
2010 MPLIST_DO (pl, ft_font_list)
2012 MSymbol family = MPLIST_KEY (pl);
2015 #ifdef HAVE_FONTCONFIG
2016 if (msymbol_get (family, Mgeneric_family) != Mnil)
2018 #endif /* HAVE_FONTCONFIG */
2019 MPLIST_DO (p, plist)
2021 MSymbol sym = MPLIST_SYMBOL (p);
2025 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2027 mplist_push (p, Msymbol, family);
2031 if (MPLIST_TAIL_P (p))
2032 mplist_push (p, Msymbol, family);
2037 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2039 MFontFT *ft_info = (MFontFT *) rfont->font;
2040 MRealizedFontFT *ft_rfont = rfont->info;
2041 MFontCapability *cap = mfont__get_capability (capability);
2043 if (cap->script_tag)
2045 if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2048 else if (cap->script != Mnil
2049 && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2051 if (cap->language != Mnil
2052 && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2057 static MRealizedFont *
2058 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2061 MRealizedFont *rfont;
2062 MRealizedFontFT *ft_rfont;
2065 if (data_type == Mfontconfig)
2067 #ifdef HAVE_FONTCONFIG
2068 FcPattern *pattern = data;
2070 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2073 ft_info = fc_gen_font (pattern, NULL);
2074 #else /* not HAVE_FONTCONFIG */
2076 #endif /* not HAVE_FONTCONFIG */
2078 else if (data_type == Mfreetype)
2081 ft_info = ft_gen_font (ft_face);
2086 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2087 ft_rfont->ft_face = ft_face;
2088 ft_rfont->face_encapsulated = 1;
2090 MDEBUG_DUMP (" [FONT-FT] encapsulating ", (char *) ft_face->family_name,);
2092 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2093 rfont->font = (MFont *) ft_info;
2094 rfont->info = ft_rfont;
2095 rfont->fontp = ft_face;
2096 rfont->driver = &mfont__ft_driver;
2097 rfont->spec = ft_info->font;
2098 rfont->spec.type = MFONT_TYPE_REALIZED;
2099 rfont->frame = frame;
2100 rfont->ascent = ft_face->size->metrics.ascender >> 6;
2101 rfont->descent = - ft_face->size->metrics.descender >> 6;
2102 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2103 rfont->baseline_offset = 0;
2104 rfont->x_ppem = ft_face->size->metrics.x_ppem;
2105 rfont->y_ppem = ft_face->size->metrics.y_ppem;
2108 BDF_PropertyRec prop;
2110 if (! FT_IS_SCALABLE (ft_face)
2111 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2113 rfont->baseline_offset = prop.u.integer << 6;
2114 rfont->ascent += prop.u.integer << 6;
2115 rfont->descent -= prop.u.integer << 6;
2118 #endif /* HAVE_FTBDF_H */
2119 if (FT_IS_SCALABLE (ft_face))
2120 rfont->average_width = 0;
2122 rfont->average_width = ft_face->available_sizes->width << 6;
2123 rfont->next = MPLIST_VAL (frame->realized_font_list);
2124 MPLIST_VAL (frame->realized_font_list) = rfont;
2130 ft_close (MRealizedFont *rfont)
2132 if (! rfont->encapsulating)
2135 M17N_OBJECT_UNREF (rfont->info);
2140 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2143 MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2144 MFontFT *ft_info = (MFontFT *) rfont->font;
2149 if (ft_info->otf == invalid_otf)
2154 MRealizedFontFT *ft_rfont = rfont->info;
2156 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2157 otf = OTF_open_ft_face (ft_rfont->ft_face);
2159 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2163 ft_info->otf = invalid_otf;
2169 for (i = 0; i < 2; i++)
2171 if (! spec->features[i])
2173 for (n = 0; spec->features[i][n]; n++);
2174 tags = alloca (sizeof (OTF_Tag) * n);
2175 for (n = 0, negative = 0; spec->features[i][n]; n++)
2177 if (spec->features[i][n] == 0xFFFFFFFF)
2180 tags[n - 1] = spec->features[i][n] | 0x80000000;
2182 tags[n] = spec->features[i][n];
2184 if (n - negative > 0
2185 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2186 tags, n - negative) != 1)
2190 #endif /* HAVE_OTF */
2192 return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
2193 && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
2198 #define DEVICE_DELTA(table, size) \
2199 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2200 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
2204 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2205 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2207 if (anchor->AnchorFormat == 2)
2209 FT_Outline *outline;
2210 int ap = anchor->f.f1.AnchorPoint;
2212 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2213 outline = &ft_face->glyph->outline;
2214 if (ap < outline->n_points)
2216 *x = outline->points[ap].x << 6;
2217 *y = outline->points[ap].y << 6;
2220 else if (anchor->AnchorFormat == 3)
2222 if (anchor->f.f2.XDeviceTable.offset)
2223 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2224 if (anchor->f.f2.YDeviceTable.offset)
2225 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2228 #endif /* HAVE_OTF */
2231 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2232 MFLTGlyphString *in, int from, int to,
2233 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2235 int len = to - from;
2237 MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2238 MRealizedFontFT *ft_rfont = rfont->info;
2239 MFontFT *ft_info = (MFontFT *) rfont->font;
2241 MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2242 MGlyph *out_glyphs = (MGlyph *) (out->glyphs);
2244 OTF_GlyphString otf_gstring;
2246 char script[5], *langsys = NULL;
2247 char *gsub_features = NULL, *gpos_features = NULL;
2251 if (ft_info->otf == invalid_otf)
2256 MRealizedFontFT *ft_rfont = rfont->info;
2258 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2259 otf = OTF_open_ft_face (ft_rfont->ft_face);
2261 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2265 ft_info->otf = invalid_otf;
2271 if (OTF_get_table (otf, "head") < 0)
2274 ft_info->otf = invalid_otf;
2278 OTF_tag_name (spec->script, script);
2281 langsys = alloca (5);
2282 OTF_tag_name (spec->langsys, langsys);
2284 for (i = 0; i < 2; i++)
2288 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
2290 for (j = 0; spec->features[i][j]; j++);
2292 p = gsub_features = alloca (6 * j);
2294 p = gpos_features = alloca (6 * j);
2295 for (j = 0; spec->features[i][j]; j++)
2297 if (spec->features[i][j] == 0xFFFFFFFF)
2298 *p++ = '*', *p++ = ',';
2301 OTF_tag_name (spec->features[i][j], p);
2310 otf_gstring.size = otf_gstring.used = len;
2311 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2312 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2313 for (i = 0; i < len; i++)
2315 otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c;
2316 otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2319 OTF_drive_gdef (otf, &otf_gstring);
2324 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2327 if (out->allocated < out->used + otf_gstring.used)
2329 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2331 MGlyph *g = out_glyphs + out->used;
2334 *g = in_glyphs[from + otfg->f.index.from];
2336 for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
2337 if (in_glyphs[j].g.code == otfg->glyph_id)
2339 g->g.c = in_glyphs[j].g.c;
2342 if (g->g.code != otfg->glyph_id)
2344 g->g.code = otfg->glyph_id;
2352 if (out->allocated < out->used + len)
2354 for (i = 0; i < len; i++)
2355 out_glyphs[out->used++] = in_glyphs[from + i];
2361 MGlyph *base = NULL, *mark = NULL, *g;
2362 int x_ppem, y_ppem, x_scale, y_scale;
2364 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
2368 face = ft_rfont->ft_face;
2369 x_ppem = face->size->metrics.x_ppem;
2370 y_ppem = face->size->metrics.y_ppem;
2371 x_scale = face->size->metrics.x_scale;
2372 y_scale = face->size->metrics.y_scale;
2374 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2375 i < otf_gstring.used; i++, otfg++, g++)
2379 if (! otfg->glyph_id)
2381 switch (otfg->positioning_type)
2385 case 1: /* Single */
2388 int format = otfg->f.f1.format;
2390 if (format & OTF_XPlacement)
2392 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2393 if (format & OTF_XPlaDevice)
2395 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2396 if (format & OTF_YPlacement)
2398 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
2399 if (format & OTF_YPlaDevice)
2401 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2402 if (format & OTF_XAdvance)
2404 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2405 if (format & OTF_XAdvDevice)
2407 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2408 if (format & OTF_YAdvance)
2410 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2411 if (format & OTF_YAdvDevice)
2413 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2414 adjustment[i].set = 1;
2417 case 3: /* Cursive */
2418 /* Not yet supported. */
2420 case 4: /* Mark-to-Base */
2421 case 5: /* Mark-to-Ligature */
2425 goto label_adjust_anchor;
2426 default: /* i.e. case 6 Mark-to-Mark */
2431 label_adjust_anchor:
2433 int base_x, base_y, mark_x, mark_y;
2434 int this_from, this_to;
2436 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2437 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2438 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2439 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2441 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2442 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2443 x_ppem, y_ppem, &base_x, &base_y);
2444 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2445 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2446 x_ppem, y_ppem, &mark_x, &mark_y);
2447 adjustment[i].xoff = (base_x - mark_x);
2448 adjustment[i].yoff = - (base_y - mark_y);
2449 adjustment[i].back = (g - prev);
2450 adjustment[i].xadv = 0;
2451 adjustment[i].advance_is_absolute = 1;
2452 adjustment[i].set = 1;
2453 this_from = g->g.from;
2455 for (j = 0; prev + j < g; j++)
2457 if (this_from > prev[j].g.from)
2458 this_from = prev[j].g.from;
2459 if (this_to < prev[j].g.to)
2460 this_to = prev[j].g.to;
2462 for (; prev <= g; prev++)
2464 prev->g.from = this_from;
2465 prev->g.to = this_to;
2469 if (otfg->GlyphClass == OTF_GlyphClass0)
2471 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2477 free (otf_gstring.glyphs);
2481 #endif /* HAVE_OTF */
2482 if (out->allocated < out->used + len)
2484 font->get_metrics (font, in, from, to);
2485 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2486 sizeof (MGlyph) * len);
2488 if (otf_gstring.glyphs)
2489 free (otf_gstring.glyphs);
2496 MFontDriver mfont__ft_driver =
2497 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2498 ft_render, ft_list, ft_list_family_names, ft_check_capability,
2499 ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf };
2506 if (FT_Init_FreeType (&ft_library) != 0)
2507 MERROR (MERROR_FONT_FT, -1);
2509 for (i = 0; i < ft_to_prop_size; i++)
2510 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2512 Mmedium = msymbol ("medium");
2514 Mnull = msymbol ("");
2516 M0[0] = msymbol ("0-0");
2517 M0[1] = msymbol ("0-1");
2518 M0[2] = msymbol ("0-2");
2519 M0[3] = msymbol ("0-3");
2520 M0[4] = msymbol ("0-4");
2521 M3_1 = msymbol ("3-1");
2522 M1_0 = msymbol ("1-0");
2524 #ifdef HAVE_FONTCONFIG
2525 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2527 FC_vs_M17N_font_prop *table = fc_all_table[i];
2530 for (j = 0; table[j].m17n_value; j++)
2531 table[j].sym = msymbol (table[j].m17n_value);
2532 table[j].sym = table[j - 1].sym;
2539 MSymbol serif, sans_serif, monospace;
2541 fc_config = FcInitLoadConfigAndFonts ();
2542 if (mfont_freetype_path)
2544 MPLIST_DO (plist, mfont_freetype_path)
2545 if (MPLIST_STRING_P (plist)
2546 && (pathname = MPLIST_STRING (plist))
2547 && stat (pathname, &buf) == 0)
2549 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2552 while ((dir = FcStrListNext (strlist)))
2553 if (strcmp ((char *) dir, pathname) == 0)
2556 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2557 FcStrListDone (strlist);
2560 Mgeneric_family = msymbol ("generic famly");
2561 serif = msymbol ("serif");
2562 msymbol_put (serif, Mgeneric_family, serif);
2563 sans_serif = msymbol ("sans-serif");
2564 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2565 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2566 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2567 monospace = msymbol ("monospace");
2568 msymbol_put (monospace, Mgeneric_family, monospace);
2569 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2571 #endif /* HAVE_FONTCONFIG */
2581 if (ft_default_list)
2583 M17N_OBJECT_UNREF (ft_default_list);
2584 ft_default_list = NULL;
2589 MPLIST_DO (plist, ft_font_list)
2591 if (MPLIST_VAL (plist))
2592 MPLIST_DO (p, MPLIST_VAL (plist))
2594 if (MPLIST_KEY (p) != Mt)
2595 free_ft_info (MPLIST_VAL (p));
2597 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2599 M17N_OBJECT_UNREF (ft_font_list);
2600 ft_font_list = NULL;
2602 if (ft_language_list)
2604 MPLIST_DO (plist, ft_language_list)
2605 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2606 M17N_OBJECT_UNREF (ft_language_list);
2607 ft_language_list = NULL;
2612 MPLIST_DO (plist, ft_script_list)
2613 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2614 M17N_OBJECT_UNREF (ft_script_list);
2615 ft_script_list = NULL;
2618 if (ft_capability_list)
2620 MPLIST_DO (plist, ft_capability_list)
2621 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2622 M17N_OBJECT_UNREF (ft_capability_list);
2623 ft_capability_list = NULL;
2628 MPLIST_DO (plist, ft_file_list)
2629 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2630 M17N_OBJECT_UNREF (ft_file_list);
2631 ft_file_list = NULL;
2634 FT_Done_FreeType (ft_library);
2635 #ifdef HAVE_FONTCONFIG
2636 FcConfigDestroy (fc_config);
2638 #endif /* HAVE_FONTCONFIG */
2639 all_fonts_scaned = 0;
2642 #ifdef HAVE_FONTCONFIG
2645 mfont__ft_parse_name (const char *name, MFont *font)
2647 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2656 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2658 STRDUP_LOWER (buf, bufsize, (char *) str);
2659 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2661 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2663 STRDUP_LOWER (buf, bufsize, (char *) str);
2664 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2666 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2667 mfont__set_property (font, MFONT_WEIGHT,
2668 fc_decode_prop (val, fc_weight_table,
2669 fc_weight_table_size));
2670 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2671 mfont__set_property (font, MFONT_STYLE,
2672 fc_decode_prop (val, fc_slant_table,
2673 fc_slant_table_size));
2674 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2675 mfont__set_property (font, MFONT_STRETCH,
2676 fc_decode_prop (val, fc_width_table,
2677 fc_width_table_size));
2678 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2679 font->size = size * 10 + 0.5;
2680 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2681 font->size = - (size * 10 + 0.5);
2682 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2684 font->file = msymbol ((char *) str);
2686 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2687 font->type = MFONT_TYPE_SPEC;
2688 FcPatternDestroy (pat);
2693 mfont__ft_unparse_name (MFont *font)
2695 FcPattern *pat = fc_get_pattern (font);
2696 char *name = (char *) FcNameUnparse (pat);
2698 FcPatternDestroy (pat);
2701 #endif /* HAVE_FONTCONFIG */
2703 #endif /* HAVE_FREETYPE */