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)
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)
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)
209 mplist_add (plist, Municode_full, (void *) unicode_full);
210 mplist_add (plist, Municode_bmp, (void *) unicode_full);
212 else if (unicode_bmp >= 0)
214 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
219 #ifdef HAVE_FONTCONFIG
226 } FC_vs_M17N_font_prop;
228 static FC_vs_M17N_font_prop fc_weight_table[] =
229 { { FC_WEIGHT_THIN, "thin" },
230 { FC_WEIGHT_ULTRALIGHT, "extralight" },
231 { FC_WEIGHT_LIGHT, "light" },
232 #ifdef FC_WEIGHT_BOOK
233 { FC_WEIGHT_BOOK, "book" },
234 #endif /* FC_WEIGHT_BOOK */
235 { FC_WEIGHT_NORMAL, "normal" },
236 { FC_WEIGHT_MEDIUM, "medium" },
237 { FC_WEIGHT_DEMIBOLD, "demibold" },
238 { FC_WEIGHT_BOLD, "bold" },
239 { FC_WEIGHT_EXTRABOLD, "extrabold" },
240 { FC_WEIGHT_BLACK, "black" },
241 { FC_WEIGHT_HEAVY, "heavy" },
242 { FC_WEIGHT_MEDIUM, NULL } };
243 int fc_weight_table_size =
244 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
246 static FC_vs_M17N_font_prop fc_slant_table[] =
247 { { FC_SLANT_ROMAN, "r" },
248 { FC_SLANT_ITALIC, "i" },
249 { FC_SLANT_OBLIQUE, "o" },
250 { FC_SLANT_ROMAN, NULL } };
251 int fc_slant_table_size =
252 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
254 static FC_vs_M17N_font_prop fc_width_table[] =
255 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
256 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
257 { FC_WIDTH_CONDENSED, "condensed" },
258 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
259 { FC_WIDTH_NORMAL, "normal" },
260 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
261 { FC_WIDTH_EXPANDED, "expanded" },
262 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
263 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
264 { FC_WIDTH_NORMAL, NULL } };
265 int fc_width_table_size =
266 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
269 static FC_vs_M17N_font_prop *fc_all_table[] =
270 { fc_weight_table, fc_slant_table, fc_width_table };
273 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
277 if (val < table[i].fc_value)
279 for (i--; i >= 0; i--)
280 if (val > table[i].fc_value)
286 for (; i < size; i++)
287 if (val <= table[i].fc_value)
294 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
298 for (i = 0; table[i].m17n_value; i++)
299 if (table[i].sym == sym)
301 return table[i].fc_value;
305 fc_get_pattern (MFont *font)
307 FcPattern *pat = FcPatternCreate ();
308 MSymbol sym, weight, style, stretch;
311 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
312 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
313 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
314 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
315 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
316 FcPatternAddInteger (pat, FC_WEIGHT,
317 fc_encode_prop (weight, fc_weight_table));
318 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
319 FcPatternAddInteger (pat, FC_SLANT,
320 fc_encode_prop (style, fc_slant_table));
321 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
322 FcPatternAddInteger (pat, FC_WIDTH,
323 fc_encode_prop (stretch, fc_width_table));
326 double size = font->size;
327 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
329 else if (font->size < 0)
331 double size = - font->size;
332 FcPatternAddDouble (pat, FC_SIZE, size / 10);
338 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
348 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
350 STRDUP_LOWER (buf, bufsize, (char *) str);
351 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
354 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
355 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
357 STRDUP_LOWER (buf, bufsize, (char *) str);
358 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
360 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
362 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
363 mfont__set_property (font, MFONT_WEIGHT, sym);
365 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
367 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
368 mfont__set_property (font, MFONT_STYLE, sym);
370 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
372 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
373 mfont__set_property (font, MFONT_STRETCH, sym);
375 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
376 font->type = MFONT_TYPE_SPEC;
377 font->source = MFONT_SOURCE_FT;
378 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
379 font->size = size * 10;
380 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
381 font->file = msymbol ((char *) str);
386 fc_gen_font (FcPattern *pat, char *family)
390 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
391 fc_parse_pattern (pat, family, &ft_info->font);
392 ft_info->font.type = MFONT_TYPE_OBJECT;
396 #else /* not HAVE_FONTCONFIG */
399 ft_add_font (char *filename)
412 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
414 if (! FT_IS_SCALABLE (ft_face))
418 BDF_PropertyRec prop;
420 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
421 size = prop.u.integer * 10;
422 #else /* not HAVE_FTBDF_H */
424 #endif /* not HAVE_FTBDF_H */
427 FT_Done_Face (ft_face);
432 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
433 font = &ft_info->font;
434 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
435 family = msymbol (buf);
436 mfont__set_property (font, MFONT_FAMILY, family);
437 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
438 mfont__set_property (font, MFONT_STYLE, Mr);
439 mfont__set_property (font, MFONT_STRETCH, Mnormal);
440 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
441 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
442 font->type = MFONT_TYPE_OBJECT;
443 font->source = MFONT_SOURCE_FT;
445 font->file = msymbol (filename);
447 stylename = ft_face->style_name;
450 for (i = 0; i < ft_to_prop_size; i++)
451 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
454 mfont__set_property (font, ft_to_prop[i].prop,
455 msymbol (ft_to_prop[i].val));
456 stylename += ft_to_prop[i].len;
459 if (i == ft_to_prop_size)
461 char *p1 = stylename + 1;
464 while (*p1 >= 'a' && *p1 <= 'z') p1++;
465 sym = msymbol__with_len (stylename, p1 - stylename);
466 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
467 if (msymbol_get (sym, mfont__property_table[i].property))
469 mfont__set_property (font, i, sym);
474 while (*stylename && ! isalpha (*stylename))
478 FT_Done_Face (ft_face);
480 plist = mplist_find_by_key (ft_font_list, family);
482 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
486 mplist_add (plist, font->file, ft_info);
487 plist = mplist_push (ft_font_list, family, plist);
492 #endif /* not HAVE_FONTCONFIG */
495 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
496 scan all fonts and return ft_font_list. */
499 ft_list_family (MSymbol family, int check_generic)
502 #ifdef HAVE_FONTCONFIG
517 plist = ft_font_list = mplist ();
518 pattern = FcPatternCreate ();
519 os = FcObjectSetBuild (FC_FAMILY, NULL);
520 fs = FcFontList (fc_config, pattern, os);
521 for (i = 0; i < fs->nfont; i++)
523 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
524 (FcChar8 **) &fam) != FcResultMatch)
526 STRDUP_LOWER (buf, bufsize, fam);
528 if (! mplist_find_by_key (ft_font_list, sym))
529 plist = mplist_add (plist, sym, NULL);
531 FcFontSetDestroy (fs);
532 FcObjectSetDestroy (os);
533 FcPatternDestroy (pattern);
538 if (! all_fonts_scaned)
540 MPLIST_DO (plist, ft_font_list)
542 if (! MPLIST_VAL (plist))
543 ft_list_family (MPLIST_KEY (plist), 0);
545 all_fonts_scaned = 1;
550 plist = mplist_find_by_key (ft_font_list, family);
553 if (! MPLIST_VAL (plist))
555 fam = MSYMBOL_NAME (family);
556 pattern = FcPatternCreate ();
557 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
558 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
559 FC_PIXEL_SIZE, FC_FILE, NULL);
560 fs = FcFontList (fc_config, pattern, os);
562 for (i = 0; i < fs->nfont; i++)
564 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
565 p = mplist_add (p, ft_info->font.file, ft_info);
567 MPLIST_VAL (plist) = pl;
568 FcFontSetDestroy (fs);
569 FcObjectSetDestroy (os);
570 FcPatternDestroy (pattern);
573 else if (check_generic
574 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
576 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
579 if (family != generic)
580 plist = ft_list_family (generic, 1);
583 fam = MSYMBOL_NAME (family);
585 mplist_push (ft_font_list, family, plist);
586 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
587 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
590 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
593 STRDUP_LOWER (buf, bufsize, (char *) fam8);
594 family = msymbol (buf);
595 if (msymbol_get (family, Mgeneric_family))
597 pl = ft_list_family (family, 0);
600 MPLIST_DO (pl, MPLIST_PLIST (pl))
601 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
603 plist = ft_font_list;
607 plist = mplist_add (ft_font_list, family, mplist ());
609 #else /* not HAVE_FONTCONFIG */
611 if (! all_fonts_scaned)
619 ft_font_list = mplist ();
620 MPLIST_DO (plist, mfont_freetype_path)
621 if (MPLIST_STRING_P (plist)
622 && (pathname = MPLIST_STRING (plist))
623 && stat (pathname, &buf) == 0)
625 if (S_ISREG (buf.st_mode))
626 ft_add_font (pathname);
627 else if (S_ISDIR (buf.st_mode))
629 DIR *dir = opendir (pathname);
633 int len = strlen (pathname);
636 while ((dp = readdir (dir)) != NULL)
638 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
639 strcpy (path, pathname);
641 strcpy (path + len + 1, dp->d_name);
649 all_fonts_scaned = 1;
652 plist = ft_font_list;
655 plist = mplist_find_by_key (ft_font_list, family);
657 plist = mplist_push (ft_font_list, family, mplist ());
659 #endif /* not HAVE_FONTCONFIG */
665 ft_list_language (MSymbol language)
667 MPlist *plist = NULL;
671 if (! ft_language_list)
672 ft_language_list = mplist ();
673 else if ((plist = mplist_find_by_key (ft_language_list, language)))
674 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
676 #ifdef HAVE_FONTCONFIG
677 for (step = 0; step < 2; step++)
679 FcPattern *pattern = NULL;
680 FcObjectSet *os = NULL;
681 FcFontSet *fs = NULL;
686 if (! (pattern = FcPatternCreate ())
687 || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
691 FcLangSet *ls = FcLangSetCreate ();
695 if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
696 && FcPatternAddLangSet (pattern, FC_LANG, ls))
697 fs = FcFontList (fc_config, pattern, os);
698 FcLangSetDestroy (ls);
706 if (! (mt = msymbol_get (language, Mtext)))
708 if (! (cs = FcCharSetCreate ()))
710 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
711 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
715 if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
716 fs = FcFontList (fc_config, pattern, os);
718 FcCharSetDestroy (cs);
723 for (i = 0; i < fs->nfont; i++)
725 MSymbol family, file;
726 char *fam, *filename;
730 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
731 (FcChar8 **) &fam) != FcResultMatch)
733 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
734 (FcChar8 **) &filename) != FcResultMatch)
736 STRDUP_LOWER (buf, bufsize, fam);
737 family = msymbol (buf);
738 file = msymbol (filename);
739 pl = MPLIST_PLIST (ft_list_family (family, 0));
740 ft_info = mplist_get (pl, file);
745 mplist_add (plist, family, ft_info);
748 FcFontSetDestroy (fs);
749 FcObjectSetDestroy (os);
750 FcPatternDestroy (pattern);
755 FcObjectSetDestroy (os);
757 FcPatternDestroy (pattern);
758 MEMORY_FULL (MERROR_FONT_FT);
762 mplist_push (ft_language_list, language, plist);
765 #else /* not HAVE_FONTCONFIG */
767 if ((mt = msymbol_get (language, Mtext)))
770 int len = mtext_nchars (mt);
774 ft_list_family (Mnil, 0);
775 MPLIST_DO (pl, ft_font_list)
777 MPLIST_DO (p, MPLIST_PLIST (pl))
779 MFontFT *ft_info = MPLIST_VAL (p);
783 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
786 for (i = 0; i < len; i++)
787 if (FT_Get_Char_Index (ft_face,
788 (FT_ULong) mtext_ref_char (mt, i)) == 0)
790 FT_Done_Face (ft_face);
795 family = mfont_get_prop (&ft_info->font, Mfamily);
796 mplist_push (plist, family, ft_info);
801 #endif /* not HAVE_FONTCONFIG */
805 ft_list_script (MSymbol script)
807 MPlist *plist = NULL;
808 MPlist *language_list, *pl;
810 if (! ft_script_list)
811 ft_script_list = mplist ();
812 else if ((plist = mplist_find_by_key (ft_script_list, script)))
813 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
815 language_list = mlanguage__list (script);
816 MPLIST_DO (pl, language_list)
818 MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
819 MPlist *p = ft_list_language (language);
828 family = MPLIST_KEY (p);
829 if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
830 mplist_add (plist, family, MPLIST_VAL (p));
833 mplist_push (ft_script_list, script, plist);
834 M17N_OBJECT_UNREF (language_list);
839 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
841 if (ft_info->otf == invalid_otf)
845 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
848 ft_info->otf = invalid_otf;
852 if (cap->features[MFONT_OTT_GSUB].nfeatures
853 && cap->features[MFONT_OTT_GSUB].tags[0]
854 && (OTF_check_features
856 cap->script_tag, cap->langsys_tag,
857 cap->features[MFONT_OTT_GSUB].tags,
858 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
860 if (cap->features[MFONT_OTT_GPOS].nfeatures
861 && cap->features[MFONT_OTT_GPOS].tags[0]
862 && (OTF_check_features
864 cap->script_tag, cap->langsys_tag,
865 cap->features[MFONT_OTT_GPOS].tags,
866 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
872 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
874 #ifdef HAVE_FONTCONFIG
879 for (i = 0; cap->lang[i] != Mnil; i++)
882 && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
884 if (MPLIST_VAL (plist))
889 if (! ft_info->langset)
891 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
892 MSYMBOL_NAME (ft_info->font.file),
894 FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
895 FcFontSet *fs = FcFontList (fc_config, pat, os);
899 if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
901 ft_info->langset = FcLangSetCopy (ft_info->langset);
903 ft_info->langset = FcLangSetCreate ();
904 FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
905 FcFontSetDestroy (fs);
906 FcObjectSetDestroy (os);
907 FcPatternDestroy (pat);
910 ft_info->lang = mplist ();
911 if (FcLangSetHasLang (ft_info->langset,
912 (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
915 mplist_push (ft_info->lang, cap->lang[i], Mt);
919 mt = msymbol_get (cap->lang[i], Mtext);
922 mplist_push (ft_info->lang, cap->lang[i], Mnil);
926 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
927 if (! FcCharSetAddChar (ft_info->charset,
928 (FcChar32) mtext_ref_char (mt, j)))
930 mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
934 #endif /* HAVE_FONTCONFIG */
938 static MPlist *ft_capability_list;
941 ft_list_capability (MSymbol sym)
943 MPlist *plist, *pl, *p;
944 MFontCapability *cap = mfont__get_capability (sym);
948 if (ft_capability_list)
950 plist = mplist_find_by_key (ft_capability_list, sym);
952 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
957 ft_capability_list = mplist ();
960 if (cap->script != Mnil)
962 pl = ft_list_script (cap->script);
966 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
968 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
972 mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
974 mplist_push (ft_capability_list, sym, plist);
982 for (i = 0; cap->lang[i] != Mnil; i++)
984 p = ft_list_language (cap->lang[i]);
990 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
994 mplist_push (ft_capability_list, sym, plist);
1000 ft_list_file (MSymbol filename)
1002 MPlist *plist = NULL;
1005 ft_file_list = mplist ();
1006 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1007 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1009 #ifdef HAVE_FONTCONFIG
1011 FcPattern *pattern = FcPatternCreate ();
1015 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1016 os = FcObjectSetBuild (FC_FAMILY, NULL);
1017 fs = FcFontList (fc_config, pattern, os);
1024 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1025 (FcChar8 **) &fam) == FcResultMatch)
1030 STRDUP_LOWER (buf, bufsize, fam);
1031 family = msymbol (buf);
1032 pl = ft_list_family (family, 0);
1033 MPLIST_DO (pl, MPLIST_PLIST (pl))
1035 MFontFT *ft_info = MPLIST_VAL (pl);
1037 if (ft_info->font.file == filename)
1040 mplist_add (plist, family, ft_info);
1047 #else /* not HAVE_FONTCONFIG */
1051 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1053 MPLIST_DO (p, MPLIST_PLIST (pl))
1055 MFontFT *ft_info = MPLIST_VAL (pl);
1057 if (ft_info->font.file == filename)
1060 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1068 #endif /* not HAVE_FONTCONFIG */
1070 mplist_push (ft_file_list, filename, plist);
1074 /* The FreeType font driver function SELECT. */
1077 ft_select (MFrame *frame, MFont *font, int limited_size)
1079 MFont *found = NULL;
1080 #ifdef HAVE_FONTCONFIG
1083 int check_font_property = 1;
1085 if (font->file != Mnil)
1087 plist = ft_list_file (font->file);
1090 check_font_property = 0;
1094 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1098 plist = MPLIST_PLIST (ft_list_family (family, 1));
1099 if (MPLIST_TAIL_P (plist))
1103 plist = mplist_copy (plist);
1105 if (font->capability != Mnil)
1107 MFontCapability *cap = mfont__get_capability (font->capability);
1109 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1111 if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1112 || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1115 pl = MPLIST_NEXT (pl);
1119 if (check_font_property)
1121 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1122 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1123 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1125 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1126 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1128 ft_info = MPLIST_VAL (pl);
1130 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1132 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1134 && stretch != FONT_PROPERTY (&ft_info->font,
1137 && ft_info->font.size > 0
1138 && ft_info->font.size != font->size))
1141 pl = MPLIST_NEXT (pl);
1145 MPLIST_DO (pl, plist)
1147 font = MPLIST_VAL (plist);
1148 if (limited_size == 0
1150 || font->size <= limited_size)
1156 M17N_OBJECT_UNREF (plist);
1162 static MRealizedFont *
1163 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1165 MFontFT *ft_info = (MFontFT *) font;
1166 int reg = spec->property[MFONT_REGISTRY];
1167 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1168 MRealizedFontFT *ft_rfont;
1170 MPlist *plist, *charmap_list = NULL;
1172 int size = font->size ? font->size : spec->size;
1176 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1177 for (; rfont; rfont = rfont->next)
1178 if (rfont->font == font
1179 && (rfont->font->size ? rfont->font->size == size
1180 : rfont->spec.size == size)
1181 && rfont->spec.property[MFONT_REGISTRY] == reg
1182 && rfont->driver == &mfont__ft_driver)
1186 MDEBUG_PRINT3 (" [FONT-FT] opening %s-%d:file=%s ...",
1187 MSYMBOL_NAME ((MSymbol) mfont_get_prop (font, Mfamily)),
1188 size / 10, MSYMBOL_NAME (font->file));
1190 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1193 font->type = MFONT_TYPE_FAILURE;
1194 MDEBUG_PRINT ("failed\n");
1198 M17N_OBJECT_REF (charmap_list);
1200 charmap_list = ft_get_charmaps (ft_face);
1201 if (registry == Mnil)
1203 plist = mplist_find_by_key (charmap_list, registry);
1206 FT_Done_Face (ft_face);
1207 M17N_OBJECT_UNREF (charmap_list);
1208 MDEBUG_PRINT ("failed\n");
1211 charmap_index = (int) MPLIST_VAL (plist);
1212 if (FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index])
1213 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1215 FT_Done_Face (ft_face);
1216 M17N_OBJECT_UNREF (charmap_list);
1217 font->type = MFONT_TYPE_FAILURE;
1218 MDEBUG_PRINT ("failed\n");
1222 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1223 ft_rfont->ft_face = ft_face;
1224 ft_rfont->charmap_list = charmap_list;
1225 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1226 rfont->spec = *font;
1227 rfont->spec.type = MFONT_TYPE_REALIZED;
1228 rfont->spec.property[MFONT_REGISTRY] = reg;
1229 rfont->spec.size = size;
1230 rfont->frame = frame;
1232 rfont->driver = &mfont__ft_driver;
1233 rfont->info = ft_rfont;
1234 rfont->fontp = ft_face;
1235 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1236 rfont->descent = - ft_face->size->metrics.descender >> 6;
1237 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1238 rfont->next = MPLIST_VAL (frame->realized_font_list);
1239 MPLIST_VAL (frame->realized_font_list) = rfont;
1240 MDEBUG_PRINT ("ok\n");
1244 /* The FreeType font driver function FIND_METRIC. */
1247 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1250 FT_Face ft_face = rfont->fontp;
1251 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1253 for (; g != gend; g++)
1255 if (g->code == MCHAR_INVALID_CODE)
1257 if (FT_IS_SCALABLE (ft_face))
1259 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1260 int size = rfont->spec.size;
1263 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1264 g->width = g->rbearing;
1265 g->ascent = ft_face->ascender * size / unitsPerEm10;
1266 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1271 BDF_PropertyRec prop;
1275 g->rbearing = g->width = ft_face->available_sizes->width;
1277 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1279 g->ascent = prop.u.integer;
1280 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1281 g->descent = prop.u.integer;
1286 g->ascent = ft_face->available_sizes->height;
1293 FT_Glyph_Metrics *metrics;
1295 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1296 metrics = &ft_face->glyph->metrics;
1297 g->lbearing = (metrics->horiBearingX >> 6);
1298 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1299 g->width = metrics->horiAdvance >> 6;
1300 g->ascent = metrics->horiBearingY >> 6;
1301 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1307 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1309 MRealizedFont *rfont = NULL;
1310 MRealizedFontFT *ft_rfont;
1313 if (font->type == MFONT_TYPE_REALIZED)
1314 rfont = (MRealizedFont *) font;
1315 else if (font->type == MFONT_TYPE_OBJECT)
1317 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1318 rfont = rfont->next)
1319 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1323 #ifdef HAVE_FONTCONFIG
1324 MFontFT *ft_info = (MFontFT *) font;
1326 if (! ft_info->charset)
1328 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1329 MSYMBOL_NAME (font->file),
1331 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1332 FcFontSet *fs = FcFontList (fc_config, pat, os);
1335 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1336 &ft_info->charset) == FcResultMatch)
1337 ft_info->charset = FcCharSetCopy (ft_info->charset);
1339 ft_info->charset = FcCharSetCreate ();
1340 FcFontSetDestroy (fs);
1341 FcObjectSetDestroy (os);
1342 FcPatternDestroy (pat);
1344 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1345 #else /* not HAVE_FONTCONFIG */
1346 rfont = ft_open (frame, font, spec, NULL);
1347 #endif /* not HAVE_FONTCONFIG */
1351 MFATAL (MERROR_FONT_FT);
1355 ft_rfont = rfont->info;
1356 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1360 /* The FreeType font driver function ENCODE_CHAR. */
1363 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1365 MRealizedFont *rfont;
1366 MRealizedFontFT *ft_rfont;
1369 if (font->type == MFONT_TYPE_REALIZED)
1370 rfont = (MRealizedFont *) font;
1371 else if (font->type == MFONT_TYPE_OBJECT)
1373 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1374 rfont = rfont->next)
1375 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1379 rfont = ft_open (frame, font, spec, NULL);
1385 MFATAL (MERROR_FONT_FT);
1387 ft_rfont = rfont->info;
1388 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1389 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1392 /* The FreeType font driver function RENDER. */
1394 #define NUM_POINTS 0x1000
1397 MDrawPoint points[NUM_POINTS];
1402 ft_render (MDrawWindow win, int x, int y,
1403 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1404 int reverse, MDrawRegion region)
1407 MRealizedFace *rface = from->rface;
1408 MFrame *frame = rface->frame;
1409 FT_Int32 load_flags = FT_LOAD_RENDER;
1412 MPointTable point_table[8];
1417 /* It is assured that the all glyphs in the current range use the
1418 same realized face. */
1419 ft_face = rface->rfont->fontp;
1421 if (! gstring->anti_alias)
1423 #ifdef FT_LOAD_TARGET_MONO
1424 load_flags |= FT_LOAD_TARGET_MONO;
1426 load_flags |= FT_LOAD_MONOCHROME;
1430 for (i = 0; i < 8; i++)
1431 point_table[i].p = point_table[i].points;
1433 for (g = from; g < to; x += g++->width)
1437 MPointTable *ptable;
1441 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1442 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1443 bmp = ft_face->glyph->bitmap.buffer;
1444 width = ft_face->glyph->bitmap.width;
1445 pitch = ft_face->glyph->bitmap.pitch;
1446 if (! gstring->anti_alias)
1451 if (gstring->anti_alias)
1452 for (i = 0; i < ft_face->glyph->bitmap.rows;
1453 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1455 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1456 for (j = 0; j < width; j++, xoff++)
1458 intensity = bmp[j] >> 5;
1461 ptable = point_table + intensity;
1462 ptable->p->x = xoff;
1463 ptable->p->y = yoff;
1465 if (ptable->p - ptable->points == NUM_POINTS)
1467 (*frame->driver->draw_points)
1469 reverse ? 7 - intensity : intensity,
1470 ptable->points, NUM_POINTS, region);
1471 ptable->p = ptable->points;
1477 for (i = 0; i < ft_face->glyph->bitmap.rows;
1478 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1480 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1481 for (j = 0; j < width; j++, xoff++)
1483 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1486 ptable = point_table;
1487 ptable->p->x = xoff;
1488 ptable->p->y = yoff;
1490 if (ptable->p - ptable->points == NUM_POINTS)
1492 (*frame->driver->draw_points) (frame, win, rface,
1494 ptable->points, NUM_POINTS, region);
1495 ptable->p = ptable->points;
1502 if (gstring->anti_alias)
1504 for (i = 1; i < 8; i++)
1505 if (point_table[i].p != point_table[i].points)
1506 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1507 point_table[i].points,
1508 point_table[i].p - point_table[i].points, region);
1512 if (point_table[0].p != point_table[0].points)
1513 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1514 point_table[0].points,
1515 point_table[0].p - point_table[0].points, region);
1520 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1522 MPlist *pl = NULL, *p;
1524 MPlist *file_list = NULL;
1525 MPlist *family_list = NULL, *capability_list = NULL;
1526 MSymbol registry = Mnil;
1528 MDEBUG_PRINT2 (" [FONT-FT] listing %s%s...",
1529 FONT_PROPERTY (font, MFONT_FAMILY)
1530 ? msymbol_name (FONT_PROPERTY (font, MFONT_FAMILY)) : "*",
1531 font->capability ? msymbol_name (font->capability) : "");
1537 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1538 if (registry != Mnil)
1540 char *reg = MSYMBOL_NAME (registry);
1542 if (strncmp (reg, "unicode-", 8)
1543 && strncmp (reg, "apple-roman", 11)
1544 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1548 if (font->file != Mnil
1549 && ! (file_list = ft_list_file (font->file)))
1551 family = FONT_PROPERTY (font, MFONT_FAMILY);
1553 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1554 && MPLIST_TAIL_P (family_list))
1556 if (font->capability != Mnil
1557 && (capability_list = ft_list_capability (font->capability))
1558 && MPLIST_TAIL_P (capability_list))
1562 if (! file_list && ! family_list && ! capability_list)
1564 /* No restriction. Get all fonts. */
1566 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1568 MPLIST_DO (p, MPLIST_PLIST (family_list))
1569 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1577 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1582 for (p = pl; ! MPLIST_TAIL_P (p);)
1584 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1585 p = MPLIST_NEXT (p);
1592 MPLIST_DO (p, family_list)
1593 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1596 if (capability_list)
1599 for (p = pl; ! MPLIST_TAIL_P (p);)
1601 MFontFT *ft_info = MPLIST_VAL (p);
1603 if (mplist_find_by_value (capability_list, ft_info))
1604 p = MPLIST_NEXT (p);
1611 MPLIST_DO (p, capability_list)
1612 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1619 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1620 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1621 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1622 int size = font->size;
1624 if (weight != Mnil || style != Mnil || stretch != Mnil || size > 0)
1625 for (p = pl; ! MPLIST_TAIL_P (p); )
1627 MFontFT *ft_info = MPLIST_VAL (p);
1630 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1632 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1634 && stretch != FONT_PROPERTY (&ft_info->font,
1637 && ft_info->font.size > 0
1638 && ft_info->font.size != size))
1641 p = MPLIST_NEXT (p);
1647 plist = mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1649 if (maxnum && maxnum <= num)
1652 M17N_OBJECT_UNREF (pl);
1655 MDEBUG_PRINT1 (" %d found\n", num);
1662 MFontDriver mfont__ft_driver =
1663 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1664 ft_render, ft_list };
1671 if (FT_Init_FreeType (&ft_library) != 0)
1672 MERROR (MERROR_FONT_FT, -1);
1674 for (i = 0; i < ft_to_prop_size; i++)
1675 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1677 Mmedium = msymbol ("medium");
1679 Mnull = msymbol ("");
1681 M0_3 = msymbol ("0-3");
1682 M3_1 = msymbol ("3-1");
1683 M1_0 = msymbol ("1-0");
1685 #ifdef HAVE_FONTCONFIG
1686 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1688 FC_vs_M17N_font_prop *table = fc_all_table[i];
1691 for (j = 0; table[j].m17n_value; j++)
1692 table[j].sym = msymbol (table[j].m17n_value);
1693 table[j].sym = table[j - 1].sym;
1700 MSymbol serif, sans_serif, monospace;
1702 fc_config = FcInitLoadConfigAndFonts ();
1703 if (mfont_freetype_path)
1705 MPLIST_DO (plist, mfont_freetype_path)
1706 if (MPLIST_STRING_P (plist)
1707 && (pathname = MPLIST_STRING (plist))
1708 && stat (pathname, &buf) == 0)
1710 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1713 while ((dir = FcStrListNext (strlist)))
1714 if (strcmp ((char *) dir, pathname) == 0)
1717 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1718 FcStrListDone (strlist);
1721 Mgeneric_family = msymbol ("generic famly");
1722 serif = msymbol ("serif");
1723 msymbol_put (serif, Mgeneric_family, serif);
1724 sans_serif = msymbol ("sans-serif");
1725 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1726 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1727 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1728 monospace = msymbol ("monospace");
1729 msymbol_put (monospace, Mgeneric_family, monospace);
1730 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1744 MPLIST_DO (plist, ft_font_list)
1746 if (MPLIST_VAL (plist))
1747 MPLIST_DO (p, MPLIST_VAL (plist))
1749 if (MPLIST_KEY (p) != Mt)
1750 free_ft_info (MPLIST_VAL (p));
1752 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1754 M17N_OBJECT_UNREF (ft_font_list);
1756 if (ft_language_list)
1758 MPLIST_DO (plist, ft_language_list)
1759 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1760 M17N_OBJECT_UNREF (ft_language_list);
1765 MPLIST_DO (plist, ft_script_list)
1766 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1767 M17N_OBJECT_UNREF (ft_script_list);
1770 if (ft_capability_list)
1772 MPLIST_DO (plist, ft_capability_list)
1773 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1774 M17N_OBJECT_UNREF (ft_capability_list);
1779 MPLIST_DO (plist, ft_file_list)
1780 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1781 M17N_OBJECT_UNREF (ft_file_list);
1785 FT_Done_FreeType (ft_library);
1786 #ifdef HAVE_FONTCONFIG
1787 FcConfigDestroy (fc_config);
1789 #endif /* HAVE_FONTCONFIG */
1790 all_fonts_scaned = 0;
1793 #ifdef HAVE_FONTCONFIG
1796 mfont__ft_parse_name (const char *name, MFont *font)
1798 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1807 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1809 STRDUP_LOWER (buf, bufsize, (char *) str);
1810 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1812 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1814 STRDUP_LOWER (buf, bufsize, (char *) str);
1815 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1817 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1818 mfont__set_property (font, MFONT_WEIGHT,
1819 fc_decode_prop (val, fc_weight_table,
1820 fc_weight_table_size));
1821 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1822 mfont__set_property (font, MFONT_STYLE,
1823 fc_decode_prop (val, fc_slant_table,
1824 fc_slant_table_size));
1825 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1826 mfont__set_property (font, MFONT_STRETCH,
1827 fc_decode_prop (val, fc_width_table,
1828 fc_width_table_size));
1829 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1830 font->size = size * 10 + 0.5;
1831 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1832 font->size = - (size * 10 + 0.5);
1833 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1835 font->file = msymbol ((char *) str);
1837 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1838 font->type = MFONT_TYPE_SPEC;
1839 FcPatternDestroy (pat);
1844 mfont__ft_unparse_name (MFont *font)
1846 FcPattern *pat = fc_get_pattern (font);
1847 char *name = (char *) FcNameUnparse (pat);
1849 FcPatternDestroy (pat);
1852 #endif /* HAVE_FONTCONFIG */
1857 #define DEVICE_DELTA(table, size) \
1858 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1859 ? (table).DeltaValue[(size) >= (table).StartSize] \
1863 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1864 unsigned code, int size, int *x, int *y)
1866 if (anchor->AnchorFormat == 2)
1868 FT_Outline *outline;
1869 int ap = anchor->f.f1.AnchorPoint;
1871 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1872 outline = &ft_face->glyph->outline;
1873 if (ap < outline->n_points)
1875 *x = outline->points[ap].x;
1876 *y = outline->points[ap].y;
1879 else if (anchor->AnchorFormat == 3)
1881 if (anchor->f.f2.XDeviceTable.offset)
1882 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1883 if (anchor->f.f2.YDeviceTable.offset)
1884 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1889 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1890 MFontCapability *cap)
1892 int len = to - from;
1893 MGlyph *g = MGLYPH (from);
1895 MRealizedFont *rfont;
1898 OTF_GlyphString otf_gstring;
1900 char *script, *langsys;
1901 char *gsub_features, *gpos_features;
1907 otf_gstring.glyphs = NULL;
1908 rfont = g->rface->rfont;
1909 ft_info = (MFontFT *) rfont->font;
1910 if (ft_info->otf == invalid_otf)
1915 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1918 ft_info->otf = invalid_otf;
1923 if (OTF_get_table (otf, "head") < 0)
1926 ft_info->otf = invalid_otf;
1930 if (cap->script_tag)
1932 script = alloca (5);
1933 OTF_tag_name (cap->script_tag, script);
1937 if (cap->langsys_tag)
1939 langsys = alloca (5);
1940 OTF_tag_name (cap->langsys_tag, langsys);
1944 gsub_features = cap->features[MFONT_OTT_GSUB].str;
1945 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
1946 gsub_features = NULL;
1947 gpos_features = cap->features[MFONT_OTT_GPOS].str;
1948 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
1949 gpos_features = NULL;
1951 otf_gstring.size = otf_gstring.used = len;
1952 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1953 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1954 for (i = 0, need_cmap = 0; i < len; i++)
1956 if (gstring->glyphs[from + i].otf_encoded)
1958 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1959 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1963 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1968 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1971 OTF_drive_gdef (otf, &otf_gstring);
1972 gidx = gstring->used;
1976 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1979 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1981 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1984 temp.combining_code = 0;
1987 temp.code = otfg->glyph_id;
1988 temp.otf_encoded = 1;
1993 temp.otf_encoded = 0;
1995 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1996 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2000 for (i = 0; i < len; i++)
2002 MGlyph temp = gstring->glyphs[from + i];
2004 if (otf_gstring.glyphs[i].glyph_id)
2006 temp.code = otf_gstring.glyphs[i].glyph_id;
2007 temp.otf_encoded = 1;
2009 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2012 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2018 MGlyph *base = NULL, *mark = NULL;
2020 if (OTF_check_features (otf, 1,
2021 cap->script_tag, cap->langsys_tag,
2022 cap->features[MFONT_OTT_GPOS].tags,
2023 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2024 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2025 gpos_features) < 0))
2028 u = otf->head->unitsPerEm;
2029 size10 = rfont->spec.size;
2032 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2033 i < otf_gstring.used; i++, otfg++, g++)
2037 if (! otfg->glyph_id)
2039 switch (otfg->positioning_type)
2045 int format = otfg->f.f1.format;
2047 if (format & OTF_XPlacement)
2048 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2049 if (format & OTF_XPlaDevice)
2050 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2051 if (format & OTF_YPlacement)
2052 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2053 if (format & OTF_YPlaDevice)
2054 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2055 if (format & OTF_XAdvance)
2056 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2057 if (format & OTF_XAdvDevice)
2058 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2062 /* Not yet supported. */
2068 goto label_adjust_anchor;
2069 default: /* i.e. case 6 */
2074 label_adjust_anchor:
2076 int base_x, base_y, mark_x, mark_y;
2078 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2079 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2080 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2081 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2083 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2084 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2085 prev->code, size, &base_x, &base_y);
2086 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2087 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2088 g->code, size, &mark_x, &mark_y);
2089 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2090 g->yoff = prev->yoff + mark_y - base_y;
2091 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2094 if (otfg->GlyphClass == OTF_GlyphClass0)
2096 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2102 free (otf_gstring.glyphs);
2106 ft_find_metric (rfont, gstring, from, to);
2107 for (i = 0; i < len; i++)
2109 MGlyph temp = gstring->glyphs[from + i];
2110 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2112 if (otf_gstring.glyphs)
2113 free (otf_gstring.glyphs);
2119 mfont__ft_decode_otf (MGlyph *g)
2121 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2122 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2124 return (c ? c : -1);
2127 #endif /* HAVE_OTF */
2129 #endif /* HAVE_FREETYPE */