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 GenericFamilyInfo *info = msymbol_get (generic, M_generic_family_info);
490 #ifdef HAVE_FONTCONFIG
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));
519 #endif /* HAVE_FONTCONFIG */
524 /* The FreeType font driver function SELECT. */
526 static MRealizedFont *
527 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
529 MPlist *plist, *pl, *p;
532 MRealizedFont *rfont;
533 MSymbol registry, family;
534 unsigned short spec_family_id, request_family_id;
536 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
537 if (registry == Mnil)
539 family = FONT_PROPERTY (spec, MFONT_FAMILY);
540 spec_family_id = spec->property[MFONT_FAMILY];
541 request_family_id = request->property[MFONT_FAMILY];
545 plist = ft_list_generic (family);
549 spec->property[MFONT_FAMILY] = 0;
550 if (spec_family_id == request_family_id)
551 request->property[MFONT_FAMILY] = 0;
555 if (request_family_id
557 = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY)))
558 && mplist_get (plist, family))
559 request->property[MFONT_FAMILY] = 0;
560 plist = ft_list_family (family);
565 if (request_family_id
566 && (plist = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY))))
567 request->property[MFONT_FAMILY] = 0;
569 plist = ft_list_family (FONT_PROPERTY (request, MFONT_FAMILY));
574 MPLIST_DO (pl, plist)
576 MPLIST_DO (p, MPLIST_VAL (pl))
578 MFTInfo *ft_info = MPLIST_VAL (p);
581 if (! mplist_find_by_key (ft_info->charmap_list, registry))
584 /* Always ignore FOUNDRY. */
585 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
586 score = mfont__score (&ft_info->font, spec, request, limited_size);
589 || best_score > score))
597 if (best_score == 0 || family != Mnil)
600 spec->property[MFONT_FAMILY] = spec_family_id;
601 request->property[MFONT_FAMILY] = request_family_id;
605 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
606 rfont->frame = frame;
608 rfont->request = *request;
609 rfont->font = best_font->font;
610 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
611 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
612 rfont->score = best_score;
613 rfont->info = best_font;
614 M17N_OBJECT_REF (best_font);
619 /* The FreeType font driver function OPEN. */
622 ft_open (MRealizedFont *rfont)
624 MFTInfo *base = rfont->info, *ft_info;
625 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
626 int mdebug_mask = MDEBUG_FONT;
629 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
630 ft_info->font = base->font;
631 ft_info->filename = strdup (base->filename);
632 ft_info->otf_flag = base->otf_flag;
633 ft_info->charmap_list = base->charmap_list;
634 M17N_OBJECT_REF (ft_info->charmap_list);
635 M17N_OBJECT_UNREF (base);
636 rfont->info = ft_info;
639 ft_info->ft_face = NULL;
640 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
642 if (registry == Mnil)
644 ft_info->charmap_index
645 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
646 if (ft_info->charmap_index >= 0
647 && FT_Set_Charmap (ft_info->ft_face,
648 ft_info->ft_face->charmaps[ft_info->charmap_index]))
650 size = rfont->font.property[MFONT_SIZE] / 10;
651 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
654 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
656 rfont->ascent = ft_info->ft_face->size->metrics.ascender >> 6;
657 rfont->descent = - (ft_info->ft_face->size->metrics.descender >> 6);
658 rfont->type = Mfreetype;
659 rfont->fontp = ft_info->ft_face;
663 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
664 if (ft_info->ft_face)
665 FT_Done_Face (ft_info->ft_face);
666 M17N_OBJECT_UNREF (ft_info->charmap_list);
667 free (ft_info->filename);
673 /* The FreeType font driver function FIND_METRIC. */
676 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
679 MFTInfo *ft_info = (MFTInfo *) rfont->info;
680 FT_Face ft_face = ft_info->ft_face;
681 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
683 for (; g != gend; g++)
685 if (g->code == MCHAR_INVALID_CODE)
687 if (FT_IS_SCALABLE (ft_face))
689 unsigned unitsPerEm = ft_face->units_per_EM;
690 int size = rfont->font.property[MFONT_SIZE] / 10;
693 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
694 g->width = ft_face->max_advance_width * size / unitsPerEm;
695 g->ascent = ft_face->ascender * size / unitsPerEm;
696 g->descent = (- ft_face->descender) * size / unitsPerEm;
700 BDF_PropertyRec prop;
703 g->rbearing = g->width = ft_face->available_sizes->width;
704 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
706 g->ascent = prop.u.integer;
707 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
708 g->descent = prop.u.integer;
712 g->ascent = ft_face->available_sizes->height;
719 FT_Glyph_Metrics *metrics;
721 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
722 metrics = &ft_face->glyph->metrics;
723 g->lbearing = (metrics->horiBearingX >> 6);
724 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
725 g->width = metrics->horiAdvance >> 6;
726 g->ascent = metrics->horiBearingY >> 6;
727 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
732 /* The FreeType font driver function ENCODE_CHAR. */
735 ft_encode_char (MRealizedFont *rfont, unsigned code)
739 if (rfont->status == 0)
741 if ((rfont->driver->open) (rfont) < 0)
744 ft_info = (MFTInfo *) rfont->info;
745 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
747 return MCHAR_INVALID_CODE;
752 /* The FreeType font driver function RENDER. */
754 #define NUM_POINTS 0x1000
757 MDrawPoint points[NUM_POINTS];
762 ft_render (MDrawWindow win, int x, int y,
763 MGlyphString *gstring, MGlyph *from, MGlyph *to,
764 int reverse, MDrawRegion region)
768 MRealizedFace *rface = from->rface;
769 MFrame *frame = rface->frame;
770 FT_Int32 load_flags = FT_LOAD_RENDER;
773 MPointTable point_table[8];
778 /* It is assured that the all glyphs in the current range use the
779 same realized face. */
780 ft_info = (MFTInfo *) rface->rfont->info;
781 ft_face = ft_info->ft_face;
783 if (! gstring->anti_alias)
785 #ifdef FT_LOAD_TARGET_MONO
786 load_flags |= FT_LOAD_TARGET_MONO;
788 load_flags |= FT_LOAD_MONOCHROME;
792 for (i = 0; i < 8; i++)
793 point_table[i].p = point_table[i].points;
795 for (g = from; g < to; x += g++->width)
803 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
804 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
805 bmp = ft_face->glyph->bitmap.buffer;
806 width = ft_face->glyph->bitmap.width;
807 pitch = ft_face->glyph->bitmap.pitch;
808 if (! gstring->anti_alias)
813 if (gstring->anti_alias)
814 for (i = 0; i < ft_face->glyph->bitmap.rows;
815 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
817 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
818 for (j = 0; j < width; j++, xoff++)
820 intensity = bmp[j] >> 5;
823 ptable = point_table + intensity;
827 if (ptable->p - ptable->points == NUM_POINTS)
829 (*frame->driver->draw_points)
831 reverse ? 7 - intensity : intensity,
832 ptable->points, NUM_POINTS, region);
833 ptable->p = ptable->points;
839 for (i = 0; i < ft_face->glyph->bitmap.rows;
840 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
842 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
843 for (j = 0; j < width; j++, xoff++)
845 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
848 ptable = point_table;
852 if (ptable->p - ptable->points == NUM_POINTS)
854 (*frame->driver->draw_points) (frame, win, rface,
856 ptable->points, NUM_POINTS, region);
857 ptable->p = ptable->points;
864 if (gstring->anti_alias)
866 for (i = 1; i < 8; i++)
867 if (point_table[i].p != point_table[i].points)
868 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
869 point_table[i].points,
870 point_table[i].p - point_table[i].points, region);
874 if (point_table[0].p != point_table[0].points)
875 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
876 point_table[0].points,
877 point_table[0].p - point_table[0].points, region);
882 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
886 #ifdef HAVE_FONTCONFIG
887 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
894 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
895 pl = ft_list_generic (family);
899 pl = ft_list_family (family);
902 MPLIST_DO (p, MPLIST_PLIST (pl))
904 MFTInfo *ft_info = MPLIST_VAL (p);
906 #ifdef HAVE_FONTCONFIG
907 if (lang && ft_info->langset
908 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
911 mplist_add (plist, MPLIST_KEY (pl), &ft_info->font);
922 ft_list_family (Mnil);
923 MPLIST_DO (p, ft_family_list)
925 MFTInfo *ft_info = MPLIST_VAL (p);
927 #ifdef HAVE_FONTCONFIG
928 if (lang && ft_info->langset
929 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
932 mplist_add (plist, MPLIST_KEY (p), &ft_info->font);
944 MFontDriver mfont__ft_driver =
945 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
952 if (FT_Init_FreeType (&ft_library) != 0)
953 MERROR (MERROR_FONT_FT, -1);
955 for (i = 0; i < ft_to_prop_size; i++)
956 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
958 Municode_bmp = msymbol ("unicode-bmp");
959 Municode_full = msymbol ("unicode-full");
960 Miso10646_1 = msymbol ("iso10646-1");
961 Miso8859_1 = msymbol ("iso8859-1");
963 Mmedium = msymbol ("medium");
965 Mnull = msymbol ("");
967 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
968 generic_family_table[i].list = NULL;
969 M_generic_family_info = msymbol (" generic_family_info");
970 msymbol_put (msymbol ("serif"), M_generic_family_info,
971 generic_family_table + GENERIC_FAMILY_SERIF);
972 msymbol_put (msymbol ("sans-serif"), M_generic_family_info,
973 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
974 msymbol_put (msymbol ("sans"), M_generic_family_info,
975 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
976 msymbol_put (msymbol ("sans serif"), M_generic_family_info,
977 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
978 msymbol_put (msymbol ("monospace"), M_generic_family_info,
979 generic_family_table + GENERIC_FAMILY_MONOSPACE);
980 msymbol_put (msymbol ("mono"), M_generic_family_info,
981 generic_family_table + GENERIC_FAMILY_MONOSPACE);
982 msymbol_put (msymbol ("m"), M_generic_family_info,
983 generic_family_table + GENERIC_FAMILY_MONOSPACE);
985 #ifdef HAVE_FONTCONFIG
993 fc_config = FcConfigGetCurrent ();
994 MPLIST_DO (plist, mfont_freetype_path)
995 if (MPLIST_STRING_P (plist)
996 && (pathname = MPLIST_STRING (plist))
997 && stat (pathname, &buf) == 0)
999 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1002 while ((dir = FcStrListNext (strlist)))
1003 if (strcmp ((char *) dir, pathname) == 0)
1006 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1007 FcStrListDone (strlist);
1021 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
1022 if (generic_family_table[i].list)
1023 M17N_OBJECT_UNREF (generic_family_table[i].list);
1026 MPLIST_DO (plist, ft_font_list)
1028 MPLIST_DO (p, MPLIST_VAL (plist))
1030 MFTInfo *ft_info = MPLIST_VAL (p);
1032 M17N_OBJECT_UNREF (ft_info);
1034 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1036 M17N_OBJECT_UNREF (ft_font_list);
1037 ft_font_list = NULL;
1039 M17N_OBJECT_UNREF (ft_family_list);
1040 ft_family_list = NULL;
1042 FT_Done_FreeType (ft_library);
1043 all_fonts_scaned = 0;
1047 #ifdef HAVE_FONTCONFIG
1052 } FC_vs_M17N_font_prop;
1054 static FC_vs_M17N_font_prop fc_weight_table[] =
1055 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1056 { FC_WEIGHT_LIGHT, "light" },
1057 { FC_WEIGHT_NORMAL, "normal" },
1058 { FC_WEIGHT_MEDIUM, "medium" },
1059 { FC_WEIGHT_DEMIBOLD, "demibold" },
1060 { FC_WEIGHT_EXTRABOLD, "extrabold" },
1061 { FC_WEIGHT_BLACK, "black" },
1062 { FC_WEIGHT_MEDIUM, NULL } };
1064 static FC_vs_M17N_font_prop fc_slant_table[] =
1065 { { FC_SLANT_ROMAN, "r" },
1066 { FC_SLANT_ITALIC, "i" },
1067 { FC_SLANT_OBLIQUE, "o" },
1068 { FC_SLANT_ROMAN, NULL } };
1070 static FC_vs_M17N_font_prop fc_width_table[] =
1071 { { FC_WIDTH_CONDENSED, "condensed" },
1072 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1073 { FC_WIDTH_NORMAL, "normal" },
1074 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1075 { FC_WIDTH_EXPANDED, "expanded" },
1076 { FC_WIDTH_NORMAL, NULL } };
1080 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1084 for (i = 0; table[i].m17n_value; i++)
1085 if (val <= table[i].fc_value)
1086 return msymbol ("table[i].m17n_value");
1087 return msymbol ("table[i - 1].m17n_value");
1091 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1095 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1096 return table[i].fc_value;
1100 mfont__ft_parse_name (char *name, MFont *font)
1102 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1109 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1110 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1111 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1112 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1113 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1114 mfont__set_property (font, MFONT_WEIGHT,
1115 fc_decode_prop (val, fc_weight_table));
1116 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1117 mfont__set_property (font, MFONT_STYLE,
1118 fc_decode_prop (val, fc_slant_table));
1119 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1120 mfont__set_property (font, MFONT_STRETCH,
1121 fc_decode_prop (val, fc_width_table));
1122 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1123 font->property[MFONT_SIZE] = size * 10;
1124 FcPatternDestroy (pat);
1129 mfont__ft_unparse_name (MFont *font)
1131 FcPattern *pat = FcPatternCreate ();
1132 MSymbol sym, weight, style, stretch;
1135 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1136 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1137 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1138 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1139 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1140 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1142 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1143 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1145 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1146 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1148 name = (char *) FcNameUnparse (pat);
1149 FcPatternDestroy (pat);
1152 #endif /* HAVE_FONTCONFIG */
1157 #define DEVICE_DELTA(table, size) \
1158 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1159 ? (table).DeltaValue[(size) >= (table).StartSize] \
1163 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1164 unsigned code, int size, int *x, int *y)
1166 if (anchor->AnchorFormat == 2)
1168 FT_Outline *outline;
1169 int ap = anchor->f.f1.AnchorPoint;
1171 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1172 outline = &ft_face->glyph->outline;
1173 if (ap < outline->n_points)
1175 *x = outline->points[ap].x;
1176 *y = outline->points[ap].y;
1179 else if (anchor->AnchorFormat == 3)
1181 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1182 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1187 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1188 MSymbol script, MSymbol langsys,
1189 MSymbol gsub_features, MSymbol gpos_features)
1191 int len = to - from;
1192 MGlyph *g = MGLYPH (from);
1194 MRealizedFont *rfont;
1197 OTF_GlyphString otf_gstring;
1199 char *script_name, *language_name;
1200 char *gsub_feature_names, *gpos_feature_names;
1206 rfont = g->rface->rfont;
1207 ft_info = rfont->info;
1208 if (ft_info->otf_flag < 0)
1213 otf = OTF_open (ft_info->filename);
1214 if (otf && OTF_get_table (otf, "head") < 0)
1221 ft_info->otf_flag = -1;
1228 script_name = msymbol_name (script);
1231 if (langsys != Mnil)
1232 language_name = msymbol_name (langsys);
1234 language_name = NULL;
1236 = (gsub_features == Mt ? "*"
1237 : gsub_features == Mnil ? NULL
1238 : msymbol_name (gsub_features));
1239 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1240 gsub_feature_names = NULL;
1242 = (gpos_features == Mt ? "*"
1243 : gpos_features == Mnil ? NULL
1244 : msymbol_name (gpos_features));
1245 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1246 gpos_feature_names = NULL;
1248 otf_gstring.size = otf_gstring.used = len;
1249 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1250 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1251 for (i = 0, need_cmap = 0; i < len; i++)
1253 if (gstring->glyphs[from + i].otf_encoded)
1255 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1256 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1260 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1265 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1268 OTF_drive_gdef (otf, &otf_gstring);
1269 gidx = gstring->used;
1271 if (gsub_feature_names)
1273 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1274 gsub_feature_names) < 0)
1276 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1278 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1281 temp.combining_code = 0;
1284 temp.code = otfg->glyph_id;
1285 temp.otf_encoded = 1;
1290 temp.otf_encoded = 0;
1292 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1293 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1297 for (i = 0; i < len; i++)
1299 MGlyph temp = gstring->glyphs[from + i];
1301 if (otf_gstring.glyphs[i].glyph_id)
1303 temp.code = otf_gstring.glyphs[i].glyph_id;
1304 temp.otf_encoded = 1;
1306 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1309 ft_find_metric (rfont, gstring, gidx, gstring->used);
1311 if (gpos_feature_names)
1315 MGlyph *base = NULL, *mark = NULL;
1317 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1318 gpos_feature_names) < 0)
1321 u = otf->head->unitsPerEm;
1322 size10 = rfont->font.property[MFONT_SIZE];
1325 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1326 i < otf_gstring.used; i++, otfg++, g++)
1330 if (! otfg->glyph_id)
1332 switch (otfg->positioning_type)
1338 int format = otfg->f.f1.format;
1340 if (format & OTF_XPlacement)
1341 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1342 if (format & OTF_XPlaDevice)
1343 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1344 if (format & OTF_YPlacement)
1345 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1346 if (format & OTF_YPlaDevice)
1347 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1348 if (format & OTF_XAdvance)
1349 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1350 if (format & OTF_XAdvDevice)
1351 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1355 /* Not yet supported. */
1361 goto label_adjust_anchor;
1362 default: /* i.e. case 6 */
1367 label_adjust_anchor:
1369 int base_x, base_y, mark_x, mark_y;
1371 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1372 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1373 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1374 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1376 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1377 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1378 prev->code, size, &base_x, &base_y);
1379 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1380 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1381 g->code, size, &mark_x, &mark_y);
1382 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1383 g->yoff = prev->yoff + mark_y - base_y;
1384 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1387 if (otfg->GlyphClass == OTF_GlyphClass0)
1389 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1395 free (otf_gstring.glyphs);
1399 ft_find_metric (rfont, gstring, from, to);
1400 for (i = 0; i < len; i++)
1402 MGlyph temp = gstring->glyphs[from + i];
1403 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1405 free (otf_gstring.glyphs);
1411 mfont__ft_decode_otf (MGlyph *g)
1413 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1414 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1416 return (c ? c : -1);
1419 #endif /* HAVE_OTF */
1421 #endif /* HAVE_FREETYPE */