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);
1114 #ifdef HAVE_FONTCONFIG
1115 if (! char_list || ! ft_info->charset)
1117 MPLIST_DO (char_list, char_list)
1118 if (FcCharSetHasChar (ft_info->charset,
1119 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1122 #else /* not HAVE_FONTCONFIG */
1126 || FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1130 MPLIST_DO (char_list, char_list)
1131 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list)) == 0)
1133 FT_Done_Face (ft_face);
1134 #endif /* not HAVE_FONTCONFIG */
1136 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1139 static MPlist *ft_default_list;
1144 if (ft_default_list)
1145 return ft_default_list;
1146 ft_default_list = mplist ();
1147 #ifdef HAVE_FONTCONFIG
1149 FcPattern *pat = FcPatternCreate ();
1155 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1156 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1162 STRDUP_LOWER (buf, bufsize, (char *) fam);
1163 family = msymbol (buf);
1164 if (msymbol_get (family, Mgeneric_family))
1166 plist = MPLIST_PLIST (ft_list_family (family, 0));
1167 MPLIST_DO (plist, plist)
1168 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1171 #else /* not HAVE_FONTCONFIG */
1175 MPLIST_DO (plist, ft_list_family (Mnil, 0))
1177 pl = MPLIST_PLIST (plist);
1178 if (! MPLIST_TAIL_P (pl))
1179 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1182 #endif /* not HAVE_FONTCONFIG */
1183 return ft_default_list;
1187 static MPlist *ft_capability_list;
1190 ft_list_capability (MSymbol capability)
1192 MFontCapability *cap;
1193 MPlist *plist = NULL, *pl, *p;
1195 if (! ft_capability_list)
1196 ft_capability_list = mplist ();
1197 else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1198 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1200 cap = mfont__get_capability (capability);
1202 if (cap && cap->language != Mnil)
1204 plist = ft_list_language (cap->language);
1207 plist = mplist_copy (plist);
1210 if (cap && cap->script != Mnil)
1214 plist = ft_list_script (cap->script);
1217 plist = mplist_copy (plist);
1221 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1223 if (ft_check_script (MPLIST_VAL (pl), cap->script) < 0)
1226 pl = MPLIST_NEXT (pl);
1230 if (cap->script_tag)
1232 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1234 if (ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1237 pl = MPLIST_NEXT (pl);
1241 if (MPLIST_TAIL_P (plist))
1243 M17N_OBJECT_UNREF (plist);
1248 mplist_push (ft_capability_list, capability, plist);
1254 ft_list_file (MSymbol filename)
1256 MPlist *plist = NULL;
1259 ft_file_list = mplist ();
1260 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1261 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1263 #ifdef HAVE_FONTCONFIG
1265 FcPattern *pattern = FcPatternCreate ();
1269 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1270 os = FcObjectSetBuild (FC_FAMILY, NULL);
1271 fs = FcFontList (fc_config, pattern, os);
1278 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1279 (FcChar8 **) &fam) == FcResultMatch)
1284 STRDUP_LOWER (buf, bufsize, fam);
1285 family = msymbol (buf);
1286 pl = ft_list_family (family, 0);
1287 MPLIST_DO (pl, MPLIST_PLIST (pl))
1289 MFontFT *ft_info = MPLIST_VAL (pl);
1291 if (ft_info->font.file == filename)
1294 mplist_add (plist, family, ft_info);
1301 #else /* not HAVE_FONTCONFIG */
1305 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1307 MPLIST_DO (p, MPLIST_PLIST (pl))
1309 MFontFT *ft_info = MPLIST_VAL (pl);
1311 if (ft_info->font.file == filename)
1314 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1322 #endif /* not HAVE_FONTCONFIG */
1324 mplist_push (ft_file_list, filename, plist);
1328 /* The FreeType font driver function SELECT. */
1331 ft_select (MFrame *frame, MFont *font, int limited_size)
1333 MFont *found = NULL;
1334 #ifdef HAVE_FONTCONFIG
1337 int check_font_property = 1;
1339 if (font->file != Mnil)
1341 plist = ft_list_file (font->file);
1344 check_font_property = 0;
1348 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1351 plist = MPLIST_PLIST (ft_list_family (family, 1));
1353 plist = ft_list_default ();
1354 if (MPLIST_TAIL_P (plist))
1358 plist = mplist_copy (plist);
1360 if (font->capability != Mnil)
1362 MFontCapability *cap = mfont__get_capability (font->capability);
1364 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1366 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1372 && ft_check_language (MPLIST_VAL (pl), cap->language) < 0)
1375 pl = MPLIST_NEXT (pl);
1379 if (check_font_property)
1381 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1382 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1383 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1384 MSymbol alternate_weight = Mnil;
1386 if (weight == Mnormal)
1387 alternate_weight = Mmedium;
1388 else if (weight == Mmedium)
1389 alternate_weight = Mnormal;
1390 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1391 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1393 ft_info = MPLIST_VAL (pl);
1395 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1396 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1398 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1400 && stretch != FONT_PROPERTY (&ft_info->font,
1403 && ft_info->font.size > 0
1404 && ft_info->font.size != font->size))
1407 pl = MPLIST_NEXT (pl);
1411 MPLIST_DO (pl, plist)
1413 font = MPLIST_VAL (plist);
1414 if (limited_size == 0
1416 || font->size <= limited_size)
1422 M17N_OBJECT_UNREF (plist);
1423 #endif /* HAVE_FONTCONFIG */
1428 static MRealizedFont *
1429 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1431 MFontFT *ft_info = (MFontFT *) font;
1432 int reg = spec->property[MFONT_REGISTRY];
1433 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1434 MRealizedFontFT *ft_rfont;
1436 MPlist *plist, *charmap_list = NULL;
1441 /* non-scalable font */
1443 else if (spec->size)
1445 int ratio = mfont_resize_ratio (font);
1447 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1454 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1455 for (; rfont; rfont = rfont->next)
1456 if (rfont->font == font
1457 && (rfont->font->size ? rfont->font->size == size
1458 : rfont->spec.size == size)
1459 && rfont->spec.property[MFONT_REGISTRY] == reg
1460 && rfont->driver == &mfont__ft_driver)
1464 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1466 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1469 font->type = MFONT_TYPE_FAILURE;
1470 MDEBUG_PRINT (" no (FT_New_Face)\n");
1474 M17N_OBJECT_REF (charmap_list);
1476 charmap_list = ft_get_charmaps (ft_face);
1477 if (registry == Mnil)
1478 registry = Municode_bmp;
1479 plist = mplist_find_by_key (charmap_list, registry);
1482 FT_Done_Face (ft_face);
1483 M17N_OBJECT_UNREF (charmap_list);
1484 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1487 charmap_index = (int) MPLIST_VAL (plist);
1488 if ((charmap_index >= 0
1489 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1490 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1492 FT_Done_Face (ft_face);
1493 M17N_OBJECT_UNREF (charmap_list);
1494 font->type = MFONT_TYPE_FAILURE;
1495 MDEBUG_PRINT1 (" no (size %d)\n", size);
1499 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1500 ft_rfont->ft_face = ft_face;
1501 ft_rfont->charmap_list = charmap_list;
1502 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1503 rfont->spec = *font;
1504 rfont->spec.type = MFONT_TYPE_REALIZED;
1505 rfont->spec.property[MFONT_REGISTRY] = reg;
1506 rfont->spec.size = size;
1507 rfont->frame = frame;
1509 rfont->driver = &mfont__ft_driver;
1510 rfont->info = ft_rfont;
1511 rfont->fontp = ft_face;
1512 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1513 rfont->descent = - ft_face->size->metrics.descender >> 6;
1514 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1515 rfont->baseline_offset = 0;
1518 BDF_PropertyRec prop;
1520 if (! FT_IS_SCALABLE (ft_face)
1521 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1523 rfont->baseline_offset = prop.u.integer;
1524 rfont->ascent += prop.u.integer;
1525 rfont->descent -= prop.u.integer;
1528 #endif /* HAVE_FTBDF_H */
1529 if (FT_IS_SCALABLE (ft_face))
1530 rfont->average_width = 0;
1532 rfont->average_width = ft_face->available_sizes->width;
1533 rfont->next = MPLIST_VAL (frame->realized_font_list);
1534 MPLIST_VAL (frame->realized_font_list) = rfont;
1535 MDEBUG_PRINT (" ok\n");
1539 /* The FreeType font driver function FIND_METRIC. */
1542 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1545 FT_Face ft_face = rfont->fontp;
1546 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1548 for (; g != gend; g++)
1550 if (g->code == MCHAR_INVALID_CODE)
1552 if (FT_IS_SCALABLE (ft_face))
1554 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1555 int size = rfont->spec.size;
1558 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1559 g->width = g->rbearing;
1560 g->ascent = ft_face->ascender * size / unitsPerEm10;
1561 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1566 BDF_PropertyRec prop;
1567 #endif /* HAVE_FTBDF_H */
1570 g->rbearing = g->width = ft_face->available_sizes->width;
1572 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1574 g->ascent = prop.u.integer;
1575 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1576 g->descent = prop.u.integer;
1577 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1580 g->ascent += prop.u.integer;
1581 g->descent -= prop.u.integer;
1585 #endif /* HAVE_FTBDF_H */
1587 g->ascent = ft_face->available_sizes->height;
1594 FT_Glyph_Metrics *metrics;
1596 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1597 metrics = &ft_face->glyph->metrics;
1598 g->lbearing = (metrics->horiBearingX >> 6);
1599 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1600 g->width = metrics->horiAdvance >> 6;
1601 g->ascent = metrics->horiBearingY >> 6;
1602 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1604 g->ascent += rfont->baseline_offset;
1605 g->descent -= rfont->baseline_offset;
1610 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1612 MRealizedFont *rfont = NULL;
1613 MRealizedFontFT *ft_rfont;
1616 if (font->type == MFONT_TYPE_REALIZED)
1617 rfont = (MRealizedFont *) font;
1618 else if (font->type == MFONT_TYPE_OBJECT)
1620 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1621 rfont = rfont->next)
1622 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1626 #ifdef HAVE_FONTCONFIG
1627 MFontFT *ft_info = (MFontFT *) font;
1629 if (! ft_info->charset)
1631 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1632 MSYMBOL_NAME (font->file),
1634 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1635 FcFontSet *fs = FcFontList (fc_config, pat, os);
1638 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1639 &ft_info->charset) == FcResultMatch)
1640 ft_info->charset = FcCharSetCopy (ft_info->charset);
1642 ft_info->charset = FcCharSetCreate ();
1643 FcFontSetDestroy (fs);
1644 FcObjectSetDestroy (os);
1645 FcPatternDestroy (pat);
1647 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1648 #else /* not HAVE_FONTCONFIG */
1649 rfont = ft_open (frame, font, spec, NULL);
1650 #endif /* not HAVE_FONTCONFIG */
1654 MFATAL (MERROR_FONT_FT);
1658 ft_rfont = rfont->info;
1659 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1663 /* The FreeType font driver function ENCODE_CHAR. */
1666 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1668 MRealizedFont *rfont;
1669 MRealizedFontFT *ft_rfont;
1672 if (font->type == MFONT_TYPE_REALIZED)
1673 rfont = (MRealizedFont *) font;
1674 else if (font->type == MFONT_TYPE_OBJECT)
1676 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1677 rfont = rfont->next)
1678 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1682 rfont = ft_open (frame, font, spec, NULL);
1688 MFATAL (MERROR_FONT_FT);
1690 ft_rfont = rfont->info;
1691 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1692 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1695 /* The FreeType font driver function RENDER. */
1697 #define NUM_POINTS 0x1000
1700 MDrawPoint points[NUM_POINTS];
1705 ft_render (MDrawWindow win, int x, int y,
1706 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1707 int reverse, MDrawRegion region)
1710 MRealizedFace *rface = from->rface;
1711 MFrame *frame = rface->frame;
1712 FT_Int32 load_flags = FT_LOAD_RENDER;
1715 MPointTable point_table[8];
1716 int baseline_offset;
1721 /* It is assured that the all glyphs in the current range use the
1722 same realized face. */
1723 ft_face = rface->rfont->fontp;
1724 baseline_offset = rface->rfont->baseline_offset;
1726 if (! gstring->anti_alias)
1728 #ifdef FT_LOAD_TARGET_MONO
1729 load_flags |= FT_LOAD_TARGET_MONO;
1731 load_flags |= FT_LOAD_MONOCHROME;
1735 for (i = 0; i < 8; i++)
1736 point_table[i].p = point_table[i].points;
1738 for (g = from; g < to; x += g++->width)
1742 MPointTable *ptable;
1746 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1747 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1748 bmp = ft_face->glyph->bitmap.buffer;
1749 width = ft_face->glyph->bitmap.width;
1750 pitch = ft_face->glyph->bitmap.pitch;
1751 if (! gstring->anti_alias)
1756 if (gstring->anti_alias)
1757 for (i = 0; i < ft_face->glyph->bitmap.rows;
1758 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1760 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1761 for (j = 0; j < width; j++, xoff++)
1763 intensity = bmp[j] >> 5;
1766 ptable = point_table + intensity;
1767 ptable->p->x = xoff;
1768 ptable->p->y = yoff - baseline_offset;
1770 if (ptable->p - ptable->points == NUM_POINTS)
1772 (*frame->driver->draw_points)
1774 reverse ? 7 - intensity : intensity,
1775 ptable->points, NUM_POINTS, region);
1776 ptable->p = ptable->points;
1782 for (i = 0; i < ft_face->glyph->bitmap.rows;
1783 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1785 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1786 for (j = 0; j < width; j++, xoff++)
1788 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1791 ptable = point_table;
1792 ptable->p->x = xoff;
1793 ptable->p->y = yoff - baseline_offset;
1795 if (ptable->p - ptable->points == NUM_POINTS)
1797 (*frame->driver->draw_points) (frame, win, rface,
1799 ptable->points, NUM_POINTS, region);
1800 ptable->p = ptable->points;
1807 if (gstring->anti_alias)
1809 for (i = 1; i < 8; i++)
1810 if (point_table[i].p != point_table[i].points)
1811 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1812 point_table[i].points,
1813 point_table[i].p - point_table[i].points, region);
1817 if (point_table[0].p != point_table[0].points)
1818 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1819 point_table[0].points,
1820 point_table[0].p - point_table[0].points, region);
1825 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1827 MPlist *pl = NULL, *p;
1829 MPlist *file_list = NULL;
1830 MPlist *family_list = NULL, *capability_list = NULL;
1831 MSymbol registry = Mnil;
1833 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1839 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1840 if (registry != Mnil && registry != Miso8859_1)
1842 char *reg = MSYMBOL_NAME (registry);
1844 if (strncmp (reg, "unicode-", 8)
1845 && strncmp (reg, "apple-roman", 11)
1846 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1850 if (font->file != Mnil
1851 && ! (file_list = ft_list_file (font->file)))
1853 family = FONT_PROPERTY (font, MFONT_FAMILY);
1855 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1856 && MPLIST_TAIL_P (family_list))
1858 if (font->capability != Mnil)
1860 capability_list = ft_list_capability (font->capability);
1861 if (! capability_list || MPLIST_TAIL_P (capability_list))
1866 if (! file_list && ! family_list && ! capability_list)
1868 /* No restriction. Get all fonts. */
1870 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1872 MPLIST_DO (p, MPLIST_PLIST (family_list))
1873 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1881 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1886 for (p = pl; ! MPLIST_TAIL_P (p);)
1888 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1889 p = MPLIST_NEXT (p);
1896 MPLIST_DO (p, family_list)
1897 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1900 if (capability_list)
1903 for (p = pl; ! MPLIST_TAIL_P (p);)
1905 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1906 p = MPLIST_NEXT (p);
1913 MPLIST_DO (p, capability_list)
1914 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1920 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1921 + font->property[MFONT_STRETCH] + font->size) > 0)
1923 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1924 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1925 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1926 int size = font->size;
1928 for (p = pl; ! MPLIST_TAIL_P (p); )
1930 MFontFT *ft_info = MPLIST_VAL (p);
1933 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1935 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1937 && stretch != FONT_PROPERTY (&ft_info->font,
1940 && ft_info->font.size > 0
1941 && ft_info->font.size != size))
1944 p = MPLIST_NEXT (p);
1950 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1952 if (maxnum && maxnum <= num)
1955 M17N_OBJECT_UNREF (pl);
1958 MDEBUG_PRINT1 (" %d found\n", num);
1963 ft_list_family_names (MFrame *frame, MPlist *plist)
1969 #ifdef HAVE_FONTCONFIG
1970 fc_init_font_list ();
1971 #else /* not HAVE_FONTCONFIG */
1972 ft_init_font_list ();
1973 #endif /* not HAVE_FONTCONFIG */
1976 MPLIST_DO (pl, ft_font_list)
1978 MSymbol family = MPLIST_KEY (pl);
1981 #ifdef HAVE_FONTCONFIG
1982 if (msymbol_get (family, Mgeneric_family) != Mnil)
1984 #endif /* HAVE_FONTCONFIG */
1985 MPLIST_DO (p, plist)
1987 MSymbol sym = MPLIST_SYMBOL (p);
1991 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
1993 mplist_push (p, Msymbol, family);
1997 if (MPLIST_TAIL_P (p))
1998 mplist_push (p, Msymbol, family);
2003 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2005 MFontFT *ft_info = (MFontFT *) rfont->font;
2006 MFontCapability *cap = mfont__get_capability (capability);
2008 if (cap->script != Mnil
2009 && ft_check_script (ft_info, cap->script) < 0)
2011 if (cap->language != Mnil
2012 && ft_check_language (ft_info, cap->language) < 0)
2014 if (cap->script_tag && ft_check_otf (ft_info, cap) < 0)
2023 MFontDriver mfont__ft_driver =
2024 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2025 ft_render, ft_list, ft_list_family_names, ft_check_capability};
2032 if (FT_Init_FreeType (&ft_library) != 0)
2033 MERROR (MERROR_FONT_FT, -1);
2035 for (i = 0; i < ft_to_prop_size; i++)
2036 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2038 Mmedium = msymbol ("medium");
2040 Mnull = msymbol ("");
2042 M0[0] = msymbol ("0-0");
2043 M0[1] = msymbol ("0-1");
2044 M0[2] = msymbol ("0-2");
2045 M0[3] = msymbol ("0-3");
2046 M0[4] = msymbol ("0-4");
2047 M3_1 = msymbol ("3-1");
2048 M1_0 = msymbol ("1-0");
2050 #ifdef HAVE_FONTCONFIG
2051 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2053 FC_vs_M17N_font_prop *table = fc_all_table[i];
2056 for (j = 0; table[j].m17n_value; j++)
2057 table[j].sym = msymbol (table[j].m17n_value);
2058 table[j].sym = table[j - 1].sym;
2065 MSymbol serif, sans_serif, monospace;
2067 fc_config = FcInitLoadConfigAndFonts ();
2068 if (mfont_freetype_path)
2070 MPLIST_DO (plist, mfont_freetype_path)
2071 if (MPLIST_STRING_P (plist)
2072 && (pathname = MPLIST_STRING (plist))
2073 && stat (pathname, &buf) == 0)
2075 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2078 while ((dir = FcStrListNext (strlist)))
2079 if (strcmp ((char *) dir, pathname) == 0)
2082 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2083 FcStrListDone (strlist);
2086 Mgeneric_family = msymbol ("generic famly");
2087 serif = msymbol ("serif");
2088 msymbol_put (serif, Mgeneric_family, serif);
2089 sans_serif = msymbol ("sans-serif");
2090 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2091 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2092 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2093 monospace = msymbol ("monospace");
2094 msymbol_put (monospace, Mgeneric_family, monospace);
2095 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2107 if (ft_default_list)
2109 M17N_OBJECT_UNREF (ft_default_list);
2110 ft_default_list = NULL;
2115 MPLIST_DO (plist, ft_font_list)
2117 if (MPLIST_VAL (plist))
2118 MPLIST_DO (p, MPLIST_VAL (plist))
2120 if (MPLIST_KEY (p) != Mt)
2121 free_ft_info (MPLIST_VAL (p));
2123 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2125 M17N_OBJECT_UNREF (ft_font_list);
2126 ft_font_list = NULL;
2128 if (ft_language_list)
2130 MPLIST_DO (plist, ft_language_list)
2131 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2132 M17N_OBJECT_UNREF (ft_language_list);
2133 ft_language_list = NULL;
2138 MPLIST_DO (plist, ft_script_list)
2139 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2140 M17N_OBJECT_UNREF (ft_script_list);
2141 ft_script_list = NULL;
2144 if (ft_capability_list)
2146 MPLIST_DO (plist, ft_capability_list)
2147 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2148 M17N_OBJECT_UNREF (ft_capability_list);
2149 ft_capability_list = NULL;
2154 MPLIST_DO (plist, ft_file_list)
2155 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2156 M17N_OBJECT_UNREF (ft_file_list);
2157 ft_file_list = NULL;
2160 FT_Done_FreeType (ft_library);
2161 #ifdef HAVE_FONTCONFIG
2162 FcConfigDestroy (fc_config);
2164 #endif /* HAVE_FONTCONFIG */
2165 all_fonts_scaned = 0;
2168 #ifdef HAVE_FONTCONFIG
2171 mfont__ft_parse_name (const char *name, MFont *font)
2173 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2182 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2184 STRDUP_LOWER (buf, bufsize, (char *) str);
2185 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2187 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2189 STRDUP_LOWER (buf, bufsize, (char *) str);
2190 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2192 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2193 mfont__set_property (font, MFONT_WEIGHT,
2194 fc_decode_prop (val, fc_weight_table,
2195 fc_weight_table_size));
2196 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2197 mfont__set_property (font, MFONT_STYLE,
2198 fc_decode_prop (val, fc_slant_table,
2199 fc_slant_table_size));
2200 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2201 mfont__set_property (font, MFONT_STRETCH,
2202 fc_decode_prop (val, fc_width_table,
2203 fc_width_table_size));
2204 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2205 font->size = size * 10 + 0.5;
2206 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2207 font->size = - (size * 10 + 0.5);
2208 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2210 font->file = msymbol ((char *) str);
2212 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2213 font->type = MFONT_TYPE_SPEC;
2214 FcPatternDestroy (pat);
2219 mfont__ft_unparse_name (MFont *font)
2221 FcPattern *pat = fc_get_pattern (font);
2222 char *name = (char *) FcNameUnparse (pat);
2224 FcPatternDestroy (pat);
2227 #endif /* HAVE_FONTCONFIG */
2232 #define DEVICE_DELTA(table, size) \
2233 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2234 ? (table).DeltaValue[(size) - (table).StartSize] \
2238 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2239 unsigned code, int size, int *x, int *y)
2241 if (anchor->AnchorFormat == 2)
2243 FT_Outline *outline;
2244 int ap = anchor->f.f1.AnchorPoint;
2246 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2247 outline = &ft_face->glyph->outline;
2248 if (ap < outline->n_points)
2250 *x = outline->points[ap].x;
2251 *y = outline->points[ap].y;
2254 else if (anchor->AnchorFormat == 3)
2256 if (anchor->f.f2.XDeviceTable.offset)
2257 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2258 if (anchor->f.f2.YDeviceTable.offset)
2259 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2264 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2265 MFontCapability *cap)
2267 int len = to - from;
2268 MGlyph *g = MGLYPH (from);
2270 MRealizedFont *rfont;
2273 OTF_GlyphString otf_gstring;
2275 char *script, *langsys;
2276 char *gsub_features, *gpos_features;
2282 otf_gstring.glyphs = NULL;
2283 rfont = g->rface->rfont;
2284 ft_info = (MFontFT *) rfont->font;
2285 if (ft_info->otf == invalid_otf)
2290 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2293 ft_info->otf = invalid_otf;
2298 if (OTF_get_table (otf, "head") < 0)
2301 ft_info->otf = invalid_otf;
2305 if (cap->script_tag)
2307 script = alloca (5);
2308 OTF_tag_name (cap->script_tag, script);
2312 if (cap->langsys_tag)
2314 langsys = alloca (5);
2315 OTF_tag_name (cap->langsys_tag, langsys);
2319 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2320 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2321 gsub_features = NULL;
2322 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2323 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2324 gpos_features = NULL;
2326 otf_gstring.size = otf_gstring.used = len;
2327 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2328 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2329 for (i = 0, need_cmap = 0; i < len; i++)
2331 if (gstring->glyphs[from + i].otf_encoded)
2333 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2334 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2338 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2343 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2346 OTF_drive_gdef (otf, &otf_gstring);
2347 gidx = gstring->used;
2351 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2354 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2356 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2359 temp.combining_code = 0;
2362 temp.code = otfg->glyph_id;
2363 temp.otf_encoded = 1;
2368 temp.otf_encoded = 0;
2370 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2371 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2375 for (i = 0; i < len; i++)
2377 MGlyph temp = gstring->glyphs[from + i];
2379 if (otf_gstring.glyphs[i].glyph_id)
2381 temp.code = otf_gstring.glyphs[i].glyph_id;
2382 temp.otf_encoded = 1;
2384 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2387 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2393 MGlyph *base = NULL, *mark = NULL;
2395 if (OTF_check_features (otf, 1,
2396 cap->script_tag, cap->langsys_tag,
2397 cap->features[MFONT_OTT_GPOS].tags,
2398 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2399 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2400 gpos_features) < 0))
2403 u = otf->head->unitsPerEm;
2404 size10 = rfont->spec.size;
2407 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2408 i < otf_gstring.used; i++, otfg++, g++)
2412 if (! otfg->glyph_id)
2414 switch (otfg->positioning_type)
2420 int format = otfg->f.f1.format;
2422 if (format & OTF_XPlacement)
2423 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2424 if (format & OTF_XPlaDevice)
2425 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2426 if (format & OTF_YPlacement)
2427 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2428 if (format & OTF_YPlaDevice)
2429 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2430 if (format & OTF_XAdvance)
2431 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2432 if (format & OTF_XAdvDevice)
2433 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2437 /* Not yet supported. */
2443 goto label_adjust_anchor;
2444 default: /* i.e. case 6 */
2449 label_adjust_anchor:
2451 int base_x, base_y, mark_x, mark_y;
2453 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2454 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2455 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2456 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2458 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2459 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2460 prev->code, size, &base_x, &base_y);
2461 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2462 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2463 g->code, size, &mark_x, &mark_y);
2464 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2465 g->yoff = prev->yoff + mark_y - base_y;
2466 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2469 if (otfg->GlyphClass == OTF_GlyphClass0)
2471 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2477 free (otf_gstring.glyphs);
2481 ft_find_metric (rfont, gstring, from, to);
2482 for (i = 0; i < len; i++)
2484 MGlyph temp = gstring->glyphs[from + i];
2485 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2487 if (otf_gstring.glyphs)
2488 free (otf_gstring.glyphs);
2494 mfont__ft_decode_otf (MGlyph *g)
2496 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2497 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2499 return (c ? c : -1);
2502 #endif /* HAVE_OTF */
2504 #endif /* HAVE_FREETYPE */