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"
39 #include "internal-gui.h"
46 #include <freetype/ftbdf.h>
49 #ifdef HAVE_FONTCONFIG
50 static FcConfig *fc_config;
51 #endif /* HAVE_FONTCONFIG */
54 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
56 /* Font properties; Mnormal is already defined in face.c. */
57 static MSymbol Mmedium, Mr, Mnull;
59 static FT_Library ft_library;
65 enum MFontProperty prop;
69 static MFTtoProp ft_to_prop[] =
70 { { "italic", 0, MFONT_STYLE, "i" },
71 { "roman", 0, MFONT_STYLE, "r" },
72 { "oblique", 0, MFONT_STYLE, "p" },
73 { "regular", 0, MFONT_WEIGHT, "medium" },
74 { "normal", 0, MFONT_WEIGHT, "medium" },
75 /* We need this entry even if "bold" is in commone_weight[] to
76 handle such style names as "bolditalic" and "boldoblique". */
77 { "bold", 0, MFONT_WEIGHT, "bold" },
78 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
79 { "demi", 0, MFONT_WEIGHT, "demibold" } };
80 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
82 /** List of FreeType fonts. Keys are family names, values are plists
83 containing fonts of the corresponding family. In the deeper
84 plist, keys are Mt, values are (MFTInfo *). */
85 static MPlist *ft_font_list;
87 /** List of FreeType base fonts. Keys are family names, values are
89 static MPlist *ft_family_list;
91 static int all_fonts_scaned;
93 static MSymbol M_generic_family_info;
95 enum GenericFamilyType {
97 GENERIC_FAMILY_SANS_SERIF,
98 GENERIC_FAMILY_MONOSPACE,
102 /** Table for each generic family. */
110 static GenericFamilyInfo generic_family_table[GENERIC_FAMILY_MAX] =
111 { { "serif" }, { "sans-serif" }, { "monospace" } };
113 /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize
117 check_otf_filename (const char *name)
119 int len = strlen (name);
120 const char *ext = name + (len - 4);
123 || (memcmp (ext, ".ttf", 4)
124 && memcmp (ext, ".TTF", 4)
125 && memcmp (ext, ".otf", 4)
126 && memcmp (ext, ".OTF", 4)))
131 #define STRDUP_LOWER(s1, size, s2) \
133 int len = strlen (s2) + 1; \
137 s1 = alloca (len), size = len; \
138 for (p1 = s1, p2 = s2; *p2; p1++, p2++) \
139 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
143 /** Setup members of FT_INFO from FT_FACE. If the font is a base one
144 (i.e. medium-r-normal), set BASEP to 1. Otherwise set BASEP to 0.
145 Return the family name. */
148 set_font_info (FT_Face ft_face, MFTInfo *ft_info,
149 MSymbol family, MSymbol style, int *basep)
151 MFont *font = &ft_info->font;
152 MPlist *charmap_list;
153 int unicode_bmp = -1, unicode_full = -1, unicode = -1;
158 mfont__set_property (font, MFONT_FAMILY, family);
159 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
160 mfont__set_property (font, MFONT_STYLE, Mr);
161 mfont__set_property (font, MFONT_STRETCH, Mnormal);
162 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
167 char *p = MSYMBOL_NAME (style);
171 for (i = 0; i < ft_to_prop_size; i++)
172 if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
174 mfont__set_property (font, ft_to_prop[i].prop,
175 msymbol (ft_to_prop[i].val));
176 p += ft_to_prop[i].len;
179 if (i == ft_to_prop_size)
184 while (*p1 >= 'a' && *p1 <= 'z') p1++;
185 sym = msymbol__with_len (p, p1 - p);
186 for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
187 if (msymbol_get (sym, mfont__property_table[i].property))
189 mfont__set_property (font, i, sym);
194 while (*p && (*p < 'a' || *p > 'z')) p++;
196 *basep = (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium
197 && FONT_PROPERTY (font, MFONT_STYLE) == Mr
198 && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal);
201 charmap_list = mplist ();
202 mplist_add (charmap_list, Mt, (void *) -1);
203 for (i = 0; i < ft_face->num_charmaps; i++)
205 char registry_buf[16];
208 sprintf (registry_buf, "%d-%d",
209 ft_face->charmaps[i]->platform_id,
210 ft_face->charmaps[i]->encoding_id);
211 registry = msymbol (registry_buf);
212 mplist_add (charmap_list, registry, (void *) i);
214 if (ft_face->charmaps[i]->platform_id == 0)
216 if (ft_face->charmaps[i]->encoding_id == 3)
218 else if (ft_face->charmaps[i]->encoding_id == 4)
221 else if (ft_face->charmaps[i]->platform_id == 3)
223 if (ft_face->charmaps[i]->encoding_id == 1)
225 else if (ft_face->charmaps[i]->encoding_id == 10)
228 else if (ft_face->charmaps[i]->platform_id == 1
229 && ft_face->charmaps[i]->encoding_id == 0)
230 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
232 if (unicode_full >= 0)
234 mplist_add (charmap_list, Municode_full, (void *) unicode_full);
235 mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
236 mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
237 unicode = unicode_full;
239 else if (unicode_bmp >= 0)
241 mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
242 mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
243 unicode = unicode_bmp;
247 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
248 for (i = 255; i >= 32; i--)
252 if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
256 mplist_add (charmap_list, Miso8859_1, (void *) unicode);
259 ft_info->charmap_list = charmap_list;
262 if (! FT_IS_SCALABLE (ft_face))
264 BDF_PropertyRec prop;
266 FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
267 font->property[MFONT_SIZE] = prop.u.integer * 10;
268 FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
269 font->property[MFONT_RESY] = prop.u.integer;
278 close_ft (void *object)
280 MFTInfo *ft_info = object;
282 if (ft_info->ft_face)
284 if (ft_info->extra_info)
285 M17N_OBJECT_UNREF (ft_info->extra_info);
286 FT_Done_Face (ft_info->ft_face);
289 OTF_close (ft_info->otf);
290 #endif /* HAVE_OTF */
292 free (ft_info->filename);
293 if (ft_info->languages)
294 free (ft_info->languages);
295 M17N_OBJECT_UNREF (ft_info->charmap_list);
300 add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist)
303 BDF_PropertyRec prop;
305 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
313 if (ft_face->family_name)
315 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
316 family = msymbol (buf);
320 if (! (plist = mplist_get (ft_font_list, family)))
323 mplist_add (ft_font_list, family, plist);
326 if (ft_face->style_name)
328 STRDUP_LOWER (buf, bufsize, ft_face->style_name);
329 style = msymbol (buf);
334 if (! mplist_get (plist, style)
335 && (FT_IS_SCALABLE (ft_face)
337 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0
344 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
345 ft_info->filename = strdup (filename);
346 ft_info->otf_flag = check_otf_filename (filename);
347 #ifdef HAVE_FONTCONFIG
349 ft_info->langset = FcLangSetCopy (langset);
351 set_font_info (ft_face, ft_info, family, style, &basep);
352 mplist_add (plist, style, ft_info);
355 mplist_put (ft_family_list, family, ft_info);
356 else if (! mplist_get (ft_family_list, family))
357 mplist_add (ft_family_list, family, ft_info);
359 FT_Done_Face (ft_face);
363 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
364 scan all fonts and return ft_font_list. */
366 ft_list_family (MSymbol family)
368 MPlist *plist, *head;
372 ft_font_list = mplist ();
373 ft_family_list = mplist ();
380 head = mplist_find_by_key (ft_font_list, family);
383 head = mplist_add (ft_font_list, family, mplist ());
386 #ifdef HAVE_FONTCONFIG
387 if (! all_fonts_scaned)
396 pattern = FcPatternCreate ();
399 FcPatternAddString (pattern, FC_FAMILY,
400 (FcChar8 *) (msymbol_name (family)));
402 os = FcObjectSetBuild (FC_FILE, FC_LANG, NULL);
407 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
409 fs = FcFontList (fc_config, pattern, os);
410 for (i = 0; i < fs->nfont; i++)
415 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
416 (FcChar8 **) &filename) != FcResultMatch)
418 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0,
419 &langset) != FcResultMatch)
426 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
427 (FcChar8 **) &fname) == FcResultMatch)
429 STRDUP_LOWER (buf, bufsize, fname);
431 if (! plist || MPLIST_KEY (plist) != fam)
433 plist = mplist_find_by_key (ft_font_list, fam);
435 plist = mplist_add (ft_font_list, fam, mplist ());
437 add_font_info (filename, fam, langset, MPLIST_PLIST (plist));
441 add_font_info (filename, family, langset, MPLIST_PLIST (plist));
444 FcFontSetDestroy (fs);
445 FcObjectSetDestroy (os);
446 FcPatternDestroy (pattern);
447 all_fonts_scaned = family == Mnil;
450 #else /* not HAVE_FONTCONFIG */
452 if (! all_fonts_scaned)
457 MPLIST_DO (plist, mfont_freetype_path)
458 if (MPLIST_STRING_P (plist)
459 && (pathname = MPLIST_STRING (plist))
460 && stat (pathname, &buf) == 0)
462 if (S_ISREG (buf.st_mode))
463 add_font_info (pathname, Mnil, NULL, NULL);
464 else if (S_ISDIR (buf.st_mode))
466 int len = strlen (pathname);
468 DIR *dir = opendir (pathname);
473 strcpy (path, pathname);
474 strcpy (path + len, "/");
476 while ((dp = readdir (dir)) != NULL)
478 strcpy (path + len, dp->d_name);
479 add_font_info (path, Mnil, NULL, NULL);
485 all_fonts_scaned = 1;
488 #endif /* not HAVE_FONTCONFIG */
494 ft_list_generic (MSymbol generic)
496 #ifdef HAVE_FONTCONFIG
497 GenericFamilyInfo *info = msymbol_get (generic, M_generic_family_info);
505 info->list = mplist ();
506 pattern = FcPatternCreate ();
507 FcPatternAddString (pattern, FC_FAMILY,
508 (FcChar8 *) info->name);
509 if (FcConfigSubstitute (fc_config, pattern, FcMatchPattern) == FcTrue)
515 while (FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &family)
520 STRDUP_LOWER (buf, bufsize, family);
521 plist = ft_list_family (msymbol (buf));
522 mplist_add (info->list, MPLIST_KEY (plist), MPLIST_VAL (plist));
527 #else /* not HAVE_FONTCONFIG */
529 #endif /* not HAVE_FONTCONFIG */
533 /* The FreeType font driver function SELECT. */
535 static MRealizedFont *
536 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
538 MPlist *plist, *pl, *p;
541 MRealizedFont *rfont;
542 MSymbol registry, family;
543 unsigned short spec_family_id, request_family_id;
545 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
546 if (registry == Mnil)
548 family = FONT_PROPERTY (spec, MFONT_FAMILY);
549 spec_family_id = spec->property[MFONT_FAMILY];
550 request_family_id = request->property[MFONT_FAMILY];
554 plist = ft_list_generic (family);
558 spec->property[MFONT_FAMILY] = 0;
559 if (spec_family_id == request_family_id)
560 request->property[MFONT_FAMILY] = 0;
564 if (request_family_id
566 = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY)))
567 && mplist_get (plist, family))
568 request->property[MFONT_FAMILY] = 0;
569 plist = ft_list_family (family);
574 if (request_family_id
575 && (plist = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY))))
576 request->property[MFONT_FAMILY] = 0;
578 plist = ft_list_family (FONT_PROPERTY (request, MFONT_FAMILY));
583 MPLIST_DO (pl, plist)
585 MPLIST_DO (p, MPLIST_VAL (pl))
587 MFTInfo *ft_info = MPLIST_VAL (p);
590 if (! mplist_find_by_key (ft_info->charmap_list, registry))
593 /* Always ignore FOUNDRY. */
594 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
595 score = mfont__score (&ft_info->font, spec, request, limited_size);
598 || best_score > score))
606 if (best_score == 0 || family != Mnil)
609 spec->property[MFONT_FAMILY] = spec_family_id;
610 request->property[MFONT_FAMILY] = request_family_id;
614 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
615 rfont->frame = frame;
617 rfont->request = *request;
618 rfont->font = best_font->font;
619 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
620 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
621 rfont->score = best_score;
622 rfont->info = best_font;
623 M17N_OBJECT_REF (best_font);
628 /* The FreeType font driver function OPEN. */
631 ft_open (MRealizedFont *rfont)
633 MFTInfo *base = rfont->info, *ft_info;
634 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
635 int mdebug_mask = MDEBUG_FONT;
638 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
639 ft_info->font = base->font;
640 ft_info->filename = strdup (base->filename);
641 ft_info->otf_flag = base->otf_flag;
642 ft_info->charmap_list = base->charmap_list;
643 M17N_OBJECT_REF (ft_info->charmap_list);
644 M17N_OBJECT_UNREF (base);
645 rfont->info = ft_info;
648 ft_info->ft_face = NULL;
649 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
651 if (registry == Mnil)
653 ft_info->charmap_index
654 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
655 if (ft_info->charmap_index >= 0
656 && FT_Set_Charmap (ft_info->ft_face,
657 ft_info->ft_face->charmaps[ft_info->charmap_index]))
659 size = rfont->font.property[MFONT_SIZE] / 10;
660 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
663 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
665 rfont->ascent = ft_info->ft_face->size->metrics.ascender >> 6;
666 rfont->descent = - (ft_info->ft_face->size->metrics.descender >> 6);
667 rfont->type = Mfreetype;
668 rfont->fontp = ft_info->ft_face;
672 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
673 if (ft_info->ft_face)
674 FT_Done_Face (ft_info->ft_face);
675 M17N_OBJECT_UNREF (ft_info->charmap_list);
676 free (ft_info->filename);
682 /* The FreeType font driver function FIND_METRIC. */
685 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
688 MFTInfo *ft_info = (MFTInfo *) rfont->info;
689 FT_Face ft_face = ft_info->ft_face;
690 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
692 for (; g != gend; g++)
694 if (g->code == MCHAR_INVALID_CODE)
696 if (FT_IS_SCALABLE (ft_face))
698 unsigned unitsPerEm = ft_face->units_per_EM;
699 int size = rfont->font.property[MFONT_SIZE] / 10;
702 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
703 g->width = ft_face->max_advance_width * size / unitsPerEm;
704 g->ascent = ft_face->ascender * size / unitsPerEm;
705 g->descent = (- ft_face->descender) * size / unitsPerEm;
709 BDF_PropertyRec prop;
712 g->rbearing = g->width = ft_face->available_sizes->width;
714 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
716 g->ascent = prop.u.integer;
717 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
718 g->descent = prop.u.integer;
723 g->ascent = ft_face->available_sizes->height;
730 FT_Glyph_Metrics *metrics;
732 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
733 metrics = &ft_face->glyph->metrics;
734 g->lbearing = (metrics->horiBearingX >> 6);
735 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
736 g->width = metrics->horiAdvance >> 6;
737 g->ascent = metrics->horiBearingY >> 6;
738 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
743 /* The FreeType font driver function ENCODE_CHAR. */
746 ft_encode_char (MRealizedFont *rfont, unsigned code)
750 if (rfont->status == 0)
752 if ((rfont->driver->open) (rfont) < 0)
755 ft_info = (MFTInfo *) rfont->info;
756 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
758 return MCHAR_INVALID_CODE;
763 /* The FreeType font driver function RENDER. */
765 #define NUM_POINTS 0x1000
768 MDrawPoint points[NUM_POINTS];
773 ft_render (MDrawWindow win, int x, int y,
774 MGlyphString *gstring, MGlyph *from, MGlyph *to,
775 int reverse, MDrawRegion region)
779 MRealizedFace *rface = from->rface;
780 MFrame *frame = rface->frame;
781 FT_Int32 load_flags = FT_LOAD_RENDER;
784 MPointTable point_table[8];
789 /* It is assured that the all glyphs in the current range use the
790 same realized face. */
791 ft_info = (MFTInfo *) rface->rfont->info;
792 ft_face = ft_info->ft_face;
794 if (! gstring->anti_alias)
796 #ifdef FT_LOAD_TARGET_MONO
797 load_flags |= FT_LOAD_TARGET_MONO;
799 load_flags |= FT_LOAD_MONOCHROME;
803 for (i = 0; i < 8; i++)
804 point_table[i].p = point_table[i].points;
806 for (g = from; g < to; x += g++->width)
814 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
815 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
816 bmp = ft_face->glyph->bitmap.buffer;
817 width = ft_face->glyph->bitmap.width;
818 pitch = ft_face->glyph->bitmap.pitch;
819 if (! gstring->anti_alias)
824 if (gstring->anti_alias)
825 for (i = 0; i < ft_face->glyph->bitmap.rows;
826 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
828 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
829 for (j = 0; j < width; j++, xoff++)
831 intensity = bmp[j] >> 5;
834 ptable = point_table + intensity;
838 if (ptable->p - ptable->points == NUM_POINTS)
840 (*frame->driver->draw_points)
842 reverse ? 7 - intensity : intensity,
843 ptable->points, NUM_POINTS, region);
844 ptable->p = ptable->points;
850 for (i = 0; i < ft_face->glyph->bitmap.rows;
851 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
853 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
854 for (j = 0; j < width; j++, xoff++)
856 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
859 ptable = point_table;
863 if (ptable->p - ptable->points == NUM_POINTS)
865 (*frame->driver->draw_points) (frame, win, rface,
867 ptable->points, NUM_POINTS, region);
868 ptable->p = ptable->points;
875 if (gstring->anti_alias)
877 for (i = 1; i < 8; i++)
878 if (point_table[i].p != point_table[i].points)
879 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
880 point_table[i].points,
881 point_table[i].p - point_table[i].points, region);
885 if (point_table[0].p != point_table[0].points)
886 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
887 point_table[0].points,
888 point_table[0].p - point_table[0].points, region);
893 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
897 #ifdef HAVE_FONTCONFIG
898 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
905 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
906 pl = ft_list_generic (family);
910 pl = ft_list_family (family);
913 MPLIST_DO (p, MPLIST_PLIST (pl))
915 MFTInfo *ft_info = MPLIST_VAL (p);
917 #ifdef HAVE_FONTCONFIG
918 if (lang && ft_info->langset
919 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
922 mplist_add (plist, MPLIST_KEY (pl), &ft_info->font);
933 ft_list_family (Mnil);
934 MPLIST_DO (p, ft_family_list)
936 MFTInfo *ft_info = MPLIST_VAL (p);
938 #ifdef HAVE_FONTCONFIG
939 if (lang && ft_info->langset
940 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
943 mplist_add (plist, MPLIST_KEY (p), &ft_info->font);
955 MFontDriver mfont__ft_driver =
956 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
963 if (FT_Init_FreeType (&ft_library) != 0)
964 MERROR (MERROR_FONT_FT, -1);
966 for (i = 0; i < ft_to_prop_size; i++)
967 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
969 Municode_bmp = msymbol ("unicode-bmp");
970 Municode_full = msymbol ("unicode-full");
971 Miso10646_1 = msymbol ("iso10646-1");
972 Miso8859_1 = msymbol ("iso8859-1");
974 Mmedium = msymbol ("medium");
976 Mnull = msymbol ("");
978 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
979 generic_family_table[i].list = NULL;
980 M_generic_family_info = msymbol (" generic_family_info");
981 msymbol_put (msymbol ("serif"), M_generic_family_info,
982 generic_family_table + GENERIC_FAMILY_SERIF);
983 msymbol_put (msymbol ("sans-serif"), M_generic_family_info,
984 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
985 msymbol_put (msymbol ("sans"), M_generic_family_info,
986 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
987 msymbol_put (msymbol ("sans serif"), M_generic_family_info,
988 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
989 msymbol_put (msymbol ("monospace"), M_generic_family_info,
990 generic_family_table + GENERIC_FAMILY_MONOSPACE);
991 msymbol_put (msymbol ("mono"), M_generic_family_info,
992 generic_family_table + GENERIC_FAMILY_MONOSPACE);
993 msymbol_put (msymbol ("m"), M_generic_family_info,
994 generic_family_table + GENERIC_FAMILY_MONOSPACE);
996 #ifdef HAVE_FONTCONFIG
1004 fc_config = FcConfigGetCurrent ();
1005 MPLIST_DO (plist, mfont_freetype_path)
1006 if (MPLIST_STRING_P (plist)
1007 && (pathname = MPLIST_STRING (plist))
1008 && stat (pathname, &buf) == 0)
1010 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1013 while ((dir = FcStrListNext (strlist)))
1014 if (strcmp ((char *) dir, pathname) == 0)
1017 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1018 FcStrListDone (strlist);
1032 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
1033 if (generic_family_table[i].list)
1034 M17N_OBJECT_UNREF (generic_family_table[i].list);
1037 MPLIST_DO (plist, ft_font_list)
1039 MPLIST_DO (p, MPLIST_VAL (plist))
1041 MFTInfo *ft_info = MPLIST_VAL (p);
1043 M17N_OBJECT_UNREF (ft_info);
1045 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1047 M17N_OBJECT_UNREF (ft_font_list);
1048 ft_font_list = NULL;
1050 M17N_OBJECT_UNREF (ft_family_list);
1051 ft_family_list = NULL;
1053 FT_Done_FreeType (ft_library);
1054 all_fonts_scaned = 0;
1058 #ifdef HAVE_FONTCONFIG
1063 } FC_vs_M17N_font_prop;
1065 static FC_vs_M17N_font_prop fc_weight_table[] =
1066 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1067 { FC_WEIGHT_LIGHT, "light" },
1068 { FC_WEIGHT_NORMAL, "normal" },
1069 { FC_WEIGHT_MEDIUM, "medium" },
1070 { FC_WEIGHT_DEMIBOLD, "demibold" },
1071 { FC_WEIGHT_EXTRABOLD, "extrabold" },
1072 { FC_WEIGHT_BLACK, "black" },
1073 { FC_WEIGHT_MEDIUM, NULL } };
1075 static FC_vs_M17N_font_prop fc_slant_table[] =
1076 { { FC_SLANT_ROMAN, "r" },
1077 { FC_SLANT_ITALIC, "i" },
1078 { FC_SLANT_OBLIQUE, "o" },
1079 { FC_SLANT_ROMAN, NULL } };
1081 static FC_vs_M17N_font_prop fc_width_table[] =
1082 { { FC_WIDTH_CONDENSED, "condensed" },
1083 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1084 { FC_WIDTH_NORMAL, "normal" },
1085 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1086 { FC_WIDTH_EXPANDED, "expanded" },
1087 { FC_WIDTH_NORMAL, NULL } };
1091 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1095 for (i = 0; table[i].m17n_value; i++)
1096 if (val <= table[i].fc_value)
1097 return msymbol ("table[i].m17n_value");
1098 return msymbol ("table[i - 1].m17n_value");
1102 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1106 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1107 return table[i].fc_value;
1111 mfont__ft_parse_name (char *name, MFont *font)
1113 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1120 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1121 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1122 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1123 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1124 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1125 mfont__set_property (font, MFONT_WEIGHT,
1126 fc_decode_prop (val, fc_weight_table));
1127 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1128 mfont__set_property (font, MFONT_STYLE,
1129 fc_decode_prop (val, fc_slant_table));
1130 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1131 mfont__set_property (font, MFONT_STRETCH,
1132 fc_decode_prop (val, fc_width_table));
1133 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1134 font->property[MFONT_SIZE] = size * 10;
1135 FcPatternDestroy (pat);
1140 mfont__ft_unparse_name (MFont *font)
1142 FcPattern *pat = FcPatternCreate ();
1143 MSymbol sym, weight, style, stretch;
1146 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1147 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1148 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1149 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1150 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1151 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1153 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1154 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1156 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1157 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1159 name = (char *) FcNameUnparse (pat);
1160 FcPatternDestroy (pat);
1163 #endif /* HAVE_FONTCONFIG */
1168 #define DEVICE_DELTA(table, size) \
1169 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1170 ? (table).DeltaValue[(size) >= (table).StartSize] \
1174 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1175 unsigned code, int size, int *x, int *y)
1177 if (anchor->AnchorFormat == 2)
1179 FT_Outline *outline;
1180 int ap = anchor->f.f1.AnchorPoint;
1182 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1183 outline = &ft_face->glyph->outline;
1184 if (ap < outline->n_points)
1186 *x = outline->points[ap].x;
1187 *y = outline->points[ap].y;
1190 else if (anchor->AnchorFormat == 3)
1192 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1193 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1198 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1199 MSymbol script, MSymbol langsys,
1200 MSymbol gsub_features, MSymbol gpos_features)
1202 int len = to - from;
1203 MGlyph *g = MGLYPH (from);
1205 MRealizedFont *rfont;
1208 OTF_GlyphString otf_gstring;
1210 char *script_name, *language_name;
1211 char *gsub_feature_names, *gpos_feature_names;
1217 rfont = g->rface->rfont;
1218 ft_info = rfont->info;
1219 if (ft_info->otf_flag < 0)
1224 otf = OTF_open (ft_info->filename);
1225 if (otf && OTF_get_table (otf, "head") < 0)
1232 ft_info->otf_flag = -1;
1239 script_name = msymbol_name (script);
1242 if (langsys != Mnil)
1243 language_name = msymbol_name (langsys);
1245 language_name = NULL;
1247 = (gsub_features == Mt ? "*"
1248 : gsub_features == Mnil ? NULL
1249 : msymbol_name (gsub_features));
1250 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1251 gsub_feature_names = NULL;
1253 = (gpos_features == Mt ? "*"
1254 : gpos_features == Mnil ? NULL
1255 : msymbol_name (gpos_features));
1256 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1257 gpos_feature_names = NULL;
1259 otf_gstring.size = otf_gstring.used = len;
1260 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1261 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1262 for (i = 0, need_cmap = 0; i < len; i++)
1264 if (gstring->glyphs[from + i].otf_encoded)
1266 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1267 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1271 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1276 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1279 OTF_drive_gdef (otf, &otf_gstring);
1280 gidx = gstring->used;
1282 if (gsub_feature_names)
1284 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1285 gsub_feature_names) < 0)
1287 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1289 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1292 temp.combining_code = 0;
1295 temp.code = otfg->glyph_id;
1296 temp.otf_encoded = 1;
1301 temp.otf_encoded = 0;
1303 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1304 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1308 for (i = 0; i < len; i++)
1310 MGlyph temp = gstring->glyphs[from + i];
1312 if (otf_gstring.glyphs[i].glyph_id)
1314 temp.code = otf_gstring.glyphs[i].glyph_id;
1315 temp.otf_encoded = 1;
1317 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1320 ft_find_metric (rfont, gstring, gidx, gstring->used);
1322 if (gpos_feature_names)
1326 MGlyph *base = NULL, *mark = NULL;
1328 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1329 gpos_feature_names) < 0)
1332 u = otf->head->unitsPerEm;
1333 size10 = rfont->font.property[MFONT_SIZE];
1336 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1337 i < otf_gstring.used; i++, otfg++, g++)
1341 if (! otfg->glyph_id)
1343 switch (otfg->positioning_type)
1349 int format = otfg->f.f1.format;
1351 if (format & OTF_XPlacement)
1352 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1353 if (format & OTF_XPlaDevice)
1354 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1355 if (format & OTF_YPlacement)
1356 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1357 if (format & OTF_YPlaDevice)
1358 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1359 if (format & OTF_XAdvance)
1360 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1361 if (format & OTF_XAdvDevice)
1362 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1366 /* Not yet supported. */
1372 goto label_adjust_anchor;
1373 default: /* i.e. case 6 */
1378 label_adjust_anchor:
1380 int base_x, base_y, mark_x, mark_y;
1382 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1383 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1384 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1385 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1387 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1388 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1389 prev->code, size, &base_x, &base_y);
1390 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1391 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1392 g->code, size, &mark_x, &mark_y);
1393 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1394 g->yoff = prev->yoff + mark_y - base_y;
1395 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1398 if (otfg->GlyphClass == OTF_GlyphClass0)
1400 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1406 free (otf_gstring.glyphs);
1410 ft_find_metric (rfont, gstring, from, to);
1411 for (i = 0; i < len; i++)
1413 MGlyph temp = gstring->glyphs[from + i];
1414 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1416 free (otf_gstring.glyphs);
1422 mfont__ft_decode_otf (MGlyph *g)
1424 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1425 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1427 return (c ? c : -1);
1430 #endif /* HAVE_OTF */
1432 #endif /* HAVE_FREETYPE */