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;
1370 rfont->next = MPLIST_VAL (frame->realized_font_list);
1371 MPLIST_VAL (frame->realized_font_list) = rfont;
1372 MDEBUG_PRINT (" ok\n");
1376 /* The FreeType font driver function FIND_METRIC. */
1379 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1382 FT_Face ft_face = rfont->fontp;
1383 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1385 for (; g != gend; g++)
1387 if (g->code == MCHAR_INVALID_CODE)
1389 if (FT_IS_SCALABLE (ft_face))
1391 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1392 int size = rfont->spec.size;
1395 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1396 g->width = g->rbearing;
1397 g->ascent = ft_face->ascender * size / unitsPerEm10;
1398 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1403 BDF_PropertyRec prop;
1407 g->rbearing = g->width = ft_face->available_sizes->width;
1409 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1411 g->ascent = prop.u.integer;
1412 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1413 g->descent = prop.u.integer;
1414 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1417 g->ascent += prop.u.integer;
1418 g->descent -= prop.u.integer;
1424 g->ascent = ft_face->available_sizes->height;
1431 FT_Glyph_Metrics *metrics;
1433 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1434 metrics = &ft_face->glyph->metrics;
1435 g->lbearing = (metrics->horiBearingX >> 6);
1436 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1437 g->width = metrics->horiAdvance >> 6;
1438 g->ascent = metrics->horiBearingY >> 6;
1439 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1441 g->ascent += rfont->baseline_offset;
1442 g->descent -= rfont->baseline_offset;
1447 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1449 MRealizedFont *rfont = NULL;
1450 MRealizedFontFT *ft_rfont;
1453 if (font->type == MFONT_TYPE_REALIZED)
1454 rfont = (MRealizedFont *) font;
1455 else if (font->type == MFONT_TYPE_OBJECT)
1457 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1458 rfont = rfont->next)
1459 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1463 #ifdef HAVE_FONTCONFIG
1464 MFontFT *ft_info = (MFontFT *) font;
1466 if (! ft_info->charset)
1468 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1469 MSYMBOL_NAME (font->file),
1471 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1472 FcFontSet *fs = FcFontList (fc_config, pat, os);
1475 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1476 &ft_info->charset) == FcResultMatch)
1477 ft_info->charset = FcCharSetCopy (ft_info->charset);
1479 ft_info->charset = FcCharSetCreate ();
1480 FcFontSetDestroy (fs);
1481 FcObjectSetDestroy (os);
1482 FcPatternDestroy (pat);
1484 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1485 #else /* not HAVE_FONTCONFIG */
1486 rfont = ft_open (frame, font, spec, NULL);
1487 #endif /* not HAVE_FONTCONFIG */
1491 MFATAL (MERROR_FONT_FT);
1495 ft_rfont = rfont->info;
1496 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1500 /* The FreeType font driver function ENCODE_CHAR. */
1503 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1505 MRealizedFont *rfont;
1506 MRealizedFontFT *ft_rfont;
1509 if (font->type == MFONT_TYPE_REALIZED)
1510 rfont = (MRealizedFont *) font;
1511 else if (font->type == MFONT_TYPE_OBJECT)
1513 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1514 rfont = rfont->next)
1515 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1519 rfont = ft_open (frame, font, spec, NULL);
1525 MFATAL (MERROR_FONT_FT);
1527 ft_rfont = rfont->info;
1528 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1529 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1532 /* The FreeType font driver function RENDER. */
1534 #define NUM_POINTS 0x1000
1537 MDrawPoint points[NUM_POINTS];
1542 ft_render (MDrawWindow win, int x, int y,
1543 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1544 int reverse, MDrawRegion region)
1547 MRealizedFace *rface = from->rface;
1548 MFrame *frame = rface->frame;
1549 FT_Int32 load_flags = FT_LOAD_RENDER;
1552 MPointTable point_table[8];
1553 int baseline_offset;
1558 /* It is assured that the all glyphs in the current range use the
1559 same realized face. */
1560 ft_face = rface->rfont->fontp;
1561 baseline_offset = rface->rfont->baseline_offset;
1563 if (! gstring->anti_alias)
1565 #ifdef FT_LOAD_TARGET_MONO
1566 load_flags |= FT_LOAD_TARGET_MONO;
1568 load_flags |= FT_LOAD_MONOCHROME;
1572 for (i = 0; i < 8; i++)
1573 point_table[i].p = point_table[i].points;
1575 for (g = from; g < to; x += g++->width)
1579 MPointTable *ptable;
1583 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1584 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1585 bmp = ft_face->glyph->bitmap.buffer;
1586 width = ft_face->glyph->bitmap.width;
1587 pitch = ft_face->glyph->bitmap.pitch;
1588 if (! gstring->anti_alias)
1593 if (gstring->anti_alias)
1594 for (i = 0; i < ft_face->glyph->bitmap.rows;
1595 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1597 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1598 for (j = 0; j < width; j++, xoff++)
1600 intensity = bmp[j] >> 5;
1603 ptable = point_table + intensity;
1604 ptable->p->x = xoff;
1605 ptable->p->y = yoff - baseline_offset;
1607 if (ptable->p - ptable->points == NUM_POINTS)
1609 (*frame->driver->draw_points)
1611 reverse ? 7 - intensity : intensity,
1612 ptable->points, NUM_POINTS, region);
1613 ptable->p = ptable->points;
1619 for (i = 0; i < ft_face->glyph->bitmap.rows;
1620 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1622 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1623 for (j = 0; j < width; j++, xoff++)
1625 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1628 ptable = point_table;
1629 ptable->p->x = xoff;
1630 ptable->p->y = yoff - baseline_offset;
1632 if (ptable->p - ptable->points == NUM_POINTS)
1634 (*frame->driver->draw_points) (frame, win, rface,
1636 ptable->points, NUM_POINTS, region);
1637 ptable->p = ptable->points;
1644 if (gstring->anti_alias)
1646 for (i = 1; i < 8; i++)
1647 if (point_table[i].p != point_table[i].points)
1648 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1649 point_table[i].points,
1650 point_table[i].p - point_table[i].points, region);
1654 if (point_table[0].p != point_table[0].points)
1655 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1656 point_table[0].points,
1657 point_table[0].p - point_table[0].points, region);
1662 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1664 MPlist *pl = NULL, *p;
1666 MPlist *file_list = NULL;
1667 MPlist *family_list = NULL, *capability_list = NULL;
1668 MSymbol registry = Mnil;
1670 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1676 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1677 if (registry != Mnil && registry != Miso8859_1)
1679 char *reg = MSYMBOL_NAME (registry);
1681 if (strncmp (reg, "unicode-", 8)
1682 && strncmp (reg, "apple-roman", 11)
1683 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1687 if (font->file != Mnil
1688 && ! (file_list = ft_list_file (font->file)))
1690 family = FONT_PROPERTY (font, MFONT_FAMILY);
1692 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1693 && MPLIST_TAIL_P (family_list))
1695 if (font->capability != Mnil)
1697 capability_list = ft_list_capability (font->capability);
1698 if (! capability_list || MPLIST_TAIL_P (capability_list))
1701 else if (family == Mnil)
1703 capability_list = ft_list_default ();
1707 if (! file_list && ! family_list && ! capability_list)
1709 /* No restriction. Get all fonts. */
1711 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1713 MPLIST_DO (p, MPLIST_PLIST (family_list))
1714 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1722 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1727 for (p = pl; ! MPLIST_TAIL_P (p);)
1729 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1730 p = MPLIST_NEXT (p);
1737 MPLIST_DO (p, family_list)
1738 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1741 if (capability_list)
1744 for (p = pl; ! MPLIST_TAIL_P (p);)
1746 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1747 p = MPLIST_NEXT (p);
1754 MPLIST_DO (p, capability_list)
1755 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1761 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1762 + font->property[MFONT_STRETCH] + font->size) > 0)
1764 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1765 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1766 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1767 int size = font->size;
1769 for (p = pl; ! MPLIST_TAIL_P (p); )
1771 MFontFT *ft_info = MPLIST_VAL (p);
1774 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1776 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1778 && stretch != FONT_PROPERTY (&ft_info->font,
1781 && ft_info->font.size > 0
1782 && ft_info->font.size != size))
1785 p = MPLIST_NEXT (p);
1791 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1793 if (maxnum && maxnum <= num)
1796 M17N_OBJECT_UNREF (pl);
1799 MDEBUG_PRINT1 (" %d found\n", num);
1806 MFontDriver mfont__ft_driver =
1807 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1808 ft_render, ft_list };
1815 if (FT_Init_FreeType (&ft_library) != 0)
1816 MERROR (MERROR_FONT_FT, -1);
1818 for (i = 0; i < ft_to_prop_size; i++)
1819 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1821 Mmedium = msymbol ("medium");
1823 Mnull = msymbol ("");
1825 M0_3 = msymbol ("0-3");
1826 M3_1 = msymbol ("3-1");
1827 M1_0 = msymbol ("1-0");
1829 #ifdef HAVE_FONTCONFIG
1830 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1832 FC_vs_M17N_font_prop *table = fc_all_table[i];
1835 for (j = 0; table[j].m17n_value; j++)
1836 table[j].sym = msymbol (table[j].m17n_value);
1837 table[j].sym = table[j - 1].sym;
1844 MSymbol serif, sans_serif, monospace;
1846 fc_config = FcInitLoadConfigAndFonts ();
1847 if (mfont_freetype_path)
1849 MPLIST_DO (plist, mfont_freetype_path)
1850 if (MPLIST_STRING_P (plist)
1851 && (pathname = MPLIST_STRING (plist))
1852 && stat (pathname, &buf) == 0)
1854 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1857 while ((dir = FcStrListNext (strlist)))
1858 if (strcmp ((char *) dir, pathname) == 0)
1861 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1862 FcStrListDone (strlist);
1865 Mgeneric_family = msymbol ("generic famly");
1866 serif = msymbol ("serif");
1867 msymbol_put (serif, Mgeneric_family, serif);
1868 sans_serif = msymbol ("sans-serif");
1869 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1870 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1871 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1872 monospace = msymbol ("monospace");
1873 msymbol_put (monospace, Mgeneric_family, monospace);
1874 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1888 MPLIST_DO (plist, ft_font_list)
1890 if (MPLIST_VAL (plist))
1891 MPLIST_DO (p, MPLIST_VAL (plist))
1893 if (MPLIST_KEY (p) != Mt)
1894 free_ft_info (MPLIST_VAL (p));
1896 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1898 M17N_OBJECT_UNREF (ft_font_list);
1900 if (ft_language_list)
1902 MPLIST_DO (plist, ft_language_list)
1903 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1904 M17N_OBJECT_UNREF (ft_language_list);
1909 MPLIST_DO (plist, ft_script_list)
1910 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1911 M17N_OBJECT_UNREF (ft_script_list);
1914 if (ft_capability_list)
1916 MPLIST_DO (plist, ft_capability_list)
1917 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1918 M17N_OBJECT_UNREF (ft_capability_list);
1923 MPLIST_DO (plist, ft_file_list)
1924 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1925 M17N_OBJECT_UNREF (ft_file_list);
1929 FT_Done_FreeType (ft_library);
1930 #ifdef HAVE_FONTCONFIG
1931 FcConfigDestroy (fc_config);
1933 #endif /* HAVE_FONTCONFIG */
1934 all_fonts_scaned = 0;
1937 #ifdef HAVE_FONTCONFIG
1940 mfont__ft_parse_name (const char *name, MFont *font)
1942 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1951 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1953 STRDUP_LOWER (buf, bufsize, (char *) str);
1954 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1956 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1958 STRDUP_LOWER (buf, bufsize, (char *) str);
1959 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1961 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1962 mfont__set_property (font, MFONT_WEIGHT,
1963 fc_decode_prop (val, fc_weight_table,
1964 fc_weight_table_size));
1965 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1966 mfont__set_property (font, MFONT_STYLE,
1967 fc_decode_prop (val, fc_slant_table,
1968 fc_slant_table_size));
1969 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1970 mfont__set_property (font, MFONT_STRETCH,
1971 fc_decode_prop (val, fc_width_table,
1972 fc_width_table_size));
1973 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1974 font->size = size * 10 + 0.5;
1975 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1976 font->size = - (size * 10 + 0.5);
1977 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1979 font->file = msymbol ((char *) str);
1981 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1982 font->type = MFONT_TYPE_SPEC;
1983 FcPatternDestroy (pat);
1988 mfont__ft_unparse_name (MFont *font)
1990 FcPattern *pat = fc_get_pattern (font);
1991 char *name = (char *) FcNameUnparse (pat);
1993 FcPatternDestroy (pat);
1996 #endif /* HAVE_FONTCONFIG */
2001 #define DEVICE_DELTA(table, size) \
2002 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2003 ? (table).DeltaValue[(size) >= (table).StartSize] \
2007 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2008 unsigned code, int size, int *x, int *y)
2010 if (anchor->AnchorFormat == 2)
2012 FT_Outline *outline;
2013 int ap = anchor->f.f1.AnchorPoint;
2015 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2016 outline = &ft_face->glyph->outline;
2017 if (ap < outline->n_points)
2019 *x = outline->points[ap].x;
2020 *y = outline->points[ap].y;
2023 else if (anchor->AnchorFormat == 3)
2025 if (anchor->f.f2.XDeviceTable.offset)
2026 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
2027 if (anchor->f.f2.YDeviceTable.offset)
2028 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
2033 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
2034 MFontCapability *cap)
2036 int len = to - from;
2037 MGlyph *g = MGLYPH (from);
2039 MRealizedFont *rfont;
2042 OTF_GlyphString otf_gstring;
2044 char *script, *langsys;
2045 char *gsub_features, *gpos_features;
2051 otf_gstring.glyphs = NULL;
2052 rfont = g->rface->rfont;
2053 ft_info = (MFontFT *) rfont->font;
2054 if (ft_info->otf == invalid_otf)
2059 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2062 ft_info->otf = invalid_otf;
2067 if (OTF_get_table (otf, "head") < 0)
2070 ft_info->otf = invalid_otf;
2074 if (cap->script_tag)
2076 script = alloca (5);
2077 OTF_tag_name (cap->script_tag, script);
2081 if (cap->langsys_tag)
2083 langsys = alloca (5);
2084 OTF_tag_name (cap->langsys_tag, langsys);
2088 gsub_features = cap->features[MFONT_OTT_GSUB].str;
2089 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
2090 gsub_features = NULL;
2091 gpos_features = cap->features[MFONT_OTT_GPOS].str;
2092 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
2093 gpos_features = NULL;
2095 otf_gstring.size = otf_gstring.used = len;
2096 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2097 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2098 for (i = 0, need_cmap = 0; i < len; i++)
2100 if (gstring->glyphs[from + i].otf_encoded)
2102 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
2103 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
2107 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
2112 && OTF_drive_cmap (otf, &otf_gstring) < 0)
2115 OTF_drive_gdef (otf, &otf_gstring);
2116 gidx = gstring->used;
2120 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
2123 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
2125 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
2128 temp.combining_code = 0;
2131 temp.code = otfg->glyph_id;
2132 temp.otf_encoded = 1;
2137 temp.otf_encoded = 0;
2139 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2140 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2144 for (i = 0; i < len; i++)
2146 MGlyph temp = gstring->glyphs[from + i];
2148 if (otf_gstring.glyphs[i].glyph_id)
2150 temp.code = otf_gstring.glyphs[i].glyph_id;
2151 temp.otf_encoded = 1;
2153 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2156 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2162 MGlyph *base = NULL, *mark = NULL;
2164 if (OTF_check_features (otf, 1,
2165 cap->script_tag, cap->langsys_tag,
2166 cap->features[MFONT_OTT_GPOS].tags,
2167 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2168 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2169 gpos_features) < 0))
2172 u = otf->head->unitsPerEm;
2173 size10 = rfont->spec.size;
2176 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2177 i < otf_gstring.used; i++, otfg++, g++)
2181 if (! otfg->glyph_id)
2183 switch (otfg->positioning_type)
2189 int format = otfg->f.f1.format;
2191 if (format & OTF_XPlacement)
2192 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2193 if (format & OTF_XPlaDevice)
2194 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2195 if (format & OTF_YPlacement)
2196 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2197 if (format & OTF_YPlaDevice)
2198 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2199 if (format & OTF_XAdvance)
2200 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2201 if (format & OTF_XAdvDevice)
2202 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2206 /* Not yet supported. */
2212 goto label_adjust_anchor;
2213 default: /* i.e. case 6 */
2218 label_adjust_anchor:
2220 int base_x, base_y, mark_x, mark_y;
2222 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2223 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2224 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2225 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2227 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2228 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2229 prev->code, size, &base_x, &base_y);
2230 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2231 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2232 g->code, size, &mark_x, &mark_y);
2233 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2234 g->yoff = prev->yoff + mark_y - base_y;
2235 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2238 if (otfg->GlyphClass == OTF_GlyphClass0)
2240 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2246 free (otf_gstring.glyphs);
2250 ft_find_metric (rfont, gstring, from, to);
2251 for (i = 0; i < len; i++)
2253 MGlyph temp = gstring->glyphs[from + i];
2254 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2256 if (otf_gstring.glyphs)
2257 free (otf_gstring.glyphs);
2263 mfont__ft_decode_otf (MGlyph *g)
2265 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2266 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2268 return (c ? c : -1);
2271 #endif /* HAVE_OTF */
2273 #endif /* HAVE_FREETYPE */