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);
2145 /* See the comment of parse_otf_command (m17n-flt.c). */
2148 ft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
2150 #define FEATURE_NONE(IDX) (! spec->features[IDX])
2152 #define FEATURE_ANY(IDX) \
2153 (spec->features[IDX] \
2154 && spec->features[IDX][0] == 0xFFFFFFFF && spec->features[IDX][1] == 0)
2159 OTF *otf = get_otf (font, NULL);
2161 if (FEATURE_ANY (0) && FEATURE_ANY (1))
2162 /* Return 1 iff any of GSUB or GPOS support the script (and language). */
2164 && (OTF_check_features (otf, 0, spec->script, spec->langsys,
2166 || OTF_check_features (otf, 1, spec->script, spec->langsys,
2169 for (i = 0; i < 2; i++)
2170 if (! FEATURE_ANY (i))
2172 if (FEATURE_NONE (i))
2175 && OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2180 if (spec->features[i][0] == 0xFFFFFFFF)
2183 || OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2189 for (n = 1; spec->features[i][n]; n++);
2190 tags = alloca (sizeof (OTF_Tag) * n);
2191 for (n = 0, negative = 0; spec->features[i][n]; n++)
2193 if (spec->features[i][n] == 0xFFFFFFFF)
2196 tags[n - 1] = spec->features[i][n] | 0x80000000;
2198 tags[n] = spec->features[i][n];
2200 if (OTF_check_features (otf, i == 0, spec->script, spec->langsys,
2201 tags, n - negative) != 1)
2206 #endif /* HAVE_OTF */
2207 return (FEATURE_NONE (0) ? (FEATURE_NONE (1) || FEATURE_ANY (1))
2208 : (FEATURE_NONE (1) && FEATURE_ANY (0)));
2214 get_otf (MFLTFont *font, FT_Face *ft_face)
2216 MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
2217 MFontFT *ft_info = (MFontFT *) rfont->font;
2218 MRealizedFontFT *ft_rfont = rfont->info;
2219 OTF *otf = ft_info->otf;
2223 #if (LIBOTF_MAJOR_VERSION > 0 || LIBOTF_MINOR_VERSION > 9 || LIBOTF_RELEASE_NUMBER > 4)
2224 otf = OTF_open_ft_face (ft_rfont->ft_face);
2226 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
2228 if (! otf || OTF_get_table (otf, "head") < 0)
2233 *ft_face = ft_rfont->ft_face;
2234 return (otf == invalid_otf ? NULL : otf);
2237 #define DEVICE_DELTA(table, size) \
2238 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
2239 ? (table).DeltaValue[(size) - (table).StartSize] << 6 \
2243 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
2244 unsigned code, int x_ppem, int y_ppem, int *x, int *y)
2246 if (anchor->AnchorFormat == 2)
2248 FT_Outline *outline;
2249 int ap = anchor->f.f1.AnchorPoint;
2251 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
2252 outline = &ft_face->glyph->outline;
2253 if (ap < outline->n_points)
2255 *x = outline->points[ap].x << 6;
2256 *y = outline->points[ap].y << 6;
2259 else if (anchor->AnchorFormat == 3)
2261 if (anchor->f.f2.XDeviceTable.offset)
2262 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
2263 if (anchor->f.f2.YDeviceTable.offset)
2264 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
2267 #endif /* HAVE_OTF */
2270 ft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
2271 MFLTGlyphString *in, int from, int to,
2272 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
2274 int len = to - from;
2277 MGlyph *in_glyphs = (MGlyph *) (in->glyphs);
2278 MGlyph *out_glyphs = out ? (MGlyph *) (out->glyphs) : NULL;
2281 OTF_GlyphString otf_gstring;
2283 char script[5], *langsys = NULL;
2284 char *gsub_features = NULL, *gpos_features = NULL;
2289 otf = get_otf (font, &face);
2292 OTF_tag_name (spec->script, script);
2295 langsys = alloca (5);
2296 OTF_tag_name (spec->langsys, langsys);
2298 for (i = 0; i < 2; i++)
2302 if (spec->features[i])
2304 for (j = 0; spec->features[i][j]; j++);
2306 p = gsub_features = alloca (6 * j);
2308 p = gpos_features = alloca (6 * j);
2309 for (j = 0; spec->features[i][j]; j++)
2311 if (spec->features[i][j] == 0xFFFFFFFF)
2312 *p++ = '*', *p++ = ',';
2315 OTF_tag_name (spec->features[i][j], p);
2324 otf_gstring.size = otf_gstring.used = len;
2325 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
2326 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
2327 for (i = 0; i < len; i++)
2329 otf_gstring.glyphs[i].c = ((MGlyph *)in->glyphs)[from + i].g.c & 0x11FFFF;
2330 otf_gstring.glyphs[i].glyph_id = ((MGlyph *)in->glyphs)[from + i].g.code;
2333 OTF_drive_gdef (otf, &otf_gstring);
2334 gidx = out ? out->used : from;
2338 OTF_Feature *features;
2341 if (OTF_drive_gsub_with_log (otf, &otf_gstring, script, langsys,
2344 features = otf->gsub->FeatureList.Feature;
2347 if (out->allocated < gidx + otf_gstring.used)
2349 for (i = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2350 i < otf_gstring.used; i++, otfg++, g++, out->used++)
2352 int feature_idx = otfg->positioning_type >> 4;
2354 int min_from, max_to;
2356 *g = in_glyphs[from + otfg->f.index.from];
2357 min_from = g->g.from, max_to = g->g.to;
2359 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2360 if (in_glyphs[from + j].g.code == otfg->glyph_id)
2362 g->g.c = in_glyphs[from + j].g.c;
2367 tag = features[feature_idx - 1].FeatureTag;
2368 tag = PACK_OTF_TAG (tag);
2369 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2371 for (j = otfg->f.index.from + 1; j <= otfg->f.index.to; j++)
2373 if (min_from > in_glyphs[from + j].g.from)
2374 min_from = in_glyphs[from + j].g.from;
2375 if (max_to < in_glyphs[from + j].g.to)
2376 max_to = in_glyphs[from + j].g.to;
2378 if (g->g.code != otfg->glyph_id)
2380 g->g.code = otfg->glyph_id;
2383 g->g.from = min_from, g->g.to = max_to;
2388 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2391 int feature_idx = otfg->positioning_type >> 4;
2395 tag = features[feature_idx - 1].FeatureTag;
2396 tag = PACK_OTF_TAG (tag);
2397 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2399 g = in_glyphs + (from + j);
2400 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2408 if (out->allocated < gidx + len)
2410 for (i = 0; i < len; i++)
2411 out_glyphs[out->used++] = in_glyphs[from + i];
2416 OTF_Feature *features;
2419 if (OTF_drive_gpos_with_log (otf, &otf_gstring, script, langsys,
2422 features = otf->gpos->FeatureList.Feature;
2425 MGlyph *base = NULL, *mark = NULL;
2426 int x_ppem = face->size->metrics.x_ppem;
2427 int y_ppem = face->size->metrics.y_ppem;
2428 int x_scale = face->size->metrics.x_scale;
2429 int y_scale = face->size->metrics.y_scale;
2431 for (i = j = 0, otfg = otf_gstring.glyphs, g = out_glyphs + gidx;
2432 i < otf_gstring.used; i++, otfg++)
2435 int adjust_idx = otfg->glyph_id ? j : j - 1;
2436 int feature_idx = otfg->positioning_type >> 4;
2440 tag = features[feature_idx - 1].FeatureTag;
2441 tag = PACK_OTF_TAG (tag);
2442 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2444 switch (otfg->positioning_type & 0xF)
2448 case 1: /* Single */
2451 int format = otfg->f.f1.format;
2453 if (format & OTF_XPlacement)
2454 adjustment[adjust_idx].xoff
2455 += otfg->f.f1.value->XPlacement * x_scale / 0x10000;
2456 if (format & OTF_XPlaDevice)
2457 adjustment[adjust_idx].xoff
2458 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
2459 if (format & OTF_YPlacement)
2460 adjustment[adjust_idx].yoff
2461 -= otfg->f.f1.value->YPlacement * y_scale / 0x10000;
2462 if (format & OTF_YPlaDevice)
2463 adjustment[adjust_idx].yoff
2464 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
2465 if (format & OTF_XAdvance)
2466 adjustment[adjust_idx].xadv
2467 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
2468 if (format & OTF_XAdvDevice)
2469 adjustment[adjust_idx].xadv
2470 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
2471 if (format & OTF_YAdvance)
2472 adjustment[adjust_idx].yadv
2473 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
2474 if (format & OTF_YAdvDevice)
2475 adjustment[adjust_idx].yadv
2476 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
2477 adjustment[adjust_idx].set = 1;
2480 case 3: /* Cursive */
2481 /* Not yet supported. */
2483 case 4: /* Mark-to-Base */
2484 case 5: /* Mark-to-Ligature */
2488 goto label_adjust_anchor;
2489 default: /* i.e. case 6 Mark-to-Mark */
2494 label_adjust_anchor:
2496 int base_x, base_y, mark_x, mark_y;
2497 int this_from, this_to;
2500 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
2501 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
2502 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
2503 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
2505 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2506 adjust_anchor (otfg->f.f4.base_anchor, face, prev->g.code,
2507 x_ppem, y_ppem, &base_x, &base_y);
2508 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2509 adjust_anchor (otfg->f.f4.mark_anchor, face, g->g.code,
2510 x_ppem, y_ppem, &mark_x, &mark_y);
2511 adjustment[adjust_idx].xoff = base_x - mark_x;
2512 adjustment[adjust_idx].yoff = - (base_y - mark_y);
2513 adjustment[adjust_idx].back = (g - prev);
2514 adjustment[adjust_idx].xadv = 0;
2515 adjustment[adjust_idx].advance_is_absolute = 1;
2516 adjustment[adjust_idx].set = 1;
2517 this_from = g->g.from;
2519 for (k = 0; prev + k < g; k++)
2521 if (this_from > prev[k].g.from)
2522 this_from = prev[k].g.from;
2523 if (this_to < prev[k].g.to)
2524 this_to = prev[k].g.to;
2526 for (; prev <= g; prev++)
2528 prev->g.from = this_from;
2529 prev->g.to = this_to;
2535 if (otfg->GlyphClass == OTF_GlyphClass0)
2537 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2547 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used;
2549 if (otfg->positioning_type & 0xF)
2551 int feature_idx = otfg->positioning_type >> 4;
2555 tag = features[feature_idx - 1].FeatureTag;
2556 tag = PACK_OTF_TAG (tag);
2557 for (j = otfg->f.index.from; j <= otfg->f.index.to; j++)
2559 g = in_glyphs + (from + j);
2560 g->g.internal = (g->g.internal & ~0x1FFFFFFF) | tag;
2567 free (otf_gstring.glyphs);
2571 if (otf_gstring.glyphs)
2572 free (otf_gstring.glyphs);
2573 #endif /* HAVE_OTF */
2576 if (out->allocated < out->used + len)
2578 font->get_metrics (font, in, from, to);
2579 memcpy ((MGlyph *)out->glyphs + out->used, (MGlyph *) in->glyphs + from,
2580 sizeof (MGlyph) * len);
2587 ft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
2588 MFLTGlyphString *in, int from, int to)
2590 return ft_drive_otf (font, spec, in, from, to, NULL, NULL);
2595 static unsigned char *iterate_bitmap;
2598 iterate_callback (OTF *otf, const char *feature, unsigned glyph_id)
2600 if (glyph_id <= otf->cmap->max_glyph_id)
2601 iterate_bitmap[glyph_id / 8] |= 1 << (glyph_id % 8);
2606 ft_iterate_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
2607 int from, int to, unsigned char *table)
2609 OTF *otf = get_otf (font, NULL);
2612 unsigned char *bitmap = NULL;
2614 char script[5], *langsys = NULL;
2618 if (OTF_get_table (otf, "cmap") < 0)
2620 if (! spec->features[0])
2622 strcpy (id, "feature-");
2624 OTF_tag_name (spec->script, script);
2627 langsys = alloca (5);
2628 OTF_tag_name (spec->langsys, langsys);
2630 bmp_size = (otf->cmap->max_glyph_id / 8) + 1;
2631 for (i = 0; spec->features[0][i]; i++)
2635 OTF_tag_name (spec->features[0][i], id + 8);
2636 bmp = OTF_get_data (otf, id);
2639 iterate_bitmap = bmp = calloc (bmp_size, 1);
2640 OTF_iterate_gsub_feature (otf, iterate_callback,
2641 script, langsys, id + 8);
2642 OTF_put_data (otf, id, bmp, free);
2644 if (i == 0 && ! spec->features[0][1])
2645 /* Single feature */
2651 bitmap = alloca (bmp_size);
2652 memcpy (bitmap, bmp, bmp_size);
2658 for (j = 0; j < bmp_size; j++)
2659 bitmap[j] &= bmp[j];
2663 for (i = 0; i < bmp_size; i++)
2666 for (j = 0; j < 8; j++)
2667 if (bitmap[i] & (1 << j))
2669 int c = OTF_get_unicode (otf, (i * 8) + j);
2671 if (c >= from && c <= to)
2672 table[c - from] = 1;
2683 MFontDriver mfont__ft_driver =
2684 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
2685 ft_render, ft_list, ft_list_family_names, ft_check_capability,
2686 ft_encapsulate, ft_close, ft_check_otf, ft_drive_otf, ft_try_otf,
2688 ft_iterate_otf_feature
2689 #endif /* HAVE_OTF */
2697 if (FT_Init_FreeType (&ft_library) != 0)
2698 MERROR (MERROR_FONT_FT, -1);
2700 for (i = 0; i < ft_to_prop_size; i++)
2701 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
2703 Mmedium = msymbol ("medium");
2705 Mnull = msymbol ("");
2707 M0[0] = msymbol ("0-0");
2708 M0[1] = msymbol ("0-1");
2709 M0[2] = msymbol ("0-2");
2710 M0[3] = msymbol ("0-3");
2711 M0[4] = msymbol ("0-4");
2712 M3_1 = msymbol ("3-1");
2713 M1_0 = msymbol ("1-0");
2715 #ifdef HAVE_FONTCONFIG
2716 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
2718 FC_vs_M17N_font_prop *table = fc_all_table[i];
2721 for (j = 0; table[j].m17n_value; j++)
2722 table[j].sym = msymbol (table[j].m17n_value);
2723 table[j].sym = table[j - 1].sym;
2730 MSymbol serif, sans_serif, monospace;
2732 fc_config = FcInitLoadConfigAndFonts ();
2733 if (mfont_freetype_path)
2735 MPLIST_DO (plist, mfont_freetype_path)
2736 if (MPLIST_STRING_P (plist)
2737 && (pathname = MPLIST_STRING (plist))
2738 && stat (pathname, &buf) == 0)
2740 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
2743 while ((dir = FcStrListNext (strlist)))
2744 if (strcmp ((char *) dir, pathname) == 0)
2747 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
2748 FcStrListDone (strlist);
2751 Mgeneric_family = msymbol ("generic famly");
2752 serif = msymbol ("serif");
2753 msymbol_put (serif, Mgeneric_family, serif);
2754 sans_serif = msymbol ("sans-serif");
2755 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
2756 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
2757 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
2758 monospace = msymbol ("monospace");
2759 msymbol_put (monospace, Mgeneric_family, monospace);
2760 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
2762 #endif /* HAVE_FONTCONFIG */
2772 if (ft_default_list)
2774 M17N_OBJECT_UNREF (ft_default_list);
2775 ft_default_list = NULL;
2780 MPLIST_DO (plist, ft_font_list)
2782 if (MPLIST_VAL (plist))
2783 MPLIST_DO (p, MPLIST_VAL (plist))
2785 if (MPLIST_KEY (p) != Mt)
2786 free_ft_info (MPLIST_VAL (p));
2788 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2790 M17N_OBJECT_UNREF (ft_font_list);
2791 ft_font_list = NULL;
2793 if (ft_language_list)
2795 MPLIST_DO (plist, ft_language_list)
2796 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2797 M17N_OBJECT_UNREF (ft_language_list);
2798 ft_language_list = NULL;
2803 MPLIST_DO (plist, ft_script_list)
2804 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2805 M17N_OBJECT_UNREF (ft_script_list);
2806 ft_script_list = NULL;
2809 if (ft_capability_list)
2811 MPLIST_DO (plist, ft_capability_list)
2812 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2813 M17N_OBJECT_UNREF (ft_capability_list);
2814 ft_capability_list = NULL;
2819 MPLIST_DO (plist, ft_file_list)
2820 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2821 M17N_OBJECT_UNREF (ft_file_list);
2822 ft_file_list = NULL;
2825 FT_Done_FreeType (ft_library);
2826 #ifdef HAVE_FONTCONFIG
2827 FcConfigDestroy (fc_config);
2829 #endif /* HAVE_FONTCONFIG */
2830 all_fonts_scaned = 0;
2833 #ifdef HAVE_FONTCONFIG
2836 mfont__ft_parse_name (const char *name, MFont *font)
2838 FcPattern *pat = FcNameParse ((FcChar8 *) name);
2847 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
2849 STRDUP_LOWER (buf, bufsize, (char *) str);
2850 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
2852 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
2854 STRDUP_LOWER (buf, bufsize, (char *) str);
2855 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
2857 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
2858 mfont__set_property (font, MFONT_WEIGHT,
2859 fc_decode_prop (val, fc_weight_table,
2860 fc_weight_table_size));
2861 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
2862 mfont__set_property (font, MFONT_STYLE,
2863 fc_decode_prop (val, fc_slant_table,
2864 fc_slant_table_size));
2865 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
2866 mfont__set_property (font, MFONT_STRETCH,
2867 fc_decode_prop (val, fc_width_table,
2868 fc_width_table_size));
2869 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2870 font->size = size * 10 + 0.5;
2871 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
2872 font->size = - (size * 10 + 0.5);
2873 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
2875 font->file = msymbol ((char *) str);
2877 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
2878 font->type = MFONT_TYPE_SPEC;
2879 FcPatternDestroy (pat);
2884 mfont__ft_unparse_name (MFont *font)
2886 FcPattern *pat = fc_get_pattern (font);
2887 char *name = (char *) FcNameUnparse (pat);
2889 FcPatternDestroy (pat);
2892 #endif /* HAVE_FONTCONFIG */
2894 #endif /* HAVE_FREETYPE */