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_3, 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 == 3)
179 registry = M0_3, unicode_bmp = i;
180 else 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") == FcLangEqual
388 || FcLangSetHasLang (ls, (FcChar8 *) "zh-cn") == FcLangEqual
389 || FcLangSetHasLang (ls, (FcChar8 *) "zh-hk") == FcLangEqual
390 || FcLangSetHasLang (ls, (FcChar8 *) "zh-tw") == FcLangEqual
391 || FcLangSetHasLang (ls, (FcChar8 *) "ko") == FcLangEqual)
392 font->for_full_width = 1;
395 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
396 font->type = MFONT_TYPE_SPEC;
397 font->source = MFONT_SOURCE_FT;
398 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
399 font->size = size * 10;
400 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
401 font->file = msymbol ((char *) str);
406 fc_gen_font (FcPattern *pat, char *family)
410 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
411 fc_parse_pattern (pat, family, &ft_info->font);
412 ft_info->font.type = MFONT_TYPE_OBJECT;
416 #else /* not HAVE_FONTCONFIG */
419 ft_add_font (char *filename)
432 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
434 if (! FT_IS_SCALABLE (ft_face))
438 BDF_PropertyRec prop;
440 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
441 size = prop.u.integer * 10;
442 #else /* not HAVE_FTBDF_H */
444 #endif /* not HAVE_FTBDF_H */
447 FT_Done_Face (ft_face);
452 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
453 font = &ft_info->font;
454 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
455 family = msymbol (buf);
456 mfont__set_property (font, MFONT_FAMILY, family);
457 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
458 mfont__set_property (font, MFONT_STYLE, Mr);
459 mfont__set_property (font, MFONT_STRETCH, Mnormal);
460 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
461 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
462 font->type = MFONT_TYPE_OBJECT;
463 font->source = MFONT_SOURCE_FT;
465 font->file = msymbol (filename);
467 stylename = ft_face->style_name;
470 for (i = 0; i < ft_to_prop_size; i++)
471 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
474 mfont__set_property (font, ft_to_prop[i].prop,
475 msymbol (ft_to_prop[i].val));
476 stylename += ft_to_prop[i].len;
479 if (i == ft_to_prop_size)
481 char *p1 = stylename + 1;
484 while (*p1 >= 'a' && *p1 <= 'z') p1++;
485 sym = msymbol__with_len (stylename, p1 - stylename);
486 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
487 if (msymbol_get (sym, mfont__property_table[i].property))
489 mfont__set_property (font, i, sym);
494 while (*stylename && ! isalpha (*stylename))
498 FT_Done_Face (ft_face);
500 plist = mplist_find_by_key (ft_font_list, family);
502 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
506 mplist_add (plist, font->file, ft_info);
507 plist = mplist_push (ft_font_list, family, plist);
512 #endif /* not HAVE_FONTCONFIG */
515 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
516 scan all fonts and return ft_font_list. */
519 ft_list_family (MSymbol family, int check_generic)
522 #ifdef HAVE_FONTCONFIG
537 plist = ft_font_list = mplist ();
538 pattern = FcPatternCreate ();
539 os = FcObjectSetBuild (FC_FAMILY, NULL);
540 fs = FcFontList (fc_config, pattern, os);
541 for (i = 0; i < fs->nfont; i++)
543 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
544 (FcChar8 **) &fam) != FcResultMatch)
546 STRDUP_LOWER (buf, bufsize, fam);
548 if (! mplist_find_by_key (ft_font_list, sym))
549 plist = mplist_add (plist, sym, NULL);
551 FcFontSetDestroy (fs);
552 FcObjectSetDestroy (os);
553 FcPatternDestroy (pattern);
558 if (! all_fonts_scaned)
560 MPLIST_DO (plist, ft_font_list)
562 if (! MPLIST_VAL (plist))
563 ft_list_family (MPLIST_KEY (plist), 0);
565 all_fonts_scaned = 1;
570 plist = mplist_find_by_key (ft_font_list, family);
573 if (! MPLIST_VAL (plist))
575 fam = MSYMBOL_NAME (family);
576 pattern = FcPatternCreate ();
577 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
578 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
579 FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL);
580 fs = FcFontList (fc_config, pattern, os);
582 for (i = 0; i < fs->nfont; i++)
584 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
585 p = mplist_add (p, ft_info->font.file, ft_info);
587 MPLIST_VAL (plist) = pl;
588 FcFontSetDestroy (fs);
589 FcObjectSetDestroy (os);
590 FcPatternDestroy (pattern);
593 else if (check_generic
594 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
596 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
599 if (family != generic)
600 plist = ft_list_family (generic, 1);
603 fam = MSYMBOL_NAME (family);
605 mplist_push (ft_font_list, family, plist);
606 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
607 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
610 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
613 STRDUP_LOWER (buf, bufsize, (char *) fam8);
614 family = msymbol (buf);
615 if (msymbol_get (family, Mgeneric_family))
617 pl = ft_list_family (family, 0);
620 MPLIST_DO (pl, MPLIST_PLIST (pl))
621 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
623 plist = ft_font_list;
628 /* Check if there exist an alias. */
630 plist = mplist_add (ft_font_list, family, pl);
632 pattern = FcPatternBuild (NULL,
633 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
635 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
637 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
638 (FcChar8 **) &fam) == FcResultMatch;
642 /* The last one is a generic family. */
645 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
648 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
649 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
650 (FcChar8 **) &fam) == FcResultMatch;
653 /* Now we know that the last J fonts in PATTERN are from
654 generic font, and the first one is not available. So,
655 the remaining ones are aliases. */
657 for (i = 1; i < j; i++)
659 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
660 STRDUP_LOWER (buf, bufsize, fam);
662 p = MPLIST_PLIST (ft_list_family (sym, 0));
663 if (! MPLIST_TAIL_P (p))
665 mplist_push (pl, Mt, MPLIST_VAL (p));
670 #else /* not HAVE_FONTCONFIG */
672 if (! all_fonts_scaned)
680 ft_font_list = mplist ();
681 MPLIST_DO (plist, mfont_freetype_path)
682 if (MPLIST_STRING_P (plist)
683 && (pathname = MPLIST_STRING (plist))
684 && stat (pathname, &buf) == 0)
686 if (S_ISREG (buf.st_mode))
687 ft_add_font (pathname);
688 else if (S_ISDIR (buf.st_mode))
690 DIR *dir = opendir (pathname);
694 int len = strlen (pathname);
697 while ((dp = readdir (dir)) != NULL)
699 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
700 strcpy (path, pathname);
702 strcpy (path + len + 1, dp->d_name);
710 all_fonts_scaned = 1;
713 plist = ft_font_list;
716 plist = mplist_find_by_key (ft_font_list, family);
718 plist = mplist_push (ft_font_list, family, mplist ());
720 #endif /* not HAVE_FONTCONFIG */
726 ft_list_language (MSymbol language)
728 MPlist *plist = NULL;
732 if (! ft_language_list)
733 ft_language_list = mplist ();
734 else if ((plist = mplist_find_by_key (ft_language_list, language)))
735 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
737 #ifdef HAVE_FONTCONFIG
738 for (step = 0; step < 2; step++)
740 FcPattern *pattern = NULL;
741 FcObjectSet *os = NULL;
742 FcFontSet *fs = NULL;
747 if (! (pattern = FcPatternCreate ())
748 || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
752 FcLangSet *ls = FcLangSetCreate ();
756 if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
757 && FcPatternAddLangSet (pattern, FC_LANG, ls))
758 fs = FcFontList (fc_config, pattern, os);
759 FcLangSetDestroy (ls);
767 if (! (mt = msymbol_get (language, Mtext)))
769 if (! (cs = FcCharSetCreate ()))
771 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
772 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
776 if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
777 fs = FcFontList (fc_config, pattern, os);
779 FcCharSetDestroy (cs);
784 for (i = 0; i < fs->nfont; i++)
786 MSymbol family, file;
787 char *fam, *filename;
791 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
792 (FcChar8 **) &fam) != FcResultMatch)
794 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
795 (FcChar8 **) &filename) != FcResultMatch)
797 STRDUP_LOWER (buf, bufsize, fam);
798 family = msymbol (buf);
799 file = msymbol (filename);
800 pl = MPLIST_PLIST (ft_list_family (family, 0));
801 ft_info = mplist_get (pl, file);
806 mplist_add (plist, family, ft_info);
809 FcFontSetDestroy (fs);
810 FcObjectSetDestroy (os);
811 FcPatternDestroy (pattern);
812 if (language == msymbol ("en"))
818 FcObjectSetDestroy (os);
820 FcPatternDestroy (pattern);
821 MEMORY_FULL (MERROR_FONT_FT);
825 mplist_push (ft_language_list, language, plist);
828 #else /* not HAVE_FONTCONFIG */
830 if ((mt = msymbol_get (language, Mtext)))
833 int len = mtext_nchars (mt);
837 ft_list_family (Mnil, 0);
838 MPLIST_DO (pl, ft_font_list)
840 MPLIST_DO (p, MPLIST_PLIST (pl))
842 MFontFT *ft_info = MPLIST_VAL (p);
846 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
849 for (i = 0; i < len; i++)
850 if (FT_Get_Char_Index (ft_face,
851 (FT_ULong) mtext_ref_char (mt, i)) == 0)
853 FT_Done_Face (ft_face);
858 family = mfont_get_prop (&ft_info->font, Mfamily);
859 mplist_push (plist, family, ft_info);
864 #endif /* not HAVE_FONTCONFIG */
868 ft_list_script (MSymbol script)
870 MPlist *plist = NULL;
871 MPlist *language_list, *pl;
873 if (! ft_script_list)
874 ft_script_list = mplist ();
875 else if ((plist = mplist_find_by_key (ft_script_list, script)))
876 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
878 language_list = mlanguage__list (script);
879 MPLIST_DO (pl, language_list)
881 MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
882 MPlist *p = ft_list_language (language);
891 family = MPLIST_KEY (p);
892 if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
893 mplist_add (plist, family, MPLIST_VAL (p));
896 mplist_push (ft_script_list, script, plist);
897 M17N_OBJECT_UNREF (language_list);
902 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
904 if (ft_info->otf == invalid_otf)
908 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
911 ft_info->otf = invalid_otf;
915 if (cap->features[MFONT_OTT_GSUB].nfeatures
916 && cap->features[MFONT_OTT_GSUB].tags[0]
917 && (OTF_check_features
919 cap->script_tag, cap->langsys_tag,
920 cap->features[MFONT_OTT_GSUB].tags,
921 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
923 if (cap->features[MFONT_OTT_GPOS].nfeatures
924 && cap->features[MFONT_OTT_GPOS].tags[0]
925 && (OTF_check_features
927 cap->script_tag, cap->langsys_tag,
928 cap->features[MFONT_OTT_GPOS].tags,
929 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
935 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
937 #ifdef HAVE_FONTCONFIG
942 for (i = 0; cap->lang[i] != Mnil; i++)
945 && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
947 if (MPLIST_VAL (plist))
952 if (! ft_info->langset)
954 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
955 MSYMBOL_NAME (ft_info->font.file),
957 FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
958 FcFontSet *fs = FcFontList (fc_config, pat, os);
962 if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
964 ft_info->langset = FcLangSetCopy (ft_info->langset);
966 ft_info->langset = FcLangSetCreate ();
967 FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
968 FcFontSetDestroy (fs);
969 FcObjectSetDestroy (os);
970 FcPatternDestroy (pat);
973 ft_info->lang = mplist ();
974 if (FcLangSetHasLang (ft_info->langset,
975 (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
978 mplist_push (ft_info->lang, cap->lang[i], Mt);
982 mt = msymbol_get (cap->lang[i], Mtext);
985 mplist_push (ft_info->lang, cap->lang[i], Mnil);
989 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
990 if (! FcCharSetAddChar (ft_info->charset,
991 (FcChar32) mtext_ref_char (mt, j)))
993 mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
997 #endif /* HAVE_FONTCONFIG */
1001 static MPlist *ft_default_list;
1006 if (ft_default_list)
1007 return ft_default_list;
1008 ft_default_list = mplist ();
1009 #ifdef HAVE_FONTCONFIG
1011 FcPattern *pat = FcPatternCreate ();
1017 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1018 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1024 STRDUP_LOWER (buf, bufsize, (char *) fam);
1025 family = msymbol (buf);
1026 if (msymbol_get (family, Mgeneric_family))
1028 plist = MPLIST_PLIST (ft_list_family (family, 0));
1029 MPLIST_DO (plist, plist)
1030 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1033 #else /* not HAVE_FONTCONFIG */
1037 MPLIST_DO (plist, ft_list_family (Mnil, 0))
1039 pl = MPLIST_PLIST (plist);
1040 if (! MPLIST_TAIL_P (pl))
1041 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1044 #endif /* not HAVE_FONTCONFIG */
1045 return ft_default_list;
1049 static MPlist *ft_capability_list;
1052 ft_list_capability (MSymbol sym)
1054 MPlist *plist, *pl, *p;
1055 MFontCapability *cap = mfont__get_capability (sym);
1059 if (ft_capability_list)
1061 plist = mplist_find_by_key (ft_capability_list, sym);
1063 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1068 ft_capability_list = mplist ();
1071 if (cap->script != Mnil)
1073 pl = ft_list_script (cap->script);
1077 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1079 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
1083 mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
1085 mplist_push (ft_capability_list, sym, plist);
1093 for (i = 0; cap->lang[i] != Mnil; i++)
1095 p = ft_list_language (cap->lang[i]);
1101 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1105 mplist_push (ft_capability_list, sym, plist);
1111 ft_list_file (MSymbol filename)
1113 MPlist *plist = NULL;
1116 ft_file_list = mplist ();
1117 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1118 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1120 #ifdef HAVE_FONTCONFIG
1122 FcPattern *pattern = FcPatternCreate ();
1126 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1127 os = FcObjectSetBuild (FC_FAMILY, NULL);
1128 fs = FcFontList (fc_config, pattern, os);
1135 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1136 (FcChar8 **) &fam) == FcResultMatch)
1141 STRDUP_LOWER (buf, bufsize, fam);
1142 family = msymbol (buf);
1143 pl = ft_list_family (family, 0);
1144 MPLIST_DO (pl, MPLIST_PLIST (pl))
1146 MFontFT *ft_info = MPLIST_VAL (pl);
1148 if (ft_info->font.file == filename)
1151 mplist_add (plist, family, ft_info);
1158 #else /* not HAVE_FONTCONFIG */
1162 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1164 MPLIST_DO (p, MPLIST_PLIST (pl))
1166 MFontFT *ft_info = MPLIST_VAL (pl);
1168 if (ft_info->font.file == filename)
1171 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1179 #endif /* not HAVE_FONTCONFIG */
1181 mplist_push (ft_file_list, filename, plist);
1185 /* The FreeType font driver function SELECT. */
1188 ft_select (MFrame *frame, MFont *font, int limited_size)
1190 MFont *found = NULL;
1191 #ifdef HAVE_FONTCONFIG
1194 int check_font_property = 1;
1196 if (font->file != Mnil)
1198 plist = ft_list_file (font->file);
1201 check_font_property = 0;
1205 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1208 plist = MPLIST_PLIST (ft_list_family (family, 1));
1210 plist = ft_list_default ();
1211 if (MPLIST_TAIL_P (plist))
1215 plist = mplist_copy (plist);
1217 if (font->capability != Mnil)
1219 MFontCapability *cap = mfont__get_capability (font->capability);
1221 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1223 if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1224 || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1227 pl = MPLIST_NEXT (pl);
1231 if (check_font_property)
1233 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1234 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1235 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1236 MSymbol alternate_weight = Mnil;
1238 if (weight == Mnormal)
1239 alternate_weight = Mmedium;
1240 else if (weight == Mmedium)
1241 alternate_weight = Mnormal;
1242 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1243 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1245 ft_info = MPLIST_VAL (pl);
1247 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1248 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1250 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1252 && stretch != FONT_PROPERTY (&ft_info->font,
1255 && ft_info->font.size > 0
1256 && ft_info->font.size != font->size))
1259 pl = MPLIST_NEXT (pl);
1263 MPLIST_DO (pl, plist)
1265 font = MPLIST_VAL (plist);
1266 if (limited_size == 0
1268 || font->size <= limited_size)
1274 M17N_OBJECT_UNREF (plist);
1280 static MRealizedFont *
1281 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1283 MFontFT *ft_info = (MFontFT *) font;
1284 int reg = spec->property[MFONT_REGISTRY];
1285 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1286 MRealizedFontFT *ft_rfont;
1288 MPlist *plist, *charmap_list = NULL;
1290 int size = font->size ? font->size : spec->size;
1294 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1295 for (; rfont; rfont = rfont->next)
1296 if (rfont->font == font
1297 && (rfont->font->size ? rfont->font->size == size
1298 : rfont->spec.size == size)
1299 && rfont->spec.property[MFONT_REGISTRY] == reg
1300 && rfont->driver == &mfont__ft_driver)
1304 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (spec));
1306 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1309 font->type = MFONT_TYPE_FAILURE;
1310 MDEBUG_PRINT (" no\n");
1314 M17N_OBJECT_REF (charmap_list);
1316 charmap_list = ft_get_charmaps (ft_face);
1317 if (registry == Mnil)
1318 registry = Municode_bmp;
1319 plist = mplist_find_by_key (charmap_list, registry);
1322 FT_Done_Face (ft_face);
1323 M17N_OBJECT_UNREF (charmap_list);
1324 MDEBUG_PRINT (" no\n");
1327 charmap_index = (int) MPLIST_VAL (plist);
1328 if ((charmap_index >= 0
1329 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1330 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1332 FT_Done_Face (ft_face);
1333 M17N_OBJECT_UNREF (charmap_list);
1334 font->type = MFONT_TYPE_FAILURE;
1335 MDEBUG_PRINT (" no\n");
1339 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1340 ft_rfont->ft_face = ft_face;
1341 ft_rfont->charmap_list = charmap_list;
1342 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1343 rfont->spec = *font;
1344 rfont->spec.type = MFONT_TYPE_REALIZED;
1345 rfont->spec.property[MFONT_REGISTRY] = reg;
1346 rfont->spec.size = size;
1347 rfont->frame = frame;
1349 rfont->driver = &mfont__ft_driver;
1350 rfont->info = ft_rfont;
1351 rfont->fontp = ft_face;
1352 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1353 rfont->descent = - ft_face->size->metrics.descender >> 6;
1354 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1355 rfont->baseline_offset = 0;
1358 BDF_PropertyRec prop;
1360 if (! FT_IS_SCALABLE (ft_face)
1361 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1363 rfont->baseline_offset = prop.u.integer;
1364 rfont->ascent += prop.u.integer;
1365 rfont->descent -= prop.u.integer;
1369 if (FT_IS_SCALABLE (ft_face))
1370 rfont->average_width = 0;
1372 rfont->average_width = ft_face->available_sizes->width;
1373 rfont->next = MPLIST_VAL (frame->realized_font_list);
1374 MPLIST_VAL (frame->realized_font_list) = rfont;
1375 MDEBUG_PRINT (" ok\n");
1379 /* The FreeType font driver function FIND_METRIC. */
1382 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1385 FT_Face ft_face = rfont->fontp;
1386 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1388 for (; g != gend; g++)
1390 if (g->code == MCHAR_INVALID_CODE)
1392 if (FT_IS_SCALABLE (ft_face))
1394 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1395 int size = rfont->spec.size;
1398 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1399 g->width = g->rbearing;
1400 g->ascent = ft_face->ascender * size / unitsPerEm10;
1401 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1406 BDF_PropertyRec prop;
1410 g->rbearing = g->width = ft_face->available_sizes->width;
1412 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1414 g->ascent = prop.u.integer;
1415 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1416 g->descent = prop.u.integer;
1417 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1420 g->ascent += prop.u.integer;
1421 g->descent -= prop.u.integer;
1427 g->ascent = ft_face->available_sizes->height;
1434 FT_Glyph_Metrics *metrics;
1436 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1437 metrics = &ft_face->glyph->metrics;
1438 g->lbearing = (metrics->horiBearingX >> 6);
1439 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1440 g->width = metrics->horiAdvance >> 6;
1441 g->ascent = metrics->horiBearingY >> 6;
1442 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1444 g->ascent += rfont->baseline_offset;
1445 g->descent -= rfont->baseline_offset;
1450 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1452 MRealizedFont *rfont = NULL;
1453 MRealizedFontFT *ft_rfont;
1456 if (font->type == MFONT_TYPE_REALIZED)
1457 rfont = (MRealizedFont *) font;
1458 else if (font->type == MFONT_TYPE_OBJECT)
1460 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1461 rfont = rfont->next)
1462 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1466 #ifdef HAVE_FONTCONFIG
1467 MFontFT *ft_info = (MFontFT *) font;
1469 if (! ft_info->charset)
1471 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1472 MSYMBOL_NAME (font->file),
1474 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1475 FcFontSet *fs = FcFontList (fc_config, pat, os);
1478 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1479 &ft_info->charset) == FcResultMatch)
1480 ft_info->charset = FcCharSetCopy (ft_info->charset);
1482 ft_info->charset = FcCharSetCreate ();
1483 FcFontSetDestroy (fs);
1484 FcObjectSetDestroy (os);
1485 FcPatternDestroy (pat);
1487 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1488 #else /* not HAVE_FONTCONFIG */
1489 rfont = ft_open (frame, font, spec, NULL);
1490 #endif /* not HAVE_FONTCONFIG */
1494 MFATAL (MERROR_FONT_FT);
1498 ft_rfont = rfont->info;
1499 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1503 /* The FreeType font driver function ENCODE_CHAR. */
1506 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1508 MRealizedFont *rfont;
1509 MRealizedFontFT *ft_rfont;
1512 if (font->type == MFONT_TYPE_REALIZED)
1513 rfont = (MRealizedFont *) font;
1514 else if (font->type == MFONT_TYPE_OBJECT)
1516 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1517 rfont = rfont->next)
1518 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1522 rfont = ft_open (frame, font, spec, NULL);
1528 MFATAL (MERROR_FONT_FT);
1530 ft_rfont = rfont->info;
1531 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1532 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1535 /* The FreeType font driver function RENDER. */
1537 #define NUM_POINTS 0x1000
1540 MDrawPoint points[NUM_POINTS];
1545 ft_render (MDrawWindow win, int x, int y,
1546 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1547 int reverse, MDrawRegion region)
1550 MRealizedFace *rface = from->rface;
1551 MFrame *frame = rface->frame;
1552 FT_Int32 load_flags = FT_LOAD_RENDER;
1555 MPointTable point_table[8];
1556 int baseline_offset;
1561 /* It is assured that the all glyphs in the current range use the
1562 same realized face. */
1563 ft_face = rface->rfont->fontp;
1564 baseline_offset = rface->rfont->baseline_offset;
1566 if (! gstring->anti_alias)
1568 #ifdef FT_LOAD_TARGET_MONO
1569 load_flags |= FT_LOAD_TARGET_MONO;
1571 load_flags |= FT_LOAD_MONOCHROME;
1575 for (i = 0; i < 8; i++)
1576 point_table[i].p = point_table[i].points;
1578 for (g = from; g < to; x += g++->width)
1582 MPointTable *ptable;
1586 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1587 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1588 bmp = ft_face->glyph->bitmap.buffer;
1589 width = ft_face->glyph->bitmap.width;
1590 pitch = ft_face->glyph->bitmap.pitch;
1591 if (! gstring->anti_alias)
1596 if (gstring->anti_alias)
1597 for (i = 0; i < ft_face->glyph->bitmap.rows;
1598 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1600 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1601 for (j = 0; j < width; j++, xoff++)
1603 intensity = bmp[j] >> 5;
1606 ptable = point_table + intensity;
1607 ptable->p->x = xoff;
1608 ptable->p->y = yoff - baseline_offset;
1610 if (ptable->p - ptable->points == NUM_POINTS)
1612 (*frame->driver->draw_points)
1614 reverse ? 7 - intensity : intensity,
1615 ptable->points, NUM_POINTS, region);
1616 ptable->p = ptable->points;
1622 for (i = 0; i < ft_face->glyph->bitmap.rows;
1623 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1625 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1626 for (j = 0; j < width; j++, xoff++)
1628 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1631 ptable = point_table;
1632 ptable->p->x = xoff;
1633 ptable->p->y = yoff - baseline_offset;
1635 if (ptable->p - ptable->points == NUM_POINTS)
1637 (*frame->driver->draw_points) (frame, win, rface,
1639 ptable->points, NUM_POINTS, region);
1640 ptable->p = ptable->points;
1647 if (gstring->anti_alias)
1649 for (i = 1; i < 8; i++)
1650 if (point_table[i].p != point_table[i].points)
1651 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1652 point_table[i].points,
1653 point_table[i].p - point_table[i].points, region);
1657 if (point_table[0].p != point_table[0].points)
1658 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1659 point_table[0].points,
1660 point_table[0].p - point_table[0].points, region);
1665 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1667 MPlist *pl = NULL, *p;
1669 MPlist *file_list = NULL;
1670 MPlist *family_list = NULL, *capability_list = NULL;
1671 MSymbol registry = Mnil;
1673 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1679 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1680 if (registry != Mnil && registry != Miso8859_1)
1682 char *reg = MSYMBOL_NAME (registry);
1684 if (strncmp (reg, "unicode-", 8)
1685 && strncmp (reg, "apple-roman", 11)
1686 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1690 if (font->file != Mnil
1691 && ! (file_list = ft_list_file (font->file)))
1693 family = FONT_PROPERTY (font, MFONT_FAMILY);
1695 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1696 && MPLIST_TAIL_P (family_list))
1698 if (font->capability != Mnil)
1700 capability_list = ft_list_capability (font->capability);
1701 if (! capability_list || MPLIST_TAIL_P (capability_list))
1704 else if (family == Mnil)
1706 capability_list = ft_list_default ();
1710 if (! file_list && ! family_list && ! capability_list)
1712 /* No restriction. Get all fonts. */
1714 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1716 MPLIST_DO (p, MPLIST_PLIST (family_list))
1717 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1725 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1730 for (p = pl; ! MPLIST_TAIL_P (p);)
1732 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1733 p = MPLIST_NEXT (p);
1740 MPLIST_DO (p, family_list)
1741 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1744 if (capability_list)
1747 for (p = pl; ! MPLIST_TAIL_P (p);)
1749 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1750 p = MPLIST_NEXT (p);
1757 MPLIST_DO (p, capability_list)
1758 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1764 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1765 + font->property[MFONT_STRETCH] + font->size) > 0)
1767 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1768 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1769 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1770 int size = font->size;
1772 for (p = pl; ! MPLIST_TAIL_P (p); )
1774 MFontFT *ft_info = MPLIST_VAL (p);
1777 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1779 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1781 && stretch != FONT_PROPERTY (&ft_info->font,
1784 && ft_info->font.size > 0
1785 && ft_info->font.size != size))
1788 p = MPLIST_NEXT (p);
1794 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1796 if (maxnum && maxnum <= num)
1799 M17N_OBJECT_UNREF (pl);
1802 MDEBUG_PRINT1 (" %d found\n", num);
1809 MFontDriver mfont__ft_driver =
1810 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1811 ft_render, ft_list };
1818 if (FT_Init_FreeType (&ft_library) != 0)
1819 MERROR (MERROR_FONT_FT, -1);
1821 for (i = 0; i < ft_to_prop_size; i++)
1822 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1824 Mmedium = msymbol ("medium");
1826 Mnull = msymbol ("");
1828 M0_3 = msymbol ("0-3");
1829 M3_1 = msymbol ("3-1");
1830 M1_0 = msymbol ("1-0");
1832 #ifdef HAVE_FONTCONFIG
1833 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1835 FC_vs_M17N_font_prop *table = fc_all_table[i];
1838 for (j = 0; table[j].m17n_value; j++)
1839 table[j].sym = msymbol (table[j].m17n_value);
1840 table[j].sym = table[j - 1].sym;
1847 MSymbol serif, sans_serif, monospace;
1849 fc_config = FcInitLoadConfigAndFonts ();
1850 if (mfont_freetype_path)
1852 MPLIST_DO (plist, mfont_freetype_path)
1853 if (MPLIST_STRING_P (plist)
1854 && (pathname = MPLIST_STRING (plist))
1855 && stat (pathname, &buf) == 0)
1857 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1860 while ((dir = FcStrListNext (strlist)))
1861 if (strcmp ((char *) dir, pathname) == 0)
1864 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1865 FcStrListDone (strlist);
1868 Mgeneric_family = msymbol ("generic famly");
1869 serif = msymbol ("serif");
1870 msymbol_put (serif, Mgeneric_family, serif);
1871 sans_serif = msymbol ("sans-serif");
1872 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1873 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1874 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1875 monospace = msymbol ("monospace");
1876 msymbol_put (monospace, Mgeneric_family, monospace);
1877 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1889 if (ft_default_list)
1891 M17N_OBJECT_UNREF (ft_default_list);
1892 ft_default_list = NULL;
1897 MPLIST_DO (plist, ft_font_list)
1899 if (MPLIST_VAL (plist))
1900 MPLIST_DO (p, MPLIST_VAL (plist))
1902 if (MPLIST_KEY (p) != Mt)
1903 free_ft_info (MPLIST_VAL (p));
1905 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1907 M17N_OBJECT_UNREF (ft_font_list);
1908 ft_font_list = NULL;
1910 if (ft_language_list)
1912 MPLIST_DO (plist, ft_language_list)
1913 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1914 M17N_OBJECT_UNREF (ft_language_list);
1915 ft_language_list = NULL;
1920 MPLIST_DO (plist, ft_script_list)
1921 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1922 M17N_OBJECT_UNREF (ft_script_list);
1923 ft_script_list = NULL;
1926 if (ft_capability_list)
1928 MPLIST_DO (plist, ft_capability_list)
1929 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1930 M17N_OBJECT_UNREF (ft_capability_list);
1931 ft_capability_list = NULL;
1936 MPLIST_DO (plist, ft_file_list)
1937 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1938 M17N_OBJECT_UNREF (ft_file_list);
1939 ft_file_list = NULL;
1942 FT_Done_FreeType (ft_library);
1943 #ifdef HAVE_FONTCONFIG
1944 FcConfigDestroy (fc_config);
1946 #endif /* HAVE_FONTCONFIG */
1947 all_fonts_scaned = 0;
1950 #ifdef HAVE_FONTCONFIG
1953 mfont__ft_parse_name (const char *name, MFont *font)
1955 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1964 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1966 STRDUP_LOWER (buf, bufsize, (char *) str);
1967 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1969 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1971 STRDUP_LOWER (buf, bufsize, (char *) str);
1972 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1974 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1975 mfont__set_property (font, MFONT_WEIGHT,
1976 fc_decode_prop (val, fc_weight_table,
1977 fc_weight_table_size));
1978 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1979 mfont__set_property (font, MFONT_STYLE,
1980 fc_decode_prop (val, fc_slant_table,
1981 fc_slant_table_size));
1982 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1983 mfont__set_property (font, MFONT_STRETCH,
1984 fc_decode_prop (val, fc_width_table,
1985 fc_width_table_size));
1986 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1987 font->size = size * 10 + 0.5;
1988 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1989 font->size = - (size * 10 + 0.5);
1990 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1992 font->file = msymbol ((char *) str);
1994 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1995 font->type = MFONT_TYPE_SPEC;
1996 FcPatternDestroy (pat);
2001 mfont__ft_unparse_name (MFont *font)
2003 FcPattern *pat = fc_get_pattern (font);
2004 char *name = (char *) FcNameUnparse (pat);
2006 FcPatternDestroy (pat);
2009 #endif /* HAVE_FONTCONFIG */
2014 #define DEVICE_DELTA(table, size) \
2015 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2016 ? (table).DeltaValue[(size) >= (table).StartSize] \
2020 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2021 unsigned code, int size, int *x, int *y)
2023 if (anchor->AnchorFormat == 2)
2025 FT_Outline *outline;
2026 int ap = anchor->f.f1.AnchorPoint;
2028 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2029 outline = &ft_face->glyph->outline;
2030 if (ap < outline->n_points)
2032 *x = outline->points[ap].x;
2033 *y = outline->points[ap].y;
2036 else if (anchor->AnchorFormat == 3)
2038 if (anchor->f.f2.XDeviceTable.offset)
2039 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2040 if (anchor->f.f2.YDeviceTable.offset)
2041 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2046 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2047 MFontCapability *cap)
2049 int len = to - from;
2050 MGlyph *g = MGLYPH (from);
2052 MRealizedFont *rfont;
2055 OTF_GlyphString otf_gstring;
2057 char *script, *langsys;
2058 char *gsub_features, *gpos_features;
2064 otf_gstring.glyphs = NULL;
2065 rfont = g->rface->rfont;
2066 ft_info = (MFontFT *) rfont->font;
2067 if (ft_info->otf == invalid_otf)
2072 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2075 ft_info->otf = invalid_otf;
2080 if (OTF_get_table (otf, "head") < 0)
2083 ft_info->otf = invalid_otf;
2087 if (cap->script_tag)
2089 script = alloca (5);
2090 OTF_tag_name (cap->script_tag, script);
2094 if (cap->langsys_tag)
2096 langsys = alloca (5);
2097 OTF_tag_name (cap->langsys_tag, langsys);
2101 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2102 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2103 gsub_features = NULL;
2104 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2105 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2106 gpos_features = NULL;
2108 otf_gstring.size = otf_gstring.used = len;
2109 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2110 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2111 for (i = 0, need_cmap = 0; i < len; i++)
2113 if (gstring->glyphs[from + i].otf_encoded)
2115 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2116 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2120 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2125 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2128 OTF_drive_gdef (otf, &otf_gstring);
2129 gidx = gstring->used;
2133 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2136 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2138 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2141 temp.combining_code = 0;
2144 temp.code = otfg->glyph_id;
2145 temp.otf_encoded = 1;
2150 temp.otf_encoded = 0;
2152 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2153 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2157 for (i = 0; i < len; i++)
2159 MGlyph temp = gstring->glyphs[from + i];
2161 if (otf_gstring.glyphs[i].glyph_id)
2163 temp.code = otf_gstring.glyphs[i].glyph_id;
2164 temp.otf_encoded = 1;
2166 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2169 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2175 MGlyph *base = NULL, *mark = NULL;
2177 if (OTF_check_features (otf, 1,
2178 cap->script_tag, cap->langsys_tag,
2179 cap->features[MFONT_OTT_GPOS].tags,
2180 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2181 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2182 gpos_features) < 0))
2185 u = otf->head->unitsPerEm;
2186 size10 = rfont->spec.size;
2189 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2190 i < otf_gstring.used; i++, otfg++, g++)
2194 if (! otfg->glyph_id)
2196 switch (otfg->positioning_type)
2202 int format = otfg->f.f1.format;
2204 if (format & OTF_XPlacement)
2205 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2206 if (format & OTF_XPlaDevice)
2207 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2208 if (format & OTF_YPlacement)
2209 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2210 if (format & OTF_YPlaDevice)
2211 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2212 if (format & OTF_XAdvance)
2213 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2214 if (format & OTF_XAdvDevice)
2215 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2219 /* Not yet supported. */
2225 goto label_adjust_anchor;
2226 default: /* i.e. case 6 */
2231 label_adjust_anchor:
2233 int base_x, base_y, mark_x, mark_y;
2235 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2236 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2237 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2238 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2240 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2241 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2242 prev->code, size, &base_x, &base_y);
2243 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2244 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2245 g->code, size, &mark_x, &mark_y);
2246 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2247 g->yoff = prev->yoff + mark_y - base_y;
2248 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2251 if (otfg->GlyphClass == OTF_GlyphClass0)
2253 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2259 free (otf_gstring.glyphs);
2263 ft_find_metric (rfont, gstring, from, to);
2264 for (i = 0; i < len; i++)
2266 MGlyph temp = gstring->glyphs[from + i];
2267 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2269 if (otf_gstring.glyphs)
2270 free (otf_gstring.glyphs);
2276 mfont__ft_decode_otf (MGlyph *g)
2278 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2279 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2281 return (c ? c : -1);
2284 #endif /* HAVE_OTF */
2286 #endif /* HAVE_FREETYPE */