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); \
143 free_ft_rfont (void *object)
145 MRealizedFontFT *ft_rfont = object;
147 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
148 FT_Done_Face (ft_rfont->ft_face);
153 free_ft_info (MFontFT *ft_info)
155 M17N_OBJECT_UNREF (ft_info->lang);
157 if (ft_info->otf && ft_info->otf != invalid_otf)
158 OTF_close (ft_info->otf);
159 #endif /* HAVE_OTF */
164 ft_get_charmaps (FT_Face ft_face)
166 MPlist *plist = mplist ();
167 int unicode_bmp = -1, unicode_full = -1;
170 mplist_add (plist, Mt, (void *) -1);
171 for (i = 0; i < ft_face->num_charmaps; i++)
173 MSymbol registry = Mnil;
175 if (ft_face->charmaps[i]->platform_id == 0)
177 if (ft_face->charmaps[i]->encoding_id == 3)
178 registry = M0_3, unicode_bmp = i;
179 else if (ft_face->charmaps[i]->encoding_id == 4)
182 else if (ft_face->charmaps[i]->platform_id == 3)
184 if (ft_face->charmaps[i]->encoding_id == 1)
185 registry = M3_1, unicode_bmp = i;
186 else if (ft_face->charmaps[i]->encoding_id == 10)
189 else if (ft_face->charmaps[i]->platform_id == 1
190 && ft_face->charmaps[i]->encoding_id == 0)
193 mplist_add (plist, Mapple_roman, (void *) i);
195 if (registry == Mnil)
197 char registry_buf[16];
199 sprintf (registry_buf, "%d-%d",
200 ft_face->charmaps[i]->platform_id,
201 ft_face->charmaps[i]->encoding_id);
202 registry = msymbol (registry_buf);
204 mplist_add (plist, registry, (void *) i);
206 if (unicode_full >= 0)
208 mplist_add (plist, Municode_full, (void *) unicode_full);
209 mplist_add (plist, Municode_bmp, (void *) unicode_full);
211 else if (unicode_bmp >= 0)
213 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
218 #ifdef HAVE_FONTCONFIG
225 } FC_vs_M17N_font_prop;
227 static FC_vs_M17N_font_prop fc_weight_table[] =
228 { { FC_WEIGHT_THIN, "thin" },
229 { FC_WEIGHT_ULTRALIGHT, "extralight" },
230 { FC_WEIGHT_LIGHT, "light" },
231 #ifdef FC_WEIGHT_BOOK
232 { FC_WEIGHT_BOOK, "book" },
233 #endif /* FC_WEIGHT_BOOK */
234 { FC_WEIGHT_NORMAL, "normal" },
235 { FC_WEIGHT_MEDIUM, "medium" },
236 { FC_WEIGHT_DEMIBOLD, "demibold" },
237 { FC_WEIGHT_BOLD, "bold" },
238 { FC_WEIGHT_EXTRABOLD, "extrabold" },
239 { FC_WEIGHT_BLACK, "black" },
240 { FC_WEIGHT_HEAVY, "heavy" },
241 { FC_WEIGHT_MEDIUM, NULL } };
242 int fc_weight_table_size =
243 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
245 static FC_vs_M17N_font_prop fc_slant_table[] =
246 { { FC_SLANT_ROMAN, "r" },
247 { FC_SLANT_ITALIC, "i" },
248 { FC_SLANT_OBLIQUE, "o" },
249 { FC_SLANT_ROMAN, NULL } };
250 int fc_slant_table_size =
251 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
253 static FC_vs_M17N_font_prop fc_width_table[] =
254 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
255 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
256 { FC_WIDTH_CONDENSED, "condensed" },
257 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
258 { FC_WIDTH_NORMAL, "normal" },
259 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
260 { FC_WIDTH_EXPANDED, "expanded" },
261 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
262 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
263 { FC_WIDTH_NORMAL, NULL } };
264 int fc_width_table_size =
265 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
268 static FC_vs_M17N_font_prop *fc_all_table[] =
269 { fc_weight_table, fc_slant_table, fc_width_table };
272 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
276 if (val < table[i].fc_value)
278 for (i--; i >= 0; i--)
279 if (val > table[i].fc_value)
285 for (; i < size; i++)
286 if (val <= table[i].fc_value)
293 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
297 for (i = 0; table[i].m17n_value; i++)
298 if (table[i].sym == sym)
300 return table[i].fc_value;
304 fc_get_pattern (MFont *font)
306 FcPattern *pat = FcPatternCreate ();
307 MSymbol sym, weight, style, stretch;
310 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
311 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
312 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
313 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
314 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
315 FcPatternAddInteger (pat, FC_WEIGHT,
316 fc_encode_prop (weight, fc_weight_table));
317 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
318 FcPatternAddInteger (pat, FC_SLANT,
319 fc_encode_prop (style, fc_slant_table));
320 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
321 FcPatternAddInteger (pat, FC_WIDTH,
322 fc_encode_prop (stretch, fc_width_table));
325 double size = font->size;
326 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
332 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
342 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
344 STRDUP_LOWER (buf, bufsize, (char *) str);
345 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
348 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
349 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
351 STRDUP_LOWER (buf, bufsize, (char *) str);
352 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
354 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
356 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
357 mfont__set_property (font, MFONT_WEIGHT, sym);
359 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
361 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
362 mfont__set_property (font, MFONT_STYLE, sym);
364 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
366 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
367 mfont__set_property (font, MFONT_STRETCH, sym);
369 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
370 font->type = MFONT_TYPE_SPEC;
371 font->source = MFONT_SOURCE_FT;
372 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
373 font->size = size * 10;
374 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
375 font->file = msymbol ((char *) str);
380 fc_gen_font (FcPattern *pat, char *family)
384 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
385 fc_parse_pattern (pat, family, &ft_info->font);
386 ft_info->font.type = MFONT_TYPE_OBJECT;
390 #else /* not HAVE_FONTCONFIG */
393 ft_add_font (char *filename)
406 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
408 if (! FT_IS_SCALABLE (ft_face))
412 BDF_PropertyRec prop;
414 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
415 size = prop.u.integer * 10;
416 #else /* not HAVE_FTBDF_H */
418 #endif /* not HAVE_FTBDF_H */
421 FT_Done_Face (ft_face);
426 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
427 font = &ft_info->font;
428 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
429 family = msymbol (buf);
430 mfont__set_property (font, MFONT_FAMILY, family);
431 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
432 mfont__set_property (font, MFONT_STYLE, Mr);
433 mfont__set_property (font, MFONT_STRETCH, Mnormal);
434 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
435 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
436 font->type = MFONT_TYPE_OBJECT;
437 font->source = MFONT_SOURCE_FT;
439 font->file = msymbol (filename);
441 stylename = ft_face->style_name;
444 for (i = 0; i < ft_to_prop_size; i++)
445 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
448 mfont__set_property (font, ft_to_prop[i].prop,
449 msymbol (ft_to_prop[i].val));
450 stylename += ft_to_prop[i].len;
453 if (i == ft_to_prop_size)
455 char *p1 = stylename + 1;
458 while (*p1 >= 'a' && *p1 <= 'z') p1++;
459 sym = msymbol__with_len (stylename, p1 - stylename);
460 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
461 if (msymbol_get (sym, mfont__property_table[i].property))
463 mfont__set_property (font, i, sym);
468 while (*stylename && ! isalpha (*stylename))
472 FT_Done_Face (ft_face);
474 plist = mplist_find_by_key (ft_font_list, family);
476 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
480 mplist_add (plist, font->file, ft_info);
481 plist = mplist_push (ft_font_list, family, plist);
486 #endif /* not HAVE_FONTCONFIG */
489 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
490 scan all fonts and return ft_font_list. */
493 ft_list_family (MSymbol family, int check_generic)
496 #ifdef HAVE_FONTCONFIG
511 plist = ft_font_list = mplist ();
512 pattern = FcPatternCreate ();
513 os = FcObjectSetBuild (FC_FAMILY, NULL);
514 fs = FcFontList (fc_config, pattern, os);
515 for (i = 0; i < fs->nfont; i++)
517 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
518 (FcChar8 **) &fam) != FcResultMatch)
520 STRDUP_LOWER (buf, bufsize, fam);
522 if (! mplist_find_by_key (ft_font_list, sym))
523 plist = mplist_add (plist, sym, NULL);
525 FcFontSetDestroy (fs);
526 FcObjectSetDestroy (os);
527 FcPatternDestroy (pattern);
532 if (! all_fonts_scaned)
534 MPLIST_DO (plist, ft_font_list)
536 if (! MPLIST_VAL (plist))
537 ft_list_family (MPLIST_KEY (plist), 0);
539 all_fonts_scaned = 1;
544 plist = mplist_find_by_key (ft_font_list, family);
547 if (! MPLIST_VAL (plist))
549 fam = MSYMBOL_NAME (family);
550 pattern = FcPatternCreate ();
551 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
552 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
553 FC_PIXEL_SIZE, FC_FILE, NULL);
554 fs = FcFontList (fc_config, pattern, os);
556 for (i = 0; i < fs->nfont; i++)
558 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
559 p = mplist_add (p, ft_info->font.file, ft_info);
561 MPLIST_VAL (plist) = pl;
562 FcFontSetDestroy (fs);
563 FcObjectSetDestroy (os);
564 FcPatternDestroy (pattern);
567 else if (check_generic
568 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
570 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
573 if (family != generic)
574 plist = ft_list_family (generic, 1);
577 fam = MSYMBOL_NAME (family);
579 mplist_push (ft_font_list, family, plist);
580 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
581 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
584 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
587 STRDUP_LOWER (buf, bufsize, (char *) fam8);
588 family = msymbol (buf);
589 if (msymbol_get (family, Mgeneric_family))
591 pl = ft_list_family (family, 0);
594 MPLIST_DO (pl, MPLIST_PLIST (pl))
595 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
597 plist = ft_font_list;
601 plist = mplist_add (ft_font_list, family, mplist ());
603 #else /* not HAVE_FONTCONFIG */
605 if (! all_fonts_scaned)
613 ft_font_list = mplist ();
614 MPLIST_DO (plist, mfont_freetype_path)
615 if (MPLIST_STRING_P (plist)
616 && (pathname = MPLIST_STRING (plist))
617 && stat (pathname, &buf) == 0)
619 if (S_ISREG (buf.st_mode))
620 ft_add_font (pathname);
621 else if (S_ISDIR (buf.st_mode))
623 DIR *dir = opendir (pathname);
627 int len = strlen (pathname);
630 while ((dp = readdir (dir)) != NULL)
632 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
633 strcpy (path, pathname);
635 strcpy (path + len + 1, dp->d_name);
643 all_fonts_scaned = 1;
646 plist = ft_font_list;
649 plist = mplist_find_by_key (ft_font_list, family);
651 plist = mplist_push (ft_font_list, family, mplist ());
653 #endif /* not HAVE_FONTCONFIG */
659 ft_list_language (MSymbol language)
661 MPlist *plist = NULL;
665 if (! ft_language_list)
666 ft_language_list = mplist ();
667 else if ((plist = mplist_find_by_key (ft_language_list, language)))
668 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
670 #ifdef HAVE_FONTCONFIG
671 for (step = 0; step < 2; step++)
673 FcPattern *pattern = NULL;
674 FcObjectSet *os = NULL;
675 FcFontSet *fs = NULL;
680 if (! (pattern = FcPatternCreate ())
681 || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
685 FcLangSet *ls = FcLangSetCreate ();
689 if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
690 && FcPatternAddLangSet (pattern, FC_LANG, ls))
691 fs = FcFontList (fc_config, pattern, os);
692 FcLangSetDestroy (ls);
700 if (! (mt = msymbol_get (language, Mtext)))
702 if (! (cs = FcCharSetCreate ()))
704 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
705 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
709 if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
710 fs = FcFontList (fc_config, pattern, os);
712 FcCharSetDestroy (cs);
717 for (i = 0; i < fs->nfont; i++)
719 MSymbol family, file;
720 char *fam, *filename;
724 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
725 (FcChar8 **) &fam) != FcResultMatch)
727 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
728 (FcChar8 **) &filename) != FcResultMatch)
730 STRDUP_LOWER (buf, bufsize, fam);
731 family = msymbol (buf);
732 file = msymbol (filename);
733 pl = MPLIST_PLIST (ft_list_family (family, 0));
734 ft_info = mplist_get (pl, file);
739 mplist_add (plist, family, ft_info);
742 FcFontSetDestroy (fs);
743 FcObjectSetDestroy (os);
744 FcPatternDestroy (pattern);
749 FcObjectSetDestroy (os);
751 FcPatternDestroy (pattern);
752 MEMORY_FULL (MERROR_FONT_FT);
756 mplist_push (ft_language_list, language, plist);
759 #else /* not HAVE_FONTCONFIG */
761 if ((mt = msymbol_get (language, Mtext)))
764 int len = mtext_nchars (mt);
768 ft_list_family (Mnil, 0);
769 MPLIST_DO (pl, ft_font_list)
771 MPLIST_DO (p, MPLIST_PLIST (pl))
773 MFontFT *ft_info = MPLIST_VAL (p);
777 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
780 for (i = 0; i < len; i++)
781 if (FT_Get_Char_Index (ft_face,
782 (FT_ULong) mtext_ref_char (mt, i)) == 0)
784 FT_Done_Face (ft_face);
789 family = mfont_get_prop (&ft_info->font, Mfamily);
790 mplist_push (plist, family, ft_info);
795 #endif /* not HAVE_FONTCONFIG */
799 ft_list_script (MSymbol script)
801 MPlist *plist = NULL;
802 MPlist *language_list, *pl;
804 if (! ft_script_list)
805 ft_script_list = mplist ();
806 else if ((plist = mplist_find_by_key (ft_script_list, script)))
807 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
809 language_list = mlanguage__list (script);
810 MPLIST_DO (pl, language_list)
812 MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
813 MPlist *p = ft_list_language (language);
822 family = MPLIST_KEY (p);
823 if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
824 mplist_add (plist, family, MPLIST_VAL (p));
827 mplist_push (ft_script_list, script, plist);
828 M17N_OBJECT_UNREF (language_list);
833 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
835 if (ft_info->otf == invalid_otf)
839 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
842 ft_info->otf = invalid_otf;
846 if (cap->features[MFONT_OTT_GSUB].nfeatures
847 && cap->features[MFONT_OTT_GSUB].tags[0]
848 && (OTF_check_features
850 cap->script_tag, cap->langsys_tag,
851 cap->features[MFONT_OTT_GSUB].tags,
852 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
854 if (cap->features[MFONT_OTT_GPOS].nfeatures
855 && cap->features[MFONT_OTT_GPOS].tags[0]
856 && (OTF_check_features
858 cap->script_tag, cap->langsys_tag,
859 cap->features[MFONT_OTT_GPOS].tags,
860 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
866 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
868 #ifdef HAVE_FONTCONFIG
873 for (i = 0; cap->lang[i] != Mnil; i++)
876 && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
878 if (MPLIST_VAL (plist))
883 if (! ft_info->langset)
885 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
886 MSYMBOL_NAME (ft_info->font.file),
888 FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
889 FcFontSet *fs = FcFontList (fc_config, pat, os);
893 if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
895 ft_info->langset = FcLangSetCopy (ft_info->langset);
897 ft_info->langset = FcLangSetCreate ();
898 FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
899 FcFontSetDestroy (fs);
900 FcObjectSetDestroy (os);
901 FcPatternDestroy (pat);
904 ft_info->lang = mplist ();
905 if (FcLangSetHasLang (ft_info->langset,
906 (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
909 mplist_push (ft_info->lang, cap->lang[i], Mt);
913 mt = msymbol_get (cap->lang[i], Mtext);
916 mplist_push (ft_info->lang, cap->lang[i], Mnil);
920 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
921 if (! FcCharSetAddChar (ft_info->charset,
922 (FcChar32) mtext_ref_char (mt, j)))
924 mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
928 #endif /* HAVE_FONTCONFIG */
932 static MPlist *ft_capability_list;
935 ft_list_capability (MSymbol sym)
937 MPlist *plist, *pl, *p;
938 MFontCapability *cap = mfont__get_capability (sym);
942 if (ft_capability_list)
944 plist = mplist_find_by_key (ft_capability_list, sym);
946 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
951 ft_capability_list = mplist ();
954 if (cap->script != Mnil)
956 pl = ft_list_script (cap->script);
960 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
962 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
966 mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
968 mplist_push (ft_capability_list, sym, plist);
976 for (i = 0; cap->lang[i] != Mnil; i++)
978 p = ft_list_language (cap->lang[i]);
984 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
988 mplist_push (ft_capability_list, sym, plist);
994 ft_list_file (MSymbol filename)
996 MPlist *plist = NULL;
999 ft_file_list = mplist ();
1000 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1001 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1003 #ifdef HAVE_FONTCONFIG
1005 FcPattern *pattern = FcPatternCreate ();
1009 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1010 os = FcObjectSetBuild (FC_FAMILY, NULL);
1011 fs = FcFontList (fc_config, pattern, os);
1018 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1019 (FcChar8 **) &fam) == FcResultMatch)
1024 STRDUP_LOWER (buf, bufsize, fam);
1025 family = msymbol (buf);
1026 pl = ft_list_family (family, 0);
1027 MPLIST_DO (pl, MPLIST_PLIST (pl))
1029 MFontFT *ft_info = MPLIST_VAL (pl);
1031 if (ft_info->font.file == filename)
1034 mplist_add (plist, family, ft_info);
1041 #else /* not HAVE_FONTCONFIG */
1045 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1047 MPLIST_DO (p, MPLIST_PLIST (pl))
1049 MFontFT *ft_info = MPLIST_VAL (pl);
1051 if (ft_info->font.file == filename)
1054 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1062 #endif /* not HAVE_FONTCONFIG */
1064 mplist_push (ft_file_list, filename, plist);
1068 /* The FreeType font driver function SELECT. */
1071 ft_select (MFrame *frame, MFont *font, int limited_size)
1073 MFont *found = NULL;
1074 #ifdef HAVE_FONTCONFIG
1077 int check_font_property = 1;
1079 if (font->file != Mnil)
1081 plist = ft_list_file (font->file);
1084 check_font_property = 0;
1088 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1092 plist = MPLIST_PLIST (ft_list_family (family, 1));
1093 if (MPLIST_TAIL_P (plist))
1097 plist = mplist_copy (plist);
1099 if (font->capability != Mnil)
1101 MFontCapability *cap = mfont__get_capability (font->capability);
1103 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1105 if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1106 || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1109 pl = MPLIST_NEXT (pl);
1113 if (check_font_property)
1115 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1116 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1117 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1119 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1120 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1122 ft_info = MPLIST_VAL (pl);
1124 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1126 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1128 && stretch != FONT_PROPERTY (&ft_info->font,
1131 && ft_info->font.size > 0
1132 && ft_info->font.size != font->size))
1135 pl = MPLIST_NEXT (pl);
1139 MPLIST_DO (pl, plist)
1141 font = MPLIST_VAL (plist);
1142 if (limited_size == 0
1144 || font->size <= limited_size)
1150 M17N_OBJECT_UNREF (plist);
1156 static MRealizedFont *
1157 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1159 MFontFT *ft_info = (MFontFT *) font;
1160 int reg = spec->property[MFONT_REGISTRY];
1161 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1162 MRealizedFontFT *ft_rfont;
1164 MPlist *plist, *charmap_list = NULL;
1166 int size = font->size ? font->size : spec->size;
1170 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1171 for (; rfont; rfont = rfont->next)
1172 if (rfont->font == font
1173 && (rfont->font->size ? rfont->font->size == size
1174 : rfont->spec.size == size)
1175 && rfont->spec.property[MFONT_REGISTRY] == reg
1176 && rfont->driver == &mfont__ft_driver)
1180 MDEBUG_PRINT3 (" [FONT-FT] opening %s-%d:file=%s ...",
1181 MSYMBOL_NAME ((MSymbol) mfont_get_prop (font, Mfamily)),
1182 size / 10, MSYMBOL_NAME (font->file));
1184 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1187 font->type = MFONT_TYPE_FAILURE;
1188 MDEBUG_PRINT ("failed\n");
1192 M17N_OBJECT_REF (charmap_list);
1194 charmap_list = ft_get_charmaps (ft_face);
1195 if (registry == Mnil)
1197 plist = mplist_find_by_key (charmap_list, registry);
1200 FT_Done_Face (ft_face);
1201 M17N_OBJECT_UNREF (charmap_list);
1202 MDEBUG_PRINT ("failed\n");
1205 charmap_index = (int) MPLIST_VAL (plist);
1206 if (FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index])
1207 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1209 FT_Done_Face (ft_face);
1210 M17N_OBJECT_UNREF (charmap_list);
1211 font->type = MFONT_TYPE_FAILURE;
1212 MDEBUG_PRINT ("failed\n");
1216 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1217 ft_rfont->ft_face = ft_face;
1218 ft_rfont->charmap_list = charmap_list;
1219 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1220 rfont->spec = *font;
1221 rfont->spec.type = MFONT_TYPE_REALIZED;
1222 rfont->spec.property[MFONT_REGISTRY] = reg;
1223 rfont->spec.size = size;
1224 rfont->frame = frame;
1226 rfont->driver = &mfont__ft_driver;
1227 rfont->info = ft_rfont;
1228 rfont->fontp = ft_face;
1229 rfont->next = MPLIST_VAL (frame->realized_font_list);
1230 MPLIST_VAL (frame->realized_font_list) = rfont;
1231 MDEBUG_PRINT ("ok\n");
1235 /* The FreeType font driver function FIND_METRIC. */
1238 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1241 FT_Face ft_face = rfont->fontp;
1242 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1244 for (; g != gend; g++)
1246 if (g->code == MCHAR_INVALID_CODE)
1248 if (FT_IS_SCALABLE (ft_face))
1250 unsigned unitsPerEm = ft_face->units_per_EM;
1251 int size = rfont->spec.size / 10;
1254 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
1255 g->width = g->rbearing;
1256 g->ascent = ft_face->ascender * size / unitsPerEm;
1257 g->descent = (- ft_face->descender) * size / unitsPerEm;
1262 BDF_PropertyRec prop;
1266 g->rbearing = g->width = ft_face->available_sizes->width;
1268 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1270 g->ascent = prop.u.integer;
1271 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1272 g->descent = prop.u.integer;
1277 g->ascent = ft_face->available_sizes->height;
1284 FT_Glyph_Metrics *metrics;
1286 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1287 metrics = &ft_face->glyph->metrics;
1288 g->lbearing = (metrics->horiBearingX >> 6);
1289 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1290 g->width = metrics->horiAdvance >> 6;
1291 g->ascent = metrics->horiBearingY >> 6;
1292 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1298 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1300 MRealizedFont *rfont = NULL;
1301 MRealizedFontFT *ft_rfont;
1304 if (font->type == MFONT_TYPE_REALIZED)
1305 rfont = (MRealizedFont *) font;
1306 else if (font->type == MFONT_TYPE_OBJECT)
1308 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1309 rfont = rfont->next)
1310 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1314 #ifdef HAVE_FONTCONFIG
1315 MFontFT *ft_info = (MFontFT *) font;
1317 if (! ft_info->charset)
1319 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1320 MSYMBOL_NAME (font->file),
1322 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1323 FcFontSet *fs = FcFontList (fc_config, pat, os);
1326 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1327 &ft_info->charset) == FcResultMatch)
1328 ft_info->charset = FcCharSetCopy (ft_info->charset);
1330 ft_info->charset = FcCharSetCreate ();
1331 FcFontSetDestroy (fs);
1332 FcObjectSetDestroy (os);
1333 FcPatternDestroy (pat);
1335 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1336 #else /* not HAVE_FONTCONFIG */
1337 rfont = ft_open (frame, font, spec, NULL);
1338 #endif /* not HAVE_FONTCONFIG */
1342 MFATAL (MERROR_FONT_FT);
1346 ft_rfont = rfont->info;
1347 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1351 /* The FreeType font driver function ENCODE_CHAR. */
1354 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1356 MRealizedFont *rfont;
1357 MRealizedFontFT *ft_rfont;
1360 if (font->type == MFONT_TYPE_REALIZED)
1361 rfont = (MRealizedFont *) font;
1362 else if (font->type == MFONT_TYPE_OBJECT)
1364 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1365 rfont = rfont->next)
1366 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1370 rfont = ft_open (frame, font, spec, NULL);
1376 MFATAL (MERROR_FONT_FT);
1378 ft_rfont = rfont->info;
1379 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1380 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1383 /* The FreeType font driver function RENDER. */
1385 #define NUM_POINTS 0x1000
1388 MDrawPoint points[NUM_POINTS];
1393 ft_render (MDrawWindow win, int x, int y,
1394 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1395 int reverse, MDrawRegion region)
1398 MRealizedFace *rface = from->rface;
1399 MFrame *frame = rface->frame;
1400 FT_Int32 load_flags = FT_LOAD_RENDER;
1403 MPointTable point_table[8];
1408 /* It is assured that the all glyphs in the current range use the
1409 same realized face. */
1410 ft_face = rface->rfont->fontp;
1412 if (! gstring->anti_alias)
1414 #ifdef FT_LOAD_TARGET_MONO
1415 load_flags |= FT_LOAD_TARGET_MONO;
1417 load_flags |= FT_LOAD_MONOCHROME;
1421 for (i = 0; i < 8; i++)
1422 point_table[i].p = point_table[i].points;
1424 for (g = from; g < to; x += g++->width)
1428 MPointTable *ptable;
1432 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1433 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1434 bmp = ft_face->glyph->bitmap.buffer;
1435 width = ft_face->glyph->bitmap.width;
1436 pitch = ft_face->glyph->bitmap.pitch;
1437 if (! gstring->anti_alias)
1442 if (gstring->anti_alias)
1443 for (i = 0; i < ft_face->glyph->bitmap.rows;
1444 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1446 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1447 for (j = 0; j < width; j++, xoff++)
1449 intensity = bmp[j] >> 5;
1452 ptable = point_table + intensity;
1453 ptable->p->x = xoff;
1454 ptable->p->y = yoff;
1456 if (ptable->p - ptable->points == NUM_POINTS)
1458 (*frame->driver->draw_points)
1460 reverse ? 7 - intensity : intensity,
1461 ptable->points, NUM_POINTS, region);
1462 ptable->p = ptable->points;
1468 for (i = 0; i < ft_face->glyph->bitmap.rows;
1469 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1471 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1472 for (j = 0; j < width; j++, xoff++)
1474 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1477 ptable = point_table;
1478 ptable->p->x = xoff;
1479 ptable->p->y = yoff;
1481 if (ptable->p - ptable->points == NUM_POINTS)
1483 (*frame->driver->draw_points) (frame, win, rface,
1485 ptable->points, NUM_POINTS, region);
1486 ptable->p = ptable->points;
1493 if (gstring->anti_alias)
1495 for (i = 1; i < 8; i++)
1496 if (point_table[i].p != point_table[i].points)
1497 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1498 point_table[i].points,
1499 point_table[i].p - point_table[i].points, region);
1503 if (point_table[0].p != point_table[0].points)
1504 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1505 point_table[0].points,
1506 point_table[0].p - point_table[0].points, region);
1511 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1513 MPlist *pl = NULL, *p;
1515 MPlist *file_list = NULL;
1516 MPlist *family_list = NULL, *capability_list = NULL;
1517 MSymbol registry = Mnil;
1519 MDEBUG_PRINT2 (" [FONT-FT] listing %s%s...",
1520 FONT_PROPERTY (font, MFONT_FAMILY)
1521 ? msymbol_name (FONT_PROPERTY (font, MFONT_FAMILY)) : "*",
1522 font->capability ? msymbol_name (font->capability) : "");
1528 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1529 if (registry != Mnil)
1531 char *reg = MSYMBOL_NAME (registry);
1533 if (strncmp (reg, "unicode-", 8)
1534 && strncmp (reg, "apple-roman", 11)
1535 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1539 if (font->file != Mnil
1540 && ! (file_list = ft_list_file (font->file)))
1542 family = FONT_PROPERTY (font, MFONT_FAMILY);
1544 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1545 && MPLIST_TAIL_P (family_list))
1547 if (font->capability != Mnil
1548 && (capability_list = ft_list_capability (font->capability))
1549 && MPLIST_TAIL_P (capability_list))
1553 if (! file_list && ! family_list && ! capability_list)
1555 /* No restriction. Get all fonts. */
1557 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1559 MPLIST_DO (p, MPLIST_PLIST (family_list))
1560 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1568 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1573 for (p = pl; ! MPLIST_TAIL_P (p);)
1575 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1576 p = MPLIST_NEXT (p);
1583 MPLIST_DO (p, family_list)
1584 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1587 if (capability_list)
1590 for (p = pl; ! MPLIST_TAIL_P (p);)
1592 MFontFT *ft_info = MPLIST_VAL (p);
1594 if (mplist_find_by_value (capability_list, ft_info))
1595 p = MPLIST_NEXT (p);
1602 MPLIST_DO (p, capability_list)
1603 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1610 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1611 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1612 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1613 int size = font->size;
1615 if (weight != Mnil || style != Mnil || stretch != Mnil || size > 0)
1616 for (p = pl; ! MPLIST_TAIL_P (p); )
1618 MFontFT *ft_info = MPLIST_VAL (p);
1621 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1623 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1625 && stretch != FONT_PROPERTY (&ft_info->font,
1628 && ft_info->font.size > 0
1629 && ft_info->font.size != size))
1632 p = MPLIST_NEXT (p);
1638 plist = mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1640 if (maxnum && maxnum <= num)
1643 M17N_OBJECT_UNREF (pl);
1646 MDEBUG_PRINT1 (" %d found\n", num);
1653 MFontDriver mfont__ft_driver =
1654 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1655 ft_render, ft_list };
1662 if (FT_Init_FreeType (&ft_library) != 0)
1663 MERROR (MERROR_FONT_FT, -1);
1665 for (i = 0; i < ft_to_prop_size; i++)
1666 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1668 Mmedium = msymbol ("medium");
1670 Mnull = msymbol ("");
1672 M0_3 = msymbol ("0-3");
1673 M3_1 = msymbol ("3-1");
1674 M1_0 = msymbol ("1-0");
1676 #ifdef HAVE_FONTCONFIG
1677 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1679 FC_vs_M17N_font_prop *table = fc_all_table[i];
1682 for (j = 0; table[j].m17n_value; j++)
1683 table[j].sym = msymbol (table[j].m17n_value);
1684 table[j].sym = table[j - 1].sym;
1691 MSymbol serif, sans_serif, monospace;
1693 fc_config = FcInitLoadConfigAndFonts ();
1694 if (mfont_freetype_path)
1696 MPLIST_DO (plist, mfont_freetype_path)
1697 if (MPLIST_STRING_P (plist)
1698 && (pathname = MPLIST_STRING (plist))
1699 && stat (pathname, &buf) == 0)
1701 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1704 while ((dir = FcStrListNext (strlist)))
1705 if (strcmp ((char *) dir, pathname) == 0)
1708 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1709 FcStrListDone (strlist);
1712 Mgeneric_family = msymbol ("generic famly");
1713 serif = msymbol ("serif");
1714 msymbol_put (serif, Mgeneric_family, serif);
1715 sans_serif = msymbol ("sans-serif");
1716 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1717 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1718 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1719 monospace = msymbol ("monospace");
1720 msymbol_put (monospace, Mgeneric_family, monospace);
1721 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1735 MPLIST_DO (plist, ft_font_list)
1737 if (MPLIST_VAL (plist))
1738 MPLIST_DO (p, MPLIST_VAL (plist))
1740 if (MPLIST_KEY (p) != Mt)
1741 free_ft_info (MPLIST_VAL (p));
1743 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1745 M17N_OBJECT_UNREF (ft_font_list);
1747 if (ft_language_list)
1749 MPLIST_DO (plist, ft_language_list)
1750 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1751 M17N_OBJECT_UNREF (ft_language_list);
1756 MPLIST_DO (plist, ft_script_list)
1757 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1758 M17N_OBJECT_UNREF (ft_script_list);
1761 if (ft_capability_list)
1763 MPLIST_DO (plist, ft_capability_list)
1764 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1765 M17N_OBJECT_UNREF (ft_capability_list);
1770 MPLIST_DO (plist, ft_file_list)
1771 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1772 M17N_OBJECT_UNREF (ft_file_list);
1776 FT_Done_FreeType (ft_library);
1777 #ifdef HAVE_FONTCONFIG
1778 FcConfigDestroy (fc_config);
1780 #endif /* HAVE_FONTCONFIG */
1781 all_fonts_scaned = 0;
1784 #ifdef HAVE_FONTCONFIG
1787 mfont__ft_parse_name (char *name, MFont *font)
1789 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1798 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1800 STRDUP_LOWER (buf, bufsize, (char *) str);
1801 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1803 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1805 STRDUP_LOWER (buf, bufsize, (char *) str);
1806 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1808 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1809 mfont__set_property (font, MFONT_WEIGHT,
1810 fc_decode_prop (val, fc_weight_table,
1811 fc_weight_table_size));
1812 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1813 mfont__set_property (font, MFONT_STYLE,
1814 fc_decode_prop (val, fc_slant_table,
1815 fc_slant_table_size));
1816 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1817 mfont__set_property (font, MFONT_STRETCH,
1818 fc_decode_prop (val, fc_width_table,
1819 fc_width_table_size));
1820 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1821 font->size = size * 10;
1822 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1824 font->file = msymbol ((char *) str);
1826 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1827 font->type = MFONT_TYPE_SPEC;
1828 FcPatternDestroy (pat);
1833 mfont__ft_unparse_name (MFont *font)
1835 FcPattern *pat = fc_get_pattern (font);
1836 char *name = (char *) FcNameUnparse (pat);
1838 FcPatternDestroy (pat);
1841 #endif /* HAVE_FONTCONFIG */
1846 #define DEVICE_DELTA(table, size) \
1847 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1848 ? (table).DeltaValue[(size) >= (table).StartSize] \
1852 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1853 unsigned code, int size, int *x, int *y)
1855 if (anchor->AnchorFormat == 2)
1857 FT_Outline *outline;
1858 int ap = anchor->f.f1.AnchorPoint;
1860 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1861 outline = &ft_face->glyph->outline;
1862 if (ap < outline->n_points)
1864 *x = outline->points[ap].x;
1865 *y = outline->points[ap].y;
1868 else if (anchor->AnchorFormat == 3)
1870 if (anchor->f.f2.XDeviceTable.offset)
1871 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1872 if (anchor->f.f2.YDeviceTable.offset)
1873 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1878 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1879 MFontCapability *cap)
1881 int len = to - from;
1882 MGlyph *g = MGLYPH (from);
1884 MRealizedFont *rfont;
1887 OTF_GlyphString otf_gstring;
1889 char *script, *langsys;
1890 char *gsub_features, *gpos_features;
1896 otf_gstring.glyphs = NULL;
1897 rfont = g->rface->rfont;
1898 ft_info = (MFontFT *) rfont->font;
1899 if (ft_info->otf == invalid_otf)
1904 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1907 ft_info->otf = invalid_otf;
1912 if (OTF_get_table (otf, "head") < 0)
1915 ft_info->otf = invalid_otf;
1919 if (cap->script_tag)
1921 script = alloca (5);
1922 OTF_tag_name (cap->script_tag, script);
1926 if (cap->langsys_tag)
1928 langsys = alloca (5);
1929 OTF_tag_name (cap->langsys_tag, langsys);
1933 gsub_features = cap->features[MFONT_OTT_GSUB].str;
1934 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
1935 gsub_features = NULL;
1936 gpos_features = cap->features[MFONT_OTT_GPOS].str;
1937 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
1938 gpos_features = NULL;
1940 otf_gstring.size = otf_gstring.used = len;
1941 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1942 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1943 for (i = 0, need_cmap = 0; i < len; i++)
1945 if (gstring->glyphs[from + i].otf_encoded)
1947 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1948 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1952 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1957 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1960 OTF_drive_gdef (otf, &otf_gstring);
1961 gidx = gstring->used;
1965 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1968 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1970 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1973 temp.combining_code = 0;
1976 temp.code = otfg->glyph_id;
1977 temp.otf_encoded = 1;
1982 temp.otf_encoded = 0;
1984 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1985 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1989 for (i = 0; i < len; i++)
1991 MGlyph temp = gstring->glyphs[from + i];
1993 if (otf_gstring.glyphs[i].glyph_id)
1995 temp.code = otf_gstring.glyphs[i].glyph_id;
1996 temp.otf_encoded = 1;
1998 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2001 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2007 MGlyph *base = NULL, *mark = NULL;
2009 if (OTF_check_features (otf, 1,
2010 cap->script_tag, cap->langsys_tag,
2011 cap->features[MFONT_OTT_GPOS].tags,
2012 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2013 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2014 gpos_features) < 0))
2017 u = otf->head->unitsPerEm;
2018 size10 = rfont->spec.size;
2021 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2022 i < otf_gstring.used; i++, otfg++, g++)
2026 if (! otfg->glyph_id)
2028 switch (otfg->positioning_type)
2034 int format = otfg->f.f1.format;
2036 if (format & OTF_XPlacement)
2037 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2038 if (format & OTF_XPlaDevice)
2039 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2040 if (format & OTF_YPlacement)
2041 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2042 if (format & OTF_YPlaDevice)
2043 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2044 if (format & OTF_XAdvance)
2045 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2046 if (format & OTF_XAdvDevice)
2047 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2051 /* Not yet supported. */
2057 goto label_adjust_anchor;
2058 default: /* i.e. case 6 */
2063 label_adjust_anchor:
2065 int base_x, base_y, mark_x, mark_y;
2067 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2068 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2069 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2070 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2072 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2073 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2074 prev->code, size, &base_x, &base_y);
2075 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2076 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2077 g->code, size, &mark_x, &mark_y);
2078 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2079 g->yoff = prev->yoff + mark_y - base_y;
2080 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2083 if (otfg->GlyphClass == OTF_GlyphClass0)
2085 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2091 free (otf_gstring.glyphs);
2095 ft_find_metric (rfont, gstring, from, to);
2096 for (i = 0; i < len; i++)
2098 MGlyph temp = gstring->glyphs[from + i];
2099 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2101 if (otf_gstring.glyphs)
2102 free (otf_gstring.glyphs);
2108 mfont__ft_decode_otf (MGlyph *g)
2110 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2111 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2113 return (c ? c : -1);
2116 #endif /* HAVE_OTF */
2118 #endif /* HAVE_FREETYPE */