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 *) "";
73 /* NULL if not yet opened. invalid_otf if not OTF. */
76 #ifdef HAVE_FONTCONFIG
79 #endif /* HAVE_FONTCONFIG */
93 enum MFontProperty prop;
97 static MFTtoProp ft_to_prop[] =
98 { { "italic", 0, MFONT_STYLE, "i" },
99 { "roman", 0, MFONT_STYLE, "r" },
100 { "oblique", 0, MFONT_STYLE, "o" },
101 { "regular", 0, MFONT_WEIGHT, "normal" },
102 { "normal", 0, MFONT_WEIGHT, "normal" },
103 /* We need this entry even if "bold" is in commone_weight[] to
104 handle such style names as "bolditalic" and "boldoblique". */
105 { "bold", 0, MFONT_WEIGHT, "bold" },
106 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
107 { "demi", 0, MFONT_WEIGHT, "demibold" } };
108 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
110 /** List of FreeType fonts. Keys are family names, values are plists
111 containing fonts of the corresponding family. In the deeper
112 plist, keys are file names, values are (MFontFT *). */
113 static MPlist *ft_font_list;
115 /** List of FreeType fonts. Keys are script names, values are plists
116 containing fonts supporting the corresponding script. In the
117 deeper plist, keys are family names, values are (MFontFT *). */
118 static MPlist *ft_script_list;
120 /** List of FreeType fonts. Keys are language names, values are
121 plists containing fonts supporting the corresponding language. In
122 the deeper plist, keys are family names, values are (MFontFT *). */
123 static MPlist *ft_language_list;
125 static MPlist *ft_file_list;
127 static int all_fonts_scaned;
129 #define STRDUP_LOWER(s1, size, s2) \
131 int len = strlen (s2) + 1; \
135 (s1) = alloca (len), (size) = len; \
136 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
137 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
138 while (p1 > (s1) && p1[-1] == ' ') p1--; \
144 free_ft_rfont (void *object)
146 MRealizedFontFT *ft_rfont = object;
148 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
149 FT_Done_Face (ft_rfont->ft_face);
154 free_ft_info (MFontFT *ft_info)
156 M17N_OBJECT_UNREF (ft_info->lang);
158 if (ft_info->otf && ft_info->otf != invalid_otf)
159 OTF_close (ft_info->otf);
160 #endif /* HAVE_OTF */
165 ft_get_charmaps (FT_Face ft_face)
167 MPlist *plist = mplist ();
168 int unicode_bmp = -1, unicode_full = -1;
171 mplist_add (plist, Mt, (void *) -1);
172 for (i = 0; i < ft_face->num_charmaps; i++)
174 MSymbol registry = Mnil;
176 if (ft_face->charmaps[i]->platform_id == 0)
178 if (ft_face->charmaps[i]->encoding_id <= 4)
179 registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
180 if (ft_face->charmaps[i]->encoding_id == 4)
181 unicode_bmp = unicode_full = i;
183 else if (ft_face->charmaps[i]->platform_id == 3)
185 if (ft_face->charmaps[i]->encoding_id == 1)
186 registry = M3_1, unicode_bmp = i;
187 else if (ft_face->charmaps[i]->encoding_id == 10)
188 unicode_bmp = unicode_full = i;
190 else if (ft_face->charmaps[i]->platform_id == 1
191 && ft_face->charmaps[i]->encoding_id == 0)
194 mplist_add (plist, Mapple_roman, (void *) i);
196 if (registry == Mnil)
198 char registry_buf[16];
200 sprintf (registry_buf, "%d-%d",
201 ft_face->charmaps[i]->platform_id,
202 ft_face->charmaps[i]->encoding_id);
203 registry = msymbol (registry_buf);
205 mplist_add (plist, registry, (void *) i);
207 if (unicode_full >= 0)
208 mplist_add (plist, Municode_full, (void *) unicode_full);
209 if (unicode_bmp >= 0)
213 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
214 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
215 for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
218 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
220 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
227 #ifdef HAVE_FONTCONFIG
234 } FC_vs_M17N_font_prop;
236 static FC_vs_M17N_font_prop fc_weight_table[] =
237 { { FC_WEIGHT_THIN, "thin" },
238 { FC_WEIGHT_ULTRALIGHT, "extralight" },
239 { FC_WEIGHT_LIGHT, "light" },
240 #ifdef FC_WEIGHT_BOOK
241 { FC_WEIGHT_BOOK, "book" },
242 #endif /* FC_WEIGHT_BOOK */
243 { FC_WEIGHT_REGULAR, "normal" },
244 { FC_WEIGHT_NORMAL, "normal" },
245 { FC_WEIGHT_MEDIUM, "medium" },
246 { FC_WEIGHT_DEMIBOLD, "demibold" },
247 { FC_WEIGHT_BOLD, "bold" },
248 { FC_WEIGHT_EXTRABOLD, "extrabold" },
249 { FC_WEIGHT_BLACK, "black" },
250 { FC_WEIGHT_HEAVY, "heavy" },
251 { FC_WEIGHT_MEDIUM, NULL } };
252 int fc_weight_table_size =
253 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
255 static FC_vs_M17N_font_prop fc_slant_table[] =
256 { { FC_SLANT_ROMAN, "r" },
257 { FC_SLANT_ITALIC, "i" },
258 { FC_SLANT_OBLIQUE, "o" },
259 { FC_SLANT_ROMAN, NULL } };
260 int fc_slant_table_size =
261 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
263 static FC_vs_M17N_font_prop fc_width_table[] =
264 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
265 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
266 { FC_WIDTH_CONDENSED, "condensed" },
267 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
268 { FC_WIDTH_NORMAL, "normal" },
269 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
270 { FC_WIDTH_EXPANDED, "expanded" },
271 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
272 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
273 { FC_WIDTH_NORMAL, NULL } };
274 int fc_width_table_size =
275 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
278 static FC_vs_M17N_font_prop *fc_all_table[] =
279 { fc_weight_table, fc_slant_table, fc_width_table };
282 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
286 if (val < table[i].fc_value)
288 for (i--; i >= 0; i--)
289 if (val > table[i].fc_value)
295 for (; i < size; i++)
296 if (val <= table[i].fc_value)
303 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
307 for (i = 0; table[i].m17n_value; i++)
308 if (table[i].sym == sym)
310 return table[i].fc_value;
314 fc_get_pattern (MFont *font)
316 FcPattern *pat = FcPatternCreate ();
317 MSymbol sym, weight, style, stretch;
320 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
321 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
322 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
323 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
324 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
325 FcPatternAddInteger (pat, FC_WEIGHT,
326 fc_encode_prop (weight, fc_weight_table));
327 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
328 FcPatternAddInteger (pat, FC_SLANT,
329 fc_encode_prop (style, fc_slant_table));
330 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
331 FcPatternAddInteger (pat, FC_WIDTH,
332 fc_encode_prop (stretch, fc_width_table));
335 double size = font->size;
336 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
338 else if (font->size < 0)
340 double size = - font->size;
341 FcPatternAddDouble (pat, FC_SIZE, size / 10);
347 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
358 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
360 STRDUP_LOWER (buf, bufsize, (char *) str);
361 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
364 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
365 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
367 STRDUP_LOWER (buf, bufsize, (char *) str);
368 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
370 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
372 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
373 mfont__set_property (font, MFONT_WEIGHT, sym);
375 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
377 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
378 mfont__set_property (font, MFONT_STYLE, sym);
380 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
382 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
383 mfont__set_property (font, MFONT_STRETCH, sym);
385 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
387 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
388 || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
389 || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
390 font->for_full_width = 1;
393 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
394 font->type = MFONT_TYPE_SPEC;
395 font->source = MFONT_SOURCE_FT;
396 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
397 font->size = size * 10;
398 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
399 font->file = msymbol ((char *) str);
404 fc_gen_font (FcPattern *pat, char *family)
408 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
409 fc_parse_pattern (pat, family, &ft_info->font);
410 ft_info->font.type = MFONT_TYPE_OBJECT;
414 #else /* not HAVE_FONTCONFIG */
417 ft_add_font (char *filename)
430 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
432 if (! FT_IS_SCALABLE (ft_face))
436 BDF_PropertyRec prop;
438 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
439 size = prop.u.integer * 10;
440 #else /* not HAVE_FTBDF_H */
442 #endif /* not HAVE_FTBDF_H */
445 FT_Done_Face (ft_face);
450 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
451 font = &ft_info->font;
452 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
453 family = msymbol (buf);
454 mfont__set_property (font, MFONT_FAMILY, family);
455 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
456 mfont__set_property (font, MFONT_STYLE, Mr);
457 mfont__set_property (font, MFONT_STRETCH, Mnormal);
458 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
459 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
460 font->type = MFONT_TYPE_OBJECT;
461 font->source = MFONT_SOURCE_FT;
463 font->file = msymbol (filename);
465 stylename = ft_face->style_name;
468 for (i = 0; i < ft_to_prop_size; i++)
469 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
472 mfont__set_property (font, ft_to_prop[i].prop,
473 msymbol (ft_to_prop[i].val));
474 stylename += ft_to_prop[i].len;
477 if (i == ft_to_prop_size)
479 char *p1 = stylename + 1;
482 while (*p1 >= 'a' && *p1 <= 'z') p1++;
483 sym = msymbol__with_len (stylename, p1 - stylename);
484 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
485 if (msymbol_get (sym, mfont__property_table[i].property))
487 mfont__set_property (font, i, sym);
492 while (*stylename && ! isalpha (*stylename))
496 FT_Done_Face (ft_face);
498 plist = mplist_find_by_key (ft_font_list, family);
500 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
504 mplist_add (plist, font->file, ft_info);
505 plist = mplist_push (ft_font_list, family, plist);
510 #endif /* not HAVE_FONTCONFIG */
513 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
514 scan all fonts and return ft_font_list. */
517 ft_list_family (MSymbol family, int check_generic)
520 #ifdef HAVE_FONTCONFIG
535 plist = ft_font_list = mplist ();
536 pattern = FcPatternCreate ();
537 os = FcObjectSetBuild (FC_FAMILY, NULL);
538 fs = FcFontList (fc_config, pattern, os);
539 for (i = 0; i < fs->nfont; i++)
541 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
542 (FcChar8 **) &fam) != FcResultMatch)
544 STRDUP_LOWER (buf, bufsize, fam);
546 if (! mplist_find_by_key (ft_font_list, sym))
547 plist = mplist_add (plist, sym, NULL);
549 FcFontSetDestroy (fs);
550 FcObjectSetDestroy (os);
551 FcPatternDestroy (pattern);
556 if (! all_fonts_scaned)
558 MPLIST_DO (plist, ft_font_list)
560 if (! MPLIST_VAL (plist))
561 ft_list_family (MPLIST_KEY (plist), 0);
563 all_fonts_scaned = 1;
568 plist = mplist_find_by_key (ft_font_list, family);
571 if (! MPLIST_VAL (plist))
573 fam = MSYMBOL_NAME (family);
574 pattern = FcPatternCreate ();
575 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
576 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
577 FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL);
578 fs = FcFontList (fc_config, pattern, os);
580 for (i = 0; i < fs->nfont; i++)
582 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
583 p = mplist_add (p, ft_info->font.file, ft_info);
585 MPLIST_VAL (plist) = pl;
586 FcFontSetDestroy (fs);
587 FcObjectSetDestroy (os);
588 FcPatternDestroy (pattern);
591 else if (check_generic
592 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
594 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
597 if (family != generic)
598 plist = ft_list_family (generic, 1);
601 fam = MSYMBOL_NAME (family);
603 mplist_push (ft_font_list, family, plist);
604 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
605 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
608 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
611 STRDUP_LOWER (buf, bufsize, (char *) fam8);
612 family = msymbol (buf);
613 if (msymbol_get (family, Mgeneric_family))
615 pl = ft_list_family (family, 0);
618 MPLIST_DO (pl, MPLIST_PLIST (pl))
619 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
621 plist = ft_font_list;
626 /* Check if there exist an alias. */
628 plist = mplist_add (ft_font_list, family, pl);
630 pattern = FcPatternBuild (NULL,
631 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
633 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
635 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
636 (FcChar8 **) &fam) == FcResultMatch;
640 /* The last one is a generic family. */
643 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
646 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
647 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
648 (FcChar8 **) &fam) == FcResultMatch;
651 /* Now we know that the last J fonts in PATTERN are from
652 generic font, and the first one is not available. So,
653 the remaining ones are aliases. */
655 for (i = 1; i < j; i++)
657 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
658 STRDUP_LOWER (buf, bufsize, fam);
660 p = MPLIST_PLIST (ft_list_family (sym, 0));
661 if (! MPLIST_TAIL_P (p))
663 mplist_push (pl, Mt, MPLIST_VAL (p));
668 #else /* not HAVE_FONTCONFIG */
670 if (! all_fonts_scaned)
678 ft_font_list = mplist ();
679 MPLIST_DO (plist, mfont_freetype_path)
680 if (MPLIST_STRING_P (plist)
681 && (pathname = MPLIST_STRING (plist))
682 && stat (pathname, &buf) == 0)
684 if (S_ISREG (buf.st_mode))
685 ft_add_font (pathname);
686 else if (S_ISDIR (buf.st_mode))
688 DIR *dir = opendir (pathname);
692 int len = strlen (pathname);
695 while ((dp = readdir (dir)) != NULL)
697 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
698 strcpy (path, pathname);
700 strcpy (path + len + 1, dp->d_name);
708 all_fonts_scaned = 1;
711 plist = ft_font_list;
714 plist = mplist_find_by_key (ft_font_list, family);
716 plist = mplist_push (ft_font_list, family, mplist ());
718 #endif /* not HAVE_FONTCONFIG */
724 ft_list_language (MSymbol language)
726 MPlist *plist = NULL;
730 if (! ft_language_list)
731 ft_language_list = mplist ();
732 else if ((plist = mplist_find_by_key (ft_language_list, language)))
733 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
735 #ifdef HAVE_FONTCONFIG
736 for (step = 0; step < 2; step++)
738 FcPattern *pattern = NULL;
739 FcObjectSet *os = NULL;
740 FcFontSet *fs = NULL;
745 if (! (pattern = FcPatternCreate ())
746 || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
750 FcLangSet *ls = FcLangSetCreate ();
754 if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
755 && FcPatternAddLangSet (pattern, FC_LANG, ls))
756 fs = FcFontList (fc_config, pattern, os);
757 FcLangSetDestroy (ls);
765 if (! (mt = msymbol_get (language, Mtext)))
767 if (! (cs = FcCharSetCreate ()))
769 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
770 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
773 && (mt = mtext_get_prop (mt, 0, Mtext)))
774 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
775 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
779 if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
780 fs = FcFontList (fc_config, pattern, os);
782 FcCharSetDestroy (cs);
787 for (i = 0; i < fs->nfont; i++)
789 MSymbol family, file;
790 char *fam, *filename;
794 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
795 (FcChar8 **) &fam) != FcResultMatch)
797 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
798 (FcChar8 **) &filename) != FcResultMatch)
800 STRDUP_LOWER (buf, bufsize, fam);
801 family = msymbol (buf);
802 file = msymbol (filename);
803 pl = MPLIST_PLIST (ft_list_family (family, 0));
804 ft_info = mplist_get (pl, file);
809 mplist_add (plist, family, ft_info);
812 FcFontSetDestroy (fs);
813 FcObjectSetDestroy (os);
814 FcPatternDestroy (pattern);
815 if (language == msymbol ("en"))
821 FcObjectSetDestroy (os);
823 FcPatternDestroy (pattern);
824 MEMORY_FULL (MERROR_FONT_FT);
828 mplist_push (ft_language_list, language, plist);
831 #else /* not HAVE_FONTCONFIG */
833 if ((mt = msymbol_get (language, Mtext)))
835 MText *extra = mtext_get_prop (mt, 0, Mtext);
837 int len = mtext_nchars (mt);
838 int extra_len = extra ? mtext_nchars (extra) : 0;
842 ft_list_family (Mnil, 0);
843 MPLIST_DO (pl, ft_font_list)
845 MPLIST_DO (p, MPLIST_PLIST (pl))
847 MFontFT *ft_info = MPLIST_VAL (p);
851 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
854 for (i = len - 1; i >= 0; i--)
855 if (FT_Get_Char_Index (ft_face,
856 (FT_ULong) mtext_ref_char (mt, i)) == 0)
858 if (i < 0 && extra_len > 0)
859 for (i = extra_len - 1; i >= 0; i--)
860 if (FT_Get_Char_Index (ft_face,
861 (FT_ULong) mtext_ref_char (extra, i)) == 0)
863 FT_Done_Face (ft_face);
868 family = mfont_get_prop (&ft_info->font, Mfamily);
869 mplist_push (plist, family, ft_info);
874 #endif /* not HAVE_FONTCONFIG */
878 ft_list_script (MSymbol script)
880 MPlist *plist = NULL;
881 MPlist *language_list, *pl;
883 if (! ft_script_list)
884 ft_script_list = mplist ();
885 else if ((plist = mplist_find_by_key (ft_script_list, script)))
886 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
888 language_list = mlanguage__list (script);
889 MPLIST_DO (pl, language_list)
891 MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
892 MPlist *p = ft_list_language (language);
901 family = MPLIST_KEY (p);
902 if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
903 mplist_add (plist, family, MPLIST_VAL (p));
906 mplist_push (ft_script_list, script, plist);
907 M17N_OBJECT_UNREF (language_list);
912 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
915 if (ft_info->otf == invalid_otf)
919 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
922 ft_info->otf = invalid_otf;
926 if (cap->features[MFONT_OTT_GSUB].nfeatures
927 && cap->features[MFONT_OTT_GSUB].tags[0]
928 && (OTF_check_features
930 cap->script_tag, cap->langsys_tag,
931 cap->features[MFONT_OTT_GSUB].tags,
932 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
934 if (cap->features[MFONT_OTT_GPOS].nfeatures
935 && cap->features[MFONT_OTT_GPOS].tags[0]
936 && (OTF_check_features
938 cap->script_tag, cap->langsys_tag,
939 cap->features[MFONT_OTT_GPOS].tags,
940 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
943 #else /* not HAVE_OTF */
945 #endif /* not HAVE_OTF */
949 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
951 #ifdef HAVE_FONTCONFIG
956 for (i = 0; cap->lang[i] != Mnil; i++)
959 && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
961 if (MPLIST_VAL (plist))
966 if (! ft_info->langset)
968 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
969 MSYMBOL_NAME (ft_info->font.file),
971 FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
972 FcFontSet *fs = FcFontList (fc_config, pat, os);
976 if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
978 ft_info->langset = FcLangSetCopy (ft_info->langset);
980 ft_info->langset = FcLangSetCreate ();
981 FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
982 FcFontSetDestroy (fs);
983 FcObjectSetDestroy (os);
984 FcPatternDestroy (pat);
987 ft_info->lang = mplist ();
988 if (FcLangSetHasLang (ft_info->langset,
989 (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
990 != FcLangDifferentLang)
992 mplist_push (ft_info->lang, cap->lang[i], Mt);
996 mt = msymbol_get (cap->lang[i], Mtext);
999 mplist_push (ft_info->lang, cap->lang[i], Mnil);
1003 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
1004 if (! FcCharSetAddChar (ft_info->charset,
1005 (FcChar32) mtext_ref_char (mt, j)))
1008 && (mt = mtext_get_prop (mt, 0, Mtext)))
1009 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
1010 if (! FcCharSetAddChar (ft_info->charset,
1011 (FcChar32) mtext_ref_char (mt, j)))
1013 mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
1017 #endif /* HAVE_FONTCONFIG */
1021 static MPlist *ft_default_list;
1026 if (ft_default_list)
1027 return ft_default_list;
1028 ft_default_list = mplist ();
1029 #ifdef HAVE_FONTCONFIG
1031 FcPattern *pat = FcPatternCreate ();
1037 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1038 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1044 STRDUP_LOWER (buf, bufsize, (char *) fam);
1045 family = msymbol (buf);
1046 if (msymbol_get (family, Mgeneric_family))
1048 plist = MPLIST_PLIST (ft_list_family (family, 0));
1049 MPLIST_DO (plist, plist)
1050 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1053 #else /* not HAVE_FONTCONFIG */
1057 MPLIST_DO (plist, ft_list_family (Mnil, 0))
1059 pl = MPLIST_PLIST (plist);
1060 if (! MPLIST_TAIL_P (pl))
1061 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1064 #endif /* not HAVE_FONTCONFIG */
1065 return ft_default_list;
1069 static MPlist *ft_capability_list;
1072 ft_list_capability (MSymbol sym)
1074 MPlist *plist, *pl, *p;
1075 MFontCapability *cap = mfont__get_capability (sym);
1079 if (ft_capability_list)
1081 plist = mplist_find_by_key (ft_capability_list, sym);
1083 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1088 ft_capability_list = mplist ();
1091 if (cap->script != Mnil)
1093 pl = ft_list_script (cap->script);
1097 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1099 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
1103 mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
1105 mplist_push (ft_capability_list, sym, plist);
1113 for (i = 0; cap->lang[i] != Mnil; i++)
1115 p = ft_list_language (cap->lang[i]);
1121 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1125 mplist_push (ft_capability_list, sym, plist);
1131 ft_list_file (MSymbol filename)
1133 MPlist *plist = NULL;
1136 ft_file_list = mplist ();
1137 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1138 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1140 #ifdef HAVE_FONTCONFIG
1142 FcPattern *pattern = FcPatternCreate ();
1146 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1147 os = FcObjectSetBuild (FC_FAMILY, NULL);
1148 fs = FcFontList (fc_config, pattern, os);
1155 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1156 (FcChar8 **) &fam) == FcResultMatch)
1161 STRDUP_LOWER (buf, bufsize, fam);
1162 family = msymbol (buf);
1163 pl = ft_list_family (family, 0);
1164 MPLIST_DO (pl, MPLIST_PLIST (pl))
1166 MFontFT *ft_info = MPLIST_VAL (pl);
1168 if (ft_info->font.file == filename)
1171 mplist_add (plist, family, ft_info);
1178 #else /* not HAVE_FONTCONFIG */
1182 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1184 MPLIST_DO (p, MPLIST_PLIST (pl))
1186 MFontFT *ft_info = MPLIST_VAL (pl);
1188 if (ft_info->font.file == filename)
1191 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1199 #endif /* not HAVE_FONTCONFIG */
1201 mplist_push (ft_file_list, filename, plist);
1205 /* The FreeType font driver function SELECT. */
1208 ft_select (MFrame *frame, MFont *font, int limited_size)
1210 MFont *found = NULL;
1211 #ifdef HAVE_FONTCONFIG
1214 int check_font_property = 1;
1216 if (font->file != Mnil)
1218 plist = ft_list_file (font->file);
1221 check_font_property = 0;
1225 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1228 plist = MPLIST_PLIST (ft_list_family (family, 1));
1230 plist = ft_list_default ();
1231 if (MPLIST_TAIL_P (plist))
1235 plist = mplist_copy (plist);
1237 if (font->capability != Mnil)
1239 MFontCapability *cap = mfont__get_capability (font->capability);
1241 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1243 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1248 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
1251 pl = MPLIST_NEXT (pl);
1255 if (check_font_property)
1257 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1258 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1259 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1260 MSymbol alternate_weight = Mnil;
1262 if (weight == Mnormal)
1263 alternate_weight = Mmedium;
1264 else if (weight == Mmedium)
1265 alternate_weight = Mnormal;
1266 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1267 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1269 ft_info = MPLIST_VAL (pl);
1271 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1272 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1274 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1276 && stretch != FONT_PROPERTY (&ft_info->font,
1279 && ft_info->font.size > 0
1280 && ft_info->font.size != font->size))
1283 pl = MPLIST_NEXT (pl);
1287 MPLIST_DO (pl, plist)
1289 font = MPLIST_VAL (plist);
1290 if (limited_size == 0
1292 || font->size <= limited_size)
1298 M17N_OBJECT_UNREF (plist);
1304 static MRealizedFont *
1305 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1307 MFontFT *ft_info = (MFontFT *) font;
1308 int reg = spec->property[MFONT_REGISTRY];
1309 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1310 MRealizedFontFT *ft_rfont;
1312 MPlist *plist, *charmap_list = NULL;
1317 /* non-scalable font */
1319 else if (spec->size)
1321 int ratio = mfont_resize_ratio (font);
1323 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1330 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1331 for (; rfont; rfont = rfont->next)
1332 if (rfont->font == font
1333 && (rfont->font->size ? rfont->font->size == size
1334 : rfont->spec.size == size)
1335 && rfont->spec.property[MFONT_REGISTRY] == reg
1336 && rfont->driver == &mfont__ft_driver)
1340 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1342 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1345 font->type = MFONT_TYPE_FAILURE;
1346 MDEBUG_PRINT (" no (FT_New_Face)\n");
1350 M17N_OBJECT_REF (charmap_list);
1352 charmap_list = ft_get_charmaps (ft_face);
1353 if (registry == Mnil)
1354 registry = Municode_bmp;
1355 plist = mplist_find_by_key (charmap_list, registry);
1358 FT_Done_Face (ft_face);
1359 M17N_OBJECT_UNREF (charmap_list);
1360 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1363 charmap_index = (int) MPLIST_VAL (plist);
1364 if ((charmap_index >= 0
1365 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1366 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1368 FT_Done_Face (ft_face);
1369 M17N_OBJECT_UNREF (charmap_list);
1370 font->type = MFONT_TYPE_FAILURE;
1371 MDEBUG_PRINT1 (" no (size %d)\n", size);
1375 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1376 ft_rfont->ft_face = ft_face;
1377 ft_rfont->charmap_list = charmap_list;
1378 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1379 rfont->spec = *font;
1380 rfont->spec.type = MFONT_TYPE_REALIZED;
1381 rfont->spec.property[MFONT_REGISTRY] = reg;
1382 rfont->spec.size = size;
1383 rfont->frame = frame;
1385 rfont->driver = &mfont__ft_driver;
1386 rfont->info = ft_rfont;
1387 rfont->fontp = ft_face;
1388 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1389 rfont->descent = - ft_face->size->metrics.descender >> 6;
1390 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1391 rfont->baseline_offset = 0;
1394 BDF_PropertyRec prop;
1396 if (! FT_IS_SCALABLE (ft_face)
1397 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1399 rfont->baseline_offset = prop.u.integer;
1400 rfont->ascent += prop.u.integer;
1401 rfont->descent -= prop.u.integer;
1405 if (FT_IS_SCALABLE (ft_face))
1406 rfont->average_width = 0;
1408 rfont->average_width = ft_face->available_sizes->width;
1409 rfont->next = MPLIST_VAL (frame->realized_font_list);
1410 MPLIST_VAL (frame->realized_font_list) = rfont;
1411 MDEBUG_PRINT (" ok\n");
1415 /* The FreeType font driver function FIND_METRIC. */
1418 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1421 FT_Face ft_face = rfont->fontp;
1422 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1424 for (; g != gend; g++)
1426 if (g->code == MCHAR_INVALID_CODE)
1428 if (FT_IS_SCALABLE (ft_face))
1430 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1431 int size = rfont->spec.size;
1434 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1435 g->width = g->rbearing;
1436 g->ascent = ft_face->ascender * size / unitsPerEm10;
1437 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1442 BDF_PropertyRec prop;
1446 g->rbearing = g->width = ft_face->available_sizes->width;
1448 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1450 g->ascent = prop.u.integer;
1451 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1452 g->descent = prop.u.integer;
1453 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1456 g->ascent += prop.u.integer;
1457 g->descent -= prop.u.integer;
1463 g->ascent = ft_face->available_sizes->height;
1470 FT_Glyph_Metrics *metrics;
1472 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1473 metrics = &ft_face->glyph->metrics;
1474 g->lbearing = (metrics->horiBearingX >> 6);
1475 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1476 g->width = metrics->horiAdvance >> 6;
1477 g->ascent = metrics->horiBearingY >> 6;
1478 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1480 g->ascent += rfont->baseline_offset;
1481 g->descent -= rfont->baseline_offset;
1486 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1488 MRealizedFont *rfont = NULL;
1489 MRealizedFontFT *ft_rfont;
1492 if (font->type == MFONT_TYPE_REALIZED)
1493 rfont = (MRealizedFont *) font;
1494 else if (font->type == MFONT_TYPE_OBJECT)
1496 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1497 rfont = rfont->next)
1498 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1502 #ifdef HAVE_FONTCONFIG
1503 MFontFT *ft_info = (MFontFT *) font;
1505 if (! ft_info->charset)
1507 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1508 MSYMBOL_NAME (font->file),
1510 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1511 FcFontSet *fs = FcFontList (fc_config, pat, os);
1514 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1515 &ft_info->charset) == FcResultMatch)
1516 ft_info->charset = FcCharSetCopy (ft_info->charset);
1518 ft_info->charset = FcCharSetCreate ();
1519 FcFontSetDestroy (fs);
1520 FcObjectSetDestroy (os);
1521 FcPatternDestroy (pat);
1523 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1524 #else /* not HAVE_FONTCONFIG */
1525 rfont = ft_open (frame, font, spec, NULL);
1526 #endif /* not HAVE_FONTCONFIG */
1530 MFATAL (MERROR_FONT_FT);
1534 ft_rfont = rfont->info;
1535 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1539 /* The FreeType font driver function ENCODE_CHAR. */
1542 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1544 MRealizedFont *rfont;
1545 MRealizedFontFT *ft_rfont;
1548 if (font->type == MFONT_TYPE_REALIZED)
1549 rfont = (MRealizedFont *) font;
1550 else if (font->type == MFONT_TYPE_OBJECT)
1552 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1553 rfont = rfont->next)
1554 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1558 rfont = ft_open (frame, font, spec, NULL);
1564 MFATAL (MERROR_FONT_FT);
1566 ft_rfont = rfont->info;
1567 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1568 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1571 /* The FreeType font driver function RENDER. */
1573 #define NUM_POINTS 0x1000
1576 MDrawPoint points[NUM_POINTS];
1581 ft_render (MDrawWindow win, int x, int y,
1582 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1583 int reverse, MDrawRegion region)
1586 MRealizedFace *rface = from->rface;
1587 MFrame *frame = rface->frame;
1588 FT_Int32 load_flags = FT_LOAD_RENDER;
1591 MPointTable point_table[8];
1592 int baseline_offset;
1597 /* It is assured that the all glyphs in the current range use the
1598 same realized face. */
1599 ft_face = rface->rfont->fontp;
1600 baseline_offset = rface->rfont->baseline_offset;
1602 if (! gstring->anti_alias)
1604 #ifdef FT_LOAD_TARGET_MONO
1605 load_flags |= FT_LOAD_TARGET_MONO;
1607 load_flags |= FT_LOAD_MONOCHROME;
1611 for (i = 0; i < 8; i++)
1612 point_table[i].p = point_table[i].points;
1614 for (g = from; g < to; x += g++->width)
1618 MPointTable *ptable;
1622 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1623 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1624 bmp = ft_face->glyph->bitmap.buffer;
1625 width = ft_face->glyph->bitmap.width;
1626 pitch = ft_face->glyph->bitmap.pitch;
1627 if (! gstring->anti_alias)
1632 if (gstring->anti_alias)
1633 for (i = 0; i < ft_face->glyph->bitmap.rows;
1634 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1636 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1637 for (j = 0; j < width; j++, xoff++)
1639 intensity = bmp[j] >> 5;
1642 ptable = point_table + intensity;
1643 ptable->p->x = xoff;
1644 ptable->p->y = yoff - baseline_offset;
1646 if (ptable->p - ptable->points == NUM_POINTS)
1648 (*frame->driver->draw_points)
1650 reverse ? 7 - intensity : intensity,
1651 ptable->points, NUM_POINTS, region);
1652 ptable->p = ptable->points;
1658 for (i = 0; i < ft_face->glyph->bitmap.rows;
1659 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1661 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1662 for (j = 0; j < width; j++, xoff++)
1664 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1667 ptable = point_table;
1668 ptable->p->x = xoff;
1669 ptable->p->y = yoff - baseline_offset;
1671 if (ptable->p - ptable->points == NUM_POINTS)
1673 (*frame->driver->draw_points) (frame, win, rface,
1675 ptable->points, NUM_POINTS, region);
1676 ptable->p = ptable->points;
1683 if (gstring->anti_alias)
1685 for (i = 1; i < 8; i++)
1686 if (point_table[i].p != point_table[i].points)
1687 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1688 point_table[i].points,
1689 point_table[i].p - point_table[i].points, region);
1693 if (point_table[0].p != point_table[0].points)
1694 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1695 point_table[0].points,
1696 point_table[0].p - point_table[0].points, region);
1701 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1703 MPlist *pl = NULL, *p;
1705 MPlist *file_list = NULL;
1706 MPlist *family_list = NULL, *capability_list = NULL;
1707 MSymbol registry = Mnil;
1709 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1715 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1716 if (registry != Mnil && registry != Miso8859_1)
1718 char *reg = MSYMBOL_NAME (registry);
1720 if (strncmp (reg, "unicode-", 8)
1721 && strncmp (reg, "apple-roman", 11)
1722 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1726 if (font->file != Mnil
1727 && ! (file_list = ft_list_file (font->file)))
1729 family = FONT_PROPERTY (font, MFONT_FAMILY);
1731 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1732 && MPLIST_TAIL_P (family_list))
1734 if (font->capability != Mnil)
1736 capability_list = ft_list_capability (font->capability);
1737 if (! capability_list || MPLIST_TAIL_P (capability_list))
1742 if (! file_list && ! family_list && ! capability_list)
1744 /* No restriction. Get all fonts. */
1746 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1748 MPLIST_DO (p, MPLIST_PLIST (family_list))
1749 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1757 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1762 for (p = pl; ! MPLIST_TAIL_P (p);)
1764 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1765 p = MPLIST_NEXT (p);
1772 MPLIST_DO (p, family_list)
1773 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1776 if (capability_list)
1779 for (p = pl; ! MPLIST_TAIL_P (p);)
1781 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1782 p = MPLIST_NEXT (p);
1789 MPLIST_DO (p, capability_list)
1790 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1796 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1797 + font->property[MFONT_STRETCH] + font->size) > 0)
1799 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1800 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1801 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1802 int size = font->size;
1804 for (p = pl; ! MPLIST_TAIL_P (p); )
1806 MFontFT *ft_info = MPLIST_VAL (p);
1809 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1811 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1813 && stretch != FONT_PROPERTY (&ft_info->font,
1816 && ft_info->font.size > 0
1817 && ft_info->font.size != size))
1820 p = MPLIST_NEXT (p);
1826 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1828 if (maxnum && maxnum <= num)
1831 M17N_OBJECT_UNREF (pl);
1834 MDEBUG_PRINT1 (" %d found\n", num);
1839 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
1841 MFontFT *ft_info = (MFontFT *) rfont->font;
1842 MFontCapability *cap = mfont__get_capability (capability);
1844 if (cap->script_tag && ft_check_otf (ft_info, cap) < 0)
1846 if (cap->lang && ft_check_lang (ft_info, cap) < 0)
1855 MFontDriver mfont__ft_driver =
1856 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1857 ft_render, ft_list , ft_check_capability};
1864 if (FT_Init_FreeType (&ft_library) != 0)
1865 MERROR (MERROR_FONT_FT, -1);
1867 for (i = 0; i < ft_to_prop_size; i++)
1868 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1870 Mmedium = msymbol ("medium");
1872 Mnull = msymbol ("");
1874 M0[0] = msymbol ("0-0");
1875 M0[1] = msymbol ("0-1");
1876 M0[2] = msymbol ("0-2");
1877 M0[3] = msymbol ("0-3");
1878 M0[4] = msymbol ("0-4");
1879 M3_1 = msymbol ("3-1");
1880 M1_0 = msymbol ("1-0");
1882 #ifdef HAVE_FONTCONFIG
1883 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1885 FC_vs_M17N_font_prop *table = fc_all_table[i];
1888 for (j = 0; table[j].m17n_value; j++)
1889 table[j].sym = msymbol (table[j].m17n_value);
1890 table[j].sym = table[j - 1].sym;
1897 MSymbol serif, sans_serif, monospace;
1899 fc_config = FcInitLoadConfigAndFonts ();
1900 if (mfont_freetype_path)
1902 MPLIST_DO (plist, mfont_freetype_path)
1903 if (MPLIST_STRING_P (plist)
1904 && (pathname = MPLIST_STRING (plist))
1905 && stat (pathname, &buf) == 0)
1907 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1910 while ((dir = FcStrListNext (strlist)))
1911 if (strcmp ((char *) dir, pathname) == 0)
1914 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1915 FcStrListDone (strlist);
1918 Mgeneric_family = msymbol ("generic famly");
1919 serif = msymbol ("serif");
1920 msymbol_put (serif, Mgeneric_family, serif);
1921 sans_serif = msymbol ("sans-serif");
1922 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1923 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1924 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1925 monospace = msymbol ("monospace");
1926 msymbol_put (monospace, Mgeneric_family, monospace);
1927 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1939 if (ft_default_list)
1941 M17N_OBJECT_UNREF (ft_default_list);
1942 ft_default_list = NULL;
1947 MPLIST_DO (plist, ft_font_list)
1949 if (MPLIST_VAL (plist))
1950 MPLIST_DO (p, MPLIST_VAL (plist))
1952 if (MPLIST_KEY (p) != Mt)
1953 free_ft_info (MPLIST_VAL (p));
1955 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1957 M17N_OBJECT_UNREF (ft_font_list);
1958 ft_font_list = NULL;
1960 if (ft_language_list)
1962 MPLIST_DO (plist, ft_language_list)
1963 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1964 M17N_OBJECT_UNREF (ft_language_list);
1965 ft_language_list = NULL;
1970 MPLIST_DO (plist, ft_script_list)
1971 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1972 M17N_OBJECT_UNREF (ft_script_list);
1973 ft_script_list = NULL;
1976 if (ft_capability_list)
1978 MPLIST_DO (plist, ft_capability_list)
1979 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1980 M17N_OBJECT_UNREF (ft_capability_list);
1981 ft_capability_list = NULL;
1986 MPLIST_DO (plist, ft_file_list)
1987 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1988 M17N_OBJECT_UNREF (ft_file_list);
1989 ft_file_list = NULL;
1992 FT_Done_FreeType (ft_library);
1993 #ifdef HAVE_FONTCONFIG
1994 FcConfigDestroy (fc_config);
1996 #endif /* HAVE_FONTCONFIG */
1997 all_fonts_scaned = 0;
2000 #ifdef HAVE_FONTCONFIG
2003 mfont__ft_parse_name (const char *name, MFont *font)
2005 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2014 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2016 STRDUP_LOWER (buf, bufsize, (char *) str);
2017 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2019 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2021 STRDUP_LOWER (buf, bufsize, (char *) str);
2022 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2024 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2025 mfont__set_property (font, MFONT_WEIGHT,
2026 fc_decode_prop (val, fc_weight_table,
2027 fc_weight_table_size));
2028 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2029 mfont__set_property (font, MFONT_STYLE,
2030 fc_decode_prop (val, fc_slant_table,
2031 fc_slant_table_size));
2032 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2033 mfont__set_property (font, MFONT_STRETCH,
2034 fc_decode_prop (val, fc_width_table,
2035 fc_width_table_size));
2036 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2037 font->size = size * 10 + 0.5;
2038 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2039 font->size = - (size * 10 + 0.5);
2040 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2042 font->file = msymbol ((char *) str);
2044 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2045 font->type = MFONT_TYPE_SPEC;
2046 FcPatternDestroy (pat);
2051 mfont__ft_unparse_name (MFont *font)
2053 FcPattern *pat = fc_get_pattern (font);
2054 char *name = (char *) FcNameUnparse (pat);
2056 FcPatternDestroy (pat);
2059 #endif /* HAVE_FONTCONFIG */
2064 #define DEVICE_DELTA(table, size) \
2065 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2066 ? (table).DeltaValue[(size) >= (table).StartSize] \
2070 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2071 unsigned code, int size, int *x, int *y)
2073 if (anchor->AnchorFormat == 2)
2075 FT_Outline *outline;
2076 int ap = anchor->f.f1.AnchorPoint;
2078 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2079 outline = &ft_face->glyph->outline;
2080 if (ap < outline->n_points)
2082 *x = outline->points[ap].x;
2083 *y = outline->points[ap].y;
2086 else if (anchor->AnchorFormat == 3)
2088 if (anchor->f.f2.XDeviceTable.offset)
2089 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2090 if (anchor->f.f2.YDeviceTable.offset)
2091 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2096 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2097 MFontCapability *cap)
2099 int len = to - from;
2100 MGlyph *g = MGLYPH (from);
2102 MRealizedFont *rfont;
2105 OTF_GlyphString otf_gstring;
2107 char *script, *langsys;
2108 char *gsub_features, *gpos_features;
2114 otf_gstring.glyphs = NULL;
2115 rfont = g->rface->rfont;
2116 ft_info = (MFontFT *) rfont->font;
2117 if (ft_info->otf == invalid_otf)
2122 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2125 ft_info->otf = invalid_otf;
2130 if (OTF_get_table (otf, "head") < 0)
2133 ft_info->otf = invalid_otf;
2137 if (cap->script_tag)
2139 script = alloca (5);
2140 OTF_tag_name (cap->script_tag, script);
2144 if (cap->langsys_tag)
2146 langsys = alloca (5);
2147 OTF_tag_name (cap->langsys_tag, langsys);
2151 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2152 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2153 gsub_features = NULL;
2154 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2155 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2156 gpos_features = NULL;
2158 otf_gstring.size = otf_gstring.used = len;
2159 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2160 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2161 for (i = 0, need_cmap = 0; i < len; i++)
2163 if (gstring->glyphs[from + i].otf_encoded)
2165 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2166 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2170 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2175 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2178 OTF_drive_gdef (otf, &otf_gstring);
2179 gidx = gstring->used;
2183 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2186 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2188 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2191 temp.combining_code = 0;
2194 temp.code = otfg->glyph_id;
2195 temp.otf_encoded = 1;
2200 temp.otf_encoded = 0;
2202 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2203 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2207 for (i = 0; i < len; i++)
2209 MGlyph temp = gstring->glyphs[from + i];
2211 if (otf_gstring.glyphs[i].glyph_id)
2213 temp.code = otf_gstring.glyphs[i].glyph_id;
2214 temp.otf_encoded = 1;
2216 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2219 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2225 MGlyph *base = NULL, *mark = NULL;
2227 if (OTF_check_features (otf, 1,
2228 cap->script_tag, cap->langsys_tag,
2229 cap->features[MFONT_OTT_GPOS].tags,
2230 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2231 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2232 gpos_features) < 0))
2235 u = otf->head->unitsPerEm;
2236 size10 = rfont->spec.size;
2239 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2240 i < otf_gstring.used; i++, otfg++, g++)
2244 if (! otfg->glyph_id)
2246 switch (otfg->positioning_type)
2252 int format = otfg->f.f1.format;
2254 if (format & OTF_XPlacement)
2255 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2256 if (format & OTF_XPlaDevice)
2257 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2258 if (format & OTF_YPlacement)
2259 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2260 if (format & OTF_YPlaDevice)
2261 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2262 if (format & OTF_XAdvance)
2263 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2264 if (format & OTF_XAdvDevice)
2265 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2269 /* Not yet supported. */
2275 goto label_adjust_anchor;
2276 default: /* i.e. case 6 */
2281 label_adjust_anchor:
2283 int base_x, base_y, mark_x, mark_y;
2285 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2286 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2287 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2288 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2290 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2291 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2292 prev->code, size, &base_x, &base_y);
2293 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2294 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2295 g->code, size, &mark_x, &mark_y);
2296 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2297 g->yoff = prev->yoff + mark_y - base_y;
2298 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2301 if (otfg->GlyphClass == OTF_GlyphClass0)
2303 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2309 free (otf_gstring.glyphs);
2313 ft_find_metric (rfont, gstring, from, to);
2314 for (i = 0; i < len; i++)
2316 MGlyph temp = gstring->glyphs[from + i];
2317 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2319 if (otf_gstring.glyphs)
2320 free (otf_gstring.glyphs);
2326 mfont__ft_decode_otf (MGlyph *g)
2328 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2329 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2331 return (c ? c : -1);
2334 #endif /* HAVE_OTF */
2336 #endif /* HAVE_FREETYPE */