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., 59 Temple Place, Suite 330, Boston, MA
28 #include <sys/types.h>
35 #include "m17n-misc.h"
40 #include "internal-gui.h"
47 #include <freetype/ftbdf.h>
50 static int mdebug_mask = MDEBUG_FONT;
52 #ifdef HAVE_FONTCONFIG
53 static FcConfig *fc_config;
54 static MSymbol Mgeneric_family;
55 #endif /* HAVE_FONTCONFIG */
57 /* Font properties; Mnormal is already defined in face.c. */
58 static MSymbol Mmedium, Mr, Mnull;
60 static MSymbol M0[5], M3_1, M1_0;
62 static FT_Library ft_library;
65 static OTF *invalid_otf = (OTF *) "";
72 /* NULL if not yet opened. invalid_otf if not OTF. */
75 #ifdef HAVE_FONTCONFIG
78 #endif /* HAVE_FONTCONFIG */
92 enum MFontProperty prop;
96 static MFTtoProp ft_to_prop[] =
97 { { "italic", 0, MFONT_STYLE, "i" },
98 { "roman", 0, MFONT_STYLE, "r" },
99 { "oblique", 0, MFONT_STYLE, "o" },
100 { "regular", 0, MFONT_WEIGHT, "normal" },
101 { "normal", 0, MFONT_WEIGHT, "normal" },
102 /* We need this entry even if "bold" is in commone_weight[] to
103 handle such style names as "bolditalic" and "boldoblique". */
104 { "bold", 0, MFONT_WEIGHT, "bold" },
105 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
106 { "demi", 0, MFONT_WEIGHT, "demibold" } };
107 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
109 /** List of FreeType fonts. Keys are family names, values are plists
110 containing fonts of the corresponding family. In the deeper
111 plist, keys are file names, values are (MFontFT *). */
112 static MPlist *ft_font_list;
114 /** List of FreeType fonts. Keys are script names, values are plists
115 containing fonts supporting the corresponding script. In the
116 deeper plist, keys are family names, values are (MFontFT *). */
117 static MPlist *ft_script_list;
119 /** List of FreeType fonts. Keys are language names, values are
120 plists containing fonts supporting the corresponding language. In
121 the deeper plist, keys are family names, values are (MFontFT *). */
122 static MPlist *ft_language_list;
124 static MPlist *ft_file_list;
126 static int all_fonts_scaned;
128 #define STRDUP_LOWER(s1, size, s2) \
130 int len = strlen (s2) + 1; \
134 (s1) = alloca (len), (size) = len; \
135 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
136 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
137 while (p1 > (s1) && p1[-1] == ' ') p1--; \
142 static MPlist *ft_list_family (MSymbol, int);
145 free_ft_rfont (void *object)
147 MRealizedFontFT *ft_rfont = object;
149 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
150 FT_Done_Face (ft_rfont->ft_face);
155 free_ft_info (MFontFT *ft_info)
158 if (ft_info->otf && ft_info->otf != invalid_otf)
159 OTF_close (ft_info->otf);
160 #endif /* HAVE_OTF */
161 #ifdef HAVE_FONTCONFIG
162 if (ft_info->langset)
163 FcLangSetDestroy (ft_info->langset);
164 if (ft_info->charset)
165 FcCharSetDestroy (ft_info->charset);
166 #endif /* HAVE_FONTCONFIG */
171 ft_get_charmaps (FT_Face ft_face)
173 MPlist *plist = mplist ();
174 int unicode_bmp = -1, unicode_full = -1;
177 mplist_add (plist, Mt, (void *) -1);
178 for (i = 0; i < ft_face->num_charmaps; i++)
180 MSymbol registry = Mnil;
182 if (ft_face->charmaps[i]->platform_id == 0)
184 if (ft_face->charmaps[i]->encoding_id <= 4)
185 registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
186 if (ft_face->charmaps[i]->encoding_id == 4)
187 unicode_bmp = unicode_full = i;
189 else if (ft_face->charmaps[i]->platform_id == 3)
191 if (ft_face->charmaps[i]->encoding_id == 1)
192 registry = M3_1, unicode_bmp = i;
193 else if (ft_face->charmaps[i]->encoding_id == 10)
194 unicode_bmp = unicode_full = i;
196 else if (ft_face->charmaps[i]->platform_id == 1
197 && ft_face->charmaps[i]->encoding_id == 0)
200 mplist_add (plist, Mapple_roman, (void *) i);
202 if (registry == Mnil)
204 char registry_buf[16];
206 sprintf (registry_buf, "%d-%d",
207 ft_face->charmaps[i]->platform_id,
208 ft_face->charmaps[i]->encoding_id);
209 registry = msymbol (registry_buf);
211 mplist_add (plist, registry, (void *) i);
213 if (unicode_full >= 0)
214 mplist_add (plist, Municode_full, (void *) unicode_full);
215 if (unicode_bmp >= 0)
219 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
220 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
221 for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
224 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
226 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
233 #ifdef HAVE_FONTCONFIG
240 } FC_vs_M17N_font_prop;
242 static FC_vs_M17N_font_prop fc_weight_table[] =
243 { { FC_WEIGHT_THIN, "thin" },
244 { FC_WEIGHT_ULTRALIGHT, "extralight" },
245 { FC_WEIGHT_LIGHT, "light" },
246 #ifdef FC_WEIGHT_BOOK
247 { FC_WEIGHT_BOOK, "book" },
248 #endif /* FC_WEIGHT_BOOK */
249 { FC_WEIGHT_REGULAR, "normal" },
250 { FC_WEIGHT_NORMAL, "normal" },
251 { FC_WEIGHT_MEDIUM, "medium" },
252 { FC_WEIGHT_DEMIBOLD, "demibold" },
253 { FC_WEIGHT_BOLD, "bold" },
254 { FC_WEIGHT_EXTRABOLD, "extrabold" },
255 { FC_WEIGHT_BLACK, "black" },
256 { FC_WEIGHT_HEAVY, "heavy" },
257 { FC_WEIGHT_MEDIUM, NULL } };
258 int fc_weight_table_size =
259 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
261 static FC_vs_M17N_font_prop fc_slant_table[] =
262 { { FC_SLANT_ROMAN, "r" },
263 { FC_SLANT_ITALIC, "i" },
264 { FC_SLANT_OBLIQUE, "o" },
265 { FC_SLANT_ROMAN, NULL } };
266 int fc_slant_table_size =
267 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
269 static FC_vs_M17N_font_prop fc_width_table[] =
270 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
271 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
272 { FC_WIDTH_CONDENSED, "condensed" },
273 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
274 { FC_WIDTH_NORMAL, "normal" },
275 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
276 { FC_WIDTH_EXPANDED, "expanded" },
277 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
278 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
279 { FC_WIDTH_NORMAL, NULL } };
280 int fc_width_table_size =
281 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
284 static FC_vs_M17N_font_prop *fc_all_table[] =
285 { fc_weight_table, fc_slant_table, fc_width_table };
288 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
292 if (val < table[i].fc_value)
294 for (i--; i >= 0; i--)
295 if (val > table[i].fc_value)
301 for (; i < size; i++)
302 if (val <= table[i].fc_value)
309 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
313 for (i = 0; table[i].m17n_value; i++)
314 if (table[i].sym == sym)
316 return table[i].fc_value;
320 fc_get_pattern (MFont *font)
322 FcPattern *pat = FcPatternCreate ();
323 MSymbol sym, weight, style, stretch;
326 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
327 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
328 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
329 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
330 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
331 FcPatternAddInteger (pat, FC_WEIGHT,
332 fc_encode_prop (weight, fc_weight_table));
333 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
334 FcPatternAddInteger (pat, FC_SLANT,
335 fc_encode_prop (style, fc_slant_table));
336 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
337 FcPatternAddInteger (pat, FC_WIDTH,
338 fc_encode_prop (stretch, fc_width_table));
341 double size = font->size;
342 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
344 else if (font->size < 0)
346 double size = - font->size;
347 FcPatternAddDouble (pat, FC_SIZE, size / 10);
353 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
363 MFont *font = &ft_info->font;
366 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
368 STRDUP_LOWER (buf, bufsize, (char *) str);
369 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
372 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
373 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
375 STRDUP_LOWER (buf, bufsize, (char *) str);
376 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
378 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
380 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
381 mfont__set_property (font, MFONT_WEIGHT, sym);
383 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
385 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
386 mfont__set_property (font, MFONT_STYLE, sym);
388 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
390 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
391 mfont__set_property (font, MFONT_STRETCH, sym);
393 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
395 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
396 || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
397 || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
398 font->for_full_width = 1;
399 ft_info->langset = FcLangSetCopy (ls);
401 if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
402 ft_info->charset = FcCharSetCopy (cs);
404 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
405 font->type = MFONT_TYPE_SPEC;
406 font->source = MFONT_SOURCE_FT;
407 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
408 font->size = size * 10;
409 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
410 font->file = msymbol ((char *) str);
415 fc_gen_font (FcPattern *pat, char *family)
419 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
420 fc_parse_pattern (pat, family, ft_info);
421 ft_info->font.type = MFONT_TYPE_OBJECT;
426 fc_init_font_list (void)
428 FcPattern *pattern = FcPatternCreate ();
429 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
430 FcFontSet *fs = FcFontList (fc_config, pattern, os);
431 MPlist *plist = mplist ();
436 ft_font_list = plist;
437 for (i = 0; i < fs->nfont; i++)
441 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
442 (FcChar8 **) &fam) != FcResultMatch)
444 STRDUP_LOWER (buf, bufsize, fam);
445 plist = mplist_add (plist, msymbol (buf), NULL);
447 FcFontSetDestroy (fs);
448 FcObjectSetDestroy (os);
449 FcPatternDestroy (pattern);
453 fc_list_pattern (FcPattern *pattern)
455 FcObjectSet *os = NULL;
456 FcFontSet *fs = NULL;
457 MSymbol last_family = Mnil;
458 MPlist *plist = NULL, *pl = NULL;
463 if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
465 if (! (fs = FcFontList (fc_config, pattern, os)))
468 for (i = 0; i < fs->nfont; i++)
470 MSymbol family, file;
471 char *fam, *filename;
474 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
475 (FcChar8 **) &fam) != FcResultMatch)
477 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
478 (FcChar8 **) &filename) != FcResultMatch)
480 STRDUP_LOWER (buf, bufsize, fam);
481 family = msymbol (buf);
482 file = msymbol (filename);
483 if (family != last_family)
485 pl = MPLIST_PLIST (ft_list_family (family, 0));
486 last_family = family;
488 ft_info = mplist_get (pl, file);
493 mplist_add (plist, family, ft_info);
498 if (fs) FcFontSetDestroy (fs);
499 if (os) FcObjectSetDestroy (os);
503 /* Return FcCharSet object built from CHAR_LIST or MT. In the latter
504 case, it is assured that the M-text contains at least one
508 fc_build_charset (MPlist *char_list, MText *mt)
510 FcCharSet *cs = FcCharSetCreate ();
516 for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
517 if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
519 FcCharSetDestroy (cs);
527 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
528 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
530 FcCharSetDestroy (cs);
533 if (mtext_nchars (mt) > 0
534 && (mt = mtext_get_prop (mt, 0, Mtext)))
535 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
536 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
538 FcCharSetDestroy (cs);
545 #else /* not HAVE_FONTCONFIG */
548 ft_add_font (char *filename)
561 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
563 if (! FT_IS_SCALABLE (ft_face))
567 BDF_PropertyRec prop;
569 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
570 size = prop.u.integer * 10;
571 #else /* not HAVE_FTBDF_H */
573 #endif /* not HAVE_FTBDF_H */
576 FT_Done_Face (ft_face);
581 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
582 font = &ft_info->font;
583 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
584 family = msymbol (buf);
585 mfont__set_property (font, MFONT_FAMILY, family);
586 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
587 mfont__set_property (font, MFONT_STYLE, Mr);
588 mfont__set_property (font, MFONT_STRETCH, Mnormal);
589 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
590 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
591 font->type = MFONT_TYPE_OBJECT;
592 font->source = MFONT_SOURCE_FT;
594 font->file = msymbol (filename);
596 stylename = ft_face->style_name;
599 for (i = 0; i < ft_to_prop_size; i++)
600 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
603 mfont__set_property (font, ft_to_prop[i].prop,
604 msymbol (ft_to_prop[i].val));
605 stylename += ft_to_prop[i].len;
608 if (i == ft_to_prop_size)
610 char *p1 = stylename + 1;
613 while (*p1 >= 'a' && *p1 <= 'z') p1++;
614 sym = msymbol__with_len (stylename, p1 - stylename);
615 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
616 if (msymbol_get (sym, mfont__property_table[i].property))
618 mfont__set_property (font, i, sym);
623 while (*stylename && ! isalpha (*stylename))
627 FT_Done_Face (ft_face);
629 plist = mplist_find_by_key (ft_font_list, family);
631 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
635 mplist_add (plist, font->file, ft_info);
636 plist = mplist_push (ft_font_list, family, plist);
642 ft_init_font_list (void)
650 ft_font_list = mplist ();
651 MPLIST_DO (plist, mfont_freetype_path)
652 if (MPLIST_STRING_P (plist)
653 && (pathname = MPLIST_STRING (plist))
654 && stat (pathname, &buf) == 0)
656 if (S_ISREG (buf.st_mode))
657 ft_add_font (pathname);
658 else if (S_ISDIR (buf.st_mode))
660 DIR *dir = opendir (pathname);
664 int len = strlen (pathname);
667 while ((dp = readdir (dir)) != NULL)
669 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
670 strcpy (path, pathname);
672 strcpy (path + len + 1, dp->d_name);
682 /* Return 1 iff the font pointed by FT_INFO has all characters in
686 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
691 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
693 MPLIST_DO (cl, char_list)
694 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
696 FT_Done_Face (ft_face);
697 return MPLIST_TAIL_P (cl);
700 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
701 that supports characters in CHAR_LIST or MT. One of CHAR_LIST or
705 ft_list_char_list (MPlist *char_list, MText *mt)
707 MPlist *plist = NULL, *pl, *p;
710 ft_list_family (Mnil, 0);
714 int len = mtext_nchars (mt);
715 MText *extra = mtext_get_prop (mt, 0, Mtext);
716 int total_len = len + (extra ? mtext_nchars (extra) : 0);
719 char_list = mplist ();
720 for (i = 0; i < total_len; i++)
722 int c = (i < len ? mtext_ref_char (mt, i)
723 : mtext_ref_char (extra, i - len));
725 if (! mplist_find_by_value (char_list, (void *) c))
726 mplist_push (char_list, Minteger, (void *) c);
730 MPLIST_DO (pl, ft_font_list)
732 MPLIST_DO (p, MPLIST_PLIST (pl))
734 MFontFT *ft_info = MPLIST_VAL (p);
736 if (ft_has_char_list_p (ft_info, char_list))
738 MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
742 mplist_push (plist, family, ft_info);
747 M17N_OBJECT_UNREF (char_list);
750 #endif /* not HAVE_FONTCONFIG */
753 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
754 scan all fonts and return ft_font_list. */
757 ft_list_family (MSymbol family, int check_generic)
760 #ifdef HAVE_FONTCONFIG
775 plist = ft_font_list = mplist ();
776 pattern = FcPatternCreate ();
777 os = FcObjectSetBuild (FC_FAMILY, NULL);
778 fs = FcFontList (fc_config, pattern, os);
779 for (i = 0; i < fs->nfont; i++)
781 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
782 (FcChar8 **) &fam) != FcResultMatch)
784 STRDUP_LOWER (buf, bufsize, fam);
786 if (! mplist_find_by_key (ft_font_list, sym))
787 plist = mplist_add (plist, sym, NULL);
789 FcFontSetDestroy (fs);
790 FcObjectSetDestroy (os);
791 FcPatternDestroy (pattern);
796 if (! all_fonts_scaned)
798 MPLIST_DO (plist, ft_font_list)
800 if (! MPLIST_VAL (plist))
801 ft_list_family (MPLIST_KEY (plist), 0);
803 all_fonts_scaned = 1;
808 plist = mplist_find_by_key (ft_font_list, family);
811 if (! MPLIST_VAL (plist))
813 fam = MSYMBOL_NAME (family);
814 pattern = FcPatternCreate ();
815 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
816 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
817 FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
819 fs = FcFontList (fc_config, pattern, os);
821 for (i = 0; i < fs->nfont; i++)
823 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
824 p = mplist_add (p, ft_info->font.file, ft_info);
826 MPLIST_VAL (plist) = pl;
827 FcFontSetDestroy (fs);
828 FcObjectSetDestroy (os);
829 FcPatternDestroy (pattern);
832 else if (check_generic
833 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
835 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
838 if (family != generic)
839 plist = ft_list_family (generic, 1);
842 fam = MSYMBOL_NAME (family);
844 mplist_push (ft_font_list, family, plist);
845 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
846 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
849 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
852 STRDUP_LOWER (buf, bufsize, (char *) fam8);
853 family = msymbol (buf);
854 if (msymbol_get (family, Mgeneric_family))
856 pl = ft_list_family (family, 0);
859 MPLIST_DO (pl, MPLIST_PLIST (pl))
860 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
862 plist = ft_font_list;
867 /* Check if there exist an alias. */
869 plist = mplist_add (ft_font_list, family, pl);
871 pattern = FcPatternBuild (NULL,
872 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
874 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
876 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
877 (FcChar8 **) &fam) == FcResultMatch;
881 /* The last one is a generic family. */
884 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
887 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
888 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
889 (FcChar8 **) &fam) == FcResultMatch;
892 /* Now we know that the last J fonts in PATTERN are from
893 generic font, and the first one is not available. So,
894 the remaining ones are aliases. */
896 for (i = 1; i < j; i++)
898 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
899 STRDUP_LOWER (buf, bufsize, fam);
901 p = MPLIST_PLIST (ft_list_family (sym, 0));
902 if (! MPLIST_TAIL_P (p))
904 mplist_push (pl, Mt, MPLIST_VAL (p));
909 #else /* not HAVE_FONTCONFIG */
911 if (! all_fonts_scaned)
913 ft_init_font_list ();
914 all_fonts_scaned = 1;
917 plist = ft_font_list;
920 plist = mplist_find_by_key (ft_font_list, family);
922 plist = mplist_push (ft_font_list, family, mplist ());
924 #endif /* not HAVE_FONTCONFIG */
930 ft_list_language (MSymbol language)
932 MPlist *plist = NULL;
935 if (! ft_language_list)
936 ft_language_list = mplist ();
937 else if ((plist = mplist_find_by_key (ft_language_list, language)))
938 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
940 mt = mlanguage_text (language);
942 #ifdef HAVE_FONTCONFIG
944 FcPattern *pattern = NULL;
945 FcCharSet *cs = NULL;
946 FcLangSet *ls = NULL;
948 if (! (pattern = FcPatternCreate ()))
951 if (mt && mtext_nchars (mt) > 0)
953 cs = fc_build_charset (NULL, mt);
954 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
959 if (! (ls = FcLangSetCreate ()))
961 if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
962 || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
966 plist = fc_list_pattern (pattern);
968 if (cs) FcCharSetDestroy (cs);
969 if (ls) FcLangSetDestroy (ls);
970 if (pattern) FcPatternDestroy (pattern);
972 #else /* not HAVE_FONTCONFIG */
973 if (mt && mtext_nchars (mt) > 0)
974 plist = ft_list_char_list (NULL, mt);
975 #endif /* not HAVE_FONTCONFIG */
977 mplist_push (ft_language_list, language, plist);
982 ft_list_script (MSymbol script)
984 MPlist *plist = NULL;
987 if (! ft_script_list)
988 ft_script_list = mplist ();
989 else if ((plist = mplist_find_by_key (ft_script_list, script)))
990 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
992 char_list = mscript__char_list (script);
994 #ifdef HAVE_FONTCONFIG
997 FcPattern *pattern = NULL;
1000 if (! (pattern = FcPatternCreate ()))
1002 cs = fc_build_charset (char_list, NULL);
1003 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1005 plist = fc_list_pattern (pattern);
1007 if (cs) FcCharSetDestroy (cs);
1008 if (pattern) FcPatternDestroy (pattern);
1010 #else /* not HAVE_FONTCONFIG */
1012 plist = ft_list_char_list (char_list, NULL);
1013 #endif /* not HAVE_FONTCONFIG */
1019 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
1022 if (ft_info->otf == invalid_otf)
1026 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1029 ft_info->otf = invalid_otf;
1033 if (cap->features[MFONT_OTT_GSUB].nfeatures
1034 && cap->features[MFONT_OTT_GSUB].tags[0]
1035 && (OTF_check_features
1037 cap->script_tag, cap->langsys_tag,
1038 cap->features[MFONT_OTT_GSUB].tags,
1039 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1041 if (cap->features[MFONT_OTT_GPOS].nfeatures
1042 && cap->features[MFONT_OTT_GPOS].tags[0]
1043 && (OTF_check_features
1045 cap->script_tag, cap->langsys_tag,
1046 cap->features[MFONT_OTT_GPOS].tags,
1047 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1050 #else /* not HAVE_OTF */
1052 #endif /* not HAVE_OTF */
1056 ft_check_language (MFontFT *ft_info, MSymbol language)
1063 #ifdef HAVE_FONTCONFIG
1064 if (ft_info->langset
1065 && (FcLangSetHasLang (ft_info->langset,
1066 (FcChar8 *) MSYMBOL_NAME (language))
1067 != FcLangDifferentLang))
1070 if (! ft_info->charset)
1072 #else /* not HAVE_FONTCONFIG */
1075 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
1077 #endif /* not HAVE_FONTCONFIG */
1079 mt = mlanguage_text (language);
1080 if (! mt || mtext_nchars (mt) == 0)
1083 len = mtext_nchars (mt);
1084 extra = mtext_get_prop (mt, 0, Mtext);
1085 total_len = len + (extra ? mtext_nchars (extra) : 0);
1087 for (i = 0; i < total_len; i++)
1089 int c = (i < len ? mtext_ref_char (mt, i)
1090 : mtext_ref_char (extra, i - len));
1092 #ifdef HAVE_FONTCONFIG
1093 if (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1095 #else /* not HAVE_FONTCONFIG */
1096 if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1098 #endif /* not HAVE_FONTCONFIG */
1101 #ifndef HAVE_FONTCONFIG
1102 FT_Done_Face (ft_face);
1103 #endif /* not HAVE_FONTCONFIG */
1105 return (i == total_len ? 0 : -1);
1109 ft_check_script (MFontFT *ft_info, MSymbol script)
1111 MPlist *char_list = mscript__char_list (script);
1113 #ifdef HAVE_FONTCONFIG
1114 if (! char_list || ! ft_info->charset)
1116 MPLIST_DO (char_list, char_list)
1117 if (FcCharSetHasChar (ft_info->charset,
1118 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1121 #else /* not HAVE_FONTCONFIG */
1125 || FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1129 MPLIST_DO (char_list, char_list)
1130 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list)) == 0)
1132 FT_Done_Face (ft_face);
1133 #endif /* not HAVE_FONTCONFIG */
1135 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1138 static MPlist *ft_default_list;
1143 if (ft_default_list)
1144 return ft_default_list;
1145 ft_default_list = mplist ();
1146 #ifdef HAVE_FONTCONFIG
1148 FcPattern *pat = FcPatternCreate ();
1154 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1155 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1161 STRDUP_LOWER (buf, bufsize, (char *) fam);
1162 family = msymbol (buf);
1163 if (msymbol_get (family, Mgeneric_family))
1165 plist = MPLIST_PLIST (ft_list_family (family, 0));
1166 MPLIST_DO (plist, plist)
1167 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1170 #else /* not HAVE_FONTCONFIG */
1174 MPLIST_DO (plist, ft_list_family (Mnil, 0))
1176 pl = MPLIST_PLIST (plist);
1177 if (! MPLIST_TAIL_P (pl))
1178 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1181 #endif /* not HAVE_FONTCONFIG */
1182 return ft_default_list;
1186 static MPlist *ft_capability_list;
1189 ft_list_capability (MSymbol capability)
1191 MFontCapability *cap;
1192 MPlist *plist = NULL, *pl;
1194 if (! ft_capability_list)
1195 ft_capability_list = mplist ();
1196 else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1197 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1199 cap = mfont__get_capability (capability);
1201 if (cap && cap->language != Mnil)
1203 plist = ft_list_language (cap->language);
1206 plist = mplist_copy (plist);
1209 if (cap && cap->script != Mnil)
1213 plist = ft_list_script (cap->script);
1216 plist = mplist_copy (plist);
1220 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1222 if (ft_check_script (MPLIST_VAL (pl), cap->script) < 0)
1225 pl = MPLIST_NEXT (pl);
1229 if (cap->script_tag)
1231 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1233 if (ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1236 pl = MPLIST_NEXT (pl);
1240 if (MPLIST_TAIL_P (plist))
1242 M17N_OBJECT_UNREF (plist);
1247 mplist_push (ft_capability_list, capability, plist);
1253 ft_list_file (MSymbol filename)
1255 MPlist *plist = NULL;
1258 ft_file_list = mplist ();
1259 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1260 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1262 #ifdef HAVE_FONTCONFIG
1264 FcPattern *pattern = FcPatternCreate ();
1268 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1269 os = FcObjectSetBuild (FC_FAMILY, NULL);
1270 fs = FcFontList (fc_config, pattern, os);
1277 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1278 (FcChar8 **) &fam) == FcResultMatch)
1283 STRDUP_LOWER (buf, bufsize, fam);
1284 family = msymbol (buf);
1285 pl = ft_list_family (family, 0);
1286 MPLIST_DO (pl, MPLIST_PLIST (pl))
1288 MFontFT *ft_info = MPLIST_VAL (pl);
1290 if (ft_info->font.file == filename)
1293 mplist_add (plist, family, ft_info);
1300 #else /* not HAVE_FONTCONFIG */
1304 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1306 MPLIST_DO (p, MPLIST_PLIST (pl))
1308 MFontFT *ft_info = MPLIST_VAL (pl);
1310 if (ft_info->font.file == filename)
1313 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1321 #endif /* not HAVE_FONTCONFIG */
1323 mplist_push (ft_file_list, filename, plist);
1327 /* The FreeType font driver function SELECT. */
1330 ft_select (MFrame *frame, MFont *font, int limited_size)
1332 MFont *found = NULL;
1333 #ifdef HAVE_FONTCONFIG
1336 int check_font_property = 1;
1338 if (font->file != Mnil)
1340 plist = ft_list_file (font->file);
1343 check_font_property = 0;
1347 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1350 plist = MPLIST_PLIST (ft_list_family (family, 1));
1352 plist = ft_list_default ();
1353 if (MPLIST_TAIL_P (plist))
1357 plist = mplist_copy (plist);
1359 if (font->capability != Mnil)
1361 MFontCapability *cap = mfont__get_capability (font->capability);
1363 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1365 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1371 && ft_check_language (MPLIST_VAL (pl), cap->language) < 0)
1374 pl = MPLIST_NEXT (pl);
1378 if (check_font_property)
1380 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1381 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1382 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1383 MSymbol alternate_weight = Mnil;
1385 if (weight == Mnormal)
1386 alternate_weight = Mmedium;
1387 else if (weight == Mmedium)
1388 alternate_weight = Mnormal;
1389 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1390 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1392 ft_info = MPLIST_VAL (pl);
1394 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1395 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1397 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1399 && stretch != FONT_PROPERTY (&ft_info->font,
1402 && ft_info->font.size > 0
1403 && ft_info->font.size != font->size))
1406 pl = MPLIST_NEXT (pl);
1410 MPLIST_DO (pl, plist)
1412 font = MPLIST_VAL (plist);
1413 if (limited_size == 0
1415 || font->size <= limited_size)
1421 M17N_OBJECT_UNREF (plist);
1422 #endif /* HAVE_FONTCONFIG */
1427 static MRealizedFont *
1428 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1430 MFontFT *ft_info = (MFontFT *) font;
1431 int reg = spec->property[MFONT_REGISTRY];
1432 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1433 MRealizedFontFT *ft_rfont;
1435 MPlist *plist, *charmap_list = NULL;
1440 /* non-scalable font */
1442 else if (spec->size)
1444 int ratio = mfont_resize_ratio (font);
1446 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1453 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1454 for (; rfont; rfont = rfont->next)
1455 if (rfont->font == font
1456 && (rfont->font->size ? rfont->font->size == size
1457 : rfont->spec.size == size)
1458 && rfont->spec.property[MFONT_REGISTRY] == reg
1459 && rfont->driver == &mfont__ft_driver)
1463 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1465 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1468 font->type = MFONT_TYPE_FAILURE;
1469 MDEBUG_PRINT (" no (FT_New_Face)\n");
1473 M17N_OBJECT_REF (charmap_list);
1475 charmap_list = ft_get_charmaps (ft_face);
1476 if (registry == Mnil)
1477 registry = Municode_bmp;
1478 plist = mplist_find_by_key (charmap_list, registry);
1481 FT_Done_Face (ft_face);
1482 M17N_OBJECT_UNREF (charmap_list);
1483 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1486 charmap_index = (int) MPLIST_VAL (plist);
1487 if ((charmap_index >= 0
1488 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1489 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1491 FT_Done_Face (ft_face);
1492 M17N_OBJECT_UNREF (charmap_list);
1493 font->type = MFONT_TYPE_FAILURE;
1494 MDEBUG_PRINT1 (" no (size %d)\n", size);
1498 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1499 ft_rfont->ft_face = ft_face;
1500 ft_rfont->charmap_list = charmap_list;
1501 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1502 rfont->spec = *font;
1503 rfont->spec.type = MFONT_TYPE_REALIZED;
1504 rfont->spec.property[MFONT_REGISTRY] = reg;
1505 rfont->spec.size = size;
1506 rfont->frame = frame;
1508 rfont->driver = &mfont__ft_driver;
1509 rfont->info = ft_rfont;
1510 rfont->fontp = ft_face;
1511 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1512 rfont->descent = - ft_face->size->metrics.descender >> 6;
1513 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1514 rfont->baseline_offset = 0;
1517 BDF_PropertyRec prop;
1519 if (! FT_IS_SCALABLE (ft_face)
1520 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1522 rfont->baseline_offset = prop.u.integer;
1523 rfont->ascent += prop.u.integer;
1524 rfont->descent -= prop.u.integer;
1527 #endif /* HAVE_FTBDF_H */
1528 if (FT_IS_SCALABLE (ft_face))
1529 rfont->average_width = 0;
1531 rfont->average_width = ft_face->available_sizes->width;
1532 rfont->next = MPLIST_VAL (frame->realized_font_list);
1533 MPLIST_VAL (frame->realized_font_list) = rfont;
1534 MDEBUG_PRINT (" ok\n");
1538 /* The FreeType font driver function FIND_METRIC. */
1541 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1544 FT_Face ft_face = rfont->fontp;
1545 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1547 for (; g != gend; g++)
1549 if (g->code == MCHAR_INVALID_CODE)
1551 if (FT_IS_SCALABLE (ft_face))
1553 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1554 int size = rfont->spec.size;
1557 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1558 g->width = g->rbearing;
1559 g->ascent = ft_face->ascender * size / unitsPerEm10;
1560 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1565 BDF_PropertyRec prop;
1566 #endif /* HAVE_FTBDF_H */
1569 g->rbearing = g->width = ft_face->available_sizes->width;
1571 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1573 g->ascent = prop.u.integer;
1574 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1575 g->descent = prop.u.integer;
1576 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1579 g->ascent += prop.u.integer;
1580 g->descent -= prop.u.integer;
1584 #endif /* HAVE_FTBDF_H */
1586 g->ascent = ft_face->available_sizes->height;
1593 FT_Glyph_Metrics *metrics;
1595 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1596 metrics = &ft_face->glyph->metrics;
1597 g->lbearing = (metrics->horiBearingX >> 6);
1598 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1599 g->width = metrics->horiAdvance >> 6;
1600 g->ascent = metrics->horiBearingY >> 6;
1601 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1603 g->ascent += rfont->baseline_offset;
1604 g->descent -= rfont->baseline_offset;
1609 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1611 MRealizedFont *rfont = NULL;
1612 MRealizedFontFT *ft_rfont;
1615 if (font->type == MFONT_TYPE_REALIZED)
1616 rfont = (MRealizedFont *) font;
1617 else if (font->type == MFONT_TYPE_OBJECT)
1619 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1620 rfont = rfont->next)
1621 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1625 #ifdef HAVE_FONTCONFIG
1626 MFontFT *ft_info = (MFontFT *) font;
1628 if (! ft_info->charset)
1630 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1631 MSYMBOL_NAME (font->file),
1633 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1634 FcFontSet *fs = FcFontList (fc_config, pat, os);
1637 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1638 &ft_info->charset) == FcResultMatch)
1639 ft_info->charset = FcCharSetCopy (ft_info->charset);
1641 ft_info->charset = FcCharSetCreate ();
1642 FcFontSetDestroy (fs);
1643 FcObjectSetDestroy (os);
1644 FcPatternDestroy (pat);
1646 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1647 #else /* not HAVE_FONTCONFIG */
1648 rfont = ft_open (frame, font, spec, NULL);
1649 #endif /* not HAVE_FONTCONFIG */
1653 MFATAL (MERROR_FONT_FT);
1657 ft_rfont = rfont->info;
1658 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1662 /* The FreeType font driver function ENCODE_CHAR. */
1665 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1667 MRealizedFont *rfont;
1668 MRealizedFontFT *ft_rfont;
1671 if (font->type == MFONT_TYPE_REALIZED)
1672 rfont = (MRealizedFont *) font;
1673 else if (font->type == MFONT_TYPE_OBJECT)
1675 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1676 rfont = rfont->next)
1677 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1681 rfont = ft_open (frame, font, spec, NULL);
1687 MFATAL (MERROR_FONT_FT);
1689 ft_rfont = rfont->info;
1690 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1691 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1694 /* The FreeType font driver function RENDER. */
1696 #define NUM_POINTS 0x1000
1699 MDrawPoint points[NUM_POINTS];
1704 ft_render (MDrawWindow win, int x, int y,
1705 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1706 int reverse, MDrawRegion region)
1709 MRealizedFace *rface = from->rface;
1710 MFrame *frame = rface->frame;
1711 FT_Int32 load_flags = FT_LOAD_RENDER;
1714 MPointTable point_table[8];
1715 int baseline_offset;
1720 /* It is assured that the all glyphs in the current range use the
1721 same realized face. */
1722 ft_face = rface->rfont->fontp;
1723 baseline_offset = rface->rfont->baseline_offset;
1725 if (! gstring->anti_alias)
1727 #ifdef FT_LOAD_TARGET_MONO
1728 load_flags |= FT_LOAD_TARGET_MONO;
1730 load_flags |= FT_LOAD_MONOCHROME;
1734 for (i = 0; i < 8; i++)
1735 point_table[i].p = point_table[i].points;
1737 for (g = from; g < to; x += g++->width)
1741 MPointTable *ptable;
1745 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1746 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1747 bmp = ft_face->glyph->bitmap.buffer;
1748 width = ft_face->glyph->bitmap.width;
1749 pitch = ft_face->glyph->bitmap.pitch;
1750 if (! gstring->anti_alias)
1755 if (gstring->anti_alias)
1756 for (i = 0; i < ft_face->glyph->bitmap.rows;
1757 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1759 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1760 for (j = 0; j < width; j++, xoff++)
1762 intensity = bmp[j] >> 5;
1765 ptable = point_table + intensity;
1766 ptable->p->x = xoff;
1767 ptable->p->y = yoff - baseline_offset;
1769 if (ptable->p - ptable->points == NUM_POINTS)
1771 (*frame->driver->draw_points)
1773 reverse ? 7 - intensity : intensity,
1774 ptable->points, NUM_POINTS, region);
1775 ptable->p = ptable->points;
1781 for (i = 0; i < ft_face->glyph->bitmap.rows;
1782 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1784 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1785 for (j = 0; j < width; j++, xoff++)
1787 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1790 ptable = point_table;
1791 ptable->p->x = xoff;
1792 ptable->p->y = yoff - baseline_offset;
1794 if (ptable->p - ptable->points == NUM_POINTS)
1796 (*frame->driver->draw_points) (frame, win, rface,
1798 ptable->points, NUM_POINTS, region);
1799 ptable->p = ptable->points;
1806 if (gstring->anti_alias)
1808 for (i = 1; i < 8; i++)
1809 if (point_table[i].p != point_table[i].points)
1810 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1811 point_table[i].points,
1812 point_table[i].p - point_table[i].points, region);
1816 if (point_table[0].p != point_table[0].points)
1817 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1818 point_table[0].points,
1819 point_table[0].p - point_table[0].points, region);
1824 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1826 MPlist *pl = NULL, *p;
1828 MPlist *file_list = NULL;
1829 MPlist *family_list = NULL, *capability_list = NULL;
1830 MSymbol registry = Mnil;
1832 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1838 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1839 if (registry != Mnil && registry != Miso8859_1)
1841 char *reg = MSYMBOL_NAME (registry);
1843 if (strncmp (reg, "unicode-", 8)
1844 && strncmp (reg, "apple-roman", 11)
1845 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1849 if (font->file != Mnil
1850 && ! (file_list = ft_list_file (font->file)))
1852 family = FONT_PROPERTY (font, MFONT_FAMILY);
1854 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1855 && MPLIST_TAIL_P (family_list))
1857 if (font->capability != Mnil)
1859 capability_list = ft_list_capability (font->capability);
1860 if (! capability_list || MPLIST_TAIL_P (capability_list))
1865 if (! file_list && ! family_list && ! capability_list)
1867 /* No restriction. Get all fonts. */
1869 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1871 MPLIST_DO (p, MPLIST_PLIST (family_list))
1872 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1880 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1885 for (p = pl; ! MPLIST_TAIL_P (p);)
1887 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1888 p = MPLIST_NEXT (p);
1895 MPLIST_DO (p, family_list)
1896 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1899 if (capability_list)
1902 for (p = pl; ! MPLIST_TAIL_P (p);)
1904 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1905 p = MPLIST_NEXT (p);
1912 MPLIST_DO (p, capability_list)
1913 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1919 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1920 + font->property[MFONT_STRETCH] + font->size) > 0)
1922 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1923 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1924 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1925 int size = font->size;
1927 for (p = pl; ! MPLIST_TAIL_P (p); )
1929 MFontFT *ft_info = MPLIST_VAL (p);
1932 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1934 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1936 && stretch != FONT_PROPERTY (&ft_info->font,
1939 && ft_info->font.size > 0
1940 && ft_info->font.size != size))
1943 p = MPLIST_NEXT (p);
1949 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1951 if (maxnum && maxnum <= num)
1954 M17N_OBJECT_UNREF (pl);
1957 MDEBUG_PRINT1 (" %d found\n", num);
1962 ft_list_family_names (MFrame *frame, MPlist *plist)
1968 #ifdef HAVE_FONTCONFIG
1969 fc_init_font_list ();
1970 #else /* not HAVE_FONTCONFIG */
1971 ft_init_font_list ();
1972 #endif /* not HAVE_FONTCONFIG */
1975 MPLIST_DO (pl, ft_font_list)
1977 MSymbol family = MPLIST_KEY (pl);
1980 #ifdef HAVE_FONTCONFIG
1981 if (msymbol_get (family, Mgeneric_family) != Mnil)
1983 #endif /* HAVE_FONTCONFIG */
1984 MPLIST_DO (p, plist)
1986 MSymbol sym = MPLIST_SYMBOL (p);
1990 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
1992 mplist_push (p, Msymbol, family);
1996 if (MPLIST_TAIL_P (p))
1997 mplist_push (p, Msymbol, family);
2002 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2004 MFontFT *ft_info = (MFontFT *) rfont->font;
2005 MFontCapability *cap = mfont__get_capability (capability);
2007 if (cap->script != Mnil
2008 && ft_check_script (ft_info, cap->script) < 0)
2010 if (cap->language != Mnil
2011 && ft_check_language (ft_info, cap->language) < 0)
2013 if (cap->script_tag && ft_check_otf (ft_info, cap) < 0)
2022 MFontDriver mfont__ft_driver =
2023 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2024 ft_render, ft_list, ft_list_family_names, ft_check_capability};
2031 if (FT_Init_FreeType (&ft_library) != 0)
2032 MERROR (MERROR_FONT_FT, -1);
2034 for (i = 0; i < ft_to_prop_size; i++)
2035 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2037 Mmedium = msymbol ("medium");
2039 Mnull = msymbol ("");
2041 M0[0] = msymbol ("0-0");
2042 M0[1] = msymbol ("0-1");
2043 M0[2] = msymbol ("0-2");
2044 M0[3] = msymbol ("0-3");
2045 M0[4] = msymbol ("0-4");
2046 M3_1 = msymbol ("3-1");
2047 M1_0 = msymbol ("1-0");
2049 #ifdef HAVE_FONTCONFIG
2050 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2052 FC_vs_M17N_font_prop *table = fc_all_table[i];
2055 for (j = 0; table[j].m17n_value; j++)
2056 table[j].sym = msymbol (table[j].m17n_value);
2057 table[j].sym = table[j - 1].sym;
2064 MSymbol serif, sans_serif, monospace;
2066 fc_config = FcInitLoadConfigAndFonts ();
2067 if (mfont_freetype_path)
2069 MPLIST_DO (plist, mfont_freetype_path)
2070 if (MPLIST_STRING_P (plist)
2071 && (pathname = MPLIST_STRING (plist))
2072 && stat (pathname, &buf) == 0)
2074 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2077 while ((dir = FcStrListNext (strlist)))
2078 if (strcmp ((char *) dir, pathname) == 0)
2081 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2082 FcStrListDone (strlist);
2085 Mgeneric_family = msymbol ("generic famly");
2086 serif = msymbol ("serif");
2087 msymbol_put (serif, Mgeneric_family, serif);
2088 sans_serif = msymbol ("sans-serif");
2089 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2090 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2091 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2092 monospace = msymbol ("monospace");
2093 msymbol_put (monospace, Mgeneric_family, monospace);
2094 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2106 if (ft_default_list)
2108 M17N_OBJECT_UNREF (ft_default_list);
2109 ft_default_list = NULL;
2114 MPLIST_DO (plist, ft_font_list)
2116 if (MPLIST_VAL (plist))
2117 MPLIST_DO (p, MPLIST_VAL (plist))
2119 if (MPLIST_KEY (p) != Mt)
2120 free_ft_info (MPLIST_VAL (p));
2122 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2124 M17N_OBJECT_UNREF (ft_font_list);
2125 ft_font_list = NULL;
2127 if (ft_language_list)
2129 MPLIST_DO (plist, ft_language_list)
2130 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2131 M17N_OBJECT_UNREF (ft_language_list);
2132 ft_language_list = NULL;
2137 MPLIST_DO (plist, ft_script_list)
2138 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2139 M17N_OBJECT_UNREF (ft_script_list);
2140 ft_script_list = NULL;
2143 if (ft_capability_list)
2145 MPLIST_DO (plist, ft_capability_list)
2146 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2147 M17N_OBJECT_UNREF (ft_capability_list);
2148 ft_capability_list = NULL;
2153 MPLIST_DO (plist, ft_file_list)
2154 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2155 M17N_OBJECT_UNREF (ft_file_list);
2156 ft_file_list = NULL;
2159 FT_Done_FreeType (ft_library);
2160 #ifdef HAVE_FONTCONFIG
2161 FcConfigDestroy (fc_config);
2163 #endif /* HAVE_FONTCONFIG */
2164 all_fonts_scaned = 0;
2167 #ifdef HAVE_FONTCONFIG
2170 mfont__ft_parse_name (const char *name, MFont *font)
2172 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2181 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2183 STRDUP_LOWER (buf, bufsize, (char *) str);
2184 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2186 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2188 STRDUP_LOWER (buf, bufsize, (char *) str);
2189 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2191 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2192 mfont__set_property (font, MFONT_WEIGHT,
2193 fc_decode_prop (val, fc_weight_table,
2194 fc_weight_table_size));
2195 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2196 mfont__set_property (font, MFONT_STYLE,
2197 fc_decode_prop (val, fc_slant_table,
2198 fc_slant_table_size));
2199 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2200 mfont__set_property (font, MFONT_STRETCH,
2201 fc_decode_prop (val, fc_width_table,
2202 fc_width_table_size));
2203 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2204 font->size = size * 10 + 0.5;
2205 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2206 font->size = - (size * 10 + 0.5);
2207 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2209 font->file = msymbol ((char *) str);
2211 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2212 font->type = MFONT_TYPE_SPEC;
2213 FcPatternDestroy (pat);
2218 mfont__ft_unparse_name (MFont *font)
2220 FcPattern *pat = fc_get_pattern (font);
2221 char *name = (char *) FcNameUnparse (pat);
2223 FcPatternDestroy (pat);
2226 #endif /* HAVE_FONTCONFIG */
2231 #define DEVICE_DELTA(table, size) \
2232 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2233 ? (table).DeltaValue[(size) - (table).StartSize] \
2237 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2238 unsigned code, int size, int *x, int *y)
2240 if (anchor->AnchorFormat == 2)
2242 FT_Outline *outline;
2243 int ap = anchor->f.f1.AnchorPoint;
2245 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2246 outline = &ft_face->glyph->outline;
2247 if (ap < outline->n_points)
2249 *x = outline->points[ap].x;
2250 *y = outline->points[ap].y;
2253 else if (anchor->AnchorFormat == 3)
2255 if (anchor->f.f2.XDeviceTable.offset)
2256 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2257 if (anchor->f.f2.YDeviceTable.offset)
2258 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2263 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2264 MFontCapability *cap)
2266 int len = to - from;
2267 MGlyph *g = MGLYPH (from);
2269 MRealizedFont *rfont;
2272 OTF_GlyphString otf_gstring;
2274 char *script, *langsys;
2275 char *gsub_features, *gpos_features;
2281 otf_gstring.glyphs = NULL;
2282 rfont = g->rface->rfont;
2283 ft_info = (MFontFT *) rfont->font;
2284 if (ft_info->otf == invalid_otf)
2289 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2292 ft_info->otf = invalid_otf;
2297 if (OTF_get_table (otf, "head") < 0)
2300 ft_info->otf = invalid_otf;
2304 if (cap->script_tag)
2306 script = alloca (5);
2307 OTF_tag_name (cap->script_tag, script);
2311 if (cap->langsys_tag)
2313 langsys = alloca (5);
2314 OTF_tag_name (cap->langsys_tag, langsys);
2318 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2319 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2320 gsub_features = NULL;
2321 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2322 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2323 gpos_features = NULL;
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, need_cmap = 0; i < len; i++)
2330 if (gstring->glyphs[from + i].otf_encoded)
2332 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2333 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2337 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2342 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2345 OTF_drive_gdef (otf, &otf_gstring);
2346 gidx = gstring->used;
2350 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2353 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2355 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2358 temp.combining_code = 0;
2361 temp.code = otfg->glyph_id;
2362 temp.otf_encoded = 1;
2367 temp.otf_encoded = 0;
2369 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2370 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2374 for (i = 0; i < len; i++)
2376 MGlyph temp = gstring->glyphs[from + i];
2378 if (otf_gstring.glyphs[i].glyph_id)
2380 temp.code = otf_gstring.glyphs[i].glyph_id;
2381 temp.otf_encoded = 1;
2383 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2386 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2392 MGlyph *base = NULL, *mark = NULL;
2394 if (OTF_check_features (otf, 1,
2395 cap->script_tag, cap->langsys_tag,
2396 cap->features[MFONT_OTT_GPOS].tags,
2397 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2398 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2399 gpos_features) < 0))
2402 u = otf->head->unitsPerEm;
2403 size10 = rfont->spec.size;
2406 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2407 i < otf_gstring.used; i++, otfg++, g++)
2411 if (! otfg->glyph_id)
2413 switch (otfg->positioning_type)
2419 int format = otfg->f.f1.format;
2421 if (format & OTF_XPlacement)
2422 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2423 if (format & OTF_XPlaDevice)
2424 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2425 if (format & OTF_YPlacement)
2426 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2427 if (format & OTF_YPlaDevice)
2428 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2429 if (format & OTF_XAdvance)
2430 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2431 if (format & OTF_XAdvDevice)
2432 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2436 /* Not yet supported. */
2442 goto label_adjust_anchor;
2443 default: /* i.e. case 6 */
2448 label_adjust_anchor:
2450 int base_x, base_y, mark_x, mark_y;
2452 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2453 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2454 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2455 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2457 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2458 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2459 prev->code, size, &base_x, &base_y);
2460 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2461 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2462 g->code, size, &mark_x, &mark_y);
2463 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2464 g->yoff = prev->yoff + mark_y - base_y;
2465 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2468 if (otfg->GlyphClass == OTF_GlyphClass0)
2470 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2476 free (otf_gstring.glyphs);
2480 ft_find_metric (rfont, gstring, from, to);
2481 for (i = 0; i < len; i++)
2483 MGlyph temp = gstring->glyphs[from + i];
2484 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2486 if (otf_gstring.glyphs)
2487 free (otf_gstring.glyphs);
2493 mfont__ft_decode_otf (MGlyph *g)
2495 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2496 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2498 return (c ? c : -1);
2501 #endif /* HAVE_OTF */
2503 #endif /* HAVE_FREETYPE */