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;
1314 int size = font->size ? font->size : spec->size;
1318 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1319 for (; rfont; rfont = rfont->next)
1320 if (rfont->font == font
1321 && (rfont->font->size ? rfont->font->size == size
1322 : rfont->spec.size == size)
1323 && rfont->spec.property[MFONT_REGISTRY] == reg
1324 && rfont->driver == &mfont__ft_driver)
1328 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (spec));
1330 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1333 font->type = MFONT_TYPE_FAILURE;
1334 MDEBUG_PRINT (" no (FT_New_Face)\n");
1338 M17N_OBJECT_REF (charmap_list);
1340 charmap_list = ft_get_charmaps (ft_face);
1341 if (registry == Mnil)
1342 registry = Municode_bmp;
1343 plist = mplist_find_by_key (charmap_list, registry);
1346 FT_Done_Face (ft_face);
1347 M17N_OBJECT_UNREF (charmap_list);
1348 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1351 charmap_index = (int) MPLIST_VAL (plist);
1352 if ((charmap_index >= 0
1353 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1354 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1356 FT_Done_Face (ft_face);
1357 M17N_OBJECT_UNREF (charmap_list);
1358 font->type = MFONT_TYPE_FAILURE;
1359 MDEBUG_PRINT1 (" no (size %d)\n", size);
1363 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1364 ft_rfont->ft_face = ft_face;
1365 ft_rfont->charmap_list = charmap_list;
1366 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1367 rfont->spec = *font;
1368 rfont->spec.type = MFONT_TYPE_REALIZED;
1369 rfont->spec.property[MFONT_REGISTRY] = reg;
1370 rfont->spec.size = size;
1371 rfont->frame = frame;
1373 rfont->driver = &mfont__ft_driver;
1374 rfont->info = ft_rfont;
1375 rfont->fontp = ft_face;
1376 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1377 rfont->descent = - ft_face->size->metrics.descender >> 6;
1378 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1379 rfont->baseline_offset = 0;
1382 BDF_PropertyRec prop;
1384 if (! FT_IS_SCALABLE (ft_face)
1385 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1387 rfont->baseline_offset = prop.u.integer;
1388 rfont->ascent += prop.u.integer;
1389 rfont->descent -= prop.u.integer;
1393 if (FT_IS_SCALABLE (ft_face))
1394 rfont->average_width = 0;
1396 rfont->average_width = ft_face->available_sizes->width;
1397 rfont->next = MPLIST_VAL (frame->realized_font_list);
1398 MPLIST_VAL (frame->realized_font_list) = rfont;
1399 MDEBUG_PRINT (" ok\n");
1403 /* The FreeType font driver function FIND_METRIC. */
1406 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1409 FT_Face ft_face = rfont->fontp;
1410 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1412 for (; g != gend; g++)
1414 if (g->code == MCHAR_INVALID_CODE)
1416 if (FT_IS_SCALABLE (ft_face))
1418 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1419 int size = rfont->spec.size;
1422 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1423 g->width = g->rbearing;
1424 g->ascent = ft_face->ascender * size / unitsPerEm10;
1425 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1430 BDF_PropertyRec prop;
1434 g->rbearing = g->width = ft_face->available_sizes->width;
1436 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1438 g->ascent = prop.u.integer;
1439 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1440 g->descent = prop.u.integer;
1441 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1444 g->ascent += prop.u.integer;
1445 g->descent -= prop.u.integer;
1451 g->ascent = ft_face->available_sizes->height;
1458 FT_Glyph_Metrics *metrics;
1460 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1461 metrics = &ft_face->glyph->metrics;
1462 g->lbearing = (metrics->horiBearingX >> 6);
1463 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1464 g->width = metrics->horiAdvance >> 6;
1465 g->ascent = metrics->horiBearingY >> 6;
1466 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1468 g->ascent += rfont->baseline_offset;
1469 g->descent -= rfont->baseline_offset;
1474 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1476 MRealizedFont *rfont = NULL;
1477 MRealizedFontFT *ft_rfont;
1480 if (font->type == MFONT_TYPE_REALIZED)
1481 rfont = (MRealizedFont *) font;
1482 else if (font->type == MFONT_TYPE_OBJECT)
1484 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1485 rfont = rfont->next)
1486 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1490 #ifdef HAVE_FONTCONFIG
1491 MFontFT *ft_info = (MFontFT *) font;
1493 if (! ft_info->charset)
1495 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1496 MSYMBOL_NAME (font->file),
1498 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1499 FcFontSet *fs = FcFontList (fc_config, pat, os);
1502 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1503 &ft_info->charset) == FcResultMatch)
1504 ft_info->charset = FcCharSetCopy (ft_info->charset);
1506 ft_info->charset = FcCharSetCreate ();
1507 FcFontSetDestroy (fs);
1508 FcObjectSetDestroy (os);
1509 FcPatternDestroy (pat);
1511 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1512 #else /* not HAVE_FONTCONFIG */
1513 rfont = ft_open (frame, font, spec, NULL);
1514 #endif /* not HAVE_FONTCONFIG */
1518 MFATAL (MERROR_FONT_FT);
1522 ft_rfont = rfont->info;
1523 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1527 /* The FreeType font driver function ENCODE_CHAR. */
1530 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1532 MRealizedFont *rfont;
1533 MRealizedFontFT *ft_rfont;
1536 if (font->type == MFONT_TYPE_REALIZED)
1537 rfont = (MRealizedFont *) font;
1538 else if (font->type == MFONT_TYPE_OBJECT)
1540 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1541 rfont = rfont->next)
1542 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1546 rfont = ft_open (frame, font, spec, NULL);
1552 MFATAL (MERROR_FONT_FT);
1554 ft_rfont = rfont->info;
1555 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1556 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1559 /* The FreeType font driver function RENDER. */
1561 #define NUM_POINTS 0x1000
1564 MDrawPoint points[NUM_POINTS];
1569 ft_render (MDrawWindow win, int x, int y,
1570 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1571 int reverse, MDrawRegion region)
1574 MRealizedFace *rface = from->rface;
1575 MFrame *frame = rface->frame;
1576 FT_Int32 load_flags = FT_LOAD_RENDER;
1579 MPointTable point_table[8];
1580 int baseline_offset;
1585 /* It is assured that the all glyphs in the current range use the
1586 same realized face. */
1587 ft_face = rface->rfont->fontp;
1588 baseline_offset = rface->rfont->baseline_offset;
1590 if (! gstring->anti_alias)
1592 #ifdef FT_LOAD_TARGET_MONO
1593 load_flags |= FT_LOAD_TARGET_MONO;
1595 load_flags |= FT_LOAD_MONOCHROME;
1599 for (i = 0; i < 8; i++)
1600 point_table[i].p = point_table[i].points;
1602 for (g = from; g < to; x += g++->width)
1606 MPointTable *ptable;
1610 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1611 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1612 bmp = ft_face->glyph->bitmap.buffer;
1613 width = ft_face->glyph->bitmap.width;
1614 pitch = ft_face->glyph->bitmap.pitch;
1615 if (! gstring->anti_alias)
1620 if (gstring->anti_alias)
1621 for (i = 0; i < ft_face->glyph->bitmap.rows;
1622 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1624 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1625 for (j = 0; j < width; j++, xoff++)
1627 intensity = bmp[j] >> 5;
1630 ptable = point_table + intensity;
1631 ptable->p->x = xoff;
1632 ptable->p->y = yoff - baseline_offset;
1634 if (ptable->p - ptable->points == NUM_POINTS)
1636 (*frame->driver->draw_points)
1638 reverse ? 7 - intensity : intensity,
1639 ptable->points, NUM_POINTS, region);
1640 ptable->p = ptable->points;
1646 for (i = 0; i < ft_face->glyph->bitmap.rows;
1647 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1649 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1650 for (j = 0; j < width; j++, xoff++)
1652 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1655 ptable = point_table;
1656 ptable->p->x = xoff;
1657 ptable->p->y = yoff - baseline_offset;
1659 if (ptable->p - ptable->points == NUM_POINTS)
1661 (*frame->driver->draw_points) (frame, win, rface,
1663 ptable->points, NUM_POINTS, region);
1664 ptable->p = ptable->points;
1671 if (gstring->anti_alias)
1673 for (i = 1; i < 8; i++)
1674 if (point_table[i].p != point_table[i].points)
1675 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1676 point_table[i].points,
1677 point_table[i].p - point_table[i].points, region);
1681 if (point_table[0].p != point_table[0].points)
1682 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1683 point_table[0].points,
1684 point_table[0].p - point_table[0].points, region);
1689 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1691 MPlist *pl = NULL, *p;
1693 MPlist *file_list = NULL;
1694 MPlist *family_list = NULL, *capability_list = NULL;
1695 MSymbol registry = Mnil;
1697 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1703 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1704 if (registry != Mnil && registry != Miso8859_1)
1706 char *reg = MSYMBOL_NAME (registry);
1708 if (strncmp (reg, "unicode-", 8)
1709 && strncmp (reg, "apple-roman", 11)
1710 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1714 if (font->file != Mnil
1715 && ! (file_list = ft_list_file (font->file)))
1717 family = FONT_PROPERTY (font, MFONT_FAMILY);
1719 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1720 && MPLIST_TAIL_P (family_list))
1722 if (font->capability != Mnil)
1724 capability_list = ft_list_capability (font->capability);
1725 if (! capability_list || MPLIST_TAIL_P (capability_list))
1728 else if (family == Mnil)
1730 capability_list = ft_list_default ();
1734 if (! file_list && ! family_list && ! capability_list)
1736 /* No restriction. Get all fonts. */
1738 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1740 MPLIST_DO (p, MPLIST_PLIST (family_list))
1741 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1749 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1754 for (p = pl; ! MPLIST_TAIL_P (p);)
1756 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1757 p = MPLIST_NEXT (p);
1764 MPLIST_DO (p, family_list)
1765 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1768 if (capability_list)
1771 for (p = pl; ! MPLIST_TAIL_P (p);)
1773 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1774 p = MPLIST_NEXT (p);
1781 MPLIST_DO (p, capability_list)
1782 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1788 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1789 + font->property[MFONT_STRETCH] + font->size) > 0)
1791 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1792 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1793 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1794 int size = font->size;
1796 for (p = pl; ! MPLIST_TAIL_P (p); )
1798 MFontFT *ft_info = MPLIST_VAL (p);
1801 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1803 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1805 && stretch != FONT_PROPERTY (&ft_info->font,
1808 && ft_info->font.size > 0
1809 && ft_info->font.size != size))
1812 p = MPLIST_NEXT (p);
1818 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1820 if (maxnum && maxnum <= num)
1823 M17N_OBJECT_UNREF (pl);
1826 MDEBUG_PRINT1 (" %d found\n", num);
1831 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
1833 MFontFT *ft_info = (MFontFT *) rfont->font;
1834 MFontCapability *cap = mfont__get_capability (capability);
1836 if (cap->script_tag && ft_check_otf (ft_info, cap) < 0)
1838 if (cap->lang && ft_check_lang (ft_info, cap) < 0)
1847 MFontDriver mfont__ft_driver =
1848 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1849 ft_render, ft_list , ft_check_capability};
1856 if (FT_Init_FreeType (&ft_library) != 0)
1857 MERROR (MERROR_FONT_FT, -1);
1859 for (i = 0; i < ft_to_prop_size; i++)
1860 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1862 Mmedium = msymbol ("medium");
1864 Mnull = msymbol ("");
1866 M0[0] = msymbol ("0-0");
1867 M0[1] = msymbol ("0-1");
1868 M0[2] = msymbol ("0-2");
1869 M0[3] = msymbol ("0-3");
1870 M0[4] = msymbol ("0-4");
1871 M3_1 = msymbol ("3-1");
1872 M1_0 = msymbol ("1-0");
1874 #ifdef HAVE_FONTCONFIG
1875 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1877 FC_vs_M17N_font_prop *table = fc_all_table[i];
1880 for (j = 0; table[j].m17n_value; j++)
1881 table[j].sym = msymbol (table[j].m17n_value);
1882 table[j].sym = table[j - 1].sym;
1889 MSymbol serif, sans_serif, monospace;
1891 fc_config = FcInitLoadConfigAndFonts ();
1892 if (mfont_freetype_path)
1894 MPLIST_DO (plist, mfont_freetype_path)
1895 if (MPLIST_STRING_P (plist)
1896 && (pathname = MPLIST_STRING (plist))
1897 && stat (pathname, &buf) == 0)
1899 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1902 while ((dir = FcStrListNext (strlist)))
1903 if (strcmp ((char *) dir, pathname) == 0)
1906 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1907 FcStrListDone (strlist);
1910 Mgeneric_family = msymbol ("generic famly");
1911 serif = msymbol ("serif");
1912 msymbol_put (serif, Mgeneric_family, serif);
1913 sans_serif = msymbol ("sans-serif");
1914 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1915 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1916 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1917 monospace = msymbol ("monospace");
1918 msymbol_put (monospace, Mgeneric_family, monospace);
1919 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1931 if (ft_default_list)
1933 M17N_OBJECT_UNREF (ft_default_list);
1934 ft_default_list = NULL;
1939 MPLIST_DO (plist, ft_font_list)
1941 if (MPLIST_VAL (plist))
1942 MPLIST_DO (p, MPLIST_VAL (plist))
1944 if (MPLIST_KEY (p) != Mt)
1945 free_ft_info (MPLIST_VAL (p));
1947 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1949 M17N_OBJECT_UNREF (ft_font_list);
1950 ft_font_list = NULL;
1952 if (ft_language_list)
1954 MPLIST_DO (plist, ft_language_list)
1955 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1956 M17N_OBJECT_UNREF (ft_language_list);
1957 ft_language_list = NULL;
1962 MPLIST_DO (plist, ft_script_list)
1963 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1964 M17N_OBJECT_UNREF (ft_script_list);
1965 ft_script_list = NULL;
1968 if (ft_capability_list)
1970 MPLIST_DO (plist, ft_capability_list)
1971 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1972 M17N_OBJECT_UNREF (ft_capability_list);
1973 ft_capability_list = NULL;
1978 MPLIST_DO (plist, ft_file_list)
1979 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1980 M17N_OBJECT_UNREF (ft_file_list);
1981 ft_file_list = NULL;
1984 FT_Done_FreeType (ft_library);
1985 #ifdef HAVE_FONTCONFIG
1986 FcConfigDestroy (fc_config);
1988 #endif /* HAVE_FONTCONFIG */
1989 all_fonts_scaned = 0;
1992 #ifdef HAVE_FONTCONFIG
1995 mfont__ft_parse_name (const char *name, MFont *font)
1997 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2006 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2008 STRDUP_LOWER (buf, bufsize, (char *) str);
2009 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2011 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2013 STRDUP_LOWER (buf, bufsize, (char *) str);
2014 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2016 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2017 mfont__set_property (font, MFONT_WEIGHT,
2018 fc_decode_prop (val, fc_weight_table,
2019 fc_weight_table_size));
2020 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2021 mfont__set_property (font, MFONT_STYLE,
2022 fc_decode_prop (val, fc_slant_table,
2023 fc_slant_table_size));
2024 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2025 mfont__set_property (font, MFONT_STRETCH,
2026 fc_decode_prop (val, fc_width_table,
2027 fc_width_table_size));
2028 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2029 font->size = size * 10 + 0.5;
2030 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2031 font->size = - (size * 10 + 0.5);
2032 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2034 font->file = msymbol ((char *) str);
2036 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2037 font->type = MFONT_TYPE_SPEC;
2038 FcPatternDestroy (pat);
2043 mfont__ft_unparse_name (MFont *font)
2045 FcPattern *pat = fc_get_pattern (font);
2046 char *name = (char *) FcNameUnparse (pat);
2048 FcPatternDestroy (pat);
2051 #endif /* HAVE_FONTCONFIG */
2056 #define DEVICE_DELTA(table, size) \
2057 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2058 ? (table).DeltaValue[(size) >= (table).StartSize] \
2062 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2063 unsigned code, int size, int *x, int *y)
2065 if (anchor->AnchorFormat == 2)
2067 FT_Outline *outline;
2068 int ap = anchor->f.f1.AnchorPoint;
2070 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2071 outline = &ft_face->glyph->outline;
2072 if (ap < outline->n_points)
2074 *x = outline->points[ap].x;
2075 *y = outline->points[ap].y;
2078 else if (anchor->AnchorFormat == 3)
2080 if (anchor->f.f2.XDeviceTable.offset)
2081 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2082 if (anchor->f.f2.YDeviceTable.offset)
2083 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2088 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2089 MFontCapability *cap)
2091 int len = to - from;
2092 MGlyph *g = MGLYPH (from);
2094 MRealizedFont *rfont;
2097 OTF_GlyphString otf_gstring;
2099 char *script, *langsys;
2100 char *gsub_features, *gpos_features;
2106 otf_gstring.glyphs = NULL;
2107 rfont = g->rface->rfont;
2108 ft_info = (MFontFT *) rfont->font;
2109 if (ft_info->otf == invalid_otf)
2114 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2117 ft_info->otf = invalid_otf;
2122 if (OTF_get_table (otf, "head") < 0)
2125 ft_info->otf = invalid_otf;
2129 if (cap->script_tag)
2131 script = alloca (5);
2132 OTF_tag_name (cap->script_tag, script);
2136 if (cap->langsys_tag)
2138 langsys = alloca (5);
2139 OTF_tag_name (cap->langsys_tag, langsys);
2143 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2144 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2145 gsub_features = NULL;
2146 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2147 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2148 gpos_features = NULL;
2150 otf_gstring.size = otf_gstring.used = len;
2151 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2152 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2153 for (i = 0, need_cmap = 0; i < len; i++)
2155 if (gstring->glyphs[from + i].otf_encoded)
2157 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2158 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2162 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2167 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2170 OTF_drive_gdef (otf, &otf_gstring);
2171 gidx = gstring->used;
2175 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2178 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2180 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2183 temp.combining_code = 0;
2186 temp.code = otfg->glyph_id;
2187 temp.otf_encoded = 1;
2192 temp.otf_encoded = 0;
2194 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2195 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2199 for (i = 0; i < len; i++)
2201 MGlyph temp = gstring->glyphs[from + i];
2203 if (otf_gstring.glyphs[i].glyph_id)
2205 temp.code = otf_gstring.glyphs[i].glyph_id;
2206 temp.otf_encoded = 1;
2208 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2211 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2217 MGlyph *base = NULL, *mark = NULL;
2219 if (OTF_check_features (otf, 1,
2220 cap->script_tag, cap->langsys_tag,
2221 cap->features[MFONT_OTT_GPOS].tags,
2222 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2223 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2224 gpos_features) < 0))
2227 u = otf->head->unitsPerEm;
2228 size10 = rfont->spec.size;
2231 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2232 i < otf_gstring.used; i++, otfg++, g++)
2236 if (! otfg->glyph_id)
2238 switch (otfg->positioning_type)
2244 int format = otfg->f.f1.format;
2246 if (format & OTF_XPlacement)
2247 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2248 if (format & OTF_XPlaDevice)
2249 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2250 if (format & OTF_YPlacement)
2251 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2252 if (format & OTF_YPlaDevice)
2253 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2254 if (format & OTF_XAdvance)
2255 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2256 if (format & OTF_XAdvDevice)
2257 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2261 /* Not yet supported. */
2267 goto label_adjust_anchor;
2268 default: /* i.e. case 6 */
2273 label_adjust_anchor:
2275 int base_x, base_y, mark_x, mark_y;
2277 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2278 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2279 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2280 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2282 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2283 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2284 prev->code, size, &base_x, &base_y);
2285 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2286 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2287 g->code, size, &mark_x, &mark_y);
2288 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2289 g->yoff = prev->yoff + mark_y - base_y;
2290 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2293 if (otfg->GlyphClass == OTF_GlyphClass0)
2295 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2301 free (otf_gstring.glyphs);
2305 ft_find_metric (rfont, gstring, from, to);
2306 for (i = 0; i < len; i++)
2308 MGlyph temp = gstring->glyphs[from + i];
2309 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2311 if (otf_gstring.glyphs)
2312 free (otf_gstring.glyphs);
2318 mfont__ft_decode_otf (MGlyph *g)
2320 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2321 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2323 return (c ? c : -1);
2326 #endif /* HAVE_OTF */
2328 #endif /* HAVE_FREETYPE */