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"
45 #include <freetype/ftbdf.h>
47 #ifdef HAVE_FONTCONFIG
48 static FcConfig *fc_config;
49 #endif /* HAVE_FONTCONFIG */
52 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
54 /* Font properties; Mnormal is already defined in face.c. */
55 static MSymbol Mmedium, Mr, Mnull;
57 static FT_Library ft_library;
63 enum MFontProperty prop;
67 static MFTtoProp ft_to_prop[] =
68 { { "italic", 0, MFONT_STYLE, "i" },
69 { "roman", 0, MFONT_STYLE, "r" },
70 { "oblique", 0, MFONT_STYLE, "p" },
71 { "regular", 0, MFONT_WEIGHT, "medium" },
72 { "normal", 0, MFONT_WEIGHT, "medium" },
73 /* We need this entry even if "bold" is in commone_weight[] to
74 handle such style names as "bolditalic" and "boldoblique". */
75 { "bold", 0, MFONT_WEIGHT, "bold" },
76 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
77 { "demi", 0, MFONT_WEIGHT, "demibold" } };
78 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
80 /** List of FreeType fonts. Keys are family names, values are plists
81 containing fonts of the corresponding family. In the deeper
82 plist, keys are Mt, values are (MFTInfo *). */
83 static MPlist *ft_font_list;
85 /** List of FreeType base fonts. Keys are family names, values are
87 static MPlist *ft_family_list;
89 static int all_fonts_scaned;
91 static MSymbol M_generic_family_info;
93 enum GenericFamilyType {
95 GENERIC_FAMILY_SANS_SERIF,
96 GENERIC_FAMILY_MONOSPACE,
100 /** Table for each generic family. */
108 static GenericFamilyInfo generic_family_table[GENERIC_FAMILY_MAX] =
109 { { "serif" }, { "sans-serif" }, { "monospace" } };
111 /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize
115 check_otf_filename (const char *name)
117 int len = strlen (name);
118 const char *ext = name + (len - 4);
121 || (memcmp (ext, ".ttf", 4)
122 && memcmp (ext, ".TTF", 4)
123 && memcmp (ext, ".otf", 4)
124 && memcmp (ext, ".OTF", 4)))
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); \
141 /** Setup members of FT_INFO from FT_FACE. If the font is a base one
142 (i.e. medium-r-normal), set BASEP to 1. Otherwise set BASEP to 0.
143 Return the family name. */
146 set_font_info (FT_Face ft_face, MFTInfo *ft_info,
147 MSymbol family, MSymbol style, int *basep)
149 MFont *font = &ft_info->font;
150 MPlist *charmap_list;
151 int unicode_bmp = -1, unicode_full = -1, unicode = -1;
156 mfont__set_property (font, MFONT_FAMILY, family);
157 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
158 mfont__set_property (font, MFONT_STYLE, Mr);
159 mfont__set_property (font, MFONT_STRETCH, Mnormal);
160 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
165 char *p = MSYMBOL_NAME (style);
169 for (i = 0; i < ft_to_prop_size; i++)
170 if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
172 mfont__set_property (font, ft_to_prop[i].prop,
173 msymbol (ft_to_prop[i].val));
174 p += ft_to_prop[i].len;
177 if (i == ft_to_prop_size)
182 while (*p1 >= 'a' && *p1 <= 'z') p1++;
183 sym = msymbol__with_len (p, p1 - p);
184 for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
185 if (msymbol_get (sym, mfont__property_table[i].property))
187 mfont__set_property (font, i, sym);
192 while (*p && (*p < 'a' || *p > 'z')) p++;
194 *basep = (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium
195 && FONT_PROPERTY (font, MFONT_STYLE) == Mr
196 && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal);
199 charmap_list = mplist ();
200 mplist_add (charmap_list, Mt, (void *) -1);
201 for (i = 0; i < ft_face->num_charmaps; i++)
203 char registry_buf[16];
206 sprintf (registry_buf, "%d-%d",
207 ft_face->charmaps[i]->platform_id,
208 ft_face->charmaps[i]->encoding_id);
209 registry = msymbol (registry_buf);
210 mplist_add (charmap_list, registry, (void *) i);
212 if (ft_face->charmaps[i]->platform_id == 0)
214 if (ft_face->charmaps[i]->encoding_id == 3)
216 else if (ft_face->charmaps[i]->encoding_id == 4)
219 else if (ft_face->charmaps[i]->platform_id == 3)
221 if (ft_face->charmaps[i]->encoding_id == 1)
223 else if (ft_face->charmaps[i]->encoding_id == 10)
226 else if (ft_face->charmaps[i]->platform_id == 1
227 && ft_face->charmaps[i]->encoding_id == 0)
228 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
230 if (unicode_full >= 0)
232 mplist_add (charmap_list, Municode_full, (void *) unicode_full);
233 mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
234 mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
235 unicode = unicode_full;
237 else if (unicode_bmp >= 0)
239 mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
240 mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
241 unicode = unicode_bmp;
245 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
246 for (i = 255; i >= 32; i--)
250 if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
254 mplist_add (charmap_list, Miso8859_1, (void *) unicode);
257 ft_info->charmap_list = charmap_list;
259 if (! FT_IS_SCALABLE (ft_face))
261 BDF_PropertyRec prop;
263 FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
264 font->property[MFONT_SIZE] = prop.u.integer * 10;
265 FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
266 font->property[MFONT_RESY] = prop.u.integer;
274 close_ft (void *object)
276 MFTInfo *ft_info = object;
278 if (ft_info->ft_face)
280 if (ft_info->extra_info)
281 M17N_OBJECT_UNREF (ft_info->extra_info);
282 FT_Done_Face (ft_info->ft_face);
285 OTF_close (ft_info->otf);
286 #endif /* HAVE_OTF */
288 free (ft_info->filename);
289 if (ft_info->languages)
290 free (ft_info->languages);
291 M17N_OBJECT_UNREF (ft_info->charmap_list);
296 add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist)
299 BDF_PropertyRec prop;
301 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
309 if (ft_face->family_name)
311 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
312 family = msymbol (buf);
316 if (! (plist = mplist_get (ft_font_list, family)))
319 mplist_add (ft_font_list, family, plist);
322 if (ft_face->style_name)
324 STRDUP_LOWER (buf, bufsize, ft_face->style_name);
325 style = msymbol (buf);
330 if (! mplist_get (plist, style)
331 && (FT_IS_SCALABLE (ft_face)
332 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0))
337 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
338 ft_info->filename = strdup (filename);
339 ft_info->otf_flag = check_otf_filename (filename);
340 #ifdef HAVE_FONTCONFIG
342 ft_info->langset = FcLangSetCopy (langset);
344 set_font_info (ft_face, ft_info, family, style, &basep);
345 mplist_add (plist, style, ft_info);
348 mplist_put (ft_family_list, family, ft_info);
349 else if (! mplist_get (ft_family_list, family))
350 mplist_add (ft_family_list, family, ft_info);
352 FT_Done_Face (ft_face);
356 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
357 scan all fonts and return ft_font_list. */
359 ft_list_family (MSymbol family)
361 MPlist *plist, *head;
365 ft_font_list = mplist ();
366 ft_family_list = mplist ();
373 head = mplist_find_by_key (ft_font_list, family);
376 head = mplist_add (ft_font_list, family, mplist ());
379 #ifdef HAVE_FONTCONFIG
380 if (! all_fonts_scaned)
389 pattern = FcPatternCreate ();
392 FcPatternAddString (pattern, FC_FAMILY,
393 (FcChar8 *) (msymbol_name (family)));
395 os = FcObjectSetBuild (FC_FILE, FC_LANG, NULL);
400 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
402 fs = FcFontList (fc_config, pattern, os);
403 for (i = 0; i < fs->nfont; i++)
408 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
409 (FcChar8 **) &filename) != FcResultMatch)
411 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0,
412 &langset) != FcResultMatch)
419 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
420 (FcChar8 **) &fname) == FcResultMatch)
422 STRDUP_LOWER (buf, bufsize, fname);
424 if (! plist || MPLIST_KEY (plist) != fam)
426 plist = mplist_find_by_key (ft_font_list, fam);
428 plist = mplist_add (ft_font_list, fam, mplist ());
430 add_font_info (filename, fam, langset, MPLIST_PLIST (plist));
434 add_font_info (filename, family, langset, MPLIST_PLIST (plist));
437 FcFontSetDestroy (fs);
438 FcObjectSetDestroy (os);
439 FcPatternDestroy (pattern);
440 all_fonts_scaned = family == Mnil;
443 #else /* not HAVE_FONTCONFIG */
445 if (! all_fonts_scaned)
450 MPLIST_DO (plist, mfont_freetype_path)
451 if (MPLIST_STRING_P (plist)
452 && (pathname = MPLIST_STRING (plist))
453 && stat (pathname, &buf) == 0)
455 if (S_ISREG (buf.st_mode))
456 add_font_info (pathname, Mnil, NULL, NULL);
457 else if (S_ISDIR (buf.st_mode))
459 int len = strlen (pathname);
461 DIR *dir = opendir (pathname);
466 strcpy (path, pathname);
467 strcpy (path + len, "/");
469 while ((dp = readdir (dir)) != NULL)
471 strcpy (path + len, dp->d_name);
472 add_font_info (path, Mnil, NULL, NULL);
478 all_fonts_scaned = 1;
481 #endif /* not HAVE_FONTCONFIG */
487 ft_list_generic (MSymbol generic)
489 #ifdef HAVE_FONTCONFIG
490 GenericFamilyInfo *info = msymbol_get (generic, M_generic_family_info);
498 info->list = mplist ();
499 pattern = FcPatternCreate ();
500 FcPatternAddString (pattern, FC_FAMILY,
501 (FcChar8 *) info->name);
502 if (FcConfigSubstitute (fc_config, pattern, FcMatchPattern) == FcTrue)
508 while (FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &family)
513 STRDUP_LOWER (buf, bufsize, family);
514 plist = ft_list_family (msymbol (buf));
515 mplist_add (info->list, MPLIST_KEY (plist), MPLIST_VAL (plist));
520 #else /* not HAVE_FONTCONFIG */
522 #endif /* not HAVE_FONTCONFIG */
526 /* The FreeType font driver function SELECT. */
528 static MRealizedFont *
529 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
531 MPlist *plist, *pl, *p;
534 MRealizedFont *rfont;
535 MSymbol registry, family;
536 unsigned short spec_family_id, request_family_id;
538 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
539 if (registry == Mnil)
541 family = FONT_PROPERTY (spec, MFONT_FAMILY);
542 spec_family_id = spec->property[MFONT_FAMILY];
543 request_family_id = request->property[MFONT_FAMILY];
547 plist = ft_list_generic (family);
551 spec->property[MFONT_FAMILY] = 0;
552 if (spec_family_id == request_family_id)
553 request->property[MFONT_FAMILY] = 0;
557 if (request_family_id
559 = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY)))
560 && mplist_get (plist, family))
561 request->property[MFONT_FAMILY] = 0;
562 plist = ft_list_family (family);
567 if (request_family_id
568 && (plist = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY))))
569 request->property[MFONT_FAMILY] = 0;
571 plist = ft_list_family (FONT_PROPERTY (request, MFONT_FAMILY));
576 MPLIST_DO (pl, plist)
578 MPLIST_DO (p, MPLIST_VAL (pl))
580 MFTInfo *ft_info = MPLIST_VAL (p);
583 if (! mplist_find_by_key (ft_info->charmap_list, registry))
586 /* Always ignore FOUNDRY. */
587 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
588 score = mfont__score (&ft_info->font, spec, request, limited_size);
591 || best_score > score))
599 if (best_score == 0 || family != Mnil)
602 spec->property[MFONT_FAMILY] = spec_family_id;
603 request->property[MFONT_FAMILY] = request_family_id;
607 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
608 rfont->frame = frame;
610 rfont->request = *request;
611 rfont->font = best_font->font;
612 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
613 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
614 rfont->score = best_score;
615 rfont->info = best_font;
616 M17N_OBJECT_REF (best_font);
621 /* The FreeType font driver function OPEN. */
624 ft_open (MRealizedFont *rfont)
626 MFTInfo *base = rfont->info, *ft_info;
627 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
628 int mdebug_mask = MDEBUG_FONT;
631 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
632 ft_info->font = base->font;
633 ft_info->filename = strdup (base->filename);
634 ft_info->otf_flag = base->otf_flag;
635 ft_info->charmap_list = base->charmap_list;
636 M17N_OBJECT_REF (ft_info->charmap_list);
637 M17N_OBJECT_UNREF (base);
638 rfont->info = ft_info;
641 ft_info->ft_face = NULL;
642 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
644 if (registry == Mnil)
646 ft_info->charmap_index
647 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
648 if (ft_info->charmap_index >= 0
649 && FT_Set_Charmap (ft_info->ft_face,
650 ft_info->ft_face->charmaps[ft_info->charmap_index]))
652 size = rfont->font.property[MFONT_SIZE] / 10;
653 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
656 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
658 rfont->ascent = ft_info->ft_face->size->metrics.ascender >> 6;
659 rfont->descent = - (ft_info->ft_face->size->metrics.descender >> 6);
660 rfont->type = Mfreetype;
661 rfont->fontp = ft_info->ft_face;
665 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
666 if (ft_info->ft_face)
667 FT_Done_Face (ft_info->ft_face);
668 M17N_OBJECT_UNREF (ft_info->charmap_list);
669 free (ft_info->filename);
675 /* The FreeType font driver function FIND_METRIC. */
678 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
681 MFTInfo *ft_info = (MFTInfo *) rfont->info;
682 FT_Face ft_face = ft_info->ft_face;
683 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
685 for (; g != gend; g++)
687 if (g->code == MCHAR_INVALID_CODE)
689 if (FT_IS_SCALABLE (ft_face))
691 unsigned unitsPerEm = ft_face->units_per_EM;
692 int size = rfont->font.property[MFONT_SIZE] / 10;
695 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
696 g->width = ft_face->max_advance_width * size / unitsPerEm;
697 g->ascent = ft_face->ascender * size / unitsPerEm;
698 g->descent = (- ft_face->descender) * size / unitsPerEm;
702 BDF_PropertyRec prop;
705 g->rbearing = g->width = ft_face->available_sizes->width;
706 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
708 g->ascent = prop.u.integer;
709 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
710 g->descent = prop.u.integer;
714 g->ascent = ft_face->available_sizes->height;
721 FT_Glyph_Metrics *metrics;
723 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
724 metrics = &ft_face->glyph->metrics;
725 g->lbearing = (metrics->horiBearingX >> 6);
726 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
727 g->width = metrics->horiAdvance >> 6;
728 g->ascent = metrics->horiBearingY >> 6;
729 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
734 /* The FreeType font driver function ENCODE_CHAR. */
737 ft_encode_char (MRealizedFont *rfont, unsigned code)
741 if (rfont->status == 0)
743 if ((rfont->driver->open) (rfont) < 0)
746 ft_info = (MFTInfo *) rfont->info;
747 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
749 return MCHAR_INVALID_CODE;
754 /* The FreeType font driver function RENDER. */
756 #define NUM_POINTS 0x1000
759 MDrawPoint points[NUM_POINTS];
764 ft_render (MDrawWindow win, int x, int y,
765 MGlyphString *gstring, MGlyph *from, MGlyph *to,
766 int reverse, MDrawRegion region)
770 MRealizedFace *rface = from->rface;
771 MFrame *frame = rface->frame;
772 FT_Int32 load_flags = FT_LOAD_RENDER;
775 MPointTable point_table[8];
780 /* It is assured that the all glyphs in the current range use the
781 same realized face. */
782 ft_info = (MFTInfo *) rface->rfont->info;
783 ft_face = ft_info->ft_face;
785 if (! gstring->anti_alias)
787 #ifdef FT_LOAD_TARGET_MONO
788 load_flags |= FT_LOAD_TARGET_MONO;
790 load_flags |= FT_LOAD_MONOCHROME;
794 for (i = 0; i < 8; i++)
795 point_table[i].p = point_table[i].points;
797 for (g = from; g < to; x += g++->width)
805 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
806 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
807 bmp = ft_face->glyph->bitmap.buffer;
808 width = ft_face->glyph->bitmap.width;
809 pitch = ft_face->glyph->bitmap.pitch;
810 if (! gstring->anti_alias)
815 if (gstring->anti_alias)
816 for (i = 0; i < ft_face->glyph->bitmap.rows;
817 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
819 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
820 for (j = 0; j < width; j++, xoff++)
822 intensity = bmp[j] >> 5;
825 ptable = point_table + intensity;
829 if (ptable->p - ptable->points == NUM_POINTS)
831 (*frame->driver->draw_points)
833 reverse ? 7 - intensity : intensity,
834 ptable->points, NUM_POINTS, region);
835 ptable->p = ptable->points;
841 for (i = 0; i < ft_face->glyph->bitmap.rows;
842 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
844 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
845 for (j = 0; j < width; j++, xoff++)
847 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
850 ptable = point_table;
854 if (ptable->p - ptable->points == NUM_POINTS)
856 (*frame->driver->draw_points) (frame, win, rface,
858 ptable->points, NUM_POINTS, region);
859 ptable->p = ptable->points;
866 if (gstring->anti_alias)
868 for (i = 1; i < 8; i++)
869 if (point_table[i].p != point_table[i].points)
870 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
871 point_table[i].points,
872 point_table[i].p - point_table[i].points, region);
876 if (point_table[0].p != point_table[0].points)
877 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
878 point_table[0].points,
879 point_table[0].p - point_table[0].points, region);
884 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
888 #ifdef HAVE_FONTCONFIG
889 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
896 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
897 pl = ft_list_generic (family);
901 pl = ft_list_family (family);
904 MPLIST_DO (p, MPLIST_PLIST (pl))
906 MFTInfo *ft_info = MPLIST_VAL (p);
908 #ifdef HAVE_FONTCONFIG
909 if (lang && ft_info->langset
910 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
913 mplist_add (plist, MPLIST_KEY (pl), &ft_info->font);
924 ft_list_family (Mnil);
925 MPLIST_DO (p, ft_family_list)
927 MFTInfo *ft_info = MPLIST_VAL (p);
929 #ifdef HAVE_FONTCONFIG
930 if (lang && ft_info->langset
931 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
934 mplist_add (plist, MPLIST_KEY (p), &ft_info->font);
946 MFontDriver mfont__ft_driver =
947 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
954 if (FT_Init_FreeType (&ft_library) != 0)
955 MERROR (MERROR_FONT_FT, -1);
957 for (i = 0; i < ft_to_prop_size; i++)
958 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
960 Municode_bmp = msymbol ("unicode-bmp");
961 Municode_full = msymbol ("unicode-full");
962 Miso10646_1 = msymbol ("iso10646-1");
963 Miso8859_1 = msymbol ("iso8859-1");
965 Mmedium = msymbol ("medium");
967 Mnull = msymbol ("");
969 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
970 generic_family_table[i].list = NULL;
971 M_generic_family_info = msymbol (" generic_family_info");
972 msymbol_put (msymbol ("serif"), M_generic_family_info,
973 generic_family_table + GENERIC_FAMILY_SERIF);
974 msymbol_put (msymbol ("sans-serif"), M_generic_family_info,
975 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
976 msymbol_put (msymbol ("sans"), M_generic_family_info,
977 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
978 msymbol_put (msymbol ("sans serif"), M_generic_family_info,
979 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
980 msymbol_put (msymbol ("monospace"), M_generic_family_info,
981 generic_family_table + GENERIC_FAMILY_MONOSPACE);
982 msymbol_put (msymbol ("mono"), M_generic_family_info,
983 generic_family_table + GENERIC_FAMILY_MONOSPACE);
984 msymbol_put (msymbol ("m"), M_generic_family_info,
985 generic_family_table + GENERIC_FAMILY_MONOSPACE);
987 #ifdef HAVE_FONTCONFIG
995 fc_config = FcConfigGetCurrent ();
996 MPLIST_DO (plist, mfont_freetype_path)
997 if (MPLIST_STRING_P (plist)
998 && (pathname = MPLIST_STRING (plist))
999 && stat (pathname, &buf) == 0)
1001 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1004 while ((dir = FcStrListNext (strlist)))
1005 if (strcmp ((char *) dir, pathname) == 0)
1008 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1009 FcStrListDone (strlist);
1023 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
1024 if (generic_family_table[i].list)
1025 M17N_OBJECT_UNREF (generic_family_table[i].list);
1028 MPLIST_DO (plist, ft_font_list)
1030 MPLIST_DO (p, MPLIST_VAL (plist))
1032 MFTInfo *ft_info = MPLIST_VAL (p);
1034 M17N_OBJECT_UNREF (ft_info);
1036 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1038 M17N_OBJECT_UNREF (ft_font_list);
1039 ft_font_list = NULL;
1041 M17N_OBJECT_UNREF (ft_family_list);
1042 ft_family_list = NULL;
1044 FT_Done_FreeType (ft_library);
1045 all_fonts_scaned = 0;
1049 #ifdef HAVE_FONTCONFIG
1054 } FC_vs_M17N_font_prop;
1056 static FC_vs_M17N_font_prop fc_weight_table[] =
1057 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1058 { FC_WEIGHT_LIGHT, "light" },
1059 { FC_WEIGHT_NORMAL, "normal" },
1060 { FC_WEIGHT_MEDIUM, "medium" },
1061 { FC_WEIGHT_DEMIBOLD, "demibold" },
1062 { FC_WEIGHT_EXTRABOLD, "extrabold" },
1063 { FC_WEIGHT_BLACK, "black" },
1064 { FC_WEIGHT_MEDIUM, NULL } };
1066 static FC_vs_M17N_font_prop fc_slant_table[] =
1067 { { FC_SLANT_ROMAN, "r" },
1068 { FC_SLANT_ITALIC, "i" },
1069 { FC_SLANT_OBLIQUE, "o" },
1070 { FC_SLANT_ROMAN, NULL } };
1072 static FC_vs_M17N_font_prop fc_width_table[] =
1073 { { FC_WIDTH_CONDENSED, "condensed" },
1074 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1075 { FC_WIDTH_NORMAL, "normal" },
1076 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1077 { FC_WIDTH_EXPANDED, "expanded" },
1078 { FC_WIDTH_NORMAL, NULL } };
1082 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1086 for (i = 0; table[i].m17n_value; i++)
1087 if (val <= table[i].fc_value)
1088 return msymbol ("table[i].m17n_value");
1089 return msymbol ("table[i - 1].m17n_value");
1093 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1097 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1098 return table[i].fc_value;
1102 mfont__ft_parse_name (char *name, MFont *font)
1104 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1111 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1112 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1113 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1114 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1115 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1116 mfont__set_property (font, MFONT_WEIGHT,
1117 fc_decode_prop (val, fc_weight_table));
1118 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1119 mfont__set_property (font, MFONT_STYLE,
1120 fc_decode_prop (val, fc_slant_table));
1121 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1122 mfont__set_property (font, MFONT_STRETCH,
1123 fc_decode_prop (val, fc_width_table));
1124 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1125 font->property[MFONT_SIZE] = size * 10;
1126 FcPatternDestroy (pat);
1131 mfont__ft_unparse_name (MFont *font)
1133 FcPattern *pat = FcPatternCreate ();
1134 MSymbol sym, weight, style, stretch;
1137 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1138 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1139 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1140 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1141 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1142 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1144 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1145 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1147 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1148 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1150 name = (char *) FcNameUnparse (pat);
1151 FcPatternDestroy (pat);
1154 #endif /* HAVE_FONTCONFIG */
1159 #define DEVICE_DELTA(table, size) \
1160 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1161 ? (table).DeltaValue[(size) >= (table).StartSize] \
1165 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1166 unsigned code, int size, int *x, int *y)
1168 if (anchor->AnchorFormat == 2)
1170 FT_Outline *outline;
1171 int ap = anchor->f.f1.AnchorPoint;
1173 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1174 outline = &ft_face->glyph->outline;
1175 if (ap < outline->n_points)
1177 *x = outline->points[ap].x;
1178 *y = outline->points[ap].y;
1181 else if (anchor->AnchorFormat == 3)
1183 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1184 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1189 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1190 MSymbol script, MSymbol langsys,
1191 MSymbol gsub_features, MSymbol gpos_features)
1193 int len = to - from;
1194 MGlyph *g = MGLYPH (from);
1196 MRealizedFont *rfont;
1199 OTF_GlyphString otf_gstring;
1201 char *script_name, *language_name;
1202 char *gsub_feature_names, *gpos_feature_names;
1208 rfont = g->rface->rfont;
1209 ft_info = rfont->info;
1210 if (ft_info->otf_flag < 0)
1215 otf = OTF_open (ft_info->filename);
1216 if (otf && OTF_get_table (otf, "head") < 0)
1223 ft_info->otf_flag = -1;
1230 script_name = msymbol_name (script);
1233 if (langsys != Mnil)
1234 language_name = msymbol_name (langsys);
1236 language_name = NULL;
1238 = (gsub_features == Mt ? "*"
1239 : gsub_features == Mnil ? NULL
1240 : msymbol_name (gsub_features));
1241 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1242 gsub_feature_names = NULL;
1244 = (gpos_features == Mt ? "*"
1245 : gpos_features == Mnil ? NULL
1246 : msymbol_name (gpos_features));
1247 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1248 gpos_feature_names = NULL;
1250 otf_gstring.size = otf_gstring.used = len;
1251 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1252 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1253 for (i = 0, need_cmap = 0; i < len; i++)
1255 if (gstring->glyphs[from + i].otf_encoded)
1257 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1258 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1262 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1267 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1270 OTF_drive_gdef (otf, &otf_gstring);
1271 gidx = gstring->used;
1273 if (gsub_feature_names)
1275 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1276 gsub_feature_names) < 0)
1278 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1280 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1283 temp.combining_code = 0;
1286 temp.code = otfg->glyph_id;
1287 temp.otf_encoded = 1;
1292 temp.otf_encoded = 0;
1294 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1295 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1299 for (i = 0; i < len; i++)
1301 MGlyph temp = gstring->glyphs[from + i];
1303 if (otf_gstring.glyphs[i].glyph_id)
1305 temp.code = otf_gstring.glyphs[i].glyph_id;
1306 temp.otf_encoded = 1;
1308 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1311 ft_find_metric (rfont, gstring, gidx, gstring->used);
1313 if (gpos_feature_names)
1317 MGlyph *base = NULL, *mark = NULL;
1319 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1320 gpos_feature_names) < 0)
1323 u = otf->head->unitsPerEm;
1324 size10 = rfont->font.property[MFONT_SIZE];
1327 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1328 i < otf_gstring.used; i++, otfg++, g++)
1332 if (! otfg->glyph_id)
1334 switch (otfg->positioning_type)
1340 int format = otfg->f.f1.format;
1342 if (format & OTF_XPlacement)
1343 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1344 if (format & OTF_XPlaDevice)
1345 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1346 if (format & OTF_YPlacement)
1347 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1348 if (format & OTF_YPlaDevice)
1349 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1350 if (format & OTF_XAdvance)
1351 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1352 if (format & OTF_XAdvDevice)
1353 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1357 /* Not yet supported. */
1363 goto label_adjust_anchor;
1364 default: /* i.e. case 6 */
1369 label_adjust_anchor:
1371 int base_x, base_y, mark_x, mark_y;
1373 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1374 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1375 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1376 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1378 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1379 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1380 prev->code, size, &base_x, &base_y);
1381 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1382 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1383 g->code, size, &mark_x, &mark_y);
1384 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1385 g->yoff = prev->yoff + mark_y - base_y;
1386 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1389 if (otfg->GlyphClass == OTF_GlyphClass0)
1391 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1397 free (otf_gstring.glyphs);
1401 ft_find_metric (rfont, gstring, from, to);
1402 for (i = 0; i < len; i++)
1404 MGlyph temp = gstring->glyphs[from + i];
1405 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1407 free (otf_gstring.glyphs);
1413 mfont__ft_decode_otf (MGlyph *g)
1415 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1416 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1418 return (c ? c : -1);
1421 #endif /* HAVE_OTF */
1423 #endif /* HAVE_FREETYPE */