1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
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., 51 Franklin Street, Fifth Floor,
28 #include <sys/types.h>
35 #include "m17n-misc.h"
40 #include "internal-flt.h"
41 #include "internal-gui.h"
51 static int mdebug_flag = MDEBUG_FONT;
53 #ifdef HAVE_FONTCONFIG
54 #include <fontconfig/fcfreetype.h>
56 static FcConfig *fc_config;
57 static MSymbol Mgeneric_family;
58 #endif /* HAVE_FONTCONFIG */
60 /* Font properties; Mnormal is already defined in face.c. */
61 static MSymbol Mmedium, Mr, Mnull;
63 static MSymbol M0[5], M3_1, M1_0;
65 static FT_Library ft_library;
68 static OTF *invalid_otf = (OTF *) "";
69 static OTF *get_otf (MFLTFont *font, FT_Face *ft_face);
76 /* NULL if not yet opened. invalid_otf if not OTF. */
79 #ifdef HAVE_FONTCONFIG
82 #endif /* HAVE_FONTCONFIG */
88 FT_Face ft_face; /* This must be the 2nd member. */
90 int face_encapsulated;
97 enum MFontProperty prop;
101 static MFTtoProp ft_to_prop[] =
102 { { "italic", 0, MFONT_STYLE, "i" },
103 { "roman", 0, MFONT_STYLE, "r" },
104 { "oblique", 0, MFONT_STYLE, "o" },
105 { "regular", 0, MFONT_WEIGHT, "normal" },
106 { "normal", 0, MFONT_WEIGHT, "normal" },
107 /* We need this entry even if "bold" is in commone_weight[] to
108 handle such style names as "bolditalic" and "boldoblique". */
109 { "bold", 0, MFONT_WEIGHT, "bold" },
110 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
111 { "demi", 0, MFONT_WEIGHT, "demibold" } };
112 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
114 /** List of FreeType fonts. Keys are family names, values are plists
115 containing fonts of the corresponding family. In the deeper
116 plist, keys are file names, values are (MFontFT *). */
117 static MPlist *ft_font_list;
119 /** List of FreeType fonts. Keys are script names, values are plists
120 containing fonts supporting the corresponding script. In the
121 deeper plist, keys are family names, values are (MFontFT *). */
122 static MPlist *ft_script_list;
124 /** List of FreeType fonts. Keys are language names, values are
125 plists containing fonts supporting the corresponding language. In
126 the deeper plist, keys are family names, values are (MFontFT *). */
127 static MPlist *ft_language_list;
129 static MPlist *ft_file_list;
131 static int all_fonts_scaned;
133 #define STRDUP_LOWER(s1, size, s2) \
135 int len = strlen (s2) + 1; \
139 (s1) = alloca (len), (size) = len; \
140 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
141 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
146 static MPlist *ft_list_family (MSymbol, int, int);
149 free_ft_rfont (void *object)
151 MRealizedFontFT *ft_rfont = object;
153 if (! ft_rfont->face_encapsulated)
155 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
156 FT_Done_Face (ft_rfont->ft_face);
162 free_ft_info (MFontFT *ft_info)
165 if (ft_info->otf && ft_info->otf != invalid_otf)
166 OTF_close (ft_info->otf);
167 #endif /* HAVE_OTF */
168 #ifdef HAVE_FONTCONFIG
169 if (ft_info->langset)
170 FcLangSetDestroy (ft_info->langset);
171 if (ft_info->charset)
172 FcCharSetDestroy (ft_info->charset);
173 #endif /* HAVE_FONTCONFIG */
178 ft_get_charmaps (FT_Face ft_face)
180 MPlist *plist = mplist ();
181 int unicode_bmp = -1, unicode_full = -1;
184 mplist_add (plist, Mt, (void *) -1);
185 for (i = 0; i < ft_face->num_charmaps; i++)
187 MSymbol registry = Mnil;
189 if (ft_face->charmaps[i]->platform_id == 0)
191 if (ft_face->charmaps[i]->encoding_id <= 4)
192 registry = M0[ft_face->charmaps[i]->encoding_id], unicode_bmp = i;
193 if (ft_face->charmaps[i]->encoding_id == 4)
194 unicode_bmp = unicode_full = i;
196 else if (ft_face->charmaps[i]->platform_id == 3)
198 if (ft_face->charmaps[i]->encoding_id == 1)
199 registry = M3_1, unicode_bmp = i;
200 else if (ft_face->charmaps[i]->encoding_id == 10)
201 unicode_bmp = unicode_full = i;
203 else if (ft_face->charmaps[i]->platform_id == 1
204 && ft_face->charmaps[i]->encoding_id == 0)
207 mplist_add (plist, Mapple_roman, (void *) i);
209 if (registry == Mnil)
211 char registry_buf[16];
213 sprintf (registry_buf, "%d-%d",
214 ft_face->charmaps[i]->platform_id,
215 ft_face->charmaps[i]->encoding_id);
216 registry = msymbol (registry_buf);
218 mplist_add (plist, registry, (void *) i);
220 if (unicode_full >= 0)
221 mplist_add (plist, Municode_full, (void *) unicode_full);
222 if (unicode_bmp >= 0)
226 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
227 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode_bmp]);
228 for (i = 0x21; i < 0x7F && FT_Get_Char_Index (ft_face, i) > 0; i++);
231 for (i = 0xC0; i < 0x100 && FT_Get_Char_Index (ft_face, i) > 0; i++);
233 mplist_add (plist, Miso8859_1, (void *) unicode_bmp);
241 ft_gen_font (FT_Face ft_face)
251 if (FT_IS_SCALABLE (ft_face))
252 size = ft_face->size->metrics.y_ppem;
253 else if (ft_face->num_fixed_sizes == 0)
256 size = ft_face->available_sizes[0].height;
258 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
259 font = &ft_info->font;
260 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
261 family = msymbol (buf);
262 mfont__set_property (font, MFONT_FAMILY, family);
263 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
264 mfont__set_property (font, MFONT_STYLE, Mr);
265 mfont__set_property (font, MFONT_STRETCH, Mnormal);
266 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
267 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
268 font->size = size * 10;
269 font->type = MFONT_TYPE_OBJECT;
270 font->source = MFONT_SOURCE_FT;
273 stylename = ft_face->style_name;
278 for (i = 0; i < ft_to_prop_size; i++)
279 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
282 mfont__set_property (font, ft_to_prop[i].prop,
283 msymbol (ft_to_prop[i].val));
284 stylename += ft_to_prop[i].len;
287 if (i == ft_to_prop_size)
289 char *p1 = stylename + 1;
292 while (*p1 >= 'a' && *p1 <= 'z') p1++;
293 sym = msymbol__with_len (stylename, p1 - stylename);
294 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
295 if (msymbol_get (sym, mfont__property_table[i].property))
297 mfont__set_property (font, i, sym);
302 while (*stylename && ! isalpha (*stylename))
308 #ifdef HAVE_FONTCONFIG
315 } FC_vs_M17N_font_prop;
317 static FC_vs_M17N_font_prop fc_weight_table[] =
318 { { FC_WEIGHT_THIN, "thin" },
319 { FC_WEIGHT_ULTRALIGHT, "extralight" },
320 { FC_WEIGHT_LIGHT, "light" },
321 #ifdef FC_WEIGHT_BOOK
322 { FC_WEIGHT_BOOK, "book" },
323 #endif /* FC_WEIGHT_BOOK */
324 { FC_WEIGHT_REGULAR, "normal" },
325 { FC_WEIGHT_NORMAL, "normal" },
326 { FC_WEIGHT_MEDIUM, "medium" },
327 { FC_WEIGHT_DEMIBOLD, "demibold" },
328 { FC_WEIGHT_BOLD, "bold" },
329 { FC_WEIGHT_EXTRABOLD, "extrabold" },
330 { FC_WEIGHT_BLACK, "black" },
331 { FC_WEIGHT_HEAVY, "heavy" },
332 { FC_WEIGHT_MEDIUM, NULL } };
333 int fc_weight_table_size =
334 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
336 static FC_vs_M17N_font_prop fc_slant_table[] =
337 { { FC_SLANT_ROMAN, "r" },
338 { FC_SLANT_ITALIC, "i" },
339 { FC_SLANT_OBLIQUE, "o" },
340 { FC_SLANT_ROMAN, NULL } };
341 int fc_slant_table_size =
342 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
344 static FC_vs_M17N_font_prop fc_width_table[] =
345 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
346 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
347 { FC_WIDTH_CONDENSED, "condensed" },
348 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
349 { FC_WIDTH_NORMAL, "normal" },
350 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
351 { FC_WIDTH_EXPANDED, "expanded" },
352 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
353 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
354 { FC_WIDTH_NORMAL, NULL } };
355 int fc_width_table_size =
356 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
359 static FC_vs_M17N_font_prop *fc_all_table[] =
360 { fc_weight_table, fc_slant_table, fc_width_table };
363 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
367 if (val < table[i].fc_value)
369 for (i--; i >= 0; i--)
370 if (val > table[i].fc_value)
376 for (; i < size; i++)
377 if (val <= table[i].fc_value)
384 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
388 for (i = 0; table[i].m17n_value; i++)
389 if (table[i].sym == sym)
391 return table[i].fc_value;
395 fc_get_pattern (MFont *font)
397 FcPattern *pat = FcPatternCreate ();
398 MSymbol sym, weight, style, stretch;
401 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
402 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
403 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
404 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
405 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
406 FcPatternAddInteger (pat, FC_WEIGHT,
407 fc_encode_prop (weight, fc_weight_table));
408 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
409 FcPatternAddInteger (pat, FC_SLANT,
410 fc_encode_prop (style, fc_slant_table));
411 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
412 FcPatternAddInteger (pat, FC_WIDTH,
413 fc_encode_prop (stretch, fc_width_table));
416 double size = font->size;
417 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
419 else if (font->size < 0)
421 double size = - font->size;
422 FcPatternAddDouble (pat, FC_SIZE, size / 10);
428 fc_parse_pattern (FcPattern *pat, char *family, MFontFT *ft_info)
438 MFont *font = &ft_info->font;
441 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
443 STRDUP_LOWER (buf, bufsize, (char *) str);
444 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
447 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
448 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
450 STRDUP_LOWER (buf, bufsize, (char *) str);
451 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
453 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
455 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
456 mfont__set_property (font, MFONT_WEIGHT, sym);
458 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
460 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
461 mfont__set_property (font, MFONT_STYLE, sym);
463 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
465 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
466 mfont__set_property (font, MFONT_STRETCH, sym);
468 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
470 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") != FcLangDifferentLang
471 || FcLangSetHasLang (ls, (FcChar8 *) "zh") != FcLangDifferentLang
472 || FcLangSetHasLang (ls, (FcChar8 *) "ko") != FcLangDifferentLang)
473 font->for_full_width = 1;
474 ft_info->langset = FcLangSetCopy (ls);
476 if (FcPatternGetCharSet (pat, FC_CHARSET, 0, &cs) == FcResultMatch)
477 ft_info->charset = FcCharSetCopy (cs);
479 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
480 font->type = MFONT_TYPE_SPEC;
481 font->source = MFONT_SOURCE_FT;
482 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
483 font->size = size * 10;
484 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
485 font->file = msymbol ((char *) str);
490 fc_gen_font (FcPattern *pat, char *family)
494 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
495 fc_parse_pattern (pat, family, ft_info);
496 ft_info->font.type = MFONT_TYPE_OBJECT;
501 fc_init_font_list (void)
503 FcPattern *pattern = FcPatternCreate ();
504 FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL);
505 FcFontSet *fs = FcFontList (fc_config, pattern, os);
506 MPlist *plist = mplist ();
511 ft_font_list = plist;
512 for (i = 0; i < fs->nfont; i++)
516 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
517 (FcChar8 **) &fam) != FcResultMatch)
519 STRDUP_LOWER (buf, bufsize, fam);
520 plist = mplist_add (plist, msymbol (buf), NULL);
522 FcFontSetDestroy (fs);
523 FcObjectSetDestroy (os);
524 FcPatternDestroy (pattern);
528 fc_list_pattern (FcPattern *pattern)
530 FcObjectSet *os = NULL;
531 FcFontSet *fs = NULL;
532 MSymbol last_family = Mnil;
533 MPlist *plist = NULL, *pl = NULL;
538 if (! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
540 if (! (fs = FcFontList (fc_config, pattern, os)))
543 for (i = 0; i < fs->nfont; i++)
545 MSymbol family, file;
546 char *fam, *filename;
549 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
550 (FcChar8 **) &fam) != FcResultMatch)
552 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
553 (FcChar8 **) &filename) != FcResultMatch)
555 STRDUP_LOWER (buf, bufsize, fam);
556 family = msymbol (buf);
557 file = msymbol (filename);
558 if (family != last_family)
560 pl = MPLIST_PLIST (ft_list_family (family, 0, 1));
561 last_family = family;
563 ft_info = mplist_get (pl, file);
568 mplist_add (plist, family, ft_info);
573 if (fs) FcFontSetDestroy (fs);
574 if (os) FcObjectSetDestroy (os);
578 /* Return FcCharSet object built from CHAR_LIST or MT. In the latter
579 case, it is assured that the M-text contains at least one
583 fc_build_charset (MPlist *char_list, MText *mt)
585 FcCharSet *cs = FcCharSetCreate ();
591 for (; ! MPLIST_TAIL_P (char_list); char_list = MPLIST_NEXT (char_list))
592 if (! FcCharSetAddChar (cs, (FcChar32) MPLIST_INTEGER (char_list)))
594 FcCharSetDestroy (cs);
602 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
603 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
605 FcCharSetDestroy (cs);
608 if (mtext_nchars (mt) > 0
609 && (mt = mtext_get_prop (mt, 0, Mtext)))
610 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
611 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
613 FcCharSetDestroy (cs);
620 #else /* not HAVE_FONTCONFIG */
623 ft_add_font (char *filename)
636 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
638 ft_info = ft_gen_font (ft_face);
639 FT_Done_Face (ft_face);
643 font = &ft_info->font;
644 font->file = msymbol (filename);
646 plist = mplist_find_by_key (ft_font_list, family);
648 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
652 mplist_add (plist, font->file, ft_info);
653 plist = mplist_push (ft_font_list, family, plist);
659 ft_init_font_list (void)
667 ft_font_list = mplist ();
668 MPLIST_DO (plist, mfont_freetype_path)
669 if (MPLIST_STRING_P (plist)
670 && (pathname = MPLIST_STRING (plist))
671 && stat (pathname, &buf) == 0)
673 if (S_ISREG (buf.st_mode))
674 ft_add_font (pathname);
675 else if (S_ISDIR (buf.st_mode))
677 DIR *dir = opendir (pathname);
681 int len = strlen (pathname);
684 while ((dp = readdir (dir)) != NULL)
686 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
687 strcpy (path, pathname);
689 strcpy (path + len + 1, dp->d_name);
699 /* Return 1 iff the font pointed by FT_INFO has all characters in
703 ft_has_char_list_p (MFontFT *ft_info, MPlist *char_list)
708 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0, &ft_face))
710 MPLIST_DO (cl, char_list)
711 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (cl)) == 0)
713 FT_Done_Face (ft_face);
714 return MPLIST_TAIL_P (cl);
717 /* Return ((FAMILY . FONT) ...) where FONT is a pointer to MFontFT
718 that supports characters in CHAR_LIST or MT. One of CHAR_LIST or
722 ft_list_char_list (MPlist *char_list, MText *mt)
724 MPlist *plist = NULL, *pl, *p;
727 ft_list_family (Mnil, 0, 1);
731 int len = mtext_nchars (mt);
732 MText *extra = mtext_get_prop (mt, 0, Mtext);
733 int total_len = len + (extra ? mtext_nchars (extra) : 0);
736 char_list = mplist ();
737 for (i = 0; i < total_len; i++)
739 int c = (i < len ? mtext_ref_char (mt, i)
740 : mtext_ref_char (extra, i - len));
742 if (! mplist_find_by_value (char_list, (void *) c))
743 mplist_push (char_list, Minteger, (void *) c);
747 MPLIST_DO (pl, ft_font_list)
749 MPLIST_DO (p, MPLIST_PLIST (pl))
751 MFontFT *ft_info = MPLIST_VAL (p);
753 if (ft_has_char_list_p (ft_info, char_list))
755 MSymbol family = mfont_get_prop (&ft_info->font, Mfamily);
759 mplist_push (plist, family, ft_info);
764 M17N_OBJECT_UNREF (char_list);
767 #endif /* not HAVE_FONTCONFIG */
770 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
771 scan all fonts and return ft_font_list. */
774 ft_list_family (MSymbol family, int check_generic, int check_alias)
777 #ifdef HAVE_FONTCONFIG
792 plist = ft_font_list = mplist ();
793 pattern = FcPatternCreate ();
794 os = FcObjectSetBuild (FC_FAMILY, NULL);
795 fs = FcFontList (fc_config, pattern, os);
796 for (i = 0; i < fs->nfont; i++)
798 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
799 (FcChar8 **) &fam) != FcResultMatch)
801 STRDUP_LOWER (buf, bufsize, fam);
803 if (! mplist_find_by_key (ft_font_list, sym))
804 plist = mplist_add (plist, sym, NULL);
806 FcFontSetDestroy (fs);
807 FcObjectSetDestroy (os);
808 FcPatternDestroy (pattern);
813 if (! all_fonts_scaned)
815 MPLIST_DO (plist, ft_font_list)
817 if (! MPLIST_VAL (plist))
818 ft_list_family (MPLIST_KEY (plist), 0, 1);
820 all_fonts_scaned = 1;
825 plist = mplist_find_by_key (ft_font_list, family);
828 if (! MPLIST_VAL (plist))
830 fam = MSYMBOL_NAME (family);
831 pattern = FcPatternCreate ();
832 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
833 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
834 FC_PIXEL_SIZE, FC_LANG, FC_CHARSET, FC_FILE,
836 fs = FcFontList (fc_config, pattern, os);
838 for (i = 0; i < fs->nfont; i++)
840 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
841 p = mplist_add (p, ft_info->font.file, ft_info);
843 MPLIST_VAL (plist) = pl;
844 FcFontSetDestroy (fs);
845 FcObjectSetDestroy (os);
846 FcPatternDestroy (pattern);
849 else if (check_generic
850 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
852 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
855 if (family != generic)
856 plist = ft_list_family (generic, 1, 1);
859 fam = MSYMBOL_NAME (family);
861 mplist_push (ft_font_list, family, plist);
862 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
863 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
866 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
869 STRDUP_LOWER (buf, bufsize, (char *) fam8);
870 family = msymbol (buf);
871 if (msymbol_get (family, Mgeneric_family))
873 pl = ft_list_family (family, 0, 1);
876 MPLIST_DO (pl, MPLIST_PLIST (pl))
877 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
879 plist = ft_font_list;
882 else if (check_alias)
884 /* Check if there exist an alias. */
886 plist = mplist_add (ft_font_list, family, pl);
888 pattern = FcPatternBuild (NULL,
889 FC_FAMILY, FcTypeString, MSYMBOL_NAME (family),
891 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
893 for (i = 0; FcPatternGetString (pattern, FC_FAMILY, i,
894 (FcChar8 **) &fam) == FcResultMatch;
898 /* The last one is a generic family. */
901 FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam,
904 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
905 for (j = 0; FcPatternGetString (pat, FC_FAMILY, j,
906 (FcChar8 **) &fam) == FcResultMatch;
909 /* Now we know that the last J fonts in PATTERN are from
910 generic font, and the first one is not available. So,
911 the remaining ones are aliases. */
913 for (i = 1; i < j; i++)
915 FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &fam);
916 STRDUP_LOWER (buf, bufsize, fam);
918 p = MPLIST_PLIST (ft_list_family (sym, 0, 0));
919 if (! MPLIST_TAIL_P (p))
921 mplist_push (pl, Mt, MPLIST_VAL (p));
928 plist = mplist_add (ft_font_list, family, pl);
931 #else /* not HAVE_FONTCONFIG */
933 if (! all_fonts_scaned)
935 ft_init_font_list ();
936 all_fonts_scaned = 1;
939 plist = ft_font_list;
942 plist = mplist_find_by_key (ft_font_list, family);
944 plist = mplist_push (ft_font_list, family, mplist ());
946 #endif /* not HAVE_FONTCONFIG */
952 ft_list_language (MSymbol language)
954 MPlist *plist = NULL;
957 if (! ft_language_list)
958 ft_language_list = mplist ();
959 else if ((plist = mplist_find_by_key (ft_language_list, language)))
960 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
962 mt = mlanguage_text (language);
964 #ifdef HAVE_FONTCONFIG
966 FcPattern *pattern = NULL;
967 FcCharSet *cs = NULL;
968 FcLangSet *ls = NULL;
970 if (! (pattern = FcPatternCreate ()))
973 if (mt && mtext_nchars (mt) > 0)
975 cs = fc_build_charset (NULL, mt);
976 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
981 if (! (ls = FcLangSetCreate ()))
983 if (! FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
984 || ! FcPatternAddLangSet (pattern, FC_LANG, ls))
988 plist = fc_list_pattern (pattern);
990 if (cs) FcCharSetDestroy (cs);
991 if (ls) FcLangSetDestroy (ls);
992 if (pattern) FcPatternDestroy (pattern);
994 #else /* not HAVE_FONTCONFIG */
995 if (mt && mtext_nchars (mt) > 0)
996 plist = ft_list_char_list (NULL, mt);
997 #endif /* not HAVE_FONTCONFIG */
999 mplist_push (ft_language_list, language, plist);
1004 ft_list_script (MSymbol script)
1006 MPlist *plist = NULL;
1009 if (! ft_script_list)
1010 ft_script_list = mplist ();
1011 else if ((plist = mplist_find_by_key (ft_script_list, script)))
1012 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1014 char_list = mscript__char_list (script);
1016 #ifdef HAVE_FONTCONFIG
1019 FcPattern *pattern = NULL;
1022 if (! (pattern = FcPatternCreate ()))
1024 cs = fc_build_charset (char_list, NULL);
1025 if (cs && ! FcPatternAddCharSet (pattern, FC_CHARSET, cs))
1027 plist = fc_list_pattern (pattern);
1029 if (cs) FcCharSetDestroy (cs);
1030 if (pattern) FcPatternDestroy (pattern);
1032 #else /* not HAVE_FONTCONFIG */
1034 plist = ft_list_char_list (char_list, NULL);
1035 #endif /* not HAVE_FONTCONFIG */
1037 mplist_push (ft_script_list, script, plist);
1042 ft_check_cap_otf (MFontFT *ft_info, MFontCapability *cap, FT_Face ft_face)
1045 if (ft_info->otf == invalid_otf)
1049 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
1051 ft_info->otf = OTF_open_ft_face (ft_face);
1054 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1057 ft_info->otf = invalid_otf;
1061 if (cap->features[MFONT_OTT_GSUB].nfeatures
1062 && (OTF_check_features
1064 cap->script_tag, cap->langsys_tag,
1065 cap->features[MFONT_OTT_GSUB].tags,
1066 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
1068 if (cap->features[MFONT_OTT_GPOS].nfeatures
1069 && (OTF_check_features
1071 cap->script_tag, cap->langsys_tag,
1072 cap->features[MFONT_OTT_GPOS].tags,
1073 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
1076 #else /* not HAVE_OTF */
1078 #endif /* not HAVE_OTF */
1082 ft_check_language (MFontFT *ft_info, MSymbol language, FT_Face ft_face)
1086 int ft_face_allocaed = 0;
1090 #ifdef HAVE_FONTCONFIG
1091 if (ft_info->langset
1092 && (FcLangSetHasLang (ft_info->langset,
1093 (FcChar8 *) MSYMBOL_NAME (language))
1094 != FcLangDifferentLang))
1096 #endif /* HAVE_FONTCONFIG */
1098 mt = mlanguage_text (language);
1099 if (! mt || mtext_nchars (mt) == 0)
1104 char *filename = MSYMBOL_NAME (ft_info->font.file);
1106 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1108 ft_face_allocaed = 1;
1111 len = mtext_nchars (mt);
1112 extra = mtext_get_prop (mt, 0, Mtext);
1113 total_len = len + (extra ? mtext_nchars (extra) : 0);
1115 for (i = 0; i < total_len; i++)
1117 int c = (i < len ? mtext_ref_char (mt, i)
1118 : mtext_ref_char (extra, i - len));
1120 #ifdef HAVE_FONTCONFIG
1121 if (ft_info->charset
1122 && FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcFalse)
1124 #endif /* HAVE_FONTCONFIG */
1125 if (FT_Get_Char_Index (ft_face, (FT_ULong) c) == 0)
1129 if (ft_face_allocaed)
1130 FT_Done_Face (ft_face);
1132 return (i == total_len ? 0 : -1);
1136 ft_check_script (MFontFT *ft_info, MSymbol script, FT_Face ft_face)
1138 MPlist *char_list = mscript__char_list (script);
1142 #ifdef HAVE_FONTCONFIG
1143 if (ft_info->charset)
1145 MPLIST_DO (char_list, char_list)
1146 if (FcCharSetHasChar (ft_info->charset,
1147 (FcChar32) MPLIST_INTEGER (char_list)) == FcFalse)
1151 #endif /* HAVE_FONTCONFIG */
1153 int ft_face_allocaed = 0;
1157 char *filename = MSYMBOL_NAME (ft_info->font.file);
1159 if (FT_New_Face (ft_library, filename, 0, &ft_face))
1161 ft_face_allocaed = 1;
1164 MPLIST_DO (char_list, char_list)
1165 if (FT_Get_Char_Index (ft_face, (FT_ULong) MPLIST_INTEGER (char_list))
1168 if (ft_face_allocaed)
1169 FT_Done_Face (ft_face);
1172 return (MPLIST_TAIL_P (char_list) ? 0 : -1);
1175 static MPlist *ft_default_list;
1180 if (ft_default_list)
1181 return ft_default_list;
1182 ft_default_list = mplist ();
1183 #ifdef HAVE_FONTCONFIG
1185 FcPattern *pat = FcPatternCreate ();
1191 FcConfigSubstitute (fc_config, pat, FcMatchPattern);
1192 for (i = 0; FcPatternGetString (pat, FC_FAMILY, i, &fam) == FcResultMatch;
1198 STRDUP_LOWER (buf, bufsize, (char *) fam);
1199 family = msymbol (buf);
1200 if (msymbol_get (family, Mgeneric_family))
1202 plist = MPLIST_PLIST (ft_list_family (family, 0, 1));
1203 MPLIST_DO (plist, plist)
1204 mplist_add (ft_default_list, family, MPLIST_VAL (plist));
1207 #else /* not HAVE_FONTCONFIG */
1211 MPLIST_DO (plist, ft_list_family (Mnil, 0, 1))
1213 pl = MPLIST_PLIST (plist);
1214 if (! MPLIST_TAIL_P (pl))
1215 mplist_add (ft_default_list, MPLIST_KEY (plist), pl);
1218 #endif /* not HAVE_FONTCONFIG */
1219 return ft_default_list;
1223 static MPlist *ft_capability_list;
1226 ft_list_capability (MSymbol capability)
1228 MFontCapability *cap;
1229 MPlist *plist = NULL, *pl;
1231 if (! ft_capability_list)
1232 ft_capability_list = mplist ();
1233 else if ((plist = mplist_find_by_key (ft_capability_list, capability)))
1234 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
1236 cap = mfont__get_capability (capability);
1238 if (cap && cap->language != Mnil)
1240 plist = ft_list_language (cap->language);
1243 plist = mplist_copy (plist);
1246 if (cap && cap->script != Mnil)
1250 plist = ft_list_script (cap->script);
1253 plist = mplist_copy (plist);
1257 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1259 if (ft_check_script (MPLIST_VAL (pl), cap->script, NULL) < 0)
1262 pl = MPLIST_NEXT (pl);
1266 if (cap->script_tag)
1268 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1270 if (ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1273 pl = MPLIST_NEXT (pl);
1277 if (MPLIST_TAIL_P (plist))
1279 M17N_OBJECT_UNREF (plist);
1284 mplist_push (ft_capability_list, capability, plist);
1290 ft_list_file (MSymbol filename)
1292 MPlist *plist = NULL;
1295 ft_file_list = mplist ();
1296 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1297 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1299 #ifdef HAVE_FONTCONFIG
1301 FcPattern *pattern = FcPatternCreate ();
1305 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1306 os = FcObjectSetBuild (FC_FAMILY, NULL);
1307 fs = FcFontList (fc_config, pattern, os);
1314 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1315 (FcChar8 **) &fam) == FcResultMatch)
1320 STRDUP_LOWER (buf, bufsize, fam);
1321 family = msymbol (buf);
1322 pl = ft_list_family (family, 0, 1);
1323 MPLIST_DO (pl, MPLIST_PLIST (pl))
1325 MFontFT *ft_info = MPLIST_VAL (pl);
1327 if (ft_info->font.file == filename)
1330 mplist_add (plist, family, ft_info);
1337 #else /* not HAVE_FONTCONFIG */
1341 MPLIST_DO (pl, ft_list_family (Mnil, 0, 1))
1343 MPLIST_DO (p, MPLIST_PLIST (pl))
1345 MFontFT *ft_info = MPLIST_VAL (pl);
1347 if (ft_info->font.file == filename)
1350 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1358 #endif /* not HAVE_FONTCONFIG */
1360 mplist_push (ft_file_list, filename, plist);
1364 /* The FreeType font driver function SELECT. */
1367 ft_select (MFrame *frame, MFont *font, int limited_size)
1369 MFont *found = NULL;
1370 #ifdef HAVE_FONTCONFIG
1373 int check_font_property = 1;
1375 if (font->file != Mnil)
1377 plist = ft_list_file (font->file);
1380 check_font_property = 0;
1384 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1387 plist = MPLIST_PLIST (ft_list_family (family, 1, 1));
1389 plist = ft_list_default ();
1390 if (MPLIST_TAIL_P (plist))
1394 plist = mplist_copy (plist);
1396 if (font->capability != Mnil)
1398 MFontCapability *cap = mfont__get_capability (font->capability);
1400 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1402 if (cap->script_tag && ft_check_cap_otf (MPLIST_VAL (pl), cap, NULL) < 0)
1408 && ft_check_language (MPLIST_VAL (pl), cap->language, NULL) < 0)
1411 pl = MPLIST_NEXT (pl);
1415 if (check_font_property)
1417 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1418 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1419 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1420 MSymbol alternate_weight = Mnil;
1422 if (weight == Mnormal)
1423 alternate_weight = Mmedium;
1424 else if (weight == Mmedium)
1425 alternate_weight = Mnormal;
1426 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1427 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1429 ft_info = MPLIST_VAL (pl);
1431 && (weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)
1432 && alternate_weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT)))
1434 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1436 && stretch != FONT_PROPERTY (&ft_info->font,
1439 && ft_info->font.size > 0
1440 && ft_info->font.size != font->size))
1443 pl = MPLIST_NEXT (pl);
1447 MPLIST_DO (pl, plist)
1449 font = MPLIST_VAL (plist);
1450 if (limited_size == 0
1452 || font->size <= limited_size)
1458 M17N_OBJECT_UNREF (plist);
1459 #endif /* HAVE_FONTCONFIG */
1464 static MRealizedFont *
1465 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1467 MFontFT *ft_info = (MFontFT *) font;
1468 int reg = spec->property[MFONT_REGISTRY];
1469 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1470 MRealizedFontFT *ft_rfont;
1472 MPlist *plist, *charmap_list = NULL;
1477 /* non-scalable font */
1479 else if (spec->size)
1481 int ratio = mfont_resize_ratio (font);
1483 size = ratio == 100 ? spec->size : spec->size * ratio / 100;
1490 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1491 for (; rfont; rfont = rfont->next)
1492 if (rfont->font == font
1493 && (rfont->font->size ? rfont->font->size == size
1494 : rfont->spec.size == size)
1495 && rfont->spec.property[MFONT_REGISTRY] == reg
1496 && rfont->driver == &mfont__ft_driver)
1500 MDEBUG_DUMP (" [FONT-FT] opening ", "", mdebug_dump_font (&ft_info->font));
1502 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1505 font->type = MFONT_TYPE_FAILURE;
1506 MDEBUG_PRINT (" no (FT_New_Face)\n");
1510 M17N_OBJECT_REF (charmap_list);
1512 charmap_list = ft_get_charmaps (ft_face);
1513 if (registry == Mnil)
1514 registry = Municode_bmp;
1515 plist = mplist_find_by_key (charmap_list, registry);
1518 FT_Done_Face (ft_face);
1519 M17N_OBJECT_UNREF (charmap_list);
1520 MDEBUG_PRINT1 (" no (%s)\n", MSYMBOL_NAME (registry));
1523 charmap_index = (int) MPLIST_VAL (plist);
1524 if ((charmap_index >= 0
1525 && FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index]))
1526 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1528 FT_Done_Face (ft_face);
1529 M17N_OBJECT_UNREF (charmap_list);
1530 font->type = MFONT_TYPE_FAILURE;
1531 MDEBUG_PRINT1 (" no (size %d)\n", size);
1535 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1536 ft_rfont->ft_face = ft_face;
1537 ft_rfont->charmap_list = charmap_list;
1538 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1539 rfont->id = ft_info->font.file;
1540 rfont->spec = *font;
1541 rfont->spec.type = MFONT_TYPE_REALIZED;
1542 rfont->spec.property[MFONT_REGISTRY] = reg;
1543 rfont->spec.size = size;
1544 rfont->frame = frame;
1546 rfont->driver = &mfont__ft_driver;
1547 rfont->info = ft_rfont;
1548 rfont->fontp = ft_face;
1549 rfont->ascent = ft_face->size->metrics.ascender;
1550 rfont->descent = - ft_face->size->metrics.descender;
1551 rfont->max_advance = ft_face->size->metrics.max_advance;
1552 rfont->baseline_offset = 0;
1553 rfont->x_ppem = ft_face->size->metrics.x_ppem;
1554 rfont->y_ppem = ft_face->size->metrics.y_ppem;
1557 BDF_PropertyRec prop;
1559 if (! FT_IS_SCALABLE (ft_face)
1560 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
1562 rfont->baseline_offset = prop.u.integer << 6;
1563 rfont->ascent += prop.u.integer << 6;
1564 rfont->descent -= prop.u.integer << 6;
1567 #endif /* HAVE_FTBDF_H */
1568 if (FT_IS_SCALABLE (ft_face))
1569 rfont->average_width = 0;
1571 rfont->average_width = ft_face->available_sizes->width << 6;
1572 rfont->next = MPLIST_VAL (frame->realized_font_list);
1573 MPLIST_VAL (frame->realized_font_list) = rfont;
1574 MDEBUG_PRINT (" ok\n");
1578 /* The FreeType font driver function FIND_METRIC. */
1581 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1584 FT_Face ft_face = rfont->fontp;
1585 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1587 for (; g != gend; g++)
1591 if (g->g.code == MCHAR_INVALID_CODE)
1593 if (FT_IS_SCALABLE (ft_face))
1596 g->g.rbearing = ft_face->size->metrics.max_advance;
1597 g->g.xadv = g->g.rbearing;
1598 g->g.ascent = ft_face->size->metrics.ascender;
1599 g->g.descent = - ft_face->size->metrics.descender;
1604 BDF_PropertyRec prop;
1605 #endif /* HAVE_FTBDF_H */
1608 g->g.rbearing = g->g.xadv = ft_face->available_sizes->width << 6;
1610 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1612 g->g.ascent = prop.u.integer << 6;
1613 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1614 g->g.descent = prop.u.integer << 6;
1615 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET",
1618 g->g.ascent += prop.u.integer << 6;
1619 g->g.descent -= prop.u.integer << 6;
1623 #endif /* HAVE_FTBDF_H */
1625 g->g.ascent = ft_face->available_sizes->height << 6;
1632 FT_Glyph_Metrics *metrics;
1634 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, FT_LOAD_DEFAULT);
1635 metrics = &ft_face->glyph->metrics;
1636 g->g.lbearing = metrics->horiBearingX;
1637 g->g.rbearing = metrics->horiBearingX + metrics->width;
1638 g->g.xadv = metrics->horiAdvance;
1639 g->g.ascent = metrics->horiBearingY;
1640 g->g.descent = metrics->height - metrics->horiBearingY;
1643 g->g.ascent += rfont->baseline_offset;
1644 g->g.descent -= rfont->baseline_offset;
1650 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1652 MRealizedFont *rfont = NULL;
1653 MRealizedFontFT *ft_rfont;
1656 if (font->type == MFONT_TYPE_REALIZED)
1657 rfont = (MRealizedFont *) font;
1658 else if (font->type == MFONT_TYPE_OBJECT)
1660 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1661 rfont = rfont->next)
1662 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1666 #ifdef HAVE_FONTCONFIG
1667 MFontFT *ft_info = (MFontFT *) font;
1669 if (! ft_info->charset)
1671 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1672 MSYMBOL_NAME (font->file),
1674 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1675 FcFontSet *fs = FcFontList (fc_config, pat, os);
1678 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1679 &ft_info->charset) == FcResultMatch)
1680 ft_info->charset = FcCharSetCopy (ft_info->charset);
1682 ft_info->charset = FcCharSetCreate ();
1683 FcFontSetDestroy (fs);
1684 FcObjectSetDestroy (os);
1685 FcPatternDestroy (pat);
1687 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1688 #else /* not HAVE_FONTCONFIG */
1689 rfont = ft_open (frame, font, spec, NULL);
1690 #endif /* not HAVE_FONTCONFIG */
1694 MFATAL (MERROR_FONT_FT);
1698 ft_rfont = rfont->info;
1699 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1703 /* The FreeType font driver function ENCODE_CHAR. */
1706 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1708 MRealizedFont *rfont;
1709 MRealizedFontFT *ft_rfont;
1712 if (font->type == MFONT_TYPE_REALIZED)
1713 rfont = (MRealizedFont *) font;
1714 else if (font->type == MFONT_TYPE_OBJECT)
1716 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1717 rfont = rfont->next)
1718 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1722 rfont = ft_open (frame, font, spec, NULL);
1728 MFATAL (MERROR_FONT_FT);
1730 ft_rfont = rfont->info;
1731 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1732 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1735 /* The FreeType font driver function RENDER. */
1737 #define NUM_POINTS 0x1000
1740 MDrawPoint points[NUM_POINTS];
1745 ft_render (MDrawWindow win, int x, int y,
1746 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1747 int reverse, MDrawRegion region)
1750 MRealizedFace *rface = from->rface;
1751 MFrame *frame = rface->frame;
1752 FT_Int32 load_flags = FT_LOAD_RENDER;
1755 MPointTable point_table[8];
1756 int baseline_offset;
1757 int pixel_mode = -1;
1762 /* It is assured that the all glyphs in the current range use the
1763 same realized face. */
1764 ft_face = rface->rfont->fontp;
1765 baseline_offset = rface->rfont->baseline_offset >> 6;
1767 if (! gstring->anti_alias)
1769 #ifdef FT_LOAD_TARGET_MONO
1770 load_flags |= FT_LOAD_TARGET_MONO;
1772 load_flags |= FT_LOAD_MONOCHROME;
1776 for (i = 0; i < 8; i++)
1777 point_table[i].p = point_table[i].points;
1779 for (g = from; g < to; x += g++->g.xadv)
1783 MPointTable *ptable;
1787 FT_Load_Glyph (ft_face, (FT_UInt) g->g.code, load_flags);
1789 pixel_mode = ft_face->glyph->bitmap.pixel_mode;
1790 yoff = y - ft_face->glyph->bitmap_top + g->g.yoff;
1791 bmp = ft_face->glyph->bitmap.buffer;
1792 width = ft_face->glyph->bitmap.width;
1793 pitch = ft_face->glyph->bitmap.pitch;
1795 if (pixel_mode != FT_PIXEL_MODE_MONO)
1796 for (i = 0; i < ft_face->glyph->bitmap.rows;
1797 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1799 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1800 for (j = 0; j < width; j++, xoff++)
1802 intensity = bmp[j] >> 5;
1805 ptable = point_table + intensity;
1806 ptable->p->x = xoff;
1807 ptable->p->y = yoff - baseline_offset;
1809 if (ptable->p - ptable->points == NUM_POINTS)
1811 (*frame->driver->draw_points)
1813 reverse ? 7 - intensity : intensity,
1814 ptable->points, NUM_POINTS, region);
1815 ptable->p = ptable->points;
1821 for (i = 0; i < ft_face->glyph->bitmap.rows;
1822 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1824 xoff = x + ft_face->glyph->bitmap_left + g->g.xoff;
1825 for (j = 0; j < width; j++, xoff++)
1827 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1830 ptable = point_table;
1831 ptable->p->x = xoff;
1832 ptable->p->y = yoff - baseline_offset;
1834 if (ptable->p - ptable->points == NUM_POINTS)
1836 (*frame->driver->draw_points) (frame, win, rface,
1838 ptable->points, NUM_POINTS, region);
1839 ptable->p = ptable->points;
1846 if (pixel_mode != FT_PIXEL_MODE_MONO)
1848 for (i = 1; i < 8; i++)
1849 if (point_table[i].p != point_table[i].points)
1850 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1851 point_table[i].points,
1852 point_table[i].p - point_table[i].points, region);
1856 if (point_table[0].p != point_table[0].points)
1857 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1858 point_table[0].points,
1859 point_table[0].p - point_table[0].points, region);
1864 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1866 MPlist *pl = NULL, *p;
1868 MPlist *file_list = NULL;
1869 MPlist *family_list = NULL, *capability_list = NULL;
1870 MSymbol registry = Mnil;
1872 MDEBUG_DUMP (" [FONT-FT] listing ", "", mdebug_dump_font (font));
1878 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1879 if (registry != Mnil && registry != Miso8859_1)
1881 char *reg = MSYMBOL_NAME (registry);
1883 if (strncmp (reg, "unicode-", 8)
1884 && strncmp (reg, "apple-roman", 11)
1885 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1889 if (font->file != Mnil
1890 && ! (file_list = ft_list_file (font->file)))
1892 family = FONT_PROPERTY (font, MFONT_FAMILY);
1894 && (family_list = MPLIST_PLIST (ft_list_family (family, 1, 1)))
1895 && MPLIST_TAIL_P (family_list))
1897 if (font->capability != Mnil)
1899 capability_list = ft_list_capability (font->capability);
1900 if (! capability_list || MPLIST_TAIL_P (capability_list))
1905 if (! file_list && ! family_list && ! capability_list)
1907 /* No restriction. Get all fonts. */
1909 MPLIST_DO (family_list, ft_list_family (Mnil, 0, 1))
1911 MPLIST_DO (p, MPLIST_PLIST (family_list))
1912 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1920 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1925 for (p = pl; ! MPLIST_TAIL_P (p);)
1927 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1928 p = MPLIST_NEXT (p);
1935 MPLIST_DO (p, family_list)
1936 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1939 if (capability_list)
1942 for (p = pl; ! MPLIST_TAIL_P (p);)
1944 if (mplist_find_by_value (capability_list, MPLIST_VAL (p)))
1945 p = MPLIST_NEXT (p);
1952 MPLIST_DO (p, capability_list)
1953 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1959 && (font->property[MFONT_WEIGHT] + font->property[MFONT_STYLE]
1960 + font->property[MFONT_STRETCH] + font->size) > 0)
1962 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1963 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1964 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1965 int size = font->size;
1967 for (p = pl; ! MPLIST_TAIL_P (p); )
1969 MFontFT *ft_info = MPLIST_VAL (p);
1972 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1974 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1976 && stretch != FONT_PROPERTY (&ft_info->font,
1979 && ft_info->font.size > 0
1980 && ft_info->font.size != size))
1983 p = MPLIST_NEXT (p);
1989 mplist_push (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1991 if (maxnum && maxnum <= num)
1994 M17N_OBJECT_UNREF (pl);
1997 MDEBUG_PRINT1 (" %d found\n", num);
2002 ft_list_family_names (MFrame *frame, MPlist *plist)
2008 #ifdef HAVE_FONTCONFIG
2009 fc_init_font_list ();
2010 #else /* not HAVE_FONTCONFIG */
2011 ft_init_font_list ();
2012 #endif /* not HAVE_FONTCONFIG */
2015 MPLIST_DO (pl, ft_font_list)
2017 MSymbol family = MPLIST_KEY (pl);
2020 #ifdef HAVE_FONTCONFIG
2021 if (msymbol_get (family, Mgeneric_family) != Mnil)
2023 #endif /* HAVE_FONTCONFIG */
2024 MPLIST_DO (p, plist)
2026 MSymbol sym = MPLIST_SYMBOL (p);
2030 if (strcmp (MSYMBOL_NAME (sym), MSYMBOL_NAME (family)) > 0)
2032 mplist_push (p, Msymbol, family);
2036 if (MPLIST_TAIL_P (p))
2037 mplist_push (p, Msymbol, family);
2042 ft_check_capability (MRealizedFont *rfont, MSymbol capability)
2044 MFontFT *ft_info = (MFontFT *) rfont->font;
2045 MRealizedFontFT *ft_rfont = rfont->info;
2046 MFontCapability *cap = mfont__get_capability (capability);
2048 if (cap->script_tag)
2050 if (ft_check_cap_otf (ft_info, cap, ft_rfont->ft_face) < 0)
2053 else if (cap->script != Mnil
2054 && ft_check_script (ft_info, cap->script, ft_rfont->ft_face) < 0)
2056 if (cap->language != Mnil
2057 && ft_check_language (ft_info, cap->language, ft_rfont->ft_face) < 0)
2062 static MRealizedFont *
2063 ft_encapsulate (MFrame *frame, MSymbol data_type, void *data)
2066 MRealizedFont *rfont;
2067 MRealizedFontFT *ft_rfont;
2070 if (data_type == Mfontconfig)
2072 #ifdef HAVE_FONTCONFIG
2073 FcPattern *pattern = data;
2075 if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &ft_face)
2078 ft_info = fc_gen_font (pattern, NULL);
2079 #else /* not HAVE_FONTCONFIG */
2081 #endif /* not HAVE_FONTCONFIG */
2083 else if (data_type == Mfreetype)
2086 ft_info = ft_gen_font (ft_face);
2091 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
2092 ft_rfont->ft_face = ft_face;
2093 ft_rfont->face_encapsulated = 1;
2095 MDEBUG_PRINT1 (" [FONT-FT] encapsulating %s", (char *) ft_face->family_name);
2097 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
2098 rfont->id = ft_info->font.file;
2099 rfont->font = (MFont *) ft_info;
2100 rfont->info = ft_rfont;
2101 rfont->fontp = ft_face;
2102 rfont->driver = &mfont__ft_driver;
2103 rfont->spec = ft_info->font;
2104 rfont->spec.type = MFONT_TYPE_REALIZED;
2105 rfont->frame = frame;
2106 rfont->ascent = ft_face->size->metrics.ascender >> 6;
2107 rfont->descent = - ft_face->size->metrics.descender >> 6;
2108 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
2109 rfont->baseline_offset = 0;
2110 rfont->x_ppem = ft_face->size->metrics.x_ppem;
2111 rfont->y_ppem = ft_face->size->metrics.y_ppem;
2114 BDF_PropertyRec prop;
2116 if (! FT_IS_SCALABLE (ft_face)
2117 && FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &prop) == 0)
2119 rfont->baseline_offset = prop.u.integer << 6;
2120 rfont->ascent += prop.u.integer << 6;
2121 rfont->descent -= prop.u.integer << 6;
2124 #endif /* HAVE_FTBDF_H */
2125 if (FT_IS_SCALABLE (ft_face))
2126 rfont->average_width = 0;
2128 rfont->average_width = ft_face->available_sizes->width << 6;
2129 rfont->next = MPLIST_VAL (frame->realized_font_list);
2130 MPLIST_VAL (frame->realized_font_list) = rfont;
2136 ft_close (MRealizedFont *rfont)
2138 if (! rfont->encapsulating)
2141 M17N_OBJECT_UNREF (rfont->info);
2146 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2151 OTF *otf = get_otf (font, NULL);
2155 for (i = 0; i < 2; i++)
2157 if (! spec->features[i])
2159 for (n = 0; spec->features[i][n]; n++);
2160 tags = alloca (sizeof (OTF_Tag) * n);
2161 for (n = 0, negative = 0; spec->features[i][n]; n++)
2163 if (spec->features[i][n] == 0xFFFFFFFF)
2166 tags[n - 1] = spec->features[i][n] | 0x80000000;
2168 tags[n] = spec->features[i][n];
2170 if (n - negative > 0
2171 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2172 tags, n - negative) != 1)
2177 #endif /* HAVE_OTF */
2178 return ((! spec->features[0] || spec->features[0][0] == 0xFFFFFFFF)
2179 && (! spec->features[1] || spec->features[1][0] == 0xFFFFFFFF));
2185 get_otf (MFLTFont *font, FT_Face *ft_face)
2187 MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2188 MFontFT *ft_info = (MFontFT *) rfont->font;
2189 MRealizedFontFT *ft_rfont = rfont->info;
2190 OTF *otf = ft_info->otf;
2194 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2195 otf = OTF_open_ft_face (ft_rfont->ft_face);
2197 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2199 if (! otf || OTF_get_table (otf, "head") < 0)
2204 *ft_face = ft_rfont->ft_face;
2205 return (otf == invalid_otf ? NULL : otf);
2208 #define DEVICE_DELTA(table, size) \
2209 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2210 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
2214 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2215 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2217 if (anchor->AnchorFormat == 2)
2219 FT_Outline *outline;
2220 int ap = anchor->f.f1.AnchorPoint;
2222 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2223 outline = &ft_face->glyph->outline;
2224 if (ap < outline->n_points)
2226 *x = outline->points[ap].x << 6;
2227 *y = outline->points[ap].y << 6;
2230 else if (anchor->AnchorFormat == 3)
2232 if (anchor->f.f2.XDeviceTable.offset)
2233 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2234 if (anchor->f.f2.YDeviceTable.offset)
2235 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2238 #endif /* HAVE_OTF */
2241 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2242 MFLTGlyphString *in, int from, int to,
2243 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2245 int len = to - from;
2248 MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2249 MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
2252 OTF_GlyphString otf_gstring;
2254 char script[5], *langsys = NULL;
2255 char *gsub_features = NULL, *gpos_features = NULL;
2260 otf = get_otf (font, &face);
2263 OTF_tag_name (spec->script, script);
2266 langsys = alloca (5);
2267 OTF_tag_name (spec->langsys, langsys);
2269 for (i = 0; i < 2; i++)
2273 if (spec->features[i])
2275 for (j = 0; spec->features[i][j]; j++);
2277 p = gsub_features = alloca (6 * j);
2279 p = gpos_features = alloca (6 * j);
2280 for (j = 0; spec->features[i][j]; j++)
2282 if (spec->features[i][j] == 0xFFFFFFFF)
2283 *p++ = '*', *p++ = ',';
2286 OTF_tag_name (spec->features[i][j], p);
2295 otf_gstring.size = otf_gstring.used = len;
2296 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2297 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2298 for (i = 0; i < len; i++)
2300 otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
2301 otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2304 OTF_drive_gdef (otf, &otf_gstring);
2305 gidx = out ? out->used : from;
2309 OTF_Feature *features;
2312 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
2315 features = otf->gsub->FeatureList.Feature;
2318 if (out->allocated < gidx + otf_gstring.used)
2320 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2321 i < otf_gstring.used; i++, otfg++, g++, out->used++)
2323 int feature_idx = otfg->positioning_type >> 4;
2325 int min_from, max_to;
2327 *g = in_glyphs[from + otfg->f.index.from];
2328 min_from = g->g.from, max_to = g->g.to;
2330 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2331 if (in_glyphs[from + j].g.code == otfg->glyph_id)
2333 g->g.c = in_glyphs[from + j].g.c;
2338 tag = features[feature_idx - 1].FeatureTag;
2339 tag = PACK_OTF_TAG (tag);
2340 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2342 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2344 if (min_from > in_glyphs[from + j].g.from)
2345 min_from = in_glyphs[from + j].g.from;
2346 if (max_to < in_glyphs[from + j].g.to)
2347 max_to = in_glyphs[from + j].g.to;
2349 if (g->g.code != otfg->glyph_id)
2351 g->g.code = otfg->glyph_id;
2354 g->g.from = min_from, g->g.to = max_to;
2359 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2362 int feature_idx = otfg->positioning_type >> 4;
2366 tag = features[feature_idx - 1].FeatureTag;
2367 tag = PACK_OTF_TAG (tag);
2368 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2370 g = in_glyphs + (from + j);
2371 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2379 if (out->allocated < gidx + len)
2381 for (i = 0; i < len; i++)
2382 out_glyphs[out->used++] = in_glyphs[from + i];
2387 OTF_Feature *features;
2390 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2393 features = otf->gpos->FeatureList.Feature;
2396 MGlyph *base = NULL, *mark = NULL;
2397 int x_ppem = face->size->metrics.x_ppem;
2398 int y_ppem = face->size->metrics.y_ppem;
2399 int x_scale = face->size->metrics.x_scale;
2400 int y_scale = face->size->metrics.y_scale;
2402 for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2403 i < otf_gstring.used; i++, otfg++)
2406 int adjust_idx = otfg->glyph_id ? j : j - 1;
2407 int feature_idx = otfg->positioning_type >> 4;
2411 tag = features[feature_idx - 1].FeatureTag;
2412 tag = PACK_OTF_TAG (tag);
2413 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2415 switch (otfg->positioning_type & 0xF)
2419 case 1: /* Single */
2422 int format = otfg->f.f1.format;
2424 if (format & OTF_XPlacement)
2425 adjustment[adjust_idx].xoff
2426 += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2427 if (format & OTF_XPlaDevice)
2428 adjustment[adjust_idx].xoff
2429 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2430 if (format & OTF_YPlacement)
2431 adjustment[adjust_idx].yoff
2432 -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2433 if (format & OTF_YPlaDevice)
2434 adjustment[adjust_idx].yoff
2435 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2436 if (format & OTF_XAdvance)
2437 adjustment[adjust_idx].xadv
2438 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2439 if (format & OTF_XAdvDevice)
2440 adjustment[adjust_idx].xadv
2441 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2442 if (format & OTF_YAdvance)
2443 adjustment[adjust_idx].yadv
2444 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2445 if (format & OTF_YAdvDevice)
2446 adjustment[adjust_idx].yadv
2447 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2448 adjustment[adjust_idx].set = 1;
2451 case 3: /* Cursive */
2452 /* Not yet supported. */
2454 case 4: /* Mark-to-Base */
2455 case 5: /* Mark-to-Ligature */
2459 goto label_adjust_anchor;
2460 default: /* i.e. case 6 Mark-to-Mark */
2465 label_adjust_anchor:
2467 int base_x, base_y, mark_x, mark_y;
2468 int this_from, this_to;
2471 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2472 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2473 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2474 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2476 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2477 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2478 x_ppem, y_ppem, &base_x, &base_y);
2479 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2480 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2481 x_ppem, y_ppem, &mark_x, &mark_y);
2482 adjustment[adjust_idx].xoff = base_x - mark_x;
2483 adjustment[adjust_idx].yoff = - (base_y - mark_y);
2484 adjustment[adjust_idx].back = (g - prev);
2485 adjustment[adjust_idx].xadv = 0;
2486 adjustment[adjust_idx].advance_is_absolute = 1;
2487 adjustment[adjust_idx].set = 1;
2488 this_from = g->g.from;
2490 for (k = 0; prev + k < g; k++)
2492 if (this_from > prev[k].g.from)
2493 this_from = prev[k].g.from;
2494 if (this_to < prev[k].g.to)
2495 this_to = prev[k].g.to;
2497 for (; prev <= g; prev++)
2499 prev->g.from = this_from;
2500 prev->g.to = this_to;
2506 if (otfg->GlyphClass == OTF_GlyphClass0)
2508 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2518 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2520 if (otfg->positioning_type & 0xF)
2522 int feature_idx = otfg->positioning_type >> 4;
2526 tag = features[feature_idx - 1].FeatureTag;
2527 tag = PACK_OTF_TAG (tag);
2528 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2530 g = in_glyphs + (from + j);
2531 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2538 free (otf_gstring.glyphs);
2542 if (otf_gstring.glyphs)
2543 free (otf_gstring.glyphs);
2544 #endif /* HAVE_OTF */
2547 if (out->allocated < out->used + len)
2549 font->get_metrics (font, in, from, to);
2550 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2551 sizeof (MGlyph) * len);
2558 ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2559 MFLTGlyphString *in, int from, int to)
2561 return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
2566 static unsigned char *iterate_bitmap;
2569 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2571 if (glyph_id <= otf->cmap->max_glyph_id)
2572 iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2577 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2578 int from, int to, unsigned char *table)
2580 OTF *otf = get_otf (font, NULL);
2583 unsigned char *bitmap = NULL;
2585 char script[5], *langsys = NULL;
2589 if (OTF_get_table (otf, "cmap") < 0)
2591 if (! spec->features[0])
2593 strcpy (id, "feature-");
2595 OTF_tag_name (spec->script, script);
2598 langsys = alloca (5);
2599 OTF_tag_name (spec->langsys, langsys);
2601 bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2602 for (i = 0; spec->features[0][i]; i++)
2606 OTF_tag_name (spec->features[0][i], id + 8);
2607 bmp = OTF_get_data (otf, id);
2610 iterate_bitmap = bmp = calloc (bmp_size, 1);
2611 OTF_iterate_gsub_feature (otf, iterate_callback,
2612 script, langsys, id + 8);
2613 OTF_put_data (otf, id, bmp, free);
2615 if (i == 0 && ! spec->features[0][1])
2616 /* Single feature */
2622 bitmap = alloca (bmp_size);
2623 memcpy (bitmap, bmp, bmp_size);
2629 for (j = 0; j < bmp_size; j++)
2630 bitmap[j] &= bmp[j];
2634 for (i = 0; i < bmp_size; i++)
2637 for (j = 0; j < 8; j++)
2638 if (bitmap[i] & (1 << j))
2640 int c = OTF_get_unicode (otf, (i * 8) + j);
2642 if (c >= from && c <= to)
2643 table[c - from] = 1;
2654 MFontDriver mfont__ft_driver =
2655 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2656 ft_render, ft_list, ft_list_family_names, ft_check_capability,
2657 ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
2659 ft_iterate_otf_feature
2660 #endif /* HAVE_OTF */
2668 if (FT_Init_FreeType (&ft_library) != 0)
2669 MERROR (MERROR_FONT_FT, -1);
2671 for (i = 0; i < ft_to_prop_size; i++)
2672 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2674 Mmedium = msymbol ("medium");
2676 Mnull = msymbol ("");
2678 M0[0] = msymbol ("0-0");
2679 M0[1] = msymbol ("0-1");
2680 M0[2] = msymbol ("0-2");
2681 M0[3] = msymbol ("0-3");
2682 M0[4] = msymbol ("0-4");
2683 M3_1 = msymbol ("3-1");
2684 M1_0 = msymbol ("1-0");
2686 #ifdef HAVE_FONTCONFIG
2687 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2689 FC_vs_M17N_font_prop *table = fc_all_table[i];
2692 for (j = 0; table[j].m17n_value; j++)
2693 table[j].sym = msymbol (table[j].m17n_value);
2694 table[j].sym = table[j - 1].sym;
2701 MSymbol serif, sans_serif, monospace;
2703 fc_config = FcInitLoadConfigAndFonts ();
2704 if (mfont_freetype_path)
2706 MPLIST_DO (plist, mfont_freetype_path)
2707 if (MPLIST_STRING_P (plist)
2708 && (pathname = MPLIST_STRING (plist))
2709 && stat (pathname, &buf) == 0)
2711 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2714 while ((dir = FcStrListNext (strlist)))
2715 if (strcmp ((char *) dir, pathname) == 0)
2718 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2719 FcStrListDone (strlist);
2722 Mgeneric_family = msymbol ("generic famly");
2723 serif = msymbol ("serif");
2724 msymbol_put (serif, Mgeneric_family, serif);
2725 sans_serif = msymbol ("sans-serif");
2726 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2727 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2728 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2729 monospace = msymbol ("monospace");
2730 msymbol_put (monospace, Mgeneric_family, monospace);
2731 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2733 #endif /* HAVE_FONTCONFIG */
2743 if (ft_default_list)
2745 M17N_OBJECT_UNREF (ft_default_list);
2746 ft_default_list = NULL;
2751 MPLIST_DO (plist, ft_font_list)
2753 if (MPLIST_VAL (plist))
2754 MPLIST_DO (p, MPLIST_VAL (plist))
2756 if (MPLIST_KEY (p) != Mt)
2757 free_ft_info (MPLIST_VAL (p));
2759 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2761 M17N_OBJECT_UNREF (ft_font_list);
2762 ft_font_list = NULL;
2764 if (ft_language_list)
2766 MPLIST_DO (plist, ft_language_list)
2767 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2768 M17N_OBJECT_UNREF (ft_language_list);
2769 ft_language_list = NULL;
2774 MPLIST_DO (plist, ft_script_list)
2775 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2776 M17N_OBJECT_UNREF (ft_script_list);
2777 ft_script_list = NULL;
2780 if (ft_capability_list)
2782 MPLIST_DO (plist, ft_capability_list)
2783 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2784 M17N_OBJECT_UNREF (ft_capability_list);
2785 ft_capability_list = NULL;
2790 MPLIST_DO (plist, ft_file_list)
2791 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2792 M17N_OBJECT_UNREF (ft_file_list);
2793 ft_file_list = NULL;
2796 FT_Done_FreeType (ft_library);
2797 #ifdef HAVE_FONTCONFIG
2798 FcConfigDestroy (fc_config);
2800 #endif /* HAVE_FONTCONFIG */
2801 all_fonts_scaned = 0;
2804 #ifdef HAVE_FONTCONFIG
2807 mfont__ft_parse_name (const char *name, MFont *font)
2809 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2818 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2820 STRDUP_LOWER (buf, bufsize, (char *) str);
2821 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2823 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2825 STRDUP_LOWER (buf, bufsize, (char *) str);
2826 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2828 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2829 mfont__set_property (font, MFONT_WEIGHT,
2830 fc_decode_prop (val, fc_weight_table,
2831 fc_weight_table_size));
2832 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2833 mfont__set_property (font, MFONT_STYLE,
2834 fc_decode_prop (val, fc_slant_table,
2835 fc_slant_table_size));
2836 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2837 mfont__set_property (font, MFONT_STRETCH,
2838 fc_decode_prop (val, fc_width_table,
2839 fc_width_table_size));
2840 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2841 font->size = size * 10 + 0.5;
2842 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2843 font->size = - (size * 10 + 0.5);
2844 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2846 font->file = msymbol ((char *) str);
2848 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2849 font->type = MFONT_TYPE_SPEC;
2850 FcPatternDestroy (pat);
2855 mfont__ft_unparse_name (MFont *font)
2857 FcPattern *pat = fc_get_pattern (font);
2858 char *name = (char *) FcNameUnparse (pat);
2860 FcPatternDestroy (pat);
2863 #endif /* HAVE_FONTCONFIG */
2865 #endif /* HAVE_FREETYPE */