1 /* font-ft.c -- FreeType interface sub-module.
2 Copyright (C) 2003, 2004
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H15PRO112
6 This file is part of the m17n library.
8 The m17n library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public License
10 as published by the Free Software Foundation; either version 2.1 of
11 the License, or (at your option) any later version.
13 The m17n library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the m17n library; if not, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <sys/types.h>
35 #include "m17n-misc.h"
40 #include "internal-gui.h"
47 #include <freetype/ftbdf.h>
50 static int mdebug_mask = MDEBUG_FONT;
52 #ifdef HAVE_FONTCONFIG
53 static FcConfig *fc_config;
54 static MSymbol Mgeneric_family;
55 #endif /* HAVE_FONTCONFIG */
57 /* Font properties; Mnormal is already defined in face.c. */
58 static MSymbol Mmedium, Mr, Mnull;
60 static MSymbol M0_3, M3_1, M1_0;
62 static FT_Library ft_library;
65 static OTF *invalid_otf = (OTF *) "";
73 /* NULL if not yet opened. invalid_otf if not OTF. */
76 #ifdef HAVE_FONTCONFIG
79 #endif /* HAVE_FONTCONFIG */
93 enum MFontProperty prop;
97 static MFTtoProp ft_to_prop[] =
98 { { "italic", 0, MFONT_STYLE, "i" },
99 { "roman", 0, MFONT_STYLE, "r" },
100 { "oblique", 0, MFONT_STYLE, "o" },
101 { "regular", 0, MFONT_WEIGHT, "normal" },
102 { "normal", 0, MFONT_WEIGHT, "normal" },
103 /* We need this entry even if "bold" is in commone_weight[] to
104 handle such style names as "bolditalic" and "boldoblique". */
105 { "bold", 0, MFONT_WEIGHT, "bold" },
106 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
107 { "demi", 0, MFONT_WEIGHT, "demibold" } };
108 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
110 /** List of FreeType fonts. Keys are family names, values are plists
111 containing fonts of the corresponding family. In the deeper
112 plist, keys are file names, values are (MFontFT *). */
113 static MPlist *ft_font_list;
115 /** List of FreeType fonts. Keys are script names, values are plists
116 containing fonts supporting the corresponding script. In the
117 deeper plist, keys are family names, values are (MFontFT *). */
118 static MPlist *ft_script_list;
120 /** List of FreeType fonts. Keys are language names, values are
121 plists containing fonts supporting the corresponding language. In
122 the deeper plist, keys are family names, values are (MFontFT *). */
123 static MPlist *ft_language_list;
125 static MPlist *ft_file_list;
127 static int all_fonts_scaned;
129 #define STRDUP_LOWER(s1, size, s2) \
131 int len = strlen (s2) + 1; \
135 (s1) = alloca (len), (size) = len; \
136 for (p1 = (s1), p2 = (s2); *p2; p1++, p2++) \
137 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
138 while (p1 > (s1) && p1[-1] == ' ') p1--; \
144 free_ft_rfont (void *object)
146 MRealizedFontFT *ft_rfont = object;
148 M17N_OBJECT_UNREF (ft_rfont->charmap_list);
149 FT_Done_Face (ft_rfont->ft_face);
154 free_ft_info (MFontFT *ft_info)
156 M17N_OBJECT_UNREF (ft_info->lang);
158 if (ft_info->otf && ft_info->otf != invalid_otf)
159 OTF_close (ft_info->otf);
160 #endif /* HAVE_OTF */
165 ft_get_charmaps (FT_Face ft_face)
167 MPlist *plist = mplist ();
168 int unicode_bmp = -1, unicode_full = -1;
171 mplist_add (plist, Mt, (void *) -1);
172 for (i = 0; i < ft_face->num_charmaps; i++)
174 MSymbol registry = Mnil;
176 if (ft_face->charmaps[i]->platform_id == 0)
178 if (ft_face->charmaps[i]->encoding_id == 3)
179 registry = M0_3, unicode_bmp = i;
180 else if (ft_face->charmaps[i]->encoding_id == 4)
183 else if (ft_face->charmaps[i]->platform_id == 3)
185 if (ft_face->charmaps[i]->encoding_id == 1)
186 registry = M3_1, unicode_bmp = i;
187 else if (ft_face->charmaps[i]->encoding_id == 10)
190 else if (ft_face->charmaps[i]->platform_id == 1
191 && ft_face->charmaps[i]->encoding_id == 0)
194 mplist_add (plist, Mapple_roman, (void *) i);
196 if (registry == Mnil)
198 char registry_buf[16];
200 sprintf (registry_buf, "%d-%d",
201 ft_face->charmaps[i]->platform_id,
202 ft_face->charmaps[i]->encoding_id);
203 registry = msymbol (registry_buf);
205 mplist_add (plist, registry, (void *) i);
207 if (unicode_full >= 0)
209 mplist_add (plist, Municode_full, (void *) unicode_full);
210 mplist_add (plist, Municode_bmp, (void *) unicode_full);
212 else if (unicode_bmp >= 0)
214 mplist_add (plist, Municode_bmp, (void *) unicode_bmp);
219 #ifdef HAVE_FONTCONFIG
226 } FC_vs_M17N_font_prop;
228 static FC_vs_M17N_font_prop fc_weight_table[] =
229 { { FC_WEIGHT_THIN, "thin" },
230 { FC_WEIGHT_ULTRALIGHT, "extralight" },
231 { FC_WEIGHT_LIGHT, "light" },
232 #ifdef FC_WEIGHT_BOOK
233 { FC_WEIGHT_BOOK, "book" },
234 #endif /* FC_WEIGHT_BOOK */
235 { FC_WEIGHT_NORMAL, "normal" },
236 { FC_WEIGHT_MEDIUM, "medium" },
237 { FC_WEIGHT_DEMIBOLD, "demibold" },
238 { FC_WEIGHT_BOLD, "bold" },
239 { FC_WEIGHT_EXTRABOLD, "extrabold" },
240 { FC_WEIGHT_BLACK, "black" },
241 { FC_WEIGHT_HEAVY, "heavy" },
242 { FC_WEIGHT_MEDIUM, NULL } };
243 int fc_weight_table_size =
244 sizeof fc_weight_table / sizeof (FC_vs_M17N_font_prop);
246 static FC_vs_M17N_font_prop fc_slant_table[] =
247 { { FC_SLANT_ROMAN, "r" },
248 { FC_SLANT_ITALIC, "i" },
249 { FC_SLANT_OBLIQUE, "o" },
250 { FC_SLANT_ROMAN, NULL } };
251 int fc_slant_table_size =
252 sizeof fc_slant_table / sizeof (FC_vs_M17N_font_prop);
254 static FC_vs_M17N_font_prop fc_width_table[] =
255 { { FC_WIDTH_ULTRACONDENSED, "ultracondensed" },
256 { FC_WIDTH_EXTRACONDENSED, "extracondensed" },
257 { FC_WIDTH_CONDENSED, "condensed" },
258 { FC_WIDTH_SEMICONDENSED, "semicondensed" },
259 { FC_WIDTH_NORMAL, "normal" },
260 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
261 { FC_WIDTH_EXPANDED, "expanded" },
262 { FC_WIDTH_EXTRAEXPANDED, "extraexpanded" },
263 { FC_WIDTH_ULTRAEXPANDED, "ultraexpanded" },
264 { FC_WIDTH_NORMAL, NULL } };
265 int fc_width_table_size =
266 sizeof fc_width_table / sizeof (FC_vs_M17N_font_prop);
269 static FC_vs_M17N_font_prop *fc_all_table[] =
270 { fc_weight_table, fc_slant_table, fc_width_table };
273 fc_decode_prop (int val, FC_vs_M17N_font_prop *table, int size)
277 if (val < table[i].fc_value)
279 for (i--; i >= 0; i--)
280 if (val > table[i].fc_value)
286 for (; i < size; i++)
287 if (val <= table[i].fc_value)
294 fc_encode_prop (MSymbol sym, FC_vs_M17N_font_prop *table)
298 for (i = 0; table[i].m17n_value; i++)
299 if (table[i].sym == sym)
301 return table[i].fc_value;
305 fc_get_pattern (MFont *font)
307 FcPattern *pat = FcPatternCreate ();
308 MSymbol sym, weight, style, stretch;
311 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
312 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
313 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
314 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
315 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
316 FcPatternAddInteger (pat, FC_WEIGHT,
317 fc_encode_prop (weight, fc_weight_table));
318 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
319 FcPatternAddInteger (pat, FC_SLANT,
320 fc_encode_prop (style, fc_slant_table));
321 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
322 FcPatternAddInteger (pat, FC_WIDTH,
323 fc_encode_prop (stretch, fc_width_table));
326 double size = font->size;
327 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size / 10);
329 else if (font->size < 0)
331 double size = - font->size;
332 FcPatternAddDouble (pat, FC_SIZE, size / 10);
338 fc_parse_pattern (FcPattern *pat, char *family, MFont *font)
349 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
351 STRDUP_LOWER (buf, bufsize, (char *) str);
352 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
355 mfont__set_property (font, MFONT_FAMILY, msymbol (family));
356 else if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
358 STRDUP_LOWER (buf, bufsize, (char *) str);
359 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
361 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
363 sym = fc_decode_prop (val, fc_weight_table, fc_weight_table_size);
364 mfont__set_property (font, MFONT_WEIGHT, sym);
366 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
368 sym = fc_decode_prop (val, fc_slant_table, fc_slant_table_size);
369 mfont__set_property (font, MFONT_STYLE, sym);
371 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
373 sym = fc_decode_prop (val, fc_width_table, fc_width_table_size);
374 mfont__set_property (font, MFONT_STRETCH, sym);
376 if (FcPatternGetLangSet (pat, FC_LANG, 0, &ls) == FcResultMatch)
378 if (FcLangSetHasLang (ls, (FcChar8 *) "ja") == FcLangEqual
379 || FcLangSetHasLang (ls, (FcChar8 *) "zh-cn") == FcLangEqual
380 || FcLangSetHasLang (ls, (FcChar8 *) "zh-hk") == FcLangEqual
381 || FcLangSetHasLang (ls, (FcChar8 *) "zh-tw") == FcLangEqual
382 || FcLangSetHasLang (ls, (FcChar8 *) "ko") == FcLangEqual)
383 font->for_full_width = 1;
386 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
387 font->type = MFONT_TYPE_SPEC;
388 font->source = MFONT_SOURCE_FT;
389 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
390 font->size = size * 10;
391 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
392 font->file = msymbol ((char *) str);
397 fc_gen_font (FcPattern *pat, char *family)
401 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
402 fc_parse_pattern (pat, family, &ft_info->font);
403 ft_info->font.type = MFONT_TYPE_OBJECT;
407 #else /* not HAVE_FONTCONFIG */
410 ft_add_font (char *filename)
423 if (FT_New_Face (ft_library, filename, 0, &ft_face) != 0)
425 if (! FT_IS_SCALABLE (ft_face))
429 BDF_PropertyRec prop;
431 reject = FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0;
432 size = prop.u.integer * 10;
433 #else /* not HAVE_FTBDF_H */
435 #endif /* not HAVE_FTBDF_H */
438 FT_Done_Face (ft_face);
443 MSTRUCT_CALLOC (ft_info, MERROR_FONT_FT);
444 font = &ft_info->font;
445 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
446 family = msymbol (buf);
447 mfont__set_property (font, MFONT_FAMILY, family);
448 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
449 mfont__set_property (font, MFONT_STYLE, Mr);
450 mfont__set_property (font, MFONT_STRETCH, Mnormal);
451 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
452 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
453 font->type = MFONT_TYPE_OBJECT;
454 font->source = MFONT_SOURCE_FT;
456 font->file = msymbol (filename);
458 stylename = ft_face->style_name;
461 for (i = 0; i < ft_to_prop_size; i++)
462 if (! strncasecmp (ft_to_prop[i].ft_style, stylename,
465 mfont__set_property (font, ft_to_prop[i].prop,
466 msymbol (ft_to_prop[i].val));
467 stylename += ft_to_prop[i].len;
470 if (i == ft_to_prop_size)
472 char *p1 = stylename + 1;
475 while (*p1 >= 'a' && *p1 <= 'z') p1++;
476 sym = msymbol__with_len (stylename, p1 - stylename);
477 for (i = MFONT_WEIGHT; i <= MFONT_STRETCH; i++)
478 if (msymbol_get (sym, mfont__property_table[i].property))
480 mfont__set_property (font, i, sym);
485 while (*stylename && ! isalpha (*stylename))
489 FT_Done_Face (ft_face);
491 plist = mplist_find_by_key (ft_font_list, family);
493 mplist_push (MPLIST_PLIST (plist), font->file, ft_info);
497 mplist_add (plist, font->file, ft_info);
498 plist = mplist_push (ft_font_list, family, plist);
503 #endif /* not HAVE_FONTCONFIG */
506 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
507 scan all fonts and return ft_font_list. */
510 ft_list_family (MSymbol family, int check_generic)
513 #ifdef HAVE_FONTCONFIG
528 plist = ft_font_list = mplist ();
529 pattern = FcPatternCreate ();
530 os = FcObjectSetBuild (FC_FAMILY, NULL);
531 fs = FcFontList (fc_config, pattern, os);
532 for (i = 0; i < fs->nfont; i++)
534 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
535 (FcChar8 **) &fam) != FcResultMatch)
537 STRDUP_LOWER (buf, bufsize, fam);
539 if (! mplist_find_by_key (ft_font_list, sym))
540 plist = mplist_add (plist, sym, NULL);
542 FcFontSetDestroy (fs);
543 FcObjectSetDestroy (os);
544 FcPatternDestroy (pattern);
549 if (! all_fonts_scaned)
551 MPLIST_DO (plist, ft_font_list)
553 if (! MPLIST_VAL (plist))
554 ft_list_family (MPLIST_KEY (plist), 0);
556 all_fonts_scaned = 1;
561 plist = mplist_find_by_key (ft_font_list, family);
564 if (! MPLIST_VAL (plist))
566 fam = MSYMBOL_NAME (family);
567 pattern = FcPatternCreate ();
568 FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) fam);
569 os = FcObjectSetBuild (FC_FOUNDRY, FC_WEIGHT, FC_SLANT, FC_WIDTH,
570 FC_PIXEL_SIZE, FC_LANG, FC_FILE, NULL);
571 fs = FcFontList (fc_config, pattern, os);
573 for (i = 0; i < fs->nfont; i++)
575 MFontFT *ft_info = fc_gen_font (fs->fonts[i], fam);
576 p = mplist_add (p, ft_info->font.file, ft_info);
578 MPLIST_VAL (plist) = pl;
579 FcFontSetDestroy (fs);
580 FcObjectSetDestroy (os);
581 FcPatternDestroy (pattern);
584 else if (check_generic
585 && (generic = msymbol_get (family, Mgeneric_family)) != Mnil)
587 /* Check if FAMILY is a geneneric family (e.g. `serif'). */
590 if (family != generic)
591 plist = ft_list_family (generic, 1);
594 fam = MSYMBOL_NAME (family);
596 mplist_push (ft_font_list, family, plist);
597 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fam, NULL);
598 FcConfigSubstitute (fc_config, pattern, FcMatchPattern);
601 if (FcPatternGetString (pattern, FC_FAMILY, i, &fam8)
604 STRDUP_LOWER (buf, bufsize, (char *) fam8);
605 family = msymbol (buf);
606 if (msymbol_get (family, Mgeneric_family))
608 pl = ft_list_family (family, 0);
611 MPLIST_DO (pl, MPLIST_PLIST (pl))
612 plist = mplist_add (plist, Mt, MPLIST_VAL (pl));
614 plist = ft_font_list;
618 plist = mplist_add (ft_font_list, family, mplist ());
620 #else /* not HAVE_FONTCONFIG */
622 if (! all_fonts_scaned)
630 ft_font_list = mplist ();
631 MPLIST_DO (plist, mfont_freetype_path)
632 if (MPLIST_STRING_P (plist)
633 && (pathname = MPLIST_STRING (plist))
634 && stat (pathname, &buf) == 0)
636 if (S_ISREG (buf.st_mode))
637 ft_add_font (pathname);
638 else if (S_ISDIR (buf.st_mode))
640 DIR *dir = opendir (pathname);
644 int len = strlen (pathname);
647 while ((dp = readdir (dir)) != NULL)
649 SAFE_ALLOCA (path, len + strlen (dp->d_name) + 2);
650 strcpy (path, pathname);
652 strcpy (path + len + 1, dp->d_name);
660 all_fonts_scaned = 1;
663 plist = ft_font_list;
666 plist = mplist_find_by_key (ft_font_list, family);
668 plist = mplist_push (ft_font_list, family, mplist ());
670 #endif /* not HAVE_FONTCONFIG */
676 ft_list_language (MSymbol language)
678 MPlist *plist = NULL;
682 if (! ft_language_list)
683 ft_language_list = mplist ();
684 else if ((plist = mplist_find_by_key (ft_language_list, language)))
685 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
687 #ifdef HAVE_FONTCONFIG
688 for (step = 0; step < 2; step++)
690 FcPattern *pattern = NULL;
691 FcObjectSet *os = NULL;
692 FcFontSet *fs = NULL;
697 if (! (pattern = FcPatternCreate ())
698 || ! (os = FcObjectSetBuild (FC_FAMILY, FC_FILE, NULL)))
702 FcLangSet *ls = FcLangSetCreate ();
706 if (FcLangSetAdd (ls, (FcChar8 *) MSYMBOL_NAME (language))
707 && FcPatternAddLangSet (pattern, FC_LANG, ls))
708 fs = FcFontList (fc_config, pattern, os);
709 FcLangSetDestroy (ls);
717 if (! (mt = msymbol_get (language, Mtext)))
719 if (! (cs = FcCharSetCreate ()))
721 for (i = mtext_nchars (mt) - 1; i >= 0; i--)
722 if (! FcCharSetAddChar (cs, (FcChar32) mtext_ref_char (mt, i)))
726 if (FcPatternAddCharSet (pattern, FC_CHARSET, cs))
727 fs = FcFontList (fc_config, pattern, os);
729 FcCharSetDestroy (cs);
734 for (i = 0; i < fs->nfont; i++)
736 MSymbol family, file;
737 char *fam, *filename;
741 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
742 (FcChar8 **) &fam) != FcResultMatch)
744 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
745 (FcChar8 **) &filename) != FcResultMatch)
747 STRDUP_LOWER (buf, bufsize, fam);
748 family = msymbol (buf);
749 file = msymbol (filename);
750 pl = MPLIST_PLIST (ft_list_family (family, 0));
751 ft_info = mplist_get (pl, file);
756 mplist_add (plist, family, ft_info);
759 FcFontSetDestroy (fs);
760 FcObjectSetDestroy (os);
761 FcPatternDestroy (pattern);
766 FcObjectSetDestroy (os);
768 FcPatternDestroy (pattern);
769 MEMORY_FULL (MERROR_FONT_FT);
773 mplist_push (ft_language_list, language, plist);
776 #else /* not HAVE_FONTCONFIG */
778 if ((mt = msymbol_get (language, Mtext)))
781 int len = mtext_nchars (mt);
785 ft_list_family (Mnil, 0);
786 MPLIST_DO (pl, ft_font_list)
788 MPLIST_DO (p, MPLIST_PLIST (pl))
790 MFontFT *ft_info = MPLIST_VAL (p);
794 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file),
797 for (i = 0; i < len; i++)
798 if (FT_Get_Char_Index (ft_face,
799 (FT_ULong) mtext_ref_char (mt, i)) == 0)
801 FT_Done_Face (ft_face);
806 family = mfont_get_prop (&ft_info->font, Mfamily);
807 mplist_push (plist, family, ft_info);
812 #endif /* not HAVE_FONTCONFIG */
816 ft_list_script (MSymbol script)
818 MPlist *plist = NULL;
819 MPlist *language_list, *pl;
821 if (! ft_script_list)
822 ft_script_list = mplist ();
823 else if ((plist = mplist_find_by_key (ft_script_list, script)))
824 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
826 language_list = mlanguage__list (script);
827 MPLIST_DO (pl, language_list)
829 MSymbol language = MPLIST_VAL (pl) ? MPLIST_SYMBOL (pl) : MPLIST_KEY (pl);
830 MPlist *p = ft_list_language (language);
839 family = MPLIST_KEY (p);
840 if (! mplist_find_by_value (plist, MPLIST_VAL (p)))
841 mplist_add (plist, family, MPLIST_VAL (p));
844 mplist_push (ft_script_list, script, plist);
845 M17N_OBJECT_UNREF (language_list);
850 ft_check_otf (MFontFT *ft_info, MFontCapability *cap)
852 if (ft_info->otf == invalid_otf)
856 ft_info->otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
859 ft_info->otf = invalid_otf;
863 if (cap->features[MFONT_OTT_GSUB].nfeatures
864 && cap->features[MFONT_OTT_GSUB].tags[0]
865 && (OTF_check_features
867 cap->script_tag, cap->langsys_tag,
868 cap->features[MFONT_OTT_GSUB].tags,
869 cap->features[MFONT_OTT_GSUB].nfeatures) != 1))
871 if (cap->features[MFONT_OTT_GPOS].nfeatures
872 && cap->features[MFONT_OTT_GPOS].tags[0]
873 && (OTF_check_features
875 cap->script_tag, cap->langsys_tag,
876 cap->features[MFONT_OTT_GPOS].tags,
877 cap->features[MFONT_OTT_GPOS].nfeatures) != 1))
883 ft_check_lang (MFontFT *ft_info, MFontCapability *cap)
885 #ifdef HAVE_FONTCONFIG
890 for (i = 0; cap->lang[i] != Mnil; i++)
893 && (plist = mplist_find_by_key (ft_info->lang, cap->lang[i])))
895 if (MPLIST_VAL (plist))
900 if (! ft_info->langset)
902 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
903 MSYMBOL_NAME (ft_info->font.file),
905 FcObjectSet *os = FcObjectSetBuild (FC_LANG, FC_CHARSET, NULL);
906 FcFontSet *fs = FcFontList (fc_config, pat, os);
910 if (FcPatternGetLangSet (fs->fonts[0], FC_LANG, 0, &ft_info->langset)
912 ft_info->langset = FcLangSetCopy (ft_info->langset);
914 ft_info->langset = FcLangSetCreate ();
915 FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0, &ft_info->charset);
916 FcFontSetDestroy (fs);
917 FcObjectSetDestroy (os);
918 FcPatternDestroy (pat);
921 ft_info->lang = mplist ();
922 if (FcLangSetHasLang (ft_info->langset,
923 (FcChar8 *) MSYMBOL_NAME (cap->lang[i]))
926 mplist_push (ft_info->lang, cap->lang[i], Mt);
930 mt = msymbol_get (cap->lang[i], Mtext);
933 mplist_push (ft_info->lang, cap->lang[i], Mnil);
937 for (j = mtext_nchars (mt) - 1; j >= 0; j--)
938 if (! FcCharSetAddChar (ft_info->charset,
939 (FcChar32) mtext_ref_char (mt, j)))
941 mplist_push (ft_info->lang, cap->lang[i], (j < 0 ? Mt : Mnil));
945 #endif /* HAVE_FONTCONFIG */
949 static MPlist *ft_capability_list;
952 ft_list_capability (MSymbol sym)
954 MPlist *plist, *pl, *p;
955 MFontCapability *cap = mfont__get_capability (sym);
959 if (ft_capability_list)
961 plist = mplist_find_by_key (ft_capability_list, sym);
963 return (MPLIST_VAL (plist) ? MPLIST_VAL (plist) : NULL);
968 ft_capability_list = mplist ();
971 if (cap->script != Mnil)
973 pl = ft_list_script (cap->script);
977 if (cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
979 if (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0)
983 mplist_add (plist, MPLIST_KEY (pl), MPLIST_VAL (pl));
985 mplist_push (ft_capability_list, sym, plist);
993 for (i = 0; cap->lang[i] != Mnil; i++)
995 p = ft_list_language (cap->lang[i]);
1001 mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1005 mplist_push (ft_capability_list, sym, plist);
1011 ft_list_file (MSymbol filename)
1013 MPlist *plist = NULL;
1016 ft_file_list = mplist ();
1017 else if ((plist = mplist_find_by_key (ft_file_list, filename)))
1018 return (MPLIST_VAL (plist) ? MPLIST_PLIST (plist) : NULL);
1020 #ifdef HAVE_FONTCONFIG
1022 FcPattern *pattern = FcPatternCreate ();
1026 FcPatternAddString (pattern, FC_FILE, (FcChar8 *) MSYMBOL_NAME (filename));
1027 os = FcObjectSetBuild (FC_FAMILY, NULL);
1028 fs = FcFontList (fc_config, pattern, os);
1035 if (FcPatternGetString (fs->fonts[0], FC_FAMILY, 0,
1036 (FcChar8 **) &fam) == FcResultMatch)
1041 STRDUP_LOWER (buf, bufsize, fam);
1042 family = msymbol (buf);
1043 pl = ft_list_family (family, 0);
1044 MPLIST_DO (pl, MPLIST_PLIST (pl))
1046 MFontFT *ft_info = MPLIST_VAL (pl);
1048 if (ft_info->font.file == filename)
1051 mplist_add (plist, family, ft_info);
1058 #else /* not HAVE_FONTCONFIG */
1062 MPLIST_DO (pl, ft_list_family (Mnil, 0))
1064 MPLIST_DO (p, MPLIST_PLIST (pl))
1066 MFontFT *ft_info = MPLIST_VAL (pl);
1068 if (ft_info->font.file == filename)
1071 mplist_add (plist, MPLIST_KEY (pl), ft_info);
1079 #endif /* not HAVE_FONTCONFIG */
1081 mplist_push (ft_file_list, filename, plist);
1085 /* The FreeType font driver function SELECT. */
1088 ft_select (MFrame *frame, MFont *font, int limited_size)
1090 MFont *found = NULL;
1091 #ifdef HAVE_FONTCONFIG
1094 int check_font_property = 1;
1096 if (font->file != Mnil)
1098 plist = ft_list_file (font->file);
1101 check_font_property = 0;
1105 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
1109 plist = MPLIST_PLIST (ft_list_family (family, 1));
1110 if (MPLIST_TAIL_P (plist))
1114 plist = mplist_copy (plist);
1116 if (font->capability != Mnil)
1118 MFontCapability *cap = mfont__get_capability (font->capability);
1120 for (pl = plist; ! MPLIST_TAIL_P (pl);)
1122 if ((cap->script_tag && ft_check_otf (MPLIST_VAL (pl), cap) < 0)
1123 || (cap->lang && ft_check_lang (MPLIST_VAL (pl), cap) < 0))
1126 pl = MPLIST_NEXT (pl);
1130 if (check_font_property)
1132 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1133 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1134 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1136 if (weight != Mnil || style != Mnil || stretch != Mnil || font->size > 0)
1137 for (pl = plist; ! MPLIST_TAIL_P (pl); )
1139 ft_info = MPLIST_VAL (pl);
1141 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1143 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1145 && stretch != FONT_PROPERTY (&ft_info->font,
1148 && ft_info->font.size > 0
1149 && ft_info->font.size != font->size))
1152 pl = MPLIST_NEXT (pl);
1156 MPLIST_DO (pl, plist)
1158 font = MPLIST_VAL (plist);
1159 if (limited_size == 0
1161 || font->size <= limited_size)
1167 M17N_OBJECT_UNREF (plist);
1173 static MRealizedFont *
1174 ft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
1176 MFontFT *ft_info = (MFontFT *) font;
1177 int reg = spec->property[MFONT_REGISTRY];
1178 MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
1179 MRealizedFontFT *ft_rfont;
1181 MPlist *plist, *charmap_list = NULL;
1183 int size = font->size ? font->size : spec->size;
1187 charmap_list = ((MRealizedFontFT *) rfont->info)->charmap_list;
1188 for (; rfont; rfont = rfont->next)
1189 if (rfont->font == font
1190 && (rfont->font->size ? rfont->font->size == size
1191 : rfont->spec.size == size)
1192 && rfont->spec.property[MFONT_REGISTRY] == reg
1193 && rfont->driver == &mfont__ft_driver)
1197 MDEBUG_PRINT3 (" [FONT-FT] opening %s-%d:file=%s ...",
1198 MSYMBOL_NAME ((MSymbol) mfont_get_prop (font, Mfamily)),
1199 size / 10, MSYMBOL_NAME (font->file));
1201 if (FT_New_Face (ft_library, MSYMBOL_NAME (ft_info->font.file), 0,
1204 font->type = MFONT_TYPE_FAILURE;
1205 MDEBUG_PRINT ("failed\n");
1209 M17N_OBJECT_REF (charmap_list);
1211 charmap_list = ft_get_charmaps (ft_face);
1212 if (registry == Mnil)
1214 plist = mplist_find_by_key (charmap_list, registry);
1217 FT_Done_Face (ft_face);
1218 M17N_OBJECT_UNREF (charmap_list);
1219 MDEBUG_PRINT ("failed\n");
1222 charmap_index = (int) MPLIST_VAL (plist);
1223 if (FT_Set_Charmap (ft_face, ft_face->charmaps[charmap_index])
1224 || FT_Set_Pixel_Sizes (ft_face, 0, size / 10))
1226 FT_Done_Face (ft_face);
1227 M17N_OBJECT_UNREF (charmap_list);
1228 font->type = MFONT_TYPE_FAILURE;
1229 MDEBUG_PRINT ("failed\n");
1233 M17N_OBJECT (ft_rfont, free_ft_rfont, MERROR_FONT_FT);
1234 ft_rfont->ft_face = ft_face;
1235 ft_rfont->charmap_list = charmap_list;
1236 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
1237 rfont->spec = *font;
1238 rfont->spec.type = MFONT_TYPE_REALIZED;
1239 rfont->spec.property[MFONT_REGISTRY] = reg;
1240 rfont->spec.size = size;
1241 rfont->frame = frame;
1243 rfont->driver = &mfont__ft_driver;
1244 rfont->info = ft_rfont;
1245 rfont->fontp = ft_face;
1246 rfont->ascent = ft_face->size->metrics.ascender >> 6;
1247 rfont->descent = - ft_face->size->metrics.descender >> 6;
1248 rfont->max_advance = ft_face->size->metrics.max_advance >> 6;
1249 rfont->next = MPLIST_VAL (frame->realized_font_list);
1250 MPLIST_VAL (frame->realized_font_list) = rfont;
1251 MDEBUG_PRINT ("ok\n");
1255 /* The FreeType font driver function FIND_METRIC. */
1258 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
1261 FT_Face ft_face = rfont->fontp;
1262 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
1264 for (; g != gend; g++)
1266 if (g->code == MCHAR_INVALID_CODE)
1268 if (FT_IS_SCALABLE (ft_face))
1270 unsigned unitsPerEm10 = ft_face->units_per_EM * 10;
1271 int size = rfont->spec.size;
1274 g->rbearing = ft_face->max_advance_width * size / unitsPerEm10;
1275 g->width = g->rbearing;
1276 g->ascent = ft_face->ascender * size / unitsPerEm10;
1277 g->descent = (- ft_face->descender) * size / unitsPerEm10;
1282 BDF_PropertyRec prop;
1286 g->rbearing = g->width = ft_face->available_sizes->width;
1288 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
1290 g->ascent = prop.u.integer;
1291 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
1292 g->descent = prop.u.integer;
1297 g->ascent = ft_face->available_sizes->height;
1304 FT_Glyph_Metrics *metrics;
1306 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
1307 metrics = &ft_face->glyph->metrics;
1308 g->lbearing = (metrics->horiBearingX >> 6);
1309 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
1310 g->width = metrics->horiAdvance >> 6;
1311 g->ascent = metrics->horiBearingY >> 6;
1312 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
1318 ft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
1320 MRealizedFont *rfont = NULL;
1321 MRealizedFontFT *ft_rfont;
1324 if (font->type == MFONT_TYPE_REALIZED)
1325 rfont = (MRealizedFont *) font;
1326 else if (font->type == MFONT_TYPE_OBJECT)
1328 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1329 rfont = rfont->next)
1330 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1334 #ifdef HAVE_FONTCONFIG
1335 MFontFT *ft_info = (MFontFT *) font;
1337 if (! ft_info->charset)
1339 FcPattern *pat = FcPatternBuild (NULL, FC_FILE, FcTypeString,
1340 MSYMBOL_NAME (font->file),
1342 FcObjectSet *os = FcObjectSetBuild (FC_CHARSET, NULL);
1343 FcFontSet *fs = FcFontList (fc_config, pat, os);
1346 && FcPatternGetCharSet (fs->fonts[0], FC_CHARSET, 0,
1347 &ft_info->charset) == FcResultMatch)
1348 ft_info->charset = FcCharSetCopy (ft_info->charset);
1350 ft_info->charset = FcCharSetCreate ();
1351 FcFontSetDestroy (fs);
1352 FcObjectSetDestroy (os);
1353 FcPatternDestroy (pat);
1355 return (FcCharSetHasChar (ft_info->charset, (FcChar32) c) == FcTrue);
1356 #else /* not HAVE_FONTCONFIG */
1357 rfont = ft_open (frame, font, spec, NULL);
1358 #endif /* not HAVE_FONTCONFIG */
1362 MFATAL (MERROR_FONT_FT);
1366 ft_rfont = rfont->info;
1367 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1371 /* The FreeType font driver function ENCODE_CHAR. */
1374 ft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
1376 MRealizedFont *rfont;
1377 MRealizedFontFT *ft_rfont;
1380 if (font->type == MFONT_TYPE_REALIZED)
1381 rfont = (MRealizedFont *) font;
1382 else if (font->type == MFONT_TYPE_OBJECT)
1384 for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
1385 rfont = rfont->next)
1386 if (rfont->font == font && rfont->driver == &mfont__ft_driver)
1390 rfont = ft_open (frame, font, spec, NULL);
1396 MFATAL (MERROR_FONT_FT);
1398 ft_rfont = rfont->info;
1399 idx = FT_Get_Char_Index (ft_rfont->ft_face, (FT_ULong) code);
1400 return (idx ? (unsigned) idx : MCHAR_INVALID_CODE);
1403 /* The FreeType font driver function RENDER. */
1405 #define NUM_POINTS 0x1000
1408 MDrawPoint points[NUM_POINTS];
1413 ft_render (MDrawWindow win, int x, int y,
1414 MGlyphString *gstring, MGlyph *from, MGlyph *to,
1415 int reverse, MDrawRegion region)
1418 MRealizedFace *rface = from->rface;
1419 MFrame *frame = rface->frame;
1420 FT_Int32 load_flags = FT_LOAD_RENDER;
1423 MPointTable point_table[8];
1428 /* It is assured that the all glyphs in the current range use the
1429 same realized face. */
1430 ft_face = rface->rfont->fontp;
1432 if (! gstring->anti_alias)
1434 #ifdef FT_LOAD_TARGET_MONO
1435 load_flags |= FT_LOAD_TARGET_MONO;
1437 load_flags |= FT_LOAD_MONOCHROME;
1441 for (i = 0; i < 8; i++)
1442 point_table[i].p = point_table[i].points;
1444 for (g = from; g < to; x += g++->width)
1448 MPointTable *ptable;
1452 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
1453 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
1454 bmp = ft_face->glyph->bitmap.buffer;
1455 width = ft_face->glyph->bitmap.width;
1456 pitch = ft_face->glyph->bitmap.pitch;
1457 if (! gstring->anti_alias)
1462 if (gstring->anti_alias)
1463 for (i = 0; i < ft_face->glyph->bitmap.rows;
1464 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1466 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1467 for (j = 0; j < width; j++, xoff++)
1469 intensity = bmp[j] >> 5;
1472 ptable = point_table + intensity;
1473 ptable->p->x = xoff;
1474 ptable->p->y = yoff;
1476 if (ptable->p - ptable->points == NUM_POINTS)
1478 (*frame->driver->draw_points)
1480 reverse ? 7 - intensity : intensity,
1481 ptable->points, NUM_POINTS, region);
1482 ptable->p = ptable->points;
1488 for (i = 0; i < ft_face->glyph->bitmap.rows;
1489 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
1491 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
1492 for (j = 0; j < width; j++, xoff++)
1494 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
1497 ptable = point_table;
1498 ptable->p->x = xoff;
1499 ptable->p->y = yoff;
1501 if (ptable->p - ptable->points == NUM_POINTS)
1503 (*frame->driver->draw_points) (frame, win, rface,
1505 ptable->points, NUM_POINTS, region);
1506 ptable->p = ptable->points;
1513 if (gstring->anti_alias)
1515 for (i = 1; i < 8; i++)
1516 if (point_table[i].p != point_table[i].points)
1517 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
1518 point_table[i].points,
1519 point_table[i].p - point_table[i].points, region);
1523 if (point_table[0].p != point_table[0].points)
1524 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
1525 point_table[0].points,
1526 point_table[0].p - point_table[0].points, region);
1531 ft_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
1533 MPlist *pl = NULL, *p;
1535 MPlist *file_list = NULL;
1536 MPlist *family_list = NULL, *capability_list = NULL;
1537 MSymbol registry = Mnil;
1539 MDEBUG_PRINT2 (" [FONT-FT] listing %s%s...",
1540 FONT_PROPERTY (font, MFONT_FAMILY)
1541 ? msymbol_name (FONT_PROPERTY (font, MFONT_FAMILY)) : "*",
1542 font->capability ? msymbol_name (font->capability) : "");
1548 registry = FONT_PROPERTY (font, MFONT_REGISTRY);
1549 if (registry != Mnil)
1551 char *reg = MSYMBOL_NAME (registry);
1553 if (strncmp (reg, "unicode-", 8)
1554 && strncmp (reg, "apple-roman", 11)
1555 && (reg[0] < '0' || reg[0] > '9' || reg[1] != '-'))
1559 if (font->file != Mnil
1560 && ! (file_list = ft_list_file (font->file)))
1562 family = FONT_PROPERTY (font, MFONT_FAMILY);
1564 && (family_list = MPLIST_PLIST (ft_list_family (family, 1)))
1565 && MPLIST_TAIL_P (family_list))
1567 if (font->capability != Mnil
1568 && (capability_list = ft_list_capability (font->capability))
1569 && MPLIST_TAIL_P (capability_list))
1573 if (! file_list && ! family_list && ! capability_list)
1575 /* No restriction. Get all fonts. */
1577 MPLIST_DO (family_list, ft_list_family (Mnil, 0))
1579 MPLIST_DO (p, MPLIST_PLIST (family_list))
1580 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1588 mplist_push (pl, MPLIST_KEY (file_list), MPLIST_VAL (file_list));
1593 for (p = pl; ! MPLIST_TAIL_P (p);)
1595 if (mplist_find_by_value (family_list, MPLIST_VAL (p)))
1596 p = MPLIST_NEXT (p);
1603 MPLIST_DO (p, family_list)
1604 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1607 if (capability_list)
1610 for (p = pl; ! MPLIST_TAIL_P (p);)
1612 MFontFT *ft_info = MPLIST_VAL (p);
1614 if (mplist_find_by_value (capability_list, ft_info))
1615 p = MPLIST_NEXT (p);
1622 MPLIST_DO (p, capability_list)
1623 mplist_push (pl, MPLIST_KEY (p), MPLIST_VAL (p));
1630 MSymbol weight = FONT_PROPERTY (font, MFONT_WEIGHT);
1631 MSymbol style = FONT_PROPERTY (font, MFONT_STYLE);
1632 MSymbol stretch = FONT_PROPERTY (font, MFONT_STRETCH);
1633 int size = font->size;
1635 if (weight != Mnil || style != Mnil || stretch != Mnil || size > 0)
1636 for (p = pl; ! MPLIST_TAIL_P (p); )
1638 MFontFT *ft_info = MPLIST_VAL (p);
1641 && weight != FONT_PROPERTY (&ft_info->font, MFONT_WEIGHT))
1643 && style != FONT_PROPERTY (&ft_info->font, MFONT_STYLE))
1645 && stretch != FONT_PROPERTY (&ft_info->font,
1648 && ft_info->font.size > 0
1649 && ft_info->font.size != size))
1652 p = MPLIST_NEXT (p);
1658 plist = mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
1660 if (maxnum && maxnum <= num)
1663 M17N_OBJECT_UNREF (pl);
1666 MDEBUG_PRINT1 (" %d found\n", num);
1673 MFontDriver mfont__ft_driver =
1674 { ft_select, ft_open, ft_find_metric, ft_has_char, ft_encode_char,
1675 ft_render, ft_list };
1682 if (FT_Init_FreeType (&ft_library) != 0)
1683 MERROR (MERROR_FONT_FT, -1);
1685 for (i = 0; i < ft_to_prop_size; i++)
1686 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
1688 Mmedium = msymbol ("medium");
1690 Mnull = msymbol ("");
1692 M0_3 = msymbol ("0-3");
1693 M3_1 = msymbol ("3-1");
1694 M1_0 = msymbol ("1-0");
1696 #ifdef HAVE_FONTCONFIG
1697 for (i = 0; i < (sizeof (fc_all_table) / sizeof fc_all_table[0]); i++)
1699 FC_vs_M17N_font_prop *table = fc_all_table[i];
1702 for (j = 0; table[j].m17n_value; j++)
1703 table[j].sym = msymbol (table[j].m17n_value);
1704 table[j].sym = table[j - 1].sym;
1711 MSymbol serif, sans_serif, monospace;
1713 fc_config = FcInitLoadConfigAndFonts ();
1714 if (mfont_freetype_path)
1716 MPLIST_DO (plist, mfont_freetype_path)
1717 if (MPLIST_STRING_P (plist)
1718 && (pathname = MPLIST_STRING (plist))
1719 && stat (pathname, &buf) == 0)
1721 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1724 while ((dir = FcStrListNext (strlist)))
1725 if (strcmp ((char *) dir, pathname) == 0)
1728 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1729 FcStrListDone (strlist);
1732 Mgeneric_family = msymbol ("generic famly");
1733 serif = msymbol ("serif");
1734 msymbol_put (serif, Mgeneric_family, serif);
1735 sans_serif = msymbol ("sans-serif");
1736 msymbol_put (sans_serif, Mgeneric_family, sans_serif);
1737 msymbol_put (msymbol ("sans serif"), Mgeneric_family, sans_serif);
1738 msymbol_put (msymbol ("sans"), Mgeneric_family, sans_serif);
1739 monospace = msymbol ("monospace");
1740 msymbol_put (monospace, Mgeneric_family, monospace);
1741 msymbol_put (msymbol ("mono"), Mgeneric_family, monospace);
1755 MPLIST_DO (plist, ft_font_list)
1757 if (MPLIST_VAL (plist))
1758 MPLIST_DO (p, MPLIST_VAL (plist))
1760 if (MPLIST_KEY (p) != Mt)
1761 free_ft_info (MPLIST_VAL (p));
1763 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1765 M17N_OBJECT_UNREF (ft_font_list);
1767 if (ft_language_list)
1769 MPLIST_DO (plist, ft_language_list)
1770 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1771 M17N_OBJECT_UNREF (ft_language_list);
1776 MPLIST_DO (plist, ft_script_list)
1777 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1778 M17N_OBJECT_UNREF (ft_script_list);
1781 if (ft_capability_list)
1783 MPLIST_DO (plist, ft_capability_list)
1784 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1785 M17N_OBJECT_UNREF (ft_capability_list);
1790 MPLIST_DO (plist, ft_file_list)
1791 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1792 M17N_OBJECT_UNREF (ft_file_list);
1796 FT_Done_FreeType (ft_library);
1797 #ifdef HAVE_FONTCONFIG
1798 FcConfigDestroy (fc_config);
1800 #endif /* HAVE_FONTCONFIG */
1801 all_fonts_scaned = 0;
1804 #ifdef HAVE_FONTCONFIG
1807 mfont__ft_parse_name (const char *name, MFont *font)
1809 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1818 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1820 STRDUP_LOWER (buf, bufsize, (char *) str);
1821 mfont__set_property (font, MFONT_FOUNDRY, msymbol (buf));
1823 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1825 STRDUP_LOWER (buf, bufsize, (char *) str);
1826 mfont__set_property (font, MFONT_FAMILY, msymbol (buf));
1828 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1829 mfont__set_property (font, MFONT_WEIGHT,
1830 fc_decode_prop (val, fc_weight_table,
1831 fc_weight_table_size));
1832 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1833 mfont__set_property (font, MFONT_STYLE,
1834 fc_decode_prop (val, fc_slant_table,
1835 fc_slant_table_size));
1836 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1837 mfont__set_property (font, MFONT_STRETCH,
1838 fc_decode_prop (val, fc_width_table,
1839 fc_width_table_size));
1840 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1841 font->size = size * 10 + 0.5;
1842 else if (FcPatternGetDouble (pat, FC_SIZE, 0, &size) == FcResultMatch)
1843 font->size = - (size * 10 + 0.5);
1844 if (FcPatternGetString (pat, FC_FILE, 0, &str) == FcResultMatch)
1846 font->file = msymbol ((char *) str);
1848 mfont__set_property (font, MFONT_REGISTRY, Municode_bmp);
1849 font->type = MFONT_TYPE_SPEC;
1850 FcPatternDestroy (pat);
1855 mfont__ft_unparse_name (MFont *font)
1857 FcPattern *pat = fc_get_pattern (font);
1858 char *name = (char *) FcNameUnparse (pat);
1860 FcPatternDestroy (pat);
1863 #endif /* HAVE_FONTCONFIG */
1868 #define DEVICE_DELTA(table, size) \
1869 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1870 ? (table).DeltaValue[(size) >= (table).StartSize] \
1874 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1875 unsigned code, int size, int *x, int *y)
1877 if (anchor->AnchorFormat == 2)
1879 FT_Outline *outline;
1880 int ap = anchor->f.f1.AnchorPoint;
1882 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1883 outline = &ft_face->glyph->outline;
1884 if (ap < outline->n_points)
1886 *x = outline->points[ap].x;
1887 *y = outline->points[ap].y;
1890 else if (anchor->AnchorFormat == 3)
1892 if (anchor->f.f2.XDeviceTable.offset)
1893 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1894 if (anchor->f.f2.YDeviceTable.offset)
1895 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1900 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1901 MFontCapability *cap)
1903 int len = to - from;
1904 MGlyph *g = MGLYPH (from);
1906 MRealizedFont *rfont;
1909 OTF_GlyphString otf_gstring;
1911 char *script, *langsys;
1912 char *gsub_features, *gpos_features;
1918 otf_gstring.glyphs = NULL;
1919 rfont = g->rface->rfont;
1920 ft_info = (MFontFT *) rfont->font;
1921 if (ft_info->otf == invalid_otf)
1926 otf = OTF_open (MSYMBOL_NAME (ft_info->font.file));
1929 ft_info->otf = invalid_otf;
1934 if (OTF_get_table (otf, "head") < 0)
1937 ft_info->otf = invalid_otf;
1941 if (cap->script_tag)
1943 script = alloca (5);
1944 OTF_tag_name (cap->script_tag, script);
1948 if (cap->langsys_tag)
1950 langsys = alloca (5);
1951 OTF_tag_name (cap->langsys_tag, langsys);
1955 gsub_features = cap->features[MFONT_OTT_GSUB].str;
1956 if (gsub_features && OTF_check_table (otf, "GSUB") < 0)
1957 gsub_features = NULL;
1958 gpos_features = cap->features[MFONT_OTT_GPOS].str;
1959 if (gpos_features && OTF_check_table (otf, "GPOS") < 0)
1960 gpos_features = NULL;
1962 otf_gstring.size = otf_gstring.used = len;
1963 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1964 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1965 for (i = 0, need_cmap = 0; i < len; i++)
1967 if (gstring->glyphs[from + i].otf_encoded)
1969 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1970 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1974 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1979 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1982 OTF_drive_gdef (otf, &otf_gstring);
1983 gidx = gstring->used;
1987 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
1990 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1992 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1995 temp.combining_code = 0;
1998 temp.code = otfg->glyph_id;
1999 temp.otf_encoded = 1;
2004 temp.otf_encoded = 0;
2006 temp.to = MGLYPH (from + otfg->f.index.to)->to;
2007 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2011 for (i = 0; i < len; i++)
2013 MGlyph temp = gstring->glyphs[from + i];
2015 if (otf_gstring.glyphs[i].glyph_id)
2017 temp.code = otf_gstring.glyphs[i].glyph_id;
2018 temp.otf_encoded = 1;
2020 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2023 (rfont->driver->find_metric) (rfont, gstring, gidx, gstring->used);
2029 MGlyph *base = NULL, *mark = NULL;
2031 if (OTF_check_features (otf, 1,
2032 cap->script_tag, cap->langsys_tag,
2033 cap->features[MFONT_OTT_GPOS].tags,
2034 cap->features[MFONT_OTT_GPOS].nfeatures) != 1
2035 || (OTF_drive_gpos (otf, &otf_gstring, script, langsys,
2036 gpos_features) < 0))
2039 u = otf->head->unitsPerEm;
2040 size10 = rfont->spec.size;
2043 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
2044 i < otf_gstring.used; i++, otfg++, g++)
2048 if (! otfg->glyph_id)
2050 switch (otfg->positioning_type)
2056 int format = otfg->f.f1.format;
2058 if (format & OTF_XPlacement)
2059 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
2060 if (format & OTF_XPlaDevice)
2061 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
2062 if (format & OTF_YPlacement)
2063 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
2064 if (format & OTF_YPlaDevice)
2065 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
2066 if (format & OTF_XAdvance)
2067 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
2068 if (format & OTF_XAdvDevice)
2069 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
2073 /* Not yet supported. */
2079 goto label_adjust_anchor;
2080 default: /* i.e. case 6 */
2085 label_adjust_anchor:
2087 int base_x, base_y, mark_x, mark_y;
2089 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
2090 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
2091 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
2092 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
2094 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
2095 adjust_anchor (otfg->f.f4.base_anchor, rfont->fontp,
2096 prev->code, size, &base_x, &base_y);
2097 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
2098 adjust_anchor (otfg->f.f4.mark_anchor, rfont->fontp,
2099 g->code, size, &mark_x, &mark_y);
2100 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
2101 g->yoff = prev->yoff + mark_y - base_y;
2102 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
2105 if (otfg->GlyphClass == OTF_GlyphClass0)
2107 else if (otfg->GlyphClass == OTF_GlyphClassMark)
2113 free (otf_gstring.glyphs);
2117 ft_find_metric (rfont, gstring, from, to);
2118 for (i = 0; i < len; i++)
2120 MGlyph temp = gstring->glyphs[from + i];
2121 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
2123 if (otf_gstring.glyphs)
2124 free (otf_gstring.glyphs);
2130 mfont__ft_decode_otf (MGlyph *g)
2132 MFontFT *ft_info = (MFontFT *) g->rface->rfont->font;
2133 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
2135 return (c ? c : -1);
2138 #endif /* HAVE_OTF */
2140 #endif /* HAVE_FREETYPE */