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->ascent = ft_face->size->metrics.ascender >> 6;
1230 rfont->descent = - ft_face->size->metrics.descender >> 6;
1231 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1232 rfont->next = MPLIST_VAL (frame->realized_font_list);
1233 MPLIST_VAL (frame->realized_font_list) = rfont;
1234 MDEBUG_PRINT ("ok\n");
1238 /* The FreeType font driver function FIND_METRIC. */
1241 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1244 FT_Face ft_face = rfont->fontp;
1245 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1247 for (; g != gend; g++)
1249 if (g->code == MCHAR_INVALID_CODE)
1251 if (FT_IS_SCALABLE (ft_face))
1253 unsigned unitsPerEm = ft_face->units_per_EM;
1254 int size = rfont->spec.size / 10;
1257 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
1258 g->width = g->rbearing;
1259 g->ascent = ft_face->ascender * size / unitsPerEm;
1260 g->descent = (- ft_face->descender) * size / unitsPerEm;
1265 BDF_PropertyRec prop;
1269 g->rbearing = g->width = ft_face->available_sizes->width;
1271 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1273 g->ascent = prop.u.integer;
1274 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1275 g->descent = prop.u.integer;
1280 g->ascent = ft_face->available_sizes->height;
1287 FT_Glyph_Metrics *metrics;
1289 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1290 metrics = &ft_face->glyph->metrics;
1291 g->lbearing = (metrics->horiBearingX >> 6);
1292 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1293 g->width = metrics->horiAdvance >> 6;
1294 g->ascent = metrics->horiBearingY >> 6;
1295 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1301 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1303 MRealizedFont *rfont = NULL;
1304 MRealizedFontFT *ft_rfont;
1307 if (font->type == MFONT_TYPE_REALIZED)
1308 rfont = (MRealizedFont *) font;
1309 else if (font->type == MFONT_TYPE_OBJECT)
1311 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1312 rfont = rfont->next)
1313 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1317 #ifdef HAVE_FONTCONFIG
1318 MFontFT *ft_info = (MFontFT *) font;
1320 if (! ft_info->charset)
1322 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1323 MSYMBOL_NAME (font->file),
1325 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1326 FcFontSet *fs = FcFontList (fc_config, pat, os);
1329 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1330 &ft_info->charset) == FcResultMatch)
1331 ft_info->charset = FcCharSetCopy (ft_info->charset);
1333 ft_info->charset = FcCharSetCreate ();
1334 FcFontSetDestroy (fs);
1335 FcObjectSetDestroy (os);
1336 FcPatternDestroy (pat);
1338 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1339 #else /* not HAVE_FONTCONFIG */
1340 rfont = ft_open (frame, font, spec, NULL);
1341 #endif /* not HAVE_FONTCONFIG */
1345 MFATAL (MERROR_FONT_FT);
1349 ft_rfont = rfont->info;
1350 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1354 /* The FreeType font driver function ENCODE_CHAR. */
1357 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1359 MRealizedFont *rfont;
1360 MRealizedFontFT *ft_rfont;
1363 if (font->type == MFONT_TYPE_REALIZED)
1364 rfont = (MRealizedFont *) font;
1365 else if (font->type == MFONT_TYPE_OBJECT)
1367 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1368 rfont = rfont->next)
1369 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1373 rfont = ft_open (frame, font, spec, NULL);
1379 MFATAL (MERROR_FONT_FT);
1381 ft_rfont = rfont->info;
1382 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1383 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1386 /* The FreeType font driver function RENDER. */
1388 #define NUM_POINTS 0x1000
1391 MDrawPoint points[NUM_POINTS];
1396 ft_render (MDrawWindow win, int x, int y,
1397 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1398 int reverse, MDrawRegion region)
1401 MRealizedFace *rface = from->rface;
1402 MFrame *frame = rface->frame;
1403 FT_Int32 load_flags = FT_LOAD_RENDER;
1406 MPointTable point_table[8];
1411 /* It is assured that the all glyphs in the current range use the
1412 same realized face. */
1413 ft_face = rface->rfont->fontp;
1415 if (! gstring->anti_alias)
1417 #ifdef FT_LOAD_TARGET_MONO
1418 load_flags |= FT_LOAD_TARGET_MONO;
1420 load_flags |= FT_LOAD_MONOCHROME;
1424 for (i = 0; i < 8; i++)
1425 point_table[i].p = point_table[i].points;
1427 for (g = from; g < to; x += g++->width)
1431 MPointTable *ptable;
1435 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1436 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1437 bmp = ft_face->glyph->bitmap.buffer;
1438 width = ft_face->glyph->bitmap.width;
1439 pitch = ft_face->glyph->bitmap.pitch;
1440 if (! gstring->anti_alias)
1445 if (gstring->anti_alias)
1446 for (i = 0; i < ft_face->glyph->bitmap.rows;
1447 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1449 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1450 for (j = 0; j < width; j++, xoff++)
1452 intensity = bmp[j] >> 5;
1455 ptable = point_table + intensity;
1456 ptable->p->x = xoff;
1457 ptable->p->y = yoff;
1459 if (ptable->p - ptable->points == NUM_POINTS)
1461 (*frame->driver->draw_points)
1463 reverse ? 7 - intensity : intensity,
1464 ptable->points, NUM_POINTS, region);
1465 ptable->p = ptable->points;
1471 for (i = 0; i < ft_face->glyph->bitmap.rows;
1472 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1474 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1475 for (j = 0; j < width; j++, xoff++)
1477 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1480 ptable = point_table;
1481 ptable->p->x = xoff;
1482 ptable->p->y = yoff;
1484 if (ptable->p - ptable->points == NUM_POINTS)
1486 (*frame->driver->draw_points) (frame, win, rface,
1488 ptable->points, NUM_POINTS, region);
1489 ptable->p = ptable->points;
1496 if (gstring->anti_alias)
1498 for (i = 1; i < 8; i++)
1499 if (point_table[i].p != point_table[i].points)
1500 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1501 point_table[i].points,
1502 point_table[i].p - point_table[i].points, region);
1506 if (point_table[0].p != point_table[0].points)
1507 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1508 point_table[0].points,
1509 point_table[0].p - point_table[0].points, region);
1514 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1516 MPlist *pl = NULL, *p;
1518 MPlist *file_list = NULL;
1519 MPlist *family_list = NULL, *capability_list = NULL;
1520 MSymbol registry = Mnil;
1522 MDEBUG_PRINT2 (" [FONT-FT] listing %s%s...",
1523 FONT_PROPERTY (font, MFONT_FAMILY)
1524 ? msymbol_name (FONT_PROPERTY (font, MFONT_FAMILY)) : "*",
1525 font->capability ? msymbol_name (font->capability) : "");
1531 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1532 if (registry != Mnil)
1534 char *reg = MSYMBOL_NAME (registry);
1536 if (strncmp (reg, "unicode-", 8)
1537 && strncmp (reg, "apple-roman", 11)
1538 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1542 if (font->file != Mnil
1543 && ! (file_list = ft_list_file (font->file)))
1545 family = FONT_PROPERTY (font, MFONT_FAMILY);
1547 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1548 && MPLIST_TAIL_P (family_list))
1550 if (font->capability != Mnil
1551 && (capability_list = ft_list_capability (font->capability))
1552 && MPLIST_TAIL_P (capability_list))
1556 if (! file_list && ! family_list && ! capability_list)
1558 /* No restriction. Get all fonts. */
1560 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1562 MPLIST_DO (p, MPLIST_PLIST (family_list))
1563 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1571 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1576 for (p = pl; ! MPLIST_TAIL_P (p);)
1578 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1579 p = MPLIST_NEXT (p);
1586 MPLIST_DO (p, family_list)
1587 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1590 if (capability_list)
1593 for (p = pl; ! MPLIST_TAIL_P (p);)
1595 MFontFT *ft_info = MPLIST_VAL (p);
1597 if (mplist_find_by_value (capability_list, ft_info))
1598 p = MPLIST_NEXT (p);
1605 MPLIST_DO (p, capability_list)
1606 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1613 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1614 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1615 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1616 int size = font->size;
1618 if (weight != Mnil || style != Mnil || stretch != Mnil || size > 0)
1619 for (p = pl; ! MPLIST_TAIL_P (p); )
1621 MFontFT *ft_info = MPLIST_VAL (p);
1624 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1626 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1628 && stretch != FONT_PROPERTY (&ft_info->font,
1631 && ft_info->font.size > 0
1632 && ft_info->font.size != size))
1635 p = MPLIST_NEXT (p);
1641 plist = mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1643 if (maxnum && maxnum <= num)
1646 M17N_OBJECT_UNREF (pl);
1649 MDEBUG_PRINT1 (" %d found\n", num);
1656 MFontDriver mfont__ft_driver =
1657 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1658 ft_render, ft_list };
1665 if (FT_Init_FreeType (&ft_library) != 0)
1666 MERROR (MERROR_FONT_FT, -1);
1668 for (i = 0; i < ft_to_prop_size; i++)
1669 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1671 Mmedium = msymbol ("medium");
1673 Mnull = msymbol ("");
1675 M0_3 = msymbol ("0-3");
1676 M3_1 = msymbol ("3-1");
1677 M1_0 = msymbol ("1-0");
1679 #ifdef HAVE_FONTCONFIG
1680 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1682 FC_vs_M17N_font_prop *table = fc_all_table[i];
1685 for (j = 0; table[j].m17n_value; j++)
1686 table[j].sym = msymbol (table[j].m17n_value);
1687 table[j].sym = table[j - 1].sym;
1694 MSymbol serif, sans_serif, monospace;
1696 fc_config = FcInitLoadConfigAndFonts ();
1697 if (mfont_freetype_path)
1699 MPLIST_DO (plist, mfont_freetype_path)
1700 if (MPLIST_STRING_P (plist)
1701 && (pathname = MPLIST_STRING (plist))
1702 && stat (pathname, &buf) == 0)
1704 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1707 while ((dir = FcStrListNext (strlist)))
1708 if (strcmp ((char *) dir, pathname) == 0)
1711 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1712 FcStrListDone (strlist);
1715 Mgeneric_family = msymbol ("generic famly");
1716 serif = msymbol ("serif");
1717 msymbol_put (serif, Mgeneric_family, serif);
1718 sans_serif = msymbol ("sans-serif");
1719 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1720 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1721 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1722 monospace = msymbol ("monospace");
1723 msymbol_put (monospace, Mgeneric_family, monospace);
1724 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1738 MPLIST_DO (plist, ft_font_list)
1740 if (MPLIST_VAL (plist))
1741 MPLIST_DO (p, MPLIST_VAL (plist))
1743 if (MPLIST_KEY (p) != Mt)
1744 free_ft_info (MPLIST_VAL (p));
1746 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1748 M17N_OBJECT_UNREF (ft_font_list);
1750 if (ft_language_list)
1752 MPLIST_DO (plist, ft_language_list)
1753 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1754 M17N_OBJECT_UNREF (ft_language_list);
1759 MPLIST_DO (plist, ft_script_list)
1760 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1761 M17N_OBJECT_UNREF (ft_script_list);
1764 if (ft_capability_list)
1766 MPLIST_DO (plist, ft_capability_list)
1767 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1768 M17N_OBJECT_UNREF (ft_capability_list);
1773 MPLIST_DO (plist, ft_file_list)
1774 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1775 M17N_OBJECT_UNREF (ft_file_list);
1779 FT_Done_FreeType (ft_library);
1780 #ifdef HAVE_FONTCONFIG
1781 FcConfigDestroy (fc_config);
1783 #endif /* HAVE_FONTCONFIG */
1784 all_fonts_scaned = 0;
1787 #ifdef HAVE_FONTCONFIG
1790 mfont__ft_parse_name (const char *name, MFont *font)
1792 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1801 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1803 STRDUP_LOWER (buf, bufsize, (char *) str);
1804 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1806 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1808 STRDUP_LOWER (buf, bufsize, (char *) str);
1809 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1811 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1812 mfont__set_property (font, MFONT_WEIGHT,
1813 fc_decode_prop (val, fc_weight_table,
1814 fc_weight_table_size));
1815 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1816 mfont__set_property (font, MFONT_STYLE,
1817 fc_decode_prop (val, fc_slant_table,
1818 fc_slant_table_size));
1819 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1820 mfont__set_property (font, MFONT_STRETCH,
1821 fc_decode_prop (val, fc_width_table,
1822 fc_width_table_size));
1823 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1824 font->size = size * 10;
1825 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1827 font->file = msymbol ((char *) str);
1829 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1830 font->type = MFONT_TYPE_SPEC;
1831 FcPatternDestroy (pat);
1836 mfont__ft_unparse_name (MFont *font)
1838 FcPattern *pat = fc_get_pattern (font);
1839 char *name = (char *) FcNameUnparse (pat);
1841 FcPatternDestroy (pat);
1844 #endif /* HAVE_FONTCONFIG */
1849 #define DEVICE_DELTA(table, size) \
1850 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1851 ? (table).DeltaValue[(size) >= (table).StartSize] \
1855 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1856 unsigned code, int size, int *x, int *y)
1858 if (anchor->AnchorFormat == 2)
1860 FT_Outline *outline;
1861 int ap = anchor->f.f1.AnchorPoint;
1863 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1864 outline = &ft_face->glyph->outline;
1865 if (ap < outline->n_points)
1867 *x = outline->points[ap].x;
1868 *y = outline->points[ap].y;
1871 else if (anchor->AnchorFormat == 3)
1873 if (anchor->f.f2.XDeviceTable.offset)
1874 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1875 if (anchor->f.f2.YDeviceTable.offset)
1876 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1881 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1882 MFontCapability *cap)
1884 int len = to - from;
1885 MGlyph *g = MGLYPH (from);
1887 MRealizedFont *rfont;
1890 OTF_GlyphString otf_gstring;
1892 char *script, *langsys;
1893 char *gsub_features, *gpos_features;
1899 otf_gstring.glyphs = NULL;
1900 rfont = g->rface->rfont;
1901 ft_info = (MFontFT *) rfont->font;
1902 if (ft_info->otf == invalid_otf)
1907 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1910 ft_info->otf = invalid_otf;
1915 if (OTF_get_table (otf, "head") < 0)
1918 ft_info->otf = invalid_otf;
1922 if (cap->script_tag)
1924 script = alloca (5);
1925 OTF_tag_name (cap->script_tag, script);
1929 if (cap->langsys_tag)
1931 langsys = alloca (5);
1932 OTF_tag_name (cap->langsys_tag, langsys);
1936 gsub_features = cap->features[MFONT_OTT_GSUB].str;
1937 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
1938 gsub_features = NULL;
1939 gpos_features = cap->features[MFONT_OTT_GPOS].str;
1940 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
1941 gpos_features = NULL;
1943 otf_gstring.size = otf_gstring.used = len;
1944 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1945 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1946 for (i = 0, need_cmap = 0; i < len; i++)
1948 if (gstring->glyphs[from + i].otf_encoded)
1950 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1951 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1955 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1960 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1963 OTF_drive_gdef (otf, &otf_gstring);
1964 gidx = gstring->used;
1968 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1971 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1973 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1976 temp.combining_code = 0;
1979 temp.code = otfg->glyph_id;
1980 temp.otf_encoded = 1;
1985 temp.otf_encoded = 0;
1987 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1988 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1992 for (i = 0; i < len; i++)
1994 MGlyph temp = gstring->glyphs[from + i];
1996 if (otf_gstring.glyphs[i].glyph_id)
1998 temp.code = otf_gstring.glyphs[i].glyph_id;
1999 temp.otf_encoded = 1;
2001 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2004 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2010 MGlyph *base = NULL, *mark = NULL;
2012 if (OTF_check_features (otf, 1,
2013 cap->script_tag, cap->langsys_tag,
2014 cap->features[MFONT_OTT_GPOS].tags,
2015 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2016 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2017 gpos_features) < 0))
2020 u = otf->head->unitsPerEm;
2021 size10 = rfont->spec.size;
2024 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2025 i < otf_gstring.used; i++, otfg++, g++)
2029 if (! otfg->glyph_id)
2031 switch (otfg->positioning_type)
2037 int format = otfg->f.f1.format;
2039 if (format & OTF_XPlacement)
2040 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2041 if (format & OTF_XPlaDevice)
2042 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2043 if (format & OTF_YPlacement)
2044 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2045 if (format & OTF_YPlaDevice)
2046 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2047 if (format & OTF_XAdvance)
2048 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2049 if (format & OTF_XAdvDevice)
2050 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2054 /* Not yet supported. */
2060 goto label_adjust_anchor;
2061 default: /* i.e. case 6 */
2066 label_adjust_anchor:
2068 int base_x, base_y, mark_x, mark_y;
2070 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2071 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2072 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2073 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2075 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2076 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2077 prev->code, size, &base_x, &base_y);
2078 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2079 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2080 g->code, size, &mark_x, &mark_y);
2081 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2082 g->yoff = prev->yoff + mark_y - base_y;
2083 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2086 if (otfg->GlyphClass == OTF_GlyphClass0)
2088 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2094 free (otf_gstring.glyphs);
2098 ft_find_metric (rfont, gstring, from, to);
2099 for (i = 0; i < len; i++)
2101 MGlyph temp = gstring->glyphs[from + i];
2102 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2104 if (otf_gstring.glyphs)
2105 free (otf_gstring.glyphs);
2111 mfont__ft_decode_otf (MGlyph *g)
2113 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2114 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2116 return (c ? c : -1);
2119 #endif /* HAVE_OTF */
2121 #endif /* HAVE_FREETYPE */